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 45var poses; 46 47poses = [140, 4000000000]; 48while (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 119poses = [140, 4000000000]; 120while (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 192a = []; 193c = a.concat('Hello'); 194assertEquals(1, c.length); 195assertEquals("Hello", c[0]); 196assertEquals("Hello", c.toString()); 197 198// Check that concat preserves holes. 199var holey = [void 0,'a',,'c'].concat(['d',,'f',[0,,2],void 0]) 200assertEquals(9, holey.length); // hole in embedded array is ignored 201for (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. 210delete Array.prototype[123]; 211 212// Check that concat reads getters in the correct order. 213var arr1 = [,2]; 214var arr2 = [1,3]; 215var r1 = [].concat(arr1, arr2); // [,2,1,3] 216assertEquals([,2,1,3], r1); 217 218// Make first array change length of second array. 219Object.defineProperty(arr1, 0, {get: function() { 220 arr2.push("X"); 221 return undefined; 222 }, configurable: true}) 223var r2 = [].concat(arr1, arr2); // [undefined,2,1,3,"X"] 224assertEquals([undefined,2,1,3,"X"], r2); 225 226// Make first array change length of second array massively. 227arr2.length = 2; 228Object.defineProperty(arr1, 0, {get: function() { 229 arr2[500000] = "X"; 230 return undefined; 231 }, configurable: true}) 232var r3 = [].concat(arr1, arr2); // [undefined,2,1,3,"X"] 233var expected = [undefined,2,1,3]; 234expected[500000 + 2] = "X"; 235 236assertEquals(expected, r3); 237 238var arr3 = []; 239var trace = []; 240var expectedTrace = [] 241function mkGetter(i) { return function() { trace.push(i); }; } 242arr3.length = 10000; 243for (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} 248var r4 = [0].concat(arr3, arr3); 249assertEquals(1 + arr3.length * 2, r4.length); 250assertEquals(expectedTrace, trace); 251