1// Copyright 2015 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// script-level tests
6var ox, oy = {}, oz;
7({
8  x: ox,
9  y: oy.value,
10  y2: oy["value2"],
11  z: ({ set v(val) { oz = val; } }).v
12} = {
13  x: "value of x",
14  y: "value of y1",
15  y2: "value of y2",
16  z: "value of z"
17});
18assertEquals("value of x", ox);
19assertEquals("value of y1", oy.value);
20assertEquals("value of y2", oy.value2);
21assertEquals("value of z", oz);
22
23[ox, oy.value, oy["value2"], ...{ set v(val) { oz = val; } }.v] = [
24  1007,
25  798432,
26  555,
27  1, 2, 3, 4, 5
28];
29assertEquals(ox, 1007);
30assertEquals(oy.value, 798432);
31assertEquals(oy.value2, 555);
32assertEquals(oz, [1, 2, 3, 4, 5]);
33
34
35(function testInFunction() {
36  var x, y = {}, z;
37  ({
38    x: x,
39    y: y.value,
40    y2: y["value2"],
41    z: ({ set v(val) { z = val; } }).v
42  } = {
43    x: "value of x",
44    y: "value of y1",
45    y2: "value of y2",
46    z: "value of z"
47  });
48  assertEquals("value of x", x);
49  assertEquals("value of y1", y.value);
50  assertEquals("value of y2", y.value2);
51  assertEquals("value of z", z);
52
53  [x, y.value, y["value2"], ...{ set v(val) { z = val; } }.v] = [
54    1007,
55    798432,
56    555,
57    1, 2, 3, 4, 5
58  ];
59  assertEquals(x, 1007);
60  assertEquals(y.value, 798432);
61  assertEquals(y.value2, 555);
62  assertEquals(z, [1, 2, 3, 4, 5]);
63})();
64
65
66(function testArrowFunctionInitializers() {
67  var fn = (config = {
68    value: defaults.value,
69    nada: { nada: defaults.nada } = { nada: "nothing" }
70  } = { value: "BLAH" }) => config;
71  var defaults = {};
72  assertEquals({ value: "BLAH" }, fn());
73  assertEquals("BLAH", defaults.value);
74  assertEquals("nothing", defaults.nada);
75})();
76
77
78(function testArrowFunctionInitializers2() {
79  var fn = (config = [
80    defaults.value,
81    { nada: defaults.nada } = { nada: "nothing" }
82  ] = ["BLAH"]) => config;
83  var defaults = {};
84  assertEquals(["BLAH"], fn());
85  assertEquals("BLAH", defaults.value);
86  assertEquals("nothing", defaults.nada);
87})();
88
89
90(function testFunctionInitializers() {
91  function fn(config = {
92    value: defaults.value,
93    nada: { nada: defaults.nada } = { nada: "nothing" }
94  } = { value: "BLAH" }) {
95    return config;
96  }
97  var defaults = {};
98  assertEquals({ value: "BLAH" }, fn());
99  assertEquals("BLAH", defaults.value);
100  assertEquals("nothing", defaults.nada);
101})();
102
103
104(function testFunctionInitializers2() {
105  function fn(config = [
106    defaults.value,
107    { nada: defaults.nada } = { nada: "nothing" }
108  ] = ["BLAH"]) { return config; }
109  var defaults = {};
110  assertEquals(["BLAH"], fn());
111  assertEquals("BLAH", defaults.value);
112  assertEquals("nothing", defaults.nada);
113})();
114
115
116(function testDeclarationInitializers() {
117  var defaults = {};
118  var { value } = { value: defaults.value } = { value: "BLAH" };
119  assertEquals("BLAH", value);
120  assertEquals("BLAH", defaults.value);
121})();
122
123
124(function testDeclarationInitializers2() {
125  var defaults = {};
126  var [value] = [defaults.value] = ["BLAH"];
127  assertEquals("BLAH", value);
128  assertEquals("BLAH", defaults.value);
129})();
130
131
132(function testObjectLiteralProperty() {
133  var ext = {};
134  var obj = {
135    a: { b: ext.b, c: ext["c"], d: { set v(val) { ext.d = val; } }.v } = {
136      b: "b", c: "c", d: "d" }
137  };
138  assertEquals({ b: "b", c: "c", d: "d" }, ext);
139  assertEquals({ a: { b: "b", c: "c", d: "d" } }, obj);
140})();
141
142
143(function testArrayLiteralProperty() {
144  var ext = {};
145  var obj = [
146    ...[ ext.b, ext["c"], { set v(val) { ext.d = val; } }.v ] = [
147      "b", "c", "d" ]
148  ];
149  assertEquals({ b: "b", c: "c", d: "d" }, ext);
150  assertEquals([ "b", "c", "d" ], obj);
151})();
152
153
154// TODO(caitp): add similar test for ArrayPatterns, once Proxies support
155// delegating symbol-keyed get/set.
156(function testObjectPatternOperationOrder() {
157  var steps = [];
158  var store = {};
159  function computePropertyName(name) {
160    steps.push("compute name: " + name);
161    return name;
162  }
163  function loadValue(descr, value) {
164    steps.push("load: " + descr + " > " + value);
165    return value;
166  }
167  function storeValue(descr, name, value) {
168    steps.push("store: " + descr + " = " + value);
169    store[name] = value;
170  }
171  var result = {
172    get a() { assertUnreachable(); },
173    set a(value) { storeValue("result.a", "a", value); },
174    get b() { assertUnreachable(); },
175    set b(value) { storeValue("result.b", "b", value); }
176  };
177
178  ({
179    obj: {
180      x: result.a = 10,
181      [computePropertyName("y")]: result.b = false,
182    } = {}
183  } = { obj: {
184    get x() { return loadValue(".temp.obj.x", undefined); },
185    set x(value) { assertUnreachable(); },
186    get y() { return loadValue(".temp.obj.y", undefined); },
187    set y(value) { assertUnreachable(); }
188  }});
189
190  assertPropertiesEqual({
191    a: 10,
192    b: false
193  }, store);
194
195  assertArrayEquals([
196    "load: .temp.obj.x > undefined",
197    "store: result.a = 10",
198
199    "compute name: y",
200    "load: .temp.obj.y > undefined",
201    "store: result.b = false"
202  ], steps);
203
204  steps = [];
205
206  ({
207    obj: {
208      x: result.a = 50,
209      [computePropertyName("y")]: result.b = "hello",
210    } = {}
211  } = { obj: {
212    get x() { return loadValue(".temp.obj.x", 20); },
213    set x(value) { assertUnreachable(); },
214    get y() { return loadValue(".temp.obj.y", true); },
215    set y(value) { assertUnreachable(); }
216  }});
217
218  assertPropertiesEqual({
219    a: 20,
220    b: true
221  }, store);
222
223  assertArrayEquals([
224    "load: .temp.obj.x > 20",
225    "store: result.a = 20",
226    "compute name: y",
227    "load: .temp.obj.y > true",
228    "store: result.b = true",
229  ], steps);
230})();
231
232// Credit to Mike Pennisi and other Test262 contributors for originally writing
233// the testse the following are based on.
234(function testArrayElision() {
235  var value = [1, 2, 3, 4, 5, 6, 7, 8, 9];
236  var a, obj = {};
237  var result = [, a, , obj.b, , ...obj["rest"]] = value;
238
239  assertEquals(result, value);
240  assertEquals(2, a);
241  assertEquals(4, obj.b);
242  assertArrayEquals([6, 7, 8, 9], obj.rest);
243})();
244
245(function testArrayElementInitializer() {
246  function test(value, initializer, expected) {
247    var a, obj = {};
248    var initialized = false;
249    var shouldBeInitialized = value[0] === undefined;
250    assertEquals(value, [ a = (initialized = true, initializer) ] = value);
251    assertEquals(expected, a);
252    assertEquals(shouldBeInitialized, initialized);
253
254    var initialized2 = false;
255    assertEquals(value, [ obj.a = (initialized2 = true, initializer) ] = value);
256    assertEquals(expected, obj.a);
257    assertEquals(shouldBeInitialized, initialized2);
258  }
259
260  test([], "BAM!", "BAM!");
261  test([], "BOOP!", "BOOP!");
262  test([null], 123, null);
263  test([undefined], 456, 456);
264  test([,], "PUPPIES", "PUPPIES");
265
266  (function accept_IN() {
267    var value = [], x;
268    assertEquals(value, [ x = 'x' in {} ] = value);
269    assertEquals(false, x);
270  })();
271
272  (function ordering() {
273    var x = 0, a, b, value = [];
274    assertEquals(value, [ a = x += 1, b = x *= 2 ] = value);
275    assertEquals(1, a);
276    assertEquals(2, b);
277    assertEquals(2, x);
278  })();
279
280  (function yieldExpression() {
281    var value = [], it, result, x;
282    it = (function*() {
283      result = [ x = yield ] = value;
284    })();
285    var next = it.next();
286
287    assertEquals(undefined, result);
288    assertEquals(undefined, next.value);
289    assertEquals(false, next.done);
290    assertEquals(undefined, x);
291
292    next = it.next(86);
293
294    assertEquals(value, result);
295    assertEquals(undefined, next.value);
296    assertEquals(true, next.done);
297    assertEquals(86, x);
298  })();
299
300  (function yieldIdentifier() {
301    var value = [], yield = "BOOP!", x;
302    assertEquals(value, [ x = yield ] = value);
303    assertEquals("BOOP!", x);
304  })();
305
306  assertThrows(function let_TDZ() {
307    "use strict";
308    var x;
309    [ x = y ] = [];
310    let y;
311  }, ReferenceError);
312})();
313
314
315(function testArrayElementNestedPattern() {
316  assertThrows(function nestedArrayRequireObjectCoercibleNull() {
317    var x; [ [ x ] ] = [ null ];
318  }, TypeError);
319
320  assertThrows(function nestedArrayRequireObjectCoercibleUndefined() {
321    var x; [ [ x ] ] = [ undefined ];
322  }, TypeError);
323
324  assertThrows(function nestedArrayRequireObjectCoercibleUndefined2() {
325    var x; [ [ x ] ] = [ ];
326  }, TypeError);
327
328  assertThrows(function nestedArrayRequireObjectCoercibleUndefined3() {
329    var x; [ [ x ] ] = [ , ];
330  }, TypeError);
331
332  assertThrows(function nestedObjectRequireObjectCoercibleNull() {
333    var x; [ { x } ] = [ null ];
334  }, TypeError);
335
336  assertThrows(function nestedObjectRequireObjectCoercibleUndefined() {
337    var x; [ { x } ] = [ undefined ];
338  }, TypeError);
339
340  assertThrows(function nestedObjectRequireObjectCoercibleUndefined2() {
341    var x; [ { x } ] = [ ];
342  }, TypeError);
343
344  assertThrows(function nestedObjectRequireObjectCoercibleUndefined3() {
345    var x; [ { x } ] = [ , ];
346  }, TypeError);
347
348  (function nestedArray() {
349    var x, value = [ [ "zap", "blonk" ] ];
350    assertEquals(value, [ [ , x ] ] = value);
351    assertEquals("blonk", x);
352  })();
353
354  (function nestedObject() {
355    var x, value = [ { a: "zap", b: "blonk" } ];
356    assertEquals(value, [ { b: x } ] = value);
357    assertEquals("blonk", x);
358  })();
359})();
360
361(function testArrayRestElement() {
362  (function testBasic() {
363    var x, rest, array = [1, 2, 3];
364    assertEquals(array, [x, ...rest] = array);
365    assertEquals(1, x);
366    assertEquals([2, 3], rest);
367
368    array = [4, 5, 6];
369    assertEquals(array, [, ...rest] = array);
370    assertEquals([5, 6], rest);
371
372  })();
373
374  (function testNestedRestObject() {
375    var value = [1, 2, 3], x;
376    assertEquals(value, [...{ 1: x }] = value);
377    assertEquals(2, x);
378  })();
379
380  (function iterable() {
381    var count = 0;
382    var x, y, z;
383    function* g() {
384      count++;
385      yield;
386      count++;
387      yield;
388      count++;
389      yield;
390    }
391    var it = g();
392    assertEquals(it, [...x] = it);
393    assertEquals([undefined, undefined, undefined], x);
394    assertEquals(3, count);
395
396    it = [g()];
397    assertEquals(it, [ [...y] ] = it);
398    assertEquals([undefined, undefined, undefined], y);
399    assertEquals(6, count);
400
401    it = { a: g() };
402    assertEquals(it, { a: [...z] } = it);
403    assertEquals([undefined, undefined, undefined], z);
404    assertEquals(9, count);
405  })();
406})();
407
408(function testRequireObjectCoercible() {
409  assertThrows(() => ({} = undefined), TypeError);
410  assertThrows(() => ({} = null), TypeError);
411  assertThrows(() => [] = undefined, TypeError);
412  assertThrows(() => [] = null, TypeError);
413  assertEquals("test", ({} = "test"));
414  assertEquals("test", [] = "test");
415  assertEquals(123, ({} = 123));
416})();
417
418(function testConstReassignment() {
419  "use strict";
420  const c = "untouchable";
421  assertThrows(() => { [ c ] = [ "nope!" ]; }, TypeError);
422  assertThrows(() => { [ [ c ] ]  = [ [ "nope!" ] ]; }, TypeError);
423  assertThrows(() => { [ { c } ]  = [ { c: "nope!" } ]; }, TypeError);
424  assertThrows(() => { ({ c } = { c: "nope!" }); }, TypeError);
425  assertThrows(() => { ({ a: { c } } = { a: { c: "nope!" } }); }, TypeError);
426  assertThrows(() => { ({ a: [ c ] } = { a: [ "nope!" ] }); }, TypeError);
427  assertEquals("untouchable", c);
428})();
429
430(function testForIn() {
431  var log = [];
432  var x = {};
433  var object = {
434    "Apenguin": 1,
435    "\u{1F382}cake": 2,
436    "Bpuppy": 3,
437    "Cspork": 4
438  };
439  for ([x.firstLetter, ...x.rest] in object) {
440    if (x.firstLetter === "A") {
441      assertEquals(["p", "e", "n", "g", "u", "i", "n"], x.rest);
442      continue;
443    }
444    if (x.firstLetter === "C") {
445      assertEquals(["s", "p", "o", "r", "k"], x.rest);
446      break;
447    }
448    log.push({ firstLetter: x.firstLetter, rest: x.rest });
449  }
450  assertEquals([
451    { firstLetter: "\u{1F382}", rest: ["c", "a", "k", "e"] },
452    { firstLetter: "B", rest: ["p", "u", "p", "p", "y"] },
453  ], log);
454})();
455
456(function testForOf() {
457  var log = [];
458  var x = {};
459  var names = [
460    "Apenguin",
461    "\u{1F382}cake",
462    "Bpuppy",
463    "Cspork"
464  ];
465  for ([x.firstLetter, ...x.rest] of names) {
466    if (x.firstLetter === "A") {
467      assertEquals(["p", "e", "n", "g", "u", "i", "n"], x.rest);
468      continue;
469    }
470    if (x.firstLetter === "C") {
471      assertEquals(["s", "p", "o", "r", "k"], x.rest);
472      break;
473    }
474    log.push({ firstLetter: x.firstLetter, rest: x.rest });
475  }
476  assertEquals([
477    { firstLetter: "\u{1F382}", rest: ["c", "a", "k", "e"] },
478    { firstLetter: "B", rest: ["p", "u", "p", "p", "y"] },
479  ], log);
480})();
481