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