blob: a2c1410837c256553b9d9d0bf0e6f2e848162d05 [file] [log] [blame]
Andrei Popescu402d9372010-02-26 13:31:12 +00001// Copyright 2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28/**
29 * @fileoverview Test splice, shift, unshift, slice and join on small
30 * and large arrays. Some of these methods are specified such that they
31 * should work on other objects too, so we test that too.
32 */
33
Ben Murdochb8a8cc12014-11-26 15:28:44 +000034var LARGE = 4000000;
Andrei Popescu402d9372010-02-26 13:31:12 +000035var VERYLARGE = 4000000000;
36
37// Nicer for firefox 1.5. Unless you uncomment the following two lines,
38// smjs will appear to hang on this file.
39//var LARGE = 40000;
40//var VERYLARGE = 40000;
41
42var fourhundredth = LARGE/400;
43
44function PseudoArray() {
45};
46
47for (var use_real_arrays = 0; use_real_arrays <= 1; use_real_arrays++) {
48 var poses = [0, 140, 20000, VERYLARGE];
49 var the_prototype;
50 var new_function;
51 var push_function;
52 var concat_function;
53 var slice_function;
54 var splice_function;
55 var splice_function_2;
56 var unshift_function;
57 var unshift_function_2;
58 var shift_function;
59 if (use_real_arrays) {
60 new_function = function(length) {
61 return new Array(length);
62 };
63 the_prototype = Array.prototype;
64 push_function = function(array, elt) {
65 return array.push(elt);
66 };
67 concat_function = function(array, other) {
68 return array.concat(other);
69 };
70 slice_function = function(array, start, len) {
71 return array.slice(start, len);
72 };
73 splice_function = function(array, start, len) {
74 return array.splice(start, len);
75 };
76 splice_function_2 = function(array, start, len, elt) {
77 return array.splice(start, len, elt);
78 };
79 unshift_function = function(array, elt) {
80 return array.unshift(elt);
81 };
82 unshift_function_2 = function(array, elt1, elt2) {
83 return array.unshift(elt1, elt2);
84 };
85 shift_function = function(array) {
86 return array.shift();
87 };
88 } else {
89 // Don't run largest size on non-arrays or we'll be here for ever.
90 poses.pop();
91 new_function = function(length) {
92 var obj = new PseudoArray();
93 obj.length = length;
94 return obj;
95 };
96 the_prototype = PseudoArray.prototype;
97 push_function = function(array, elt) {
98 array[array.length] = elt;
99 array.length++;
100 };
101 concat_function = function(array, other) {
102 return Array.prototype.concat.call(array, other);
103 };
104 slice_function = function(array, start, len) {
105 return Array.prototype.slice.call(array, start, len);
106 };
107 splice_function = function(array, start, len) {
108 return Array.prototype.splice.call(array, start, len);
109 };
110 splice_function_2 = function(array, start, len, elt) {
111 return Array.prototype.splice.call(array, start, len, elt);
112 };
113 unshift_function = function(array, elt) {
114 return Array.prototype.unshift.call(array, elt);
115 };
116 unshift_function_2 = function(array, elt1, elt2) {
117 return Array.prototype.unshift.call(array, elt1, elt2);
118 };
119 shift_function = function(array) {
120 return Array.prototype.shift.call(array);
121 };
122 }
123
124 for (var pos_pos = 0; pos_pos < poses.length; pos_pos++) {
125 var pos = poses[pos_pos];
126 if (pos > 100) {
127 var a = new_function(pos);
128 assertEquals(pos, a.length);
129 push_function(a, 'foo');
130 assertEquals(pos + 1, a.length);
131 var b = ['bar'];
132 // Delete a huge number of holes.
133 var c = splice_function(a, 10, pos - 20);
134 assertEquals(pos - 20, c.length);
135 assertEquals(21, a.length);
136 }
137
138 // Add a numeric property to the prototype of the array class. This
139 // allows us to test some borderline stuff relative to the standard.
140 the_prototype["" + (pos + 1)] = 'baz';
141
142 if (use_real_arrays) {
143 // It seems quite clear from ECMAScript spec 15.4.4.5. Just call Get on
144 // every integer in the range.
145 // IE, Safari get this right.
146 // FF, Opera get this wrong.
147 var a = ['zero', ,'two'];
148 if (pos == 0) {
149 assertEquals("zero,baz,two", a.join(","));
150 }
151
152 // Concat only applies to real arrays, unlike most of the other methods.
153 var a = new_function(pos);
154 push_function(a, "con");
155 assertEquals("con", a[pos]);
156 assertEquals(pos + 1, a.length);
157 var b = new_function(0);
158 push_function(b, "cat");
159 assertEquals("cat", b[0]);
160 var ab = concat_function(a, b);
161 assertEquals("con", ab[pos]);
162 assertEquals(pos + 2, ab.length);
163 assertEquals("cat", ab[pos + 1]);
164 var ba = concat_function(b, a);
165 assertEquals("con", ba[pos + 1]);
166 assertEquals(pos + 2, ba.length);
167 assertEquals("cat", ba[0]);
168
169 // Join with '' as separator.
170 var join = a.join('');
171 assertEquals("con", join);
172 join = b.join('');
173 assertEquals("cat", join);
174 join = ab.join('');
175 assertEquals("concat", join);
176 join = ba.join('');
177 assertEquals("catcon", join);
178
179 var sparse = [];
180 sparse[pos + 1000] = 'is ';
181 sparse[pos + 271828] = 'time ';
182 sparse[pos + 31415] = 'the ';
183 sparse[pos + 012260199] = 'all ';
184 sparse[-1] = 'foo';
185 sparse[pos + 22591927] = 'good ';
186 sparse[pos + 1618033] = 'for ';
187 sparse[pos + 91] = ': Now ';
188 sparse[pos + 86720199] = 'men.';
189 sparse.hest = 'fisk';
190
191 assertEquals("baz: Now is the time for all good men.", sparse.join(''));
192 }
193
194 a = new_function(pos);
195 push_function(a, 'zero');
196 push_function(a, void 0);
197 push_function(a, 'two');
198
199 // Splice works differently from join.
200 // IE, Safari get this wrong.
201 // FF, Opera get this right.
202 // 15.4.4.12 line 24 says the object itself has to have the property...
203 var zero = splice_function(a, pos, 1);
204 assertEquals("undefined", typeof(a[pos]));
205 assertEquals("two", a[pos+1], "pos1:" + pos);
206 assertEquals(pos + 2, a.length, "a length");
207 assertEquals(1, zero.length, "zero length");
208 assertEquals("zero", zero[0]);
209
210 // 15.4.4.12 line 41 says the object itself has to have the property...
211 a = new_function(pos);
212 push_function(a, 'zero');
213 push_function(a, void 0);
214 push_function(a, 'two');
215 var nothing = splice_function_2(a, pos, 0, 'minus1');
216 assertEquals("minus1", a[pos]);
217 assertEquals("zero", a[pos+1]);
218 assertEquals("undefined", typeof(a[pos+2]), "toot!");
219 assertEquals("two", a[pos+3], "pos3");
220 assertEquals(pos + 4, a.length);
221 assertEquals(1, zero.length);
222 assertEquals("zero", zero[0]);
223
224 // 15.4.4.12 line 10 says the object itself has to have the property...
225 a = new_function(pos);
226 push_function(a, 'zero');
227 push_function(a, void 0);
228 push_function(a, 'two');
229 var one = splice_function(a, pos + 1, 1);
230 assertEquals("", one.join(","));
231 assertEquals(pos + 2, a.length);
232 assertEquals("zero", a[pos]);
233 assertEquals("two", a[pos+1]);
234
235 // Set things back to the way they were.
236 the_prototype[pos + 1] = undefined;
237
238 // Unshift.
239 var a = new_function(pos);
240 push_function(a, "foo");
241 assertEquals("foo", a[pos]);
242 assertEquals(pos + 1, a.length);
243 unshift_function(a, "bar");
244 assertEquals("foo", a[pos+1]);
245 assertEquals(pos + 2, a.length);
246 assertEquals("bar", a[0]);
247 unshift_function_2(a, "baz", "boo");
248 assertEquals("foo", a[pos+3]);
249 assertEquals(pos + 4, a.length);
250 assertEquals("baz", a[0]);
251 assertEquals("boo", a[1]);
252 assertEquals("bar", a[2]);
253
254 // Shift.
255 var baz = shift_function(a);
256 assertEquals("baz", baz);
257 assertEquals("boo", a[0]);
258 assertEquals(pos + 3, a.length);
259 assertEquals("foo", a[pos + 2]);
260
261 // Slice.
262 var bar = slice_function(a, 1, 0); // don't throw an exception please.
263 bar = slice_function(a, 1, 2);
264 assertEquals("bar", bar[0]);
265 assertEquals(1, bar.length);
266 assertEquals("bar", a[1]);
267
268 }
269}
270
271// Lets see if performance is reasonable.
272
273var a = new Array(LARGE + 10);
274for (var i = 0; i < a.length; i += 1000) {
275 a[i] = i;
276}
277
278// Take something near the end of the array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000279for (var i = 0; i < 10; i++) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000280 var top = a.splice(LARGE, 5);
281 assertEquals(5, top.length);
282 assertEquals(LARGE, top[0]);
283 assertEquals("undefined", typeof(top[1]));
284 assertEquals(LARGE + 5, a.length);
285 a.splice(LARGE, 0, LARGE);
286 a.length = LARGE + 10;
287}
288
289var a = new Array(LARGE + 10);
290for (var i = 0; i < a.length; i += fourhundredth) {
291 a[i] = i;
292}
293
294// Take something near the middle of the array.
295for (var i = 0; i < 10; i++) {
296 var top = a.splice(LARGE >> 1, 5);
297 assertEquals(5, top.length);
298 assertEquals(LARGE >> 1, top[0]);
299 assertEquals("undefined", typeof(top[1]));
300 assertEquals(LARGE + 5, a.length);
301 a.splice(LARGE >> 1, 0, LARGE >> 1, void 0, void 0, void 0, void 0);
302}
303
304
305// Test http://b/issue?id=1202711
306arr = [0];
307arr.length = 2;
308Array.prototype[1] = 1;
309assertEquals(1, arr.pop());
310assertEquals(0, arr.pop());
311Array.prototype[1] = undefined;
312
313// Test http://code.google.com/p/chromium/issues/detail?id=21860
314Array.prototype.push.apply([], [1].splice(0, -(-1 % 5)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000315
316
317// Check that the Array functions work also properly on non-Arrays
318var receiver;
319
320receiver = 'a string';
321assertThrows(function(){
322 Array.prototype.push.call(receiver);
323});
324
325receiver = 0;
326assertEquals(undefined, receiver.length);
327assertEquals(0, Array.prototype.push.call(receiver));
328assertEquals(1, Array.prototype.push.call(receiver, 'first'));
329assertEquals(undefined, receiver.length);
330
331receiver = {};
332assertEquals(undefined, receiver.length);
333assertEquals(0, Array.prototype.push.call(receiver));
334assertEquals(0, Array.prototype.push.call(receiver));
335assertEquals(0, receiver.length);
336assertEquals(1, Array.prototype.push.call(receiver, 'first'));
337assertEquals(1, receiver.length);
338assertEquals('first', receiver[0]);
339assertEquals(2, Array.prototype.push.call(receiver, 'second'));
340assertEquals(2, receiver.length);
341assertEquals('first', receiver[0]);
342assertEquals('second', receiver[1]);
343
344receiver = {'length': 10};
345assertEquals(10, Array.prototype.push.call(receiver));
346assertEquals(10, receiver.length);
347assertEquals(11, Array.prototype.push.call(receiver, 'first'));
348assertEquals(11, receiver.length);
349assertEquals('first', receiver[10]);
350assertEquals(13, Array.prototype.push.call(receiver, 'second', 'third'));
351assertEquals(13, receiver.length);
352assertEquals('first', receiver[10]);
353assertEquals('second', receiver[11]);
354assertEquals('third', receiver[12]);
355
356receiver = {
357 get length() { return 10; },
358 set length(l) {}
359};
360assertEquals(10, Array.prototype.push.call(receiver));
361assertEquals(10, receiver.length);
362assertEquals(11, Array.prototype.push.call(receiver, 'first'));
363assertEquals(10, receiver.length);
364assertEquals('first', receiver[10]);
365assertEquals(12, Array.prototype.push.call(receiver, 'second', 'third'));
366assertEquals(10, receiver.length);
367assertEquals('second', receiver[10]);
368assertEquals('third', receiver[11]);
369
370// readonly length
371receiver = {
372 get length() { return 10; },
373};
374assertThrows(function(){
375 Array.prototype.push.call(receiver);
376});
377
378receiver = {
379 set length(l) {}
380};
381assertEquals(0, Array.prototype.push.call(receiver));
382assertEquals(undefined, receiver.length);
383assertEquals(1, Array.prototype.push.call(receiver, 'first'));
384assertEquals(undefined, receiver.length);
385assertEquals(2, Array.prototype.push.call(receiver, 'third', 'second'));
386assertEquals(undefined, receiver.length);