1// Copyright 2014 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5(function copyWithinArity() { 6 assertEquals(Array.prototype.copyWithin.length, 2); 7})(); 8 9 10(function copyWithinTargetAndStart() { 11 // works with two arguemnts 12 assertArrayEquals([4, 5, 3, 4, 5], [1, 2, 3, 4, 5].copyWithin(0, 3)); 13 assertArrayEquals([1, 4, 5, 4, 5], [1, 2, 3, 4, 5].copyWithin(1, 3)); 14 assertArrayEquals([1, 3, 4, 5, 5], [1, 2, 3, 4, 5].copyWithin(1, 2)); 15 assertArrayEquals([1, 2, 3, 4, 5], [1, 2, 3, 4, 5].copyWithin(2, 2)); 16})(); 17 18 19(function copyWithinTargetStartAndEnd() { 20 // works with three arguments 21 assertArrayEquals([1, 2, 3, 4, 5].copyWithin(0, 3, 4), [4, 2, 3, 4, 5]); 22 assertArrayEquals([1, 2, 3, 4, 5].copyWithin(1, 3, 4), [1, 4, 3, 4, 5]); 23 assertArrayEquals([1, 2, 3, 4, 5].copyWithin(1, 2, 4), [1, 3, 4, 4, 5]); 24})(); 25 26 27(function copyWithinNegativeRelativeOffsets() { 28 // works with negative arguments 29 assertArrayEquals([4, 5, 3, 4, 5], [1, 2, 3, 4, 5].copyWithin(0, -2)); 30 assertArrayEquals([4, 2, 3, 4, 5], [1, 2, 3, 4, 5].copyWithin(0, -2, -1)); 31 assertArrayEquals([1, 3, 3, 4, 5], [1, 2, 3, 4, 5].copyWithin(-4, -3, -2)); 32 assertArrayEquals([1, 3, 4, 4, 5], [1, 2, 3, 4, 5].copyWithin(-4, -3, -1)); 33 assertArrayEquals([1, 3, 4, 5, 5], [1, 2, 3, 4, 5].copyWithin(-4, -3)); 34 // test with arguments equal to -this.length 35 assertArrayEquals([1, 2, 3, 4, 5], [1, 2, 3, 4, 5].copyWithin(-5, 0)); 36})(); 37 38 39(function copyWithinArrayLikeValues() { 40 // works with array-like values 41 var args = (function () { return arguments; }(1, 2, 3)); 42 Array.prototype.copyWithin.call(args, -2, 0); 43 assertArrayEquals([1, 1, 2], Array.prototype.slice.call(args)); 44 45 // [[Class]] does not change 46 assertArrayEquals("[object Arguments]", Object.prototype.toString.call(args)); 47})(); 48 49 50(function copyWithinNullThis() { 51 // throws on null/undefined values 52 assertThrows(function() { 53 return Array.prototype.copyWithin.call(null, 0, 3); 54 }, TypeError); 55})(); 56 57 58(function copyWithinUndefinedThis() { 59 assertThrows(function() { 60 return Array.prototype.copyWithin.call(undefined, 0, 3); 61 }, TypeError); 62})(); 63 64 65// TODO(caitp): indexed properties of String are read-only and setting them 66// should throw in strict mode. See bug v8:4042 67// (function copyWithinStringThis() { 68// // test with this value as string 69// assertThrows(function() { 70// return Array.prototype.copyWithin.call("hello world", 0, 3); 71// }, TypeError); 72// })(); 73 74 75(function copyWithinNumberThis() { 76 // test with this value as number 77 assertEquals(34, Array.prototype.copyWithin.call(34, 0, 3).valueOf()); 78})(); 79 80 81(function copyWithinSymbolThis() { 82 // test with this value as number 83 var sym = Symbol("test"); 84 assertEquals(sym, Array.prototype.copyWithin.call(sym, 0, 3).valueOf()); 85})(); 86 87 88(function copyyWithinTypedArray() { 89 // test with this value as TypedArray 90 var buffer = new ArrayBuffer(16); 91 var int32View = new Int32Array(buffer); 92 for (var i=0; i<int32View.length; i++) { 93 int32View[i] = i*2; 94 } 95 assertArrayEquals(new Int32Array([2, 4, 6, 6]), 96 Array.prototype.copyWithin.call(int32View, 0, 1)); 97})(); 98 99 100(function copyWithinSloppyArguments() { 101 // if arguments object is sloppy, copyWithin must move the arguments around 102 function f(a, b, c, d, e) { 103 [].copyWithin.call(arguments, 1, 3); 104 return [a, b, c, d, e]; 105 } 106 assertArrayEquals([1, 4, 5, 4, 5], f(1, 2, 3, 4, 5)); 107})(); 108 109 110(function copyWithinStartLessThanTarget() { 111 // test with target > start on 2 arguments 112 assertArrayEquals([1, 2, 3, 1, 2], [1, 2, 3, 4, 5].copyWithin(3, 0)); 113 114 // test with target > start on 3 arguments 115 assertArrayEquals([1, 2, 3, 1, 2], [1, 2, 3, 4, 5].copyWithin(3, 0, 4)); 116})(); 117 118 119(function copyWithinArrayWithHoles() { 120 // test on array with holes 121 var arr = new Array(6); 122 for (var i = 0; i < arr.length; i += 2) { 123 arr[i] = i; 124 } 125 assertArrayEquals([, 4, , , 4, , ], arr.copyWithin(0, 3)); 126})(); 127 128 129(function copyWithinArrayLikeWithHoles() { 130 // test on array-like object with holes 131 assertArrayEquals({ 132 length: 6, 133 1: 4, 134 4: 4 135 }, Array.prototype.copyWithin.call({ 136 length: 6, 137 0: 0, 138 2: 2, 139 4: 4 140 }, 0, 3)); 141})(); 142 143 144(function copyWithinNonIntegerRelativeOffsets() { 145 // test on fractional arguments 146 assertArrayEquals([4, 5, 3, 4, 5], [1, 2, 3, 4, 5].copyWithin(0.2, 3.9)); 147})(); 148 149 150(function copyWithinNegativeZeroTarget() { 151 // test with -0 152 assertArrayEquals([4, 5, 3, 4, 5], [1, 2, 3, 4, 5].copyWithin(-0, 3)); 153})(); 154 155 156(function copyWithinTargetOutsideStart() { 157 // test with arguments more than this.length 158 assertArrayEquals([1, 2, 3, 4, 5], [1, 2, 3, 4, 5].copyWithin(0, 7)); 159 160 // test with arguments less than -this.length 161 assertArrayEquals([1, 2, 3, 4, 5], [1, 2, 3, 4, 5].copyWithin(-7, 0)); 162})(); 163 164 165(function copyWithinEmptyArray() { 166 // test on empty array 167 assertArrayEquals([], [].copyWithin(0, 3)); 168})(); 169 170 171(function copyWithinTargetCutOff() { 172 // test with target range being shorter than end - start 173 assertArrayEquals([1, 2, 2, 3, 4], [1, 2, 3, 4, 5].copyWithin(2, 1, 4)); 174})(); 175 176 177(function copyWithinOverlappingRanges() { 178 // test overlapping ranges 179 var arr = [1, 2, 3, 4, 5]; 180 arr.copyWithin(2, 1, 4); 181 assertArrayEquals([1, 2, 2, 2, 3], arr.copyWithin(2, 1, 4)); 182})(); 183 184 185(function copyWithinStrictDelete() { 186 // check that [[Delete]] is strict (non-extensible via freeze) 187 assertThrows(function() { 188 return Object.freeze([1, , 3, , 4, 5]).copyWithin(2, 1, 4); 189 }, TypeError); 190 191 // check that [[Delete]] is strict (non-extensible via seal) 192 assertThrows(function() { 193 return Object.seal([1, , 3, , 4, 5]).copyWithin(2, 1, 4); 194 }, TypeError); 195 196 // check that [[Delete]] is strict (non-extensible via preventExtensions) 197 assertThrows(function() { 198 return Object.preventExtensions([1, , 3, , 4, 5]).copyWithin(2, 1, 4); 199 }, TypeError); 200})(); 201 202 203(function copyWithinStrictSet() { 204 // check that [[Set]] is strict (non-extensible via freeze) 205 assertThrows(function() { 206 return Object.freeze([1, 2, 3, 4, 5]).copyWithin(0, 3); 207 }, TypeError); 208 209 // check that [[Set]] is strict (non-extensible via seal) 210 assertThrows(function() { 211 return Object.seal([, 2, 3, 4, 5]).copyWithin(0, 3); 212 }, TypeError); 213 214 // check that [[Set]] is strict (non-extensible via preventExtensions) 215 assertThrows(function() { 216 return Object.preventExtensions([ , 2, 3, 4, 5]).copyWithin(0, 3); 217 }, TypeError); 218})(); 219 220 221(function copyWithinSetterThrows() { 222 function Boom() {} 223 // test if we throw in between 224 var arr = Object.defineProperty([1, 2, 3, 4, 5], 1, { 225 set: function () { 226 throw new Boom(); 227 } 228 }); 229 230 assertThrows(function() { 231 return arr.copyWithin(1, 3); 232 }, Boom); 233 234 assertArrayEquals([1, , 3, 4, 5], arr); 235})(); 236 237 238(function copyWithinDefaultEnd() { 239 // undefined as third argument 240 assertArrayEquals( 241 [4, 5, 3, 4, 5], [1, 2, 3, 4, 5].copyWithin(0, 3, undefined)); 242})(); 243 244 245(function copyWithinGetLengthOnce() { 246 // test that this.length is called only once 247 var count = 0; 248 var arr = Object.defineProperty({ 0: 1, 1: 2, 2: 3, 3: 4, 4: 5 }, "length", { 249 get: function () { 250 count++; 251 return 5; 252 } 253 }); 254 Array.prototype.copyWithin.call(arr, 1, 3); 255 assertEquals(1, count); 256 257 Array.prototype.copyWithin.call(arr, 1, 3, 4); 258 assertEquals(2, count); 259})(); 260 261 262(function copyWithinLargeArray() { 263 var large = 10000; 264 265 // test on a large array 266 var arr = new Array(large); 267 assertArrayEquals(arr, arr.copyWithin(45, 9000)); 268 269 var expected = new Array(large); 270 // test on floating point numbers 271 for (var i = 0; i < large; i++) { 272 arr[i] = Math.random(); 273 expected[i] = arr[i]; 274 if (i >= 9000) { 275 expected[(i - 9000) + 45] = arr[i]; 276 } 277 } 278 assertArrayEquals(expected, arr.copyWithin(45, 9000)); 279 280 // test on array of objects 281 for (var i = 0; i < large; i++) { 282 arr[i] = { num: Math.random() }; 283 } + 45 284 arr.copyWithin(45, 9000); 285 286 // test copied by reference 287 for (var i = 9000; i < large; ++i) { 288 assertSame(arr[(i - 9000) + 45], arr[i]); 289 } 290 291 // test array length remains same 292 assertEquals(large, arr.length); 293})(); 294 295 296(function copyWithinSuperLargeLength() { 297 // 2^53 - 1 is the maximum value returned from ToLength() 298 var large = Math.pow(2, 53) - 1; 299 var object = { length: large }; 300 301 // Initialize last 10 entries 302 for (var i = 1; i <= 10; ++i) { 303 object[(large - 11) + i] = { num: i }; 304 } 305 306 Array.prototype.copyWithin.call(object, 1, large - 10); 307 308 // Test copied values 309 for (var i = 1; i <= 10; ++i) { 310 var old_ref = object[(large - 11) + i]; 311 var new_ref = object[i]; 312 assertSame(old_ref, new_ref); 313 assertSame(new_ref.num, i); 314 } 315 316 // Assert length has not changed 317 assertEquals(large, object.length); 318})(); 319 320 321(function copyWithinNullEnd() { 322 // test null on third argument is converted to +0 323 assertArrayEquals([1, 2, 3, 4, 5], [1, 2, 3, 4, 5].copyWithin(0, 3, null)); 324})(); 325 326 327(function copyWithinElementsInObjectsPrototype() { 328 // tamper the global Object prototype and test this works 329 Object.prototype[2] = 1; 330 assertArrayEquals([4, 5, 3, 4, 5], [1, 2, 3, 4, 5].copyWithin(0, 3)); 331 delete Object.prototype[2]; 332 333 Object.prototype[3] = "FAKE"; 334 assertArrayEquals(["FAKE", 5, 3, "FAKE", 5], [1, 2, 3, , 5].copyWithin(0, 3)); 335 delete Object.prototype[3]; 336})(); 337