Home | History | Annotate | Download | only in mjsunit
      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