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 concat on small and large arrays
     30  */
     31 
     32 var poses;
     33 
     34 poses = [140, 4000000000];
     35 while (pos = poses.shift()) {
     36   var a = new Array(pos);
     37   var array_proto = [];
     38   a.__proto__ = array_proto;
     39   assertEquals(pos, a.length);
     40   a.push('foo');
     41   assertEquals(pos + 1, a.length);
     42   var b = ['bar'];
     43   var c = a.concat(b);
     44   assertEquals(pos + 2, c.length);
     45   assertEquals("undefined", typeof(c[pos - 1]));
     46   assertEquals("foo", c[pos]);
     47   assertEquals("bar", c[pos + 1]);
     48 
     49   // Can we fool the system by putting a number in a string?
     50   var onetwofour = "124";
     51   a[onetwofour] = 'doo';
     52   assertEquals(a[124], 'doo');
     53   c = a.concat(b);
     54   assertEquals(c[124], 'doo');
     55 
     56   // If we put a number in the prototype, then the spec says it should be
     57   // copied on concat.
     58   array_proto["123"] = 'baz';
     59   assertEquals(a[123], 'baz');
     60 
     61   c = a.concat(b);
     62   assertEquals(pos + 2, c.length);
     63   assertEquals("baz", c[123]);
     64   assertEquals("undefined", typeof(c[pos - 1]));
     65   assertEquals("foo", c[pos]);
     66   assertEquals("bar", c[pos + 1]);
     67 
     68   // When we take the number off the prototype it disappears from a, but
     69   // the concat put it in c itself.
     70   array_proto["123"] = undefined;
     71   assertEquals("undefined", typeof(a[123]));
     72   assertEquals("baz", c[123]);
     73 
     74   // If the element of prototype is shadowed, the element on the instance
     75   // should be copied, but not the one on the prototype.
     76   array_proto[123] = 'baz';
     77   a[123] = 'xyz';
     78   assertEquals('xyz', a[123]);
     79   c = a.concat(b);
     80   assertEquals('xyz', c[123]);
     81 
     82   // Non-numeric properties on the prototype or the array shouldn't get
     83   // copied.
     84   array_proto.moe = 'joe';
     85   a.ben = 'jerry';
     86   assertEquals(a["moe"], 'joe');
     87   assertEquals(a["ben"], 'jerry');
     88   c = a.concat(b);
     89   // ben was not copied
     90   assertEquals("undefined", typeof(c.ben));
     91 
     92   // When we take moe off the prototype it disappears from all arrays.
     93   array_proto.moe = undefined;
     94   assertEquals("undefined", typeof(c.moe));
     95 
     96   // Negative indices don't get concated.
     97   a[-1] = 'minus1';
     98   assertEquals("minus1", a[-1]);
     99   assertEquals("undefined", typeof(a[0xffffffff]));
    100   c = a.concat(b);
    101   assertEquals("undefined", typeof(c[-1]));
    102   assertEquals("undefined", typeof(c[0xffffffff]));
    103   assertEquals(c.length, a.length + 1);
    104 }
    105 
    106 poses = [140, 4000000000];
    107 while (pos = poses.shift()) {
    108   var a = new Array(pos);
    109   assertEquals(pos, a.length);
    110   a.push('foo');
    111   assertEquals(pos + 1, a.length);
    112   var b = ['bar'];
    113   var c = a.concat(b);
    114   assertEquals(pos + 2, c.length);
    115   assertEquals("undefined", typeof(c[pos - 1]));
    116   assertEquals("foo", c[pos]);
    117   assertEquals("bar", c[pos + 1]);
    118 
    119   // Can we fool the system by putting a number in a string?
    120   var onetwofour = "124";
    121   a[onetwofour] = 'doo';
    122   assertEquals(a[124], 'doo');
    123   c = a.concat(b);
    124   assertEquals(c[124], 'doo');
    125 
    126   // If we put a number in the prototype, then the spec says it should be
    127   // copied on concat.
    128   Array.prototype["123"] = 'baz';
    129   assertEquals(a[123], 'baz');
    130 
    131   c = a.concat(b);
    132   assertEquals(pos + 2, c.length);
    133   assertEquals("baz", c[123]);
    134   assertEquals("undefined", typeof(c[pos - 1]));
    135   assertEquals("foo", c[pos]);
    136   assertEquals("bar", c[pos + 1]);
    137 
    138   // When we take the number off the prototype it disappears from a, but
    139   // the concat put it in c itself.
    140   Array.prototype["123"] = undefined;
    141   assertEquals("undefined", typeof(a[123]));
    142   assertEquals("baz", c[123]);
    143 
    144   // If the element of prototype is shadowed, the element on the instance
    145   // should be copied, but not the one on the prototype.
    146   Array.prototype[123] = 'baz';
    147   a[123] = 'xyz';
    148   assertEquals('xyz', a[123]);
    149   c = a.concat(b);
    150   assertEquals('xyz', c[123]);
    151 
    152   // Non-numeric properties on the prototype or the array shouldn't get
    153   // copied.
    154   Array.prototype.moe = 'joe';
    155   a.ben = 'jerry';
    156   assertEquals(a["moe"], 'joe');
    157   assertEquals(a["ben"], 'jerry');
    158   c = a.concat(b);
    159   // ben was not copied
    160   assertEquals("undefined", typeof(c.ben));
    161   // moe was not copied, but we can see it through the prototype
    162   assertEquals("joe", c.moe);
    163 
    164   // When we take moe off the prototype it disappears from all arrays.
    165   Array.prototype.moe = undefined;
    166   assertEquals("undefined", typeof(c.moe));
    167 
    168   // Negative indices don't get concated.
    169   a[-1] = 'minus1';
    170   assertEquals("minus1", a[-1]);
    171   assertEquals("undefined", typeof(a[0xffffffff]));
    172   c = a.concat(b);
    173   assertEquals("undefined", typeof(c[-1]));
    174   assertEquals("undefined", typeof(c[0xffffffff]));
    175   assertEquals(c.length, a.length + 1);
    176 
    177 }
    178 
    179 a = [];
    180 c = a.concat('Hello');
    181 assertEquals(1, c.length);
    182 assertEquals("Hello", c[0]);
    183 assertEquals("Hello", c.toString());
    184 
    185 // Check that concat preserves holes.
    186 var holey = [void 0,'a',,'c'].concat(['d',,'f',[0,,2],void 0])
    187 assertEquals(9, holey.length);  // hole in embedded array is ignored
    188 for (var i = 0; i < holey.length; i++) {
    189   if (i == 2 || i == 5) {
    190     assertFalse(i in holey);
    191   } else {
    192     assertTrue(i in holey);
    193   }
    194 }
    195 
    196 // Polluted prototype from prior tests.
    197 delete Array.prototype[123];
    198 
    199 // Check that concat reads getters in the correct order.
    200 var arr1 = [,2];
    201 var arr2 = [1,3];
    202 var r1 = [].concat(arr1, arr2);  // [,2,1,3]
    203 assertEquals([,2,1,3], r1);
    204 
    205 // Make first array change length of second array.
    206 Object.defineProperty(arr1, 0, {get: function() {
    207       arr2.push("X");
    208       return undefined;
    209     }, configurable: true})
    210 var r2 = [].concat(arr1, arr2);  // [undefined,2,1,3,"X"]
    211 assertEquals([undefined,2,1,3,"X"], r2);
    212 
    213 // Make first array change length of second array massively.
    214 arr2.length = 2;
    215 Object.defineProperty(arr1, 0, {get: function() {
    216       arr2[500000] = "X";
    217       return undefined;
    218     }, configurable: true})
    219 var r3 = [].concat(arr1, arr2);  // [undefined,2,1,3,"X"]
    220 var expected = [undefined,2,1,3];
    221 expected[500000 + 2] = "X";
    222 
    223 assertEquals(expected, r3);
    224 
    225 var arr3 = [];
    226 var trace = [];
    227 var expectedTrace = []
    228 function mkGetter(i) { return function() { trace.push(i); }; }
    229 arr3.length = 10000;
    230 for (var i = 0; i < 100; i++) {
    231   Object.defineProperty(arr3, i * i, {get: mkGetter(i)});
    232   expectedTrace[i] = i;
    233   expectedTrace[100 + i] = i;
    234 }
    235 var r4 = [0].concat(arr3, arr3);
    236 assertEquals(1 + arr3.length * 2, r4.length);
    237 assertEquals(expectedTrace, trace);
    238