1// Copyright 2010 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// Check that slicing array of holes keeps it as array of holes 29(function() { 30 var array = new Array(10); 31 for (var i = 0; i < 7; i++) { 32 var sliced = array.slice(); 33 assertEquals(array.length, sliced.length); 34 assertFalse(0 in sliced); 35 } 36})(); 37 38 39// Check various variants of empty array's slicing. 40(function() { 41 for (var i = 0; i < 7; i++) { 42 assertEquals([], [].slice(0, 0)); 43 assertEquals([], [].slice(1, 0)); 44 assertEquals([], [].slice(0, 1)); 45 assertEquals([], [].slice(-1, 0)); 46 } 47})(); 48 49 50// Check various forms of arguments omission. 51(function() { 52 var array = new Array(7); 53 54 for (var i = 0; i < 7; i++) { 55 assertEquals(array, array.slice()); 56 assertEquals(array, array.slice(0)); 57 assertEquals(array, array.slice(undefined)); 58 assertEquals(array, array.slice("foobar")); 59 assertEquals(array, array.slice(undefined, undefined)); 60 } 61})(); 62 63 64// Check variants of negatives and positive indices. 65(function() { 66 var array = new Array(7); 67 68 for (var i = 0; i < 7; i++) { 69 assertEquals(7, array.slice(-100).length); 70 assertEquals(3, array.slice(-3).length); 71 assertEquals(3, array.slice(4).length); 72 assertEquals(1, array.slice(6).length); 73 assertEquals(0, array.slice(7).length); 74 assertEquals(0, array.slice(8).length); 75 assertEquals(0, array.slice(100).length); 76 77 assertEquals(0, array.slice(0, -100).length); 78 assertEquals(4, array.slice(0, -3).length); 79 assertEquals(4, array.slice(0, 4).length); 80 assertEquals(6, array.slice(0, 6).length); 81 assertEquals(7, array.slice(0, 7).length); 82 assertEquals(7, array.slice(0, 8).length); 83 assertEquals(7, array.slice(0, 100).length); 84 85 // Some exotic cases. 86 87 obj = { toString: function() { throw 'Exception'; } }; 88 89 // More than 2 arguments: 90 assertEquals(7, array.slice(0, 7, obj, null, undefined).length); 91 92 // Custom conversion: 93 assertEquals(1, array.slice({valueOf: function() { return 1; }}, 94 {toString: function() { return 2; }}).length); 95 96 // Throwing an exception in conversion: 97 try { 98 assertEquals(7, array.slice(0, obj).length); 99 throw 'Should have thrown'; 100 } catch (e) { 101 assertEquals('Exception', e); 102 } 103 } 104})(); 105 106 107// Nasty: modify the array in ToInteger. 108(function() { 109 var array = []; 110 var expected = [] 111 bad_guy = { valueOf: function() { array.push(array.length); return -1; } }; 112 113 for (var i = 0; i < 13; i++) { 114 var sliced = array.slice(bad_guy); 115 expected.push(i); 116 assertEquals(expected, array); 117 // According to the spec (15.4.4.10), length is calculated before 118 // performing ToInteger on arguments. 119 if (i == 0) { 120 assertEquals([], sliced); // Length was 0, nothing to get. 121 } else { 122 // Actually out of array [0..i] we get [i - 1] as length is i. 123 assertEquals([i - 1], sliced); 124 } 125 } 126})(); 127 128 129// Now check the case with array of holes and some elements on prototype. 130// Note: that is important that this test runs before the next one 131// as the next one tampers Array.prototype. 132(function() { 133 var len = 9; 134 var array = new Array(len); 135 136 var at3 = "@3"; 137 var at7 = "@7"; 138 139 for (var i = 0; i < 7; i++) { 140 var array_proto = []; 141 array_proto[3] = at3; 142 array_proto[7] = at7; 143 array.__proto__ = array_proto; 144 145 assertEquals(len, array.length); 146 for (var i = 0; i < array.length; i++) { 147 assertEquals(array[i], array_proto[i]); 148 } 149 150 var sliced = array.slice(); 151 152 assertEquals(len, sliced.length); 153 154 assertTrue(delete array_proto[3]); 155 assertTrue(delete array_proto[7]); 156 157 // Note that slice copies values from prototype into the array. 158 assertEquals(array[3], undefined); 159 assertFalse(array.hasOwnProperty(3)); 160 assertEquals(sliced[3], at3); 161 assertTrue(sliced.hasOwnProperty(3)); 162 163 assertEquals(array[7], undefined); 164 assertFalse(array.hasOwnProperty(7)); 165 assertEquals(sliced[7], at7); 166 assertTrue(sliced.hasOwnProperty(7)); 167 168 // ... but keeps the rest as holes: 169 array_proto[5] = "@5"; 170 assertEquals(array[5], array_proto[5]); 171 assertFalse(array.hasOwnProperty(5)); 172 } 173})(); 174 175 176// Now check the case with array of holes and some elements on prototype. 177(function() { 178 var len = 9; 179 var array = new Array(len); 180 181 var at3 = "@3"; 182 var at7 = "@7"; 183 184 for (var i = 0; i < 7; i++) { 185 Array.prototype[3] = at3; 186 Array.prototype[7] = at7; 187 188 assertEquals(len, array.length); 189 for (var i = 0; i < array.length; i++) { 190 assertEquals(array[i], Array.prototype[i]); 191 } 192 193 var sliced = array.slice(); 194 195 assertEquals(len, sliced.length); 196 197 assertTrue(delete Array.prototype[3]); 198 assertTrue(delete Array.prototype[7]); 199 200 // Note that slice copies values from prototype into the array. 201 assertEquals(array[3], undefined); 202 assertFalse(array.hasOwnProperty(3)); 203 assertEquals(sliced[3], at3); 204 assertTrue(sliced.hasOwnProperty(3)); 205 206 assertEquals(array[7], undefined); 207 assertFalse(array.hasOwnProperty(7)); 208 assertEquals(sliced[7], at7); 209 assertTrue(sliced.hasOwnProperty(7)); 210 211 // ... but keeps the rest as holes: 212 Array.prototype[5] = "@5"; 213 assertEquals(array[5], Array.prototype[5]); 214 assertFalse(array.hasOwnProperty(5)); 215 assertEquals(sliced[5], Array.prototype[5]); 216 assertFalse(sliced.hasOwnProperty(5)); 217 218 assertTrue(delete Array.prototype[5]); 219 } 220})(); 221 222// Check slicing on arguments object. 223(function() { 224 function func(expected, a0, a1, a2) { 225 assertEquals(expected, Array.prototype.slice.call(arguments, 1)); 226 } 227 228 func([]); 229 func(['a'], 'a'); 230 func(['a', 1], 'a', 1); 231 func(['a', 1, undefined], 'a', 1, undefined); 232 func(['a', 1, undefined, void(0)], 'a', 1, undefined, void(0)); 233})(); 234 235// Check slicing on arguments object when missing arguments get assigined. 236(function() { 237 function func(x, y) { 238 assertEquals(1, arguments.length); 239 assertEquals(undefined, y); 240 y = 239; 241 assertEquals(1, arguments.length); // arguments length is the same. 242 assertEquals([x], Array.prototype.slice.call(arguments, 0)); 243 } 244 245 func('a'); 246})(); 247 248// Check slicing on arguments object when length property has been set. 249(function() { 250 function func(x, y) { 251 assertEquals(1, arguments.length); 252 arguments.length = 7; 253 assertEquals([x,,,,,,,], Array.prototype.slice.call(arguments, 0)); 254 } 255 256 func('a'); 257})(); 258 259// Check slicing on arguments object when length property has been set to 260// some strange value. 261(function() { 262 function func(x, y) { 263 assertEquals(1, arguments.length); 264 arguments.length = 'foobar'; 265 assertEquals([], Array.prototype.slice.call(arguments, 0)); 266 } 267 268 func('a'); 269})(); 270 271// Check slicing on arguments object when extra argument has been added 272// via indexed assignment. 273(function() { 274 function func(x, y) { 275 assertEquals(1, arguments.length); 276 arguments[3] = 239; 277 assertEquals([x], Array.prototype.slice.call(arguments, 0)); 278 } 279 280 func('a'); 281})(); 282 283// Check slicing on arguments object when argument has been deleted by index. 284(function() { 285 function func(x, y, z) { 286 assertEquals(3, arguments.length); 287 delete arguments[1]; 288 assertEquals([x,,z], Array.prototype.slice.call(arguments, 0)); 289 } 290 291 func('a', 'b', 'c'); 292})(); 293 294// Check slicing of holey objects with elements in the prototype 295(function() { 296 function f() { 297 delete arguments[1]; 298 arguments.__proto__[1] = 5; 299 var result = Array.prototype.slice.call(arguments); 300 delete arguments.__proto__[1]; 301 assertEquals([1,5,3], result); 302 } 303 f(1,2,3); 304})(); 305