OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // Flags: --harmony-arrays --harmony-classes | |
6 | |
7 (function testArrayConcatArity() { | |
8 "use strict"; | |
9 assertEquals(1, Array.prototype.concat.length); | |
10 })(); | |
11 | |
12 | |
13 (function testArrayConcatNoPrototype() { | |
14 "use strict"; | |
15 assertEquals(void 0, Array.prototype.concat.prototype); | |
16 })(); | |
17 | |
18 | |
19 (function testArrayConcatDescriptor() { | |
20 "use strict"; | |
21 var desc = Object.getOwnPropertyDescriptor(Array.prototype, 'concat'); | |
22 assertEquals(false, desc.enumerable); | |
23 })(); | |
24 | |
25 | |
26 (function testConcatArrayLike() { | |
27 "use strict"; | |
28 var obj = { | |
29 "length": 6, | |
30 "1": "A", | |
31 "3": "B", | |
32 "5": "C" | |
33 }; | |
34 obj[Symbol.isConcatSpreadable] = true; | |
35 var obj2 = { length: 3, "0": "0", "1": "1", "2": "2" }; | |
36 var arr = ["X", "Y", "Z"]; | |
37 assertEquals([void 0, "A", void 0, "B", void 0, "C", | |
38 { "length": 3, "0": "0", "1": "1", "2": "2" }, | |
39 "X", "Y", "Z"], Array.prototype.concat.call(obj, obj2, arr)); | |
40 })(); | |
41 | |
42 | |
43 (function testConcatHoleyArray() { | |
44 "use strict"; | |
45 var arr = []; | |
46 arr[4] = "Item 4"; | |
47 arr[8] = "Item 8"; | |
48 var arr2 = [".", "!", "?"]; | |
49 assertEquals([void 0, void 0, void 0, void 0, "Item 4", void 0, void 0, | |
50 void 0, "Item 8", ".", "!", "?"], arr.concat(arr2)); | |
51 })(); | |
52 | |
53 | |
54 (function testIsConcatSpreadableGetterThrows() { | |
55 "use strict"; | |
56 function MyError() {} | |
57 var obj = {}; | |
58 Object.defineProperty(obj, Symbol.isConcatSpreadable, { | |
59 get: function() { throw new MyError(); } | |
60 }); | |
61 | |
62 assertThrows(function() { | |
63 [].concat(obj); | |
64 }, MyError); | |
65 | |
66 assertThrows(function() { | |
67 Array.prototype.concat.call(obj, 1, 2, 3); | |
68 }, MyError); | |
69 })(); | |
70 | |
71 | |
72 (function testConcatLengthThrows() { | |
73 "use strict"; | |
74 function MyError() {} | |
75 var obj = {}; | |
76 obj[Symbol.isConcatSpreadable] = true; | |
77 Object.defineProperty(obj, "length", { | |
78 get: function() { throw new MyError(); } | |
79 }); | |
80 | |
81 assertThrows(function() { | |
82 [].concat(obj); | |
83 }, MyError); | |
84 | |
85 assertThrows(function() { | |
86 Array.prototype.concat.call(obj, 1, 2, 3); | |
87 }, MyError); | |
88 })(); | |
89 | |
90 | |
91 (function testConcatArraySubclass() { | |
92 "use strict"; | |
93 // TODO(caitp): when concat is called on instances of classes which extend | |
94 // Array, they should: | |
95 // | |
96 // - return an instance of the class, rather than an Array instance (if from | |
97 // same Realm) | |
98 // - always treat such classes as concat-spreadable | |
99 })(); | |
100 | |
101 | |
102 (function testConcatNonArray() { | |
103 "use strict"; | |
104 class NonArray { | |
105 constructor() { Array.apply(this, arguments); } | |
106 }; | |
107 | |
108 var obj = new NonArray(1,2,3); | |
109 var result = Array.prototype.concat.call(obj, 4, 5, 6); | |
110 assertEquals(Array, result.constructor); | |
111 assertEquals([obj,4,5,6], result); | |
112 assertFalse(result instanceof NonArray); | |
113 })(); | |
114 | |
115 | |
116 function testConcatTypedArray(type, elems, modulo) { | |
117 "use strict"; | |
118 var items = new Array(elems); | |
119 for (var i = 0; i < elems; ++i) { | |
120 items[i] = modulo === false ? i : elems % modulo; | |
121 } | |
122 var ta = new type(items); | |
Dmitry Lomov (no reviews)
2014/12/11 15:11:29
The reason why you are not hitting UINT8_ELEMENTS
caitp (gmail)
2014/12/11 16:33:09
In order to use Fixed<Type>Array, the length needs
| |
123 assertEquals([ta, ta], [].concat(ta, ta)); | |
124 ta[Symbol.isConcatSpreadable] = true; | |
125 assertEquals(items, [].concat(ta)); | |
126 } | |
127 | |
128 (function testConcatSmallTypedArray() { | |
129 var max = [2^8, 2^16, 2^32, false, false]; | |
130 [ | |
131 Uint8Array, | |
132 Uint16Array, | |
133 Uint32Array, | |
134 Float32Array, | |
135 Float64Array | |
136 ].forEach(function(ctor, i) { | |
137 testConcatTypedArray(ctor, 2, max[i]); | |
138 }); | |
139 })(); | |
140 | |
141 | |
142 (function testConcatLargeTypedArray() { | |
143 var max = [2^8, 2^16, 2^32, false, false]; | |
144 [ | |
145 Uint8Array, | |
146 Uint16Array, | |
147 Uint32Array, | |
148 Float32Array, | |
149 Float64Array | |
150 ].forEach(function(ctor, i) { | |
151 testConcatTypedArray(ctor, 4000, max[i]); | |
152 }); | |
153 })(); | |
154 | |
155 | |
156 (function testConcatStrictArguments() { | |
157 var args = (function(a, b, c) { "use strict"; return arguments; })(1,2,3); | |
158 args[Symbol.isConcatSpreadable] = true; | |
159 assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args)); | |
160 })(); | |
161 | |
162 | |
163 (function testConcatSloppyArguments() { | |
164 var args = (function(a, b, c) { return arguments; })(1,2,3); | |
165 args[Symbol.isConcatSpreadable] = true; | |
166 assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args)); | |
167 })(); | |
168 | |
169 | |
170 (function testConcatSloppyArgumentsWithDupes() { | |
171 var args = (function(a, a, a) { return arguments; })(1,2,3); | |
172 args[Symbol.isConcatSpreadable] = true; | |
173 assertEquals([1, 2, 3, 1, 2, 3], [].concat(args, args)); | |
174 })(); | |
175 | |
176 | |
177 (function testConcatSloppyArgumentsThrows() { | |
178 function MyError() {} | |
179 var args = (function(a) { return arguments; })(1,2,3); | |
180 Object.defineProperty(args, 0, { | |
181 get: function() { throw new MyError(); } | |
182 }); | |
183 args[Symbol.isConcatSpreadable] = true; | |
184 assertThrows(function() { | |
185 return [].concat(args, args); | |
186 }, MyError); | |
187 })(); | |
188 | |
189 | |
190 (function testConcatHoleySloppyArguments() { | |
191 var args = (function(a) { return arguments; })(1,2,3); | |
192 delete args[1]; | |
193 args[Symbol.isConcatSpreadable] = true; | |
194 assertEquals([1, void 0, 3, 1, void 0, 3], [].concat(args, args)); | |
195 })(); | |
196 | |
197 | |
198 // ES5 tests | |
199 (function testArrayConcatES5() { | |
200 "use strict"; | |
201 var poses; | |
202 var pos; | |
203 | |
204 poses = [140, 4000000000]; | |
205 while (pos = poses.shift()) { | |
206 var a = new Array(pos); | |
207 var array_proto = []; | |
208 a.__proto__ = array_proto; | |
209 assertEquals(pos, a.length); | |
210 a.push('foo'); | |
211 assertEquals(pos + 1, a.length); | |
212 var b = ['bar']; | |
213 var c = a.concat(b); | |
214 assertEquals(pos + 2, c.length); | |
215 assertEquals("undefined", typeof(c[pos - 1])); | |
216 assertEquals("foo", c[pos]); | |
217 assertEquals("bar", c[pos + 1]); | |
218 | |
219 // Can we fool the system by putting a number in a string? | |
220 var onetwofour = "124"; | |
221 a[onetwofour] = 'doo'; | |
222 assertEquals(a[124], 'doo'); | |
223 c = a.concat(b); | |
224 assertEquals(c[124], 'doo'); | |
225 | |
226 // If we put a number in the prototype, then the spec says it should be | |
227 // copied on concat. | |
228 array_proto["123"] = 'baz'; | |
229 assertEquals(a[123], 'baz'); | |
230 | |
231 c = a.concat(b); | |
232 assertEquals(pos + 2, c.length); | |
233 assertEquals("baz", c[123]); | |
234 assertEquals("undefined", typeof(c[pos - 1])); | |
235 assertEquals("foo", c[pos]); | |
236 assertEquals("bar", c[pos + 1]); | |
237 | |
238 // When we take the number off the prototype it disappears from a, but | |
239 // the concat put it in c itself. | |
240 array_proto["123"] = undefined; | |
241 assertEquals("undefined", typeof(a[123])); | |
242 assertEquals("baz", c[123]); | |
243 | |
244 // If the element of prototype is shadowed, the element on the instance | |
245 // should be copied, but not the one on the prototype. | |
246 array_proto[123] = 'baz'; | |
247 a[123] = 'xyz'; | |
248 assertEquals('xyz', a[123]); | |
249 c = a.concat(b); | |
250 assertEquals('xyz', c[123]); | |
251 | |
252 // Non-numeric properties on the prototype or the array shouldn't get | |
253 // copied. | |
254 array_proto.moe = 'joe'; | |
255 a.ben = 'jerry'; | |
256 assertEquals(a["moe"], 'joe'); | |
257 assertEquals(a["ben"], 'jerry'); | |
258 c = a.concat(b); | |
259 // ben was not copied | |
260 assertEquals("undefined", typeof(c.ben)); | |
261 | |
262 // When we take moe off the prototype it disappears from all arrays. | |
263 array_proto.moe = undefined; | |
264 assertEquals("undefined", typeof(c.moe)); | |
265 | |
266 // Negative indices don't get concated. | |
267 a[-1] = 'minus1'; | |
268 assertEquals("minus1", a[-1]); | |
269 assertEquals("undefined", typeof(a[0xffffffff])); | |
270 c = a.concat(b); | |
271 assertEquals("undefined", typeof(c[-1])); | |
272 assertEquals("undefined", typeof(c[0xffffffff])); | |
273 assertEquals(c.length, a.length + 1); | |
274 } | |
275 | |
276 poses = [140, 4000000000]; | |
277 while (pos = poses.shift()) { | |
278 var a = new Array(pos); | |
279 assertEquals(pos, a.length); | |
280 a.push('foo'); | |
281 assertEquals(pos + 1, a.length); | |
282 var b = ['bar']; | |
283 var c = a.concat(b); | |
284 assertEquals(pos + 2, c.length); | |
285 assertEquals("undefined", typeof(c[pos - 1])); | |
286 assertEquals("foo", c[pos]); | |
287 assertEquals("bar", c[pos + 1]); | |
288 | |
289 // Can we fool the system by putting a number in a string? | |
290 var onetwofour = "124"; | |
291 a[onetwofour] = 'doo'; | |
292 assertEquals(a[124], 'doo'); | |
293 c = a.concat(b); | |
294 assertEquals(c[124], 'doo'); | |
295 | |
296 // If we put a number in the prototype, then the spec says it should be | |
297 // copied on concat. | |
298 Array.prototype["123"] = 'baz'; | |
299 assertEquals(a[123], 'baz'); | |
300 | |
301 c = a.concat(b); | |
302 assertEquals(pos + 2, c.length); | |
303 assertEquals("baz", c[123]); | |
304 assertEquals("undefined", typeof(c[pos - 1])); | |
305 assertEquals("foo", c[pos]); | |
306 assertEquals("bar", c[pos + 1]); | |
307 | |
308 // When we take the number off the prototype it disappears from a, but | |
309 // the concat put it in c itself. | |
310 Array.prototype["123"] = undefined; | |
311 assertEquals("undefined", typeof(a[123])); | |
312 assertEquals("baz", c[123]); | |
313 | |
314 // If the element of prototype is shadowed, the element on the instance | |
315 // should be copied, but not the one on the prototype. | |
316 Array.prototype[123] = 'baz'; | |
317 a[123] = 'xyz'; | |
318 assertEquals('xyz', a[123]); | |
319 c = a.concat(b); | |
320 assertEquals('xyz', c[123]); | |
321 | |
322 // Non-numeric properties on the prototype or the array shouldn't get | |
323 // copied. | |
324 Array.prototype.moe = 'joe'; | |
325 a.ben = 'jerry'; | |
326 assertEquals(a["moe"], 'joe'); | |
327 assertEquals(a["ben"], 'jerry'); | |
328 c = a.concat(b); | |
329 // ben was not copied | |
330 assertEquals("undefined", typeof(c.ben)); | |
331 // moe was not copied, but we can see it through the prototype | |
332 assertEquals("joe", c.moe); | |
333 | |
334 // When we take moe off the prototype it disappears from all arrays. | |
335 Array.prototype.moe = undefined; | |
336 assertEquals("undefined", typeof(c.moe)); | |
337 | |
338 // Negative indices don't get concated. | |
339 a[-1] = 'minus1'; | |
340 assertEquals("minus1", a[-1]); | |
341 assertEquals("undefined", typeof(a[0xffffffff])); | |
342 c = a.concat(b); | |
343 assertEquals("undefined", typeof(c[-1])); | |
344 assertEquals("undefined", typeof(c[0xffffffff])); | |
345 assertEquals(c.length, a.length + 1); | |
346 | |
347 } | |
348 | |
349 a = []; | |
350 c = a.concat('Hello'); | |
351 assertEquals(1, c.length); | |
352 assertEquals("Hello", c[0]); | |
353 assertEquals("Hello", c.toString()); | |
354 | |
355 // Check that concat preserves holes. | |
356 var holey = [void 0,'a',,'c'].concat(['d',,'f',[0,,2],void 0]) | |
357 assertEquals(9, holey.length); // hole in embedded array is ignored | |
358 for (var i = 0; i < holey.length; i++) { | |
359 if (i == 2 || i == 5) { | |
360 assertFalse(i in holey); | |
361 } else { | |
362 assertTrue(i in holey); | |
363 } | |
364 } | |
365 | |
366 // Polluted prototype from prior tests. | |
367 delete Array.prototype[123]; | |
368 | |
369 // Check that concat reads getters in the correct order. | |
370 var arr1 = [,2]; | |
371 var arr2 = [1,3]; | |
372 var r1 = [].concat(arr1, arr2); // [,2,1,3] | |
373 assertEquals([,2,1,3], r1); | |
374 | |
375 // Make first array change length of second array. | |
376 Object.defineProperty(arr1, 0, {get: function() { | |
377 arr2.push("X"); | |
378 return undefined; | |
379 }, configurable: true}) | |
380 var r2 = [].concat(arr1, arr2); // [undefined,2,1,3,"X"] | |
381 assertEquals([undefined,2,1,3,"X"], r2); | |
382 | |
383 // Make first array change length of second array massively. | |
384 arr2.length = 2; | |
385 Object.defineProperty(arr1, 0, {get: function() { | |
386 arr2[500000] = "X"; | |
387 return undefined; | |
388 }, configurable: true}) | |
389 var r3 = [].concat(arr1, arr2); // [undefined,2,1,3,"X"] | |
390 var expected = [undefined,2,1,3]; | |
391 expected[500000 + 2] = "X"; | |
392 | |
393 assertEquals(expected, r3); | |
394 | |
395 var arr3 = []; | |
396 var trace = []; | |
397 var expectedTrace = [] | |
398 function mkGetter(i) { return function() { trace.push(i); }; } | |
399 arr3.length = 10000; | |
400 for (var i = 0; i < 100; i++) { | |
401 Object.defineProperty(arr3, i * i, {get: mkGetter(i)}); | |
402 expectedTrace[i] = i; | |
403 expectedTrace[100 + i] = i; | |
404 } | |
405 var r4 = [0].concat(arr3, arr3); | |
406 assertEquals(1 + arr3.length * 2, r4.length); | |
407 assertEquals(expectedTrace, trace); | |
408 })(); | |
OLD | NEW |