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// Based on Mozilla Object.assign() tests
6
7function checkDataProperty(object, propertyKey, value, writable, enumerable, configurable) {
8  var desc = Object.getOwnPropertyDescriptor(object, propertyKey);
9  assertFalse(desc === undefined);
10  assertTrue('value' in desc);
11  assertEquals(desc.value, value);
12  assertEquals(desc.writable, writable);
13  assertEquals(desc.enumerable, enumerable);
14  assertEquals(desc.configurable, configurable);
15}
16
17// 19.1.2.1 Object.assign ( target, ...sources )
18assertEquals(Object.assign.length, 2);
19
20// Basic functionality works with multiple sources
21(function basicMultipleSources() {
22  var a = {};
23  var b = { bProp: 1 };
24  var c = { cProp: 2 };
25  Object.assign(a, b, c);
26  assertEquals(a, {
27    bProp: 1,
28    cProp: 2
29  });
30})();
31
32// Basic functionality works with symbols
33(function basicSymbols() {
34  var a = {};
35  var b = { bProp: 1 };
36  var aSymbol = Symbol("aSymbol");
37  b[aSymbol] = 2;
38  Object.assign(a, b);
39  assertEquals(1, a.bProp);
40  assertEquals(2, a[aSymbol]);
41})();
42
43// Dies if target is null or undefined
44assertThrows(function() { return Object.assign(null, null); }, TypeError);
45assertThrows(function() { return Object.assign(null, {}); }, TypeError);
46assertThrows(function() { return Object.assign(undefined); }, TypeError);
47assertThrows(function() { return Object.assign(); }, TypeError);
48
49// Calls ToObject for target
50assertTrue(Object.assign(true, {}) instanceof Boolean);
51assertTrue(Object.assign(1, {}) instanceof Number);
52assertTrue(Object.assign("string", {}) instanceof String);
53var o = {};
54assertSame(Object.assign(o, {}), o);
55
56// Only [[Enumerable]] properties are assigned to target
57(function onlyEnumerablePropertiesAssigned() {
58  var source = Object.defineProperties({}, {
59    a: {value: 1, enumerable: true},
60    b: {value: 2, enumerable: false},
61  });
62  var target = Object.assign({}, source);
63  assertTrue("a" in target);
64  assertFalse("b" in target);
65})();
66
67// Properties are retrieved through Get()
68// Properties are assigned through Put()
69(function testPropertiesAssignedThroughPut() {
70  var setterCalled = false;
71  Object.assign({set a(v) { setterCalled = v }}, {a: true});
72  assertTrue(setterCalled);
73})();
74
75// Properties are retrieved through Get()
76// Properties are assigned through Put(): Existing property attributes are not altered
77(function propertiesAssignedExistingNotAltered() {
78  var source = {a: 1, b: 2, c: 3};
79  var target = {a: 0, b: 0, c: 0};
80  Object.defineProperty(target, "a", {enumerable: false});
81  Object.defineProperty(target, "b", {configurable: false});
82  Object.defineProperty(target, "c", {enumerable: false, configurable: false});
83  Object.assign(target, source);
84  checkDataProperty(target, "a", 1, true, false, true);
85  checkDataProperty(target, "b", 2, true, true, false);
86  checkDataProperty(target, "c", 3, true, false, false);
87})();
88
89// Properties are retrieved through Get()
90// Properties are assigned through Put(): Throws TypeError if non-writable
91(function propertiesAssignedTypeErrorNonWritable() {
92  var source = {a: 1};
93  var target = {a: 0};
94  Object.defineProperty(target, "a", {writable: false});
95  assertThrows(function() { return Object.assign(target, source); }, TypeError);
96  checkDataProperty(target, "a", 0, false, true, true);
97})();
98
99// Properties are retrieved through Get()
100// Put() creates standard properties; Property attributes from source are
101// ignored
102(function createsStandardProperties() {
103  var source = {a: 1, b: 2, c: 3, get d() { return 4 }};
104  Object.defineProperty(source, "b", {writable: false});
105  Object.defineProperty(source, "c", {configurable: false});
106  var target = Object.assign({}, source);
107  checkDataProperty(target, "a", 1, true, true, true);
108  checkDataProperty(target, "b", 2, true, true, true);
109  checkDataProperty(target, "c", 3, true, true, true);
110  checkDataProperty(target, "d", 4, true, true, true);
111})();
112
113// Properties created during traversal are not copied
114(function propertiesCreatedDuringTraversalNotCopied() {
115  var source = {get a() { this.b = 2 }};
116  var target = Object.assign({}, source);
117  assertTrue("a" in target);
118  assertFalse("b" in target);
119})();
120
121// String and Symbol valued properties are copied
122(function testStringAndSymbolPropertiesCopied() {
123  var keyA = "str-prop";
124  var source = {"str-prop": 1};
125  var target = Object.assign({}, source);
126  checkDataProperty(target, keyA, 1, true, true, true);
127})();
128
129(function testExceptionsStopFirstException() {
130  var ErrorA = function ErrorA() {};
131  var ErrorB = function ErrorB() {};
132  var log = "";
133  var source = { b: 1, a: 1 };
134  var target = {
135      set a(v) { log += "a"; throw new ErrorA },
136      set b(v) { log += "b"; throw new ErrorB },
137  };
138  assertThrows(function() { return Object.assign(target, source); }, ErrorB);
139  assertEquals(log, "b");
140})();
141