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