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 slicing array of holes keeps it as array of holes
     29 (function() {
     30   var array = new Array(10);
     31   for (var i = 0; i < 7; i++) {
     32     var sliced = array.slice();
     33     assertEquals(array.length, sliced.length);
     34     assertFalse(0 in sliced);
     35   }
     36 })();
     37 
     38 
     39 // Check various variants of empty array's slicing.
     40 (function() {
     41   for (var i = 0; i < 7; i++) {
     42     assertEquals([], [].slice(0, 0));
     43     assertEquals([], [].slice(1, 0));
     44     assertEquals([], [].slice(0, 1));
     45     assertEquals([], [].slice(-1, 0));
     46   }
     47 })();
     48 
     49 
     50 // Check various forms of arguments omission.
     51 (function() {
     52   var array = new Array(7);
     53 
     54   for (var i = 0; i < 7; i++) {
     55     assertEquals(array, array.slice());
     56     assertEquals(array, array.slice(0));
     57     assertEquals(array, array.slice(undefined));
     58     assertEquals(array, array.slice("foobar"));
     59     assertEquals(array, array.slice(undefined, undefined));
     60   }
     61 })();
     62 
     63 
     64 // Check variants of negatives and positive indices.
     65 (function() {
     66   var array = new Array(7);
     67 
     68   for (var i = 0; i < 7; i++) {
     69     assertEquals(7, array.slice(-100).length);
     70     assertEquals(3, array.slice(-3).length);
     71     assertEquals(3, array.slice(4).length);
     72     assertEquals(1, array.slice(6).length);
     73     assertEquals(0, array.slice(7).length);
     74     assertEquals(0, array.slice(8).length);
     75     assertEquals(0, array.slice(100).length);
     76 
     77     assertEquals(0, array.slice(0, -100).length);
     78     assertEquals(4, array.slice(0, -3).length);
     79     assertEquals(4, array.slice(0, 4).length);
     80     assertEquals(6, array.slice(0, 6).length);
     81     assertEquals(7, array.slice(0, 7).length);
     82     assertEquals(7, array.slice(0, 8).length);
     83     assertEquals(7, array.slice(0, 100).length);
     84 
     85     // Some exotic cases.
     86 
     87     obj = { toString: function() { throw 'Exception'; } };
     88 
     89     // More than 2 arguments:
     90     assertEquals(7, array.slice(0, 7, obj, null, undefined).length);
     91 
     92     // Custom conversion:
     93     assertEquals(1, array.slice({valueOf: function() { return 1; }},
     94                                 {toString: function() { return 2; }}).length);
     95 
     96     // Throwing an exception in conversion:
     97     try {
     98       assertEquals(7, array.slice(0, obj).length);
     99       throw 'Should have thrown';
    100     } catch (e) {
    101       assertEquals('Exception', e);
    102     }
    103   }
    104 })();
    105 
    106 
    107 // Nasty: modify the array in ToInteger.
    108 (function() {
    109   var array = [];
    110   var expected = []
    111   bad_guy = { valueOf: function() { array.push(array.length); return -1; } };
    112 
    113   for (var i = 0; i < 13; i++) {
    114     var sliced = array.slice(bad_guy);
    115     expected.push(i);
    116     assertEquals(expected, array);
    117     // According to the spec (15.4.4.10), length is calculated before
    118     // performing ToInteger on arguments.
    119     if (i == 0) {
    120       assertEquals([], sliced);  // Length was 0, nothing to get.
    121     } else {
    122       // Actually out of array [0..i] we get [i - 1] as length is i.
    123       assertEquals([i - 1], sliced);
    124     }
    125   }
    126 })();
    127 
    128 
    129 // Now check the case with array of holes and some elements on prototype.
    130 // Note: that is important that this test runs before the next one
    131 // as the next one tampers Array.prototype.
    132 (function() {
    133   var len = 9;
    134   var array = new Array(len);
    135 
    136   var at3 = "@3";
    137   var at7 = "@7";
    138 
    139   for (var i = 0; i < 7; i++) {
    140     var array_proto = [];
    141     array_proto[3] = at3;
    142     array_proto[7] = at7;
    143     array.__proto__ = array_proto;
    144 
    145     assertEquals(len, array.length);
    146     for (var i = 0; i < array.length; i++) {
    147       assertEquals(array[i], array_proto[i]);
    148     }
    149 
    150     var sliced = array.slice();
    151 
    152     assertEquals(len, sliced.length);
    153 
    154     assertTrue(delete array_proto[3]);
    155     assertTrue(delete array_proto[7]);
    156 
    157     // Note that slice copies values from prototype into the array.
    158     assertEquals(array[3], undefined);
    159     assertFalse(array.hasOwnProperty(3));
    160     assertEquals(sliced[3], at3);
    161     assertTrue(sliced.hasOwnProperty(3));
    162 
    163     assertEquals(array[7], undefined);
    164     assertFalse(array.hasOwnProperty(7));
    165     assertEquals(sliced[7], at7);
    166     assertTrue(sliced.hasOwnProperty(7));
    167 
    168     // ... but keeps the rest as holes:
    169     array_proto[5] = "@5";
    170     assertEquals(array[5], array_proto[5]);
    171     assertFalse(array.hasOwnProperty(5));
    172   }
    173 })();
    174 
    175 
    176 // Now check the case with array of holes and some elements on prototype.
    177 (function() {
    178   var len = 9;
    179   var array = new Array(len);
    180 
    181   var at3 = "@3";
    182   var at7 = "@7";
    183 
    184   for (var i = 0; i < 7; i++) {
    185     Array.prototype[3] = at3;
    186     Array.prototype[7] = at7;
    187 
    188     assertEquals(len, array.length);
    189     for (var i = 0; i < array.length; i++) {
    190       assertEquals(array[i], Array.prototype[i]);
    191     }
    192 
    193     var sliced = array.slice();
    194 
    195     assertEquals(len, sliced.length);
    196 
    197     assertTrue(delete Array.prototype[3]);
    198     assertTrue(delete Array.prototype[7]);
    199 
    200     // Note that slice copies values from prototype into the array.
    201     assertEquals(array[3], undefined);
    202     assertFalse(array.hasOwnProperty(3));
    203     assertEquals(sliced[3], at3);
    204     assertTrue(sliced.hasOwnProperty(3));
    205 
    206     assertEquals(array[7], undefined);
    207     assertFalse(array.hasOwnProperty(7));
    208     assertEquals(sliced[7], at7);
    209     assertTrue(sliced.hasOwnProperty(7));
    210 
    211     // ... but keeps the rest as holes:
    212     Array.prototype[5] = "@5";
    213     assertEquals(array[5], Array.prototype[5]);
    214     assertFalse(array.hasOwnProperty(5));
    215     assertEquals(sliced[5], Array.prototype[5]);
    216     assertFalse(sliced.hasOwnProperty(5));
    217 
    218     assertTrue(delete Array.prototype[5]);
    219   }
    220 })();
    221 
    222 // Check slicing on arguments object.
    223 (function() {
    224   function func(expected, a0, a1, a2) {
    225     assertEquals(expected, Array.prototype.slice.call(arguments, 1));
    226   }
    227 
    228   func([]);
    229   func(['a'], 'a');
    230   func(['a', 1], 'a', 1);
    231   func(['a', 1, undefined], 'a', 1, undefined);
    232   func(['a', 1, undefined, void(0)], 'a', 1, undefined, void(0));
    233 })();
    234 
    235 // Check slicing on arguments object when missing arguments get assigined.
    236 (function() {
    237   function func(x, y) {
    238     assertEquals(1, arguments.length);
    239     assertEquals(undefined, y);
    240     y = 239;
    241     assertEquals(1, arguments.length);  // arguments length is the same.
    242     assertEquals([x], Array.prototype.slice.call(arguments, 0));
    243   }
    244 
    245   func('a');
    246 })();
    247 
    248 // Check slicing on arguments object when length property has been set.
    249 (function() {
    250   function func(x, y) {
    251     assertEquals(1, arguments.length);
    252     arguments.length = 7;
    253     assertEquals([x,,,,,,,], Array.prototype.slice.call(arguments, 0));
    254   }
    255 
    256   func('a');
    257 })();
    258 
    259 // Check slicing on arguments object when length property has been set to
    260 // some strange value.
    261 (function() {
    262   function func(x, y) {
    263     assertEquals(1, arguments.length);
    264     arguments.length = 'foobar';
    265     assertEquals([], Array.prototype.slice.call(arguments, 0));
    266   }
    267 
    268   func('a');
    269 })();
    270 
    271 // Check slicing on arguments object when extra argument has been added
    272 // via indexed assignment.
    273 (function() {
    274   function func(x, y) {
    275     assertEquals(1, arguments.length);
    276     arguments[3] = 239;
    277     assertEquals([x], Array.prototype.slice.call(arguments, 0));
    278   }
    279 
    280   func('a');
    281 })();
    282 
    283 // Check slicing on arguments object when argument has been deleted by index.
    284 (function() {
    285   function func(x, y, z) {
    286     assertEquals(3, arguments.length);
    287     delete arguments[1];
    288     assertEquals([x,,z], Array.prototype.slice.call(arguments, 0));
    289   }
    290 
    291   func('a', 'b', 'c');
    292 })();
    293