JsRTApiTest.cpp 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935
  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. #include "catch.hpp"
  7. #include <process.h>
  8. #pragma warning(disable:4100) // unreferenced formal parameter
  9. #pragma warning(disable:6387) // suppressing preFAST which raises warning for passing null to the JsRT APIs
  10. #pragma warning(disable:6262) // CATCH is using stack variables to report errors, suppressing the preFAST warning.
  11. namespace JsRTApiTest
  12. {
  13. bool TestSetup(JsRuntimeAttributes attributes, JsRuntimeHandle *runtime)
  14. {
  15. JsValueRef context = JS_INVALID_REFERENCE;
  16. JsValueRef setContext = JS_INVALID_REFERENCE;
  17. // Create runtime, context and set current context
  18. REQUIRE(JsCreateRuntime(attributes, nullptr, runtime) == JsNoError);
  19. REQUIRE(JsCreateContext(*runtime, &context) == JsNoError);
  20. REQUIRE(JsSetCurrentContext(context) == JsNoError);
  21. REQUIRE(((JsGetCurrentContext(&setContext) == JsNoError) || setContext == context));
  22. return true;
  23. }
  24. bool TestCleanup(JsRuntimeHandle runtime)
  25. {
  26. if (runtime != nullptr)
  27. {
  28. JsSetCurrentContext(nullptr);
  29. JsDisposeRuntime(runtime);
  30. }
  31. return true;
  32. }
  33. JsValueRef GetUndefined()
  34. {
  35. JsValueRef undefined = JS_INVALID_REFERENCE;
  36. REQUIRE(JsGetUndefinedValue(&undefined) == JsNoError);
  37. return undefined;
  38. }
  39. template <class Handler>
  40. void WithSetup(JsRuntimeAttributes attributes, Handler handler)
  41. {
  42. JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE;
  43. if (!TestSetup(attributes, &runtime))
  44. {
  45. REQUIRE(false);
  46. return;
  47. }
  48. handler(attributes, runtime);
  49. TestCleanup(runtime);
  50. }
  51. template <class Handler>
  52. void RunWithAttributes(Handler handler)
  53. {
  54. WithSetup(JsRuntimeAttributeNone, handler);
  55. WithSetup(JsRuntimeAttributeDisableBackgroundWork, handler);
  56. WithSetup(JsRuntimeAttributeAllowScriptInterrupt, handler);
  57. WithSetup(JsRuntimeAttributeEnableIdleProcessing, handler);
  58. WithSetup(JsRuntimeAttributeDisableNativeCodeGeneration, handler);
  59. WithSetup(JsRuntimeAttributeDisableEval, handler);
  60. WithSetup((JsRuntimeAttributes)(JsRuntimeAttributeDisableBackgroundWork | JsRuntimeAttributeAllowScriptInterrupt | JsRuntimeAttributeEnableIdleProcessing), handler);
  61. }
  62. void ReferenceCountingTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  63. {
  64. JsContextRef context = JS_INVALID_REFERENCE;
  65. REQUIRE(JsGetCurrentContext(&context) == JsNoError);
  66. CHECK(JsAddRef(context, nullptr) == JsNoError);
  67. CHECK(JsRelease(context, nullptr) == JsNoError);
  68. JsValueRef undefined = JS_INVALID_REFERENCE;
  69. REQUIRE(JsGetUndefinedValue(&undefined) == JsNoError);
  70. REQUIRE(JsSetCurrentContext(nullptr) == JsNoError);
  71. CHECK(JsAddRef(undefined, nullptr) == JsErrorNoCurrentContext);
  72. CHECK(JsRelease(undefined, nullptr) == JsErrorNoCurrentContext);
  73. REQUIRE(JsSetCurrentContext(context) == JsNoError);
  74. CHECK(JsAddRef(undefined, nullptr) == JsNoError);
  75. CHECK(JsRelease(undefined, nullptr) == JsNoError);
  76. JsPropertyIdRef foo = JS_INVALID_REFERENCE;
  77. REQUIRE(JsGetPropertyIdFromName(_u("foo"), &foo) == JsNoError);
  78. CHECK(JsAddRef(foo, nullptr) == JsNoError);
  79. CHECK(JsRelease(foo, nullptr) == JsNoError);
  80. }
  81. TEST_CASE("ApiTest_ReferenceCountingTest", "[ApiTest]")
  82. {
  83. JsRTApiTest::RunWithAttributes(JsRTApiTest::ReferenceCountingTest);
  84. }
  85. void ObjectsAndPropertiesTest1(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  86. {
  87. JsValueRef object = JS_INVALID_REFERENCE;
  88. REQUIRE(JsCreateObject(&object) == JsNoError);
  89. JsPropertyIdRef name1 = JS_INVALID_REFERENCE;
  90. const WCHAR* name = nullptr;
  91. REQUIRE(JsGetPropertyIdFromName(_u("stringProperty1"), &name1) == JsNoError);
  92. REQUIRE(JsGetPropertyNameFromId(name1, &name) == JsNoError);
  93. CHECK(!wcscmp(name, _u("stringProperty1")));
  94. JsPropertyIdType propertyIdType;
  95. REQUIRE(JsGetPropertyIdType(name1, &propertyIdType) == JsNoError);
  96. CHECK(propertyIdType == JsPropertyIdTypeString);
  97. JsPropertyIdRef name2 = JS_INVALID_REFERENCE;
  98. REQUIRE(JsGetPropertyIdFromName(_u("stringProperty2"), &name2) == JsNoError);
  99. JsValueRef value1 = JS_INVALID_REFERENCE;
  100. REQUIRE(JsPointerToString(_u("value1"), wcslen(_u("value1")), &value1) == JsNoError);
  101. JsValueRef value2 = JS_INVALID_REFERENCE;
  102. REQUIRE(JsPointerToString(_u("value1"), wcslen(_u("value1")), &value2) == JsNoError);
  103. REQUIRE(JsSetProperty(object, name1, value1, true) == JsNoError);
  104. REQUIRE(JsSetProperty(object, name2, value2, true) == JsNoError);
  105. JsValueRef value1Check = JS_INVALID_REFERENCE;
  106. REQUIRE(JsGetProperty(object, name1, &value1Check) == JsNoError);
  107. CHECK(value1 == value1Check);
  108. JsValueRef value2Check = JS_INVALID_REFERENCE;
  109. REQUIRE(JsGetProperty(object, name2, &value2Check) == JsNoError);
  110. CHECK(value1 == value1Check);
  111. }
  112. TEST_CASE("ApiTest_ObjectsAndPropertiesTest1", "[ApiTest]")
  113. {
  114. JsRTApiTest::RunWithAttributes(JsRTApiTest::ObjectsAndPropertiesTest1);
  115. }
  116. void ObjectsAndPropertiesTest2(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  117. {
  118. // Run a script to setup some globals
  119. JsValueRef function = JS_INVALID_REFERENCE;
  120. LPCWSTR script = nullptr;
  121. REQUIRE(FileLoadHelpers::LoadScriptFromFile("ObjectsAndProperties2.js", script) == S_OK);
  122. REQUIRE(script != nullptr);
  123. REQUIRE(JsParseScript(script, JS_SOURCE_CONTEXT_NONE, _u(""), &function) == JsNoError);
  124. JsValueRef args[] = { JS_INVALID_REFERENCE };
  125. REQUIRE(JsCallFunction(function, nullptr, 10, nullptr) == JsErrorInvalidArgument);
  126. REQUIRE(JsCallFunction(function, args, 0, nullptr) == JsErrorInvalidArgument);
  127. REQUIRE(JsCallFunction(function, args, _countof(args), nullptr) == JsErrorInvalidArgument);
  128. args[0] = GetUndefined();
  129. REQUIRE(JsCallFunction(function, args, _countof(args), nullptr) == JsNoError);
  130. // Get proto properties
  131. JsValueRef circle = JS_INVALID_REFERENCE;
  132. REQUIRE(JsRunScript(_u("new Circle()"), JS_SOURCE_CONTEXT_NONE, _u(""), &circle) == JsNoError);
  133. JsPropertyIdRef name = JS_INVALID_REFERENCE;
  134. REQUIRE(JsGetPropertyIdFromName(_u("color"), &name) == JsNoError);
  135. JsValueRef value = JS_INVALID_REFERENCE;
  136. REQUIRE(JsGetProperty(circle, name, &value) == JsNoError);
  137. JsValueRef asString = JS_INVALID_REFERENCE;
  138. REQUIRE(JsConvertValueToString(value, &asString) == JsNoError);
  139. LPCWSTR str = nullptr;
  140. size_t length;
  141. REQUIRE(JsStringToPointer(asString, &str, &length) == JsNoError);
  142. REQUIRE(!wcscmp(str, _u("white")));
  143. }
  144. TEST_CASE("ApiTest_ObjectsAndPropertiesTest2", "[ApiTest]")
  145. {
  146. JsRTApiTest::RunWithAttributes(JsRTApiTest::ObjectsAndPropertiesTest2);
  147. }
  148. void DeleteObjectIndexedPropertyBug(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  149. {
  150. JsValueRef object;
  151. REQUIRE(JsRunScript(_u("({a: 'a', 1: 1, 100: 100})"), JS_SOURCE_CONTEXT_NONE, _u(""), &object) == JsNoError);
  152. JsPropertyIdRef idRef = JS_INVALID_REFERENCE;
  153. JsValueRef result = JS_INVALID_REFERENCE;
  154. // delete property "a" triggers PathTypeHandler -> SimpleDictionaryTypeHandler
  155. REQUIRE(JsGetPropertyIdFromName(_u("a"), &idRef) == JsNoError);
  156. REQUIRE(JsDeleteProperty(object, idRef, false, &result) == JsNoError);
  157. // Now delete property "100". Bug causes we always delete "1" instead.
  158. REQUIRE(JsGetPropertyIdFromName(_u("100"), &idRef) == JsNoError);
  159. REQUIRE(JsDeleteProperty(object, idRef, false, &result) == JsNoError);
  160. bool has;
  161. JsValueRef indexRef = JS_INVALID_REFERENCE;
  162. REQUIRE(JsIntToNumber(100, &indexRef) == JsNoError);
  163. REQUIRE(JsHasIndexedProperty(object, indexRef, &has) == JsNoError);
  164. CHECK(!has); // index 100 should be deleted
  165. REQUIRE(JsIntToNumber(1, &indexRef) == JsNoError);
  166. REQUIRE(JsHasIndexedProperty(object, indexRef, &has) == JsNoError);
  167. CHECK(has); // index 1 should be intact
  168. }
  169. TEST_CASE("ApiTest_DeleteObjectIndexedPropertyBug", "[ApiTest]")
  170. {
  171. JsRTApiTest::RunWithAttributes(JsRTApiTest::DeleteObjectIndexedPropertyBug);
  172. }
  173. void CALLBACK ExternalObjectFinalizeCallback(void *data)
  174. {
  175. CHECK(data == (void *)0xdeadbeef);
  176. }
  177. void CrossContextSetPropertyTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  178. {
  179. bool hasExternalData;
  180. JsContextRef oldContext = JS_INVALID_REFERENCE, secondContext = JS_INVALID_REFERENCE, testContext = JS_INVALID_REFERENCE;
  181. JsValueRef secondValueRef = JS_INVALID_REFERENCE, secondObjectRef = JS_INVALID_REFERENCE, jsrtExternalObjectRef = JS_INVALID_REFERENCE, mainObjectRef = JS_INVALID_REFERENCE;
  182. JsPropertyIdRef idRef = JS_INVALID_REFERENCE;
  183. JsValueRef indexRef = JS_INVALID_REFERENCE;
  184. REQUIRE(JsGetCurrentContext(&oldContext) == JsNoError);
  185. REQUIRE(JsCreateObject(&mainObjectRef) == JsNoError);
  186. REQUIRE(JsGetPropertyIdFromName(_u("prop1"), &idRef) == JsNoError);
  187. REQUIRE(JsCreateContext(runtime, &secondContext) == JsNoError);
  188. REQUIRE(JsSetCurrentContext(secondContext) == JsNoError);
  189. REQUIRE(JsCreateObject(&secondObjectRef) == JsNoError);
  190. // Verify the main object is from first context
  191. REQUIRE(JsGetContextOfObject(mainObjectRef, &testContext) == JsNoError);
  192. REQUIRE(testContext == oldContext);
  193. // Create external Object in 2nd context which will be accessed in main context.
  194. REQUIRE(JsCreateExternalObject((void *)0xdeadbeef, ExternalObjectFinalizeCallback, &jsrtExternalObjectRef) == JsNoError);
  195. REQUIRE(JsIntToNumber(1, &secondValueRef) == JsNoError);
  196. REQUIRE(JsIntToNumber(2, &indexRef) == JsNoError);
  197. REQUIRE(JsSetCurrentContext(oldContext) == JsNoError);
  198. // Verify the second object is from second context
  199. REQUIRE(JsGetContextOfObject(secondObjectRef, &testContext) == JsNoError);
  200. CHECK(testContext == secondContext);
  201. REQUIRE(JsSetProperty(mainObjectRef, idRef, secondValueRef, false) == JsNoError);
  202. REQUIRE(JsSetProperty(mainObjectRef, idRef, secondObjectRef, false) == JsNoError);
  203. REQUIRE(JsSetIndexedProperty(mainObjectRef, indexRef, secondValueRef) == JsNoError);
  204. REQUIRE(JsSetIndexedProperty(mainObjectRef, indexRef, secondObjectRef) == JsNoError);
  205. REQUIRE(JsSetPrototype(jsrtExternalObjectRef, mainObjectRef) == JsNoError);
  206. REQUIRE(JsHasExternalData(jsrtExternalObjectRef, &hasExternalData) == JsNoError);
  207. REQUIRE(hasExternalData);
  208. }
  209. TEST_CASE("ApiTest_CrossContextSetPropertyTest", "[ApiTest]")
  210. {
  211. JsRTApiTest::RunWithAttributes(JsRTApiTest::CrossContextSetPropertyTest);
  212. }
  213. void CrossContextFunctionCall(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  214. {
  215. /*
  216. 1. function changeFoo() { foo = 100 }
  217. 2. CreateContext
  218. 3. Set f : changeFoo in newContext
  219. 4. Call f() from newContext
  220. */
  221. JsContextRef oldContext = JS_INVALID_REFERENCE, secondContext = JS_INVALID_REFERENCE;
  222. JsValueRef functionRef = JS_INVALID_REFERENCE, functionResultRef = JS_INVALID_REFERENCE, globalRef = JS_INVALID_REFERENCE, globalNewCtxRef = JS_INVALID_REFERENCE, valueRef = JS_INVALID_REFERENCE;
  223. JsPropertyIdRef propertyIdFRef = JS_INVALID_REFERENCE, propertyIdFooRef = JS_INVALID_REFERENCE, propertyIdChangeFooRef = JS_INVALID_REFERENCE;
  224. int answer;
  225. REQUIRE(JsGetCurrentContext(&oldContext) == JsNoError);
  226. REQUIRE(JsGetPropertyIdFromName(_u("f"), &propertyIdFRef) == JsNoError);
  227. REQUIRE(JsGetPropertyIdFromName(_u("foo"), &propertyIdFooRef) == JsNoError);
  228. REQUIRE(JsGetPropertyIdFromName(_u("changeFoo"), &propertyIdChangeFooRef) == JsNoError);
  229. //1. function changeFoo() { foo = 100 }
  230. REQUIRE(JsRunScript(_u("foo = 3; function changeFoo() { foo = 100 }"), JS_SOURCE_CONTEXT_NONE, _u(""), &functionResultRef) == JsNoError);
  231. REQUIRE(JsGetGlobalObject(&globalRef) == JsNoError);
  232. REQUIRE(JsGetProperty(globalRef, propertyIdChangeFooRef, &functionRef) == JsNoError);
  233. //2. CreateContext
  234. REQUIRE(JsCreateContext(runtime, &secondContext) == JsNoError);
  235. REQUIRE(JsSetCurrentContext(secondContext) == JsNoError);
  236. //3. Set f : changeFoo in newContext
  237. REQUIRE(JsGetGlobalObject(&globalNewCtxRef) == JsNoError);
  238. REQUIRE(JsSetProperty(globalNewCtxRef, propertyIdFRef, functionRef, false) == JsNoError);
  239. //4. Call 'f()' from newContext
  240. REQUIRE(JsRunScript(_u("f()"), JS_SOURCE_CONTEXT_NONE, _u(""), &functionResultRef) == JsNoError);
  241. //5. Change context to oldContext
  242. REQUIRE(JsSetCurrentContext(oldContext) == JsNoError);
  243. //6. Verify foo == 100
  244. REQUIRE(JsGetProperty(globalRef, propertyIdFooRef, &valueRef) == JsNoError);
  245. REQUIRE(JsNumberToInt(valueRef, &answer) == JsNoError);
  246. CHECK(answer == 100);
  247. }
  248. TEST_CASE("ApiTest_CrossContextFunctionCall", "[ApiTest]")
  249. {
  250. JsRTApiTest::RunWithAttributes(JsRTApiTest::CrossContextSetPropertyTest);
  251. }
  252. void ExternalDataOnJsrtContextTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  253. {
  254. int i = 5;
  255. void *j;
  256. JsContextRef currentContext = JS_INVALID_REFERENCE;
  257. REQUIRE(JsGetCurrentContext(&currentContext) == JsNoError);
  258. REQUIRE(JsSetContextData(currentContext, &i) == JsNoError);
  259. REQUIRE(JsGetContextData(currentContext, &j) == JsNoError);
  260. CHECK(static_cast<int*>(j) == &i);
  261. }
  262. TEST_CASE("ApiTest_ExternalDataOnJsrtContextTest", "[ApiTest]")
  263. {
  264. JsRTApiTest::RunWithAttributes(JsRTApiTest::ExternalDataOnJsrtContextTest);
  265. }
  266. void ArrayAndItemTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  267. {
  268. // Create some arrays
  269. JsValueRef array1 = JS_INVALID_REFERENCE;
  270. JsValueRef array2 = JS_INVALID_REFERENCE;
  271. REQUIRE(JsCreateArray(0, &array1) == JsNoError);
  272. REQUIRE(JsCreateArray(100, &array2) == JsNoError);
  273. // Create an object we'll treat like an array
  274. JsValueRef object = JS_INVALID_REFERENCE;
  275. REQUIRE(JsCreateObject(&object) == JsNoError);
  276. // Create an index value to use
  277. JsValueRef index = JS_INVALID_REFERENCE;
  278. REQUIRE(JsDoubleToNumber(3, &index) == JsNoError);
  279. JsValueRef value1 = JS_INVALID_REFERENCE;
  280. REQUIRE(JsPointerToString(_u("value1"), wcslen(_u("value1")), &value1) == JsNoError);
  281. // Do some index-based manipulation
  282. bool result;
  283. REQUIRE(JsHasIndexedProperty(array1, index, &result) == JsNoError);
  284. REQUIRE(result == false);
  285. REQUIRE(JsHasIndexedProperty(array2, index, &result) == JsNoError);
  286. REQUIRE(result == false);
  287. REQUIRE(JsHasIndexedProperty(object, index, &result) == JsNoError);
  288. REQUIRE(result == false);
  289. REQUIRE(JsSetIndexedProperty(array1, index, value1) == JsNoError);
  290. REQUIRE(JsSetIndexedProperty(array2, index, value1) == JsNoError);
  291. REQUIRE(JsSetIndexedProperty(object, index, value1) == JsNoError);
  292. REQUIRE(JsHasIndexedProperty(array1, index, &result) == JsNoError);
  293. REQUIRE(result == true);
  294. REQUIRE(JsHasIndexedProperty(array2, index, &result) == JsNoError);
  295. REQUIRE(result == true);
  296. REQUIRE(JsHasIndexedProperty(object, index, &result) == JsNoError);
  297. REQUIRE(result == true);
  298. JsValueRef value2 = JS_INVALID_REFERENCE;
  299. REQUIRE(JsGetIndexedProperty(array1, index, &value2) == JsNoError);
  300. REQUIRE(JsStrictEquals(value1, value2, &result) == JsNoError);
  301. REQUIRE(result == true);
  302. REQUIRE(JsGetIndexedProperty(array2, index, &value2) == JsNoError);
  303. REQUIRE(JsStrictEquals(value1, value2, &result) == JsNoError);
  304. REQUIRE(result == true);
  305. REQUIRE(JsGetIndexedProperty(object, index, &value2) == JsNoError);
  306. REQUIRE(JsStrictEquals(value1, value2, &result) == JsNoError);
  307. REQUIRE(result == true);
  308. REQUIRE(JsDeleteIndexedProperty(array1, index) == JsNoError);
  309. REQUIRE(JsDeleteIndexedProperty(array2, index) == JsNoError);
  310. REQUIRE(JsDeleteIndexedProperty(object, index) == JsNoError);
  311. REQUIRE(JsHasIndexedProperty(array1, index, &result) == JsNoError);
  312. REQUIRE(result == false);
  313. REQUIRE(JsHasIndexedProperty(array2, index, &result) == JsNoError);
  314. REQUIRE(result == false);
  315. REQUIRE(JsHasIndexedProperty(object, index, &result) == JsNoError);
  316. REQUIRE(result == false);
  317. }
  318. TEST_CASE("ApiTest_ArrayAndItemTest", "[ApiTest]")
  319. {
  320. JsRTApiTest::RunWithAttributes(JsRTApiTest::ArrayAndItemTest);
  321. }
  322. void EqualsTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  323. {
  324. // Create some values
  325. JsValueRef number1 = JS_INVALID_REFERENCE;
  326. REQUIRE(JsDoubleToNumber(1, &number1) == JsNoError);
  327. JsValueRef number2 = JS_INVALID_REFERENCE;
  328. REQUIRE(JsDoubleToNumber(2, &number2) == JsNoError);
  329. JsValueRef stringa = JS_INVALID_REFERENCE;
  330. REQUIRE(JsPointerToString(_u("1"), wcslen(_u("1")), &stringa) == JsNoError);
  331. JsValueRef stringb = JS_INVALID_REFERENCE;
  332. REQUIRE(JsPointerToString(_u("1"), wcslen(_u("1")), &stringb) == JsNoError);
  333. bool result;
  334. REQUIRE(JsEquals(number1, number1, &result) == JsNoError);
  335. CHECK(result == true);
  336. REQUIRE(JsEquals(number1, number2, &result) == JsNoError);
  337. CHECK(result == false);
  338. REQUIRE(JsEquals(number1, stringa, &result) == JsNoError);
  339. CHECK(result == true);
  340. REQUIRE(JsEquals(number1, stringb, &result) == JsNoError);
  341. CHECK(result == true);
  342. REQUIRE(JsEquals(number2, stringa, &result) == JsNoError);
  343. CHECK(result == false);
  344. REQUIRE(JsEquals(number2, stringb, &result) == JsNoError);
  345. CHECK(result == false);
  346. REQUIRE(JsEquals(stringa, stringb, &result) == JsNoError);
  347. CHECK(result == true);
  348. REQUIRE(JsStrictEquals(number1, number1, &result) == JsNoError);
  349. CHECK(result == true);
  350. REQUIRE(JsStrictEquals(number1, number2, &result) == JsNoError);
  351. CHECK(result == false);
  352. REQUIRE(JsStrictEquals(number1, stringa, &result) == JsNoError);
  353. CHECK(result == false);
  354. REQUIRE(JsStrictEquals(number1, stringb, &result) == JsNoError);
  355. CHECK(result == false);
  356. REQUIRE(JsStrictEquals(number2, stringa, &result) == JsNoError);
  357. CHECK(result == false);
  358. REQUIRE(JsStrictEquals(number2, stringb, &result) == JsNoError);
  359. CHECK(result == false);
  360. REQUIRE(JsStrictEquals(stringa, stringb, &result) == JsNoError);
  361. CHECK(result == true);
  362. }
  363. TEST_CASE("ApiTest_EqualsTest", "[ApiTest]")
  364. {
  365. JsRTApiTest::RunWithAttributes(JsRTApiTest::EqualsTest);
  366. }
  367. void InstanceOfTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  368. {
  369. JsValueRef F = JS_INVALID_REFERENCE;
  370. REQUIRE(JsRunScript(_u("F = function(){}"), JS_SOURCE_CONTEXT_NONE, _u(""), &F) == JsNoError);
  371. JsValueRef x = JS_INVALID_REFERENCE;
  372. REQUIRE(JsRunScript(_u("new F()"), JS_SOURCE_CONTEXT_NONE, _u(""), &x) == JsNoError);
  373. bool instanceOf;
  374. REQUIRE(JsInstanceOf(x, F, &instanceOf) == JsNoError);
  375. REQUIRE(instanceOf);
  376. REQUIRE(JsCreateObject(&x) == JsNoError);
  377. REQUIRE(JsInstanceOf(x, F, &instanceOf) == JsNoError);
  378. CHECK(instanceOf == false);
  379. }
  380. TEST_CASE("ApiTest_InstanceOfTest", "[ApiTest]")
  381. {
  382. JsRTApiTest::RunWithAttributes(JsRTApiTest::InstanceOfTest);
  383. }
  384. void LanguageTypeConversionTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  385. {
  386. JsValueRef value = JS_INVALID_REFERENCE;
  387. JsValueType type;
  388. JsValueRef asString = JS_INVALID_REFERENCE;
  389. LPCWSTR str = nullptr;
  390. size_t length;
  391. // Number
  392. REQUIRE(JsDoubleToNumber(3.141592, &value) == JsNoError);
  393. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  394. REQUIRE(type == JsNumber);
  395. double dbl = 0.0;
  396. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  397. REQUIRE(dbl == 3.141592);
  398. REQUIRE(JsPointerToString(_u("3.141592"), wcslen(_u("3.141592")), &asString) == JsNoError);
  399. REQUIRE(JsConvertValueToNumber(asString, &value) == JsNoError);
  400. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  401. REQUIRE(dbl == 3.141592);
  402. int intValue;
  403. REQUIRE(JsNumberToInt(value, &intValue) == JsNoError);
  404. CHECK(3 == intValue);
  405. REQUIRE(JsDoubleToNumber(2147483648.1, &value) == JsNoError);
  406. REQUIRE(JsNumberToInt(value, &intValue) == JsNoError);
  407. CHECK(INT_MIN == intValue);
  408. REQUIRE(JsDoubleToNumber(-2147483649.1, &value) == JsNoError);
  409. REQUIRE(JsNumberToInt(value, &intValue) == JsNoError);
  410. CHECK(2147483647 == intValue);
  411. // String
  412. REQUIRE(JsDoubleToNumber(3.141592, &value) == JsNoError);
  413. REQUIRE(JsConvertValueToString(value, &asString) == JsNoError);
  414. REQUIRE(JsStringToPointer(asString, &str, &length) == JsNoError);
  415. CHECK(!wcscmp(str, _u("3.141592")));
  416. REQUIRE(JsGetTrueValue(&value) == JsNoError);
  417. REQUIRE(JsConvertValueToString(value, &asString) == JsNoError);
  418. REQUIRE(JsGetValueType(asString, &type) == JsNoError);
  419. CHECK(type == JsString);
  420. REQUIRE(JsStringToPointer(asString, &str, &length) == JsNoError);
  421. CHECK(!wcscmp(str, _u("true")));
  422. // Undefined
  423. REQUIRE(JsGetUndefinedValue(&value) == JsNoError);
  424. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  425. CHECK(type == JsUndefined);
  426. // Null
  427. REQUIRE(JsGetNullValue(&value) == JsNoError);
  428. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  429. CHECK(type == JsNull);
  430. // Boolean
  431. REQUIRE(JsGetTrueValue(&value) == JsNoError);
  432. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  433. CHECK(type == JsBoolean);
  434. REQUIRE(JsGetFalseValue(&value) == JsNoError);
  435. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  436. CHECK(type == JsBoolean);
  437. bool boolValue;
  438. REQUIRE(JsBoolToBoolean(true, &value) == JsNoError);
  439. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  440. CHECK(type == JsBoolean);
  441. REQUIRE(JsBooleanToBool(value, &boolValue) == JsNoError);
  442. CHECK(boolValue == true);
  443. REQUIRE(JsPointerToString(_u("true"), wcslen(_u("true")), &asString) == JsNoError);
  444. REQUIRE(JsConvertValueToBoolean(asString, &value) == JsNoError);
  445. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  446. CHECK(type == JsBoolean);
  447. REQUIRE(JsBooleanToBool(value, &boolValue) == JsNoError);
  448. CHECK(boolValue == true);
  449. // Object
  450. REQUIRE(JsCreateObject(&value) == JsNoError);
  451. REQUIRE(JsGetValueType(value, &type) == JsNoError);
  452. CHECK(type == JsObject);
  453. }
  454. TEST_CASE("ApiTest_LanguageTypeConversionTest", "[ApiTest]")
  455. {
  456. JsRTApiTest::RunWithAttributes(JsRTApiTest::LanguageTypeConversionTest);
  457. }
  458. JsValueRef CALLBACK ExternalFunctionCallback(JsValueRef /* function */, bool /* isConstructCall */, JsValueRef * /* args */, USHORT /* cargs */, void * /* callbackState */)
  459. {
  460. return nullptr;
  461. }
  462. void CALLBACK FinalizeCallback(JsValueRef object)
  463. {
  464. CHECK(object != JS_INVALID_REFERENCE);
  465. }
  466. void CALLBACK OldFinalizeCallback(void *data)
  467. {
  468. CHECK(data == nullptr);
  469. }
  470. JsValueRef CALLBACK ExternalFunctionPreScriptAbortionCallback(JsValueRef /* function */, bool /* isConstructCall */, JsValueRef * args /* args */, USHORT /* cargs */, void * /* callbackState */)
  471. {
  472. JsValueRef result = JS_INVALID_REFERENCE;
  473. const WCHAR *scriptText = nullptr;
  474. size_t scriptTextLen;
  475. REQUIRE(JsStringToPointer(args[0], &scriptText, &scriptTextLen) == JsNoError);
  476. REQUIRE(JsRunScript(scriptText, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsErrorScriptTerminated);
  477. return nullptr;
  478. }
  479. JsValueRef CALLBACK ExternalFunctionPostScriptAbortionCallback(JsValueRef /* function */, bool /* isConstructCall */, JsValueRef * args /* args */, USHORT /* cargs */, void * /* callbackState */)
  480. {
  481. JsValueRef result = JS_INVALID_REFERENCE;
  482. const WCHAR *scriptText = nullptr;
  483. size_t scriptTextLen;
  484. REQUIRE(JsStringToPointer(args[0], &scriptText, &scriptTextLen) == JsNoError);
  485. REQUIRE(JsRunScript(scriptText, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsErrorInDisabledState);
  486. return nullptr;
  487. }
  488. JsValueRef CALLBACK ErrorHandlingCallback(JsValueRef /* function */, bool /* isConstructCall */, JsValueRef * /* args */, USHORT /* cargs */, void * /* callbackState */)
  489. {
  490. JsValueRef result = JS_INVALID_REFERENCE;
  491. REQUIRE(JsRunScript(_u("new Error()"), JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsNoError);
  492. REQUIRE(JsSetException(result) == JsNoError);
  493. return nullptr;
  494. }
  495. void ExternalFunctionTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  496. {
  497. JsValueRef function = JS_INVALID_REFERENCE;
  498. REQUIRE(JsCreateFunction(ExternalFunctionCallback, nullptr, &function) == JsNoError);
  499. JsValueRef undefined = JS_INVALID_REFERENCE;
  500. REQUIRE(JsGetUndefinedValue(&undefined) == JsNoError);
  501. JsValueRef args[] = { undefined };
  502. REQUIRE(JsCallFunction(function, args, 1, nullptr) == JsNoError);
  503. JsValueRef result = JS_INVALID_REFERENCE;
  504. REQUIRE(JsConstructObject(function, args, 1, &result) == JsNoError);
  505. }
  506. TEST_CASE("ApiTest_ExternalFunctionTest", "[ApiTest]")
  507. {
  508. JsRTApiTest::RunWithAttributes(JsRTApiTest::ExternalFunctionTest);
  509. }
  510. void ExternalFunctionNameTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  511. {
  512. auto testConstructorName = [=](JsValueRef function, PCWCHAR expectedName, size_t expectedNameLength)
  513. {
  514. JsValueRef undefined = JS_INVALID_REFERENCE;
  515. REQUIRE(JsGetUndefinedValue(&undefined) == JsNoError);
  516. JsValueRef args[] = { undefined };
  517. JsValueRef obj = JS_INVALID_REFERENCE, constructor = JS_INVALID_REFERENCE, name = JS_INVALID_REFERENCE;
  518. JsPropertyIdRef propId = JS_INVALID_REFERENCE;
  519. REQUIRE(JsConstructObject(function, args, 1, &obj) == JsNoError);
  520. REQUIRE(JsGetPropertyIdFromName(_u("constructor"), &propId) == JsNoError);
  521. REQUIRE(JsGetProperty(obj, propId, &constructor) == JsNoError);
  522. REQUIRE(JsGetPropertyIdFromName(_u("name"), &propId) == JsNoError);
  523. REQUIRE(JsGetProperty(constructor, propId, &name) == JsNoError);
  524. PCWCHAR actualName = nullptr;
  525. size_t actualNameLength;
  526. REQUIRE(JsStringToPointer(name, &actualName, &actualNameLength) == JsNoError);
  527. CHECK(expectedNameLength == actualNameLength);
  528. CHECK(wcscmp(expectedName, actualName) == 0);
  529. };
  530. JsValueRef function = JS_INVALID_REFERENCE;
  531. REQUIRE(JsCreateFunction(ExternalFunctionCallback, nullptr, &function) == JsNoError);
  532. testConstructorName(function, _u(""), 0);
  533. WCHAR name[] = _u("FooName");
  534. JsValueRef nameString = JS_INVALID_REFERENCE;
  535. REQUIRE(JsPointerToString(name, _countof(name) - 1, &nameString) == JsNoError);
  536. REQUIRE(JsCreateNamedFunction(nameString, ExternalFunctionCallback, nullptr, &function) == JsNoError);
  537. testConstructorName(function, name, _countof(name) - 1);
  538. }
  539. TEST_CASE("ApiTest_ExternalFunctionNameTest", "[ApiTest]")
  540. {
  541. JsRTApiTest::RunWithAttributes(JsRTApiTest::ExternalFunctionNameTest);
  542. }
  543. void ErrorHandlingTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  544. {
  545. // Run a script to setup some globals
  546. LPCWSTR script = nullptr;
  547. REQUIRE(FileLoadHelpers::LoadScriptFromFile("ErrorHandling.js", script) == S_OK);
  548. REQUIRE(script != nullptr);
  549. REQUIRE(JsRunScript(script, JS_SOURCE_CONTEXT_NONE, _u(""), nullptr) == JsNoError);
  550. JsValueRef global = JS_INVALID_REFERENCE;
  551. REQUIRE(JsGetGlobalObject(&global) == JsNoError);
  552. JsPropertyIdRef name = JS_INVALID_REFERENCE;
  553. JsValueRef result = JS_INVALID_REFERENCE;
  554. JsValueRef exception = JS_INVALID_REFERENCE;
  555. JsValueRef function = JS_INVALID_REFERENCE;
  556. JsValueType type;
  557. JsValueRef args[] = { GetUndefined() };
  558. // throw from script, handle in host
  559. REQUIRE(JsGetPropertyIdFromName(_u("throwAtHost"), &name) == JsNoError);
  560. REQUIRE(JsGetProperty(global, name, &function) == JsNoError);
  561. REQUIRE(JsCallFunction(function, args, _countof(args), &result) == JsErrorScriptException);
  562. REQUIRE(JsGetAndClearException(&exception) == JsNoError);
  563. // setup a host callback for the next couple of tests
  564. REQUIRE(JsCreateFunction(ErrorHandlingCallback, nullptr, &result) == JsNoError);
  565. REQUIRE(JsGetValueType(result, &type) == JsNoError);
  566. REQUIRE(type == JsFunction);
  567. REQUIRE(JsGetPropertyIdFromName(_u("callHost"), &name) == JsNoError);
  568. REQUIRE(JsSetProperty(global, name, result, true) == JsNoError);
  569. // throw from host callback, catch in script
  570. REQUIRE(JsGetPropertyIdFromName(_u("callHostWithTryCatch"), &name) == JsNoError);
  571. REQUIRE(JsGetProperty(global, name, &function) == JsNoError);
  572. REQUIRE(JsCallFunction(function, args, _countof(args), &result) == JsNoError);
  573. // throw from host callback, through script, handle in host
  574. REQUIRE(JsGetPropertyIdFromName(_u("callHostWithNoTryCatch"), &name) == JsNoError);
  575. REQUIRE(JsGetProperty(global, name, &function) == JsNoError);
  576. REQUIRE(JsCallFunction(function, args, _countof(args), &result) == JsErrorScriptException);
  577. }
  578. TEST_CASE("ApiTest_ErrorHandlingTest", "[ApiTest]")
  579. {
  580. JsRTApiTest::RunWithAttributes(JsRTApiTest::ErrorHandlingTest);
  581. }
  582. void EngineFlagTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  583. {
  584. JsValueRef ret = JS_INVALID_REFERENCE;
  585. REQUIRE(JsRunScript(_u("new ActiveXObject('Scripting.FileSystemObject')"), JS_SOURCE_CONTEXT_NONE, _u(""), &ret) == JsErrorScriptException);
  586. REQUIRE(JsGetAndClearException(&ret) == JsNoError);
  587. }
  588. TEST_CASE("ApiTest_EngineFlagTest", "[ApiTest]")
  589. {
  590. JsRTApiTest::RunWithAttributes(JsRTApiTest::EngineFlagTest);
  591. }
  592. void ExceptionHandlingTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  593. {
  594. bool value;
  595. JsValueRef exception = JS_INVALID_REFERENCE;
  596. JsValueType type;
  597. REQUIRE(JsHasException(&value) == JsNoError);
  598. CHECK(value == false);
  599. REQUIRE(JsRunScript(_u("throw new Error()"), JS_SOURCE_CONTEXT_NONE, _u(""), nullptr) == JsErrorScriptException);
  600. REQUIRE(JsHasException(&value) == JsNoError);
  601. CHECK(value == true);
  602. REQUIRE(JsGetAndClearException(&exception) == JsNoError);
  603. REQUIRE(JsHasException(&value) == JsNoError);
  604. CHECK(value == false);
  605. REQUIRE(JsGetValueType(exception, &type) == JsNoError);
  606. CHECK(type == JsError);
  607. REQUIRE(JsSetException(exception) == JsNoError);
  608. REQUIRE(JsHasException(&value) == JsNoError);
  609. CHECK(value == true);
  610. }
  611. TEST_CASE("ApiTest_ExceptionHandlingTest", "[ApiTest]")
  612. {
  613. JsRTApiTest::RunWithAttributes(JsRTApiTest::ExceptionHandlingTest);
  614. }
  615. void ScriptCompileErrorTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  616. {
  617. JsValueRef error = JS_INVALID_REFERENCE;
  618. REQUIRE(JsRunScript(
  619. _u("if (x > 0) { \n") \
  620. _u(" x = 1; \n") \
  621. _u("}}"),
  622. JS_SOURCE_CONTEXT_NONE, _u(""), nullptr) == JsErrorScriptCompile);
  623. REQUIRE(JsGetAndClearException(&error) == JsNoError);
  624. JsPropertyIdRef property = JS_INVALID_REFERENCE;
  625. JsValueRef value = JS_INVALID_REFERENCE;
  626. LPCWSTR str = nullptr;
  627. size_t length;
  628. REQUIRE(JsGetPropertyIdFromName(_u("message"), &property) == JsNoError);
  629. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  630. REQUIRE(JsStringToPointer(value, &str, &length) == JsNoError);
  631. CHECK(wcscmp(_u("Syntax error"), str) == 0);
  632. double dbl;
  633. REQUIRE(JsGetPropertyIdFromName(_u("line"), &property) == JsNoError);
  634. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  635. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  636. CHECK(2 == dbl);
  637. REQUIRE(JsGetPropertyIdFromName(_u("column"), &property) == JsNoError);
  638. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  639. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  640. CHECK(1 == dbl);
  641. REQUIRE(JsGetPropertyIdFromName(_u("length"), &property) == JsNoError);
  642. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  643. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  644. CHECK(1 == dbl);
  645. REQUIRE(JsGetPropertyIdFromName(_u("source"), &property) == JsNoError);
  646. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  647. REQUIRE(JsStringToPointer(value, &str, &length) == JsNoError);
  648. CHECK(wcscmp(_u("}}"), str) == 0);
  649. REQUIRE(JsRunScript(
  650. _u("var for = 10;\n"),
  651. JS_SOURCE_CONTEXT_NONE, _u(""), nullptr) == JsErrorScriptCompile);
  652. REQUIRE(JsGetAndClearException(&error) == JsNoError);
  653. REQUIRE(JsGetPropertyIdFromName(_u("message"), &property) == JsNoError);
  654. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  655. REQUIRE(JsStringToPointer(value, &str, &length) == JsNoError);
  656. CHECK(wcscmp(_u("The use of a keyword for an identifier is invalid"), str) == 0);
  657. REQUIRE(JsGetPropertyIdFromName(_u("line"), &property) == JsNoError);
  658. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  659. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  660. CHECK(0 == dbl);
  661. REQUIRE(JsGetPropertyIdFromName(_u("column"), &property) == JsNoError);
  662. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  663. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  664. CHECK(4 == dbl);
  665. REQUIRE(JsGetPropertyIdFromName(_u("length"), &property) == JsNoError);
  666. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  667. REQUIRE(JsNumberToDouble(value, &dbl) == JsNoError);
  668. CHECK(3 == dbl);
  669. REQUIRE(JsGetPropertyIdFromName(_u("source"), &property) == JsNoError);
  670. REQUIRE(JsGetProperty(error, property, &value) == JsNoError);
  671. REQUIRE(JsStringToPointer(value, &str, &length) == JsNoError);
  672. CHECK(wcscmp(_u("var for = 10;"), str) == 0);
  673. }
  674. TEST_CASE("ApiTest_ScriptCompileErrorTest", "[ApiTest]")
  675. {
  676. JsRTApiTest::RunWithAttributes(JsRTApiTest::ScriptCompileErrorTest);
  677. }
  678. void ObjectTests(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  679. {
  680. LPCWSTR script = _u("x = { a: \"abc\", b: \"def\", c: \"ghi\" }; x");
  681. JsValueRef result = JS_INVALID_REFERENCE;
  682. JsValueRef propertyNames = JS_INVALID_REFERENCE;
  683. REQUIRE(JsRunScript(script, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsNoError);
  684. REQUIRE(JsGetOwnPropertyNames(result, &propertyNames) == JsNoError);
  685. for (int index = 0; index < 3; index++)
  686. {
  687. JsValueRef indexValue = JS_INVALID_REFERENCE;
  688. REQUIRE(JsDoubleToNumber(index, &indexValue) == JsNoError);
  689. JsValueRef nameValue = JS_INVALID_REFERENCE;
  690. REQUIRE(JsGetIndexedProperty(propertyNames, indexValue, &nameValue) == JsNoError);
  691. const WCHAR *name = nullptr;
  692. size_t length;
  693. REQUIRE(JsStringToPointer(nameValue, &name, &length) == JsNoError);
  694. CHECK(length == 1);
  695. CHECK(name[0] == ('a' + index));
  696. }
  697. }
  698. TEST_CASE("ApiTest_ObjectTests", "[ApiTest]")
  699. {
  700. JsRTApiTest::RunWithAttributes(JsRTApiTest::ObjectTests);
  701. }
  702. void SymbolTests(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  703. {
  704. JsValueRef object = JS_INVALID_REFERENCE;
  705. JsValueRef symbol1 = JS_INVALID_REFERENCE;
  706. JsValueRef string1 = JS_INVALID_REFERENCE;
  707. JsValueRef symbol2 = JS_INVALID_REFERENCE;
  708. JsValueRef value = JS_INVALID_REFERENCE;
  709. JsPropertyIdRef propertyId = JS_INVALID_REFERENCE;
  710. JsValueRef outValue = JS_INVALID_REFERENCE;
  711. JsValueRef propertySymbols = JS_INVALID_REFERENCE;
  712. const WCHAR* name = nullptr;
  713. JsPropertyIdType propertyIdType;
  714. REQUIRE(JsCreateObject(&object) == JsNoError);
  715. REQUIRE(JsGetPropertyIdFromSymbol(object, &propertyId) == JsErrorPropertyNotSymbol);
  716. REQUIRE(JsPointerToString(_u("abc"), 3, &string1) == JsNoError);
  717. REQUIRE(JsCreateSymbol(string1, &symbol1) == JsNoError);
  718. REQUIRE(JsCreateSymbol(JS_INVALID_REFERENCE, &symbol2) == JsNoError);
  719. REQUIRE(JsIntToNumber(1, &value) == JsNoError);
  720. REQUIRE(JsGetPropertyIdFromSymbol(symbol1, &propertyId) == JsNoError);
  721. REQUIRE(JsGetPropertyNameFromId(propertyId, &name) == JsErrorPropertyNotString);
  722. REQUIRE(JsGetPropertyIdType(propertyId, &propertyIdType) == JsNoError);
  723. CHECK(propertyIdType == JsPropertyIdTypeSymbol);
  724. JsValueRef symbol11 = JS_INVALID_REFERENCE;
  725. bool resultBool;
  726. REQUIRE(JsGetSymbolFromPropertyId(propertyId, &symbol11) == JsNoError);
  727. REQUIRE(JsEquals(symbol1, symbol11, &resultBool) == JsNoError);
  728. CHECK(resultBool);
  729. REQUIRE(JsStrictEquals(symbol1, symbol11, &resultBool) == JsNoError);
  730. CHECK(resultBool);
  731. REQUIRE(JsSetProperty(object, propertyId, value, true) == JsNoError);
  732. REQUIRE(JsGetProperty(object, propertyId, &outValue) == JsNoError);
  733. CHECK(value == outValue);
  734. REQUIRE(JsGetPropertyIdFromSymbol(symbol2, &propertyId) == JsNoError);
  735. REQUIRE(JsSetProperty(object, propertyId, value, true) == JsNoError);
  736. REQUIRE(JsGetProperty(object, propertyId, &outValue) == JsNoError);
  737. CHECK(value == outValue);
  738. JsValueType type;
  739. JsValueRef index = JS_INVALID_REFERENCE;
  740. REQUIRE(JsGetOwnPropertySymbols(object, &propertySymbols) == JsNoError);
  741. REQUIRE(JsIntToNumber(0, &index) == JsNoError);
  742. REQUIRE(JsGetIndexedProperty(propertySymbols, index, &outValue) == JsNoError);
  743. REQUIRE(JsGetValueType(outValue, &type) == JsNoError);
  744. CHECK(type == JsSymbol);
  745. REQUIRE(JsGetPropertyIdFromSymbol(outValue, &propertyId) == JsNoError);
  746. REQUIRE(JsGetProperty(object, propertyId, &outValue) == JsNoError);
  747. CHECK(value == outValue);
  748. REQUIRE(JsIntToNumber(1, &index) == JsNoError);
  749. REQUIRE(JsGetIndexedProperty(propertySymbols, index, &outValue) == JsNoError);
  750. REQUIRE(JsGetValueType(outValue, &type) == JsNoError);
  751. CHECK(type == JsSymbol);
  752. REQUIRE(JsGetPropertyIdFromSymbol(outValue, &propertyId) == JsNoError);
  753. REQUIRE(JsGetProperty(object, propertyId, &outValue) == JsNoError);
  754. CHECK(value == outValue);
  755. }
  756. TEST_CASE("ApiTest_SymbolTests", "[ApiTest]")
  757. {
  758. JsRTApiTest::RunWithAttributes(JsRTApiTest::SymbolTests);
  759. }
  760. void ByteCodeTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  761. {
  762. LPCWSTR script = _u("function test() { return true; }; test();");
  763. JsValueRef result = JS_INVALID_REFERENCE;
  764. JsValueType type;
  765. bool boolValue;
  766. BYTE *compiledScript = nullptr;
  767. unsigned int scriptSize = 0;
  768. REQUIRE(JsSerializeScript(script, compiledScript, &scriptSize) == JsNoError);
  769. compiledScript = new BYTE[scriptSize];
  770. unsigned int newScriptSize = scriptSize;
  771. REQUIRE(JsSerializeScript(script, compiledScript, &newScriptSize) == JsNoError);
  772. CHECK(newScriptSize == scriptSize);
  773. REQUIRE(JsRunSerializedScript(script, compiledScript, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsNoError);
  774. REQUIRE(JsGetValueType(result, &type) == JsNoError);
  775. REQUIRE(JsBooleanToBool(result, &boolValue) == JsNoError);
  776. CHECK(boolValue);
  777. JsRuntimeHandle second = JS_INVALID_RUNTIME_HANDLE;
  778. JsContextRef secondContext = JS_INVALID_REFERENCE, current = JS_INVALID_REFERENCE;
  779. REQUIRE(JsCreateRuntime(attributes, NULL, &second) == JsNoError);
  780. REQUIRE(JsCreateContext(second, &secondContext) == JsNoError);
  781. REQUIRE(JsGetCurrentContext(&current) == JsNoError);
  782. REQUIRE(JsSetCurrentContext(secondContext) == JsNoError);
  783. REQUIRE(JsRunSerializedScript(script, compiledScript, JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsNoError);
  784. REQUIRE(JsGetValueType(result, &type) == JsNoError);
  785. REQUIRE(JsBooleanToBool(result, &boolValue) == JsNoError);
  786. CHECK(boolValue);
  787. REQUIRE(JsSetCurrentContext(current) == JsNoError);
  788. REQUIRE(JsDisposeRuntime(second) == JsNoError);
  789. delete [] compiledScript;
  790. }
  791. TEST_CASE("ApiTest_ByteCodeTest", "[ApiTest]")
  792. {
  793. JsRTApiTest::RunWithAttributes(JsRTApiTest::ByteCodeTest);
  794. }
  795. #define BYTECODEWITHCALLBACK_METHODBODY _u("function test() { return true; }")
  796. typedef struct _ByteCodeCallbackTracker
  797. {
  798. bool loadedScript;
  799. bool unloadedScript;
  800. LPCWSTR script;
  801. } ByteCodeCallbackTracker;
  802. void ByteCodeWithCallbackTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  803. {
  804. LPCWSTR fn_decl = BYTECODEWITHCALLBACK_METHODBODY;
  805. LPCWSTR script = BYTECODEWITHCALLBACK_METHODBODY _u("; test();");
  806. LPCWSTR scriptFnToString = BYTECODEWITHCALLBACK_METHODBODY _u("; test.toString();");
  807. JsValueRef result = JS_INVALID_REFERENCE;
  808. JsValueType type;
  809. bool boolValue;
  810. BYTE *compiledScript = nullptr;
  811. unsigned int scriptSize = 0;
  812. const WCHAR *stringValue;
  813. size_t stringLength;
  814. ByteCodeCallbackTracker tracker = {};
  815. JsRuntimeHandle first = JS_INVALID_RUNTIME_HANDLE, second = JS_INVALID_RUNTIME_HANDLE;
  816. JsContextRef firstContext = JS_INVALID_REFERENCE, secondContext = JS_INVALID_REFERENCE, current = JS_INVALID_REFERENCE;
  817. REQUIRE(JsCreateRuntime(attributes, NULL, &first) == JsNoError);
  818. REQUIRE(JsCreateContext(first, &firstContext) == JsNoError);
  819. REQUIRE(JsGetCurrentContext(&current) == JsNoError);
  820. // First run the script returning a boolean. This should not require the source code.
  821. REQUIRE(JsSerializeScript(script, compiledScript, &scriptSize) == JsNoError);
  822. compiledScript = (BYTE*)VirtualAlloc(nullptr, scriptSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  823. unsigned int newScriptSize = scriptSize;
  824. REQUIRE(JsSerializeScript(script, compiledScript, &newScriptSize) == JsNoError);
  825. CHECK(newScriptSize == scriptSize);
  826. /*Change protection to READONLY as serialized byte code is supposed to be in READONLY region*/
  827. DWORD oldProtect;
  828. VirtualProtect(compiledScript, scriptSize, PAGE_READONLY, &oldProtect);
  829. CHECK(oldProtect == PAGE_READWRITE);
  830. tracker.script = script;
  831. REQUIRE(JsRunSerializedScriptWithCallback(
  832. [](JsSourceContext sourceContext, const WCHAR** scriptBuffer)
  833. {
  834. ((ByteCodeCallbackTracker*)sourceContext)->loadedScript = true;
  835. *scriptBuffer = ((ByteCodeCallbackTracker*)sourceContext)->script;
  836. return true;
  837. },
  838. [](JsSourceContext sourceContext)
  839. {
  840. // unless we can force unloaded before popping the stack we cant touch tracker.
  841. //((ByteCodeCallbackTracker*)sourceContext)->unloadedScript = true;
  842. },
  843. compiledScript, (JsSourceContext)&tracker, _u(""), &result) == JsNoError);
  844. CHECK(tracker.loadedScript == false);
  845. REQUIRE(JsGetValueType(result, &type) == JsNoError);
  846. REQUIRE(JsBooleanToBool(result, &boolValue) == JsNoError);
  847. CHECK(boolValue);
  848. REQUIRE(JsSetCurrentContext(current) == JsNoError);
  849. REQUIRE(JsDisposeRuntime(first) == JsNoError);
  850. // Create a second runtime.
  851. REQUIRE(JsCreateRuntime(attributes, nullptr, &second) == JsNoError);
  852. REQUIRE(JsCreateContext(second, &secondContext) == JsNoError);
  853. REQUIRE(JsSetCurrentContext(secondContext) == JsNoError);
  854. tracker.loadedScript = false;
  855. tracker.unloadedScript = false;
  856. VirtualFree(compiledScript, 0, MEM_RELEASE);
  857. compiledScript = nullptr;
  858. scriptSize = 0;
  859. // Second run the script returning function.toString(). This should require the source code.
  860. REQUIRE(JsSerializeScript(scriptFnToString, compiledScript, &scriptSize) == JsNoError);
  861. compiledScript = (BYTE*)VirtualAlloc(nullptr, scriptSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
  862. newScriptSize = scriptSize;
  863. REQUIRE(JsSerializeScript(scriptFnToString, compiledScript, &newScriptSize) == JsNoError);
  864. CHECK(newScriptSize == scriptSize);
  865. /*Change protection to READONLY as serialized byte code is supposed to be in READONLY region*/
  866. oldProtect;
  867. VirtualProtect(compiledScript, scriptSize, PAGE_READONLY, &oldProtect);
  868. REQUIRE(oldProtect == PAGE_READWRITE);
  869. tracker.script = scriptFnToString;
  870. REQUIRE(JsRunSerializedScriptWithCallback(
  871. [](JsSourceContext sourceContext, const WCHAR** scriptBuffer)
  872. {
  873. ((ByteCodeCallbackTracker*)sourceContext)->loadedScript = true;
  874. *scriptBuffer = ((ByteCodeCallbackTracker*)sourceContext)->script;
  875. return true;
  876. },
  877. [](JsSourceContext sourceContext)
  878. {
  879. // unless we can force unloaded before popping the stack we cant touch tracker.
  880. },
  881. compiledScript, (JsSourceContext)&tracker, _u(""), &result) == JsNoError);
  882. CHECK(tracker.loadedScript);
  883. REQUIRE(JsGetValueType(result, &type) == JsNoError);
  884. REQUIRE(JsStringToPointer(result, &stringValue, &stringLength) == JsNoError);
  885. CHECK(wcscmp(fn_decl, stringValue) == 0);
  886. REQUIRE(JsSetCurrentContext(current) == JsNoError);
  887. REQUIRE(JsDisposeRuntime(second) == JsNoError);
  888. VirtualFree(compiledScript, 0, MEM_RELEASE);
  889. }
  890. TEST_CASE("ApiTest_ByteCodeWithCallbackTest", "[ApiTest]")
  891. {
  892. JsRTApiTest::RunWithAttributes(JsRTApiTest::ByteCodeWithCallbackTest);
  893. }
  894. void ContextCleanupTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  895. {
  896. JsRuntimeHandle rt;
  897. REQUIRE(JsCreateRuntime(attributes, nullptr, &rt) == JsNoError);
  898. JsContextRef c1 = JS_INVALID_REFERENCE,
  899. c2 = JS_INVALID_REFERENCE,
  900. c3 = JS_INVALID_REFERENCE,
  901. c4 = JS_INVALID_REFERENCE,
  902. c5 = JS_INVALID_REFERENCE,
  903. c6 = JS_INVALID_REFERENCE,
  904. c7 = JS_INVALID_REFERENCE;
  905. // Create a bunch of contexts
  906. REQUIRE(JsCreateContext(rt, &c1) == JsNoError);
  907. REQUIRE(JsCreateContext(rt, &c2) == JsNoError);
  908. REQUIRE(JsCreateContext(rt, &c3) == JsNoError);
  909. REQUIRE(JsCreateContext(rt, &c4) == JsNoError);
  910. REQUIRE(JsCreateContext(rt, &c5) == JsNoError);
  911. REQUIRE(JsCreateContext(rt, &c6) == JsNoError);
  912. REQUIRE(JsCreateContext(rt, &c7) == JsNoError);
  913. // Clear references to some, then collect, causing them to be collected
  914. c1 = nullptr;
  915. c3 = nullptr;
  916. c5 = nullptr;
  917. c7 = nullptr;
  918. REQUIRE(JsCollectGarbage(rt) == JsNoError);
  919. // Now dispose
  920. REQUIRE(JsDisposeRuntime(rt) == JsNoError);
  921. }
  922. TEST_CASE("ApiTest_ContextCleanupTest", "[ApiTest]")
  923. {
  924. JsRTApiTest::RunWithAttributes(JsRTApiTest::ContextCleanupTest);
  925. }
  926. void ObjectMethodTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  927. {
  928. JsValueRef proto = JS_INVALID_REFERENCE;
  929. JsValueRef object = JS_INVALID_REFERENCE;
  930. REQUIRE(JsCreateObject(&proto) == JsNoError);
  931. REQUIRE(JsCreateObject(&object) == JsNoError);
  932. REQUIRE(JsSetPrototype(object, proto) == JsNoError);
  933. JsValueRef objectProto = JS_INVALID_REFERENCE;
  934. REQUIRE(JsGetPrototype(object, &objectProto) == JsNoError);
  935. CHECK(proto == objectProto);
  936. JsPropertyIdRef propertyId = JS_INVALID_REFERENCE;
  937. bool hasProperty;
  938. JsValueRef deleteResult = JS_INVALID_REFERENCE;
  939. REQUIRE(JsGetPropertyIdFromName(_u("foo"), &propertyId) == JsNoError);
  940. REQUIRE(JsSetProperty(object, propertyId, object, true) == JsNoError);
  941. REQUIRE(JsHasProperty(object, propertyId, &hasProperty) == JsNoError);
  942. CHECK(hasProperty);
  943. REQUIRE(JsDeleteProperty(object, propertyId, true, &deleteResult) == JsNoError);
  944. REQUIRE(JsHasProperty(object, propertyId, &hasProperty) == JsNoError);
  945. CHECK(!hasProperty);
  946. bool canExtend;
  947. REQUIRE(JsGetExtensionAllowed(object, &canExtend) == JsNoError);
  948. CHECK(canExtend);
  949. REQUIRE(JsPreventExtension(object) == JsNoError);
  950. REQUIRE(JsGetExtensionAllowed(object, &canExtend) == JsNoError);
  951. CHECK(!canExtend);
  952. REQUIRE(JsSetProperty(object, propertyId, object, true) == JsErrorScriptException);
  953. JsValueRef exception = JS_INVALID_REFERENCE;
  954. REQUIRE(JsGetAndClearException(&exception) == JsNoError);
  955. REQUIRE(JsHasProperty(object, propertyId, &hasProperty) == JsNoError);
  956. CHECK(!hasProperty);
  957. }
  958. TEST_CASE("ApiTest_ObjectMethodTest", "[ApiTest]")
  959. {
  960. JsRTApiTest::RunWithAttributes(JsRTApiTest::ObjectMethodTest);
  961. }
  962. void SetPrototypeTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  963. {
  964. JsValueRef proto = JS_INVALID_REFERENCE;
  965. JsValueRef object1 = JS_INVALID_REFERENCE;
  966. JsValueRef object2 = JS_INVALID_REFERENCE;
  967. JsPropertyIdRef obj1_a_pid= JS_INVALID_REFERENCE;
  968. JsPropertyIdRef obj1_b_pid = JS_INVALID_REFERENCE;
  969. JsPropertyIdRef obj2_x_pid = JS_INVALID_REFERENCE;
  970. JsPropertyIdRef obj2_y_pid = JS_INVALID_REFERENCE;
  971. JsPropertyIdRef obj2_z_pid = JS_INVALID_REFERENCE;
  972. JsValueRef obj1_a_value = JS_INVALID_REFERENCE;
  973. JsValueRef obj1_b_value = JS_INVALID_REFERENCE;
  974. JsValueRef obj2_x_value = JS_INVALID_REFERENCE;
  975. JsValueRef obj2_y_value = JS_INVALID_REFERENCE;
  976. JsValueRef obj2_z_value = JS_INVALID_REFERENCE;
  977. // var obj1 = {a : "obj1.a", b : "obj1.b"};
  978. // var obj2 = {x : "obj2.x", y : "obj2.y", z : "obj2.z"}
  979. REQUIRE(JsCreateObject(&proto) == JsNoError);
  980. REQUIRE(JsCreateExternalObject((void *)0xdeadbeef, ExternalObjectFinalizeCallback, &object1) == JsNoError);
  981. REQUIRE(JsCreateExternalObject((void *)0xdeadbeef, ExternalObjectFinalizeCallback, &object2) == JsNoError);
  982. size_t propNameLength = wcslen(_u("obj1.a"));
  983. REQUIRE(JsPointerToString(_u("obj1.a"), propNameLength, &obj1_a_value) == JsNoError);
  984. REQUIRE(JsGetPropertyIdFromName(_u("a"), &obj1_a_pid) == JsNoError);
  985. REQUIRE(JsSetProperty(object1, obj1_a_pid, obj1_a_value, true) == JsNoError);
  986. REQUIRE(JsPointerToString(_u("obj1.b"), propNameLength, &obj1_b_value) == JsNoError);
  987. REQUIRE(JsGetPropertyIdFromName(_u("b"), &obj1_b_pid) == JsNoError);
  988. REQUIRE(JsSetProperty(object1, obj1_b_pid, obj1_b_value, true) == JsNoError);
  989. REQUIRE(JsPointerToString(_u("obj2.x"), propNameLength, &obj2_x_value) == JsNoError);
  990. REQUIRE(JsGetPropertyIdFromName(_u("x"), &obj2_x_pid) == JsNoError);
  991. REQUIRE(JsSetProperty(object2, obj2_x_pid, obj2_x_value, true) == JsNoError);
  992. REQUIRE(JsPointerToString(_u("obj1.y"), propNameLength, &obj2_y_value) == JsNoError);
  993. REQUIRE(JsGetPropertyIdFromName(_u("y"), &obj2_y_pid) == JsNoError);
  994. REQUIRE(JsSetProperty(object2, obj2_y_pid, obj2_y_value, true) == JsNoError);
  995. REQUIRE(JsPointerToString(_u("obj1.z"), propNameLength, &obj2_z_value) == JsNoError);
  996. REQUIRE(JsGetPropertyIdFromName(_u("z"), &obj2_z_pid) == JsNoError);
  997. REQUIRE(JsSetProperty(object2, obj2_z_pid, obj2_z_value, true) == JsNoError);
  998. REQUIRE(JsSetPrototype(object1, proto) == JsNoError);
  999. REQUIRE(JsSetPrototype(object2, proto) == JsNoError);
  1000. JsValueRef objectProto = JS_INVALID_REFERENCE;
  1001. REQUIRE(JsGetPrototype(object1, &objectProto) == JsNoError);
  1002. CHECK(proto == objectProto);
  1003. REQUIRE(JsGetPrototype(object2, &objectProto) == JsNoError);
  1004. CHECK(proto == objectProto);
  1005. JsValueRef value = JS_INVALID_REFERENCE;
  1006. REQUIRE(JsGetProperty(object1, obj1_a_pid, &value) == JsNoError);
  1007. CHECK(value == obj1_a_value);
  1008. REQUIRE(JsGetProperty(object1, obj1_b_pid, &value) == JsNoError);
  1009. CHECK(value == obj1_b_value);
  1010. REQUIRE(JsGetProperty(object2, obj2_x_pid, &value) == JsNoError);
  1011. CHECK(value == obj2_x_value);
  1012. REQUIRE(JsGetProperty(object2, obj2_y_pid, &value) == JsNoError);
  1013. CHECK(value == obj2_y_value);
  1014. REQUIRE(JsGetProperty(object2, obj2_z_pid, &value) == JsNoError);
  1015. CHECK(value == obj2_z_value);
  1016. }
  1017. TEST_CASE("ApiTest_SetPrototypeTest", "[ApiTest]")
  1018. {
  1019. JsRTApiTest::RunWithAttributes(JsRTApiTest::SetPrototypeTest);
  1020. }
  1021. void DisableEval(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1022. {
  1023. JsValueRef result = JS_INVALID_REFERENCE;
  1024. JsErrorCode error = JsRunScript(_u("eval(\"1 + 2\")"), JS_SOURCE_CONTEXT_NONE, _u(""), &result);
  1025. if (!(attributes & JsRuntimeAttributeDisableEval))
  1026. {
  1027. CHECK(error == JsNoError);
  1028. }
  1029. else
  1030. {
  1031. CHECK(error == JsErrorScriptEvalDisabled);
  1032. }
  1033. error = JsRunScript(_u("new Function(\"return 1 + 2\")"), JS_SOURCE_CONTEXT_NONE, _u(""), &result);
  1034. if (!(attributes & JsRuntimeAttributeDisableEval))
  1035. {
  1036. CHECK(error == JsNoError);
  1037. }
  1038. else
  1039. {
  1040. CHECK(error == JsErrorScriptEvalDisabled);
  1041. }
  1042. }
  1043. TEST_CASE("ApiTest_DisableEval", "[ApiTest]")
  1044. {
  1045. JsRTApiTest::RunWithAttributes(JsRTApiTest::DisableEval);
  1046. }
  1047. static void CALLBACK PromiseContinuationCallback(JsValueRef task, void *callbackState)
  1048. {
  1049. CHECK(callbackState != nullptr);
  1050. CHECK(*(void **)callbackState == nullptr);
  1051. // All the task need to finish async, so we need to save the callback.
  1052. *(void **)callbackState = task;
  1053. }
  1054. void PromisesTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1055. {
  1056. JsValueRef result = JS_INVALID_REFERENCE;
  1057. JsValueType valueType;
  1058. JsValueRef task = JS_INVALID_REFERENCE;
  1059. JsValueRef callback = JS_INVALID_REFERENCE;
  1060. REQUIRE(JsSetPromiseContinuationCallback(PromiseContinuationCallback, &callback) == JsNoError);
  1061. REQUIRE(JsRunScript(
  1062. _u("new Promise(") \
  1063. _u(" function(resolve, reject) {") \
  1064. _u(" resolve('basic:success');") \
  1065. _u(" }") \
  1066. _u(").then (") \
  1067. _u(" function () { return new Promise(") \
  1068. _u(" function(resolve, reject) { ") \
  1069. _u(" resolve('second:success'); ") \
  1070. _u(" })") \
  1071. _u(" }") \
  1072. _u(");"), JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsNoError);
  1073. CHECK(callback != nullptr);
  1074. JsValueRef args[] = { GetUndefined() };
  1075. // first then handler was queued
  1076. task = callback;
  1077. callback = JS_INVALID_REFERENCE;
  1078. REQUIRE(JsGetValueType(task, &valueType) == JsNoError);
  1079. CHECK(valueType == JsFunction);
  1080. REQUIRE(JsCallFunction(task, args, _countof(args), &result) == JsNoError);
  1081. // the second promise resolution was queued
  1082. task = callback;
  1083. callback = JS_INVALID_REFERENCE;
  1084. REQUIRE(JsGetValueType(task, &valueType) == JsNoError);
  1085. CHECK(valueType == JsFunction);
  1086. REQUIRE(JsCallFunction(task, args, _countof(args), &result) == JsNoError);
  1087. // second then handler was queued.
  1088. task = callback;
  1089. callback = JS_INVALID_REFERENCE;
  1090. REQUIRE(JsGetValueType(task, &valueType) == JsNoError);
  1091. CHECK(valueType == JsFunction);
  1092. REQUIRE(JsCallFunction(task, args, _countof(args), &result) == JsNoError);
  1093. // we are done; no more new task are queue.
  1094. CHECK(callback == JS_INVALID_REFERENCE);
  1095. }
  1096. TEST_CASE("ApiTest_PromisesTest", "[ApiTest]")
  1097. {
  1098. JsRTApiTest::RunWithAttributes(JsRTApiTest::PromisesTest);
  1099. }
  1100. void ArrayBufferTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1101. {
  1102. for (int type = JsArrayTypeInt8; type <= JsArrayTypeFloat64; type++)
  1103. {
  1104. unsigned int size = 0;
  1105. switch (type)
  1106. {
  1107. case JsArrayTypeInt16:
  1108. size = sizeof(__int16);
  1109. break;
  1110. case JsArrayTypeInt8:
  1111. size = sizeof(__int8);
  1112. break;
  1113. case JsArrayTypeUint8:
  1114. case JsArrayTypeUint8Clamped:
  1115. size = sizeof(unsigned __int8);
  1116. break;
  1117. case JsArrayTypeUint16:
  1118. size = sizeof(unsigned __int16);
  1119. break;
  1120. case JsArrayTypeInt32:
  1121. size = sizeof(__int32);
  1122. break;
  1123. case JsArrayTypeUint32:
  1124. size = sizeof(unsigned __int32);
  1125. break;
  1126. case JsArrayTypeFloat32:
  1127. size = sizeof(float);
  1128. break;
  1129. case JsArrayTypeFloat64:
  1130. size = sizeof(double);
  1131. break;
  1132. }
  1133. // ArrayBuffer
  1134. JsValueRef arrayBuffer = JS_INVALID_REFERENCE;
  1135. JsValueType valueType;
  1136. BYTE *originBuffer = nullptr;
  1137. unsigned int originBufferLength;
  1138. REQUIRE(JsCreateArrayBuffer(16 * size, &arrayBuffer) == JsNoError);
  1139. REQUIRE(JsGetValueType(arrayBuffer, &valueType) == JsNoError);
  1140. CHECK(JsValueType::JsArrayBuffer == valueType);
  1141. REQUIRE(JsGetArrayBufferStorage(arrayBuffer, &originBuffer, &originBufferLength) == JsNoError);
  1142. CHECK(16 * size == originBufferLength);
  1143. // TypedArray
  1144. JsValueRef typedArray = JS_INVALID_REFERENCE;
  1145. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, arrayBuffer, /*byteOffset*/size, /*length*/12, &typedArray) == JsNoError);
  1146. REQUIRE(JsGetValueType(typedArray, &valueType) == JsNoError);
  1147. CHECK(JsValueType::JsTypedArray == valueType);
  1148. JsTypedArrayType arrayType;
  1149. JsValueRef tmpArrayBuffer = JS_INVALID_REFERENCE;
  1150. unsigned int tmpByteOffset, tmpByteLength;
  1151. REQUIRE(JsGetTypedArrayInfo(typedArray, &arrayType, &tmpArrayBuffer, &tmpByteOffset, &tmpByteLength) == JsNoError);
  1152. CHECK(type == arrayType);
  1153. CHECK(arrayBuffer == tmpArrayBuffer);
  1154. CHECK(size == tmpByteOffset);
  1155. CHECK(12 * size == tmpByteLength);
  1156. BYTE *buffer = nullptr;
  1157. unsigned int bufferLength;
  1158. int elementSize;
  1159. REQUIRE(JsGetTypedArrayStorage(typedArray, &buffer, &bufferLength, &arrayType, &elementSize) == JsNoError);
  1160. CHECK(originBuffer + size == buffer);
  1161. CHECK(12 * size == bufferLength);
  1162. CHECK(type == arrayType);
  1163. CHECK(size == (size_t)elementSize);
  1164. // DataView
  1165. JsValueRef dataView = JS_INVALID_REFERENCE;
  1166. REQUIRE(JsCreateDataView(arrayBuffer, /*byteOffset*/3, /*byteLength*/13, &dataView) == JsNoError);
  1167. REQUIRE(JsGetValueType(dataView, &valueType) == JsNoError);
  1168. CHECK(JsValueType::JsDataView == valueType);
  1169. REQUIRE(JsGetDataViewStorage(dataView, &buffer, &bufferLength) == JsNoError);
  1170. CHECK(originBuffer + 3 == buffer);
  1171. CHECK(13 == (int)bufferLength);
  1172. // InvalidArgs Get...
  1173. JsValueRef bad = JS_INVALID_REFERENCE;
  1174. REQUIRE(JsIntToNumber(5, &bad) == JsNoError);
  1175. REQUIRE(JsGetArrayBufferStorage(typedArray, &buffer, &bufferLength) == JsErrorInvalidArgument);
  1176. REQUIRE(JsGetArrayBufferStorage(dataView, &buffer, &bufferLength) == JsErrorInvalidArgument);
  1177. REQUIRE(JsGetArrayBufferStorage(bad, &buffer, &bufferLength) == JsErrorInvalidArgument);
  1178. REQUIRE(JsGetTypedArrayStorage(arrayBuffer, &buffer, &bufferLength, &arrayType, &elementSize) == JsErrorInvalidArgument);
  1179. REQUIRE(JsGetTypedArrayStorage(dataView, &buffer, &bufferLength, &arrayType, &elementSize) == JsErrorInvalidArgument);
  1180. REQUIRE(JsGetTypedArrayStorage(bad, &buffer, &bufferLength, &arrayType, &elementSize) == JsErrorInvalidArgument);
  1181. REQUIRE(JsGetDataViewStorage(arrayBuffer, &buffer, &bufferLength) == JsErrorInvalidArgument);
  1182. REQUIRE(JsGetDataViewStorage(typedArray, &buffer, &bufferLength) == JsErrorInvalidArgument);
  1183. REQUIRE(JsGetDataViewStorage(bad, &buffer, &bufferLength) == JsErrorInvalidArgument);
  1184. // no base array
  1185. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, JS_INVALID_REFERENCE, /*byteOffset*/0, /*length*/0, &typedArray) == JsNoError); // no base array
  1186. REQUIRE(JsGetTypedArrayInfo(typedArray, &arrayType, &tmpArrayBuffer, &tmpByteOffset, &tmpByteLength) == JsNoError);
  1187. CHECK(type == arrayType);
  1188. CHECK(tmpArrayBuffer != nullptr);
  1189. CHECK(tmpByteOffset == 0);
  1190. CHECK(tmpByteLength == 0);
  1191. // InvalidArgs Create...
  1192. REQUIRE(JsCreateTypedArray((JsTypedArrayType)(type + 100), arrayBuffer, /*byteOffset*/size, /*length*/12, &typedArray) == JsErrorInvalidArgument); // bad array type
  1193. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, JS_INVALID_REFERENCE, /*byteOffset*/size, /*length*/12, &typedArray) == JsErrorInvalidArgument); // byteOffset should be 0
  1194. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, dataView, /*byteOffset*/size, /*length*/12, &typedArray) == JsErrorInvalidArgument); // byteOffset should be 0
  1195. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, bad, /*byteOffset*/size, /*length*/12, &typedArray) == JsErrorInvalidArgument); // byteOffset should be 0
  1196. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, dataView, /*byteOffset*/0, /*length*/12, &typedArray) == JsErrorInvalidArgument); // length should be 0
  1197. REQUIRE(JsCreateTypedArray((JsTypedArrayType)type, bad, /*byteOffset*/0, /*length*/12, &typedArray) == JsErrorInvalidArgument); // length should be 0
  1198. REQUIRE(JsCreateDataView(typedArray, /*byteOffset*/size, /*byteLength*/12, &dataView) == JsErrorInvalidArgument); // must from arrayBuffer
  1199. REQUIRE(JsCreateDataView(dataView, /*byteOffset*/size, /*byteLength*/12, &dataView) == JsErrorInvalidArgument); // must from arrayBuffer
  1200. REQUIRE(JsCreateDataView(bad, /*byteOffset*/size, /*byteLength*/12, &dataView) == JsErrorInvalidArgument); // must from arrayBuffer
  1201. }
  1202. }
  1203. TEST_CASE("ApiTest_ArrayBufferTest", "[ApiTest]")
  1204. {
  1205. JsRTApiTest::RunWithAttributes(JsRTApiTest::ArrayBufferTest);
  1206. }
  1207. struct ThreadArgsData
  1208. {
  1209. JsRuntimeHandle runtime;
  1210. HANDLE hMonitor;
  1211. BOOL isScriptActive;
  1212. static const int waitTime = 1000;
  1213. void BeginScriptExecution() { isScriptActive = true; }
  1214. void EndScriptExecution() { isScriptActive = false; }
  1215. void SignalMonitor() { SetEvent(hMonitor); }
  1216. unsigned int ThreadProc()
  1217. {
  1218. while (1)
  1219. {
  1220. WaitForSingleObject(hMonitor, INFINITE);
  1221. // TODO: have a generic stopping mechanism.
  1222. if (isScriptActive)
  1223. {
  1224. Sleep(waitTime);
  1225. REQUIRE(JsDisableRuntimeExecution(runtime) == JsNoError);
  1226. }
  1227. else
  1228. {
  1229. CloseHandle(hMonitor);
  1230. break;
  1231. }
  1232. }
  1233. return 0;
  1234. }
  1235. };
  1236. static unsigned int CALLBACK StaticThreadProc(LPVOID lpParameter)
  1237. {
  1238. DWORD ret = (DWORD)-1;
  1239. ThreadArgsData * args = (ThreadArgsData *)lpParameter;
  1240. ret = args->ThreadProc();
  1241. return ret;
  1242. }
  1243. #define TERMINATION_TESTS \
  1244. _u("for (i=0; i<200; i = 20) {") \
  1245. _u(" var a = new Int8Array(800);") \
  1246. _u("}"), \
  1247. \
  1248. _u("function nextFunc() { ") \
  1249. _u(" throw 'hello'") \
  1250. _u("};") \
  1251. _u("for (i=0; i<200; i = 20) { ") \
  1252. _u(" try {") \
  1253. _u(" nextFunc();") \
  1254. _u(" } ") \
  1255. _u(" catch(e) {}") \
  1256. _u("}"), \
  1257. \
  1258. _u("function nextFunc() {") \
  1259. _u(" bar = bar + nextFunc.toString();") \
  1260. _u("};") \
  1261. _u("bar = '';") \
  1262. _u("for (i=0; i<200; i = 20) {") \
  1263. _u(" nextFunc()") \
  1264. _u("}"), \
  1265. \
  1266. _u("while(1);"), \
  1267. \
  1268. _u("function foo(){}") \
  1269. _u("do{") \
  1270. _u(" foo();") \
  1271. _u("}while(1);"), \
  1272. \
  1273. _u("(function foo(){") \
  1274. _u(" do {") \
  1275. _u(" if (foo) continue;") \
  1276. _u(" if (!foo) break;") \
  1277. _u(" } while(1); ") \
  1278. _u("})();"), \
  1279. \
  1280. _u("(function foo(a){") \
  1281. _u(" while (a){") \
  1282. _u(" L1:") \
  1283. _u(" do {") \
  1284. _u(" while(1) {") \
  1285. _u(" continue L1;") \
  1286. _u(" }") \
  1287. _u(" a = 0;") \
  1288. _u(" } while(0);") \
  1289. _u(" }") \
  1290. _u("})(1);"), \
  1291. \
  1292. _u("(function (){") \
  1293. _u(" while (1) {") \
  1294. _u(" try {") \
  1295. _u(" throw 0;") \
  1296. _u(" break;") \
  1297. _u(" }") \
  1298. _u(" catch(e) {") \
  1299. _u(" if (!e) continue;") \
  1300. _u(" }") \
  1301. _u(" break;") \
  1302. _u(" }") \
  1303. _u("})();")
  1304. static const LPCWSTR terminationTests[] = { TERMINATION_TESTS };
  1305. void ExternalFunctionWithScriptAbortionTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1306. {
  1307. if (!(attributes & JsRuntimeAttributeAllowScriptInterrupt))
  1308. {
  1309. REQUIRE(JsDisableRuntimeExecution(runtime) == JsErrorCannotDisableExecution);
  1310. return;
  1311. }
  1312. ThreadArgsData threadArgs = {};
  1313. threadArgs.runtime = runtime;
  1314. threadArgs.hMonitor = CreateEvent(nullptr, FALSE, FALSE, nullptr);
  1315. HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &StaticThreadProc, &threadArgs, 0, nullptr));
  1316. REQUIRE(threadHandle != nullptr);
  1317. if (threadHandle == nullptr)
  1318. {
  1319. // This is to satisfy preFAST, above REQUIRE call ensuring that it will report exception when threadHandle is null.
  1320. return;
  1321. }
  1322. JsValueRef preScriptAbortFunction = JS_INVALID_REFERENCE, postScriptAbortFunction = JS_INVALID_REFERENCE;
  1323. JsValueRef exception = JS_INVALID_REFERENCE;
  1324. for (int i = 0; i < _countof(terminationTests); i++)
  1325. {
  1326. threadArgs.BeginScriptExecution();
  1327. threadArgs.SignalMonitor();
  1328. REQUIRE(JsCreateFunction(ExternalFunctionPreScriptAbortionCallback, nullptr, &preScriptAbortFunction) == JsNoError);
  1329. REQUIRE(JsCreateFunction(ExternalFunctionPostScriptAbortionCallback, nullptr, &postScriptAbortFunction) == JsNoError);
  1330. JsValueRef scriptTextArg = JS_INVALID_REFERENCE;
  1331. WCHAR *scriptText = const_cast<WCHAR *>(terminationTests[i]);
  1332. REQUIRE(JsPointerToString(scriptText, wcslen(scriptText), &scriptTextArg) == JsNoError);
  1333. JsValueRef args[] = { scriptTextArg };
  1334. REQUIRE(JsCallFunction(preScriptAbortFunction, args, 1, nullptr) == JsErrorScriptTerminated);
  1335. bool isDisabled;
  1336. REQUIRE(JsIsRuntimeExecutionDisabled(runtime, &isDisabled) == JsNoError);
  1337. CHECK(isDisabled);
  1338. REQUIRE(JsCallFunction(postScriptAbortFunction, args, 1, nullptr) == JsErrorInDisabledState);
  1339. REQUIRE(JsGetAndClearException(&exception) == JsErrorInDisabledState);
  1340. REQUIRE(JsEnableRuntimeExecution(runtime) == JsNoError);
  1341. threadArgs.EndScriptExecution();
  1342. }
  1343. threadArgs.SignalMonitor();
  1344. WaitForSingleObject(threadHandle, INFINITE);
  1345. threadArgs.hMonitor = nullptr;
  1346. }
  1347. TEST_CASE("ApiTest_ExternalFunctionWithScriptAbortionTest", "[ApiTest]")
  1348. {
  1349. JsRTApiTest::RunWithAttributes(JsRTApiTest::ExternalFunctionWithScriptAbortionTest);
  1350. }
  1351. void ScriptTerminationTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1352. {
  1353. // can't interrupt if scriptinterrupt is disabled.
  1354. if (!(attributes & JsRuntimeAttributeAllowScriptInterrupt))
  1355. {
  1356. REQUIRE(JsDisableRuntimeExecution(runtime) == JsErrorCannotDisableExecution);
  1357. return;
  1358. }
  1359. ThreadArgsData threadArgs = {};
  1360. threadArgs.runtime = runtime;
  1361. threadArgs.hMonitor = CreateEvent(nullptr, FALSE, FALSE, nullptr);
  1362. HANDLE threadHandle = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &StaticThreadProc, &threadArgs, 0, nullptr));
  1363. REQUIRE(threadHandle != nullptr);
  1364. if (threadHandle == nullptr)
  1365. {
  1366. // This is to satisfy preFAST, above REQUIRE call ensuring that it will report exception when threadHandle is null.
  1367. return;
  1368. }
  1369. JsValueRef result;
  1370. JsValueRef exception;
  1371. for (int i = 0; i < _countof(terminationTests); i++)
  1372. {
  1373. threadArgs.BeginScriptExecution();
  1374. threadArgs.SignalMonitor();
  1375. REQUIRE(JsRunScript(terminationTests[i], JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsErrorScriptTerminated);
  1376. bool isDisabled;
  1377. REQUIRE(JsIsRuntimeExecutionDisabled(runtime, &isDisabled) == JsNoError);
  1378. CHECK(isDisabled);
  1379. REQUIRE(JsRunScript(terminationTests[i], JS_SOURCE_CONTEXT_NONE, _u(""), &result) == JsErrorInDisabledState);
  1380. REQUIRE(JsGetAndClearException(&exception) == JsErrorInDisabledState);
  1381. REQUIRE(JsEnableRuntimeExecution(runtime) == JsNoError);
  1382. threadArgs.EndScriptExecution();
  1383. }
  1384. threadArgs.SignalMonitor();
  1385. WaitForSingleObject(threadHandle, INFINITE);
  1386. threadArgs.hMonitor = nullptr;
  1387. }
  1388. TEST_CASE("ApiTest_ScriptTerminationTest", "[ApiTest]")
  1389. {
  1390. JsRTApiTest::RunWithAttributes(JsRTApiTest::ScriptTerminationTest);
  1391. }
  1392. struct ModuleResponseData
  1393. {
  1394. ModuleResponseData()
  1395. : mainModule(JS_INVALID_REFERENCE), childModule(JS_INVALID_REFERENCE), mainModuleException(JS_INVALID_REFERENCE), mainModuleReady(false)
  1396. {
  1397. }
  1398. JsModuleRecord mainModule;
  1399. JsModuleRecord childModule;
  1400. JsValueRef mainModuleException;
  1401. bool mainModuleReady;
  1402. };
  1403. ModuleResponseData successTest;
  1404. static JsErrorCode CALLBACK Success_FIMC(_In_ JsModuleRecord referencingModule, _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord)
  1405. {
  1406. JsModuleRecord moduleRecord = JS_INVALID_REFERENCE;
  1407. LPCWSTR specifierStr;
  1408. size_t length;
  1409. JsErrorCode errorCode = JsStringToPointer(specifier, &specifierStr, &length);
  1410. REQUIRE(errorCode == JsNoError);
  1411. REQUIRE(!wcscmp(specifierStr, _u("foo.js")));
  1412. errorCode = JsInitializeModuleRecord(referencingModule, specifier, &moduleRecord);
  1413. REQUIRE(errorCode == JsNoError);
  1414. *dependentModuleRecord = moduleRecord;
  1415. successTest.childModule = moduleRecord;
  1416. return JsNoError;
  1417. }
  1418. static JsErrorCode CALLBACK Succes_NMRC(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef exceptionVar)
  1419. {
  1420. if (successTest.mainModule == referencingModule)
  1421. {
  1422. successTest.mainModuleReady = true;
  1423. successTest.mainModuleException = exceptionVar;
  1424. }
  1425. return JsNoError;
  1426. }
  1427. void ModuleSuccessTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1428. {
  1429. JsModuleRecord requestModule = JS_INVALID_REFERENCE;
  1430. JsValueRef specifier;
  1431. REQUIRE(JsPointerToString(_u(""), 1, &specifier) == JsNoError);
  1432. REQUIRE(JsInitializeModuleRecord(nullptr, specifier, &requestModule) == JsNoError);
  1433. successTest.mainModule = requestModule;
  1434. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_FetchImportedModuleCallback, Success_FIMC) == JsNoError);
  1435. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_NotifyModuleReadyCallback, Succes_NMRC) == JsNoError);
  1436. JsValueRef errorObject = JS_INVALID_REFERENCE;
  1437. const char* fileContent = "import {x} from 'foo.js'";
  1438. JsErrorCode errorCode = JsParseModuleSource(requestModule, 0, (LPBYTE)fileContent,
  1439. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  1440. CHECK(errorCode == JsNoError);
  1441. CHECK(errorObject == JS_INVALID_REFERENCE);
  1442. CHECK(successTest.mainModuleReady == false);
  1443. REQUIRE(successTest.childModule != JS_INVALID_REFERENCE);
  1444. errorObject = JS_INVALID_REFERENCE;
  1445. fileContent = "/*error code*/ var x x";
  1446. errorCode = JsParseModuleSource(successTest.childModule, 1, (LPBYTE)fileContent,
  1447. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  1448. CHECK(errorCode == JsErrorScriptCompile);
  1449. CHECK(errorObject != JS_INVALID_REFERENCE);
  1450. CHECK(successTest.mainModuleReady == true);
  1451. REQUIRE(successTest.mainModuleException != JS_INVALID_REFERENCE);
  1452. JsPropertyIdRef message = JS_INVALID_REFERENCE;
  1453. REQUIRE(JsGetPropertyIdFromName(_u("message"), &message) == JsNoError);
  1454. JsValueRef value1Check = JS_INVALID_REFERENCE;
  1455. REQUIRE(JsGetProperty(successTest.mainModuleException, message, &value1Check) == JsNoError);
  1456. JsValueRef asString = JS_INVALID_REFERENCE;
  1457. REQUIRE(JsConvertValueToString(value1Check, &asString) == JsNoError);
  1458. LPCWSTR str = nullptr;
  1459. size_t length;
  1460. REQUIRE(JsStringToPointer(asString, &str, &length) == JsNoError);
  1461. REQUIRE(!wcscmp(str, _u("Expected ';'")));
  1462. }
  1463. TEST_CASE("ApiTest_ModuleSuccessTest", "[ApiTest]")
  1464. {
  1465. JsRTApiTest::WithSetup(JsRuntimeAttributeEnableExperimentalFeatures, ModuleSuccessTest);
  1466. }
  1467. ModuleResponseData reentrantParseData;
  1468. static JsErrorCode CALLBACK ReentrantParse_FIMC(_In_ JsModuleRecord referencingModule, _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord)
  1469. {
  1470. JsModuleRecord moduleRecord = JS_INVALID_REFERENCE;
  1471. LPCWSTR specifierStr;
  1472. size_t length;
  1473. JsErrorCode errorCode = JsStringToPointer(specifier, &specifierStr, &length);
  1474. REQUIRE(!wcscmp(specifierStr, _u("foo.js")));
  1475. REQUIRE(errorCode == JsNoError);
  1476. errorCode = JsInitializeModuleRecord(referencingModule, specifier, &moduleRecord);
  1477. REQUIRE(errorCode == JsNoError);
  1478. *dependentModuleRecord = moduleRecord;
  1479. reentrantParseData.childModule = moduleRecord;
  1480. // directly make a call to parsemodulesource
  1481. JsValueRef errorObject = JS_INVALID_REFERENCE;
  1482. const char* fileContent = "/*error code*/ var x x";
  1483. // Not checking the error code.
  1484. JsParseModuleSource(moduleRecord, 1, (LPBYTE)fileContent,
  1485. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  1486. // There must be an error
  1487. CHECK(errorObject != JS_INVALID_REFERENCE);
  1488. // Passed everything is valid.
  1489. return JsNoError;
  1490. }
  1491. static JsErrorCode CALLBACK ReentrantParse_NMRC(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef exceptionVar)
  1492. {
  1493. if (reentrantParseData.mainModule == referencingModule)
  1494. {
  1495. reentrantParseData.mainModuleReady = true;
  1496. reentrantParseData.mainModuleException = exceptionVar;
  1497. }
  1498. return JsNoError;
  1499. }
  1500. void ReentrantParseModuleTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1501. {
  1502. JsModuleRecord requestModule = JS_INVALID_REFERENCE;
  1503. JsValueRef specifier;
  1504. REQUIRE(JsPointerToString(_u(""), 1, &specifier) == JsNoError);
  1505. REQUIRE(JsInitializeModuleRecord(nullptr, specifier, &requestModule) == JsNoError);
  1506. reentrantParseData.mainModule = requestModule;
  1507. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_FetchImportedModuleCallback, ReentrantParse_FIMC) == JsNoError);
  1508. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_NotifyModuleReadyCallback, ReentrantParse_NMRC) == JsNoError);
  1509. JsValueRef errorObject = JS_INVALID_REFERENCE;
  1510. const char* fileContent = "import {x} from 'foo.js'";
  1511. JsParseModuleSource(requestModule, 0, (LPBYTE)fileContent,
  1512. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  1513. CHECK(reentrantParseData.mainModuleReady == true);
  1514. REQUIRE(reentrantParseData.mainModuleException != JS_INVALID_REFERENCE);
  1515. JsPropertyIdRef message = JS_INVALID_REFERENCE;
  1516. REQUIRE(JsGetPropertyIdFromName(_u("message"), &message) == JsNoError);
  1517. JsValueRef value1Check = JS_INVALID_REFERENCE;
  1518. REQUIRE(JsGetProperty(reentrantParseData.mainModuleException, message, &value1Check) == JsNoError);
  1519. JsValueRef asString = JS_INVALID_REFERENCE;
  1520. REQUIRE(JsConvertValueToString(value1Check, &asString) == JsNoError);
  1521. LPCWSTR str = nullptr;
  1522. size_t length;
  1523. REQUIRE(JsStringToPointer(asString, &str, &length) == JsNoError);
  1524. REQUIRE(!wcscmp(str, _u("Expected ';'")));
  1525. }
  1526. TEST_CASE("ApiTest_ReentrantParseModuleTest", "[ApiTest]")
  1527. {
  1528. JsRTApiTest::WithSetup(JsRuntimeAttributeEnableExperimentalFeatures, ReentrantParseModuleTest);
  1529. }
  1530. ModuleResponseData reentrantNoErrorParseData;
  1531. static JsErrorCode CALLBACK reentrantNoErrorParse_FIMC(_In_ JsModuleRecord referencingModule, _In_ JsValueRef specifier, _Outptr_result_maybenull_ JsModuleRecord* dependentModuleRecord)
  1532. {
  1533. JsModuleRecord moduleRecord = JS_INVALID_REFERENCE;
  1534. LPCWSTR specifierStr;
  1535. size_t length;
  1536. JsErrorCode errorCode = JsStringToPointer(specifier, &specifierStr, &length);
  1537. REQUIRE(!wcscmp(specifierStr, _u("foo.js")));
  1538. REQUIRE(errorCode == JsNoError);
  1539. errorCode = JsInitializeModuleRecord(referencingModule, specifier, &moduleRecord);
  1540. REQUIRE(errorCode == JsNoError);
  1541. *dependentModuleRecord = moduleRecord;
  1542. reentrantNoErrorParseData.childModule = moduleRecord;
  1543. JsValueRef errorObject = JS_INVALID_REFERENCE;
  1544. const char* fileContent = "export var x = 10;";
  1545. // Not checking the error code.
  1546. JsParseModuleSource(moduleRecord, 1, (LPBYTE)fileContent,
  1547. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  1548. // There must be an error
  1549. CHECK(errorObject == JS_INVALID_REFERENCE);
  1550. return JsNoError;
  1551. }
  1552. static JsErrorCode CALLBACK reentrantNoErrorParse_NMRC(_In_opt_ JsModuleRecord referencingModule, _In_opt_ JsValueRef exceptionVar)
  1553. {
  1554. if (reentrantNoErrorParseData.mainModule == referencingModule)
  1555. {
  1556. reentrantNoErrorParseData.mainModuleReady = true;
  1557. reentrantNoErrorParseData.mainModuleException = exceptionVar;
  1558. }
  1559. return JsNoError;
  1560. }
  1561. void ReentrantNoErrorParseModuleTest(JsRuntimeAttributes attributes, JsRuntimeHandle runtime)
  1562. {
  1563. JsModuleRecord requestModule = JS_INVALID_REFERENCE;
  1564. JsValueRef specifier;
  1565. REQUIRE(JsPointerToString(_u(""), 1, &specifier) == JsNoError);
  1566. REQUIRE(JsInitializeModuleRecord(nullptr, specifier, &requestModule) == JsNoError);
  1567. reentrantNoErrorParseData.mainModule = requestModule;
  1568. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_FetchImportedModuleCallback, reentrantNoErrorParse_FIMC) == JsNoError);
  1569. REQUIRE(JsSetModuleHostInfo(requestModule, JsModuleHostInfo_NotifyModuleReadyCallback, reentrantNoErrorParse_NMRC) == JsNoError);
  1570. JsValueRef errorObject = JS_INVALID_REFERENCE;
  1571. const char* fileContent = "import {x} from 'foo.js'";
  1572. JsErrorCode errorCode = JsParseModuleSource(requestModule, 0, (LPBYTE)fileContent,
  1573. (unsigned int)strlen(fileContent), JsParseModuleSourceFlags_DataIsUTF8, &errorObject);
  1574. // This is no error in this module parse.
  1575. CHECK(errorCode == JsNoError);
  1576. CHECK(errorObject == JS_INVALID_REFERENCE);
  1577. CHECK(reentrantNoErrorParseData.mainModuleReady == true);
  1578. REQUIRE(reentrantNoErrorParseData.mainModuleException == JS_INVALID_REFERENCE);
  1579. }
  1580. TEST_CASE("ApiTest_ReentrantNoErrorParseModuleTest", "[ApiTest]")
  1581. {
  1582. JsRTApiTest::WithSetup(JsRuntimeAttributeEnableExperimentalFeatures, ReentrantNoErrorParseModuleTest);
  1583. }
  1584. }