| // 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); | 
 |   } | 
 |  | 
 | })(); |