Ben Murdoch | 014dc51 | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 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 | })(); |