ArrayTests.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. using Jint.Native.Array;
  2. namespace Jint.Tests.Runtime;
  3. public class ArrayTests
  4. {
  5. private readonly Engine _engine;
  6. public ArrayTests()
  7. {
  8. _engine = new Engine()
  9. .SetValue("log", new Action<object>(Console.WriteLine))
  10. .SetValue("assert", new Action<bool>(Assert.True))
  11. .SetValue("equal", new Action<object, object>(Assert.Equal));
  12. }
  13. [Fact]
  14. public void ArrayPrototypeToStringWithArray()
  15. {
  16. var result = _engine.Evaluate("Array.prototype.toString.call([1,2,3]);").AsString();
  17. Assert.Equal("1,2,3", result);
  18. }
  19. [Fact]
  20. public void ArrayPrototypeToStringWithNumber()
  21. {
  22. var result = _engine.Evaluate("Array.prototype.toString.call(1);").AsString();
  23. Assert.Equal("[object Number]", result);
  24. }
  25. [Fact]
  26. public void ArrayPrototypeToStringWithObject()
  27. {
  28. var result = _engine.Evaluate("Array.prototype.toString.call({});").AsString();
  29. Assert.Equal("[object Object]", result);
  30. }
  31. [Fact]
  32. public void EmptyStringKey()
  33. {
  34. var result = _engine.Evaluate("var x=[];x[\"\"]=8;x[\"\"];").AsNumber();
  35. Assert.Equal(8, result);
  36. }
  37. [Fact]
  38. public void LargeArraySize()
  39. {
  40. const string code = @"
  41. let arr = [];
  42. for (let i = 0; i < 10000; i++) arr.push(i);
  43. for (let i=0;i<10000;i++) arr.splice(0, 1);
  44. ";
  45. var engine = new Engine();
  46. engine.Execute(code);
  47. }
  48. [Fact]
  49. public void ArrayLengthFromInitialState()
  50. {
  51. var engine = new Engine();
  52. var array = new ArrayInstance(engine, 0);
  53. var length = (int) array.Length;
  54. Assert.Equal(0, length);
  55. }
  56. [Fact]
  57. public void ArraySortIsStable()
  58. {
  59. const string code = @"
  60. var items = [
  61. { name: 'Edward', value: 0 },
  62. { name: 'Sharpe', value: 0 },
  63. { name: 'And', value: 0 },
  64. { name: 'The', value: 1 },
  65. { name: 'Magnetic', value: 0 },
  66. { name: 'Zeros', value: 0 }
  67. ];
  68. // sort by value
  69. function compare(a, b) {
  70. return a.value - b.value;
  71. }
  72. var a = items.sort();
  73. assert(a[0].name == 'Edward');
  74. assert(a[1].name == 'Sharpe');
  75. assert(a[2].name == 'And');
  76. assert(a[3].name == 'The');
  77. assert(a[4].name == 'Magnetic');
  78. assert(a[5].name == 'Zeros');
  79. var a = items.sort(compare);
  80. assert(a[0].name == 'Edward');
  81. assert(a[1].name == 'Sharpe');
  82. assert(a[2].name == 'And');
  83. assert(a[3].name == 'Magnetic');
  84. assert(a[4].name == 'Zeros');
  85. assert(a[5].name == 'The');
  86. ";
  87. _engine.Execute(code);
  88. }
  89. #if !NETCOREAPP
  90. // this test case only triggers on older full framework where the is no checks for infinite comparisons
  91. [Fact]
  92. public void ArraySortShouldObeyExecutionConstraints()
  93. {
  94. const string script = @"
  95. let cases = [5,5];
  96. let latestCase = cases.sort((c1, c2) => c1 > c2 ? -1: 1);";
  97. var engine = new Engine(options => options
  98. .TimeoutInterval(TimeSpan.FromSeconds(1))
  99. );
  100. Assert.Throws<TimeoutException>(() => engine.Evaluate(script));
  101. }
  102. #endif
  103. [Fact]
  104. public void ExtendingArrayAndInstanceOf()
  105. {
  106. const string script = @"
  107. class MyArr extends Array {
  108. constructor(...args) {
  109. super(...args);
  110. }
  111. }";
  112. _engine.Execute(script);
  113. _engine.Evaluate("const a = new MyArr(1,2);");
  114. Assert.True(_engine.Evaluate("a instanceof MyArr").AsBoolean());
  115. }
  116. [Fact]
  117. public void IteratorShouldBeConvertibleToArray()
  118. {
  119. Assert.Equal("hello;again", _engine.Evaluate("Array.from(['hello', 'again'].values()).join(';')"));
  120. Assert.Equal("hello;another", _engine.Evaluate("Array.from(new Map([['hello', 'world'], ['another', 'value']]).keys()).join(';')"));
  121. }
  122. [Fact]
  123. public void ArrayFromShouldNotFlattenInputArray()
  124. {
  125. Assert.Equal("a;b", _engine.Evaluate("[...['a', 'b']].join(';')"));
  126. Assert.Equal("0,a;1,b", _engine.Evaluate("[...['a', 'b'].entries()].join(';')"));
  127. Assert.Equal("0,c;1,d", _engine.Evaluate("Array.from(['c', 'd'].entries()).join(';')"));
  128. Assert.Equal("0,e;1,f", _engine.Evaluate("Array.from([[0, 'e'],[1, 'f']]).join(';')"));
  129. }
  130. [Fact]
  131. public void ArrayEntriesShouldReturnKeyValuePairs()
  132. {
  133. Assert.Equal("0,hello,1,world", _engine.Evaluate("Array.from(['hello', 'world'].entries()).join()"));
  134. Assert.Equal("0,hello;1,world", _engine.Evaluate("Array.from(['hello', 'world'].entries()).join(';')"));
  135. Assert.Equal("0,;1,1;2,5", _engine.Evaluate("Array.from([,1,5,].entries()).join(';')"));
  136. }
  137. [Fact]
  138. public void IteratorsShouldHaveIteratorSymbol()
  139. {
  140. _engine.Execute("assert(!!['hello'].values()[Symbol.iterator])");
  141. _engine.Execute("assert(!!new Map([['hello', 'world']]).keys()[Symbol.iterator])");
  142. }
  143. [Fact]
  144. public void ArraySortDoesNotCrashInDebugMode()
  145. {
  146. var engine = new Engine(o =>
  147. {
  148. o.DebugMode(true);
  149. });
  150. engine.SetValue("equal", new Action<object, object>(Assert.Equal));
  151. const string code = @"
  152. var items = [5,2,4,1];
  153. items.sort((a,b) => a - b);
  154. equal('1,2,4,5', items.join());
  155. ";
  156. engine.Execute(code);
  157. }
  158. [Fact]
  159. public void ArrayConstructorFromHoles()
  160. {
  161. _engine.Evaluate("var a = Array(...[,,]);");
  162. Assert.True(_engine.Evaluate("\"0\" in a").AsBoolean());
  163. Assert.True(_engine.Evaluate("\"1\" in a").AsBoolean());
  164. Assert.Equal("undefinedundefined", _engine.Evaluate("'' + a[0] + a[1]"));
  165. }
  166. [Fact]
  167. public void ArrayIsSubclassable()
  168. {
  169. _engine.Evaluate("class C extends Array {}");
  170. _engine.Evaluate("var c = new C();");
  171. Assert.True(_engine.Evaluate("c.map(Boolean) instanceof C").AsBoolean());
  172. }
  173. [Fact]
  174. public void HasProperIteratorPrototypeChain()
  175. {
  176. const string Script = @"
  177. // Iterator instance
  178. var iterator = [][Symbol.iterator]();
  179. // %ArrayIteratorPrototype%
  180. var proto1 = Object.getPrototypeOf(iterator);
  181. // %IteratorPrototype%
  182. var proto2 = Object.getPrototypeOf(proto1);";
  183. var engine = new Engine();
  184. engine.Execute(Script);
  185. Assert.True(engine.Evaluate("proto2.hasOwnProperty(Symbol.iterator)").AsBoolean());
  186. Assert.True(engine.Evaluate("!proto1.hasOwnProperty(Symbol.iterator)").AsBoolean());
  187. Assert.True(engine.Evaluate("!iterator.hasOwnProperty(Symbol.iterator)").AsBoolean());
  188. Assert.True(engine.Evaluate("iterator[Symbol.iterator]() === iterator").AsBoolean());
  189. }
  190. }