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