// Copyright 2008 Google Inc. All Rights Reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** * @fileoverview Test splice, shift, unshift, slice and join on small * and large arrays. Some of these methods are specified such that they * should work on other objects too, so we test that too. */ var LARGE = 40000000; var VERYLARGE = 4000000000; // Nicer for firefox 1.5. Unless you uncomment the following two lines, // smjs will appear to hang on this file. //var LARGE = 40000; //var VERYLARGE = 40000; var fourhundredth = LARGE/400; function PseudoArray() { }; for (var use_real_arrays = 0; use_real_arrays <= 1; use_real_arrays++) { var poses = [0, 140, 40000, VERYLARGE]; var the_prototype; var new_function; var push_function; var concat_function; var slice_function; var splice_function; var splice_function_2; var unshift_function; var unshift_function_2; var shift_function; if (use_real_arrays) { new_function = function(length) { return new Array(length); }; the_prototype = Array.prototype; push_function = function(array, elt) { return array.push(elt); }; concat_function = function(array, other) { return array.concat(other); }; slice_function = function(array, start, len) { return array.slice(start, len); }; splice_function = function(array, start, len) { return array.splice(start, len); }; splice_function_2 = function(array, start, len, elt) { return array.splice(start, len, elt); }; unshift_function = function(array, elt) { return array.unshift(elt); }; unshift_function_2 = function(array, elt1, elt2) { return array.unshift(elt1, elt2); }; shift_function = function(array) { return array.shift(); }; } else { // Don't run largest size on non-arrays or we'll be here for ever. poses.pop(); new_function = function(length) { var obj = new PseudoArray(); obj.length = length; return obj; }; the_prototype = PseudoArray.prototype; push_function = function(array, elt) { array[array.length] = elt; array.length++; }; concat_function = function(array, other) { return Array.prototype.concat.call(array, other); }; slice_function = function(array, start, len) { return Array.prototype.slice.call(array, start, len); }; splice_function = function(array, start, len) { return Array.prototype.splice.call(array, start, len); }; splice_function_2 = function(array, start, len, elt) { return Array.prototype.splice.call(array, start, len, elt); }; unshift_function = function(array, elt) { return Array.prototype.unshift.call(array, elt); }; unshift_function_2 = function(array, elt1, elt2) { return Array.prototype.unshift.call(array, elt1, elt2); }; shift_function = function(array) { return Array.prototype.shift.call(array); }; } for (var pos_pos = 0; pos_pos < poses.length; pos_pos++) { var pos = poses[pos_pos]; if (pos > 100) { var a = new_function(pos); assertEquals(pos, a.length); push_function(a, 'foo'); assertEquals(pos + 1, a.length); var b = ['bar']; // Delete a huge number of holes. var c = splice_function(a, 10, pos - 20); assertEquals(pos - 20, c.length); assertEquals(21, a.length); } // Add a numeric property to the prototype of the array class. This // allows us to test some borderline stuff relative to the standard. the_prototype["" + (pos + 1)] = 'baz'; if (use_real_arrays) { // It seems quite clear from ECMAScript spec 15.4.4.5. Just call Get on // every integer in the range. // IE, Safari get this right. // FF, Opera get this wrong. var a = ['zero', ,'two']; if (pos == 0) { assertEquals("zero,baz,two", a.join(",")); } // Concat only applies to real arrays, unlike most of the other methods. var a = new_function(pos); push_function(a, "con"); assertEquals("con", a[pos]); assertEquals(pos + 1, a.length); var b = new_function(0); push_function(b, "cat"); assertEquals("cat", b[0]); var ab = concat_function(a, b); assertEquals("con", ab[pos]); assertEquals(pos + 2, ab.length); assertEquals("cat", ab[pos + 1]); var ba = concat_function(b, a); assertEquals("con", ba[pos + 1]); assertEquals(pos + 2, ba.length); assertEquals("cat", ba[0]); // Join with '' as separator. var join = a.join(''); assertEquals("con", join); join = b.join(''); assertEquals("cat", join); join = ab.join(''); assertEquals("concat", join); join = ba.join(''); assertEquals("catcon", join); var sparse = []; sparse[pos + 1000] = 'is '; sparse[pos + 271828] = 'time '; sparse[pos + 31415] = 'the '; sparse[pos + 012260199] = 'all '; sparse[-1] = 'foo'; sparse[pos + 22591927] = 'good '; sparse[pos + 1618033] = 'for '; sparse[pos + 91] = ': Now '; sparse[pos + 86720199] = 'men.'; sparse.hest = 'fisk'; assertEquals("baz: Now is the time for all good men.", sparse.join('')); } a = new_function(pos); push_function(a, 'zero'); push_function(a, void 0); push_function(a, 'two'); // Splice works differently from join. // IE, Safari get this wrong. // FF, Opera get this right. // 15.4.4.12 line 24 says the object itself has to have the property... var zero = splice_function(a, pos, 1); assertEquals("undefined", typeof(a[pos])); assertEquals("two", a[pos+1], "pos1:" + pos); assertEquals(pos + 2, a.length, "a length"); assertEquals(1, zero.length, "zero length"); assertEquals("zero", zero[0]); // 15.4.4.12 line 41 says the object itself has to have the property... a = new_function(pos); push_function(a, 'zero'); push_function(a, void 0); push_function(a, 'two'); var nothing = splice_function_2(a, pos, 0, 'minus1'); assertEquals("minus1", a[pos]); assertEquals("zero", a[pos+1]); assertEquals("undefined", typeof(a[pos+2]), "toot!"); assertEquals("two", a[pos+3], "pos3"); assertEquals(pos + 4, a.length); assertEquals(1, zero.length); assertEquals("zero", zero[0]); // 15.4.4.12 line 10 says the object itself has to have the property... a = new_function(pos); push_function(a, 'zero'); push_function(a, void 0); push_function(a, 'two'); var one = splice_function(a, pos + 1, 1); assertEquals("", one.join(",")); assertEquals(pos + 2, a.length); assertEquals("zero", a[pos]); assertEquals("two", a[pos+1]); // Set things back to the way they were. the_prototype[pos + 1] = undefined; // Unshift. var a = new_function(pos); push_function(a, "foo"); assertEquals("foo", a[pos]); assertEquals(pos + 1, a.length); unshift_function(a, "bar"); assertEquals("foo", a[pos+1]); assertEquals(pos + 2, a.length); assertEquals("bar", a[0]); unshift_function_2(a, "baz", "boo"); assertEquals("foo", a[pos+3]); assertEquals(pos + 4, a.length); assertEquals("baz", a[0]); assertEquals("boo", a[1]); assertEquals("bar", a[2]); // Shift. var baz = shift_function(a); assertEquals("baz", baz); assertEquals("boo", a[0]); assertEquals(pos + 3, a.length); assertEquals("foo", a[pos + 2]); // Slice. var bar = slice_function(a, 1, 0); // don't throw an exception please. bar = slice_function(a, 1, 2); assertEquals("bar", bar[0]); assertEquals(1, bar.length); assertEquals("bar", a[1]); } } // Lets see if performance is reasonable. var a = new Array(LARGE + 10); for (var i = 0; i < a.length; i += 1000) { a[i] = i; } // Take something near the end of the array. for (var i = 0; i < 100; i++) { var top = a.splice(LARGE, 5); assertEquals(5, top.length); assertEquals(LARGE, top[0]); assertEquals("undefined", typeof(top[1])); assertEquals(LARGE + 5, a.length); a.splice(LARGE, 0, LARGE); a.length = LARGE + 10; } var a = new Array(LARGE + 10); for (var i = 0; i < a.length; i += fourhundredth) { a[i] = i; } // Take something near the middle of the array. for (var i = 0; i < 10; i++) { var top = a.splice(LARGE >> 1, 5); assertEquals(5, top.length); assertEquals(LARGE >> 1, top[0]); assertEquals("undefined", typeof(top[1])); assertEquals(LARGE + 5, a.length); a.splice(LARGE >> 1, 0, LARGE >> 1, void 0, void 0, void 0, void 0); } // Test http://b/issue?id=1202711 arr = [0]; arr.length = 2; Array.prototype[1] = 1; assertEquals(1, arr.pop()); assertEquals(0, arr.pop()); Array.prototype[1] = undefined;