JsRTApiTest.cpp 123 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "stdafx.h"
  6. #pragma warning(disable:26434) // Function definition hides non-virtual function in base class
  7. #pragma warning(disable:26439) // Implicit noexcept
  8. #pragma warning(disable:26451) // Arithmetic overflow
  9. #pragma warning(disable:26495) // Uninitialized member variable
  10. #include "catch.hpp"
  11. #include <array>
  12. #include <process.h>
  13. #include <suppress.h>
  14. #pragma warning(disable:4100) // unreferenced formal parameter
  15. #pragma warning(disable:6387) // suppressing preFAST which raises warning for passing null to the JsRT APIs
  16. #pragma warning(disable:6262) // CATCH is using stack variables to report errors, suppressing the preFAST warning.
  17. namespace JsRTApiTest
  18. {
  19. bool TestSetup(JsRuntimeAttributes attributes, JsRuntimeHandle *runtime)
  20. {
  21. JsValueRef context = JS_INVALID_REFERENCE;
  22. JsValueRef setContext = JS_INVALID_REFERENCE;
  23. // Create runtime, context and set current context
  24. REQUIRE(JsCreateRuntime(attributes, nullptr, runtime) == JsNoError);
  25. REQUIRE(JsCreateContext(*runtime, &context) == JsNoError);
  26. REQUIRE(JsSetCurrentContext(context) == JsNoError);
  27. REQUIRE(((JsGetCurrentContext(&setContext) == JsNoError) || setContext == context));
  28. return true;
  29. }
  30. bool TestCleanup(JsRuntimeHandle runtime)
  31. {
  32. if (runtime != nullptr)
  33. {
  34. JsSetCurrentContext(nullptr);
  35. JsDisposeRuntime(runtime);
  36. }
  37. return true;
  38. }
  39. JsValueRef GetUndefined()
  40. {
  41. JsValueRef undefined = JS_INVALID_REFERENCE;
  42. REQUIRE(JsGetUndefinedValue(&undefined) == JsNoError);
  43. return undefined;
  44. }
  45. template <class Handler>
  46. void WithSetup(JsRuntimeAttributes attributes, Handler handler)
  47. {
  48. JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE;
  49. if (!TestSetup(attributes, &runtime))
  50. {
  51. REQUIRE(false);
  52. return;
  53. }
  54. handler(attributes, runtime);
  55. TestCleanup(runtime);
  56. }
  57. template <class Handler>
  58. void RunWithAttributes(Handler handler)
  59. {
  60. WithSetup(JsRuntimeAttributeNone, handler);
  61. WithSetup(JsRuntimeAttributeDisableBackgroundWork, handler);
  62. WithSetup(JsRuntimeAttributeAllowScriptInterrupt, handler);
  63. WithSetup(JsRuntimeAttributeEnableIdleProcessing, handler);
  64. WithSetup(JsRuntimeAttributeDisableNativeCodeGeneration, handler);
  65. WithSetup(JsRuntimeAttributeDisableExecutablePageAllocation, handler);
  66. WithSetup(JsRuntimeAttributeDisableEval, handler);
  67. WithSetup((JsRuntimeAttributes)(JsRuntimeAttributeDisableBackgroundWork | JsRuntimeAttributeAllowScriptInterrupt | JsRuntimeAttributeEnableIdleProcessing), handler);
  68. }
  69. void ReferenceCountingTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  70. {
  71. JsContextRef context = JS_INVALID_REFERENCE;
  72. REQUIRE(JsGetCurrentContext(&context) == JsNoError);
  73. CHECK(JsAddRef(context, nullptr) == JsNoError);
  74. CHECK(JsRelease(context, nullptr) == JsNoError);
  75. JsValueRef undefined = JS_INVALID_REFERENCE;
  76. REQUIRE(JsGetUndefinedValue(&undefined) == JsNoError);
  77. REQUIRE(JsSetCurrentContext(nullptr) == JsNoError);
  78. CHECK(JsAddRef(undefined, nullptr) == JsErrorNoCurrentContext);
  79. CHECK(JsRelease(undefined, nullptr) == JsErrorNoCurrentContext);
  80. REQUIRE(JsSetCurrentContext(context) == JsNoError);
  81. CHECK(JsAddRef(undefined, nullptr) == JsNoError);
  82. CHECK(JsRelease(undefined, nullptr) == JsNoError);
  83. JsPropertyIdRef foo = JS_INVALID_REFERENCE;
  84. REQUIRE(JsGetPropertyIdFromName(_u("foo"), &foo) == JsNoError);
  85. CHECK(JsAddRef(foo, nullptr) == JsNoError);
  86. CHECK(JsRelease(foo, nullptr) == JsNoError);
  87. }
  88. TEST_CASE("ApiTest_ReferenceCountingTest", "[ApiTest]")
  89. {
  90. JsRTApiTest::RunWithAttributes(JsRTApiTest::ReferenceCountingTest);
  91. }
  92. void WeakReferenceTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  93. {
  94. JsValueRef valueRef = JS_INVALID_REFERENCE;
  95. REQUIRE(JsCreateString("test", strlen("test"), &valueRef) == JsNoError);
  96. JsWeakRef weakRef = JS_INVALID_REFERENCE;
  97. REQUIRE(JsCreateWeakReference(valueRef, &weakRef) == JsNoError);
  98. // JsGetWeakReferenceValue should return the original value reference.
  99. JsValueRef valueRefFromWeakRef = JS_INVALID_REFERENCE;
  100. CHECK(JsGetWeakReferenceValue(weakRef, &valueRefFromWeakRef) == JsNoError);
  101. CHECK(valueRefFromWeakRef != JS_INVALID_REFERENCE);
  102. CHECK(valueRefFromWeakRef == valueRef);
  103. // Clear the references on the stack, so that the value will be GC'd.
  104. valueRef = JS_INVALID_REFERENCE;
  105. valueRefFromWeakRef = JS_INVALID_REFERENCE;
  106. CHECK(JsCollectGarbage(runtime) == JsNoError);
  107. // JsGetWeakReferenceValue should return an invalid reference after the value was GC'd.
  108. JsValueRef valueRefAfterGC = JS_INVALID_REFERENCE;
  109. CHECK(JsGetWeakReferenceValue(weakRef, &valueRefAfterGC) == JsNoError);
  110. CHECK(valueRefAfterGC == JS_INVALID_REFERENCE);
  111. }
  112. TEST_CASE("ApiTest_WeakReferenceTest", "[ApiTest]")
  113. {
  114. JsRTApiTest::RunWithAttributes(JsRTApiTest::WeakReferenceTest);
  115. }
  116. void ObjectsAndPropertiesTest1(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  117. {
  118. JsValueRef object = JS_INVALID_REFERENCE;
  119. REQUIRE(JsCreateObject(&object) == JsNoError);
  120. JsPropertyIdRef name1 = JS_INVALID_REFERENCE;
  121. const WCHAR* name = nullptr;
  122. REQUIRE(JsGetPropertyIdFromName(_u("stringProperty1"), &name1) == JsNoError);
  123. REQUIRE(JsGetPropertyNameFromId(name1, &name) == JsNoError);
  124. CHECK(!wcscmp(name, _u("stringProperty1")));
  125. JsPropertyIdType propertyIdType;
  126. REQUIRE(JsGetPropertyIdType(name1, &propertyIdType) == JsNoError);
  127. CHECK(propertyIdType == JsPropertyIdTypeString);
  128. JsPropertyIdRef name2 = JS_INVALID_REFERENCE;
  129. REQUIRE(JsGetPropertyIdFromName(_u("stringProperty2"), &name2) == JsNoError);
  130. JsValueRef value1 = JS_INVALID_REFERENCE;
  131. REQUIRE(JsPointerToString(_u("value1"), wcslen(_u("value1")), &value1) == JsNoError);
  132. JsValueRef value2 = JS_INVALID_REFERENCE;
  133. REQUIRE(JsPointerToString(_u("value1"), wcslen(_u("value1")), &value2) == JsNoError);
  134. REQUIRE(JsSetProperty(object, name1, value1, true) == JsNoError);
  135. REQUIRE(JsSetProperty(object, name2, value2, true) == JsNoError);
  136. JsValueRef value1Check = JS_INVALID_REFERENCE;
  137. REQUIRE(JsGetProperty(object, name1, &value1Check) == JsNoError);
  138. CHECK(value1 == value1Check);
  139. JsValueRef value2Check = JS_INVALID_REFERENCE;
  140. REQUIRE(JsGetProperty(object, name2, &value2Check) == JsNoError);
  141. CHECK(value1 == value1Check);
  142. }
  143. TEST_CASE("ApiTest_ObjectsAndPropertiesTest1", "[ApiTest]")
  144. {
  145. JsRTApiTest::RunWithAttributes(JsRTApiTest::ObjectsAndPropertiesTest1);
  146. }
  147. void ObjectsAndPropertiesTest2(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  148. {
  149. // Run a script to setup some globals
  150. JsValueRef function = JS_INVALID_REFERENCE;
  151. LPCWSTR script = nullptr;
  152. REQUIRE(FileLoadHelpers::LoadScriptFromFile("ObjectsAndProperties2.js", script) == S_OK);
  153. REQUIRE(script != nullptr);
  154. REQUIRE(JsParseScript(script, JS_SOURCE_CONTEXT_NONE, _u(""), &function) == JsNoError);
  155. JsValueRef args[] = { JS_INVALID_REFERENCE };
  156. REQUIRE(JsCallFunction(function, nullptr, 10, nullptr) == JsErrorInvalidArgument);
  157. REQUIRE(JsCallFunction(function, args, 0, nullptr) == JsErrorInvalidArgument);
  158. REQUIRE(JsCallFunction(function, args, _countof(args), nullptr) == JsErrorInvalidArgument);
  159. args[0] = GetUndefined();
  160. REQUIRE(JsCallFunction(function, args, _countof(args), nullptr) == JsNoError);
  161. // Get proto properties
  162. JsValueRef circle = JS_INVALID_REFERENCE;
  163. REQUIRE(JsRunScript(_u("new Circle()"), JS_SOURCE_CONTEXT_NONE, _u(""), &circle) == JsNoError);
  164. JsPropertyIdRef name = JS_INVALID_REFERENCE;
  165. REQUIRE(JsGetPropertyIdFromName(_u("color"), &name) == JsNoError);
  166. JsValueRef value = JS_INVALID_REFERENCE;
  167. REQUIRE(JsGetProperty(circle, name, &value) == JsNoError);
  168. JsValueRef asString = JS_INVALID_REFERENCE;
  169. REQUIRE(JsConvertValueToString(value, &asString) == JsNoError);
  170. LPCWSTR str = nullptr;
  171. size_t length;
  172. REQUIRE(JsStringToPointer(asString, &str, &length) == JsNoError);
  173. REQUIRE(!wcscmp(str, _u("white")));
  174. }
  175. TEST_CASE("ApiTest_ObjectsAndPropertiesTest2", "[ApiTest]")
  176. {
  177. JsRTApiTest::RunWithAttributes(JsRTApiTest::ObjectsAndPropertiesTest2);
  178. }
  179. void DeleteObjectIndexedPropertyBug(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  180. {
  181. JsValueRef object;
  182. REQUIRE(JsRunScript(_u("({a: 'a', 1: 1, 100: 100})"), JS_SOURCE_CONTEXT_NONE, _u(""), &object) == JsNoError);
  183. JsPropertyIdRef idRef = JS_INVALID_REFERENCE;
  184. JsValueRef result = JS_INVALID_REFERENCE;
  185. // delete property "a" triggers PathTypeHandler -> SimpleDictionaryTypeHandler
  186. REQUIRE(JsGetPropertyIdFromName(_u("a"), &idRef) == JsNoError);
  187. REQUIRE(JsDeleteProperty(object, idRef, false, &result) == JsNoError);
  188. // Now delete property "100". Bug causes we always delete "1" instead.
  189. REQUIRE(JsGetPropertyIdFromName(_u("100"), &idRef) == JsNoError);
  190. REQUIRE(JsDeleteProperty(object, idRef, false, &result) == JsNoError);
  191. bool has;
  192. JsValueRef indexRef = JS_INVALID_REFERENCE;
  193. REQUIRE(JsIntToNumber(100, &indexRef) == JsNoError);
  194. REQUIRE(JsHasIndexedProperty(object, indexRef, &has) == JsNoError);
  195. CHECK(!has); // index 100 should be deleted
  196. REQUIRE(JsIntToNumber(1, &indexRef) == JsNoError);
  197. REQUIRE(JsHasIndexedProperty(object, indexRef, &has) == JsNoError);
  198. CHECK(has); // index 1 should be intact
  199. }
  200. TEST_CASE("ApiTest_DeleteObjectIndexedPropertyBug", "[ApiTest]")
  201. {
  202. JsRTApiTest::RunWithAttributes(JsRTApiTest::DeleteObjectIndexedPropertyBug);
  203. }
  204. void CALLBACK ExternalObjectFinalizeCallback(void *data)
  205. {
  206. CHECK(data == (void *)0xdeadbeef);
  207. }
  208. void CrossContextSetPropertyTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  209. {
  210. bool hasExternalData;
  211. JsContextRef oldContext = JS_INVALID_REFERENCE, secondContext = JS_INVALID_REFERENCE, testContext = JS_INVALID_REFERENCE;
  212. JsValueRef secondValueRef = JS_INVALID_REFERENCE, secondObjectRef = JS_INVALID_REFERENCE, jsrtExternalObjectRef = JS_INVALID_REFERENCE, mainObjectRef = JS_INVALID_REFERENCE;
  213. JsPropertyIdRef idRef = JS_INVALID_REFERENCE;
  214. JsValueRef indexRef = JS_INVALID_REFERENCE;
  215. REQUIRE(JsGetCurrentContext(&oldContext) == JsNoError);
  216. REQUIRE(JsCreateObject(&mainObjectRef) == JsNoError);
  217. REQUIRE(JsGetPropertyIdFromName(_u("prop1"), &idRef) == JsNoError);
  218. REQUIRE(JsCreateContext(runtime, &secondContext) == JsNoError);
  219. REQUIRE(JsSetCurrentContext(secondContext) == JsNoError);
  220. REQUIRE(JsCreateObject(&secondObjectRef) == JsNoError);
  221. // Verify the main object is from first context
  222. REQUIRE(JsGetContextOfObject(mainObjectRef, &testContext) == JsNoError);
  223. REQUIRE(testContext == oldContext);
  224. // Create external Object in 2nd context which will be accessed in main context.
  225. REQUIRE(JsCreateExternalObject((void *)0xdeadbeef, ExternalObjectFinalizeCallback, &jsrtExternalObjectRef) == JsNoError);
  226. REQUIRE(JsIntToNumber(1, &secondValueRef) == JsNoError);
  227. REQUIRE(JsIntToNumber(2, &indexRef) == JsNoError);
  228. REQUIRE(JsSetCurrentContext(oldContext) == JsNoError);
  229. // Verify the second object is from second context
  230. REQUIRE(JsGetContextOfObject(secondObjectRef, &testContext) == JsNoError);
  231. CHECK(testContext == secondContext);
  232. REQUIRE(JsSetProperty(mainObjectRef, idRef, secondValueRef, false) == JsNoError);
  233. REQUIRE(JsSetProperty(mainObjectRef, idRef, secondObjectRef, false) == JsNoError);
  234. REQUIRE(JsSetIndexedProperty(mainObjectRef, indexRef, secondValueRef) == JsNoError);
  235. REQUIRE(JsSetIndexedProperty(mainObjectRef, indexRef, secondObjectRef) == JsNoError);
  236. REQUIRE(JsSetPrototype(jsrtExternalObjectRef, mainObjectRef) == JsNoError);
  237. REQUIRE(JsHasExternalData(jsrtExternalObjectRef, &hasExternalData) == JsNoError);
  238. REQUIRE(hasExternalData);
  239. }
  240. TEST_CASE("ApiTest_CrossContextSetPropertyTest", "[ApiTest]")
  241. {
  242. JsRTApiTest::RunWithAttributes(JsRTApiTest::CrossContextSetPropertyTest);
  243. }
  244. void CrossContextFunctionCall(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  245. {
  246. /*
  247. 1. function changeFoo() { foo = 100 }
  248. 2. CreateContext
  249. 3. Set f : changeFoo in newContext
  250. 4. Call f() from newContext
  251. */
  252. JsContextRef oldContext = JS_INVALID_REFERENCE, secondContext = JS_INVALID_REFERENCE;
  253. JsValueRef functionRef = JS_INVALID_REFERENCE, functionResultRef = JS_INVALID_REFERENCE, globalRef = JS_INVALID_REFERENCE, globalNewCtxRef = JS_INVALID_REFERENCE, valueRef = JS_INVALID_REFERENCE;
  254. JsPropertyIdRef propertyIdFRef = JS_INVALID_REFERENCE, propertyIdFooRef = JS_INVALID_REFERENCE, propertyIdChangeFooRef = JS_INVALID_REFERENCE;
  255. int answer;
  256. REQUIRE(JsGetCurrentContext(&oldContext) == JsNoError);
  257. REQUIRE(JsGetPropertyIdFromName(_u("f"), &propertyIdFRef) == JsNoError);
  258. REQUIRE(JsGetPropertyIdFromName(_u("foo"), &propertyIdFooRef) == JsNoError);
  259. REQUIRE(JsGetPropertyIdFromName(_u("changeFoo"), &propertyIdChangeFooRef) == JsNoError);
  260. //1. function changeFoo() { foo = 100 }
  261. REQUIRE(JsRunScript(_u("foo = 3; function changeFoo() { foo = 100 }"), JS_SOURCE_CONTEXT_NONE, _u(""), &functionResultRef) == JsNoError);
  262. REQUIRE(JsGetGlobalObject(&globalRef) == JsNoError);
  263. REQUIRE(JsGetProperty(globalRef, propertyIdChangeFooRef, &functionRef) == JsNoError);
  264. //2. CreateContext
  265. REQUIRE(JsCreateContext(runtime, &secondContext) == JsNoError);
  266. REQUIRE(JsSetCurrentContext(secondContext) == JsNoError);
  267. //3. Set f : changeFoo in newContext
  268. REQUIRE(JsGetGlobalObject(&globalNewCtxRef) == JsNoError);
  269. REQUIRE(JsSetProperty(globalNewCtxRef, propertyIdFRef, functionRef, false) == JsNoError);
  270. //4. Call 'f()' from newContext
  271. REQUIRE(JsRunScript(_u("f()"), JS_SOURCE_CONTEXT_NONE, _u(""), &functionResultRef) == JsNoError);
  272. //5. Change context to oldContext
  273. REQUIRE(JsSetCurrentContext(oldContext) == JsNoError);
  274. //6. Verify foo == 100
  275. REQUIRE(JsGetProperty(globalRef, propertyIdFooRef, &valueRef) == JsNoError);
  276. REQUIRE(JsNumberToInt(valueRef, &answer) == JsNoError);
  277. CHECK(answer == 100);
  278. }
  279. TEST_CASE("ApiTest_CrossContextFunctionCall", "[ApiTest]")
  280. {
  281. JsRTApiTest::RunWithAttributes(JsRTApiTest::CrossContextSetPropertyTest);
  282. }
  283. void ExternalDataOnJsrtContextTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  284. {
  285. int i = 5;
  286. void *j;
  287. JsContextRef currentContext = JS_INVALID_REFERENCE;
  288. REQUIRE(JsGetCurrentContext(&currentContext) == JsNoError);
  289. REQUIRE(JsSetContextData(currentContext, &i) == JsNoError);
  290. REQUIRE(JsGetContextData(currentContext, &j) == JsNoError);
  291. CHECK(static_cast<int*>(j) == &i);
  292. }
  293. TEST_CASE("ApiTest_ExternalDataOnJsrtContextTest", "[ApiTest]")
  294. {
  295. JsRTApiTest::RunWithAttributes(JsRTApiTest::ExternalDataOnJsrtContextTest);
  296. }
  297. void ArrayAndItemTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  298. {
  299. // Create some arrays
  300. JsValueRef array1 = JS_INVALID_REFERENCE;
  301. JsValueRef array2 = JS_INVALID_REFERENCE;
  302. REQUIRE(JsCreateArray(0, &array1) == JsNoError);
  303. REQUIRE(JsCreateArray(100, &array2) == JsNoError);
  304. // Create an object we'll treat like an array
  305. JsValueRef object = JS_INVALID_REFERENCE;
  306. REQUIRE(JsCreateObject(&object) == JsNoError);
  307. // Create an index value to use
  308. JsValueRef index = JS_INVALID_REFERENCE;
  309. REQUIRE(JsDoubleToNumber(3, &index) == JsNoError);
  310. JsValueRef value1 = JS_INVALID_REFERENCE;
  311. REQUIRE(JsPointerToString(_u("value1"), wcslen(_u("value1")), &value1) == JsNoError);
  312. // Do some index-based manipulation
  313. bool result;
  314. REQUIRE(JsHasIndexedProperty(array1, index, &result) == JsNoError);
  315. REQUIRE(result == false);
  316. REQUIRE(JsHasIndexedProperty(array2, index, &result) == JsNoError);
  317. REQUIRE(result == false);
  318. REQUIRE(JsHasIndexedProperty(object, index, &result) == JsNoError);
  319. REQUIRE(result == false);
  320. REQUIRE(JsSetIndexedProperty(array1, index, value1) == JsNoError);
  321. REQUIRE(JsSetIndexedProperty(array2, index, value1) == JsNoError);
  322. REQUIRE(JsSetIndexedProperty(object, index, value1) == JsNoError);
  323. REQUIRE(JsHasIndexedProperty(array1, index, &result) == JsNoError);
  324. REQUIRE(result == true);
  325. REQUIRE(JsHasIndexedProperty(array2, index, &result) == JsNoError);
  326. REQUIRE(result == true);
  327. REQUIRE(JsHasIndexedProperty(object, index, &result) == JsNoError);
  328. REQUIRE(result == true);
  329. JsValueRef value2 = JS_INVALID_REFERENCE;
  330. REQUIRE(JsGetIndexedProperty(array1, index, &value2) == JsNoError);
  331. REQUIRE(JsStrictEquals(value1, value2, &result) == JsNoError);
  332. REQUIRE(result == true);
  333. REQUIRE(JsGetIndexedProperty(array2, index, &value2) == JsNoError);
  334. REQUIRE(JsStrictEquals(value1, value2, &result) == JsNoError);
  335. REQUIRE(result == true);
  336. REQUIRE(JsGetIndexedProperty(object, index, &value2) == JsNoError);
  337. REQUIRE(JsStrictEquals(value1, value2, &result) == JsNoError);
  338. REQUIRE(result == true);
  339. REQUIRE(JsDeleteIndexedProperty(array1, index) == JsNoError);
  340. REQUIRE(JsDeleteIndexedProperty(array2, index) == JsNoError);
  341. REQUIRE(JsDeleteIndexedProperty(object, index) == JsNoError);
  342. REQUIRE(JsHasIndexedProperty(array1, index, &result) == JsNoError);
  343. REQUIRE(result == false);
  344. REQUIRE(JsHasIndexedProperty(array2, index, &result) == JsNoError);
  345. REQUIRE(result == false);
  346. REQUIRE(JsHasIndexedProperty(object, index, &result) == JsNoError);
  347. REQUIRE(result == false);
  348. }
  349. TEST_CASE("ApiTest_ArrayAndItemTest", "[ApiTest]")
  350. {
  351. JsRTApiTest::RunWithAttributes(JsRTApiTest::ArrayAndItemTest);
  352. }
  353. void EqualsTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  354. {
  355. // Create some values
  356. JsValueRef number1 = JS_INVALID_REFERENCE;
  357. REQUIRE(JsDoubleToNumber(1, &number1) == JsNoError);
  358. JsValueRef number2 = JS_INVALID_REFERENCE;
  359. REQUIRE(JsDoubleToNumber(2, &number2) == JsNoError);
  360. JsValueRef stringa = JS_INVALID_REFERENCE;
  361. REQUIRE(JsPointerToString(_u("1"), wcslen(_u("1")), &stringa) == JsNoError);
  362. JsValueRef stringb = JS_INVALID_REFERENCE;
  363. REQUIRE(JsPointerToString(_u("1"), wcslen(_u("1")), &stringb) == JsNoError);
  364. bool result;
  365. REQUIRE(JsEquals(number1, number1, &result) == JsNoError);
  366. CHECK(result == true);
  367. REQUIRE(JsEquals(number1, number2, &result) == JsNoError);
  368. CHECK(result == false);
  369. REQUIRE(JsEquals(number1, stringa, &result) == JsNoError);
  370. CHECK(result == true);
  371. REQUIRE(JsEquals(number1, stringb, &result) == JsNoError);
  372. CHECK(result == true);
  373. REQUIRE(JsEquals(number2, stringa, &result) == JsNoError);
  374. CHECK(result == false);
  375. REQUIRE(JsEquals(number2, stringb, &result) == JsNoError);
  376. CHECK(result == false);
  377. REQUIRE(JsEquals(stringa, stringb, &result) == JsNoError);
  378. CHECK(result == true);
  379. REQUIRE(JsStrictEquals(number1, number1, &result) == JsNoError);
  380. CHECK(result == true);
  381. REQUIRE(JsStrictEquals(number1, number2, &result) == JsNoError);
  382. CHECK(result == false);
  383. REQUIRE(JsStrictEquals(number1, stringa, &result) == JsNoError);
  384. CHECK(result == false);
  385. REQUIRE(JsStrictEquals(number1, stringb, &result) == JsNoError);
  386. CHECK(result == false);
  387. REQUIRE(JsStrictEquals(number2, stringa, &result) == JsNoError);
  388. CHECK(result == false);
  389. REQUIRE(JsStrictEquals(number2, stringb, &result) == JsNoError);
  390. CHECK(result == false);
  391. REQUIRE(JsStrictEquals(stringa, stringb, &result) == JsNoError);
  392. CHECK(result == true);
  393. }
  394. TEST_CASE("ApiTest_EqualsTest", "[ApiTest]")
  395. {
  396. JsRTApiTest::RunWithAttributes(JsRTApiTest::EqualsTest);
  397. }
  398. void InstanceOfTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  399. {
  400. JsValueRef F = JS_INVALID_REFERENCE;
  401. REQUIRE(JsRunScript(_u("F = function(){}"), JS_SOURCE_CONTEXT_NONE, _u(""), &F) == JsNoError);
  402. JsValueRef x = JS_INVALID_REFERENCE;
  403. REQUIRE(JsRunScript(_u("new F()"), JS_SOURCE_CONTEXT_NONE, _u(""), &x) == JsNoError);
  404. bool instanceOf;
  405. REQUIRE(JsInstanceOf(x, F, &instanceOf) == JsNoError);
  406. REQUIRE(instanceOf);
  407. REQUIRE(JsCreateObject(&x) == JsNoError);
  408. REQUIRE(JsInstanceOf(x, F, &instanceOf) == JsNoError);
  409. CHECK(instanceOf == false);
  410. }
  411. TEST_CASE("ApiTest_InstanceOfTest", "[ApiTest]")
  412. {
  413. JsRTApiTest::RunWithAttributes(JsRTApiTest::InstanceOfTest);
  414. }
  415. void LanguageTypeConversionTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  416. {
  417. JsValueRef value = JS_INVALID_REFERENCE;
  418. JsValueType type;
  419. JsValueRef asString = JS_INVALID_REFERENCE;
  420. LPCWSTR str = nullptr;
  421. size_t length;
  422. // Number
  423. REQUIRE(JsDoubleToNumber(3.141592, &value) == JsNoError);
  424. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  425. REQUIRE(type == JsNumber);
  426. double dbl = 0.0;
  427. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  428. REQUIRE(dbl == 3.141592);
  429. REQUIRE(JsPointerToString(_u("3.141592"), wcslen(_u("3.141592")), &asString) == JsNoError);
  430. REQUIRE(JsConvertValueToNumber(asString, &value) == JsNoError);
  431. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  432. REQUIRE(dbl == 3.141592);
  433. int intValue;
  434. REQUIRE(JsNumberToInt(value, &intValue) == JsNoError);
  435. CHECK(3 == intValue);
  436. REQUIRE(JsDoubleToNumber(2147483648.1, &value) == JsNoError);
  437. REQUIRE(JsNumberToInt(value, &intValue) == JsNoError);
  438. CHECK(INT_MIN == intValue);
  439. REQUIRE(JsDoubleToNumber(-2147483649.1, &value) == JsNoError);
  440. REQUIRE(JsNumberToInt(value, &intValue) == JsNoError);
  441. CHECK(2147483647 == intValue);
  442. // String
  443. REQUIRE(JsDoubleToNumber(3.141592, &value) == JsNoError);
  444. REQUIRE(JsConvertValueToString(value, &asString) == JsNoError);
  445. REQUIRE(JsStringToPointer(asString, &str, &length) == JsNoError);
  446. CHECK(!wcscmp(str, _u("3.141592")));
  447. REQUIRE(JsGetTrueValue(&value) == JsNoError);
  448. REQUIRE(JsConvertValueToString(value, &asString) == JsNoError);
  449. REQUIRE(JsGetValueType(asString, &type) == JsNoError);
  450. CHECK(type == JsString);
  451. REQUIRE(JsStringToPointer(asString, &str, &length) == JsNoError);
  452. CHECK(!wcscmp(str, _u("true")));
  453. // Undefined
  454. REQUIRE(JsGetUndefinedValue(&value) == JsNoError);
  455. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  456. CHECK(type == JsUndefined);
  457. // Null
  458. REQUIRE(JsGetNullValue(&value) == JsNoError);
  459. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  460. CHECK(type == JsNull);
  461. // Boolean
  462. REQUIRE(JsGetTrueValue(&value) == JsNoError);
  463. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  464. CHECK(type == JsBoolean);
  465. REQUIRE(JsGetFalseValue(&value) == JsNoError);
  466. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  467. CHECK(type == JsBoolean);
  468. bool boolValue;
  469. REQUIRE(JsBoolToBoolean(true, &value) == JsNoError);
  470. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  471. CHECK(type == JsBoolean);
  472. REQUIRE(JsBooleanToBool(value, &boolValue) == JsNoError);
  473. CHECK(boolValue == true);
  474. REQUIRE(JsPointerToString(_u("true"), wcslen(_u("true")), &asString) == JsNoError);
  475. REQUIRE(JsConvertValueToBoolean(asString, &value) == JsNoError);
  476. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  477. CHECK(type == JsBoolean);
  478. REQUIRE(JsBooleanToBool(value, &boolValue) == JsNoError);
  479. CHECK(boolValue == true);
  480. // Object
  481. REQUIRE(JsCreateObject(&value) == JsNoError);
  482. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  483. CHECK(type == JsObject);
  484. }
  485. TEST_CASE("ApiTest_LanguageTypeConversionTest", "[ApiTest]")
  486. {
  487. JsRTApiTest::RunWithAttributes(JsRTApiTest::LanguageTypeConversionTest);
  488. }
  489. JsValueRef CALLBACK ExternalFunctionCallback(JsValueRef /* function */, bool /* isConstructCall */, JsValueRef * /* args */, USHORT /* cargs */, void * /* callbackState */)
  490. {
  491. return nullptr;
  492. }
  493. void CALLBACK FinalizeCallback(JsValueRef object)
  494. {
  495. CHECK(object != JS_INVALID_REFERENCE);
  496. }
  497. void CALLBACK OldFinalizeCallback(void *data)
  498. {
  499. CHECK(data == nullptr);
  500. }
  501. JsValueRef CALLBACK ExternalFunctionPreScriptAbortionCallback(JsValueRef /* function */, bool /* isConstructCall */, JsValueRef * args /* args */, USHORT /* cargs */, void * /* callbackState */)
  502. {
  503. JsValueRef result = JS_INVALID_REFERENCE;
  504. const WCHAR *scriptText = nullptr;
  505. size_t scriptTextLen;
  506. REQUIRE(JsStringToPointer(args[0], &scriptText, &scriptTextLen) == JsNoError);
  507. REQUIRE(JsRunScript(scriptText, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsErrorScriptTerminated);
  508. return nullptr;
  509. }
  510. JsValueRef CALLBACK ExternalFunctionPostScriptAbortionCallback(JsValueRef /* function */, bool /* isConstructCall */, JsValueRef * args /* args */, USHORT /* cargs */, void * /* callbackState */)
  511. {
  512. JsValueRef result = JS_INVALID_REFERENCE;
  513. const WCHAR *scriptText = nullptr;
  514. size_t scriptTextLen;
  515. REQUIRE(JsStringToPointer(args[0], &scriptText, &scriptTextLen) == JsNoError);
  516. REQUIRE(JsRunScript(scriptText, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsErrorInDisabledState);
  517. return nullptr;
  518. }
  519. JsValueRef CALLBACK ErrorHandlingCallback(JsValueRef /* function */, bool /* isConstructCall */, JsValueRef * /* args */, USHORT /* cargs */, void * /* callbackState */)
  520. {
  521. JsValueRef result = JS_INVALID_REFERENCE;
  522. REQUIRE(JsRunScript(_u("new Error()"), JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsNoError);
  523. REQUIRE(JsSetException(result) == JsNoError);
  524. return nullptr;
  525. }
  526. void ExternalFunctionTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  527. {
  528. JsValueRef function = JS_INVALID_REFERENCE;
  529. REQUIRE(JsCreateFunction(ExternalFunctionCallback, nullptr, &function) == JsNoError);
  530. JsValueRef undefined = JS_INVALID_REFERENCE;
  531. REQUIRE(JsGetUndefinedValue(&undefined) == JsNoError);
  532. JsValueRef args[] = { undefined };
  533. REQUIRE(JsCallFunction(function, args, 1, nullptr) == JsNoError);
  534. JsValueRef result = JS_INVALID_REFERENCE;
  535. REQUIRE(JsConstructObject(function, args, 1, &result) == JsNoError);
  536. }
  537. TEST_CASE("ApiTest_ExternalFunctionTest", "[ApiTest]")
  538. {
  539. JsRTApiTest::RunWithAttributes(JsRTApiTest::ExternalFunctionTest);
  540. }
  541. JsValueRef CALLBACK ExternalEnhancedFunctionTestCallback(JsValueRef callee, JsValueRef *arguments, unsigned short argumentCount, JsNativeFunctionInfo *info, void *callbackData)
  542. {
  543. REQUIRE(callbackData != nullptr);
  544. REQUIRE(*static_cast<int*>(callbackData) == 123);
  545. REQUIRE(argumentCount == 2);
  546. bool success = false;
  547. JsValueRef _true;
  548. REQUIRE(JsGetTrueValue(&_true) == JsNoError);
  549. JsValueRef _false;
  550. REQUIRE(JsGetFalseValue(&_false) == JsNoError);
  551. REQUIRE(JsStrictEquals(_true, arguments[0], &success) == JsNoError);
  552. REQUIRE(success);
  553. REQUIRE(JsStrictEquals(_false, arguments[1], &success) == JsNoError);
  554. REQUIRE(success);
  555. REQUIRE(!info->isConstructCall);
  556. REQUIRE(info->thisArg == arguments[0]);
  557. JsValueRef undefined;
  558. REQUIRE(JsGetUndefinedValue(&undefined) == JsNoError);
  559. REQUIRE(JsStrictEquals(undefined, info->newTargetArg, &success) == JsNoError);
  560. REQUIRE(success);
  561. JsValueRef _null;
  562. REQUIRE(JsGetNullValue(&_null) == JsNoError);
  563. return _null;
  564. }
  565. JsValueRef CALLBACK ExternalEnhancedConstructorFunctionTestCallback(JsValueRef callee, JsValueRef *arguments, unsigned short argumentCount, JsNativeFunctionInfo *info, void *callbackData)
  566. {
  567. REQUIRE(callbackData != nullptr);
  568. REQUIRE(*static_cast<int*>(callbackData) == 456);
  569. REQUIRE(argumentCount == 3);
  570. bool success = false;
  571. JsValueRef _true;
  572. REQUIRE(JsGetTrueValue(&_true) == JsNoError);
  573. JsValueRef _false;
  574. REQUIRE(JsGetFalseValue(&_false) == JsNoError);
  575. JsValueRef _null;
  576. REQUIRE(JsGetNullValue(&_null) == JsNoError);
  577. REQUIRE(info->thisArg == arguments[0]);
  578. REQUIRE(JsStrictEquals(_true, arguments[1], &success) == JsNoError);
  579. REQUIRE(success);
  580. REQUIRE(JsStrictEquals(_false, arguments[2], &success) == JsNoError);
  581. REQUIRE(success);
  582. REQUIRE(info->isConstructCall);
  583. JsValueType t;
  584. REQUIRE(JsGetValueType(info->newTargetArg, &t) == JsNoError);
  585. REQUIRE(t == JsFunction);
  586. REQUIRE(JsGetValueType(info->thisArg, &t) == JsNoError);
  587. REQUIRE(t == JsObject);
  588. return info->thisArg;
  589. }
  590. void ExternalEnhancedFunctionTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  591. {
  592. int sentinel = 123;
  593. JsValueRef function = JS_INVALID_REFERENCE;
  594. REQUIRE(JsCreateEnhancedFunction(ExternalEnhancedFunctionTestCallback, nullptr, &sentinel, &function) == JsNoError);
  595. JsValueRef _true;
  596. REQUIRE(JsGetTrueValue(&_true) == JsNoError);
  597. JsValueRef _false;
  598. REQUIRE(JsGetFalseValue(&_false) == JsNoError);
  599. JsValueRef args[2] = { _true, _false };
  600. JsValueRef _null;
  601. REQUIRE(JsGetNullValue(&_null) == JsNoError);
  602. JsValueRef result;
  603. REQUIRE(JsCallFunction(function, args, 2, &result) == JsNoError);
  604. bool success;
  605. REQUIRE(JsStrictEquals(_null, result, &success) == JsNoError);
  606. REQUIRE(success);
  607. sentinel = 456;
  608. function = JS_INVALID_REFERENCE;
  609. REQUIRE(JsCreateEnhancedFunction(ExternalEnhancedConstructorFunctionTestCallback, nullptr, &sentinel, &function) == JsNoError);
  610. JsValueRef ctorArgs[3] = { _null, _true, _false };
  611. REQUIRE(JsConstructObject(function, ctorArgs, 3, &result) == JsNoError);
  612. JsValueType t;
  613. REQUIRE(JsGetValueType(result, &t) == JsNoError);
  614. REQUIRE(t == JsObject);
  615. }
  616. TEST_CASE("ApiTest_ExternalEnhancedFunctionTest", "[ApiTest]")
  617. {
  618. JsRTApiTest::RunWithAttributes(JsRTApiTest::ExternalEnhancedFunctionTest);
  619. }
  620. struct ExternalEnhancedBaseClassFunctionTestInfo
  621. {
  622. JsValueRef derived;
  623. JsValueRef base;
  624. };
  625. JsValueRef CALLBACK ExternalEnhancedBaseClassFunctionTestCallback(JsValueRef callee, JsValueRef *arguments, unsigned short argumentCount, JsNativeFunctionInfo *info, void *callbackData)
  626. {
  627. REQUIRE(callbackData != nullptr);
  628. ExternalEnhancedBaseClassFunctionTestInfo* testinfo = (ExternalEnhancedBaseClassFunctionTestInfo*)callbackData;
  629. JsValueType t;
  630. REQUIRE(JsGetValueType(testinfo->derived, &t) == JsNoError);
  631. REQUIRE(t == JsFunction);
  632. REQUIRE(JsGetValueType(testinfo->base, &t) == JsNoError);
  633. REQUIRE(t == JsFunction);
  634. REQUIRE(argumentCount == 2);
  635. JsPropertyIdRef propId;
  636. bool success = false;
  637. JsValueRef _true;
  638. REQUIRE(JsGetTrueValue(&_true) == JsNoError);
  639. JsValueRef _false;
  640. REQUIRE(JsGetFalseValue(&_false) == JsNoError);
  641. REQUIRE(info->thisArg == arguments[0]);
  642. REQUIRE(JsStrictEquals(_true, arguments[1], &success) == JsNoError);
  643. REQUIRE(success);
  644. REQUIRE(info->isConstructCall);
  645. REQUIRE(JsGetValueType(info->newTargetArg, &t) == JsNoError);
  646. REQUIRE(t == JsFunction);
  647. REQUIRE(JsGetValueType(info->thisArg, &t) == JsNoError);
  648. REQUIRE(t == JsObject);
  649. // new.target === Derived
  650. REQUIRE(JsStrictEquals(info->newTargetArg, testinfo->derived, &success) == JsNoError);
  651. REQUIRE(success);
  652. // this.constructor === Derived
  653. REQUIRE(JsGetPropertyIdFromName(_u("constructor"), &propId) == JsNoError);
  654. JsValueRef thisCtor = JS_INVALID_REFERENCE;
  655. REQUIRE(JsGetProperty(info->thisArg, propId, &thisCtor) == JsNoError);
  656. REQUIRE(JsStrictEquals(thisCtor, testinfo->derived, &success) == JsNoError);
  657. REQUIRE(success);
  658. // this.__proto__ === Derived.prototype
  659. JsValueRef thisProto = JS_INVALID_REFERENCE;
  660. REQUIRE(JsGetPrototype(info->thisArg, &thisProto) == JsNoError);
  661. JsValueRef derivedPrototype = JS_INVALID_REFERENCE;
  662. REQUIRE(JsGetPropertyIdFromName(_u("prototype"), &propId) == JsNoError);
  663. REQUIRE(JsGetProperty(testinfo->derived, propId, &derivedPrototype) == JsNoError);
  664. REQUIRE(JsStrictEquals(thisProto, derivedPrototype, &success) == JsNoError);
  665. REQUIRE(success);
  666. return info->thisArg;
  667. }
  668. void ExternalEnhancedBaseClassFunctionTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  669. {
  670. ExternalEnhancedBaseClassFunctionTestInfo info = { nullptr, nullptr };
  671. JsValueRef name = JS_INVALID_REFERENCE;
  672. REQUIRE(JsCreateString("BaseClass", 10, &name) == JsNoError);
  673. JsValueRef base = JS_INVALID_REFERENCE;
  674. REQUIRE(JsCreateEnhancedFunction(ExternalEnhancedBaseClassFunctionTestCallback, name, &info, &base) == JsNoError);
  675. info.base = base;
  676. JsValueRef global = JS_INVALID_REFERENCE;
  677. REQUIRE(JsGetGlobalObject(&global) == JsNoError);
  678. JsPropertyIdRef propId;
  679. REQUIRE(JsGetPropertyIdFromName(_u("BaseClass"), &propId) == JsNoError);
  680. REQUIRE(JsSetProperty(global, propId, base, false) == JsNoError);
  681. bool success = false;
  682. JsValueType t;
  683. JsValueRef derived = JS_INVALID_REFERENCE;
  684. REQUIRE(JsRunScript(
  685. _u("class Derived extends BaseClass {") \
  686. _u(" constructor() {") \
  687. _u(" super(true);") \
  688. _u(" }") \
  689. _u("};"), JS_SOURCE_CONTEXT_NONE, _u(""), &derived) == JsNoError);
  690. info.derived = derived;
  691. REQUIRE(JsGetValueType(derived, &t) == JsNoError);
  692. REQUIRE(t == JsFunction);
  693. JsValueRef instance = JS_INVALID_REFERENCE;
  694. REQUIRE(JsRunScript(
  695. _u("new Derived();"), JS_SOURCE_CONTEXT_NONE, _u(""), &instance) == JsNoError);
  696. REQUIRE(JsGetValueType(instance, &t) == JsNoError);
  697. REQUIRE(t == JsObject);
  698. // instance.constructor === Derived
  699. REQUIRE(JsGetPropertyIdFromName(_u("constructor"), &propId) == JsNoError);
  700. JsValueRef instanceCtor = JS_INVALID_REFERENCE;
  701. REQUIRE(JsGetProperty(instance, propId, &instanceCtor) == JsNoError);
  702. REQUIRE(JsStrictEquals(instanceCtor, derived, &success) == JsNoError);
  703. REQUIRE(success);
  704. // instance.__proto__ === Derived.prototype
  705. JsValueRef instanceProto = JS_INVALID_REFERENCE;
  706. REQUIRE(JsGetPrototype(instance, &instanceProto) == JsNoError);
  707. JsValueRef derivedPrototype = JS_INVALID_REFERENCE;
  708. REQUIRE(JsGetPropertyIdFromName(_u("prototype"), &propId) == JsNoError);
  709. REQUIRE(JsGetProperty(derived, propId, &derivedPrototype) == JsNoError);
  710. REQUIRE(JsStrictEquals(instanceProto, derivedPrototype, &success) == JsNoError);
  711. REQUIRE(success);
  712. }
  713. TEST_CASE("ApiTest_ExternalEnhancedBaseClassFunctionTest", "[ApiTest]")
  714. {
  715. JsRTApiTest::RunWithAttributes(JsRTApiTest::ExternalEnhancedBaseClassFunctionTest);
  716. }
  717. void ExternalFunctionNameTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  718. {
  719. auto testConstructorName = [=](JsValueRef function, PCWCHAR expectedName, size_t expectedNameLength)
  720. {
  721. JsValueRef undefined = JS_INVALID_REFERENCE;
  722. REQUIRE(JsGetUndefinedValue(&undefined) == JsNoError);
  723. JsValueRef args[] = { undefined };
  724. JsValueRef obj = JS_INVALID_REFERENCE, constructor = JS_INVALID_REFERENCE, name = JS_INVALID_REFERENCE;
  725. JsPropertyIdRef propId = JS_INVALID_REFERENCE;
  726. REQUIRE(JsConstructObject(function, args, 1, &obj) == JsNoError);
  727. REQUIRE(JsGetPropertyIdFromName(_u("constructor"), &propId) == JsNoError);
  728. REQUIRE(JsGetProperty(obj, propId, &constructor) == JsNoError);
  729. REQUIRE(JsGetPropertyIdFromName(_u("name"), &propId) == JsNoError);
  730. REQUIRE(JsGetProperty(constructor, propId, &name) == JsNoError);
  731. PCWCHAR actualName = nullptr;
  732. size_t actualNameLength;
  733. REQUIRE(JsStringToPointer(name, &actualName, &actualNameLength) == JsNoError);
  734. CHECK(expectedNameLength == actualNameLength);
  735. CHECK(wcscmp(expectedName, actualName) == 0);
  736. };
  737. auto testToStringResult = [=](JsValueRef function, PCWCHAR expectedResult, size_t expectedResultLength)
  738. {
  739. JsValueRef actualResult = JS_INVALID_REFERENCE;
  740. REQUIRE(JsConvertValueToString(function, &actualResult) == JsNoError);
  741. PCWCHAR actualResultString = nullptr;
  742. size_t actualResultLength;
  743. REQUIRE(JsStringToPointer(actualResult, &actualResultString, &actualResultLength) == JsNoError);
  744. CHECK(expectedResultLength == actualResultLength);
  745. CHECK(wcscmp(expectedResult, actualResultString) == 0);
  746. };
  747. JsValueRef function = JS_INVALID_REFERENCE;
  748. REQUIRE(JsCreateFunction(ExternalFunctionCallback, nullptr, &function) == JsNoError);
  749. testConstructorName(function, _u(""), 0);
  750. WCHAR name[] = _u("FooName");
  751. JsValueRef nameString = JS_INVALID_REFERENCE;
  752. REQUIRE(JsPointerToString(name, _countof(name) - 1, &nameString) == JsNoError);
  753. REQUIRE(JsCreateNamedFunction(nameString, ExternalFunctionCallback, nullptr, &function) == JsNoError);
  754. testConstructorName(function, name, _countof(name) - 1);
  755. WCHAR toStringExpectedResult[] = _u("function FooName() { [native code] }");
  756. testToStringResult(function, toStringExpectedResult, _countof(toStringExpectedResult) - 1);
  757. // Calling toString multiple times should return the same result.
  758. testToStringResult(function, toStringExpectedResult, _countof(toStringExpectedResult) - 1);
  759. }
  760. TEST_CASE("ApiTest_ExternalFunctionNameTest", "[ApiTest]")
  761. {
  762. JsRTApiTest::RunWithAttributes(JsRTApiTest::ExternalFunctionNameTest);
  763. }
  764. void ErrorHandlingTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  765. {
  766. // Run a script to setup some globals
  767. LPCWSTR script = nullptr;
  768. REQUIRE(FileLoadHelpers::LoadScriptFromFile("ErrorHandling.js", script) == S_OK);
  769. REQUIRE(script != nullptr);
  770. REQUIRE(JsRunScript(script, JS_SOURCE_CONTEXT_NONE, _u(""), nullptr) == JsNoError);
  771. JsValueRef global = JS_INVALID_REFERENCE;
  772. REQUIRE(JsGetGlobalObject(&global) == JsNoError);
  773. JsPropertyIdRef name = JS_INVALID_REFERENCE;
  774. JsValueRef result = JS_INVALID_REFERENCE;
  775. JsValueRef exception = JS_INVALID_REFERENCE;
  776. JsValueRef function = JS_INVALID_REFERENCE;
  777. JsValueType type;
  778. JsValueRef args[] = { GetUndefined() };
  779. // throw from script, handle in host
  780. REQUIRE(JsGetPropertyIdFromName(_u("throwAtHost"), &name) == JsNoError);
  781. REQUIRE(JsGetProperty(global, name, &function) == JsNoError);
  782. REQUIRE(JsCallFunction(function, args, _countof(args), &result) == JsErrorScriptException);
  783. REQUIRE(JsGetAndClearException(&exception) == JsNoError);
  784. // setup a host callback for the next couple of tests
  785. REQUIRE(JsCreateFunction(ErrorHandlingCallback, nullptr, &result) == JsNoError);
  786. REQUIRE(JsGetValueType(result, &type) == JsNoError);
  787. REQUIRE(type == JsFunction);
  788. REQUIRE(JsGetPropertyIdFromName(_u("callHost"), &name) == JsNoError);
  789. REQUIRE(JsSetProperty(global, name, result, true) == JsNoError);
  790. // throw from host callback, catch in script
  791. REQUIRE(JsGetPropertyIdFromName(_u("callHostWithTryCatch"), &name) == JsNoError);
  792. REQUIRE(JsGetProperty(global, name, &function) == JsNoError);
  793. REQUIRE(JsCallFunction(function, args, _countof(args), &result) == JsNoError);
  794. // throw from host callback, through script, handle in host
  795. REQUIRE(JsGetPropertyIdFromName(_u("callHostWithNoTryCatch"), &name) == JsNoError);
  796. REQUIRE(JsGetProperty(global, name, &function) == JsNoError);
  797. REQUIRE(JsCallFunction(function, args, _countof(args), &result) == JsErrorScriptException);
  798. }
  799. TEST_CASE("ApiTest_ErrorHandlingTest", "[ApiTest]")
  800. {
  801. JsRTApiTest::RunWithAttributes(JsRTApiTest::ErrorHandlingTest);
  802. }
  803. void EngineFlagTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  804. {
  805. JsValueRef ret = JS_INVALID_REFERENCE;
  806. REQUIRE(JsRunScript(_u("new ActiveXObject('Scripting.FileSystemObject')"), JS_SOURCE_CONTEXT_NONE, _u(""), &ret) == JsErrorScriptException);
  807. REQUIRE(JsGetAndClearException(&ret) == JsNoError);
  808. }
  809. TEST_CASE("ApiTest_EngineFlagTest", "[ApiTest]")
  810. {
  811. JsRTApiTest::RunWithAttributes(JsRTApiTest::EngineFlagTest);
  812. }
  813. void ExceptionHandlingTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  814. {
  815. bool value;
  816. JsValueRef exception = JS_INVALID_REFERENCE;
  817. JsValueRef exceptionMetadata = JS_INVALID_REFERENCE;
  818. JsValueRef metadataValue = JS_INVALID_REFERENCE;
  819. JsPropertyIdRef property = JS_INVALID_REFERENCE;
  820. JsValueType type;
  821. REQUIRE(JsHasException(&value) == JsNoError);
  822. CHECK(value == false);
  823. REQUIRE(JsRunScript(_u("throw new Error()"), JS_SOURCE_CONTEXT_NONE, _u(""), nullptr) == JsErrorScriptException);
  824. REQUIRE(JsHasException(&value) == JsNoError);
  825. CHECK(value == true);
  826. REQUIRE(JsGetAndClearException(&exception) == JsNoError);
  827. REQUIRE(JsHasException(&value) == JsNoError);
  828. CHECK(value == false);
  829. REQUIRE(JsGetValueType(exception, &type) == JsNoError);
  830. CHECK(type == JsError);
  831. REQUIRE(JsSetException(exception) == JsNoError);
  832. REQUIRE(JsHasException(&value) == JsNoError);
  833. CHECK(value == true);
  834. REQUIRE(JsGetAndClearExceptionWithMetadata(&exceptionMetadata) == JsNoError);
  835. REQUIRE(JsHasException(&value) == JsNoError);
  836. CHECK(value == false);
  837. REQUIRE(JsGetPropertyIdFromName(_u("exception"), &property) == JsNoError);
  838. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  839. CHECK(metadataValue == exception);
  840. REQUIRE(JsGetPropertyIdFromName(_u("line"), &property) == JsNoError);
  841. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  842. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  843. CHECK(type == JsNumber);
  844. REQUIRE(JsGetPropertyIdFromName(_u("column"), &property) == JsNoError);
  845. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  846. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  847. CHECK(type == JsNumber);
  848. REQUIRE(JsGetPropertyIdFromName(_u("length"), &property) == JsNoError);
  849. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  850. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  851. CHECK(type == JsNumber);
  852. REQUIRE(JsGetPropertyIdFromName(_u("url"), &property) == JsNoError);
  853. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  854. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  855. CHECK(type == JsString);
  856. REQUIRE(JsGetPropertyIdFromName(_u("source"), &property) == JsNoError);
  857. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  858. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  859. CHECK(type == JsString);
  860. REQUIRE(JsHasException(&value) == JsNoError);
  861. CHECK(value == false);
  862. REQUIRE(JsGetAndClearExceptionWithMetadata(&exceptionMetadata) == JsErrorInvalidArgument);
  863. CHECK(exceptionMetadata == JS_INVALID_REFERENCE);
  864. REQUIRE(JsRunScript(_u("@ bad syntax"), JS_SOURCE_CONTEXT_NONE, _u(""), nullptr) == JsErrorScriptCompile);
  865. REQUIRE(JsHasException(&value) == JsNoError);
  866. CHECK(value == true);
  867. REQUIRE(JsGetAndClearExceptionWithMetadata(&exceptionMetadata) == JsNoError);
  868. REQUIRE(JsHasException(&value) == JsNoError);
  869. CHECK(value == false);
  870. REQUIRE(JsGetPropertyIdFromName(_u("exception"), &property) == JsNoError);
  871. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  872. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  873. CHECK(type == JsError);
  874. REQUIRE(JsGetPropertyIdFromName(_u("line"), &property) == JsNoError);
  875. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  876. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  877. CHECK(type == JsNumber);
  878. REQUIRE(JsGetPropertyIdFromName(_u("column"), &property) == JsNoError);
  879. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  880. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  881. CHECK(type == JsNumber);
  882. REQUIRE(JsGetPropertyIdFromName(_u("length"), &property) == JsNoError);
  883. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  884. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  885. CHECK(type == JsNumber);
  886. REQUIRE(JsGetPropertyIdFromName(_u("url"), &property) == JsNoError);
  887. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  888. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  889. CHECK(type == JsString);
  890. REQUIRE(JsGetPropertyIdFromName(_u("source"), &property) == JsNoError);
  891. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  892. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  893. CHECK(type == JsString);
  894. // Following requires eval to be enabled - no point in testing it if we've disabled eval
  895. if (!(attributes & JsRuntimeAttributeDisableEval))
  896. {
  897. REQUIRE(JsRunScript(_u("eval('var a = b');"), JS_SOURCE_CONTEXT_NONE, _u(""), nullptr) == JsErrorScriptException);
  898. REQUIRE(JsHasException(&value) == JsNoError);
  899. CHECK(value == true);
  900. REQUIRE(JsGetAndClearExceptionWithMetadata(&exceptionMetadata) == JsNoError);
  901. REQUIRE(JsHasException(&value) == JsNoError);
  902. CHECK(value == false);
  903. REQUIRE(JsGetPropertyIdFromName(_u("exception"), &property) == JsNoError);
  904. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  905. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  906. CHECK(type == JsError);
  907. REQUIRE(JsGetPropertyIdFromName(_u("line"), &property) == JsNoError);
  908. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  909. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  910. CHECK(type == JsNumber);
  911. REQUIRE(JsGetPropertyIdFromName(_u("column"), &property) == JsNoError);
  912. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  913. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  914. CHECK(type == JsNumber);
  915. REQUIRE(JsGetPropertyIdFromName(_u("length"), &property) == JsNoError);
  916. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  917. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  918. CHECK(type == JsNumber);
  919. REQUIRE(JsGetPropertyIdFromName(_u("url"), &property) == JsNoError);
  920. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  921. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  922. CHECK(type == JsString);
  923. REQUIRE(JsGetPropertyIdFromName(_u("source"), &property) == JsNoError);
  924. REQUIRE(JsGetProperty(exceptionMetadata, property, &metadataValue) == JsNoError);
  925. REQUIRE(JsGetValueType(metadataValue, &type) == JsNoError);
  926. CHECK(type == JsString);
  927. }
  928. }
  929. TEST_CASE("ApiTest_ExceptionHandlingTest", "[ApiTest]")
  930. {
  931. JsRTApiTest::RunWithAttributes(JsRTApiTest::ExceptionHandlingTest);
  932. }
  933. void ScriptCompileErrorTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  934. {
  935. JsValueRef error = JS_INVALID_REFERENCE;
  936. REQUIRE(JsRunScript(
  937. _u("if (x > 0) { \n") \
  938. _u(" x = 1; \n") \
  939. _u("}}"),
  940. JS_SOURCE_CONTEXT_NONE, _u(""), nullptr) == JsErrorScriptCompile);
  941. REQUIRE(JsGetAndClearException(&error) == JsNoError);
  942. JsPropertyIdRef property = JS_INVALID_REFERENCE;
  943. JsValueRef value = JS_INVALID_REFERENCE;
  944. LPCWSTR str = nullptr;
  945. size_t length;
  946. REQUIRE(JsGetPropertyIdFromName(_u("message"), &property) == JsNoError);
  947. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  948. REQUIRE(JsStringToPointer(value, &str, &length) == JsNoError);
  949. CHECK(wcscmp(_u("Syntax error"), str) == 0);
  950. double dbl;
  951. REQUIRE(JsGetPropertyIdFromName(_u("line"), &property) == JsNoError);
  952. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  953. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  954. CHECK(2 == dbl);
  955. REQUIRE(JsGetPropertyIdFromName(_u("column"), &property) == JsNoError);
  956. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  957. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  958. CHECK(1 == dbl);
  959. REQUIRE(JsGetPropertyIdFromName(_u("length"), &property) == JsNoError);
  960. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  961. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  962. CHECK(1 == dbl);
  963. REQUIRE(JsGetPropertyIdFromName(_u("source"), &property) == JsNoError);
  964. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  965. REQUIRE(JsStringToPointer(value, &str, &length) == JsNoError);
  966. CHECK(wcscmp(_u("}}"), str) == 0);
  967. REQUIRE(JsRunScript(
  968. _u("var for = 10;\n"),
  969. JS_SOURCE_CONTEXT_NONE, _u(""), nullptr) == JsErrorScriptCompile);
  970. REQUIRE(JsGetAndClearException(&error) == JsNoError);
  971. REQUIRE(JsGetPropertyIdFromName(_u("message"), &property) == JsNoError);
  972. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  973. REQUIRE(JsStringToPointer(value, &str, &length) == JsNoError);
  974. CHECK(wcscmp(_u("The use of a keyword for an identifier is invalid"), str) == 0);
  975. REQUIRE(JsGetPropertyIdFromName(_u("line"), &property) == JsNoError);
  976. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  977. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  978. CHECK(0 == dbl);
  979. REQUIRE(JsGetPropertyIdFromName(_u("column"), &property) == JsNoError);
  980. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  981. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  982. CHECK(4 == dbl);
  983. REQUIRE(JsGetPropertyIdFromName(_u("length"), &property) == JsNoError);
  984. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  985. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  986. CHECK(3 == dbl);
  987. REQUIRE(JsGetPropertyIdFromName(_u("source"), &property) == JsNoError);
  988. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  989. REQUIRE(JsStringToPointer(value, &str, &length) == JsNoError);
  990. CHECK(wcscmp(_u("var for = 10;"), str) == 0);
  991. }
  992. TEST_CASE("ApiTest_ScriptCompileErrorTest", "[ApiTest]")
  993. {
  994. JsRTApiTest::RunWithAttributes(JsRTApiTest::ScriptCompileErrorTest);
  995. }
  996. void ObjectTests(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  997. {
  998. LPCWSTR script = _u("x = { a: \"abc\", b: \"def\", c: \"ghi\" }; x");
  999. JsValueRef result = JS_INVALID_REFERENCE;
  1000. JsValueRef propertyNames = JS_INVALID_REFERENCE;
  1001. REQUIRE(JsRunScript(script, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsNoError);
  1002. REQUIRE(JsGetOwnPropertyNames(result, &propertyNames) == JsNoError);
  1003. for (int index = 0; index < 3; index++)
  1004. {
  1005. JsValueRef indexValue = JS_INVALID_REFERENCE;
  1006. REQUIRE(JsDoubleToNumber(index, &indexValue) == JsNoError);
  1007. JsValueRef nameValue = JS_INVALID_REFERENCE;
  1008. REQUIRE(JsGetIndexedProperty(propertyNames, indexValue, &nameValue) == JsNoError);
  1009. const WCHAR *name = nullptr;
  1010. size_t length;
  1011. REQUIRE(JsStringToPointer(nameValue, &name, &length) == JsNoError);
  1012. REQUIRE(length == 1);
  1013. #pragma prefast(suppress:__WARNING_MAYBE_UNINIT_VAR, "The require on the previous line should ensure that name[0] is initialized")
  1014. CHECK(name[0] == ('a' + index));
  1015. }
  1016. }
  1017. TEST_CASE("ApiTest_ObjectTests", "[ApiTest]")
  1018. {
  1019. JsRTApiTest::RunWithAttributes(JsRTApiTest::ObjectTests);
  1020. }
  1021. void SymbolTests(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1022. {
  1023. JsValueRef object = JS_INVALID_REFERENCE;
  1024. JsValueRef symbol1 = JS_INVALID_REFERENCE;
  1025. JsValueRef string1 = JS_INVALID_REFERENCE;
  1026. JsValueRef symbol2 = JS_INVALID_REFERENCE;
  1027. JsValueRef value = JS_INVALID_REFERENCE;
  1028. JsPropertyIdRef propertyId = JS_INVALID_REFERENCE;
  1029. JsValueRef outValue = JS_INVALID_REFERENCE;
  1030. JsValueRef propertySymbols = JS_INVALID_REFERENCE;
  1031. const WCHAR* name = nullptr;
  1032. JsPropertyIdType propertyIdType;
  1033. REQUIRE(JsCreateObject(&object) == JsNoError);
  1034. REQUIRE(JsGetPropertyIdFromSymbol(object, &propertyId) == JsErrorPropertyNotSymbol);
  1035. REQUIRE(JsPointerToString(_u("abc"), 3, &string1) == JsNoError);
  1036. REQUIRE(JsCreateSymbol(string1, &symbol1) == JsNoError);
  1037. REQUIRE(JsCreateSymbol(JS_INVALID_REFERENCE, &symbol2) == JsNoError);
  1038. REQUIRE(JsIntToNumber(1, &value) == JsNoError);
  1039. REQUIRE(JsGetPropertyIdFromSymbol(symbol1, &propertyId) == JsNoError);
  1040. REQUIRE(JsGetPropertyNameFromId(propertyId, &name) == JsErrorPropertyNotString);
  1041. REQUIRE(JsGetPropertyIdType(propertyId, &propertyIdType) == JsNoError);
  1042. CHECK(propertyIdType == JsPropertyIdTypeSymbol);
  1043. JsValueRef symbol11 = JS_INVALID_REFERENCE;
  1044. bool resultBool;
  1045. REQUIRE(JsGetSymbolFromPropertyId(propertyId, &symbol11) == JsNoError);
  1046. REQUIRE(JsEquals(symbol1, symbol11, &resultBool) == JsNoError);
  1047. CHECK(resultBool);
  1048. REQUIRE(JsStrictEquals(symbol1, symbol11, &resultBool) == JsNoError);
  1049. CHECK(resultBool);
  1050. REQUIRE(JsSetProperty(object, propertyId, value, true) == JsNoError);
  1051. REQUIRE(JsGetProperty(object, propertyId, &outValue) == JsNoError);
  1052. CHECK(value == outValue);
  1053. REQUIRE(JsGetPropertyIdFromSymbol(symbol2, &propertyId) == JsNoError);
  1054. REQUIRE(JsSetProperty(object, propertyId, value, true) == JsNoError);
  1055. REQUIRE(JsGetProperty(object, propertyId, &outValue) == JsNoError);
  1056. CHECK(value == outValue);
  1057. JsValueType type;
  1058. JsValueRef index = JS_INVALID_REFERENCE;
  1059. REQUIRE(JsGetOwnPropertySymbols(object, &propertySymbols) == JsNoError);
  1060. REQUIRE(JsIntToNumber(0, &index) == JsNoError);
  1061. REQUIRE(JsGetIndexedProperty(propertySymbols, index, &outValue) == JsNoError);
  1062. REQUIRE(JsGetValueType(outValue, &type) == JsNoError);
  1063. CHECK(type == JsSymbol);
  1064. REQUIRE(JsGetPropertyIdFromSymbol(outValue, &propertyId) == JsNoError);
  1065. REQUIRE(JsGetProperty(object, propertyId, &outValue) == JsNoError);
  1066. CHECK(value == outValue);
  1067. REQUIRE(JsIntToNumber(1, &index) == JsNoError);
  1068. REQUIRE(JsGetIndexedProperty(propertySymbols, index, &outValue) == JsNoError);
  1069. REQUIRE(JsGetValueType(outValue, &type) == JsNoError);
  1070. CHECK(type == JsSymbol);
  1071. REQUIRE(JsGetPropertyIdFromSymbol(outValue, &propertyId) == JsNoError);
  1072. REQUIRE(JsGetProperty(object, propertyId, &outValue) == JsNoError);
  1073. CHECK(value == outValue);
  1074. }
  1075. TEST_CASE("ApiTest_SymbolTests", "[ApiTest]")
  1076. {
  1077. JsRTApiTest::RunWithAttributes(JsRTApiTest::SymbolTests);
  1078. }
  1079. void ByteCodeTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1080. {
  1081. LPCWSTR script = _u("function test() { return true; }; test();");
  1082. JsValueRef result = JS_INVALID_REFERENCE;
  1083. JsValueType type;
  1084. bool boolValue;
  1085. BYTE *compiledScript = nullptr;
  1086. unsigned int scriptSize = 0;
  1087. REQUIRE(JsSerializeScript(script, compiledScript, &scriptSize) == JsNoError);
  1088. compiledScript = new BYTE[scriptSize];
  1089. unsigned int newScriptSize = scriptSize;
  1090. REQUIRE(JsSerializeScript(script, compiledScript, &newScriptSize) == JsNoError);
  1091. CHECK(newScriptSize == scriptSize);
  1092. REQUIRE(JsRunSerializedScript(script, compiledScript, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsNoError);
  1093. REQUIRE(JsGetValueType(result, &type) == JsNoError);
  1094. REQUIRE(JsBooleanToBool(result, &boolValue) == JsNoError);
  1095. CHECK(boolValue);
  1096. JsRuntimeHandle second = JS_INVALID_RUNTIME_HANDLE;
  1097. JsContextRef secondContext = JS_INVALID_REFERENCE, current = JS_INVALID_REFERENCE;
  1098. REQUIRE(JsCreateRuntime(attributes, NULL, &second) == JsNoError);
  1099. REQUIRE(JsCreateContext(second, &secondContext) == JsNoError);
  1100. REQUIRE(JsGetCurrentContext(&current) == JsNoError);
  1101. REQUIRE(JsSetCurrentContext(secondContext) == JsNoError);
  1102. REQUIRE(JsRunSerializedScript(script, compiledScript, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsNoError);
  1103. REQUIRE(JsGetValueType(result, &type) == JsNoError);
  1104. REQUIRE(JsBooleanToBool(result, &boolValue) == JsNoError);
  1105. CHECK(boolValue);
  1106. REQUIRE(JsSetCurrentContext(current) == JsNoError);
  1107. REQUIRE(JsDisposeRuntime(second) == JsNoError);
  1108. delete[] compiledScript;
  1109. }
  1110. TEST_CASE("ApiTest_ByteCodeTest", "[ApiTest]")
  1111. {
  1112. JsRTApiTest::RunWithAttributes(JsRTApiTest::ByteCodeTest);
  1113. }
  1114. #define BYTECODEWITHCALLBACK_METHODBODY _u("function test() { return true; }")
  1115. typedef struct _ByteCodeCallbackTracker
  1116. {
  1117. bool loadedScript;
  1118. bool unloadedScript;
  1119. LPCWSTR script;
  1120. } ByteCodeCallbackTracker;
  1121. void ByteCodeWithCallbackTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1122. {
  1123. LPCWSTR fn_decl = BYTECODEWITHCALLBACK_METHODBODY;
  1124. LPCWSTR script = BYTECODEWITHCALLBACK_METHODBODY _u("; test();");
  1125. LPCWSTR scriptFnToString = BYTECODEWITHCALLBACK_METHODBODY _u("; test.toString();");
  1126. JsValueRef result = JS_INVALID_REFERENCE;
  1127. JsValueType type;
  1128. bool boolValue;
  1129. BYTE *compiledScript = nullptr;
  1130. unsigned int scriptSize = 0;
  1131. const WCHAR *stringValue;
  1132. size_t stringLength;
  1133. ByteCodeCallbackTracker tracker = {};
  1134. JsRuntimeHandle first = JS_INVALID_RUNTIME_HANDLE, second = JS_INVALID_RUNTIME_HANDLE;
  1135. JsContextRef firstContext = JS_INVALID_REFERENCE, secondContext = JS_INVALID_REFERENCE, current = JS_INVALID_REFERENCE;
  1136. REQUIRE(JsCreateRuntime(attributes, NULL, &first) == JsNoError);
  1137. REQUIRE(JsCreateContext(first, &firstContext) == JsNoError);
  1138. REQUIRE(JsGetCurrentContext(&current) == JsNoError);
  1139. // First run the script returning a boolean. This should not require the source code.
  1140. REQUIRE(JsSerializeScript(script, compiledScript, &scriptSize) == JsNoError);
  1141. compiledScript = (BYTE*)VirtualAlloc(nullptr, scriptSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  1142. unsigned int newScriptSize = scriptSize;
  1143. REQUIRE(JsSerializeScript(script, compiledScript, &newScriptSize) == JsNoError);
  1144. CHECK(newScriptSize == scriptSize);
  1145. /*Change protection to READONLY as serialized byte code is supposed to be in READONLY region*/
  1146. DWORD oldProtect;
  1147. VirtualProtect(compiledScript, scriptSize, PAGE_READONLY, &oldProtect);
  1148. CHECK(oldProtect == PAGE_READWRITE);
  1149. tracker.script = script;
  1150. REQUIRE(JsRunSerializedScriptWithCallback(
  1151. [](JsSourceContext sourceContext, const WCHAR** scriptBuffer)
  1152. {
  1153. ((ByteCodeCallbackTracker*)sourceContext)->loadedScript = true;
  1154. *scriptBuffer = ((ByteCodeCallbackTracker*)sourceContext)->script;
  1155. return true;
  1156. },
  1157. [](JsSourceContext sourceContext)
  1158. {
  1159. // unless we can force unloaded before popping the stack we cant touch tracker.
  1160. //((ByteCodeCallbackTracker*)sourceContext)->unloadedScript = true;
  1161. },
  1162. compiledScript, (JsSourceContext)&tracker, _u(""), &result) == JsNoError);
  1163. CHECK(tracker.loadedScript == false);
  1164. REQUIRE(JsGetValueType(result, &type) == JsNoError);
  1165. REQUIRE(JsBooleanToBool(result, &boolValue) == JsNoError);
  1166. CHECK(boolValue);
  1167. REQUIRE(JsSetCurrentContext(current) == JsNoError);
  1168. REQUIRE(JsDisposeRuntime(first) == JsNoError);
  1169. // Create a second runtime.
  1170. REQUIRE(JsCreateRuntime(attributes, nullptr, &second) == JsNoError);
  1171. REQUIRE(JsCreateContext(second, &secondContext) == JsNoError);
  1172. REQUIRE(JsSetCurrentContext(secondContext) == JsNoError);
  1173. tracker.loadedScript = false;
  1174. tracker.unloadedScript = false;
  1175. VirtualFree(compiledScript, 0, MEM_RELEASE);
  1176. compiledScript = nullptr;
  1177. scriptSize = 0;
  1178. // Second run the script returning function.toString(). This should require the source code.
  1179. REQUIRE(JsSerializeScript(scriptFnToString, compiledScript, &scriptSize) == JsNoError);
  1180. compiledScript = (BYTE*)VirtualAlloc(nullptr, scriptSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  1181. newScriptSize = scriptSize;
  1182. REQUIRE(JsSerializeScript(scriptFnToString, compiledScript, &newScriptSize) == JsNoError);
  1183. CHECK(newScriptSize == scriptSize);
  1184. /*Change protection to READONLY as serialized byte code is supposed to be in READONLY region*/
  1185. oldProtect;
  1186. VirtualProtect(compiledScript, scriptSize, PAGE_READONLY, &oldProtect);
  1187. REQUIRE(oldProtect == PAGE_READWRITE);
  1188. tracker.script = scriptFnToString;
  1189. REQUIRE(JsRunSerializedScriptWithCallback(
  1190. [](JsSourceContext sourceContext, const WCHAR** scriptBuffer)
  1191. {
  1192. ((ByteCodeCallbackTracker*)sourceContext)->loadedScript = true;
  1193. *scriptBuffer = ((ByteCodeCallbackTracker*)sourceContext)->script;
  1194. return true;
  1195. },
  1196. [](JsSourceContext sourceContext)
  1197. {
  1198. // unless we can force unloaded before popping the stack we cant touch tracker.
  1199. },
  1200. compiledScript, (JsSourceContext)&tracker, _u(""), &result) == JsNoError);
  1201. CHECK(tracker.loadedScript);
  1202. REQUIRE(JsGetValueType(result, &type) == JsNoError);
  1203. REQUIRE(JsStringToPointer(result, &stringValue, &stringLength) == JsNoError);
  1204. CHECK(wcscmp(fn_decl, stringValue) == 0);
  1205. REQUIRE(JsSetCurrentContext(current) == JsNoError);
  1206. REQUIRE(JsDisposeRuntime(second) == JsNoError);
  1207. VirtualFree(compiledScript, 0, MEM_RELEASE);
  1208. }
  1209. TEST_CASE("ApiTest_ByteCodeWithCallbackTest", "[ApiTest]")
  1210. {
  1211. JsRTApiTest::RunWithAttributes(JsRTApiTest::ByteCodeWithCallbackTest);
  1212. }
  1213. void ContextCleanupTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1214. {
  1215. JsRuntimeHandle rt;
  1216. REQUIRE(JsCreateRuntime(attributes, nullptr, &rt) == JsNoError);
  1217. JsContextRef c1 = JS_INVALID_REFERENCE,
  1218. c2 = JS_INVALID_REFERENCE,
  1219. c3 = JS_INVALID_REFERENCE,
  1220. c4 = JS_INVALID_REFERENCE,
  1221. c5 = JS_INVALID_REFERENCE,
  1222. c6 = JS_INVALID_REFERENCE,
  1223. c7 = JS_INVALID_REFERENCE;
  1224. // Create a bunch of contexts
  1225. REQUIRE(JsCreateContext(rt, &c1) == JsNoError);
  1226. REQUIRE(JsCreateContext(rt, &c2) == JsNoError);
  1227. REQUIRE(JsCreateContext(rt, &c3) == JsNoError);
  1228. REQUIRE(JsCreateContext(rt, &c4) == JsNoError);
  1229. REQUIRE(JsCreateContext(rt, &c5) == JsNoError);
  1230. REQUIRE(JsCreateContext(rt, &c6) == JsNoError);
  1231. REQUIRE(JsCreateContext(rt, &c7) == JsNoError);
  1232. // Clear references to some, then collect, causing them to be collected
  1233. c1 = nullptr;
  1234. c3 = nullptr;
  1235. c5 = nullptr;
  1236. c7 = nullptr;
  1237. REQUIRE(JsCollectGarbage(rt) == JsNoError);
  1238. // Now dispose
  1239. REQUIRE(JsDisposeRuntime(rt) == JsNoError);
  1240. }
  1241. TEST_CASE("ApiTest_ContextCleanupTest", "[ApiTest]")
  1242. {
  1243. JsRTApiTest::RunWithAttributes(JsRTApiTest::ContextCleanupTest);
  1244. }
  1245. void ObjectMethodTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1246. {
  1247. JsValueRef proto = JS_INVALID_REFERENCE;
  1248. JsValueRef object = JS_INVALID_REFERENCE;
  1249. REQUIRE(JsCreateObject(&proto) == JsNoError);
  1250. REQUIRE(JsCreateObject(&object) == JsNoError);
  1251. REQUIRE(JsSetPrototype(object, proto) == JsNoError);
  1252. JsValueRef objectProto = JS_INVALID_REFERENCE;
  1253. REQUIRE(JsGetPrototype(object, &objectProto) == JsNoError);
  1254. CHECK(proto == objectProto);
  1255. JsPropertyIdRef propertyId = JS_INVALID_REFERENCE;
  1256. bool hasProperty;
  1257. JsValueRef deleteResult = JS_INVALID_REFERENCE;
  1258. REQUIRE(JsGetPropertyIdFromName(_u("foo"), &propertyId) == JsNoError);
  1259. REQUIRE(JsSetProperty(object, propertyId, object, true) == JsNoError);
  1260. REQUIRE(JsHasProperty(object, propertyId, &hasProperty) == JsNoError);
  1261. CHECK(hasProperty);
  1262. REQUIRE(JsDeleteProperty(object, propertyId, true, &deleteResult) == JsNoError);
  1263. REQUIRE(JsHasProperty(object, propertyId, &hasProperty) == JsNoError);
  1264. CHECK(!hasProperty);
  1265. bool canExtend;
  1266. REQUIRE(JsGetExtensionAllowed(object, &canExtend) == JsNoError);
  1267. CHECK(canExtend);
  1268. REQUIRE(JsPreventExtension(object) == JsNoError);
  1269. REQUIRE(JsGetExtensionAllowed(object, &canExtend) == JsNoError);
  1270. CHECK(!canExtend);
  1271. REQUIRE(JsSetProperty(object, propertyId, object, true) == JsErrorScriptException);
  1272. JsValueRef exception = JS_INVALID_REFERENCE;
  1273. REQUIRE(JsGetAndClearException(&exception) == JsNoError);
  1274. REQUIRE(JsHasProperty(object, propertyId, &hasProperty) == JsNoError);
  1275. CHECK(!hasProperty);
  1276. }
  1277. TEST_CASE("ApiTest_ObjectMethodTest", "[ApiTest]")
  1278. {
  1279. JsRTApiTest::RunWithAttributes(JsRTApiTest::ObjectMethodTest);
  1280. }
  1281. void SetPrototypeTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1282. {
  1283. JsValueRef proto = JS_INVALID_REFERENCE;
  1284. JsValueRef object1 = JS_INVALID_REFERENCE;
  1285. JsValueRef object2 = JS_INVALID_REFERENCE;
  1286. JsPropertyIdRef obj1_a_pid = JS_INVALID_REFERENCE;
  1287. JsPropertyIdRef obj1_b_pid = JS_INVALID_REFERENCE;
  1288. JsPropertyIdRef obj2_x_pid = JS_INVALID_REFERENCE;
  1289. JsPropertyIdRef obj2_y_pid = JS_INVALID_REFERENCE;
  1290. JsPropertyIdRef obj2_z_pid = JS_INVALID_REFERENCE;
  1291. JsValueRef obj1_a_value = JS_INVALID_REFERENCE;
  1292. JsValueRef obj1_b_value = JS_INVALID_REFERENCE;
  1293. JsValueRef obj2_x_value = JS_INVALID_REFERENCE;
  1294. JsValueRef obj2_y_value = JS_INVALID_REFERENCE;
  1295. JsValueRef obj2_z_value = JS_INVALID_REFERENCE;
  1296. // var obj1 = {a : "obj1.a", b : "obj1.b"};
  1297. // var obj2 = {x : "obj2.x", y : "obj2.y", z : "obj2.z"}
  1298. REQUIRE(JsCreateObject(&proto) == JsNoError);
  1299. REQUIRE(JsCreateExternalObject((void *)0xdeadbeef, ExternalObjectFinalizeCallback, &object1) == JsNoError);
  1300. REQUIRE(JsCreateExternalObject((void *)0xdeadbeef, ExternalObjectFinalizeCallback, &object2) == JsNoError);
  1301. size_t propNameLength = wcslen(_u("obj1.a"));
  1302. REQUIRE(JsPointerToString(_u("obj1.a"), propNameLength, &obj1_a_value) == JsNoError);
  1303. REQUIRE(JsGetPropertyIdFromName(_u("a"), &obj1_a_pid) == JsNoError);
  1304. REQUIRE(JsSetProperty(object1, obj1_a_pid, obj1_a_value, true) == JsNoError);
  1305. REQUIRE(JsPointerToString(_u("obj1.b"), propNameLength, &obj1_b_value) == JsNoError);
  1306. REQUIRE(JsGetPropertyIdFromName(_u("b"), &obj1_b_pid) == JsNoError);
  1307. REQUIRE(JsSetProperty(object1, obj1_b_pid, obj1_b_value, true) == JsNoError);
  1308. REQUIRE(JsPointerToString(_u("obj2.x"), propNameLength, &obj2_x_value) == JsNoError);
  1309. REQUIRE(JsGetPropertyIdFromName(_u("x"), &obj2_x_pid) == JsNoError);
  1310. REQUIRE(JsSetProperty(object2, obj2_x_pid, obj2_x_value, true) == JsNoError);
  1311. REQUIRE(JsPointerToString(_u("obj1.y"), propNameLength, &obj2_y_value) == JsNoError);
  1312. REQUIRE(JsGetPropertyIdFromName(_u("y"), &obj2_y_pid) == JsNoError);
  1313. REQUIRE(JsSetProperty(object2, obj2_y_pid, obj2_y_value, true) == JsNoError);
  1314. REQUIRE(JsPointerToString(_u("obj1.z"), propNameLength, &obj2_z_value) == JsNoError);
  1315. REQUIRE(JsGetPropertyIdFromName(_u("z"), &obj2_z_pid) == JsNoError);
  1316. REQUIRE(JsSetProperty(object2, obj2_z_pid, obj2_z_value, true) == JsNoError);
  1317. REQUIRE(JsSetPrototype(object1, proto) == JsNoError);
  1318. REQUIRE(JsSetPrototype(object2, proto) == JsNoError);
  1319. JsValueRef objectProto = JS_INVALID_REFERENCE;
  1320. REQUIRE(JsGetPrototype(object1, &objectProto) == JsNoError);
  1321. CHECK(proto == objectProto);
  1322. REQUIRE(JsGetPrototype(object2, &objectProto) == JsNoError);
  1323. CHECK(proto == objectProto);
  1324. JsValueRef value = JS_INVALID_REFERENCE;
  1325. REQUIRE(JsGetProperty(object1, obj1_a_pid, &value) == JsNoError);
  1326. CHECK(value == obj1_a_value);
  1327. REQUIRE(JsGetProperty(object1, obj1_b_pid, &value) == JsNoError);
  1328. CHECK(value == obj1_b_value);
  1329. REQUIRE(JsGetProperty(object2, obj2_x_pid, &value) == JsNoError);
  1330. CHECK(value == obj2_x_value);
  1331. REQUIRE(JsGetProperty(object2, obj2_y_pid, &value) == JsNoError);
  1332. CHECK(value == obj2_y_value);
  1333. REQUIRE(JsGetProperty(object2, obj2_z_pid, &value) == JsNoError);
  1334. CHECK(value == obj2_z_value);
  1335. }
  1336. TEST_CASE("ApiTest_SetPrototypeTest", "[ApiTest]")
  1337. {
  1338. JsRTApiTest::RunWithAttributes(JsRTApiTest::SetPrototypeTest);
  1339. }
  1340. void DisableEval(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1341. {
  1342. JsValueRef result = JS_INVALID_REFERENCE;
  1343. JsErrorCode error = JsRunScript(_u("eval(\"1 + 2\")"), JS_SOURCE_CONTEXT_NONE, _u(""), &result);
  1344. if (!(attributes & JsRuntimeAttributeDisableEval))
  1345. {
  1346. CHECK(error == JsNoError);
  1347. }
  1348. else
  1349. {
  1350. CHECK(error == JsErrorScriptEvalDisabled);
  1351. }
  1352. error = JsRunScript(_u("new Function(\"return 1 + 2\")"), JS_SOURCE_CONTEXT_NONE, _u(""), &result);
  1353. if (!(attributes & JsRuntimeAttributeDisableEval))
  1354. {
  1355. CHECK(error == JsNoError);
  1356. }
  1357. else
  1358. {
  1359. CHECK(error == JsErrorScriptEvalDisabled);
  1360. }
  1361. }
  1362. TEST_CASE("ApiTest_DisableEval", "[ApiTest]")
  1363. {
  1364. JsRTApiTest::RunWithAttributes(JsRTApiTest::DisableEval);
  1365. }
  1366. static void CALLBACK PromiseContinuationCallback(JsValueRef task, void *callbackState)
  1367. {
  1368. CHECK(callbackState != nullptr);
  1369. // This simply saves the given task into the callback state
  1370. // so that we can verify it in the test
  1371. CHECK(*(JsValueRef *)callbackState == JS_INVALID_REFERENCE);
  1372. *(JsValueRef *)callbackState = task;
  1373. }
  1374. void PromisesTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1375. {
  1376. JsValueRef result = JS_INVALID_REFERENCE;
  1377. JsValueType valueType;
  1378. JsValueRef task = JS_INVALID_REFERENCE;
  1379. JsValueRef callback = JS_INVALID_REFERENCE;
  1380. REQUIRE(JsSetPromiseContinuationCallback(PromiseContinuationCallback, &callback) == JsNoError);
  1381. REQUIRE(JsRunScript(
  1382. _u("new Promise(") \
  1383. _u(" function(resolve, reject) {") \
  1384. _u(" resolve('basic:success');") \
  1385. _u(" }") \
  1386. _u(").then (") \
  1387. _u(" function () { return new Promise(") \
  1388. _u(" function(resolve, reject) { ") \
  1389. _u(" resolve('second:success'); ") \
  1390. _u(" })") \
  1391. _u(" }") \
  1392. _u(");"), JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsNoError);
  1393. CHECK(callback != nullptr);
  1394. JsValueRef args[] = { GetUndefined() };
  1395. // first then handler was queued
  1396. task = callback;
  1397. callback = JS_INVALID_REFERENCE;
  1398. REQUIRE(JsGetValueType(task, &valueType) == JsNoError);
  1399. CHECK(valueType == JsFunction);
  1400. REQUIRE(JsCallFunction(task, args, _countof(args), &result) == JsNoError);
  1401. // the second promise resolution was queued
  1402. task = callback;
  1403. callback = JS_INVALID_REFERENCE;
  1404. REQUIRE(JsGetValueType(task, &valueType) == JsNoError);
  1405. CHECK(valueType == JsFunction);
  1406. REQUIRE(JsCallFunction(task, args, _countof(args), &result) == JsNoError);
  1407. // second then handler was queued.
  1408. task = callback;
  1409. callback = JS_INVALID_REFERENCE;
  1410. REQUIRE(JsGetValueType(task, &valueType) == JsNoError);
  1411. CHECK(valueType == JsFunction);
  1412. REQUIRE(JsCallFunction(task, args, _countof(args), &result) == JsNoError);
  1413. // we are done; no more new task are queue.
  1414. CHECK(callback == JS_INVALID_REFERENCE);
  1415. }
  1416. TEST_CASE("ApiTest_PromisesTest", "[ApiTest]")
  1417. {
  1418. JsRTApiTest::RunWithAttributes(JsRTApiTest::PromisesTest);
  1419. }
  1420. void UnsetPromiseContinuation(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1421. {
  1422. JsValueRef result = JS_INVALID_REFERENCE, callbackState = JS_INVALID_REFERENCE, exception = JS_INVALID_REFERENCE;
  1423. JsValueType cbStateType = JsUndefined;
  1424. const wchar_t *script = _u("new Promise((res, rej) => res()).then(() => 1)");
  1425. // script with no promise continuation callback should error
  1426. REQUIRE(JsRunScript(script, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsErrorScriptException);
  1427. CHECK(result == JS_INVALID_REFERENCE);
  1428. REQUIRE(JsGetAndClearException(&exception) == JsNoError);
  1429. // script with promise continuation callback should run successfully
  1430. result = JS_INVALID_REFERENCE;
  1431. callbackState = JS_INVALID_REFERENCE;
  1432. REQUIRE(JsSetPromiseContinuationCallback(PromiseContinuationCallback, &callbackState) == JsNoError);
  1433. REQUIRE(JsRunScript(script, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsNoError);
  1434. CHECK(result != JS_INVALID_REFERENCE);
  1435. REQUIRE(JsGetValueType(callbackState, &cbStateType) == JsNoError);
  1436. CHECK(cbStateType == JsFunction);
  1437. // unsetting the promise continuation callback should make promise scripts error
  1438. result = JS_INVALID_REFERENCE;
  1439. callbackState = JS_INVALID_REFERENCE;
  1440. REQUIRE(JsSetPromiseContinuationCallback(nullptr, nullptr) == JsNoError);
  1441. REQUIRE(JsRunScript(script, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsErrorScriptException);
  1442. CHECK(result == JS_INVALID_REFERENCE);
  1443. REQUIRE(JsGetAndClearException(&exception) == JsNoError);
  1444. // resetting promise continuation callback should run successfully
  1445. result = JS_INVALID_REFERENCE;
  1446. callbackState = JS_INVALID_REFERENCE;
  1447. REQUIRE(JsSetPromiseContinuationCallback(PromiseContinuationCallback, &callbackState) == JsNoError);
  1448. REQUIRE(JsRunScript(script, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsNoError);
  1449. CHECK(result != JS_INVALID_REFERENCE);
  1450. REQUIRE(JsGetValueType(callbackState, &cbStateType) == JsNoError);
  1451. CHECK(cbStateType == JsFunction);
  1452. }
  1453. TEST_CASE("ApiTest_UnsetPromiseContinuation", "[ApiTest]")
  1454. {
  1455. JsRTApiTest::RunWithAttributes(JsRTApiTest::UnsetPromiseContinuation);
  1456. }
  1457. void ArrayBufferTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1458. {
  1459. for (int type = JsArrayTypeInt8; type <= JsArrayTypeFloat64; type++)
  1460. {
  1461. unsigned int size = 0;
  1462. switch (type)
  1463. {
  1464. case JsArrayTypeInt16:
  1465. size = sizeof(__int16);
  1466. break;
  1467. case JsArrayTypeInt8:
  1468. size = sizeof(__int8);
  1469. break;
  1470. case JsArrayTypeUint8:
  1471. case JsArrayTypeUint8Clamped:
  1472. size = sizeof(unsigned __int8);
  1473. break;
  1474. case JsArrayTypeUint16:
  1475. size = sizeof(unsigned __int16);
  1476. break;
  1477. case JsArrayTypeInt32:
  1478. size = sizeof(__int32);
  1479. break;
  1480. case JsArrayTypeUint32:
  1481. size = sizeof(unsigned __int32);
  1482. break;
  1483. case JsArrayTypeFloat32:
  1484. size = sizeof(float);
  1485. break;
  1486. case JsArrayTypeFloat64:
  1487. size = sizeof(double);
  1488. break;
  1489. }
  1490. // ArrayBuffer
  1491. JsValueRef arrayBuffer = JS_INVALID_REFERENCE;
  1492. JsValueType valueType;
  1493. BYTE *originBuffer = nullptr;
  1494. unsigned int originBufferLength;
  1495. REQUIRE(JsCreateArrayBuffer(16 * size, &arrayBuffer) == JsNoError);
  1496. REQUIRE(JsGetValueType(arrayBuffer, &valueType) == JsNoError);
  1497. CHECK(JsValueType::JsArrayBuffer == valueType);
  1498. REQUIRE(JsGetArrayBufferStorage(arrayBuffer, &originBuffer, &originBufferLength) == JsNoError);
  1499. CHECK(16 * size == originBufferLength);
  1500. // TypedArray
  1501. JsValueRef typedArray = JS_INVALID_REFERENCE;
  1502. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, arrayBuffer, /*byteOffset*/size, /*length*/12, &typedArray) == JsNoError);
  1503. REQUIRE(JsGetValueType(typedArray, &valueType) == JsNoError);
  1504. CHECK(JsValueType::JsTypedArray == valueType);
  1505. JsTypedArrayType arrayType;
  1506. JsValueRef tmpArrayBuffer = JS_INVALID_REFERENCE;
  1507. unsigned int tmpByteOffset, tmpByteLength;
  1508. REQUIRE(JsGetTypedArrayInfo(typedArray, &arrayType, &tmpArrayBuffer, &tmpByteOffset, &tmpByteLength) == JsNoError);
  1509. CHECK(type == arrayType);
  1510. CHECK(arrayBuffer == tmpArrayBuffer);
  1511. CHECK(size == tmpByteOffset);
  1512. CHECK(12 * size == tmpByteLength);
  1513. BYTE *buffer = nullptr;
  1514. unsigned int bufferLength;
  1515. int elementSize;
  1516. REQUIRE(JsGetTypedArrayStorage(typedArray, &buffer, &bufferLength, &arrayType, &elementSize) == JsNoError);
  1517. CHECK(originBuffer + size == buffer);
  1518. CHECK(12 * size == bufferLength);
  1519. CHECK(type == arrayType);
  1520. CHECK(size == (size_t)elementSize);
  1521. // DataView
  1522. JsValueRef dataView = JS_INVALID_REFERENCE;
  1523. REQUIRE(JsCreateDataView(arrayBuffer, /*byteOffset*/3, /*byteLength*/13, &dataView) == JsNoError);
  1524. REQUIRE(JsGetValueType(dataView, &valueType) == JsNoError);
  1525. CHECK(JsValueType::JsDataView == valueType);
  1526. REQUIRE(JsGetDataViewStorage(dataView, &buffer, &bufferLength) == JsNoError);
  1527. CHECK(originBuffer + 3 == buffer);
  1528. CHECK(13 == (int)bufferLength);
  1529. // InvalidArgs Get...
  1530. JsValueRef bad = JS_INVALID_REFERENCE;
  1531. REQUIRE(JsIntToNumber(5, &bad) == JsNoError);
  1532. REQUIRE(JsGetArrayBufferStorage(typedArray, &buffer, &bufferLength) == JsErrorInvalidArgument);
  1533. REQUIRE(JsGetArrayBufferStorage(dataView, &buffer, &bufferLength) == JsErrorInvalidArgument);
  1534. REQUIRE(JsGetArrayBufferStorage(bad, &buffer, &bufferLength) == JsErrorInvalidArgument);
  1535. REQUIRE(JsGetTypedArrayStorage(arrayBuffer, &buffer, &bufferLength, &arrayType, &elementSize) == JsErrorInvalidArgument);
  1536. REQUIRE(JsGetTypedArrayStorage(dataView, &buffer, &bufferLength, &arrayType, &elementSize) == JsErrorInvalidArgument);
  1537. REQUIRE(JsGetTypedArrayStorage(bad, &buffer, &bufferLength, &arrayType, &elementSize) == JsErrorInvalidArgument);
  1538. REQUIRE(JsGetDataViewStorage(arrayBuffer, &buffer, &bufferLength) == JsErrorInvalidArgument);
  1539. REQUIRE(JsGetDataViewStorage(typedArray, &buffer, &bufferLength) == JsErrorInvalidArgument);
  1540. REQUIRE(JsGetDataViewStorage(bad, &buffer, &bufferLength) == JsErrorInvalidArgument);
  1541. // no base array
  1542. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, JS_INVALID_REFERENCE, /*byteOffset*/0, /*length*/0, &typedArray) == JsNoError); // no base array
  1543. REQUIRE(JsGetTypedArrayInfo(typedArray, &arrayType, &tmpArrayBuffer, &tmpByteOffset, &tmpByteLength) == JsNoError);
  1544. CHECK(type == arrayType);
  1545. CHECK(tmpArrayBuffer != nullptr);
  1546. CHECK(tmpByteOffset == 0);
  1547. CHECK(tmpByteLength == 0);
  1548. // InvalidArgs Create...
  1549. REQUIRE(JsCreateTypedArray((JsTypedArrayType)(type + 100), arrayBuffer, /*byteOffset*/size, /*length*/12, &typedArray) == JsErrorInvalidArgument); // bad array type
  1550. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, JS_INVALID_REFERENCE, /*byteOffset*/size, /*length*/12, &typedArray) == JsErrorInvalidArgument); // byteOffset should be 0
  1551. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, dataView, /*byteOffset*/size, /*length*/12, &typedArray) == JsErrorInvalidArgument); // byteOffset should be 0
  1552. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, bad, /*byteOffset*/size, /*length*/12, &typedArray) == JsErrorInvalidArgument); // byteOffset should be 0
  1553. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, dataView, /*byteOffset*/0, /*length*/12, &typedArray) == JsErrorInvalidArgument); // length should be 0
  1554. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, bad, /*byteOffset*/0, /*length*/12, &typedArray) == JsErrorInvalidArgument); // length should be 0
  1555. REQUIRE(JsCreateDataView(typedArray, /*byteOffset*/size, /*byteLength*/12, &dataView) == JsErrorInvalidArgument); // must from arrayBuffer
  1556. REQUIRE(JsCreateDataView(dataView, /*byteOffset*/size, /*byteLength*/12, &dataView) == JsErrorInvalidArgument); // must from arrayBuffer
  1557. REQUIRE(JsCreateDataView(bad, /*byteOffset*/size, /*byteLength*/12, &dataView) == JsErrorInvalidArgument); // must from arrayBuffer
  1558. }
  1559. }
  1560. TEST_CASE("ApiTest_ArrayBufferTest", "[ApiTest]")
  1561. {
  1562. JsRTApiTest::RunWithAttributes(JsRTApiTest::ArrayBufferTest);
  1563. }
  1564. struct ThreadArgsData
  1565. {
  1566. JsRuntimeHandle runtime;
  1567. HANDLE hMonitor;
  1568. BOOL isScriptActive;
  1569. JsErrorCode disableExecutionResult;
  1570. static const int waitTime = 1000;
  1571. void BeginScriptExecution() { isScriptActive = true; }
  1572. void EndScriptExecution() { isScriptActive = false; }
  1573. void SignalMonitor() { SetEvent(hMonitor); }
  1574. // CATCH is not thread-safe. Call this in main thread only.
  1575. void CheckDisableExecutionResult()
  1576. {
  1577. REQUIRE(disableExecutionResult == JsNoError);
  1578. }
  1579. unsigned int ThreadProc()
  1580. {
  1581. while (1)
  1582. {
  1583. WaitForSingleObject(hMonitor, INFINITE);
  1584. // TODO: have a generic stopping mechanism.
  1585. if (isScriptActive)
  1586. {
  1587. Sleep(waitTime);
  1588. // CATCH is not thread-safe. Do not verify in this thread.
  1589. disableExecutionResult = JsDisableRuntimeExecution(runtime);
  1590. if (disableExecutionResult == JsNoError)
  1591. {
  1592. continue; // done, wait for next signal
  1593. }
  1594. }
  1595. CloseHandle(hMonitor);
  1596. break;
  1597. }
  1598. return 0;
  1599. }
  1600. };
  1601. static unsigned int CALLBACK StaticThreadProc(LPVOID lpParameter)
  1602. {
  1603. DWORD ret = (DWORD)-1;
  1604. ThreadArgsData * args = (ThreadArgsData *)lpParameter;
  1605. ret = args->ThreadProc();
  1606. return ret;
  1607. }
  1608. #define TERMINATION_TESTS \
  1609. _u("for (i=0; i<200; i = 20) {") \
  1610. _u(" var a = new Int8Array(800);") \
  1611. _u("}"), \
  1612. \
  1613. _u("function nextFunc() { ") \
  1614. _u(" throw 'hello'") \
  1615. _u("};") \
  1616. _u("for (i=0; i<200; i = 20) { ") \
  1617. _u(" try {") \
  1618. _u(" nextFunc();") \
  1619. _u(" } ") \
  1620. _u(" catch(e) {}") \
  1621. _u("}"), \
  1622. \
  1623. _u("function nextFunc() {") \
  1624. _u(" bar = bar + nextFunc.toString();") \
  1625. _u("};") \
  1626. _u("bar = '';") \
  1627. _u("for (i=0; i<200; i = 20) {") \
  1628. _u(" nextFunc()") \
  1629. _u("}"), \
  1630. \
  1631. _u("while(1);"), \
  1632. \
  1633. _u("function foo(){}") \
  1634. _u("do{") \
  1635. _u(" foo();") \
  1636. _u("}while(1);"), \
  1637. \
  1638. _u("(function foo(){") \
  1639. _u(" do {") \
  1640. _u(" if (foo) continue;") \
  1641. _u(" if (!foo) break;") \
  1642. _u(" } while(1); ") \
  1643. _u("})();"), \
  1644. \
  1645. _u("(function foo(a){") \
  1646. _u(" while (a){") \
  1647. _u(" L1:") \
  1648. _u(" do {") \
  1649. _u(" while(1) {") \
  1650. _u(" continue L1;") \
  1651. _u(" }") \
  1652. _u(" a = 0;") \
  1653. _u(" } while(0);") \
  1654. _u(" }") \
  1655. _u("})(1);"), \
  1656. \
  1657. _u("(function (){") \
  1658. _u(" while (1) {") \
  1659. _u(" try {") \
  1660. _u(" throw 0;") \
  1661. _u(" break;") \
  1662. _u(" }") \
  1663. _u(" catch(e) {") \
  1664. _u(" if (!e) continue;") \
  1665. _u(" }") \
  1666. _u(" break;") \
  1667. _u(" }") \
  1668. _u("})();")
  1669. static const LPCWSTR terminationTests[] = { TERMINATION_TESTS };
  1670. void ExternalFunctionWithScriptAbortionTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1671. {
  1672. if (!(attributes & JsRuntimeAttributeAllowScriptInterrupt))
  1673. {
  1674. REQUIRE(JsDisableRuntimeExecution(runtime) == JsErrorCannotDisableExecution);
  1675. return;
  1676. }
  1677. ThreadArgsData threadArgs = {};
  1678. threadArgs.runtime = runtime;
  1679. threadArgs.hMonitor = CreateEvent(nullptr, FALSE, FALSE, nullptr);
  1680. HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &StaticThreadProc, &threadArgs, 0, nullptr));
  1681. REQUIRE(threadHandle != nullptr);
  1682. if (threadHandle == nullptr)
  1683. {
  1684. // This is to satisfy preFAST, above REQUIRE call ensuring that it will report exception when threadHandle is null.
  1685. return;
  1686. }
  1687. JsValueRef preScriptAbortFunction = JS_INVALID_REFERENCE, postScriptAbortFunction = JS_INVALID_REFERENCE;
  1688. JsValueRef exception = JS_INVALID_REFERENCE;
  1689. for (int i = 0; i < _countof(terminationTests); i++)
  1690. {
  1691. threadArgs.BeginScriptExecution();
  1692. threadArgs.SignalMonitor();
  1693. REQUIRE(JsCreateFunction(ExternalFunctionPreScriptAbortionCallback, nullptr, &preScriptAbortFunction) == JsNoError);
  1694. REQUIRE(JsCreateFunction(ExternalFunctionPostScriptAbortionCallback, nullptr, &postScriptAbortFunction) == JsNoError);
  1695. JsValueRef scriptTextArg = JS_INVALID_REFERENCE;
  1696. WCHAR *scriptText = const_cast<WCHAR *>(terminationTests[i]);
  1697. REQUIRE(JsPointerToString(scriptText, wcslen(scriptText), &scriptTextArg) == JsNoError);
  1698. JsValueRef args[] = { scriptTextArg };
  1699. REQUIRE(JsCallFunction(preScriptAbortFunction, args, 1, nullptr) == JsErrorScriptTerminated);
  1700. bool isDisabled;
  1701. REQUIRE(JsIsRuntimeExecutionDisabled(runtime, &isDisabled) == JsNoError);
  1702. CHECK(isDisabled);
  1703. #ifdef NTBUILD
  1704. REQUIRE(JsCallFunction(postScriptAbortFunction, args, 1, nullptr) == JsErrorInDisabledState);
  1705. #else // !JSRT_VERIFY_RUNTIME_STATE
  1706. bool hasException = false;
  1707. REQUIRE(JsHasException(&hasException) == JsErrorInDisabledState);
  1708. #endif
  1709. REQUIRE(JsGetAndClearException(&exception) == JsErrorInDisabledState);
  1710. REQUIRE(JsEnableRuntimeExecution(runtime) == JsNoError);
  1711. threadArgs.CheckDisableExecutionResult();
  1712. threadArgs.EndScriptExecution();
  1713. }
  1714. threadArgs.SignalMonitor();
  1715. WaitForSingleObject(threadHandle, INFINITE);
  1716. threadArgs.hMonitor = nullptr;
  1717. }
  1718. TEST_CASE("ApiTest_ExternalFunctionWithScriptAbortionTest", "[ApiTest]")
  1719. {
  1720. JsRTApiTest::RunWithAttributes(JsRTApiTest::ExternalFunctionWithScriptAbortionTest);
  1721. }
  1722. void ScriptTerminationTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1723. {
  1724. // can't interrupt if scriptinterrupt is disabled.
  1725. if (!(attributes & JsRuntimeAttributeAllowScriptInterrupt))
  1726. {
  1727. REQUIRE(JsDisableRuntimeExecution(runtime) == JsErrorCannotDisableExecution);
  1728. return;
  1729. }
  1730. ThreadArgsData threadArgs = {};
  1731. threadArgs.runtime = runtime;
  1732. threadArgs.hMonitor = CreateEvent(nullptr, FALSE, FALSE, nullptr);
  1733. HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &StaticThreadProc, &threadArgs, 0, nullptr));
  1734. REQUIRE(threadHandle != nullptr);
  1735. if (threadHandle == nullptr)
  1736. {
  1737. // This is to satisfy preFAST, above REQUIRE call ensuring that it will report exception when threadHandle is null.
  1738. return;
  1739. }
  1740. JsValueRef result;
  1741. JsValueRef exception;
  1742. for (int i = 0; i < _countof(terminationTests); i++)
  1743. {
  1744. threadArgs.BeginScriptExecution();
  1745. threadArgs.SignalMonitor();
  1746. REQUIRE(JsRunScript(terminationTests[i], JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsErrorScriptTerminated);
  1747. bool isDisabled;
  1748. REQUIRE(JsIsRuntimeExecutionDisabled(runtime, &isDisabled) == JsNoError);
  1749. CHECK(isDisabled);
  1750. #ifdef NTBUILD
  1751. REQUIRE(JsRunScript(terminationTests[i], JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsErrorInDisabledState);
  1752. #else // !JSRT_VERIFY_RUNTIME_STATE
  1753. bool hasException = false;
  1754. REQUIRE(JsHasException(&hasException) == JsErrorInDisabledState);
  1755. #endif
  1756. REQUIRE(JsGetAndClearException(&exception) == JsErrorInDisabledState);
  1757. REQUIRE(JsEnableRuntimeExecution(runtime) == JsNoError);
  1758. threadArgs.CheckDisableExecutionResult();
  1759. threadArgs.EndScriptExecution();
  1760. }
  1761. threadArgs.SignalMonitor();
  1762. WaitForSingleObject(threadHandle, INFINITE);
  1763. threadArgs.hMonitor = nullptr;
  1764. }
  1765. TEST_CASE("ApiTest_ScriptTerminationTest", "[ApiTest]")
  1766. {
  1767. JsRTApiTest::RunWithAttributes(JsRTApiTest::ScriptTerminationTest);
  1768. }
  1769. struct ModuleResponseData
  1770. {
  1771. ModuleResponseData()
  1772. : mainModule(JS_INVALID_REFERENCE), childModule(JS_INVALID_REFERENCE), mainModuleException(JS_INVALID_REFERENCE), mainModuleReady(false)
  1773. {
  1774. }
  1775. JsModuleRecord mainModule;
  1776. JsModuleRecord childModule;
  1777. JsValueRef mainModuleException;
  1778. bool mainModuleReady;
  1779. };
  1780. ModuleResponseData successTest;
  1781. static JsErrorCode CALLBACK Success_FIMC(_In_ JsModuleRecord referencingModule, _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord)
  1782. {
  1783. JsModuleRecord moduleRecord = JS_INVALID_REFERENCE;
  1784. LPCWSTR specifierStr;
  1785. size_t length;
  1786. JsErrorCode errorCode = JsStringToPointer(specifier, &specifierStr, &length);
  1787. REQUIRE(errorCode == JsNoError);
  1788. REQUIRE(!wcscmp(specifierStr, _u("foo.js")));
  1789. errorCode = JsInitializeModuleRecord(referencingModule, specifier, &moduleRecord);
  1790. REQUIRE(errorCode == JsNoError);
  1791. *dependentModuleRecord = moduleRecord;
  1792. successTest.childModule = moduleRecord;
  1793. return JsNoError;
  1794. }
  1795. static JsErrorCode CALLBACK Succes_NMRC(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef exceptionVar)
  1796. {
  1797. if (successTest.mainModule == referencingModule)
  1798. {
  1799. successTest.mainModuleReady = true;
  1800. successTest.mainModuleException = exceptionVar;
  1801. }
  1802. return JsNoError;
  1803. }
  1804. void ModuleSuccessTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1805. {
  1806. JsModuleRecord requestModule = JS_INVALID_REFERENCE;
  1807. JsValueRef specifier;
  1808. REQUIRE(JsPointerToString(_u(""), 1, &specifier) == JsNoError);
  1809. REQUIRE(JsInitializeModuleRecord(nullptr, specifier, &requestModule) == JsNoError);
  1810. successTest.mainModule = requestModule;
  1811. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_FetchImportedModuleCallback, Success_FIMC) == JsNoError);
  1812. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_FetchImportedModuleFromScriptCallback, Success_FIMC) == JsNoError);
  1813. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_NotifyModuleReadyCallback, Succes_NMRC) == JsNoError);
  1814. JsValueRef errorObject = JS_INVALID_REFERENCE;
  1815. const char* fileContent = "import {x} from 'foo.js'";
  1816. JsErrorCode errorCode = JsParseModuleSource(requestModule, 0, (LPBYTE)fileContent,
  1817. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  1818. CHECK(errorCode == JsNoError);
  1819. CHECK(errorObject == JS_INVALID_REFERENCE);
  1820. CHECK(successTest.mainModuleReady == false);
  1821. REQUIRE(successTest.childModule != JS_INVALID_REFERENCE);
  1822. errorObject = JS_INVALID_REFERENCE;
  1823. fileContent = "/*error code*/ var x x";
  1824. errorCode = JsParseModuleSource(successTest.childModule, 1, (LPBYTE)fileContent,
  1825. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  1826. CHECK(errorCode == JsErrorScriptCompile);
  1827. CHECK(errorObject != JS_INVALID_REFERENCE);
  1828. CHECK(successTest.mainModuleReady == true);
  1829. REQUIRE(successTest.mainModuleException != JS_INVALID_REFERENCE);
  1830. JsPropertyIdRef message = JS_INVALID_REFERENCE;
  1831. REQUIRE(JsGetPropertyIdFromName(_u("message"), &message) == JsNoError);
  1832. JsValueRef value1Check = JS_INVALID_REFERENCE;
  1833. REQUIRE(JsGetProperty(successTest.mainModuleException, message, &value1Check) == JsNoError);
  1834. JsValueRef asString = JS_INVALID_REFERENCE;
  1835. REQUIRE(JsConvertValueToString(value1Check, &asString) == JsNoError);
  1836. LPCWSTR str = nullptr;
  1837. size_t length;
  1838. REQUIRE(JsStringToPointer(asString, &str, &length) == JsNoError);
  1839. REQUIRE(!wcscmp(str, _u("Expected ';'")));
  1840. }
  1841. TEST_CASE("ApiTest_ModuleSuccessTest", "[ApiTest]")
  1842. {
  1843. JsRTApiTest::WithSetup(JsRuntimeAttributeEnableExperimentalFeatures, ModuleSuccessTest);
  1844. }
  1845. void SetModuleHostInfoTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1846. {
  1847. JsModuleRecord requestModule = JS_INVALID_REFERENCE;
  1848. JsValueRef specifier = nullptr;
  1849. REQUIRE(JsPointerToString(_u("mod1.js"), wcslen(_u("mod1.js")), &specifier) == JsNoError);
  1850. REQUIRE(JsInitializeModuleRecord(nullptr, specifier, &requestModule) == JsNoError);
  1851. JsValueRef error = nullptr, errorMsg = nullptr;
  1852. REQUIRE(JsPointerToString(_u("test error"), wcslen(_u("test error")), &errorMsg) == JsNoError);
  1853. REQUIRE(JsCreateError(errorMsg, &error) == JsNoError);
  1854. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_Exception, error) == JsNoError);
  1855. JsValueRef errorOut = nullptr;
  1856. JsGetModuleHostInfo(requestModule, JsModuleHostInfo_Exception, &errorOut);
  1857. REQUIRE(errorOut == error);
  1858. //REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_Exception, nullptr) == JsNoError);
  1859. REQUIRE(JsPointerToString(_u("mod2.js"), wcslen(_u("mod2.js")), &specifier) == JsNoError);
  1860. REQUIRE(JsInitializeModuleRecord(nullptr, specifier, &requestModule) == JsNoError);
  1861. successTest.mainModule = requestModule;
  1862. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_NotifyModuleReadyCallback, Succes_NMRC) == JsNoError);
  1863. // Parsing
  1864. JsValueRef errorObject1 = JS_INVALID_REFERENCE;
  1865. const char* fileContent = "var x = 10";
  1866. REQUIRE(JsParseModuleSource(requestModule, 0, (LPBYTE)fileContent,
  1867. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject1) == JsNoError);
  1868. // This should not pass
  1869. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_Exception, error) != JsNoError);
  1870. }
  1871. TEST_CASE("ApiTest_SetModuleHostInfoTest", "[ApiTest]")
  1872. {
  1873. JsRTApiTest::WithSetup(JsRuntimeAttributeEnableExperimentalFeatures, SetModuleHostInfoTest);
  1874. }
  1875. static JsErrorCode CALLBACK Success_FIMC1(_In_ JsModuleRecord referencingModule, _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord)
  1876. {
  1877. JsModuleRecord moduleRecord = JS_INVALID_REFERENCE;
  1878. LPCWSTR specifierStr;
  1879. size_t length;
  1880. JsErrorCode errorCode = JsStringToPointer(specifier, &specifierStr, &length);
  1881. REQUIRE(errorCode == JsNoError);
  1882. REQUIRE(!wcscmp(specifierStr, _u("foo.js")));
  1883. JsValueRef specifier1 = nullptr;
  1884. REQUIRE(JsPointerToString(_u("./foo.js"), wcslen(_u("./foo.js")), &specifier1) == JsNoError);
  1885. errorCode = JsInitializeModuleRecord(referencingModule, specifier1, &moduleRecord);
  1886. REQUIRE(errorCode == JsNoError);
  1887. *dependentModuleRecord = moduleRecord;
  1888. successTest.childModule = moduleRecord;
  1889. return JsNoError;
  1890. }
  1891. void PassingDifferentModuleSpecifierTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1892. {
  1893. JsModuleRecord requestModule = JS_INVALID_REFERENCE;
  1894. JsValueRef specifier;
  1895. REQUIRE(JsPointerToString(_u(""), 1, &specifier) == JsNoError);
  1896. REQUIRE(JsInitializeModuleRecord(nullptr, specifier, &requestModule) == JsNoError);
  1897. successTest.mainModule = requestModule;
  1898. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_FetchImportedModuleCallback, Success_FIMC1) == JsNoError);
  1899. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_FetchImportedModuleFromScriptCallback, Success_FIMC1) == JsNoError);
  1900. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_NotifyModuleReadyCallback, Succes_NMRC) == JsNoError);
  1901. JsValueRef errorObject = JS_INVALID_REFERENCE;
  1902. const char* fileContent = "import {x} from 'foo.js'";
  1903. JsErrorCode errorCode = JsParseModuleSource(requestModule, 0, (LPBYTE)fileContent,
  1904. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  1905. CHECK(errorCode == JsNoError);
  1906. CHECK(errorObject == JS_INVALID_REFERENCE);
  1907. REQUIRE(successTest.childModule != JS_INVALID_REFERENCE);
  1908. }
  1909. TEST_CASE("ApiTest_PassingDifferentModuleSpecifierTest", "[ApiTest]")
  1910. {
  1911. JsRTApiTest::WithSetup(JsRuntimeAttributeEnableExperimentalFeatures, PassingDifferentModuleSpecifierTest);
  1912. }
  1913. ModuleResponseData reentrantParseData;
  1914. static JsErrorCode CALLBACK ReentrantParse_FIMC(_In_ JsModuleRecord referencingModule, _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord)
  1915. {
  1916. JsModuleRecord moduleRecord = JS_INVALID_REFERENCE;
  1917. LPCWSTR specifierStr;
  1918. size_t length;
  1919. JsErrorCode errorCode = JsStringToPointer(specifier, &specifierStr, &length);
  1920. REQUIRE(!wcscmp(specifierStr, _u("foo.js")));
  1921. REQUIRE(errorCode == JsNoError);
  1922. errorCode = JsInitializeModuleRecord(referencingModule, specifier, &moduleRecord);
  1923. REQUIRE(errorCode == JsNoError);
  1924. *dependentModuleRecord = moduleRecord;
  1925. reentrantParseData.childModule = moduleRecord;
  1926. // directly make a call to parsemodulesource
  1927. JsValueRef errorObject = JS_INVALID_REFERENCE;
  1928. const char* fileContent = "/*error code*/ var x x";
  1929. // Not checking the error code.
  1930. JsParseModuleSource(moduleRecord, 1, (LPBYTE)fileContent,
  1931. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  1932. // There must be an error
  1933. CHECK(errorObject != JS_INVALID_REFERENCE);
  1934. // Passed everything is valid.
  1935. return JsNoError;
  1936. }
  1937. static JsErrorCode CALLBACK ReentrantParse_NMRC(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef exceptionVar)
  1938. {
  1939. if (reentrantParseData.mainModule == referencingModule)
  1940. {
  1941. reentrantParseData.mainModuleReady = true;
  1942. reentrantParseData.mainModuleException = exceptionVar;
  1943. }
  1944. return JsNoError;
  1945. }
  1946. void ReentrantParseModuleTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1947. {
  1948. JsModuleRecord requestModule = JS_INVALID_REFERENCE;
  1949. JsValueRef specifier;
  1950. REQUIRE(JsPointerToString(_u(""), 1, &specifier) == JsNoError);
  1951. REQUIRE(JsInitializeModuleRecord(nullptr, specifier, &requestModule) == JsNoError);
  1952. reentrantParseData.mainModule = requestModule;
  1953. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_FetchImportedModuleCallback, ReentrantParse_FIMC) == JsNoError);
  1954. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_FetchImportedModuleFromScriptCallback, ReentrantParse_FIMC) == JsNoError);
  1955. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_NotifyModuleReadyCallback, ReentrantParse_NMRC) == JsNoError);
  1956. JsValueRef errorObject = JS_INVALID_REFERENCE;
  1957. const char* fileContent = "import {x} from 'foo.js'";
  1958. JsParseModuleSource(requestModule, 0, (LPBYTE)fileContent,
  1959. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  1960. CHECK(reentrantParseData.mainModuleReady == true);
  1961. REQUIRE(reentrantParseData.mainModuleException != JS_INVALID_REFERENCE);
  1962. JsPropertyIdRef message = JS_INVALID_REFERENCE;
  1963. REQUIRE(JsGetPropertyIdFromName(_u("message"), &message) == JsNoError);
  1964. JsValueRef value1Check = JS_INVALID_REFERENCE;
  1965. REQUIRE(JsGetProperty(reentrantParseData.mainModuleException, message, &value1Check) == JsNoError);
  1966. JsValueRef asString = JS_INVALID_REFERENCE;
  1967. REQUIRE(JsConvertValueToString(value1Check, &asString) == JsNoError);
  1968. LPCWSTR str = nullptr;
  1969. size_t length;
  1970. REQUIRE(JsStringToPointer(asString, &str, &length) == JsNoError);
  1971. REQUIRE(!wcscmp(str, _u("Expected ';'")));
  1972. }
  1973. TEST_CASE("ApiTest_ReentrantParseModuleTest", "[ApiTest]")
  1974. {
  1975. JsRTApiTest::WithSetup(JsRuntimeAttributeEnableExperimentalFeatures, ReentrantParseModuleTest);
  1976. }
  1977. ModuleResponseData reentrantNoErrorParseData;
  1978. static JsErrorCode CALLBACK reentrantNoErrorParse_FIMC(_In_ JsModuleRecord referencingModule, _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord)
  1979. {
  1980. JsModuleRecord moduleRecord = JS_INVALID_REFERENCE;
  1981. LPCWSTR specifierStr;
  1982. size_t length;
  1983. JsErrorCode errorCode = JsStringToPointer(specifier, &specifierStr, &length);
  1984. REQUIRE(!wcscmp(specifierStr, _u("foo.js")));
  1985. REQUIRE(errorCode == JsNoError);
  1986. errorCode = JsInitializeModuleRecord(referencingModule, specifier, &moduleRecord);
  1987. REQUIRE(errorCode == JsNoError);
  1988. *dependentModuleRecord = moduleRecord;
  1989. reentrantNoErrorParseData.childModule = moduleRecord;
  1990. JsValueRef errorObject = JS_INVALID_REFERENCE;
  1991. const char* fileContent = "export var x = 10;";
  1992. // Not checking the error code.
  1993. JsParseModuleSource(moduleRecord, 1, (LPBYTE)fileContent,
  1994. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  1995. // There must be an error
  1996. CHECK(errorObject == JS_INVALID_REFERENCE);
  1997. return JsNoError;
  1998. }
  1999. static JsErrorCode CALLBACK reentrantNoErrorParse_NMRC(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef exceptionVar)
  2000. {
  2001. if (reentrantNoErrorParseData.mainModule == referencingModule)
  2002. {
  2003. reentrantNoErrorParseData.mainModuleReady = true;
  2004. reentrantNoErrorParseData.mainModuleException = exceptionVar;
  2005. }
  2006. return JsNoError;
  2007. }
  2008. void ReentrantNoErrorParseModuleTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  2009. {
  2010. JsModuleRecord requestModule = JS_INVALID_REFERENCE;
  2011. JsValueRef specifier;
  2012. REQUIRE(JsPointerToString(_u(""), 1, &specifier) == JsNoError);
  2013. REQUIRE(JsInitializeModuleRecord(nullptr, specifier, &requestModule) == JsNoError);
  2014. reentrantNoErrorParseData.mainModule = requestModule;
  2015. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_FetchImportedModuleCallback, reentrantNoErrorParse_FIMC) == JsNoError);
  2016. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_FetchImportedModuleFromScriptCallback, reentrantNoErrorParse_FIMC) == JsNoError);
  2017. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_NotifyModuleReadyCallback, reentrantNoErrorParse_NMRC) == JsNoError);
  2018. JsValueRef errorObject = JS_INVALID_REFERENCE;
  2019. const char* fileContent = "import {x} from 'foo.js'";
  2020. JsErrorCode errorCode = JsParseModuleSource(requestModule, 0, (LPBYTE)fileContent,
  2021. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  2022. // This is no error in this module parse.
  2023. CHECK(errorCode == JsNoError);
  2024. CHECK(errorObject == JS_INVALID_REFERENCE);
  2025. CHECK(reentrantNoErrorParseData.mainModuleReady == true);
  2026. REQUIRE(reentrantNoErrorParseData.mainModuleException == JS_INVALID_REFERENCE);
  2027. }
  2028. TEST_CASE("ApiTest_ReentrantNoErrorParseModuleTest", "[ApiTest]")
  2029. {
  2030. JsRTApiTest::WithSetup(JsRuntimeAttributeEnableExperimentalFeatures, ReentrantNoErrorParseModuleTest);
  2031. }
  2032. static JsErrorCode CALLBACK FIMC1(_In_ JsModuleRecord referencingModule, _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord)
  2033. {
  2034. JsModuleRecord moduleRecord = JS_INVALID_REFERENCE;
  2035. LPCWSTR specifierStr;
  2036. size_t length;
  2037. JsErrorCode errorCode = JsStringToPointer(specifier, &specifierStr, &length);
  2038. REQUIRE(errorCode == JsNoError);
  2039. if (wcscmp(specifierStr, _u("foo.js")) == 0)
  2040. {
  2041. errorCode = JsInitializeModuleRecord(referencingModule, specifier, &moduleRecord);
  2042. REQUIRE(errorCode == JsNoError);
  2043. *dependentModuleRecord = moduleRecord;
  2044. }
  2045. else
  2046. {
  2047. *dependentModuleRecord = nullptr;
  2048. }
  2049. return JsNoError;
  2050. }
  2051. static JsErrorCode CALLBACK NMRC1(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef exceptionVar)
  2052. {
  2053. // NotifyModuleReadyCallback handling.
  2054. return JsNoError;
  2055. }
  2056. void SomebugTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  2057. {
  2058. JsModuleRecord rec;
  2059. JsInitializeModuleRecord(nullptr, nullptr, &rec);
  2060. JsSetModuleHostInfo(rec, JsModuleHostInfo_FetchImportedModuleCallback, FIMC1);
  2061. JsSetModuleHostInfo(rec, JsModuleHostInfo_FetchImportedModuleFromScriptCallback, FIMC1);
  2062. JsSetModuleHostInfo(rec, JsModuleHostInfo_NotifyModuleReadyCallback, NMRC1);
  2063. JsValueRef F = JS_INVALID_REFERENCE;
  2064. JsErrorCode err = JsRunScript(_u("var j = import('foo.js').then(mod => { mod.bar(); })"), 0, _u(""), &F);
  2065. CHECK(err == JsNoError);
  2066. }
  2067. TEST_CASE("ApiTest_SomebugTest", "[ApiTest]")
  2068. {
  2069. JsRTApiTest::WithSetup(JsRuntimeAttributeEnableExperimentalFeatures, SomebugTest);
  2070. }
  2071. void ObjectHasOwnPropertyMethodTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  2072. {
  2073. JsValueRef proto = JS_INVALID_REFERENCE;
  2074. JsValueRef object = JS_INVALID_REFERENCE;
  2075. REQUIRE(JsCreateObject(&proto) == JsNoError);
  2076. REQUIRE(JsCreateObject(&object) == JsNoError);
  2077. REQUIRE(JsSetPrototype(object, proto) == JsNoError);
  2078. JsPropertyIdRef propertyIdFoo = JS_INVALID_REFERENCE;
  2079. JsPropertyIdRef propertyIdBar = JS_INVALID_REFERENCE;
  2080. bool hasProperty = false;
  2081. REQUIRE(JsGetPropertyIdFromName(_u("foo"), &propertyIdFoo) == JsNoError);
  2082. REQUIRE(JsGetPropertyIdFromName(_u("bar"), &propertyIdBar) == JsNoError);
  2083. REQUIRE(JsSetProperty(object, propertyIdFoo, object, true) == JsNoError);
  2084. REQUIRE(JsSetProperty(proto, propertyIdBar, object, true) == JsNoError);
  2085. REQUIRE(JsHasProperty(object, propertyIdFoo, &hasProperty) == JsNoError);
  2086. CHECK(hasProperty);
  2087. REQUIRE(JsHasOwnProperty(object, propertyIdFoo, &hasProperty) == JsNoError);
  2088. CHECK(hasProperty);
  2089. REQUIRE(JsHasProperty(object, propertyIdBar, &hasProperty) == JsNoError);
  2090. CHECK(hasProperty);
  2091. REQUIRE(JsHasOwnProperty(object, propertyIdBar, &hasProperty) == JsNoError);
  2092. CHECK(!hasProperty);
  2093. }
  2094. TEST_CASE("ApiTest_ObjectHasOwnPropertyMethodTest", "[ApiTest]")
  2095. {
  2096. JsRTApiTest::RunWithAttributes(JsRTApiTest::ObjectHasOwnPropertyMethodTest);
  2097. }
  2098. void JsCopyStringOneByteMethodTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  2099. {
  2100. size_t written = 0;
  2101. char buf[10] = {0};
  2102. JsValueRef value;
  2103. REQUIRE(JsCreateStringUtf16(reinterpret_cast<const uint16_t*>(_u("0\x10\x80\xa9\uabcd\U000104377")), 8, &value) == JsNoError);
  2104. REQUIRE(JsCopyStringOneByte(value, 0, -1, nullptr, &written) == JsNoError);
  2105. CHECK(written == 8);
  2106. buf[written] = '\xff';
  2107. REQUIRE(JsCopyStringOneByte(value, 0, 10, buf, &written) == JsNoError);
  2108. CHECK(written == 8);
  2109. CHECK(buf[0] == '0');
  2110. CHECK(buf[1] == '\x10');
  2111. CHECK(buf[2] == '\x80');
  2112. CHECK(buf[3] == '\xA9');
  2113. CHECK(buf[4] == '\xcd');
  2114. CHECK(buf[5] == '\x01');
  2115. CHECK(buf[6] == '\x37');
  2116. CHECK(buf[7] == '7');
  2117. CHECK(buf[8] == '\xff');
  2118. }
  2119. TEST_CASE("ApiTest_JsCopyStringOneByteMethodTest", "[ApiTest]")
  2120. {
  2121. JsRTApiTest::RunWithAttributes(JsRTApiTest::JsCopyStringOneByteMethodTest);
  2122. }
  2123. void JsLessThanTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  2124. {
  2125. // Create some values
  2126. JsValueRef number1 = JS_INVALID_REFERENCE; // number1 = 1
  2127. REQUIRE(JsDoubleToNumber(1, &number1) == JsNoError);
  2128. JsValueRef number2 = JS_INVALID_REFERENCE; // number2 = 2
  2129. REQUIRE(JsDoubleToNumber(2, &number2) == JsNoError);
  2130. JsValueRef stringa = JS_INVALID_REFERENCE; // stringa = "1"
  2131. REQUIRE(JsPointerToString(_u("1"), wcslen(_u("1")), &stringa) == JsNoError);
  2132. JsValueRef undefined = GetUndefined();
  2133. JsValueRef nullValue = JS_INVALID_REFERENCE;
  2134. REQUIRE(JsGetNullValue(&nullValue) == JsNoError);
  2135. JsValueRef trueValue = JS_INVALID_REFERENCE;
  2136. REQUIRE(JsGetTrueValue(&trueValue) == JsNoError);
  2137. JsValueRef falseValue = JS_INVALID_REFERENCE;
  2138. REQUIRE(JsGetFalseValue(&falseValue) == JsNoError);
  2139. bool result;
  2140. REQUIRE(JsLessThan(number1, number2, &result) == JsNoError);
  2141. CHECK(result == true);
  2142. REQUIRE(JsLessThan(number1, stringa, &result) == JsNoError);
  2143. CHECK(result == false);
  2144. REQUIRE(JsLessThan(number1, undefined, &result) == JsNoError);
  2145. CHECK(result == false);
  2146. REQUIRE(JsLessThan(falseValue, trueValue, &result) == JsNoError);
  2147. CHECK(result == true);
  2148. REQUIRE(JsLessThan(undefined, undefined, &result) == JsNoError);
  2149. CHECK(result == false);
  2150. REQUIRE(JsLessThan(nullValue, undefined, &result) == JsNoError);
  2151. CHECK(result == false);
  2152. REQUIRE(JsLessThanOrEqual(number1, number2, &result) == JsNoError);
  2153. CHECK(result == true);
  2154. REQUIRE(JsLessThanOrEqual(number1, number1, &result) == JsNoError);
  2155. CHECK(result == true);
  2156. REQUIRE(JsLessThanOrEqual(number1, stringa, &result) == JsNoError);
  2157. CHECK(result == true);
  2158. REQUIRE(JsLessThanOrEqual(trueValue, trueValue, &result) == JsNoError);
  2159. CHECK(result == true);
  2160. REQUIRE(JsLessThanOrEqual(falseValue, nullValue, &result) == JsNoError);
  2161. CHECK(result == true);
  2162. REQUIRE(JsLessThanOrEqual(falseValue, undefined, &result) == JsNoError);
  2163. CHECK(result == false);
  2164. REQUIRE(JsLessThanOrEqual(undefined, undefined, &result) == JsNoError);
  2165. CHECK(result == false);
  2166. REQUIRE(JsLessThanOrEqual(nullValue, undefined, &result) == JsNoError);
  2167. CHECK(result == false);
  2168. }
  2169. TEST_CASE("ApiTest_JsLessThanTest", "[ApiTest]")
  2170. {
  2171. JsRTApiTest::RunWithAttributes(JsRTApiTest::JsLessThanTest);
  2172. }
  2173. void JsCreateStringTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  2174. {
  2175. // Passing in invalid utf8 sequences should result in the unicode replacement character
  2176. const char invalidUtf8[] = { -127 /* 0x80 */, '\0' };
  2177. JsValueRef result;
  2178. REQUIRE(JsCreateString(invalidUtf8, 1, &result) == JsNoError);
  2179. uint16_t utf16Result[2];
  2180. size_t written;
  2181. REQUIRE(JsCopyStringUtf16(result, 0, 1, utf16Result, &written) == JsNoError);
  2182. CHECK(written == 1);
  2183. CHECK(utf16Result[0] == 0xFFFD);
  2184. // Creating a utf8 string and then copying it back out should give an identical string
  2185. // Specifying -1 as the length should result in using strlen as the length
  2186. const char validUtf8Input[] = {'T', 'e', 's', 't', ' ', -30 /* 0xe2 */, -104 /* 0x98 */, -125 /* 0x83 */, 0};
  2187. REQUIRE(JsCreateString(validUtf8Input, static_cast<size_t>(-1), &result) == JsNoError);
  2188. char utf8Result[10];
  2189. REQUIRE(JsCopyString(result,utf8Result, 10, &written) == JsNoError);
  2190. CHECK(written == strlen(validUtf8Input));
  2191. CHECK(memcmp(utf8Result, validUtf8Input, written) == 0);
  2192. }
  2193. TEST_CASE("ApiTest_JsCreateStringTest", "[ApiTest]")
  2194. {
  2195. JsRTApiTest::RunWithAttributes(JsRTApiTest::JsCreateStringTest);
  2196. }
  2197. void ApiTest_JsSerializeArrayTest(JsRuntimeAttributes /*attributes*/, JsRuntimeHandle /*runtime*/)
  2198. {
  2199. LPCSTR raw_script = "(function (){return true;})();";
  2200. LPCWSTR raw_wscript = L"(function (){return true;})();";
  2201. // JsSerializeScript has good test coverage and can be used as an oracle for JsSerialize
  2202. unsigned int bcBufferSize_Expected = 0;
  2203. REQUIRE(JsSerializeScript(raw_wscript, nullptr, &bcBufferSize_Expected) == JsNoError);
  2204. BYTE *bcBuffer_Expected = new BYTE[bcBufferSize_Expected];
  2205. REQUIRE(JsSerializeScript(raw_wscript, bcBuffer_Expected, &bcBufferSize_Expected) == JsNoError);
  2206. REQUIRE(bcBuffer_Expected != nullptr);
  2207. // JsSerialize from an external array
  2208. JsValueRef scriptSource = JS_INVALID_REFERENCE;
  2209. REQUIRE(JsCreateExternalArrayBuffer(
  2210. (void*)raw_script, (unsigned int)strlen(raw_script), nullptr, (void*)raw_script, &scriptSource) == JsNoError);
  2211. JsValueRef buffer = JS_INVALID_REFERENCE;
  2212. REQUIRE(JsSerialize(scriptSource, &buffer, JsParseScriptAttributeNone) == JsNoError);
  2213. BYTE *bcBuffer = nullptr;
  2214. unsigned int bcBufferSize = 0;
  2215. REQUIRE(JsGetArrayBufferStorage(buffer, &bcBuffer, &bcBufferSize) == JsNoError);
  2216. REQUIRE(bcBufferSize_Expected == bcBufferSize);
  2217. CHECK(memcmp(bcBuffer_Expected, bcBuffer, bcBufferSize_Expected) == 0);
  2218. }
  2219. TEST_CASE("ApiTest_JsSerialize_Array", "[ApiTest]")
  2220. {
  2221. JsRTApiTest::RunWithAttributes(JsRTApiTest::ApiTest_JsSerializeArrayTest);
  2222. }
  2223. void ApiTest_JsSerializeStringTest(JsRuntimeAttributes /*attributes*/, JsRuntimeHandle /*runtime*/)
  2224. {
  2225. LPCSTR raw_script = "(function (){return true;})();";
  2226. LPCWSTR raw_wscript = L"(function (){return true;})();";
  2227. // JsSerializeScript has good test coverage and can be used as an oracle for JsSerialize
  2228. unsigned int bcBufferSize_Expected = 0;
  2229. REQUIRE(JsSerializeScript(raw_wscript, nullptr, &bcBufferSize_Expected) == JsNoError);
  2230. BYTE* bcBuffer_Expected = new BYTE[bcBufferSize_Expected];
  2231. REQUIRE(JsSerializeScript(raw_wscript, bcBuffer_Expected, &bcBufferSize_Expected) == JsNoError);
  2232. REQUIRE(bcBuffer_Expected != nullptr);
  2233. // JsSerialize from a string
  2234. JsValueRef script = JS_INVALID_REFERENCE;
  2235. REQUIRE(JsCreateString(raw_script, static_cast<size_t>(-1), &script) == JsNoError);
  2236. JsValueRef buffer = JS_INVALID_REFERENCE;
  2237. REQUIRE(JsSerialize(script, &buffer, JsParseScriptAttributeNone) == JsNoError);
  2238. BYTE *bcBuffer = nullptr;
  2239. unsigned int bcBufferSize = 0;
  2240. REQUIRE(JsGetArrayBufferStorage(buffer, &bcBuffer, &bcBufferSize) == JsNoError);
  2241. REQUIRE(bcBufferSize_Expected == bcBufferSize);
  2242. CHECK(memcmp(bcBuffer_Expected, bcBuffer, bcBufferSize_Expected) == 0);
  2243. delete[] bcBuffer_Expected;
  2244. }
  2245. TEST_CASE("ApiTest_JsSerialize_String", "[ApiTest]")
  2246. {
  2247. JsRTApiTest::RunWithAttributes(JsRTApiTest::ApiTest_JsSerializeStringTest);
  2248. }
  2249. void ApiTest_JsSerializeParseErrorTest(JsRuntimeAttributes /*attributes*/, JsRuntimeHandle /*runtime*/)
  2250. {
  2251. LPCSTR raw_script = "(function (){return true;})(;";
  2252. JsValueRef script = JS_INVALID_REFERENCE;
  2253. REQUIRE(JsCreateString(raw_script, static_cast<size_t>(-1), &script) == JsNoError);
  2254. JsValueRef buffer = JS_INVALID_REFERENCE;
  2255. CHECK(JsSerialize(script, &buffer, JsParseScriptAttributeNone) == JsErrorScriptCompile);
  2256. }
  2257. TEST_CASE("ApiTest_JsSerialize_FailParse", "[ApiTest]")
  2258. {
  2259. JsRTApiTest::RunWithAttributes(JsRTApiTest::ApiTest_JsSerializeParseErrorTest);
  2260. }
  2261. void JsCreatePromiseTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  2262. {
  2263. JsValueRef result = JS_INVALID_REFERENCE;
  2264. JsValueRef promise = JS_INVALID_REFERENCE;
  2265. JsValueRef resolve = JS_INVALID_REFERENCE;
  2266. JsValueRef reject = JS_INVALID_REFERENCE;
  2267. // Create resolvable promise
  2268. REQUIRE(JsCreatePromise(&promise, &resolve, &reject) == JsNoError);
  2269. JsPromiseState state = JsPromiseStatePending;
  2270. REQUIRE(JsGetPromiseState(promise, &state) == JsNoError);
  2271. CHECK(state == JsPromiseStatePending);
  2272. result = JS_INVALID_REFERENCE;
  2273. CHECK(JsGetPromiseResult(promise, &result) == JsErrorPromisePending);
  2274. CHECK(result == JS_INVALID_REFERENCE);
  2275. JsValueRef num = JS_INVALID_REFERENCE;
  2276. REQUIRE(JsIntToNumber(42, &num) == JsNoError);
  2277. std::array<JsValueRef, 2> args{ GetUndefined(), num };
  2278. REQUIRE(JsCallFunction(resolve, args.data(), static_cast<unsigned short>(args.size()), &result) == JsNoError);
  2279. state = JsPromiseStatePending;
  2280. REQUIRE(JsGetPromiseState(promise, &state) == JsNoError);
  2281. CHECK(state == JsPromiseStateFulfilled);
  2282. result = JS_INVALID_REFERENCE;
  2283. REQUIRE(JsGetPromiseResult(promise, &result) == JsNoError);
  2284. int resultNum = 0;
  2285. REQUIRE(JsNumberToInt(result, &resultNum) == JsNoError);
  2286. CHECK(resultNum == 42);
  2287. // Create rejectable promise
  2288. REQUIRE(JsCreatePromise(&promise, &resolve, &reject) == JsNoError);
  2289. state = JsPromiseStatePending;
  2290. REQUIRE(JsGetPromiseState(promise, &state) == JsNoError);
  2291. CHECK(state == JsPromiseStatePending);
  2292. result = JS_INVALID_REFERENCE;
  2293. CHECK(JsGetPromiseResult(promise, &result) == JsErrorPromisePending);
  2294. CHECK(result == JS_INVALID_REFERENCE);
  2295. num = JS_INVALID_REFERENCE;
  2296. REQUIRE(JsIntToNumber(43, &num) == JsNoError);
  2297. args = { GetUndefined(), num };
  2298. REQUIRE(JsCallFunction(reject, args.data(), static_cast<unsigned short>(args.size()), &result) == JsNoError);
  2299. state = JsPromiseStatePending;
  2300. REQUIRE(JsGetPromiseState(promise, &state) == JsNoError);
  2301. CHECK(state == JsPromiseStateRejected);
  2302. result = JS_INVALID_REFERENCE;
  2303. REQUIRE(JsGetPromiseResult(promise, &result) == JsNoError);
  2304. resultNum = 0;
  2305. REQUIRE(JsNumberToInt(result, &resultNum) == JsNoError);
  2306. CHECK(resultNum == 43);
  2307. }
  2308. TEST_CASE("ApiTest_JsCreatePromiseTest", "[ApiTest]")
  2309. {
  2310. JsRTApiTest::RunWithAttributes(JsRTApiTest::JsCreatePromiseTest);
  2311. }
  2312. }