// Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // script-level tests var ox, oy = {}, oz; ({ x: ox, y: oy.value, y2: oy["value2"], z: ({ set v(val) { oz = val; } }).v } = { x: "value of x", y: "value of y1", y2: "value of y2", z: "value of z" }); assertEquals("value of x", ox); assertEquals("value of y1", oy.value); assertEquals("value of y2", oy.value2); assertEquals("value of z", oz); [ox, oy.value, oy["value2"], ...{ set v(val) { oz = val; } }.v] = [ 1007, 798432, 555, 1, 2, 3, 4, 5 ]; assertEquals(ox, 1007); assertEquals(oy.value, 798432); assertEquals(oy.value2, 555); assertEquals(oz, [1, 2, 3, 4, 5]); (function testInFunction() { var x, y = {}, z; ({ x: x, y: y.value, y2: y["value2"], z: ({ set v(val) { z = val; } }).v } = { x: "value of x", y: "value of y1", y2: "value of y2", z: "value of z" }); assertEquals("value of x", x); assertEquals("value of y1", y.value); assertEquals("value of y2", y.value2); assertEquals("value of z", z); [x, y.value, y["value2"], ...{ set v(val) { z = val; } }.v] = [ 1007, 798432, 555, 1, 2, 3, 4, 5 ]; assertEquals(x, 1007); assertEquals(y.value, 798432); assertEquals(y.value2, 555); assertEquals(z, [1, 2, 3, 4, 5]); })(); (function testArrowFunctionInitializers() { var fn = (config = { value: defaults.value, nada: { nada: defaults.nada } = { nada: "nothing" } } = { value: "BLAH" }) => config; var defaults = {}; assertEquals({ value: "BLAH" }, fn()); assertEquals("BLAH", defaults.value); assertEquals("nothing", defaults.nada); })(); (function testArrowFunctionInitializers2() { var fn = (config = [ defaults.value, { nada: defaults.nada } = { nada: "nothing" } ] = ["BLAH"]) => config; var defaults = {}; assertEquals(["BLAH"], fn()); assertEquals("BLAH", defaults.value); assertEquals("nothing", defaults.nada); })(); (function testFunctionInitializers() { function fn(config = { value: defaults.value, nada: { nada: defaults.nada } = { nada: "nothing" } } = { value: "BLAH" }) { return config; } var defaults = {}; assertEquals({ value: "BLAH" }, fn()); assertEquals("BLAH", defaults.value); assertEquals("nothing", defaults.nada); })(); (function testFunctionInitializers2() { function fn(config = [ defaults.value, { nada: defaults.nada } = { nada: "nothing" } ] = ["BLAH"]) { return config; } var defaults = {}; assertEquals(["BLAH"], fn()); assertEquals("BLAH", defaults.value); assertEquals("nothing", defaults.nada); })(); (function testDeclarationInitializers() { var defaults = {}; var { value } = { value: defaults.value } = { value: "BLAH" }; assertEquals("BLAH", value); assertEquals("BLAH", defaults.value); })(); (function testDeclarationInitializers2() { var defaults = {}; var [value] = [defaults.value] = ["BLAH"]; assertEquals("BLAH", value); assertEquals("BLAH", defaults.value); })(); (function testObjectLiteralProperty() { var ext = {}; var obj = { a: { b: ext.b, c: ext["c"], d: { set v(val) { ext.d = val; } }.v } = { b: "b", c: "c", d: "d" } }; assertEquals({ b: "b", c: "c", d: "d" }, ext); assertEquals({ a: { b: "b", c: "c", d: "d" } }, obj); })(); (function testArrayLiteralProperty() { var ext = {}; var obj = [ ...[ ext.b, ext["c"], { set v(val) { ext.d = val; } }.v ] = [ "b", "c", "d" ] ]; assertEquals({ b: "b", c: "c", d: "d" }, ext); assertEquals([ "b", "c", "d" ], obj); })(); // TODO(caitp): add similar test for ArrayPatterns, once Proxies support // delegating symbol-keyed get/set. (function testObjectPatternOperationOrder() { var steps = []; var store = {}; function computePropertyName(name) { steps.push("compute name: " + name); return name; } function loadValue(descr, value) { steps.push("load: " + descr + " > " + value); return value; } function storeValue(descr, name, value) { steps.push("store: " + descr + " = " + value); store[name] = value; } var result = { get a() { assertUnreachable(); }, set a(value) { storeValue("result.a", "a", value); }, get b() { assertUnreachable(); }, set b(value) { storeValue("result.b", "b", value); } }; ({ obj: { x: result.a = 10, [computePropertyName("y")]: result.b = false, } = {} } = { obj: { get x() { return loadValue(".temp.obj.x", undefined); }, set x(value) { assertUnreachable(); }, get y() { return loadValue(".temp.obj.y", undefined); }, set y(value) { assertUnreachable(); } }}); assertPropertiesEqual({ a: 10, b: false }, store); assertArrayEquals([ "load: .temp.obj.x > undefined", "store: result.a = 10", "compute name: y", "load: .temp.obj.y > undefined", "store: result.b = false" ], steps); steps = []; ({ obj: { x: result.a = 50, [computePropertyName("y")]: result.b = "hello", } = {} } = { obj: { get x() { return loadValue(".temp.obj.x", 20); }, set x(value) { assertUnreachable(); }, get y() { return loadValue(".temp.obj.y", true); }, set y(value) { assertUnreachable(); } }}); assertPropertiesEqual({ a: 20, b: true }, store); assertArrayEquals([ "load: .temp.obj.x > 20", "store: result.a = 20", "compute name: y", "load: .temp.obj.y > true", "store: result.b = true", ], steps); })(); // Credit to Mike Pennisi and other Test262 contributors for originally writing // the testse the following are based on. (function testArrayElision() { var value = [1, 2, 3, 4, 5, 6, 7, 8, 9]; var a, obj = {}; var result = [, a, , obj.b, , ...obj["rest"]] = value; assertEquals(result, value); assertEquals(2, a); assertEquals(4, obj.b); assertArrayEquals([6, 7, 8, 9], obj.rest); })(); (function testArrayElementInitializer() { function test(value, initializer, expected) { var a, obj = {}; var initialized = false; var shouldBeInitialized = value[0] === undefined; assertEquals(value, [ a = (initialized = true, initializer) ] = value); assertEquals(expected, a); assertEquals(shouldBeInitialized, initialized); var initialized2 = false; assertEquals(value, [ obj.a = (initialized2 = true, initializer) ] = value); assertEquals(expected, obj.a); assertEquals(shouldBeInitialized, initialized2); } test([], "BAM!", "BAM!"); test([], "BOOP!", "BOOP!"); test([null], 123, null); test([undefined], 456, 456); test([,], "PUPPIES", "PUPPIES"); (function accept_IN() { var value = [], x; assertEquals(value, [ x = 'x' in {} ] = value); assertEquals(false, x); })(); (function ordering() { var x = 0, a, b, value = []; assertEquals(value, [ a = x += 1, b = x *= 2 ] = value); assertEquals(1, a); assertEquals(2, b); assertEquals(2, x); })(); (function yieldExpression() { var value = [], it, result, x; it = (function*() { result = [ x = yield ] = value; })(); var next = it.next(); assertEquals(undefined, result); assertEquals(undefined, next.value); assertEquals(false, next.done); assertEquals(undefined, x); next = it.next(86); assertEquals(value, result); assertEquals(undefined, next.value); assertEquals(true, next.done); assertEquals(86, x); })(); (function yieldIdentifier() { var value = [], yield = "BOOP!", x; assertEquals(value, [ x = yield ] = value); assertEquals("BOOP!", x); })(); assertThrows(function let_TDZ() { "use strict"; var x; [ x = y ] = []; let y; }, ReferenceError); })(); (function testArrayElementNestedPattern() { assertThrows(function nestedArrayRequireObjectCoercibleNull() { var x; [ [ x ] ] = [ null ]; }, TypeError); assertThrows(function nestedArrayRequireObjectCoercibleUndefined() { var x; [ [ x ] ] = [ undefined ]; }, TypeError); assertThrows(function nestedArrayRequireObjectCoercibleUndefined2() { var x; [ [ x ] ] = [ ]; }, TypeError); assertThrows(function nestedArrayRequireObjectCoercibleUndefined3() { var x; [ [ x ] ] = [ , ]; }, TypeError); assertThrows(function nestedObjectRequireObjectCoercibleNull() { var x; [ { x } ] = [ null ]; }, TypeError); assertThrows(function nestedObjectRequireObjectCoercibleUndefined() { var x; [ { x } ] = [ undefined ]; }, TypeError); assertThrows(function nestedObjectRequireObjectCoercibleUndefined2() { var x; [ { x } ] = [ ]; }, TypeError); assertThrows(function nestedObjectRequireObjectCoercibleUndefined3() { var x; [ { x } ] = [ , ]; }, TypeError); (function nestedArray() { var x, value = [ [ "zap", "blonk" ] ]; assertEquals(value, [ [ , x ] ] = value); assertEquals("blonk", x); })(); (function nestedObject() { var x, value = [ { a: "zap", b: "blonk" } ]; assertEquals(value, [ { b: x } ] = value); assertEquals("blonk", x); })(); })(); (function testArrayRestElement() { (function testBasic() { var x, rest, array = [1, 2, 3]; assertEquals(array, [x, ...rest] = array); assertEquals(1, x); assertEquals([2, 3], rest); array = [4, 5, 6]; assertEquals(array, [, ...rest] = array); assertEquals([5, 6], rest); })(); (function testNestedRestObject() { var value = [1, 2, 3], x; assertEquals(value, [...{ 1: x }] = value); assertEquals(2, x); })(); (function iterable() { var count = 0; var x, y, z; function* g() { count++; yield; count++; yield; count++; yield; } var it = g(); assertEquals(it, [...x] = it); assertEquals([undefined, undefined, undefined], x); assertEquals(3, count); it = [g()]; assertEquals(it, [ [...y] ] = it); assertEquals([undefined, undefined, undefined], y); assertEquals(6, count); it = { a: g() }; assertEquals(it, { a: [...z] } = it); assertEquals([undefined, undefined, undefined], z); assertEquals(9, count); })(); })(); (function testRequireObjectCoercible() { assertThrows(() => ({} = undefined), TypeError); assertThrows(() => ({} = null), TypeError); assertThrows(() => [] = undefined, TypeError); assertThrows(() => [] = null, TypeError); assertEquals("test", ({} = "test")); assertEquals("test", [] = "test"); assertEquals(123, ({} = 123)); })(); (function testConstReassignment() { "use strict"; const c = "untouchable"; assertThrows(() => { [ c ] = [ "nope!" ]; }, TypeError); assertThrows(() => { [ [ c ] ] = [ [ "nope!" ] ]; }, TypeError); assertThrows(() => { [ { c } ] = [ { c: "nope!" } ]; }, TypeError); assertThrows(() => { ({ c } = { c: "nope!" }); }, TypeError); assertThrows(() => { ({ a: { c } } = { a: { c: "nope!" } }); }, TypeError); assertThrows(() => { ({ a: [ c ] } = { a: [ "nope!" ] }); }, TypeError); assertEquals("untouchable", c); })(); (function testForIn() { var log = []; var x = {}; var object = { "Apenguin": 1, "\u{1F382}cake": 2, "Bpuppy": 3, "Cspork": 4 }; for ([x.firstLetter, ...x.rest] in object) { if (x.firstLetter === "A") { assertEquals(["p", "e", "n", "g", "u", "i", "n"], x.rest); continue; } if (x.firstLetter === "C") { assertEquals(["s", "p", "o", "r", "k"], x.rest); break; } log.push({ firstLetter: x.firstLetter, rest: x.rest }); } assertEquals([ { firstLetter: "\u{1F382}", rest: ["c", "a", "k", "e"] }, { firstLetter: "B", rest: ["p", "u", "p", "p", "y"] }, ], log); })(); (function testForOf() { var log = []; var x = {}; var names = [ "Apenguin", "\u{1F382}cake", "Bpuppy", "Cspork" ]; for ([x.firstLetter, ...x.rest] of names) { if (x.firstLetter === "A") { assertEquals(["p", "e", "n", "g", "u", "i", "n"], x.rest); continue; } if (x.firstLetter === "C") { assertEquals(["s", "p", "o", "r", "k"], x.rest); break; } log.push({ firstLetter: x.firstLetter, rest: x.rest }); } assertEquals([ { firstLetter: "\u{1F382}", rest: ["c", "a", "k", "e"] }, { firstLetter: "B", rest: ["p", "u", "p", "p", "y"] }, ], log); })(); (function testNewTarget() { assertThrows("(function() { [...new.target] = []; })", SyntaxError); assertThrows("(function() { [a] = [...new.target] = []; })", SyntaxError); assertThrows("(function() { [new.target] = []; })", SyntaxError); assertThrows("(function() { [a] = [new.target] = []; })", SyntaxError); assertThrows("(function() { ({ a: new.target] = {a: 0}); })", SyntaxError); assertThrows("(function() { ({ a } = { a: new.target } = {}); })", SyntaxError); function ReturnNewTarget1() { var result; [result = new.target] = []; return result; } function ReturnNewTarget2() { var result; [result] = [new.target]; return result; } function ReturnNewTarget3() { var result; ({ result = new.target } = {}); return result; } function ReturnNewTarget4() { var result; ({ result } = { result: new.target }); return result; } function FakeNewTarget() {} function construct() { assertEquals(undefined, ReturnNewTarget1()); assertEquals(ReturnNewTarget1, new ReturnNewTarget1()); assertEquals(FakeNewTarget, Reflect.construct(ReturnNewTarget1, [], FakeNewTarget)); assertEquals(undefined, ReturnNewTarget2()); assertEquals(ReturnNewTarget2, new ReturnNewTarget2()); assertEquals(FakeNewTarget, Reflect.construct(ReturnNewTarget2, [], FakeNewTarget)); assertEquals(undefined, ReturnNewTarget3()); assertEquals(ReturnNewTarget3, new ReturnNewTarget3()); assertEquals(FakeNewTarget, Reflect.construct(ReturnNewTarget3, [], FakeNewTarget)); assertEquals(undefined, ReturnNewTarget4()); assertEquals(ReturnNewTarget4, new ReturnNewTarget4()); assertEquals(FakeNewTarget, Reflect.construct(ReturnNewTarget4, [], FakeNewTarget)); } construct(); FakeNewTarget.prototype = 1; construct(); })(); (function testSuperCall() { function ctor(body) { return () => eval("(class extends Object { \n" + " constructor() {\n" + body + "\n }\n" + "})"); } assertThrows(ctor("({ new: super() } = {})"), SyntaxError); assertThrows(ctor("({ new: x } = { new: super() } = {})"), SyntaxError); assertThrows(ctor("[super()] = []"), SyntaxError); assertThrows(ctor("[x] = [super()] = []"), SyntaxError); assertThrows(ctor("[...super()] = []"), SyntaxError); assertThrows(ctor("[x] = [...super()] = []"), SyntaxError); class Base { get foo() { return 1; } } function ext(body) { return eval("new (class extends Base {\n" + " constructor() {\n" + body + ";\n" + " return { x: super.foo }" + "\n }\n" + "})"); } assertEquals(1, ext("let x; [x = super()] = []").x); assertEquals(1, ext("let x, y; [y] = [x = super()] = []").x); assertEquals(1, ext("let x; [x] = [super()]").x); assertEquals(1, ext("let x, y; [y] = [x] = [super()]").x); assertEquals(1, ext("let x; ({x = super()} = {})").x); assertEquals(1, ext("let x, y; ({ x: y } = { x = super() } = {})").x); assertEquals(1, ext("let x; ({x} = { x: super() })").x); assertEquals(1, ext("let x, y; ({ x: y } = { x } = { x: super() })").x); })(); (function testInvalidReturn() { function* g() { yield 1; } let executed_x_setter; let executed_return; var a = { set x(val) { executed_x_setter = true; throw 3; } }; // The exception from the execution of g().return() should be suppressed by // the setter error. executed_x_setter = false; executed_return = false; g.prototype.return = function() { executed_return = true; throw 4; }; assertThrowsEquals("[a.x] = g()", 3); assertTrue(executed_x_setter); assertTrue(executed_return); // The exception from g().return() not returning an object should be // suppressed by the setter error. executed_x_setter = false; executed_return = false; g.prototype.return = function() { assertTrue(executed_return); return null; }; assertThrowsEquals("[a.x] = g()", 3); assertTrue(executed_x_setter); assertTrue(executed_return); // The TypeError from g().return not being a method should suppress the setter // error. executed_x_setter = false; g.prototype.return = "not a method"; assertThrows("[a.x] = g()", TypeError); assertTrue(executed_x_setter); // The exception from the access of g().return should suppress the setter // error. executed_x_setter = false; Object.setPrototypeOf(g.prototype, { get return() { throw 4; } }); assertThrowsEquals("[a.x] = g()", 4); assertTrue(executed_x_setter); })