JsRTApiTest.cpp 126 KB

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