ager@chromium.org | 5c83825 | 2010-02-19 08:53:10 +0000 | [diff] [blame] | 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 splice, shift, unshift, slice and join on small |
| 30 | * and large arrays. Some of these methods are specified such that they |
| 31 | * should work on other objects too, so we test that too. |
| 32 | */ |
| 33 | |
| 34 | var LARGE = 40000000; |
| 35 | var VERYLARGE = 4000000000; |
| 36 | |
| 37 | // Nicer for firefox 1.5. Unless you uncomment the following two lines, |
| 38 | // smjs will appear to hang on this file. |
| 39 | //var LARGE = 40000; |
| 40 | //var VERYLARGE = 40000; |
| 41 | |
| 42 | var fourhundredth = LARGE/400; |
| 43 | |
| 44 | function PseudoArray() { |
| 45 | }; |
| 46 | |
| 47 | for (var use_real_arrays = 0; use_real_arrays <= 1; use_real_arrays++) { |
| 48 | var poses = [0, 140, 20000, VERYLARGE]; |
| 49 | var the_prototype; |
| 50 | var new_function; |
| 51 | var push_function; |
| 52 | var concat_function; |
| 53 | var slice_function; |
| 54 | var splice_function; |
| 55 | var splice_function_2; |
| 56 | var unshift_function; |
| 57 | var unshift_function_2; |
| 58 | var shift_function; |
| 59 | if (use_real_arrays) { |
| 60 | new_function = function(length) { |
| 61 | return new Array(length); |
| 62 | }; |
| 63 | the_prototype = Array.prototype; |
| 64 | push_function = function(array, elt) { |
| 65 | return array.push(elt); |
| 66 | }; |
| 67 | concat_function = function(array, other) { |
| 68 | return array.concat(other); |
| 69 | }; |
| 70 | slice_function = function(array, start, len) { |
| 71 | return array.slice(start, len); |
| 72 | }; |
| 73 | splice_function = function(array, start, len) { |
| 74 | return array.splice(start, len); |
| 75 | }; |
| 76 | splice_function_2 = function(array, start, len, elt) { |
| 77 | return array.splice(start, len, elt); |
| 78 | }; |
| 79 | unshift_function = function(array, elt) { |
| 80 | return array.unshift(elt); |
| 81 | }; |
| 82 | unshift_function_2 = function(array, elt1, elt2) { |
| 83 | return array.unshift(elt1, elt2); |
| 84 | }; |
| 85 | shift_function = function(array) { |
| 86 | return array.shift(); |
| 87 | }; |
| 88 | } else { |
| 89 | // Don't run largest size on non-arrays or we'll be here for ever. |
| 90 | poses.pop(); |
| 91 | new_function = function(length) { |
| 92 | var obj = new PseudoArray(); |
| 93 | obj.length = length; |
| 94 | return obj; |
| 95 | }; |
| 96 | the_prototype = PseudoArray.prototype; |
| 97 | push_function = function(array, elt) { |
| 98 | array[array.length] = elt; |
| 99 | array.length++; |
| 100 | }; |
| 101 | concat_function = function(array, other) { |
| 102 | return Array.prototype.concat.call(array, other); |
| 103 | }; |
| 104 | slice_function = function(array, start, len) { |
| 105 | return Array.prototype.slice.call(array, start, len); |
| 106 | }; |
| 107 | splice_function = function(array, start, len) { |
| 108 | return Array.prototype.splice.call(array, start, len); |
| 109 | }; |
| 110 | splice_function_2 = function(array, start, len, elt) { |
| 111 | return Array.prototype.splice.call(array, start, len, elt); |
| 112 | }; |
| 113 | unshift_function = function(array, elt) { |
| 114 | return Array.prototype.unshift.call(array, elt); |
| 115 | }; |
| 116 | unshift_function_2 = function(array, elt1, elt2) { |
| 117 | return Array.prototype.unshift.call(array, elt1, elt2); |
| 118 | }; |
| 119 | shift_function = function(array) { |
| 120 | return Array.prototype.shift.call(array); |
| 121 | }; |
| 122 | } |
| 123 | |
| 124 | for (var pos_pos = 0; pos_pos < poses.length; pos_pos++) { |
| 125 | var pos = poses[pos_pos]; |
| 126 | if (pos > 100) { |
| 127 | var a = new_function(pos); |
| 128 | assertEquals(pos, a.length); |
| 129 | push_function(a, 'foo'); |
| 130 | assertEquals(pos + 1, a.length); |
| 131 | var b = ['bar']; |
| 132 | // Delete a huge number of holes. |
| 133 | var c = splice_function(a, 10, pos - 20); |
| 134 | assertEquals(pos - 20, c.length); |
| 135 | assertEquals(21, a.length); |
| 136 | } |
| 137 | |
| 138 | // Add a numeric property to the prototype of the array class. This |
| 139 | // allows us to test some borderline stuff relative to the standard. |
| 140 | the_prototype["" + (pos + 1)] = 'baz'; |
| 141 | |
| 142 | if (use_real_arrays) { |
| 143 | // It seems quite clear from ECMAScript spec 15.4.4.5. Just call Get on |
| 144 | // every integer in the range. |
| 145 | // IE, Safari get this right. |
| 146 | // FF, Opera get this wrong. |
| 147 | var a = ['zero', ,'two']; |
| 148 | if (pos == 0) { |
| 149 | assertEquals("zero,baz,two", a.join(",")); |
| 150 | } |
| 151 | |
| 152 | // Concat only applies to real arrays, unlike most of the other methods. |
| 153 | var a = new_function(pos); |
| 154 | push_function(a, "con"); |
| 155 | assertEquals("con", a[pos]); |
| 156 | assertEquals(pos + 1, a.length); |
| 157 | var b = new_function(0); |
| 158 | push_function(b, "cat"); |
| 159 | assertEquals("cat", b[0]); |
| 160 | var ab = concat_function(a, b); |
| 161 | assertEquals("con", ab[pos]); |
| 162 | assertEquals(pos + 2, ab.length); |
| 163 | assertEquals("cat", ab[pos + 1]); |
| 164 | var ba = concat_function(b, a); |
| 165 | assertEquals("con", ba[pos + 1]); |
| 166 | assertEquals(pos + 2, ba.length); |
| 167 | assertEquals("cat", ba[0]); |
| 168 | |
| 169 | // Join with '' as separator. |
| 170 | var join = a.join(''); |
| 171 | assertEquals("con", join); |
| 172 | join = b.join(''); |
| 173 | assertEquals("cat", join); |
| 174 | join = ab.join(''); |
| 175 | assertEquals("concat", join); |
| 176 | join = ba.join(''); |
| 177 | assertEquals("catcon", join); |
| 178 | |
| 179 | var sparse = []; |
| 180 | sparse[pos + 1000] = 'is '; |
| 181 | sparse[pos + 271828] = 'time '; |
| 182 | sparse[pos + 31415] = 'the '; |
| 183 | sparse[pos + 012260199] = 'all '; |
| 184 | sparse[-1] = 'foo'; |
| 185 | sparse[pos + 22591927] = 'good '; |
| 186 | sparse[pos + 1618033] = 'for '; |
| 187 | sparse[pos + 91] = ': Now '; |
| 188 | sparse[pos + 86720199] = 'men.'; |
| 189 | sparse.hest = 'fisk'; |
| 190 | |
| 191 | assertEquals("baz: Now is the time for all good men.", sparse.join('')); |
| 192 | } |
| 193 | |
| 194 | a = new_function(pos); |
| 195 | push_function(a, 'zero'); |
| 196 | push_function(a, void 0); |
| 197 | push_function(a, 'two'); |
| 198 | |
| 199 | // Splice works differently from join. |
| 200 | // IE, Safari get this wrong. |
| 201 | // FF, Opera get this right. |
| 202 | // 15.4.4.12 line 24 says the object itself has to have the property... |
| 203 | var zero = splice_function(a, pos, 1); |
| 204 | assertEquals("undefined", typeof(a[pos])); |
| 205 | assertEquals("two", a[pos+1], "pos1:" + pos); |
| 206 | assertEquals(pos + 2, a.length, "a length"); |
| 207 | assertEquals(1, zero.length, "zero length"); |
| 208 | assertEquals("zero", zero[0]); |
| 209 | |
| 210 | // 15.4.4.12 line 41 says the object itself has to have the property... |
| 211 | a = new_function(pos); |
| 212 | push_function(a, 'zero'); |
| 213 | push_function(a, void 0); |
| 214 | push_function(a, 'two'); |
| 215 | var nothing = splice_function_2(a, pos, 0, 'minus1'); |
| 216 | assertEquals("minus1", a[pos]); |
| 217 | assertEquals("zero", a[pos+1]); |
| 218 | assertEquals("undefined", typeof(a[pos+2]), "toot!"); |
| 219 | assertEquals("two", a[pos+3], "pos3"); |
| 220 | assertEquals(pos + 4, a.length); |
| 221 | assertEquals(1, zero.length); |
| 222 | assertEquals("zero", zero[0]); |
| 223 | |
| 224 | // 15.4.4.12 line 10 says the object itself has to have the property... |
| 225 | a = new_function(pos); |
| 226 | push_function(a, 'zero'); |
| 227 | push_function(a, void 0); |
| 228 | push_function(a, 'two'); |
| 229 | var one = splice_function(a, pos + 1, 1); |
| 230 | assertEquals("", one.join(",")); |
| 231 | assertEquals(pos + 2, a.length); |
| 232 | assertEquals("zero", a[pos]); |
| 233 | assertEquals("two", a[pos+1]); |
| 234 | |
| 235 | // Set things back to the way they were. |
| 236 | the_prototype[pos + 1] = undefined; |
| 237 | |
| 238 | // Unshift. |
| 239 | var a = new_function(pos); |
| 240 | push_function(a, "foo"); |
| 241 | assertEquals("foo", a[pos]); |
| 242 | assertEquals(pos + 1, a.length); |
| 243 | unshift_function(a, "bar"); |
| 244 | assertEquals("foo", a[pos+1]); |
| 245 | assertEquals(pos + 2, a.length); |
| 246 | assertEquals("bar", a[0]); |
| 247 | unshift_function_2(a, "baz", "boo"); |
| 248 | assertEquals("foo", a[pos+3]); |
| 249 | assertEquals(pos + 4, a.length); |
| 250 | assertEquals("baz", a[0]); |
| 251 | assertEquals("boo", a[1]); |
| 252 | assertEquals("bar", a[2]); |
| 253 | |
| 254 | // Shift. |
| 255 | var baz = shift_function(a); |
| 256 | assertEquals("baz", baz); |
| 257 | assertEquals("boo", a[0]); |
| 258 | assertEquals(pos + 3, a.length); |
| 259 | assertEquals("foo", a[pos + 2]); |
| 260 | |
| 261 | // Slice. |
| 262 | var bar = slice_function(a, 1, 0); // don't throw an exception please. |
| 263 | bar = slice_function(a, 1, 2); |
| 264 | assertEquals("bar", bar[0]); |
| 265 | assertEquals(1, bar.length); |
| 266 | assertEquals("bar", a[1]); |
| 267 | |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | // Lets see if performance is reasonable. |
| 272 | |
| 273 | var a = new Array(LARGE + 10); |
| 274 | for (var i = 0; i < a.length; i += 1000) { |
| 275 | a[i] = i; |
| 276 | } |
| 277 | |
| 278 | // Take something near the end of the array. |
| 279 | for (var i = 0; i < 100; i++) { |
| 280 | var top = a.splice(LARGE, 5); |
| 281 | assertEquals(5, top.length); |
| 282 | assertEquals(LARGE, top[0]); |
| 283 | assertEquals("undefined", typeof(top[1])); |
| 284 | assertEquals(LARGE + 5, a.length); |
| 285 | a.splice(LARGE, 0, LARGE); |
| 286 | a.length = LARGE + 10; |
| 287 | } |
| 288 | |
| 289 | var a = new Array(LARGE + 10); |
| 290 | for (var i = 0; i < a.length; i += fourhundredth) { |
| 291 | a[i] = i; |
| 292 | } |
| 293 | |
| 294 | // Take something near the middle of the array. |
| 295 | for (var i = 0; i < 10; i++) { |
| 296 | var top = a.splice(LARGE >> 1, 5); |
| 297 | assertEquals(5, top.length); |
| 298 | assertEquals(LARGE >> 1, top[0]); |
| 299 | assertEquals("undefined", typeof(top[1])); |
| 300 | assertEquals(LARGE + 5, a.length); |
| 301 | a.splice(LARGE >> 1, 0, LARGE >> 1, void 0, void 0, void 0, void 0); |
| 302 | } |
| 303 | |
| 304 | |
| 305 | // Test http://b/issue?id=1202711 |
| 306 | arr = [0]; |
| 307 | arr.length = 2; |
| 308 | Array.prototype[1] = 1; |
| 309 | assertEquals(1, arr.pop()); |
| 310 | assertEquals(0, arr.pop()); |
| 311 | Array.prototype[1] = undefined; |
| 312 | |
| 313 | // Test http://code.google.com/p/chromium/issues/detail?id=21860 |
| 314 | Array.prototype.push.apply([], [1].splice(0, -(-1 % 5))); |