builtin_arrray_test.go 7.9 KB

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