Home | History | Annotate | Download | only in mjsunit
      1 // 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 
     34 var LARGE = 40000000;
     35 var 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 
     42 var fourhundredth = LARGE/400;
     43 
     44 function PseudoArray() {
     45 };
     46 
     47 for (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 
    273 var a = new Array(LARGE + 10);
    274 for (var i = 0; i < a.length; i += 1000) {
    275   a[i] = i;
    276 }
    277 
    278 // Take something near the end of the array.
    279 for (var i = 0; i < 100; i++) {
    280   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 
    289 var a = new Array(LARGE + 10);
    290 for (var i = 0; i < a.length; i += fourhundredth) {
    291   a[i] = i;
    292 }
    293 
    294 // Take something near the middle of the array.
    295 for (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
    306 arr = [0];
    307 arr.length = 2;
    308 Array.prototype[1] = 1;
    309 assertEquals(1, arr.pop());
    310 assertEquals(0, arr.pop());
    311 Array.prototype[1] = undefined;
    312 
    313 // Test http://code.google.com/p/chromium/issues/detail?id=21860
    314 Array.prototype.push.apply([], [1].splice(0, -(-1 % 5)));
    315