EngineTests.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921
  1. using System;
  2. using System.Globalization;
  3. using System.IO;
  4. using System.Reflection;
  5. using System.Threading;
  6. using Jint.Native.Number;
  7. using Jint.Parser;
  8. using Jint.Parser.Ast;
  9. using Jint.Runtime;
  10. using Xunit;
  11. using Xunit.Extensions;
  12. using System.Net;
  13. namespace Jint.Tests.Runtime
  14. {
  15. public class EngineTests : IDisposable
  16. {
  17. private readonly Engine _engine;
  18. public EngineTests()
  19. {
  20. _engine = new Engine()
  21. .SetValue("log", new Action<object>(Console.WriteLine))
  22. .SetValue("assert", new Action<bool>(Assert.True))
  23. ;
  24. }
  25. void IDisposable.Dispose()
  26. {
  27. }
  28. private void RunTest(string source)
  29. {
  30. _engine.Execute(source);
  31. }
  32. [Theory]
  33. [InlineData("Scratch.js")]
  34. public void ShouldInterpretScriptFile(string file)
  35. {
  36. const string prefix = "Jint.Tests.Runtime.Scripts.";
  37. var assembly = Assembly.GetExecutingAssembly();
  38. var scriptPath = prefix + file;
  39. using (var stream = assembly.GetManifestResourceStream(scriptPath))
  40. if (stream != null)
  41. using (var sr = new StreamReader(stream))
  42. {
  43. var source = sr.ReadToEnd();
  44. RunTest(source);
  45. }
  46. }
  47. [Theory]
  48. [InlineData(42d, "42")]
  49. [InlineData("Hello", "'Hello'")]
  50. public void ShouldInterpretLiterals(object expected, string source)
  51. {
  52. var engine = new Engine();
  53. var result = engine.Execute(source).GetCompletionValue().ToObject();
  54. Assert.Equal(expected, result);
  55. }
  56. [Fact]
  57. public void ShouldInterpretVariableDeclaration()
  58. {
  59. var engine = new Engine();
  60. var result = engine
  61. .Execute("var foo = 'bar'; foo;")
  62. .GetCompletionValue()
  63. .ToObject();
  64. Assert.Equal("bar", result);
  65. }
  66. [Theory]
  67. [InlineData(4d, "1 + 3")]
  68. [InlineData(-2d, "1 - 3")]
  69. [InlineData(3d, "1 * 3")]
  70. [InlineData(2d, "6 / 3")]
  71. [InlineData(9d, "15 & 9")]
  72. [InlineData(15d, "15 | 9")]
  73. [InlineData(6d, "15 ^ 9")]
  74. [InlineData(36d, "9 << 2")]
  75. [InlineData(2d, "9 >> 2")]
  76. [InlineData(4d, "19 >>> 2")]
  77. public void ShouldInterpretBinaryExpression(object expected, string source)
  78. {
  79. var engine = new Engine();
  80. var result = engine.Execute(source).GetCompletionValue().ToObject();
  81. Assert.Equal(expected, result);
  82. }
  83. [Fact]
  84. public void ShouldEvaluateHasOwnProperty()
  85. {
  86. RunTest(@"
  87. var x = {};
  88. x.Bar = 42;
  89. assert(x.hasOwnProperty('Bar'));
  90. ");
  91. }
  92. [Fact]
  93. public void FunctionConstructorsShouldCreateNewObjects()
  94. {
  95. RunTest(@"
  96. var Vehicle = function () {};
  97. var vehicle = new Vehicle();
  98. assert(vehicle != undefined);
  99. ");
  100. }
  101. [Fact]
  102. public void NewObjectsInheritFunctionConstructorProperties()
  103. {
  104. RunTest(@"
  105. var Vehicle = function () {};
  106. var vehicle = new Vehicle();
  107. Vehicle.prototype.wheelCount = 4;
  108. assert(vehicle.wheelCount == 4);
  109. assert((new Vehicle()).wheelCount == 4);
  110. ");
  111. }
  112. [Fact]
  113. public void PrototypeFunctionIsInherited()
  114. {
  115. RunTest(@"
  116. function Body(mass){
  117. this.mass = mass;
  118. }
  119. Body.prototype.offsetMass = function(dm) {
  120. this.mass += dm;
  121. return this;
  122. }
  123. var b = new Body(36);
  124. b.offsetMass(6);
  125. assert(b.mass == 42);
  126. ");
  127. }
  128. [Fact]
  129. public void FunctionConstructorCall()
  130. {
  131. RunTest(@"
  132. function Body(mass){
  133. this.mass = mass;
  134. }
  135. var john = new Body(36);
  136. assert(john.mass == 36);
  137. ");
  138. }
  139. [Fact]
  140. public void NewObjectsShouldUsePrivateProperties()
  141. {
  142. RunTest(@"
  143. var Vehicle = function (color) {
  144. this.color = color;
  145. };
  146. var vehicle = new Vehicle('tan');
  147. assert(vehicle.color == 'tan');
  148. ");
  149. }
  150. [Fact]
  151. public void FunctionConstructorsShouldDefinePrototypeChain()
  152. {
  153. RunTest(@"
  154. function Vehicle() {};
  155. var vehicle = new Vehicle();
  156. assert(vehicle.hasOwnProperty('constructor') == false);
  157. ");
  158. }
  159. [Fact]
  160. public void NewObjectsConstructorIsObject()
  161. {
  162. RunTest(@"
  163. var o = new Object();
  164. assert(o.constructor == Object);
  165. ");
  166. }
  167. [Fact]
  168. public void NewObjectsIntanceOfConstructorObject()
  169. {
  170. RunTest(@"
  171. var o = new Object();
  172. assert(o instanceof Object);
  173. ");
  174. }
  175. [Fact]
  176. public void NewObjectsConstructorShouldBeConstructorObject()
  177. {
  178. RunTest(@"
  179. var Vehicle = function () {};
  180. var vehicle = new Vehicle();
  181. assert(vehicle.constructor == Vehicle);
  182. ");
  183. }
  184. [Fact]
  185. public void NewObjectsIntanceOfConstructorFunction()
  186. {
  187. RunTest(@"
  188. var Vehicle = function () {};
  189. var vehicle = new Vehicle();
  190. assert(vehicle instanceof Vehicle);
  191. ");
  192. }
  193. [Fact]
  194. public void ShouldEvaluateForLoops()
  195. {
  196. RunTest(@"
  197. var foo = 0;
  198. for (var i = 0; i < 5; i++) {
  199. foo += i;
  200. }
  201. assert(foo == 10);
  202. ");
  203. }
  204. [Fact]
  205. public void ShouldEvaluateRecursiveFunctions()
  206. {
  207. RunTest(@"
  208. function fib(n) {
  209. if (n < 2) {
  210. return n;
  211. }
  212. return fib(n - 1) + fib(n - 2);
  213. }
  214. var result = fib(6);
  215. assert(result == 8);
  216. ");
  217. }
  218. [Fact]
  219. public void ShouldAccessObjectProperties()
  220. {
  221. RunTest(@"
  222. var o = {};
  223. o.Foo = 'bar';
  224. o.Baz = 42;
  225. o.Blah = o.Foo + o.Baz;
  226. assert(o.Blah == 'bar42');
  227. ");
  228. }
  229. [Fact]
  230. public void ShouldConstructArray()
  231. {
  232. RunTest(@"
  233. var o = [];
  234. assert(o.length == 0);
  235. ");
  236. }
  237. [Fact]
  238. public void ArrayPushShouldIncrementLength()
  239. {
  240. RunTest(@"
  241. var o = [];
  242. o.push(1);
  243. assert(o.length == 1);
  244. ");
  245. }
  246. [Fact]
  247. public void ArrayFunctionInitializesLength()
  248. {
  249. RunTest(@"
  250. assert(Array(3).length == 3);
  251. assert(Array('3').length == 1);
  252. ");
  253. }
  254. [Fact]
  255. public void ArrayIndexerIsAssigned()
  256. {
  257. RunTest(@"
  258. var n = 8;
  259. var o = Array(n);
  260. for (var i = 0; i < n; i++) o[i] = i;
  261. assert(o[0] == 0);
  262. assert(o[7] == 7);
  263. ");
  264. }
  265. [Fact]
  266. public void ArrayPopShouldDecrementLength()
  267. {
  268. RunTest(@"
  269. var o = [42, 'foo'];
  270. var pop = o.pop();
  271. assert(o.length == 1);
  272. assert(pop == 'foo');
  273. ");
  274. }
  275. [Fact]
  276. public void ArrayConstructor()
  277. {
  278. RunTest(@"
  279. var o = [];
  280. assert(o.constructor == Array);
  281. ");
  282. }
  283. [Fact]
  284. public void DateConstructor()
  285. {
  286. RunTest(@"
  287. var o = new Date();
  288. assert(o.constructor == Date);
  289. assert(o.hasOwnProperty('constructor') == false);
  290. ");
  291. }
  292. [Fact]
  293. public void ShouldConvertDateToNumber()
  294. {
  295. RunTest(@"
  296. assert(Number(new Date(0)) === 0);
  297. ");
  298. }
  299. [Fact]
  300. public void DatePrimitiveValueShouldBeNaN()
  301. {
  302. RunTest(@"
  303. assert(isNaN(Date.prototype.valueOf()));
  304. ");
  305. }
  306. [Fact]
  307. public void MathObjectIsDefined()
  308. {
  309. RunTest(@"
  310. var o = Math.abs(-1)
  311. assert(o == 1);
  312. ");
  313. }
  314. [Fact]
  315. public void VoidShouldReturnUndefined()
  316. {
  317. RunTest(@"
  318. assert(void 0 === undefined);
  319. var x = '1';
  320. assert(void x === undefined);
  321. x = 'x';
  322. assert (isNaN(void x) === true);
  323. x = new String('-1');
  324. assert (void x === undefined);
  325. ");
  326. }
  327. [Fact]
  328. public void TypeofObjectShouldReturnString()
  329. {
  330. RunTest(@"
  331. assert(typeof x === 'undefined');
  332. assert(typeof 0 === 'number');
  333. var x = 0;
  334. assert (typeof x === 'number');
  335. var x = new Object();
  336. assert (typeof x === 'object');
  337. ");
  338. }
  339. [Fact]
  340. public void MathAbsReturnsAbsolute()
  341. {
  342. RunTest(@"
  343. assert(1 == Math.abs(-1));
  344. ");
  345. }
  346. [Fact]
  347. public void NaNIsNan()
  348. {
  349. RunTest(@"
  350. var x = NaN;
  351. assert(isNaN(NaN));
  352. assert(isNaN(Math.abs(x)));
  353. ");
  354. }
  355. [Fact]
  356. public void ToNumberHandlesStringObject()
  357. {
  358. RunTest(@"
  359. x = new String('1');
  360. x *= undefined;
  361. assert(isNaN(x));
  362. ");
  363. }
  364. [Fact]
  365. public void FunctionScopesAreChained()
  366. {
  367. RunTest(@"
  368. var x = 0;
  369. function f1(){
  370. function f2(){
  371. return x;
  372. };
  373. return f2();
  374. var x = 1;
  375. }
  376. assert(f1() === undefined);
  377. ");
  378. }
  379. [Fact]
  380. public void EvalFunctionParseAndExecuteCode()
  381. {
  382. RunTest(@"
  383. var x = 0;
  384. eval('assert(x == 0)');
  385. ");
  386. }
  387. [Fact]
  388. public void ForInStatement()
  389. {
  390. RunTest(@"
  391. var x, y, str = '';
  392. for(var z in this) {
  393. str += z;
  394. }
  395. assert(str == 'xystrz');
  396. ");
  397. }
  398. [Fact]
  399. public void WithStatement()
  400. {
  401. RunTest(@"
  402. with (Math) {
  403. assert(cos(0) == 1);
  404. }
  405. ");
  406. }
  407. [Fact]
  408. public void ObjectExpression()
  409. {
  410. RunTest(@"
  411. var o = { x: 1 };
  412. assert(o.x == 1);
  413. ");
  414. }
  415. [Fact]
  416. public void StringFunctionCreatesString()
  417. {
  418. RunTest(@"
  419. assert(String(NaN) === 'NaN');
  420. ");
  421. }
  422. [Fact]
  423. public void ScopeChainInWithStatement()
  424. {
  425. RunTest(@"
  426. var x = 0;
  427. var myObj = {x : 'obj'};
  428. function f1(){
  429. var x = 1;
  430. function f2(){
  431. with(myObj){
  432. return x;
  433. }
  434. };
  435. return f2();
  436. }
  437. assert(f1() === 'obj');
  438. ");
  439. }
  440. [Fact]
  441. public void TryCatchBlockStatement()
  442. {
  443. RunTest(@"
  444. var x, y, z;
  445. try {
  446. x = 1;
  447. throw new TypeError();
  448. x = 2;
  449. }
  450. catch(e) {
  451. assert(x == 1);
  452. assert(e instanceof TypeError);
  453. y = 1;
  454. }
  455. finally {
  456. assert(x == 1);
  457. z = 1;
  458. }
  459. assert(x == 1);
  460. assert(y == 1);
  461. assert(z == 1);
  462. ");
  463. }
  464. [Fact]
  465. public void FunctionsCanBeAssigned()
  466. {
  467. RunTest(@"
  468. var sin = Math.sin;
  469. assert(sin(0) == 0);
  470. ");
  471. }
  472. [Fact]
  473. public void FunctionArgumentsIsDefined()
  474. {
  475. RunTest(@"
  476. function f() {
  477. assert(arguments.length > 0);
  478. }
  479. f(42);
  480. ");
  481. }
  482. [Fact]
  483. public void PrimitiveValueFunctions()
  484. {
  485. RunTest(@"
  486. var s = (1).toString();
  487. assert(s == '1');
  488. ");
  489. }
  490. [Theory]
  491. [InlineData(true, "'ab' == 'a' + 'b'")]
  492. public void OperatorsPrecedence(object expected, string source)
  493. {
  494. var engine = new Engine();
  495. var result = engine.Execute(source).GetCompletionValue().ToObject();
  496. Assert.Equal(expected, result);
  497. }
  498. [Fact]
  499. public void FunctionPrototypeShouldHaveApplyMethod()
  500. {
  501. RunTest(@"
  502. var numbers = [5, 6, 2, 3, 7];
  503. var max = Math.max.apply(null, numbers);
  504. assert(max == 7);
  505. ");
  506. }
  507. [Theory]
  508. [InlineData(double.NaN, "parseInt(NaN)")]
  509. [InlineData(double.NaN, "parseInt(null)")]
  510. [InlineData(double.NaN, "parseInt(undefined)")]
  511. [InlineData(double.NaN, "parseInt(new Boolean(true))")]
  512. [InlineData(double.NaN, "parseInt(Infinity)")]
  513. [InlineData(-1d, "parseInt(-1)")]
  514. [InlineData(-1d, "parseInt('-1')")]
  515. public void ShouldEvaluateParseInt(object expected, string source)
  516. {
  517. var engine = new Engine();
  518. var result = engine.Execute(source).GetCompletionValue().ToObject();
  519. Assert.Equal(expected, result);
  520. }
  521. [Fact]
  522. public void ShouldNotExecuteDebuggerStatement()
  523. {
  524. new Engine().Execute("debugger");
  525. }
  526. [Fact]
  527. public void ShouldThrowStatementCountOverflow()
  528. {
  529. Assert.Throws<StatementsCountOverflowException>(
  530. () => new Engine(cfg => cfg.MaxStatements(100)).Execute("while(true);")
  531. );
  532. }
  533. [Fact]
  534. public void ShouldThrowTimeout()
  535. {
  536. Assert.Throws<TimeoutException>(
  537. () => new Engine(cfg => cfg.TimeoutInterval(new TimeSpan(0,0,0,0,500))).Execute("while(true);")
  538. );
  539. }
  540. [Fact]
  541. public void ShouldConvertDoubleToStringWithoutLosingPrecision()
  542. {
  543. RunTest(@"
  544. assert(String(14.915832707045631) === '14.915832707045631');
  545. assert(String(-14.915832707045631) === '-14.915832707045631');
  546. assert(String(0.5) === '0.5');
  547. assert(String(0.00000001) === '1e-8');
  548. assert(String(0.000001) === '0.000001');
  549. assert(String(-1.0) === '-1');
  550. assert(String(30.0) === '30');
  551. assert(String(0.2388906159889881) === '0.2388906159889881');
  552. ");
  553. }
  554. [Fact]
  555. public void ShouldWriteNumbersUsingBases()
  556. {
  557. RunTest(@"
  558. assert(15.0.toString() === '15');
  559. assert(15.0.toString(2) === '1111');
  560. assert(15.0.toString(8) === '17');
  561. assert(15.0.toString(16) === 'f');
  562. assert(15.0.toString(17) === 'f');
  563. assert(15.0.toString(36) === 'f');
  564. assert(15.1.toString(36) === 'f.3llllllllkau6snqkpygsc3di');
  565. ");
  566. }
  567. [Fact]
  568. public void ShouldNotAlterSlashesInRegex()
  569. {
  570. RunTest(@"
  571. assert(new RegExp('/').toString() === '///');
  572. ");
  573. }
  574. [Fact]
  575. public void ShouldHandleEscapedSlashesInRegex()
  576. {
  577. RunTest(@"
  578. var regex = /[a-z]\/[a-z]/;
  579. assert(regex.test('a/b') === true);
  580. assert(regex.test('a\\/b') === false);
  581. ");
  582. }
  583. [Fact]
  584. public void ShouldComputeFractionInBase()
  585. {
  586. Assert.Equal("011", NumberPrototype.ToFractionBase(0.375, 2));
  587. Assert.Equal("14141414141414141414141414141414141414141414141414", NumberPrototype.ToFractionBase(0.375, 5));
  588. }
  589. [Fact]
  590. public void ShouldInvokeAFunctionValue()
  591. {
  592. RunTest(@"
  593. function add(x, y) { return x + y; }
  594. ");
  595. var add = _engine.GetValue("add");
  596. Assert.Equal(3, add.Invoke(1, 2));
  597. }
  598. [Fact]
  599. public void ShouldNotInvokeNonFunctionValue()
  600. {
  601. RunTest(@"
  602. var x= 10;
  603. ");
  604. var x = _engine.GetValue("x");
  605. Assert.Throws<ArgumentException>(() => x.Invoke(1, 2));
  606. }
  607. [Theory]
  608. [InlineData("0", 0, 16)]
  609. [InlineData("1", 1, 16)]
  610. [InlineData("100", 100, 10)]
  611. [InlineData("1100100", 100, 2)]
  612. [InlineData("2s", 100, 36)]
  613. [InlineData("2qgpckvng1s", 10000000000000000L, 36)]
  614. public void ShouldConvertNumbersToDifferentBase(string expected, long number, int radix)
  615. {
  616. var result = NumberPrototype.ToBase(number, radix);
  617. Assert.Equal(expected, result);
  618. }
  619. [Fact]
  620. public void JsonParserShouldParseNegativeNumber()
  621. {
  622. var engine = new Engine();
  623. var result = engine.Execute(@"JSON.parse('{ ""x"":-1 }').x === -1").GetCompletionValue().AsBoolean();
  624. Assert.Equal(true, result);
  625. result = engine.Execute(@"JSON.parse('{ ""x"": -1 }').x === -1").GetCompletionValue().AsBoolean();
  626. Assert.Equal(true, result);
  627. }
  628. [Fact]
  629. public void JsonParserShouldDetectInvalidNegativeNumberSyntax()
  630. {
  631. var engine = new Engine();
  632. var code = @"
  633. function f() {
  634. try {
  635. JSON.parse('{ ""x"": -.1 }'); // Not allowed
  636. return false;
  637. }
  638. catch(ex) {
  639. return ex.toString().indexOf('Unexpected token') !== -1;
  640. }
  641. }
  642. f();
  643. ";
  644. Assert.True(engine.Execute(code).GetCompletionValue().AsBoolean());
  645. code = @"
  646. function f() {
  647. try {
  648. JSON.parse('{ ""x"": - 1 }'); // Not allowed
  649. return false;
  650. }
  651. catch(ex) {
  652. return ex.toString().indexOf('Unexpected token') !== -1;
  653. }
  654. }
  655. f();
  656. ";
  657. Assert.True(engine.Execute(code).GetCompletionValue().AsBoolean());
  658. }
  659. [Fact]
  660. public void ShouldBeCultureInvariant()
  661. {
  662. // decimals in french are separated by commas
  663. Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("fr-FR");
  664. var engine = new Engine();
  665. var result = engine.Execute("1.2 + 2.1").GetCompletionValue().AsNumber();
  666. Assert.Equal(3.3d, result);
  667. result = engine.Execute("JSON.parse('{\"x\" : 3.3}').x").GetCompletionValue().AsNumber();
  668. Assert.Equal(3.3d, result);
  669. }
  670. [Fact]
  671. public void ShouldGetTheLastSyntaxNode()
  672. {
  673. var engine = new Engine();
  674. engine.Execute("1.2");
  675. var result = engine.GetLastSyntaxNode();
  676. Assert.Equal(SyntaxNodes.Literal, result.Type);
  677. }
  678. [Fact]
  679. public void ShouldGetParseErrorLocation()
  680. {
  681. var engine = new Engine();
  682. try
  683. {
  684. engine.Execute("1.2+ new", new ParserOptions { Source = "jQuery.js" });
  685. }
  686. catch (ParserException e)
  687. {
  688. Assert.Equal(1, e.LineNumber);
  689. Assert.Equal(9, e.Column);
  690. Assert.Equal("jQuery.js", e.Source);
  691. }
  692. }
  693. [Fact]
  694. public void ParseShouldReturnNumber()
  695. {
  696. var engine = new Engine();
  697. var result = engine.Execute("Date.parse('1970-01-01');").GetCompletionValue().AsNumber();
  698. Assert.Equal(0, result);
  699. }
  700. [Fact]
  701. public void UtcShouldUseUtc()
  702. {
  703. const string customName = "Custom Time";
  704. var customTimeZone = TimeZoneInfo.CreateCustomTimeZone(customName, new TimeSpan(7, 11, 0), customName, customName, customName, null, false);
  705. var engine = new Engine(cfg => cfg.LocalTimeZone(customTimeZone));
  706. var result = engine.Execute("Date.UTC(1970,0,1)").GetCompletionValue().AsNumber();
  707. Assert.Equal(0, result);
  708. }
  709. [Fact]
  710. public void ShouldUseLocalTimeZoneOverride()
  711. {
  712. const string customName = "Custom Time";
  713. var customTimeZone = TimeZoneInfo.CreateCustomTimeZone(customName, new TimeSpan(0, 11, 0), customName, customName, customName, null, false);
  714. var engine = new Engine(cfg => cfg.LocalTimeZone(customTimeZone));
  715. var epochGetLocalMinutes = engine.Execute("var d = new Date(0); d.getMinutes();").GetCompletionValue().AsNumber();
  716. Assert.Equal(11, epochGetLocalMinutes);
  717. var localEpochGetUtcMinutes = engine.Execute("var d = new Date(1970,0,1); d.getUTCMinutes();").GetCompletionValue().AsNumber();
  718. Assert.Equal(-11, localEpochGetUtcMinutes);
  719. var parseLocalEpoch = engine.Execute("Date.parse('January 1, 1970');").GetCompletionValue().AsNumber();
  720. Assert.Equal(-11 * 60 * 1000, parseLocalEpoch);
  721. var epochToLocalString = engine.Execute("var d = new Date(0); d.toString();").GetCompletionValue().AsString();
  722. Assert.Equal("Thu Jan 01 1970 00:11:00 GMT", epochToLocalString);
  723. }
  724. [Theory]
  725. [InlineData("1970")]
  726. [InlineData("1970-01")]
  727. [InlineData("1970-01-01")]
  728. [InlineData("1970-01-01T00:00")]
  729. [InlineData("1970-01-01T00:00:00")]
  730. [InlineData("1970-01-01T00:00:00.000")]
  731. [InlineData("1970Z")]
  732. [InlineData("1970-1Z")]
  733. [InlineData("1970-1-1Z")]
  734. [InlineData("1970-1-1T0:0Z")]
  735. [InlineData("1970-1-1T0:0:0Z")]
  736. [InlineData("1970-1-1T0:0:0.0Z")]
  737. [InlineData("1970/1Z")]
  738. [InlineData("1970/1/1Z")]
  739. [InlineData("1970/1/1 0:0Z")]
  740. [InlineData("1970/1/1 0:0:0Z")]
  741. [InlineData("1970/1/1 0:0:0.0Z")]
  742. [InlineData("January 1, 1970 GMT")]
  743. [InlineData("1970-01-01T00:00:00.000-00:00")]
  744. public void ShouldParseAsUtc(string date)
  745. {
  746. const string customName = "Custom Time";
  747. var customTimeZone = TimeZoneInfo.CreateCustomTimeZone(customName, new TimeSpan(7, 11, 0), customName, customName, customName, null, false);
  748. var engine = new Engine(cfg => cfg.LocalTimeZone(customTimeZone));
  749. engine.SetValue("d", date);
  750. var result = engine.Execute("Date.parse(d);").GetCompletionValue().AsNumber();
  751. Assert.Equal(0, result);
  752. }
  753. [Theory]
  754. [InlineData("1970/01")]
  755. [InlineData("1970/01/01")]
  756. [InlineData("1970/01/01T00:00")]
  757. [InlineData("1970/01/01 00:00")]
  758. [InlineData("1970-1")]
  759. [InlineData("1970-1-1")]
  760. [InlineData("1970-1-1T0:0")]
  761. [InlineData("1970-1-1 0:0")]
  762. [InlineData("1970/1")]
  763. [InlineData("1970/1/1")]
  764. [InlineData("1970/1/1T0:0")]
  765. [InlineData("1970/1/1 0:0")]
  766. [InlineData("01-1970")]
  767. [InlineData("01-01-1970")]
  768. [InlineData("January 1, 1970")]
  769. [InlineData("1970-01-01T00:00:00.000+00:11")]
  770. public void ShouldParseAsLocalTime(string date)
  771. {
  772. const string customName = "Custom Time";
  773. var customTimeZone = TimeZoneInfo.CreateCustomTimeZone(customName, new TimeSpan(0, 11, 0), customName, customName, customName, null, false);
  774. var engine = new Engine(cfg => cfg.LocalTimeZone(customTimeZone)).SetValue("d", date);
  775. var result = engine.Execute("Date.parse(d);").GetCompletionValue().AsNumber();
  776. Assert.Equal(-11 * 60 * 1000, result);
  777. }
  778. [Fact]
  779. public void EmptyStringShouldMatchRegex()
  780. {
  781. RunTest(@"
  782. var regex = /^(?:$)/g;
  783. assert(''.match(regex) instanceof Array);
  784. ");
  785. }
  786. [Fact]
  787. public void ShouldExecuteHandlebars()
  788. {
  789. var url = "http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/2.0.0/handlebars.js";
  790. var content = new WebClient().DownloadString(url);
  791. RunTest(content);
  792. RunTest(@"
  793. var source = 'Hello {{name}}';
  794. var template = Handlebars.compile(source);
  795. var context = {name: 'Paul'};
  796. var html = template(context);
  797. assert('Hello Paul' == html);
  798. ");
  799. }
  800. }
  801. }