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 32var poses; 33 34poses = [140, 4000000000]; 35while (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 106poses = [140, 4000000000]; 107while (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 179a = []; 180c = a.concat('Hello'); 181assertEquals(1, c.length); 182assertEquals("Hello", c[0]); 183assertEquals("Hello", c.toString()); 184 185// Check that concat preserves holes. 186var holey = [void 0,'a',,'c'].concat(['d',,'f',[0,,2],void 0]) 187assertEquals(9, holey.length); // hole in embedded array is ignored 188for (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. 197delete Array.prototype[123]; 198 199// Check that concat reads getters in the correct order. 200var arr1 = [,2]; 201var arr2 = [1,3]; 202var r1 = [].concat(arr1, arr2); // [,2,1,3] 203assertEquals([,2,1,3], r1); 204 205// Make first array change length of second array. 206Object.defineProperty(arr1, 0, {get: function() { 207 arr2.push("X"); 208 return undefined; 209 }, configurable: true}) 210var r2 = [].concat(arr1, arr2); // [undefined,2,1,3,"X"] 211assertEquals([undefined,2,1,3,"X"], r2); 212 213// Make first array change length of second array massively. 214arr2.length = 2; 215Object.defineProperty(arr1, 0, {get: function() { 216 arr2[500000] = "X"; 217 return undefined; 218 }, configurable: true}) 219var r3 = [].concat(arr1, arr2); // [undefined,2,1,3,"X"] 220var expected = [undefined,2,1,3]; 221expected[500000 + 2] = "X"; 222 223assertEquals(expected, r3); 224 225var arr3 = []; 226var trace = []; 227var expectedTrace = [] 228function mkGetter(i) { return function() { trace.push(i); }; } 229arr3.length = 10000; 230for (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} 235var r4 = [0].concat(arr3, arr3); 236assertEquals(1 + arr3.length * 2, r4.length); 237assertEquals(expectedTrace, trace); 238