InteropTests.cs 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.Linq;
  5. using System.Linq.Expressions;
  6. using System.Reflection;
  7. using Jint.Native;
  8. using Jint.Native.Array;
  9. using Jint.Native.Object;
  10. using Jint.Runtime.Interop;
  11. using Jint.Tests.Runtime.Converters;
  12. using Jint.Tests.Runtime.Domain;
  13. using Shapes;
  14. using Xunit;
  15. namespace Jint.Tests.Runtime
  16. {
  17. public class InteropTests : IDisposable
  18. {
  19. private readonly Engine _engine;
  20. public InteropTests()
  21. {
  22. _engine = new Engine(cfg => cfg.AllowClr(
  23. typeof(Shape).GetTypeInfo().Assembly,
  24. typeof(Console).GetTypeInfo().Assembly,
  25. typeof(System.IO.File).GetTypeInfo().Assembly))
  26. .SetValue("log", new Action<object>(Console.WriteLine))
  27. .SetValue("assert", new Action<bool>(Assert.True))
  28. .SetValue("equal", new Action<object, object>(Assert.Equal))
  29. ;
  30. }
  31. void IDisposable.Dispose()
  32. {
  33. }
  34. private void RunTest(string source)
  35. {
  36. _engine.Execute(source);
  37. }
  38. [Fact]
  39. public void PrimitiveTypesCanBeSet()
  40. {
  41. _engine.SetValue("x", 10);
  42. _engine.SetValue("y", true);
  43. _engine.SetValue("z", "foo");
  44. RunTest(@"
  45. assert(x === 10);
  46. assert(y === true);
  47. assert(z === 'foo');
  48. ");
  49. }
  50. [Fact]
  51. public void DelegatesCanBeSet()
  52. {
  53. _engine.SetValue("square", new Func<double, double>(x => x * x));
  54. RunTest(@"
  55. assert(square(10) === 100);
  56. ");
  57. }
  58. [Fact]
  59. public void DelegateWithNullableParameterCanBePassedANull()
  60. {
  61. _engine.SetValue("isnull", new Func<double?, bool>(x => x == null));
  62. RunTest(@"
  63. assert(isnull(null) === true);
  64. ");
  65. }
  66. [Fact]
  67. public void DelegateWithObjectParameterCanBePassedANull()
  68. {
  69. _engine.SetValue("isnull", new Func<object, bool>(x => x == null));
  70. RunTest(@"
  71. assert(isnull(null) === true);
  72. ");
  73. }
  74. [Fact]
  75. public void DelegateWithNullableParameterCanBePassedAnUndefined()
  76. {
  77. _engine.SetValue("isnull", new Func<double?, bool>(x => x == null));
  78. RunTest(@"
  79. assert(isnull(undefined) === true);
  80. ");
  81. }
  82. [Fact]
  83. public void DelegateWithObjectParameterCanBePassedAnUndefined()
  84. {
  85. _engine.SetValue("isnull", new Func<object, bool>(x => x == null));
  86. RunTest(@"
  87. assert(isnull(undefined) === true);
  88. ");
  89. }
  90. [Fact]
  91. public void DelegateWithNullableParameterCanBeExcluded()
  92. {
  93. _engine.SetValue("isnull", new Func<double?, bool>(x => x == null));
  94. RunTest(@"
  95. assert(isnull() === true);
  96. ");
  97. }
  98. [Fact]
  99. public void DelegateWithObjectParameterCanBeExcluded()
  100. {
  101. _engine.SetValue("isnull", new Func<object, bool>(x => x == null));
  102. RunTest(@"
  103. assert(isnull() === true);
  104. ");
  105. }
  106. [Fact]
  107. public void DynamicDelegateCanBeSet()
  108. {
  109. #if NETFRAMEWORK
  110. var parameters = new[] { Expression.Parameter(typeof(int)), Expression.Parameter(typeof(int)) };
  111. var exp = Expression.Add(parameters[0], parameters[1]);
  112. var del = Expression.Lambda(exp, parameters).Compile();
  113. _engine.SetValue("add", del);
  114. RunTest(@"
  115. assert(add(1,1) === 2);
  116. ");
  117. #endif
  118. }
  119. [Fact]
  120. public void ExtraParametersAreIgnored()
  121. {
  122. _engine.SetValue("passNumber", new Func<int, int>(x => x));
  123. RunTest(@"
  124. assert(passNumber(123,'test',{},[],null) === 123);
  125. ");
  126. }
  127. private delegate string callParams(params object[] values);
  128. private delegate string callArgumentAndParams(string firstParam, params object[] values);
  129. [Fact]
  130. public void DelegatesWithParamsParameterCanBeInvoked()
  131. {
  132. var a = new A();
  133. _engine.SetValue("callParams", new callParams(a.Call13));
  134. _engine.SetValue("callArgumentAndParams", new callArgumentAndParams(a.Call14));
  135. RunTest(@"
  136. assert(callParams('1','2','3') === '1,2,3');
  137. assert(callParams('1') === '1');
  138. assert(callParams() === '');
  139. assert(callArgumentAndParams('a','1','2','3') === 'a:1,2,3');
  140. assert(callArgumentAndParams('a','1') === 'a:1');
  141. assert(callArgumentAndParams('a') === 'a:');
  142. assert(callArgumentAndParams() === ':');
  143. ");
  144. }
  145. [Fact]
  146. public void DelegateWithDefaultValueParametersCanBeInvoked()
  147. {
  148. var instance = new A();
  149. _engine.SetValue("Instance", instance);
  150. _engine.SetValue("Class", TypeReference.CreateTypeReference(_engine, typeof(A)));
  151. RunTest(@"
  152. assert(Instance.Call19() === 0);
  153. assert(Instance.Call19(1) === 1);
  154. assert(Instance.Call20(1) === 4);
  155. assert(Instance.Call20(1, 2) === 5);
  156. assert(Instance.Call20(1 , 2, 3) === 6);
  157. assert(Class.Call19Static() === 0);
  158. assert(Class.Call19Static(1) === 1);
  159. assert(Class.Call20Static(1) === 4);
  160. assert(Class.Call20Static(1, 2) === 5);
  161. assert(Class.Call20Static(1 , 2, 3) === 6);
  162. ");
  163. }
  164. [Fact]
  165. public void CanGetObjectProperties()
  166. {
  167. var p = new Person
  168. {
  169. Name = "Mickey Mouse"
  170. };
  171. _engine.SetValue("p", p);
  172. RunTest(@"
  173. assert(p.Name === 'Mickey Mouse');
  174. ");
  175. }
  176. [Fact]
  177. public void CanInvokeObjectMethods()
  178. {
  179. var p = new Person
  180. {
  181. Name = "Mickey Mouse"
  182. };
  183. _engine.SetValue("p", p);
  184. RunTest(@"
  185. assert(p.ToString() === 'Mickey Mouse');
  186. ");
  187. }
  188. [Fact]
  189. public void CanInvokeObjectMethodsWithPascalCase()
  190. {
  191. var p = new Person
  192. {
  193. Name = "Mickey Mouse"
  194. };
  195. _engine.SetValue("p", p);
  196. RunTest(@"
  197. assert(p.toString() === 'Mickey Mouse');
  198. ");
  199. }
  200. [Fact]
  201. public void CanSetObjectProperties()
  202. {
  203. var p = new Person
  204. {
  205. Name = "Mickey Mouse"
  206. };
  207. _engine.SetValue("p", p);
  208. RunTest(@"
  209. p.Name = 'Donald Duck';
  210. assert(p.Name === 'Donald Duck');
  211. ");
  212. Assert.Equal("Donald Duck", p.Name);
  213. }
  214. [Fact]
  215. public void CanGetIndexUsingStringKey()
  216. {
  217. var dictionary = new Dictionary<string, Person>();
  218. dictionary.Add("person1", new Person { Name = "Mickey Mouse" });
  219. dictionary.Add("person2", new Person { Name = "Goofy" });
  220. _engine.SetValue("dictionary", dictionary);
  221. RunTest(@"
  222. assert(dictionary['person1'].Name === 'Mickey Mouse');
  223. assert(dictionary['person2'].Name === 'Goofy');
  224. ");
  225. }
  226. [Fact]
  227. public void CanSetIndexUsingStringKey()
  228. {
  229. var dictionary = new Dictionary<string, Person>();
  230. dictionary.Add("person1", new Person { Name = "Mickey Mouse" });
  231. dictionary.Add("person2", new Person { Name = "Goofy" });
  232. _engine.SetValue("dictionary", dictionary);
  233. RunTest(@"
  234. dictionary['person2'].Name = 'Donald Duck';
  235. assert(dictionary['person2'].Name === 'Donald Duck');
  236. ");
  237. Assert.Equal("Donald Duck", dictionary["person2"].Name);
  238. }
  239. [Fact]
  240. public void CanGetIndexUsingIntegerKey()
  241. {
  242. var dictionary = new Dictionary<int, string>();
  243. dictionary.Add(1, "Mickey Mouse");
  244. dictionary.Add(2, "Goofy");
  245. _engine.SetValue("dictionary", dictionary);
  246. RunTest(@"
  247. assert(dictionary[1] === 'Mickey Mouse');
  248. assert(dictionary[2] === 'Goofy');
  249. ");
  250. }
  251. [Fact]
  252. public void CanSetIndexUsingIntegerKey()
  253. {
  254. var dictionary = new Dictionary<int, string>();
  255. dictionary.Add(1, "Mickey Mouse");
  256. dictionary.Add(2, "Goofy");
  257. _engine.SetValue("dictionary", dictionary);
  258. RunTest(@"
  259. dictionary[2] = 'Donald Duck';
  260. assert(dictionary[2] === 'Donald Duck');
  261. ");
  262. Assert.Equal("Mickey Mouse", dictionary[1]);
  263. Assert.Equal("Donald Duck", dictionary[2]);
  264. }
  265. private class DoubleIndexedClass
  266. {
  267. public int this[int index]
  268. {
  269. get { return index; }
  270. }
  271. public string this[string index]
  272. {
  273. get { return index; }
  274. }
  275. }
  276. [Fact]
  277. public void CanGetIndexUsingBothIntAndStringIndex()
  278. {
  279. var dictionary = new DoubleIndexedClass();
  280. _engine.SetValue("dictionary", dictionary);
  281. RunTest(@"
  282. assert(dictionary[1] === 1);
  283. assert(dictionary['test'] === 'test');
  284. ");
  285. }
  286. [Fact]
  287. public void CanUseGenericMethods()
  288. {
  289. var dictionary = new Dictionary<int, string>();
  290. dictionary.Add(1, "Mickey Mouse");
  291. _engine.SetValue("dictionary", dictionary);
  292. RunTest(@"
  293. dictionary.Add(2, 'Goofy');
  294. assert(dictionary[2] === 'Goofy');
  295. ");
  296. Assert.Equal("Mickey Mouse", dictionary[1]);
  297. Assert.Equal("Goofy", dictionary[2]);
  298. }
  299. [Fact]
  300. public void CanUseMultiGenericTypes()
  301. {
  302. RunTest(@"
  303. var type = System.Collections.Generic.Dictionary(System.Int32, System.String);
  304. var dictionary = new type();
  305. dictionary.Add(1, 'Mickey Mouse');
  306. dictionary.Add(2, 'Goofy');
  307. assert(dictionary[2] === 'Goofy');
  308. ");
  309. }
  310. [Fact]
  311. public void CanUseIndexOnCollection()
  312. {
  313. var collection = new System.Collections.ObjectModel.Collection<string>();
  314. collection.Add("Mickey Mouse");
  315. collection.Add("Goofy");
  316. _engine.SetValue("dictionary", collection);
  317. RunTest(@"
  318. dictionary[1] = 'Donald Duck';
  319. assert(dictionary[1] === 'Donald Duck');
  320. ");
  321. Assert.Equal("Mickey Mouse", collection[0]);
  322. Assert.Equal("Donald Duck", collection[1]);
  323. }
  324. [Fact]
  325. public void CanUseIndexOnList()
  326. {
  327. var list = new List<object>(2);
  328. list.Add("Mickey Mouse");
  329. list.Add("Goofy");
  330. _engine.SetValue("list", list);
  331. RunTest(@"
  332. list[1] = 'Donald Duck';
  333. assert(list[1] === 'Donald Duck');
  334. ");
  335. Assert.Equal("Mickey Mouse", list[0]);
  336. Assert.Equal("Donald Duck", list[1]);
  337. }
  338. [Fact]
  339. public void CanAccessAnonymousObject()
  340. {
  341. var p = new
  342. {
  343. Name = "Mickey Mouse",
  344. };
  345. _engine.SetValue("p", p);
  346. RunTest(@"
  347. assert(p.Name === 'Mickey Mouse');
  348. ");
  349. }
  350. [Fact]
  351. public void CanAccessAnonymousObjectProperties()
  352. {
  353. var p = new
  354. {
  355. Address = new
  356. {
  357. City = "Mouseton"
  358. }
  359. };
  360. _engine.SetValue("p", p);
  361. RunTest(@"
  362. assert(p.Address.City === 'Mouseton');
  363. ");
  364. }
  365. [Fact]
  366. public void PocosCanReturnJsValueDirectly()
  367. {
  368. var o = new
  369. {
  370. x = new JsNumber(1),
  371. y = new JsString("string"),
  372. };
  373. _engine.SetValue("o", o);
  374. RunTest(@"
  375. assert(o.x === 1);
  376. assert(o.y === 'string');
  377. ");
  378. }
  379. [Fact]
  380. public void PocosCanReturnObjectInstanceDirectly()
  381. {
  382. var x = new ObjectInstance(_engine);
  383. x.Set("foo", new JsString("bar"));
  384. var o = new
  385. {
  386. x
  387. };
  388. _engine.SetValue("o", o);
  389. RunTest(@"
  390. assert(o.x.foo === 'bar');
  391. ");
  392. }
  393. [Fact]
  394. public void DateTimeIsConvertedToDate()
  395. {
  396. var o = new
  397. {
  398. z = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)
  399. };
  400. _engine.SetValue("o", o);
  401. RunTest(@"
  402. assert(o.z.valueOf() === 0);
  403. ");
  404. }
  405. [Fact]
  406. public void DateTimeOffsetIsConvertedToDate()
  407. {
  408. var o = new
  409. {
  410. z = new DateTimeOffset(1970, 1, 1, 0, 0, 0, new TimeSpan())
  411. };
  412. _engine.SetValue("o", o);
  413. RunTest(@"
  414. assert(o.z.valueOf() === 0);
  415. ");
  416. }
  417. [Fact]
  418. public void EcmaValuesAreAutomaticallyConvertedWhenSetInPoco()
  419. {
  420. var p = new Person
  421. {
  422. Name = "foo",
  423. };
  424. _engine.SetValue("p", p);
  425. RunTest(@"
  426. assert(p.Name === 'foo');
  427. assert(p.Age === 0);
  428. p.Name = 'bar';
  429. p.Age = 10;
  430. ");
  431. Assert.Equal("bar", p.Name);
  432. Assert.Equal(10, p.Age);
  433. }
  434. [Fact]
  435. public void EcmaValuesAreAutomaticallyConvertedToBestMatchWhenSetInPoco()
  436. {
  437. var p = new Person
  438. {
  439. Name = "foo",
  440. };
  441. _engine.SetValue("p", p);
  442. RunTest(@"
  443. p.Name = 10;
  444. p.Age = '20';
  445. ");
  446. Assert.Equal("10", p.Name);
  447. Assert.Equal(20, p.Age);
  448. }
  449. [Fact]
  450. public void ShouldCallInstanceMethodWithoutArgument()
  451. {
  452. _engine.SetValue("a", new A());
  453. RunTest(@"
  454. assert(a.Call1() === 0);
  455. ");
  456. }
  457. [Fact]
  458. public void ShouldCallInstanceMethodOverloadArgument()
  459. {
  460. _engine.SetValue("a", new A());
  461. RunTest(@"
  462. assert(a.Call1(1) === 1);
  463. ");
  464. }
  465. [Fact]
  466. public void ShouldCallInstanceMethodWithString()
  467. {
  468. var p = new Person();
  469. _engine.SetValue("a", new A());
  470. _engine.SetValue("p", p);
  471. RunTest(@"
  472. p.Name = a.Call2('foo');
  473. assert(p.Name === 'foo');
  474. ");
  475. Assert.Equal("foo", p.Name);
  476. }
  477. [Fact]
  478. public void CanUseTrim()
  479. {
  480. var p = new Person { Name = "Mickey Mouse "};
  481. _engine.SetValue("p", p);
  482. RunTest(@"
  483. assert(p.Name === 'Mickey Mouse ');
  484. p.Name = p.Name.trim();
  485. assert(p.Name === 'Mickey Mouse');
  486. ");
  487. Assert.Equal("Mickey Mouse", p.Name);
  488. }
  489. [Fact]
  490. public void CanUseMathFloor()
  491. {
  492. var p = new Person();
  493. _engine.SetValue("p", p);
  494. RunTest(@"
  495. p.Age = Math.floor(1.6);p
  496. assert(p.Age === 1);
  497. ");
  498. Assert.Equal(1, p.Age);
  499. }
  500. [Fact]
  501. public void CanUseDelegateAsFunction()
  502. {
  503. var even = new Func<int, bool>(x => x % 2 == 0);
  504. _engine.SetValue("even", even);
  505. RunTest(@"
  506. assert(even(2) === true);
  507. ");
  508. }
  509. private class TestClass
  510. {
  511. public int? NullableInt { get; set; }
  512. public DateTime? NullableDate { get; set; }
  513. public bool? NullableBool { get; set; }
  514. }
  515. [Fact]
  516. public void CanSetNullablePropertiesOnPocos()
  517. {
  518. var instance = new TestClass();
  519. _engine.SetValue("instance", instance);
  520. RunTest(@"
  521. instance.NullableInt = 2;
  522. instance.NullableDate = new Date();
  523. instance.NullableBool = true;
  524. assert(instance.NullableInt===2);
  525. assert(instance.NullableDate!=null);
  526. assert(instance.NullableBool===true);
  527. ");
  528. }
  529. [Fact]
  530. public void ShouldConvertArrayToArrayInstance()
  531. {
  532. var result = _engine
  533. .SetValue("values", new[] { 1, 2, 3, 4, 5, 6 })
  534. .Execute("values.filter(function(x){ return x % 2 == 0; })");
  535. var parts = result.GetCompletionValue().ToObject();
  536. Assert.True(parts.GetType().IsArray);
  537. Assert.Equal(3, ((object[])parts).Length);
  538. Assert.Equal(2d, ((object[])parts)[0]);
  539. Assert.Equal(4d, ((object[])parts)[1]);
  540. Assert.Equal(6d, ((object[])parts)[2]);
  541. }
  542. [Fact]
  543. public void ShouldConvertListsToArrayInstance()
  544. {
  545. var result = _engine
  546. .SetValue("values", new List<object> { 1, 2, 3, 4, 5, 6 })
  547. .Execute("new Array(values).filter(function(x){ return x % 2 == 0; })");
  548. var parts = result.GetCompletionValue().ToObject();
  549. Assert.True(parts.GetType().IsArray);
  550. Assert.Equal(3, ((object[])parts).Length);
  551. Assert.Equal(2d, ((object[])parts)[0]);
  552. Assert.Equal(4d, ((object[])parts)[1]);
  553. Assert.Equal(6d, ((object[])parts)[2]);
  554. }
  555. [Fact]
  556. public void ShouldConvertArrayInstanceToArray()
  557. {
  558. var result = _engine.Execute("'[email protected]'.split('@');");
  559. var parts = result.GetCompletionValue().ToObject();
  560. Assert.True(parts.GetType().IsArray);
  561. Assert.Equal(2, ((object[])parts).Length);
  562. Assert.Equal("foo", ((object[])parts)[0]);
  563. Assert.Equal("bar.com", ((object[])parts)[1]);
  564. }
  565. [Fact]
  566. public void ShouldLoopWithNativeEnumerator()
  567. {
  568. JsValue adder(JsValue argValue)
  569. {
  570. ArrayInstance args = argValue.AsArray();
  571. double sum = 0;
  572. foreach (var item in args)
  573. {
  574. if (item.IsNumber())
  575. {
  576. sum += item.AsNumber();
  577. }
  578. }
  579. return sum;
  580. }
  581. var result = _engine.SetValue("getSum", new Func<JsValue, JsValue>(adder))
  582. .Execute("getSum([1,2,3]);");
  583. Assert.True(result.GetCompletionValue() == 6);
  584. }
  585. [Fact]
  586. public void ShouldConvertBooleanInstanceToBool()
  587. {
  588. var result = _engine.Execute("new Boolean(true)");
  589. var value = result.GetCompletionValue().ToObject();
  590. Assert.Equal(typeof(bool), value.GetType());
  591. Assert.Equal(true, value);
  592. }
  593. [Fact]
  594. public void ShouldConvertDateInstanceToDateTime()
  595. {
  596. var result = _engine.Execute("new Date(0)");
  597. var value = result.GetCompletionValue().ToObject();
  598. Assert.Equal(typeof(DateTime), value.GetType());
  599. Assert.Equal(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), value);
  600. }
  601. [Fact]
  602. public void ShouldConvertNumberInstanceToDouble()
  603. {
  604. var result = _engine.Execute("new Number(10)");
  605. var value = result.GetCompletionValue().ToObject();
  606. Assert.Equal(typeof(double), value.GetType());
  607. Assert.Equal(10d, value);
  608. }
  609. [Fact]
  610. public void ShouldConvertStringInstanceToString()
  611. {
  612. var result = _engine.Execute("new String('foo')");
  613. var value = result.GetCompletionValue().ToObject();
  614. Assert.Equal(typeof(string), value.GetType());
  615. Assert.Equal("foo", value);
  616. }
  617. [Fact]
  618. public void ShouldConvertObjectInstanceToExpando()
  619. {
  620. _engine.Execute("var o = {a: 1, b: 'foo'}");
  621. var result = _engine.GetValue("o");
  622. dynamic value = result.ToObject();
  623. Assert.Equal(1, value.a);
  624. Assert.Equal("foo", value.b);
  625. var dic = (IDictionary<string, object>)result.ToObject();
  626. Assert.Equal(1d, dic["a"]);
  627. Assert.Equal("foo", dic["b"]);
  628. }
  629. [Fact]
  630. public void ShouldNotTryToConvertCompatibleTypes()
  631. {
  632. _engine.SetValue("a", new A());
  633. RunTest(@"
  634. assert(a.Call3('foo') === 'foo');
  635. assert(a.Call3(1) === '1');
  636. ");
  637. }
  638. [Fact]
  639. public void ShouldNotTryToConvertDerivedTypes()
  640. {
  641. _engine.SetValue("a", new A());
  642. _engine.SetValue("p", new Person { Name = "Mickey" });
  643. RunTest(@"
  644. assert(a.Call4(p) === 'Mickey');
  645. ");
  646. }
  647. [Fact]
  648. public void ShouldExecuteFunctionCallBackAsDelegate()
  649. {
  650. _engine.SetValue("a", new A());
  651. RunTest(@"
  652. assert(a.Call5(function(a,b){ return a+b }) === '1foo');
  653. ");
  654. }
  655. [Fact]
  656. public void ShouldExecuteFunctionCallBackAsFuncAndThisCanBeAssigned()
  657. {
  658. _engine.SetValue("a", new A());
  659. RunTest(@"
  660. assert(a.Call6(function(a,b){ return this+a+b }) === 'bar1foo');
  661. ");
  662. }
  663. [Fact]
  664. public void ShouldExecuteFunctionCallBackAsPredicate()
  665. {
  666. _engine.SetValue("a", new A());
  667. // Func<>
  668. RunTest(@"
  669. assert(a.Call8(function(){ return 'foo'; }) === 'foo');
  670. ");
  671. }
  672. [Fact]
  673. public void ShouldExecuteFunctionWithParameterCallBackAsPredicate()
  674. {
  675. _engine.SetValue("a", new A());
  676. // Func<,>
  677. RunTest(@"
  678. assert(a.Call7('foo', function(a){ return a === 'foo'; }) === true);
  679. ");
  680. }
  681. [Fact]
  682. public void ShouldExecuteActionCallBackAsPredicate()
  683. {
  684. _engine.SetValue("a", new A());
  685. // Action
  686. RunTest(@"
  687. var value;
  688. a.Call9(function(){ value = 'foo'; });
  689. assert(value === 'foo');
  690. ");
  691. }
  692. [Fact]
  693. public void ShouldExecuteActionWithParameterCallBackAsPredicate()
  694. {
  695. _engine.SetValue("a", new A());
  696. // Action<>
  697. RunTest(@"
  698. var value;
  699. a.Call10('foo', function(b){ value = b; });
  700. assert(value === 'foo');
  701. ");
  702. }
  703. [Fact]
  704. public void ShouldExecuteActionWithMultipleParametersCallBackAsPredicate()
  705. {
  706. _engine.SetValue("a", new A());
  707. // Action<,>
  708. RunTest(@"
  709. var value;
  710. a.Call11('foo', 'bar', function(a,b){ value = a + b; });
  711. assert(value === 'foobar');
  712. ");
  713. }
  714. [Fact]
  715. public void ShouldExecuteFunc()
  716. {
  717. _engine.SetValue("a", new A());
  718. // Func<int, int>
  719. RunTest(@"
  720. var result = a.Call12(42, function(a){ return a + a; });
  721. assert(result === 84);
  722. ");
  723. }
  724. [Fact]
  725. public void ShouldExecuteActionCallbackOnEventChanged()
  726. {
  727. var collection = new System.Collections.ObjectModel.ObservableCollection<string>();
  728. Assert.True(collection.Count == 0);
  729. _engine.SetValue("collection", collection);
  730. RunTest(@"
  731. var eventAction;
  732. collection.add_CollectionChanged(function(sender, eventArgs) { eventAction = eventArgs.Action; } );
  733. collection.Add('test');
  734. ");
  735. var eventAction = _engine.GetValue("eventAction").AsNumber();
  736. Assert.True(eventAction == 0);
  737. Assert.True(collection.Count == 1);
  738. }
  739. [Fact]
  740. public void ShouldUseSystemIO()
  741. {
  742. RunTest(@"
  743. var filename = System.IO.Path.GetTempFileName();
  744. var sw = System.IO.File.CreateText(filename);
  745. sw.Write('Hello World');
  746. sw.Dispose();
  747. var content = System.IO.File.ReadAllText(filename);
  748. System.Console.WriteLine(content);
  749. assert(content === 'Hello World');
  750. ");
  751. }
  752. [Fact]
  753. public void ShouldBeInstanceOfTypeReferenceType()
  754. {
  755. _engine.SetValue("A", typeof(A));
  756. RunTest(@"
  757. var a = new A();
  758. assert(a instanceof A);
  759. ");
  760. }
  761. [Fact]
  762. public void ShouldImportNamespace()
  763. {
  764. RunTest(@"
  765. var Shapes = importNamespace('Shapes');
  766. var circle = new Shapes.Circle();
  767. assert(circle.Radius === 0);
  768. assert(circle.Perimeter() === 0);
  769. ");
  770. }
  771. [Fact]
  772. public void ShouldConstructReferenceTypeWithParameters()
  773. {
  774. RunTest(@"
  775. var Shapes = importNamespace('Shapes');
  776. var circle = new Shapes.Circle(1);
  777. assert(circle.Radius === 1);
  778. assert(circle.Perimeter() === Math.PI);
  779. ");
  780. }
  781. [Fact]
  782. public void ShouldConstructValueTypeWithoutParameters()
  783. {
  784. RunTest(@"
  785. var guid = new System.Guid();
  786. assert('00000000-0000-0000-0000-000000000000' === guid.ToString());
  787. ");
  788. }
  789. [Fact]
  790. public void ShouldInvokeAFunctionByName()
  791. {
  792. RunTest(@"
  793. function add(x, y) { return x + y; }
  794. ");
  795. Assert.Equal(3, _engine.Invoke("add", 1, 2));
  796. }
  797. [Fact]
  798. public void ShouldNotInvokeNonFunctionValue()
  799. {
  800. RunTest(@"
  801. var x= 10;
  802. ");
  803. Assert.Throws<ArgumentException>(() => _engine.Invoke("x", 1, 2));
  804. }
  805. [Fact]
  806. public void CanGetField()
  807. {
  808. var o = new ClassWithField
  809. {
  810. Field = "Mickey Mouse"
  811. };
  812. _engine.SetValue("o", o);
  813. RunTest(@"
  814. assert(o.Field === 'Mickey Mouse');
  815. ");
  816. }
  817. [Fact]
  818. public void CanSetField()
  819. {
  820. var o = new ClassWithField();
  821. _engine.SetValue("o", o);
  822. RunTest(@"
  823. o.Field = 'Mickey Mouse';
  824. assert(o.Field === 'Mickey Mouse');
  825. ");
  826. Assert.Equal("Mickey Mouse", o.Field);
  827. }
  828. [Fact]
  829. public void CanGetStaticField()
  830. {
  831. RunTest(@"
  832. var domain = importNamespace('Jint.Tests.Runtime.Domain');
  833. var statics = domain.ClassWithStaticFields;
  834. assert(statics.Get == 'Get');
  835. ");
  836. }
  837. [Fact]
  838. public void CanSetStaticField()
  839. {
  840. RunTest(@"
  841. var domain = importNamespace('Jint.Tests.Runtime.Domain');
  842. var statics = domain.ClassWithStaticFields;
  843. statics.Set = 'hello';
  844. assert(statics.Set == 'hello');
  845. ");
  846. Assert.Equal(ClassWithStaticFields.Set, "hello");
  847. }
  848. [Fact]
  849. public void CanGetStaticAccessor()
  850. {
  851. RunTest(@"
  852. var domain = importNamespace('Jint.Tests.Runtime.Domain');
  853. var statics = domain.ClassWithStaticFields;
  854. assert(statics.Getter == 'Getter');
  855. ");
  856. }
  857. [Fact]
  858. public void CanSetStaticAccessor()
  859. {
  860. RunTest(@"
  861. var domain = importNamespace('Jint.Tests.Runtime.Domain');
  862. var statics = domain.ClassWithStaticFields;
  863. statics.Setter = 'hello';
  864. assert(statics.Setter == 'hello');
  865. ");
  866. Assert.Equal(ClassWithStaticFields.Setter, "hello");
  867. }
  868. [Fact]
  869. public void CantSetStaticReadonly()
  870. {
  871. RunTest(@"
  872. var domain = importNamespace('Jint.Tests.Runtime.Domain');
  873. var statics = domain.ClassWithStaticFields;
  874. statics.Readonly = 'hello';
  875. assert(statics.Readonly == 'Readonly');
  876. ");
  877. Assert.Equal(ClassWithStaticFields.Readonly, "Readonly");
  878. }
  879. [Fact]
  880. public void CanSetCustomConverters()
  881. {
  882. var engine1 = new Engine();
  883. engine1.SetValue("p", new { Test = true });
  884. engine1.Execute("var result = p.Test;");
  885. Assert.True((bool)engine1.GetValue("result").ToObject());
  886. var engine2 = new Engine(o => o.AddObjectConverter(new NegateBoolConverter()));
  887. engine2.SetValue("p", new { Test = true });
  888. engine2.Execute("var result = p.Test;");
  889. Assert.False((bool)engine2.GetValue("result").ToObject());
  890. }
  891. [Fact]
  892. public void CanConvertEnumsToString()
  893. {
  894. var engine1 = new Engine(o => o.AddObjectConverter(new EnumsToStringConverter()))
  895. .SetValue("assert", new Action<bool>(Assert.True));
  896. engine1.SetValue("p", new { Comparison = StringComparison.CurrentCulture });
  897. engine1.Execute("assert(p.Comparison === 'CurrentCulture');");
  898. engine1.Execute("var result = p.Comparison;");
  899. Assert.Equal("CurrentCulture", (string)engine1.GetValue("result").ToObject());
  900. }
  901. [Fact]
  902. public void CanUserIncrementOperator()
  903. {
  904. var p = new Person
  905. {
  906. Age = 1,
  907. };
  908. _engine.SetValue("p", p);
  909. RunTest(@"
  910. assert(++p.Age === 2);
  911. ");
  912. Assert.Equal(2, p.Age);
  913. }
  914. [Fact]
  915. public void CanOverwriteValues()
  916. {
  917. _engine.SetValue("x", 3);
  918. _engine.SetValue("x", 4);
  919. RunTest(@"
  920. assert(x === 4);
  921. ");
  922. }
  923. [Fact]
  924. public void ShouldCreateGenericType()
  925. {
  926. RunTest(@"
  927. var ListOfString = System.Collections.Generic.List(System.String);
  928. var list = new ListOfString();
  929. list.Add('foo');
  930. list.Add(1);
  931. assert(2 === list.Count);
  932. ");
  933. }
  934. [Fact]
  935. public void EnumComparesByName()
  936. {
  937. var o = new
  938. {
  939. r = Colors.Red,
  940. b = Colors.Blue,
  941. g = Colors.Green,
  942. b2 = Colors.Red
  943. };
  944. _engine.SetValue("o", o);
  945. _engine.SetValue("assertFalse", new Action<bool>(Assert.False));
  946. RunTest(@"
  947. var domain = importNamespace('Jint.Tests.Runtime.Domain');
  948. var colors = domain.Colors;
  949. assert(o.r === colors.Red);
  950. assert(o.g === colors.Green);
  951. assert(o.b === colors.Blue);
  952. assertFalse(o.b2 === colors.Blue);
  953. ");
  954. }
  955. [Fact]
  956. public void ShouldSetEnumProperty()
  957. {
  958. var s = new Circle
  959. {
  960. Color = Colors.Red,
  961. };
  962. _engine.SetValue("s", s);
  963. RunTest(@"
  964. var domain = importNamespace('Jint.Tests.Runtime.Domain');
  965. var colors = domain.Colors;
  966. s.Color = colors.Blue;
  967. assert(s.Color === colors.Blue);
  968. ");
  969. _engine.SetValue("s", s);
  970. RunTest(@"
  971. s.Color = colors.Blue | colors.Green;
  972. assert(s.Color === colors.Blue | colors.Green);
  973. ");
  974. Assert.Equal(Colors.Blue | Colors.Green, s.Color);
  975. }
  976. enum TestEnumInt32 : int
  977. {
  978. None,
  979. One = 1,
  980. Min = int.MaxValue,
  981. Max = int.MaxValue,
  982. }
  983. enum TestEnumUInt32 : uint
  984. {
  985. None,
  986. One = 1,
  987. Min = uint.MaxValue,
  988. Max = uint.MaxValue,
  989. }
  990. enum TestEnumInt64 : long
  991. {
  992. None,
  993. One = 1,
  994. Min = long.MaxValue,
  995. Max = long.MaxValue,
  996. }
  997. enum TestEnumUInt64 : ulong
  998. {
  999. None,
  1000. One = 1,
  1001. Min = ulong.MaxValue,
  1002. Max = ulong.MaxValue,
  1003. }
  1004. void TestEnum<T>(T enumValue)
  1005. {
  1006. object i = Convert.ChangeType(enumValue, Enum.GetUnderlyingType(typeof(T)));
  1007. string s = Convert.ToString(i, CultureInfo.InvariantCulture);
  1008. var o = new Tuple<T>(enumValue);
  1009. _engine.SetValue("o", o);
  1010. RunTest("assert(o.Item1 === " + s + ");");
  1011. }
  1012. [Fact]
  1013. public void ShouldWorkWithEnumInt32()
  1014. {
  1015. TestEnum(TestEnumInt32.None);
  1016. TestEnum(TestEnumInt32.One);
  1017. TestEnum(TestEnumInt32.Min);
  1018. TestEnum(TestEnumInt32.Max);
  1019. }
  1020. [Fact]
  1021. public void ShouldWorkWithEnumUInt32()
  1022. {
  1023. TestEnum(TestEnumUInt32.None);
  1024. TestEnum(TestEnumUInt32.One);
  1025. TestEnum(TestEnumUInt32.Min);
  1026. TestEnum(TestEnumUInt32.Max);
  1027. }
  1028. [Fact]
  1029. public void ShouldWorkWithEnumInt64()
  1030. {
  1031. TestEnum(TestEnumInt64.None);
  1032. TestEnum(TestEnumInt64.One);
  1033. TestEnum(TestEnumInt64.Min);
  1034. TestEnum(TestEnumInt64.Max);
  1035. }
  1036. [Fact]
  1037. public void ShouldWorkWithEnumUInt64()
  1038. {
  1039. TestEnum(TestEnumUInt64.None);
  1040. TestEnum(TestEnumUInt64.One);
  1041. TestEnum(TestEnumUInt64.Min);
  1042. TestEnum(TestEnumUInt64.Max);
  1043. }
  1044. [Fact]
  1045. public void EnumIsConvertedToNumber()
  1046. {
  1047. var o = new
  1048. {
  1049. r = Colors.Red,
  1050. b = Colors.Blue,
  1051. g = Colors.Green
  1052. };
  1053. _engine.SetValue("o", o);
  1054. RunTest(@"
  1055. assert(o.r === 0);
  1056. assert(o.g === 1);
  1057. assert(o.b === 10);
  1058. ");
  1059. }
  1060. [Fact]
  1061. public void ShouldConvertToEnum()
  1062. {
  1063. var s = new Circle
  1064. {
  1065. Color = Colors.Red,
  1066. };
  1067. _engine.SetValue("s", s);
  1068. RunTest(@"
  1069. assert(s.Color === 0);
  1070. s.Color = 10;
  1071. assert(s.Color === 10);
  1072. ");
  1073. _engine.SetValue("s", s);
  1074. RunTest(@"
  1075. s.Color = 11;
  1076. assert(s.Color === 11);
  1077. ");
  1078. Assert.Equal(Colors.Blue | Colors.Green, s.Color);
  1079. }
  1080. [Fact]
  1081. public void ShouldUseExplicitPropertyGetter()
  1082. {
  1083. _engine.SetValue("c", new Company("ACME"));
  1084. RunTest(@"
  1085. assert(c.Name === 'ACME');
  1086. ");
  1087. }
  1088. [Fact]
  1089. public void ShouldUseExplicitIndexerPropertyGetter()
  1090. {
  1091. var company = new Company("ACME");
  1092. ((ICompany)company)["Foo"] = "Bar";
  1093. _engine.SetValue("c", company);
  1094. RunTest(@"
  1095. assert(c.Foo === 'Bar');
  1096. ");
  1097. }
  1098. [Fact]
  1099. public void ShouldUseExplicitPropertySetter()
  1100. {
  1101. _engine.SetValue("c", new Company("ACME"));
  1102. RunTest(@"
  1103. c.Name = 'Foo';
  1104. assert(c.Name === 'Foo');
  1105. ");
  1106. }
  1107. [Fact]
  1108. public void ShouldUseExplicitIndexerPropertySetter()
  1109. {
  1110. var company = new Company("ACME");
  1111. ((ICompany)company)["Foo"] = "Bar";
  1112. _engine.SetValue("c", company);
  1113. RunTest(@"
  1114. c.Foo = 'Baz';
  1115. assert(c.Foo === 'Baz');
  1116. ");
  1117. }
  1118. [Fact]
  1119. public void ShouldUseExplicitMethod()
  1120. {
  1121. _engine.SetValue("c", new Company("ACME"));
  1122. RunTest(@"
  1123. assert(0 === c.CompareTo(c));
  1124. ");
  1125. }
  1126. [Fact]
  1127. public void ShouldCallInstanceMethodWithParams()
  1128. {
  1129. _engine.SetValue("a", new A());
  1130. RunTest(@"
  1131. assert(a.Call13('1','2','3') === '1,2,3');
  1132. assert(a.Call13('1') === '1');
  1133. assert(a.Call13(1) === '1');
  1134. assert(a.Call13() === '');
  1135. assert(a.Call14('a','1','2','3') === 'a:1,2,3');
  1136. assert(a.Call14('a','1') === 'a:1');
  1137. assert(a.Call14('a') === 'a:');
  1138. function call13wrapper(){ return a.Call13.apply(a, Array.prototype.slice.call(arguments)); }
  1139. assert(call13wrapper('1','2','3') === '1,2,3');
  1140. assert(a.Call13('1','2','3') === a.Call13(['1','2','3']));
  1141. ");
  1142. }
  1143. [Fact]
  1144. public void ShouldCallInstanceMethodWithJsValueParams()
  1145. {
  1146. _engine.SetValue("a", new A());
  1147. RunTest(@"
  1148. assert(a.Call16('1','2','3') === '1,2,3');
  1149. assert(a.Call16('1') === '1');
  1150. assert(a.Call16(1) === '1');
  1151. assert(a.Call16() === '');
  1152. assert(a.Call16('1','2','3') === a.Call16(['1','2','3']));
  1153. ");
  1154. }
  1155. [Fact]
  1156. public void NullValueAsArgumentShouldWork()
  1157. {
  1158. _engine.SetValue("a", new A());
  1159. RunTest(@"
  1160. var x = a.Call2(null);
  1161. assert(x === null);
  1162. ");
  1163. }
  1164. [Fact]
  1165. public void ShouldSetPropertyToNull()
  1166. {
  1167. var p = new Person { Name = "Mickey" };
  1168. _engine.SetValue("p", p);
  1169. RunTest(@"
  1170. assert(p.Name != null);
  1171. p.Name = null;
  1172. assert(p.Name == null);
  1173. ");
  1174. Assert.True(p.Name == null);
  1175. }
  1176. [Fact]
  1177. public void ShouldCallMethodWithNull()
  1178. {
  1179. _engine.SetValue("a", new A());
  1180. RunTest(@"
  1181. a.Call15(null);
  1182. var result = a.Call2(null);
  1183. assert(result == null);
  1184. ");
  1185. }
  1186. [Fact]
  1187. public void ShouldReturnUndefinedProperty()
  1188. {
  1189. _engine.SetValue("uo", new { foo = "bar" });
  1190. _engine.SetValue("ud", new Dictionary<string, object> { {"foo", "bar"} });
  1191. _engine.SetValue("ul", new List<string> { "foo", "bar" });
  1192. RunTest(@"
  1193. assert(!uo.undefinedProperty);
  1194. assert(!ul[5]);
  1195. assert(!ud.undefinedProperty);
  1196. ");
  1197. }
  1198. [Fact]
  1199. public void ShouldAutomaticallyConvertArraysToFindBestInteropResulution()
  1200. {
  1201. _engine.SetValue("a", new ArrayConverterTestClass());
  1202. _engine.SetValue("item1", new ArrayConverterItem(1));
  1203. _engine.SetValue("item2", new ArrayConverterItem(2));
  1204. RunTest(@"
  1205. assert(a.MethodAcceptsArrayOfInt([false, '1', 2]) === a.MethodAcceptsArrayOfInt([0, 1, 2]));
  1206. assert(a.MethodAcceptsArrayOfStrings(['1', 2]) === a.MethodAcceptsArrayOfStrings([1, 2]));
  1207. assert(a.MethodAcceptsArrayOfBool(['1', 0]) === a.MethodAcceptsArrayOfBool([true, false]));
  1208. assert(a.MethodAcceptsArrayOfStrings([item1, item2]) === a.MethodAcceptsArrayOfStrings(['1', '2']));
  1209. assert(a.MethodAcceptsArrayOfInt([item1, item2]) === a.MethodAcceptsArrayOfInt([1, 2]));
  1210. ");
  1211. }
  1212. [Fact]
  1213. public void ShouldImportNamespaceNestedType()
  1214. {
  1215. RunTest(@"
  1216. var shapes = importNamespace('Shapes.Circle');
  1217. var kinds = shapes.Kind;
  1218. assert(kinds.Unit === 0);
  1219. assert(kinds.Ellipse === 1);
  1220. assert(kinds.Round === 5);
  1221. ");
  1222. }
  1223. [Fact]
  1224. public void ShouldImportNamespaceNestedNestedType()
  1225. {
  1226. RunTest(@"
  1227. var meta = importNamespace('Shapes.Circle.Meta');
  1228. var usages = meta.Usage;
  1229. assert(usages.Public === 0);
  1230. assert(usages.Private === 1);
  1231. assert(usages.Internal === 11);
  1232. ");
  1233. }
  1234. [Fact]
  1235. public void ShouldGetNestedNestedProp()
  1236. {
  1237. RunTest(@"
  1238. var meta = importNamespace('Shapes.Circle');
  1239. var m = new meta.Meta();
  1240. assert(m.Description === 'descp');
  1241. ");
  1242. }
  1243. [Fact]
  1244. public void ShouldSetNestedNestedProp()
  1245. {
  1246. RunTest(@"
  1247. var meta = importNamespace('Shapes.Circle');
  1248. var m = new meta.Meta();
  1249. m.Description = 'hello';
  1250. assert(m.Description === 'hello');
  1251. ");
  1252. }
  1253. [Fact]
  1254. public void CanGetStaticNestedField()
  1255. {
  1256. RunTest(@"
  1257. var domain = importNamespace('Jint.Tests.Runtime.Domain.Nested');
  1258. var statics = domain.ClassWithStaticFields;
  1259. assert(statics.Get == 'Get');
  1260. ");
  1261. }
  1262. [Fact]
  1263. public void CanSetStaticNestedField()
  1264. {
  1265. RunTest(@"
  1266. var domain = importNamespace('Jint.Tests.Runtime.Domain.Nested');
  1267. var statics = domain.ClassWithStaticFields;
  1268. statics.Set = 'hello';
  1269. assert(statics.Set == 'hello');
  1270. ");
  1271. Assert.Equal(Nested.ClassWithStaticFields.Set, "hello");
  1272. }
  1273. [Fact]
  1274. public void CanGetStaticNestedAccessor()
  1275. {
  1276. RunTest(@"
  1277. var domain = importNamespace('Jint.Tests.Runtime.Domain.Nested');
  1278. var statics = domain.ClassWithStaticFields;
  1279. assert(statics.Getter == 'Getter');
  1280. ");
  1281. }
  1282. [Fact]
  1283. public void CanSetStaticNestedAccessor()
  1284. {
  1285. RunTest(@"
  1286. var domain = importNamespace('Jint.Tests.Runtime.Domain.Nested');
  1287. var statics = domain.ClassWithStaticFields;
  1288. statics.Setter = 'hello';
  1289. assert(statics.Setter == 'hello');
  1290. ");
  1291. Assert.Equal(Nested.ClassWithStaticFields.Setter, "hello");
  1292. }
  1293. [Fact]
  1294. public void CantSetStaticNestedReadonly()
  1295. {
  1296. RunTest(@"
  1297. var domain = importNamespace('Jint.Tests.Runtime.Domain.Nested');
  1298. var statics = domain.ClassWithStaticFields;
  1299. statics.Readonly = 'hello';
  1300. assert(statics.Readonly == 'Readonly');
  1301. ");
  1302. Assert.Equal(Nested.ClassWithStaticFields.Readonly, "Readonly");
  1303. }
  1304. [Fact]
  1305. public void ShouldExecuteFunctionWithValueTypeParameterCorrectly()
  1306. {
  1307. _engine.SetValue("a", new A());
  1308. // Func<int, int>
  1309. RunTest(@"
  1310. assert(a.Call17(function(value){ return value; }) === 17);
  1311. ");
  1312. }
  1313. [Fact]
  1314. public void ShouldExecuteActionWithValueTypeParameterCorrectly()
  1315. {
  1316. _engine.SetValue("a", new A());
  1317. // Action<int>
  1318. RunTest(@"
  1319. a.Call18(function(value){ assert(value === 18); });
  1320. ");
  1321. }
  1322. [Fact]
  1323. public void ShouldConvertToJsValue()
  1324. {
  1325. RunTest(@"
  1326. var now = System.DateTime.Now;
  1327. assert(new String(now) == now.toString());
  1328. var zero = System.Int32.MaxValue;
  1329. assert(new String(zero) == zero.toString());
  1330. ");
  1331. }
  1332. [Fact]
  1333. public void ShouldNotCatchClrExceptions()
  1334. {
  1335. var engine = new Engine()
  1336. .SetValue("throwMyException", new Action(() => { throw new NotSupportedException(); }))
  1337. .SetValue("Thrower", typeof(Thrower))
  1338. .Execute(@"
  1339. function throwException1(){
  1340. try {
  1341. throwMyException();
  1342. return;
  1343. }
  1344. catch(e) {
  1345. return;
  1346. }
  1347. }
  1348. function throwException2(){
  1349. try {
  1350. new Thrower().ThrowNotSupportedException();
  1351. return;
  1352. }
  1353. catch(e) {
  1354. return;
  1355. }
  1356. }
  1357. ");
  1358. Assert.ThrowsAny<NotSupportedException>(() => engine.Invoke("throwException1"));
  1359. Assert.ThrowsAny<NotSupportedException>(() => engine.Invoke("throwException2"));
  1360. }
  1361. [Fact]
  1362. public void ShouldCatchAllClrExceptions()
  1363. {
  1364. string exceptionMessage = "myExceptionMessage";
  1365. var engine = new Engine(o => o.CatchClrExceptions())
  1366. .SetValue("throwMyException", new Action(() => { throw new Exception(exceptionMessage); }))
  1367. .SetValue("Thrower", typeof(Thrower))
  1368. .Execute(@"
  1369. function throwException1(){
  1370. try {
  1371. throwMyException();
  1372. return '';
  1373. }
  1374. catch(e) {
  1375. return e.message;
  1376. }
  1377. }
  1378. function throwException2(){
  1379. try {
  1380. new Thrower().ThrowExceptionWithMessage('myExceptionMessage');
  1381. return;
  1382. }
  1383. catch(e) {
  1384. return e.message;
  1385. }
  1386. }
  1387. ");
  1388. Assert.Equal(engine.Invoke("throwException1").AsString(), exceptionMessage);
  1389. Assert.Equal(engine.Invoke("throwException2").AsString(), exceptionMessage);
  1390. }
  1391. class MemberExceptionTest
  1392. {
  1393. public MemberExceptionTest(bool throwOnCreate)
  1394. {
  1395. if (throwOnCreate)
  1396. throw new InvalidOperationException();
  1397. }
  1398. public JsValue ThrowingProperty1
  1399. {
  1400. get { throw new InvalidOperationException(); }
  1401. set { throw new InvalidOperationException(); }
  1402. }
  1403. public object ThrowingProperty2
  1404. {
  1405. get { throw new InvalidOperationException(); }
  1406. set { throw new InvalidOperationException(); }
  1407. }
  1408. public void ThrowingFunction()
  1409. {
  1410. throw new InvalidOperationException();
  1411. }
  1412. }
  1413. [Fact]
  1414. public void ShouldCatchClrMemberExceptions()
  1415. {
  1416. var engine = new Engine(cfg =>
  1417. {
  1418. cfg.AllowClr();
  1419. cfg.CatchClrExceptions();
  1420. });
  1421. engine.SetValue("assert", new Action<bool>(Assert.True));
  1422. engine.SetValue("log", new Action<object>(Console.WriteLine));
  1423. engine.SetValue("create", typeof(MemberExceptionTest));
  1424. engine.SetValue("instance", new MemberExceptionTest(throwOnCreate: false));
  1425. // Test calling a constructor that throws an exception
  1426. engine.Execute(@"
  1427. try
  1428. {
  1429. create(true);
  1430. assert(false);
  1431. }
  1432. catch (e)
  1433. {
  1434. assert(true);
  1435. }
  1436. ");
  1437. // Test calling a member function that throws an exception
  1438. engine.Execute(@"
  1439. try
  1440. {
  1441. instance.ThrowingFunction();
  1442. assert(false);
  1443. }
  1444. catch (e)
  1445. {
  1446. assert(true);
  1447. }
  1448. ");
  1449. // Test using a property getter that throws an exception
  1450. engine.Execute(@"
  1451. try
  1452. {
  1453. log(o.ThrowingProperty);
  1454. assert(false);
  1455. }
  1456. catch (e)
  1457. {
  1458. assert(true);
  1459. }
  1460. ");
  1461. // Test using a property setter that throws an exception
  1462. engine.Execute(@"
  1463. try
  1464. {
  1465. instance.ThrowingProperty1 = 123;
  1466. assert(false);
  1467. }
  1468. catch (e)
  1469. {
  1470. assert(true);
  1471. }
  1472. try
  1473. {
  1474. instance.ThrowingProperty2 = 456;
  1475. assert(false);
  1476. }
  1477. catch (e)
  1478. {
  1479. assert(true);
  1480. }
  1481. ");
  1482. }
  1483. [Fact]
  1484. public void ShouldCatchSomeExceptions()
  1485. {
  1486. string exceptionMessage = "myExceptionMessage";
  1487. var engine = new Engine(o => o.CatchClrExceptions(e => e is NotSupportedException))
  1488. .SetValue("throwMyException1", new Action(() => { throw new NotSupportedException(exceptionMessage); }))
  1489. .SetValue("throwMyException2", new Action(() => { throw new ArgumentNullException(); }))
  1490. .SetValue("Thrower", typeof(Thrower))
  1491. .Execute(@"
  1492. function throwException1(){
  1493. try {
  1494. throwMyException1();
  1495. return '';
  1496. }
  1497. catch(e) {
  1498. return e.message;
  1499. }
  1500. }
  1501. function throwException2(){
  1502. try {
  1503. throwMyException2();
  1504. return '';
  1505. }
  1506. catch(e) {
  1507. return e.message;
  1508. }
  1509. }
  1510. function throwException3(){
  1511. try {
  1512. new Thrower().ThrowNotSupportedExceptionWithMessage('myExceptionMessage');
  1513. return '';
  1514. }
  1515. catch(e) {
  1516. return e.message;
  1517. }
  1518. }
  1519. function throwException4(){
  1520. try {
  1521. new Thrower().ThrowArgumentNullException();
  1522. return '';
  1523. }
  1524. catch(e) {
  1525. return e.message;
  1526. }
  1527. }
  1528. ");
  1529. Assert.Equal(engine.Invoke("throwException1").AsString(), exceptionMessage);
  1530. Assert.Throws<ArgumentNullException>(() => engine.Invoke("throwException2"));
  1531. Assert.Equal(engine.Invoke("throwException3").AsString(), exceptionMessage);
  1532. Assert.Throws<ArgumentNullException>(() => engine.Invoke("throwException4"));
  1533. }
  1534. [Fact]
  1535. public void ArrayFromShouldConvertListToArrayLike()
  1536. {
  1537. var list = new List<Person>
  1538. {
  1539. new Person {Name = "Mike"},
  1540. new Person {Name = "Mika"}
  1541. };
  1542. _engine.SetValue("a", list);
  1543. RunTest(@"
  1544. var arr = new Array(a);
  1545. assert(arr.length === 2);
  1546. assert(arr[0].Name === 'Mike');
  1547. assert(arr[1].Name === 'Mika');
  1548. ");
  1549. RunTest(@"
  1550. var arr = Array.from(a);
  1551. assert(arr.length === 2);
  1552. assert(arr[0].Name === 'Mike');
  1553. assert(arr[1].Name === 'Mika');
  1554. ");
  1555. }
  1556. [Fact]
  1557. public void ArrayFromShouldConvertArrayToArrayLike()
  1558. {
  1559. var list = new []
  1560. {
  1561. new Person {Name = "Mike"},
  1562. new Person {Name = "Mika"}
  1563. };
  1564. _engine.SetValue("a", list);
  1565. RunTest(@"
  1566. var arr = new Array(a);
  1567. assert(arr.length === 2);
  1568. assert(arr[0].Name === 'Mike');
  1569. assert(arr[1].Name === 'Mika');
  1570. ");
  1571. RunTest(@"
  1572. var arr = Array.from(a);
  1573. assert(arr.length === 2);
  1574. assert(arr[0].Name === 'Mike');
  1575. assert(arr[1].Name === 'Mika');
  1576. ");
  1577. }
  1578. [Fact]
  1579. public void ArrayFromShouldConvertIEnumerable()
  1580. {
  1581. var enumerable = new []
  1582. {
  1583. new Person {Name = "Mike"},
  1584. new Person {Name = "Mika"}
  1585. }.Select(x => x);
  1586. _engine.SetValue("a", enumerable);
  1587. RunTest(@"
  1588. var arr = new Array(a);
  1589. assert(arr.length === 2);
  1590. assert(arr[0].Name === 'Mike');
  1591. assert(arr[1].Name === 'Mika');
  1592. ");
  1593. RunTest(@"
  1594. var arr = Array.from(a);
  1595. assert(arr.length === 2);
  1596. assert(arr[0].Name === 'Mike');
  1597. assert(arr[1].Name === 'Mika');
  1598. ");
  1599. }
  1600. [Fact]
  1601. public void ShouldBeAbleToPlusAssignStringProperty()
  1602. {
  1603. var p = new Person();
  1604. var engine = new Engine();
  1605. engine.SetValue("P", p);
  1606. engine.Execute("P.Name = 'b';");
  1607. engine.Execute("P.Name += 'c';");
  1608. Assert.Equal("bc", p.Name);
  1609. }
  1610. }
  1611. }