array-splice.js revision 402d937239b0e2fd11bf2f4fe972ad78aa9fd481
1// Copyright 2010 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// Check that splicing array of holes keeps it as array of holes
29(function() {
30  for (var i = 0; i < 7; i++) {
31    var array = new Array(10);
32    var spliced = array.splice(1, 1, 'one', 'two');
33    assertEquals(1, spliced.length);
34    assertFalse(0 in spliced);
35
36    assertEquals(11, array.length);
37    assertFalse(0 in array);
38    assertTrue(1 in array);
39    assertTrue(2 in array);
40    assertFalse(3 in array);
41  }
42})();
43
44
45// Check various forms of arguments omission.
46(function() {
47  var array;
48  for (var i = 0; i < 7; i++) {
49    // SpiderMonkey and JSC return undefined in the case where no
50    // arguments are given instead of using the implicit undefined
51    // arguments.  This does not follow ECMA-262, but we do the same for
52    // compatibility.
53    // TraceMonkey follows ECMA-262 though.
54    array = [1, 2, 3]
55    assertEquals(undefined, array.splice());
56    assertEquals([1, 2, 3], array);
57
58    // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
59    // given differently from when an undefined delete count is given.
60    // This does not follow ECMA-262, but we do the same for
61    // compatibility.
62    array = [1, 2, 3]
63    assertEquals([1, 2, 3], array.splice(0));
64    assertEquals([], array);
65
66    array = [1, 2, 3]
67    assertEquals([1, 2, 3], array.splice(undefined));
68    assertEquals([], array);
69
70    array = [1, 2, 3]
71    assertEquals([1, 2, 3], array.splice("foobar"));
72    assertEquals([], array);
73
74    array = [1, 2, 3]
75    assertEquals([], array.splice(undefined, undefined));
76    assertEquals([1, 2, 3], array);
77
78    array = [1, 2, 3]
79    assertEquals([], array.splice("foobar", undefined));
80    assertEquals([1, 2, 3], array);
81
82    array = [1, 2, 3]
83    assertEquals([], array.splice(undefined, "foobar"));
84    assertEquals([1, 2, 3], array);
85
86    array = [1, 2, 3]
87    assertEquals([], array.splice("foobar", "foobar"));
88    assertEquals([1, 2, 3], array);
89  }
90})();
91
92
93// Check variants of negatives and positive indices.
94(function() {
95  var array, spliced;
96  for (var i = 0; i < 7; i++) {
97    array = [1, 2, 3, 4, 5, 6, 7];
98    spliced = array.splice(-100);
99    assertEquals([], array);
100    assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
101
102    array = [1, 2, 3, 4, 5, 6, 7];
103    spliced = array.splice(-3);
104    assertEquals([1, 2, 3, 4], array);
105    assertEquals([5, 6, 7], spliced);
106
107    array = [1, 2, 3, 4, 5, 6, 7];
108    spliced = array.splice(4);
109    assertEquals([1, 2, 3, 4], array);
110    assertEquals([5, 6, 7], spliced);
111
112    array = [1, 2, 3, 4, 5, 6, 7];
113    spliced = array.splice(6);
114    assertEquals([1, 2, 3, 4, 5, 6], array);
115    assertEquals([7], spliced);
116
117    array = [1, 2, 3, 4, 5, 6, 7];
118    spliced = array.splice(7);
119    assertEquals([1, 2, 3, 4, 5, 6, 7], array);
120    assertEquals([], spliced);
121
122    array = [1, 2, 3, 4, 5, 6, 7];
123    spliced = array.splice(8);
124    assertEquals([1, 2, 3, 4, 5, 6, 7], array);
125    assertEquals([], spliced);
126
127    array = [1, 2, 3, 4, 5, 6, 7];
128    spliced = array.splice(100);
129    assertEquals([1, 2, 3, 4, 5, 6, 7], array);
130    assertEquals([], spliced);
131
132    array = [1, 2, 3, 4, 5, 6, 7];
133    spliced = array.splice(0, -100);
134    assertEquals([1, 2, 3, 4, 5, 6, 7], array);
135    assertEquals([], spliced);
136
137    array = [1, 2, 3, 4, 5, 6, 7];
138    spliced = array.splice(0, -3);
139    assertEquals([1, 2, 3, 4, 5, 6, 7], array);
140    assertEquals([], spliced);
141
142    array = [1, 2, 3, 4, 5, 6, 7];
143    spliced = array.splice(0, 4);
144    assertEquals([5, 6, 7], array);
145    assertEquals([1, 2, 3, 4], spliced);
146
147    array = [1, 2, 3, 4, 5, 6, 7];
148    spliced = array.splice(0, 6);
149    assertEquals([7], array);
150    assertEquals([1, 2, 3, 4, 5, 6], spliced);
151
152    array = [1, 2, 3, 4, 5, 6, 7];
153    spliced = array.splice(0, 7);
154    assertEquals([], array);
155    assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
156
157    array = [1, 2, 3, 4, 5, 6, 7];
158    spliced = array.splice(0, 8);
159    assertEquals([], array);
160    assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
161
162    array = [1, 2, 3, 4, 5, 6, 7];
163    spliced = array.splice(0, 100);
164    assertEquals([], array);
165    assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
166
167    // Some exotic cases.
168    obj = { toString: function() { throw 'Exception'; } };
169
170    // Throwing an exception in conversion:
171    try {
172      [1, 2, 3].splice(obj, 3);
173      throw 'Should have thrown';
174    } catch (e) {
175      assertEquals('Exception', e);
176    }
177
178    try {
179      [1, 2, 3].splice(0, obj, 3);
180      throw 'Should have thrown';
181    } catch (e) {
182      assertEquals('Exception', e);
183    }
184
185    array = [1, 2, 3];
186    array.splice(0, 3, obj);
187    assertEquals(1, array.length);
188
189    // Custom conversion:
190    array = [1, 2, 3];
191    spliced = array.splice({valueOf: function() { return 1; }},
192                           {toString: function() { return 2; }},
193                           'one', 'two');
194    assertEquals([2, 3], spliced);
195    assertEquals([1, 'one', 'two'], array);
196  }
197})();
198
199
200// Nasty: modify the array in ToInteger.
201(function() {
202  var array = [];
203  var spliced;
204
205  for (var i = 0; i < 13; i++) {
206    bad_start = { valueOf: function() { array.push(2*i); return -1; } };
207    bad_count = { valueOf: function() { array.push(2*i + 1); return 1; } };
208    spliced = array.splice(bad_start, bad_count);
209    // According to the spec (15.4.4.12), length is calculated before
210    // performing ToInteger on arguments.  However, v8 ignores elements
211    // we add while converting, so we need corrective pushes.
212    array.push(2*i); array.push(2*i + 1);
213    if (i == 0) {
214      assertEquals([], spliced);  // Length was 0, nothing to get.
215      assertEquals([0, 1], array);
216    } else {
217      // When we start splice, array is [0 .. 2*i - 1], so we get
218      // as a result [2*i], this element is removed from the array,
219      // but [2 * i, 2 * i + 1] are added.
220      assertEquals([2 * i - 1], spliced);
221      assertEquals(2 * i, array[i]);
222      assertEquals(2 * i + 1, array[i + 1]);
223    }
224  }
225})();
226
227
228// Now check the case with array of holes and some elements on prototype.
229(function() {
230  var len = 9;
231
232  var at3 = "@3";
233  var at7 = "@7";
234
235  for (var i = 0; i < 7; i++) {
236    var array = new Array(len);
237    Array.prototype[3] = at3;
238    Array.prototype[7] = at7;
239
240    var spliced = array.splice(2, 2, 'one', undefined, 'two');
241
242    // Second hole (at index 3) of array turns into
243    // value of Array.prototype[3] while copying.
244    assertEquals([, at3], spliced);
245    assertEquals([, , 'one', undefined, 'two', , , at7, at7, ,], array);
246
247    // ... but array[7] is actually a hole:
248    assertTrue(delete Array.prototype[7]);
249    assertEquals(undefined, array[7]);
250
251    // and now check hasOwnProperty
252    assertFalse(array.hasOwnProperty(0));
253    assertFalse(array.hasOwnProperty(1));
254    assertTrue(array.hasOwnProperty(2));
255    assertTrue(array.hasOwnProperty(3));
256    assertTrue(array.hasOwnProperty(4));
257    assertFalse(array.hasOwnProperty(5));
258    assertFalse(array.hasOwnProperty(6));
259    assertFalse(array.hasOwnProperty(7));
260    assertTrue(array.hasOwnProperty(8));
261    assertFalse(array.hasOwnProperty(9));
262
263    // and now check couple of indices above length.
264    assertFalse(array.hasOwnProperty(10));
265    assertFalse(array.hasOwnProperty(15));
266    assertFalse(array.hasOwnProperty(31));
267    assertFalse(array.hasOwnProperty(63));
268    assertFalse(array.hasOwnProperty(2 << 32 - 1));
269  }
270})();
271
272
273// Check the behaviour when approaching maximal values for length.
274(function() {
275  for (var i = 0; i < 7; i++) {
276    try {
277      new Array((1 << 32) - 3).splice(-1, 0, 1, 2, 3, 4, 5);
278      throw 'Should have thrown RangeError';
279    } catch (e) {
280      assertTrue(e instanceof RangeError);
281    }
282
283    // Check smi boundary
284    var bigNum = (1 << 30) - 3;
285    var array = new Array(bigNum);
286    array.splice(-1, 0, 1, 2, 3, 4, 5, 6, 7);
287    assertEquals(bigNum + 7, array.length);
288  }
289})();
290