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 forms of arguments omission. 40 (function() { 41 var array = new Array(7); 42 43 for (var i = 0; i < 7; i++) { 44 assertEquals(array, array.slice()); 45 assertEquals(array, array.slice(0)); 46 assertEquals(array, array.slice(undefined)); 47 assertEquals(array, array.slice("foobar")); 48 assertEquals(array, array.slice(undefined, undefined)); 49 } 50 })(); 51 52 53 // Check variants of negatives and positive indices. 54 (function() { 55 var array = new Array(7); 56 57 for (var i = 0; i < 7; i++) { 58 assertEquals(7, array.slice(-100).length); 59 assertEquals(3, array.slice(-3).length); 60 assertEquals(3, array.slice(4).length); 61 assertEquals(1, array.slice(6).length); 62 assertEquals(0, array.slice(7).length); 63 assertEquals(0, array.slice(8).length); 64 assertEquals(0, array.slice(100).length); 65 66 assertEquals(0, array.slice(0, -100).length); 67 assertEquals(4, array.slice(0, -3).length); 68 assertEquals(4, array.slice(0, 4).length); 69 assertEquals(6, array.slice(0, 6).length); 70 assertEquals(7, array.slice(0, 7).length); 71 assertEquals(7, array.slice(0, 8).length); 72 assertEquals(7, array.slice(0, 100).length); 73 74 // Some exotic cases. 75 76 obj = { toString: function() { throw 'Exception'; } }; 77 78 // More than 2 arguments: 79 assertEquals(7, array.slice(0, 7, obj, null, undefined).length); 80 81 // Custom conversion: 82 assertEquals(1, array.slice({valueOf: function() { return 1; }}, 83 {toString: function() { return 2; }}).length); 84 85 // Throwing an exception in conversion: 86 try { 87 assertEquals(7, array.slice(0, obj).length); 88 throw 'Should have thrown'; 89 } catch (e) { 90 assertEquals('Exception', e); 91 } 92 } 93 })(); 94 95 96 // Nasty: modify the array in ToInteger. 97 (function() { 98 var array = []; 99 var expected = [] 100 bad_guy = { valueOf: function() { array.push(array.length); return -1; } }; 101 102 for (var i = 0; i < 13; i++) { 103 var sliced = array.slice(bad_guy); 104 expected.push(i); 105 assertEquals(expected, array); 106 // According to the spec (15.4.4.10), length is calculated before 107 // performing ToInteger on arguments. 108 if (i == 0) { 109 assertEquals([], sliced); // Length was 0, nothing to get. 110 } else { 111 // Actually out of array [0..i] we get [i - 1] as length is i. 112 assertEquals([i - 1], sliced); 113 } 114 } 115 })(); 116 117 118 // Now check the case with array of holes and some elements on prototype. 119 (function() { 120 var len = 9; 121 var array = new Array(len); 122 123 var at3 = "@3"; 124 var at7 = "@7"; 125 126 for (var i = 0; i < 7; i++) { 127 Array.prototype[3] = at3; 128 Array.prototype[7] = at7; 129 130 assertEquals(len, array.length); 131 for (var i = 0; i < array.length; i++) { 132 assertEquals(array[i], Array.prototype[i]); 133 } 134 135 var sliced = array.slice(); 136 137 assertEquals(len, sliced.length); 138 139 assertTrue(delete Array.prototype[3]); 140 assertTrue(delete Array.prototype[7]); 141 142 // Note that slice copies values from prototype into the array. 143 assertEquals(array[3], undefined); 144 assertFalse(array.hasOwnProperty(3)); 145 assertEquals(sliced[3], at3); 146 assertTrue(sliced.hasOwnProperty(3)); 147 148 assertEquals(array[7], undefined); 149 assertFalse(array.hasOwnProperty(7)); 150 assertEquals(sliced[7], at7); 151 assertTrue(sliced.hasOwnProperty(7)); 152 153 // ... but keeps the rest as holes: 154 Array.prototype[5] = "@5"; 155 assertEquals(array[5], Array.prototype[5]); 156 assertFalse(array.hasOwnProperty(5)); 157 assertEquals(sliced[5], Array.prototype[5]); 158 assertFalse(sliced.hasOwnProperty(5)); 159 160 assertTrue(delete Array.prototype[5]); 161 } 162 })(); 163