// Copyright 2014 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. // Based on Mozilla Object.assign() tests // Flags: --allow-natives-syntax function checkDataProperty(object, propertyKey, value, writable, enumerable, configurable) { var desc = Object.getOwnPropertyDescriptor(object, propertyKey); assertFalse(desc === undefined); assertTrue('value' in desc); assertEquals(desc.value, value); assertEquals(desc.writable, writable); assertEquals(desc.enumerable, enumerable); assertEquals(desc.configurable, configurable); } // 19.1.2.1 Object.assign ( target, ...sources ) assertEquals(Object.assign.length, 2); // Basic functionality works with multiple sources (function basicMultipleSources() { var a = {}; var b = { bProp: 1 }; var c = { cProp: 2 }; Object.assign(a, b, c); assertEquals(a, { bProp: 1, cProp: 2 }); })(); // Basic functionality works with symbols (function basicSymbols() { var a = {}; var b = { bProp: 1 }; var aSymbol = Symbol("aSymbol"); b[aSymbol] = 2; Object.assign(a, b); assertEquals(1, a.bProp); assertEquals(2, a[aSymbol]); })(); // Dies if target is null or undefined assertThrows(function() { return Object.assign(null, null); }, TypeError); assertThrows(function() { return Object.assign(null, {}); }, TypeError); assertThrows(function() { return Object.assign(undefined); }, TypeError); assertThrows(function() { return Object.assign(); }, TypeError); // Calls ToObject for target assertTrue(Object.assign(true, {}) instanceof Boolean); assertTrue(Object.assign(1, {}) instanceof Number); assertTrue(Object.assign("string", {}) instanceof String); var o = {}; assertSame(Object.assign(o, {}), o); // Only [[Enumerable]] properties are assigned to target (function onlyEnumerablePropertiesAssigned() { var source = Object.defineProperties({}, { a: {value: 1, enumerable: true}, b: {value: 2, enumerable: false}, }); var target = Object.assign({}, source); assertTrue("a" in target); assertFalse("b" in target); })(); // Properties are retrieved through Get() // Properties are assigned through Put() (function testPropertiesAssignedThroughPut() { var setterCalled = false; Object.assign({set a(v) { setterCalled = v }}, {a: true}); assertTrue(setterCalled); })(); // Properties are retrieved through Get() // Properties are assigned through Put(): Existing property attributes are not altered (function propertiesAssignedExistingNotAltered() { var source = {a: 1, b: 2, c: 3}; var target = {a: 0, b: 0, c: 0}; Object.defineProperty(target, "a", {enumerable: false}); Object.defineProperty(target, "b", {configurable: false}); Object.defineProperty(target, "c", {enumerable: false, configurable: false}); Object.assign(target, source); checkDataProperty(target, "a", 1, true, false, true); checkDataProperty(target, "b", 2, true, true, false); checkDataProperty(target, "c", 3, true, false, false); })(); // Properties are retrieved through Get() // Properties are assigned through Put(): Throws TypeError if non-writable (function propertiesAssignedTypeErrorNonWritable() { var source = {a: 1}; var target = {a: 0}; Object.defineProperty(target, "a", {writable: false}); assertThrows(function() { return Object.assign(target, source); }, TypeError); checkDataProperty(target, "a", 0, false, true, true); })(); // Properties are retrieved through Get() // Put() creates standard properties; Property attributes from source are // ignored (function createsStandardProperties() { var source = {a: 1, b: 2, c: 3, get d() { return 4 }}; Object.defineProperty(source, "b", {writable: false}); Object.defineProperty(source, "c", {configurable: false}); var target = Object.assign({}, source); checkDataProperty(target, "a", 1, true, true, true); checkDataProperty(target, "b", 2, true, true, true); checkDataProperty(target, "c", 3, true, true, true); checkDataProperty(target, "d", 4, true, true, true); })(); // Properties created during traversal are not copied (function propertiesCreatedDuringTraversalNotCopied() { var source = {get a() { this.b = 2 }}; var target = Object.assign({}, source); assertTrue("a" in target); assertFalse("b" in target); })(); // String and Symbol valued properties are copied (function testStringAndSymbolPropertiesCopied() { var keyA = "str-prop"; var source = {"str-prop": 1}; var target = Object.assign({}, source); checkDataProperty(target, keyA, 1, true, true, true); })(); (function testExceptionsStopFirstException() { var ErrorA = function ErrorA() {}; var ErrorB = function ErrorB() {}; var log = ""; var source = { b: 1, a: 1 }; var target = { set a(v) { log += "a"; throw new ErrorA }, set b(v) { log += "b"; throw new ErrorB }, }; assertThrows(function() { return Object.assign(target, source); }, ErrorB); assertEquals(log, "b"); })(); (function add_to_source() { var target = {set k1(v) { source.k3 = 100; }}; var source = {k1:10}; Object.defineProperty(source, "k2", {value: 20, enumerable: false, configurable: true}); Object.assign(target, source); assertEquals(undefined, target.k2); assertEquals(undefined, target.k3); })(); (function reconfigure_enumerable_source() { var target = {set k1(v) { Object.defineProperty(source, "k2", {value: 20, enumerable: true}); }}; var source = {k1:10}; Object.defineProperty(source, "k2", {value: 20, enumerable: false, configurable: true}); Object.assign(target, source); assertEquals(20, target.k2); })(); (function propagate_assign_failure() { var target = {set k1(v) { throw "fail" }}; var source = {k1:10}; assertThrows(()=>Object.assign(target, source)); })(); (function propagate_read_failure() { var target = {}; var source = {get k1() { throw "fail" }}; assertThrows(()=>Object.assign(target, source)); })(); (function strings_and_symbol_order1() { // first order var log = []; var sym1 = Symbol("x"), sym2 = Symbol("y"); var source = { get [sym1](){ log.push("get sym1"); }, get a() { log.push("get a"); }, get b() { log.push("get b"); }, get c() { log.push("get c"); }, get [sym2](){ log.push("get sym2"); }, }; Object.assign({}, source); assertEquals(log, ["get a", "get b", "get c", "get sym1", "get sym2"]); })(); (function strings_and_symbol_order2() { // first order var log = []; var sym1 = Symbol("x"), sym2 = Symbol("y"); var source = { get [sym1](){ log.push("get sym1"); }, get a() { log.push("get a"); }, get [sym2](){ log.push("get sym2"); }, get b() { log.push("get b"); }, get c() { log.push("get c"); }, }; Object.assign({}, source); assertEquals(log, ["get a", "get b", "get c", "get sym1", "get sym2"]); })(); (function strings_and_symbol_order3() { // first order var log = []; var sym1 = Symbol("x"), sym2 = Symbol("y"); var source = { get a() { log.push("get a"); }, get [sym1](){ log.push("get sym1"); }, get b() { log.push("get b"); }, get [sym2](){ log.push("get sym2"); }, get c() { log.push("get c"); }, }; Object.assign({}, source); assertEquals(log, ["get a", "get b", "get c", "get sym1", "get sym2"]); })(); (function proxy() { const fast_source = { key1: "value1", key2: "value2"}; const slow_source = {__proto__:null}; for (let i = 0; i < 2000; i++) { slow_source["key" + i] = i; } const empty_handler = {}; let target = {}; let proxy = new Proxy(target, empty_handler); assertArrayEquals(Object.keys(target), []); let result = Object.assign(proxy, fast_source); %HeapObjectVerify(result); assertArrayEquals(Object.keys(result), Object.keys(target)); assertArrayEquals(Object.keys(result), Object.keys(fast_source)); assertArrayEquals(Object.values(result), Object.values(fast_source)); target = {}; proxy = new Proxy(target, empty_handler); assertArrayEquals(Object.keys(target), []); result = Object.assign(proxy, slow_source); %HeapObjectVerify(result); assertEquals(Object.keys(result).length, Object.keys(target).length); assertEquals(Object.keys(result).length, Object.keys(slow_source).length); })(); (function global_object() { let source = { global1: "global1", get global2() { return "global2" }, }; let result = Object.assign(globalThis, source); %HeapObjectVerify(result); assertTrue(result === globalThis); assertTrue(result.global1 === source.global1); assertTrue(result.global2 === source.global2); let target = {}; result = Object.assign(target, globalThis); %HeapObjectVerify(result); assertTrue(result === target); assertTrue(result.global1 === source.global1); assertTrue(result.global2 === source.global2); for (let i = 0; i < 2000; i++) { source["property" + i] = i; } result = Object.assign(globalThis, source); %HeapObjectVerify(result); assertTrue(result === globalThis); for (let i = 0; i < 2000; i++) { const key = "property" + i; assertEquals(result[key], i); } })();