array-slice.js revision 6ded16be15dd865a9b21ea304d5273c8be299c87
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(function() { 131 var len = 9; 132 var array = new Array(len); 133 134 var at3 = "@3"; 135 var at7 = "@7"; 136 137 for (var i = 0; i < 7; i++) { 138 Array.prototype[3] = at3; 139 Array.prototype[7] = at7; 140 141 assertEquals(len, array.length); 142 for (var i = 0; i < array.length; i++) { 143 assertEquals(array[i], Array.prototype[i]); 144 } 145 146 var sliced = array.slice(); 147 148 assertEquals(len, sliced.length); 149 150 assertTrue(delete Array.prototype[3]); 151 assertTrue(delete Array.prototype[7]); 152 153 // Note that slice copies values from prototype into the array. 154 assertEquals(array[3], undefined); 155 assertFalse(array.hasOwnProperty(3)); 156 assertEquals(sliced[3], at3); 157 assertTrue(sliced.hasOwnProperty(3)); 158 159 assertEquals(array[7], undefined); 160 assertFalse(array.hasOwnProperty(7)); 161 assertEquals(sliced[7], at7); 162 assertTrue(sliced.hasOwnProperty(7)); 163 164 // ... but keeps the rest as holes: 165 Array.prototype[5] = "@5"; 166 assertEquals(array[5], Array.prototype[5]); 167 assertFalse(array.hasOwnProperty(5)); 168 assertEquals(sliced[5], Array.prototype[5]); 169 assertFalse(sliced.hasOwnProperty(5)); 170 171 assertTrue(delete Array.prototype[5]); 172 } 173})(); 174