InteropTests.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. using System;
  2. using System.Collections.Generic;
  3. using Jint.Native;
  4. using Jint.Native.Object;
  5. using Jint.Tests.Runtime.Converters;
  6. using Jint.Tests.Runtime.Domain;
  7. using Shapes;
  8. using Xunit;
  9. namespace Jint.Tests.Runtime
  10. {
  11. public class InteropTests : IDisposable
  12. {
  13. private readonly Engine _engine;
  14. public InteropTests()
  15. {
  16. _engine = new Engine(cfg => cfg.AllowClr(typeof(Shape).Assembly))
  17. .SetValue("log", new Action<object>(Console.WriteLine))
  18. .SetValue("assert", new Action<bool>(Assert.True))
  19. ;
  20. }
  21. void IDisposable.Dispose()
  22. {
  23. }
  24. private void RunTest(string source)
  25. {
  26. _engine.Execute(source);
  27. }
  28. [Fact]
  29. public void PrimitiveTypesCanBeSet()
  30. {
  31. _engine.SetValue("x", 10);
  32. _engine.SetValue("y", true);
  33. _engine.SetValue("z", "foo");
  34. RunTest(@"
  35. assert(x === 10);
  36. assert(y === true);
  37. assert(z === 'foo');
  38. ");
  39. }
  40. [Fact]
  41. public void DelegatesCanBeSet()
  42. {
  43. _engine.SetValue("square", new Func<double, double>(x => x * x));
  44. RunTest(@"
  45. assert(square(10) === 100);
  46. ");
  47. }
  48. [Fact]
  49. public void CanGetObjectProperties()
  50. {
  51. var p = new Person
  52. {
  53. Name = "Mickey Mouse"
  54. };
  55. _engine.SetValue("p", p);
  56. RunTest(@"
  57. assert(p.Name === 'Mickey Mouse');
  58. ");
  59. }
  60. [Fact]
  61. public void CanInvokeObjectMethods()
  62. {
  63. var p = new Person
  64. {
  65. Name = "Mickey Mouse"
  66. };
  67. _engine.SetValue("p", p);
  68. RunTest(@"
  69. assert(p.ToString() === 'Mickey Mouse');
  70. ");
  71. }
  72. [Fact]
  73. public void CanSetObjectProperties()
  74. {
  75. var p = new Person
  76. {
  77. Name = "Mickey Mouse"
  78. };
  79. _engine.SetValue("p", p);
  80. RunTest(@"
  81. p.Name = 'Donald Duck';
  82. assert(p.Name === 'Donald Duck');
  83. ");
  84. Assert.Equal("Donald Duck", p.Name);
  85. }
  86. [Fact]
  87. public void CanAccessAnonymousObject()
  88. {
  89. var p = new
  90. {
  91. Name = "Mickey Mouse",
  92. };
  93. _engine.SetValue("p", p);
  94. RunTest(@"
  95. assert(p.Name === 'Mickey Mouse');
  96. ");
  97. }
  98. [Fact]
  99. public void CanAccessAnonymousObjectProperties()
  100. {
  101. var p = new
  102. {
  103. Address = new
  104. {
  105. City = "Mouseton"
  106. }
  107. };
  108. _engine.SetValue("p", p);
  109. RunTest(@"
  110. assert(p.Address.City === 'Mouseton');
  111. ");
  112. }
  113. [Fact]
  114. public void PocosCanReturnJsValueDirectly()
  115. {
  116. var o = new
  117. {
  118. x = new JsValue(1),
  119. y = new JsValue("string"),
  120. };
  121. _engine.SetValue("o", o);
  122. RunTest(@"
  123. assert(o.x === 1);
  124. assert(o.y === 'string');
  125. ");
  126. }
  127. [Fact]
  128. public void PocosCanReturnObjectInstanceDirectly()
  129. {
  130. var x = new ObjectInstance(_engine) { Extensible = true};
  131. x.Put("foo", new JsValue("bar"), false);
  132. var o = new
  133. {
  134. x
  135. };
  136. _engine.SetValue("o", o);
  137. RunTest(@"
  138. assert(o.x.foo === 'bar');
  139. ");
  140. }
  141. [Fact]
  142. public void DateTimeIsConvertedToDate()
  143. {
  144. var o = new
  145. {
  146. z = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)
  147. };
  148. _engine.SetValue("o", o);
  149. RunTest(@"
  150. assert(o.z.valueOf() === 0);
  151. ");
  152. }
  153. [Fact]
  154. public void DateTimeOffsetIsConvertedToDate()
  155. {
  156. var o = new
  157. {
  158. z = new DateTimeOffset(1970, 1, 1, 0, 0, 0, new TimeSpan())
  159. };
  160. _engine.SetValue("o", o);
  161. RunTest(@"
  162. assert(o.z.valueOf() === 0);
  163. ");
  164. }
  165. [Fact]
  166. public void EcmaValuesAreAutomaticallyConvertedWhenSetInPoco()
  167. {
  168. var p = new Person
  169. {
  170. Name = "foo",
  171. };
  172. _engine.SetValue("p", p);
  173. RunTest(@"
  174. assert(p.Name === 'foo');
  175. assert(p.Age === 0);
  176. p.Name = 'bar';
  177. p.Age = 10;
  178. ");
  179. Assert.Equal("bar", p.Name);
  180. Assert.Equal(10, p.Age);
  181. }
  182. [Fact]
  183. public void EcmaValuesAreAutomaticallyConvertedToBestMatchWhenSetInPoco()
  184. {
  185. var p = new Person
  186. {
  187. Name = "foo",
  188. };
  189. _engine.SetValue("p", p);
  190. RunTest(@"
  191. p.Name = 10;
  192. p.Age = '20';
  193. ");
  194. Assert.Equal("10", p.Name);
  195. Assert.Equal(20, p.Age);
  196. }
  197. [Fact]
  198. public void ShouldCallInstanceMethodWithoutArgument()
  199. {
  200. _engine.SetValue("a", new A());
  201. RunTest(@"
  202. assert(a.Call1() === 0);
  203. ");
  204. }
  205. [Fact]
  206. public void ShouldCallInstanceMethodOverloadArgument()
  207. {
  208. _engine.SetValue("a", new A());
  209. RunTest(@"
  210. assert(a.Call1(1) === 1);
  211. ");
  212. }
  213. [Fact]
  214. public void ShouldCallInstanceMethodWithString()
  215. {
  216. var p = new Person();
  217. _engine.SetValue("a", new A());
  218. _engine.SetValue("p", p);
  219. RunTest(@"
  220. p.Name = a.Call2('foo');
  221. assert(p.Name === 'foo');
  222. ");
  223. Assert.Equal("foo", p.Name);
  224. }
  225. [Fact]
  226. public void CanUseTrim()
  227. {
  228. var p = new Person { Name = "Mickey Mouse "};
  229. _engine.SetValue("p", p);
  230. RunTest(@"
  231. assert(p.Name === 'Mickey Mouse ');
  232. p.Name = p.Name.trim();
  233. assert(p.Name === 'Mickey Mouse');
  234. ");
  235. Assert.Equal("Mickey Mouse", p.Name);
  236. }
  237. [Fact]
  238. public void CanUseMathFloor()
  239. {
  240. var p = new Person();
  241. _engine.SetValue("p", p);
  242. RunTest(@"
  243. p.Age = Math.floor(1.6);p
  244. assert(p.Age === 1);
  245. ");
  246. Assert.Equal(1, p.Age);
  247. }
  248. [Fact]
  249. public void CanUseDelegateAsFunction()
  250. {
  251. var even = new Func<int, bool>(x => x % 2 == 0);
  252. _engine.SetValue("even", even);
  253. RunTest(@"
  254. assert(even(2) === true);
  255. ");
  256. }
  257. [Fact]
  258. public void ShouldConvertArrayToArrayInstance()
  259. {
  260. var result = _engine
  261. .SetValue("values", new[] { 1, 2, 3, 4, 5, 6 })
  262. .Execute("values.filter(function(x){ return x % 2 == 0; })");
  263. var parts = result.GetCompletionValue().ToObject();
  264. Assert.True(parts.GetType().IsArray);
  265. Assert.Equal(3, ((object[])parts).Length);
  266. Assert.Equal(2d, ((object[])parts)[0]);
  267. Assert.Equal(4d, ((object[])parts)[1]);
  268. Assert.Equal(6d, ((object[])parts)[2]);
  269. }
  270. [Fact]
  271. public void ShouldConvertListsToArrayInstance()
  272. {
  273. var result = _engine
  274. .SetValue("values", new List<object> { 1, 2, 3, 4, 5, 6 })
  275. .Execute("new Array(values).filter(function(x){ return x % 2 == 0; })");
  276. var parts = result.GetCompletionValue().ToObject();
  277. Assert.True(parts.GetType().IsArray);
  278. Assert.Equal(3, ((object[])parts).Length);
  279. Assert.Equal(2d, ((object[])parts)[0]);
  280. Assert.Equal(4d, ((object[])parts)[1]);
  281. Assert.Equal(6d, ((object[])parts)[2]);
  282. }
  283. [Fact]
  284. public void ShouldConvertArrayInstanceToArray()
  285. {
  286. var result = _engine.Execute("'[email protected]'.split('@');");
  287. var parts = result.GetCompletionValue().ToObject();
  288. Assert.True(parts.GetType().IsArray);
  289. Assert.Equal(2, ((object[])parts).Length);
  290. Assert.Equal("foo", ((object[])parts)[0]);
  291. Assert.Equal("bar.com", ((object[])parts)[1]);
  292. }
  293. [Fact]
  294. public void ShouldConvertBooleanInstanceToBool()
  295. {
  296. var result = _engine.Execute("new Boolean(true)");
  297. var value = result.GetCompletionValue().ToObject();
  298. Assert.Equal(typeof(bool), value.GetType());
  299. Assert.Equal(true, value);
  300. }
  301. [Fact]
  302. public void ShouldConvertDateInstanceToDateTime()
  303. {
  304. var result = _engine.Execute("new Date(0)");
  305. var value = result.GetCompletionValue().ToObject();
  306. Assert.Equal(typeof(DateTime), value.GetType());
  307. Assert.Equal(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), value);
  308. }
  309. [Fact]
  310. public void ShouldConvertNumberInstanceToDouble()
  311. {
  312. var result = _engine.Execute("new Number(10)");
  313. var value = result.GetCompletionValue().ToObject();
  314. Assert.Equal(typeof(double), value.GetType());
  315. Assert.Equal(10d, value);
  316. }
  317. [Fact]
  318. public void ShouldConvertStringInstanceToString()
  319. {
  320. var result = _engine.Execute("new String('foo')");
  321. var value = result.GetCompletionValue().ToObject();
  322. Assert.Equal(typeof(string), value.GetType());
  323. Assert.Equal("foo", value);
  324. }
  325. [Fact]
  326. public void ShouldConvertObjectInstanceToExpando()
  327. {
  328. _engine.Execute("var o = {a: 1, b: 'foo'}");
  329. var result = _engine.GetValue("o");
  330. dynamic value = result.ToObject();
  331. Assert.Equal(1, value.a);
  332. Assert.Equal("foo", value.b);
  333. var dic = (IDictionary<string, object>)result.ToObject();
  334. Assert.Equal(1d, dic["a"]);
  335. Assert.Equal("foo", dic["b"]);
  336. }
  337. [Fact]
  338. public void ShouldNotTryToConvertCompatibleTypes()
  339. {
  340. _engine.SetValue("a", new A());
  341. RunTest(@"
  342. assert(a.Call3('foo') === 'foo');
  343. assert(a.Call3(1) === '1');
  344. ");
  345. }
  346. [Fact]
  347. public void ShouldNotTryToConvertDerivedTypes()
  348. {
  349. _engine.SetValue("a", new A());
  350. _engine.SetValue("p", new Person { Name = "Mickey" });
  351. RunTest(@"
  352. assert(a.Call4(p) === 'Mickey');
  353. ");
  354. }
  355. [Fact]
  356. public void ShouldExecuteFunctionCallBackAsDelegate()
  357. {
  358. _engine.SetValue("a", new A());
  359. RunTest(@"
  360. assert(a.Call5(function(a,b){ return a+b }) === '1foo');
  361. ");
  362. }
  363. [Fact]
  364. public void ShouldExecuteFunctionCallBackAsFuncAndThisCanBeAssigned()
  365. {
  366. _engine.SetValue("a", new A());
  367. RunTest(@"
  368. assert(a.Call6(function(a,b){ return this+a+b }) === 'bar1foo');
  369. ");
  370. }
  371. [Fact]
  372. public void ShouldUseSystemIO()
  373. {
  374. RunTest(@"
  375. var filename = System.IO.Path.GetTempFileName();
  376. var sw = System.IO.File.CreateText(filename);
  377. sw.Write('Hello World');
  378. sw.Dispose();
  379. var content = System.IO.File.ReadAllText(filename);
  380. System.Console.WriteLine(content);
  381. assert(content === 'Hello World');
  382. ");
  383. }
  384. [Fact]
  385. public void ShouldImportNamespace()
  386. {
  387. RunTest(@"
  388. var Shapes = importNamespace('Shapes');
  389. var circle = new Shapes.Circle();
  390. assert(circle.Radius === 0);
  391. assert(circle.Perimeter() === 0);
  392. ");
  393. }
  394. [Fact]
  395. public void ShouldConstructWithParameters()
  396. {
  397. RunTest(@"
  398. var Shapes = importNamespace('Shapes');
  399. var circle = new Shapes.Circle(1);
  400. assert(circle.Radius === 1);
  401. assert(circle.Perimeter() === Math.PI);
  402. ");
  403. }
  404. [Fact]
  405. public void ShouldInvokeAFunctionByName()
  406. {
  407. RunTest(@"
  408. function add(x, y) { return x + y; }
  409. ");
  410. Assert.Equal(3, _engine.Invoke("add", 1, 2));
  411. }
  412. [Fact]
  413. public void ShouldNotInvokeNonFunctionValue()
  414. {
  415. RunTest(@"
  416. var x= 10;
  417. ");
  418. Assert.Throws<ArgumentException>(() => _engine.Invoke("x", 1, 2));
  419. }
  420. [Fact]
  421. public void CanGetField()
  422. {
  423. var o = new ClassWithField
  424. {
  425. Field = "Mickey Mouse"
  426. };
  427. _engine.SetValue("o", o);
  428. RunTest(@"
  429. assert(o.Field === 'Mickey Mouse');
  430. ");
  431. }
  432. [Fact]
  433. public void CanSetField()
  434. {
  435. var o = new ClassWithField();
  436. _engine.SetValue("o", o);
  437. RunTest(@"
  438. o.Field = 'Mickey Mouse';
  439. assert(o.Field === 'Mickey Mouse');
  440. ");
  441. Assert.Equal("Mickey Mouse", o.Field);
  442. }
  443. [Fact]
  444. public void CanSetCustomConverters()
  445. {
  446. var engine1 = new Engine();
  447. engine1.SetValue("p", new { Test = true });
  448. engine1.Execute("var result = p.Test;");
  449. Assert.True((bool)engine1.GetValue("result").ToObject());
  450. var engine2 = new Engine(o => o.AddObjectConverter(new NegateBoolConverter()));
  451. engine2.SetValue("p", new { Test = true });
  452. engine2.Execute("var result = p.Test;");
  453. Assert.False((bool)engine2.GetValue("result").ToObject());
  454. }
  455. [Fact]
  456. public void CanUserIncrementOperator()
  457. {
  458. var p = new Person
  459. {
  460. Age = 1,
  461. };
  462. _engine.SetValue("p", p);
  463. RunTest(@"
  464. assert(++p.Age === 2);
  465. ");
  466. Assert.Equal(2, p.Age);
  467. }
  468. [Fact]
  469. public void CanOverwriteValues()
  470. {
  471. _engine.SetValue("x", 3);
  472. _engine.SetValue("x", 4);
  473. RunTest(@"
  474. assert(x === 4);
  475. ");
  476. }
  477. [Fact]
  478. public void ShouldCreateGenericType()
  479. {
  480. RunTest(@"
  481. var ListOfString = System.Collections.Generic.List(System.String);
  482. var list = new ListOfString();
  483. list.Add('foo');
  484. list.Add(1);
  485. assert(2 === list.Count);
  486. ");
  487. }
  488. [Fact]
  489. public void EnumComparesByName()
  490. {
  491. var o = new
  492. {
  493. r = Colors.Red,
  494. b = Colors.Blue,
  495. g = Colors.Green,
  496. b2 = Colors.Red
  497. };
  498. _engine.SetValue("o", o);
  499. _engine.SetValue("assertFalse", new Action<bool>(Assert.False));
  500. RunTest(@"
  501. var domain = importNamespace('Jint.Tests.Runtime.Domain');
  502. var colors = domain.Colors;
  503. assert(o.r === colors.Red);
  504. assert(o.g === colors.Green);
  505. assert(o.b === colors.Blue);
  506. assertFalse(o.b2 === colors.Blue);
  507. ");
  508. }
  509. [Fact]
  510. public void ShouldSetEnumProperty()
  511. {
  512. var s = new Circle
  513. {
  514. Color = Colors.Red,
  515. };
  516. _engine.SetValue("s", s);
  517. RunTest(@"
  518. var domain = importNamespace('Jint.Tests.Runtime.Domain');
  519. var colors = domain.Colors;
  520. s.Color = colors.Blue;
  521. assert(s.Color === colors.Blue);
  522. ");
  523. _engine.SetValue("s", s);
  524. RunTest(@"
  525. s.Color = colors.Blue | colors.Green;
  526. assert(s.Color === colors.Blue | colors.Green);
  527. ");
  528. Assert.Equal(Colors.Blue | Colors.Green, s.Color);
  529. }
  530. [Fact]
  531. public void EnumIsConvertedToNumber()
  532. {
  533. var o = new
  534. {
  535. r = Colors.Red,
  536. b = Colors.Blue,
  537. g = Colors.Green
  538. };
  539. _engine.SetValue("o", o);
  540. RunTest(@"
  541. assert(o.r === 0);
  542. assert(o.g === 1);
  543. assert(o.b === 10);
  544. ");
  545. }
  546. [Fact]
  547. public void ShouldConvertToEnum()
  548. {
  549. var s = new Circle
  550. {
  551. Color = Colors.Red,
  552. };
  553. _engine.SetValue("s", s);
  554. RunTest(@"
  555. assert(s.Color === 0);
  556. s.Color = 10;
  557. assert(s.Color === 10);
  558. ");
  559. _engine.SetValue("s", s);
  560. RunTest(@"
  561. s.Color = 11;
  562. assert(s.Color === 11);
  563. ");
  564. Assert.Equal(Colors.Blue | Colors.Green, s.Color);
  565. }
  566. }
  567. }