builtin_arrray_test.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. package goja
  2. import (
  3. "testing"
  4. )
  5. func TestArrayProtoProp(t *testing.T) {
  6. const SCRIPT = `
  7. Object.defineProperty(Array.prototype, '0', {value: 42, configurable: true, writable: false})
  8. var a = []
  9. a[0] = 1
  10. a[0]
  11. `
  12. testScript(SCRIPT, valueInt(42), t)
  13. }
  14. func TestArrayDelete(t *testing.T) {
  15. const SCRIPT = `
  16. var a = [1, 2];
  17. var deleted = delete a[0];
  18. var undef = a[0] === undefined;
  19. var len = a.length;
  20. deleted && undef && len === 2;
  21. `
  22. testScript(SCRIPT, valueTrue, t)
  23. }
  24. func TestArrayDeleteNonexisting(t *testing.T) {
  25. const SCRIPT = `
  26. Array.prototype[0] = 42;
  27. var a = [];
  28. delete a[0] && a[0] === 42;
  29. `
  30. testScript(SCRIPT, valueTrue, t)
  31. }
  32. func TestArraySetLength(t *testing.T) {
  33. const SCRIPT = `
  34. var a = [1, 2];
  35. var assert0 = a.length == 2;
  36. a.length = "1";
  37. a.length = 1.0;
  38. a.length = 1;
  39. var assert1 = a.length == 1;
  40. a.length = 2;
  41. var assert2 = a.length == 2;
  42. assert0 && assert1 && assert2 && a[1] === undefined;
  43. `
  44. testScript(SCRIPT, valueTrue, t)
  45. }
  46. func TestArrayReverseNonOptimisable(t *testing.T) {
  47. const SCRIPT = `
  48. var a = [];
  49. Object.defineProperty(a, "0", {get: function() {return 42}, set: function(v) {Object.defineProperty(a, "0", {value: v + 1, writable: true, configurable: true})}, configurable: true})
  50. a[1] = 43;
  51. a.reverse();
  52. a.length === 2 && a[0] === 44 && a[1] === 42;
  53. `
  54. testScript(SCRIPT, valueTrue, t)
  55. }
  56. func TestArrayPushNonOptimisable(t *testing.T) {
  57. const SCRIPT = `
  58. Object.defineProperty(Object.prototype, "0", {value: 42});
  59. var a = [];
  60. var thrown = false;
  61. try {
  62. a.push(1);
  63. } catch (e) {
  64. thrown = e instanceof TypeError;
  65. }
  66. thrown;
  67. `
  68. testScript(SCRIPT, valueTrue, t)
  69. }
  70. func TestArraySetLengthWithPropItems(t *testing.T) {
  71. const SCRIPT = `
  72. var a = [1,2,3,4];
  73. var thrown = false;
  74. Object.defineProperty(a, "2", {value: 42, configurable: false, writable: false});
  75. try {
  76. Object.defineProperty(a, "length", {value: 0, writable: false});
  77. } catch (e) {
  78. thrown = e instanceof TypeError;
  79. }
  80. thrown && a.length === 3;
  81. `
  82. testScript(SCRIPT, valueTrue, t)
  83. }
  84. func TestArrayFrom(t *testing.T) {
  85. const SCRIPT = `
  86. function checkDestHoles(dest, prefix) {
  87. assert(dest !== source, prefix + ": dest !== source");
  88. assert.sameValue(dest.length, 3, prefix + ": dest.length");
  89. assert.sameValue(dest[0], 1, prefix + ": [0]");
  90. assert.sameValue(dest[1], undefined, prefix + ": [1]");
  91. assert(dest.hasOwnProperty("1"), prefix + ': hasOwnProperty("1")');
  92. assert.sameValue(dest[2], 3, prefix + ": [2]");
  93. }
  94. function checkDest(dest, prefix) {
  95. assert(dest !== source, prefix + ": dest !== source");
  96. assert.sameValue(dest.length, 3, prefix + ": dest.length");
  97. assert.sameValue(dest[0], 1, prefix + ": [0]");
  98. assert.sameValue(dest[1], 2, prefix + ": [1]");
  99. assert.sameValue(dest[2], 3, prefix + ": [2]");
  100. }
  101. var source = [1,2,3];
  102. var srcHoles = [1,,3];
  103. checkDest(Array.from(source), "std source/std dest");
  104. checkDestHoles(Array.from(srcHoles), "std source (holes)/std dest");
  105. function Iter() {
  106. this.idx = 0;
  107. }
  108. Iter.prototype.next = function() {
  109. if (this.idx < source.length) {
  110. return {value: source[this.idx++]};
  111. } else {
  112. return {done: true};
  113. }
  114. }
  115. var src = {};
  116. src[Symbol.iterator] = function() {
  117. return new Iter();
  118. }
  119. checkDest(Array.from(src), "iter src/std dest");
  120. src = {0: 1, 2: 3, length: 3};
  121. checkDestHoles(Array.from(src), "arrayLike src/std dest");
  122. function A() {}
  123. A.from = Array.from;
  124. checkDest(A.from(source), "std src/cust dest");
  125. checkDestHoles(A.from(srcHoles), "std src (holes)/cust dest");
  126. checkDestHoles(A.from(src), "arrayLike src/cust dest");
  127. function T2() {
  128. Object.defineProperty(this, 0, {
  129. configurable: false,
  130. writable: true,
  131. enumerable: true
  132. });
  133. }
  134. assert.throws(TypeError, function() {
  135. Array.from.call(T2, source);
  136. });
  137. `
  138. testScriptWithTestLib(SCRIPT, _undefined, t)
  139. }
  140. func TestArrayOf(t *testing.T) {
  141. const SCRIPT = `
  142. function T1() {
  143. Object.preventExtensions(this);
  144. }
  145. assert.throws(TypeError, function() {
  146. Array.of.call(T1, 'Bob');
  147. });
  148. function T2() {
  149. Object.defineProperty(this, 0, {
  150. configurable: false,
  151. writable: true,
  152. enumerable: true
  153. });
  154. }
  155. assert.throws(TypeError, function() {
  156. Array.of.call(T2, 'Bob');
  157. })
  158. result = Array.of.call(undefined);
  159. assert(
  160. result instanceof Array,
  161. 'this is not a constructor'
  162. );
  163. result = Array.of.call(Math.cos);
  164. assert(
  165. result instanceof Array,
  166. 'this is a builtin function with no [[Construct]] slot'
  167. );
  168. `
  169. testScriptWithTestLib(SCRIPT, _undefined, t)
  170. }
  171. func TestUnscopables(t *testing.T) {
  172. const SCRIPT = `
  173. var keys = [];
  174. var _length;
  175. with (Array.prototype) {
  176. _length = length;
  177. keys.push('something');
  178. }
  179. _length === 0 && keys.length === 1 && keys[0] === "something";
  180. `
  181. testScript(SCRIPT, valueTrue, t)
  182. }
  183. func TestArraySort(t *testing.T) {
  184. const SCRIPT = `
  185. assert.throws(TypeError, function() {
  186. [1,2].sort(null);
  187. }, "null compare function");
  188. assert.throws(TypeError, function() {
  189. [1,2].sort({});
  190. }, "non-callable compare function");
  191. `
  192. testScriptWithTestLib(SCRIPT, _undefined, t)
  193. }
  194. func TestArraySortNonStdArray(t *testing.T) {
  195. const SCRIPT = `
  196. const array = [undefined, 'c', /*hole*/, 'b', undefined, /*hole*/, 'a', 'd'];
  197. Object.defineProperty(array, '2', {
  198. get() {
  199. array.pop();
  200. array.pop();
  201. return this.foo;
  202. },
  203. set(v) {
  204. this.foo = v;
  205. }
  206. });
  207. array.sort();
  208. assert.sameValue(array[0], 'b');
  209. assert.sameValue(array[1], 'c');
  210. assert.sameValue(array[3], undefined);
  211. assert.sameValue(array[4], undefined);
  212. assert.sameValue('5' in array, false);
  213. assert.sameValue(array.hasOwnProperty('5'), false);
  214. assert.sameValue(array.length, 6);
  215. assert.sameValue(array.foo, undefined);
  216. assert.sameValue(array[2], undefined);
  217. assert.sameValue(array.length, 4);
  218. `
  219. testScriptWithTestLib(SCRIPT, _undefined, t)
  220. }
  221. func TestArrayConcat(t *testing.T) {
  222. const SCRIPT = `
  223. var concat = Array.prototype.concat;
  224. var array = [1, 2];
  225. var sparseArray = [1, , 2];
  226. var nonSpreadableArray = [1, 2];
  227. nonSpreadableArray[Symbol.isConcatSpreadable] = false;
  228. var arrayLike = { 0: 1, 1: 2, length: 2 };
  229. var spreadableArrayLike = { 0: 1, 1: 2, length: 2 };
  230. spreadableArrayLike[Symbol.isConcatSpreadable] = true;
  231. assert(looksNative(concat));
  232. assert(deepEqual(array.concat(), [1, 2]), '#1');
  233. assert(deepEqual(sparseArray.concat(), [1, , 2]), '#2');
  234. assert(deepEqual(nonSpreadableArray.concat(), [[1, 2]]), '#3');
  235. assert(deepEqual(concat.call(arrayLike), [{ 0: 1, 1: 2, length: 2 }]), '#4');
  236. assert(deepEqual(concat.call(spreadableArrayLike), [1, 2]), '#5');
  237. assert(deepEqual([].concat(array), [1, 2]), '#6');
  238. assert(deepEqual([].concat(sparseArray), [1, , 2]), '#7');
  239. assert(deepEqual([].concat(nonSpreadableArray), [[1, 2]]), '#8');
  240. assert(deepEqual([].concat(arrayLike), [{ 0: 1, 1: 2, length: 2 }]), '#9');
  241. assert(deepEqual([].concat(spreadableArrayLike), [1, 2]), '#10');
  242. assert(deepEqual(array.concat(sparseArray, nonSpreadableArray, arrayLike, spreadableArrayLike), [
  243. 1, 2, 1, , 2, [1, 2], { 0: 1, 1: 2, length: 2 }, 1, 2,
  244. ]), '#11');
  245. array = [];
  246. array.constructor = {};
  247. array.constructor[Symbol.species] = function () {
  248. return { foo: 1 };
  249. }
  250. assert.sameValue(array.concat().foo, 1, '@@species');
  251. `
  252. testScriptWithTestLibX(SCRIPT, _undefined, t)
  253. }
  254. func TestArrayFlat(t *testing.T) {
  255. const SCRIPT = `
  256. var array = [1, [2,3,[4,5,6]], [[[[7,8,9]]]]];
  257. assert(deepEqual(array.flat(), [1,2,3,[4,5,6],[[[7,8,9]]]]), '#1');
  258. assert(deepEqual(array.flat(1), [1,2,3,[4,5,6],[[[7,8,9]]]]), '#2');
  259. assert(deepEqual(array.flat(3), [1,2,3,4,5,6,[7,8,9]]), '#3');
  260. assert(deepEqual(array.flat(4), [1,2,3,4,5,6,7,8,9]), '#4');
  261. assert(deepEqual(array.flat(10), [1,2,3,4,5,6,7,8,9]), '#5');
  262. `
  263. testScriptWithTestLibX(SCRIPT, _undefined, t)
  264. }
  265. func TestArrayFlatMap(t *testing.T) {
  266. const SCRIPT = `
  267. var double = function(x) {
  268. if (isNaN(x)) {
  269. return x
  270. }
  271. return x * 2
  272. }
  273. var array = [1, [2,3,[4,5,6]], [[[[7,8,9]]]]];
  274. assert(deepEqual(array.flatMap(double), [2,2,3,[4,5,6],[[[7,8,9]]]]), '#1');
  275. `
  276. testScriptWithTestLibX(SCRIPT, _undefined, t)
  277. }
  278. func TestArrayProto(t *testing.T) {
  279. const SCRIPT = `
  280. const a = Array.prototype;
  281. a.push(1, 2, 3, 4, 5);
  282. assert.sameValue(a.length, 5);
  283. assert.sameValue(a[0], 1);
  284. a.length = 3;
  285. assert.sameValue(a.length, 3);
  286. assert(compareArray(a, [1, 2, 3]));
  287. a.shift();
  288. assert.sameValue(a.length, 2);
  289. assert(compareArray(a, [2, 3]));
  290. `
  291. testScriptWithTestLib(SCRIPT, _undefined, t)
  292. }
  293. func TestArrayToSpliced(t *testing.T) {
  294. const SCRIPT = `
  295. const a = [1, 2, 3];
  296. a.push(4)
  297. assert(compareArray(a, [1, 2, 3, 4]));
  298. const b = a.toSpliced(2)
  299. assert(compareArray(a, [1, 2, 3, 4]));
  300. assert(compareArray(b, [1, 2]));
  301. a.push(5)
  302. const c = a.toSpliced(1, 2);
  303. assert(compareArray(a, [1, 2, 3, 4, 5]));
  304. assert(compareArray(c, [1, 4, 5]));
  305. assert(compareArray(a.toSpliced(4, 2, 'a', 'b'), [1, 2, 3, 4, 'a', 'b']));
  306. assert(compareArray(a, [1, 2, 3, 4, 5]));
  307. assert(compareArray(a.toSpliced(-2, 2), [1, 2, 3]));
  308. assert(compareArray(a, [1, 2, 3, 4, 5]));
  309. assert(compareArray(a.toSpliced(2, 10), [1, 2]));
  310. assert(compareArray(a, [1, 2, 3, 4, 5]));
  311. assert(compareArray(a.toSpliced(1, 0, 'a'), [1, 'a', 2, 3, 4, 5]));
  312. assert(compareArray(a, [1, 2, 3, 4, 5]));
  313. `
  314. testScriptWithTestLib(SCRIPT, _undefined, t)
  315. }