Attachment #8470375: assign_test_review_changes_20140808.patch for bug #937855

View | Details | Raw Unified | Return to bug 937855
Collapse All | Expand All

(-)a/js/src/tests/ecma_6/Object/assign.js (+331 lines)
Line     Link Here 
Line 0    Link Here 
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
function checkDataProperty(object, propertyKey, value, writable, enumerable, configurable) {
6
    var desc = Object.getOwnPropertyDescriptor(object, propertyKey);
7
    assertEq(desc === undefined, false);
8
    assertEq('value' in desc, true);
9
    assertEq(desc.value, value);
10
    assertEq(desc.writable, writable);
11
    assertEq(desc.enumerable, enumerable);
12
    assertEq(desc.configurable, configurable);
13
}
14
15
/* 19.1.2.1  Object.assign ( target, ...sources ) */
16
assertEq(Object.assign.length, 2);
17
18
// Basic functionality works with multiple sources
19
function basicMultipleSources() {
20
    var a = {};
21
    var b = { bProp : 7 };
22
    var c = { cProp : 8 };
23
    Object.assign(a, b, c);
24
    assertEq(a.bProp, 7);
25
    assertEq(a.cProp, 8);
26
}
27
basicMultipleSources();
28
29
// Calls ToObject() for target and source
30
function testToObject() {
31
    assertThrowsInstanceOf(() => Object.assign(null, null), TypeError);
32
    assertThrowsInstanceOf(() => Object.assign(), TypeError);
33
    assertThrowsInstanceOf(() => Object.assign(null, {}), TypeError);
34
    assertThrowsInstanceOf(() => Object.assign({}, null), TypeError);
35
    assertEq(Object.assign(true, {}) instanceof Boolean, true);
36
    assertEq(Object.assign(1, {}) instanceof Number, true);
37
    assertEq(Object.assign("string", {}) instanceof String, true);
38
    var o = {};
39
    assertEq(Object.assign(o, {}), o);
40
}
41
testToObject();
42
43
// Invokes [[OwnPropertyKeys]] on ToObject(source)
44
function testOwnPropertyKeys() {
45
    assertThrowsInstanceOf(() => Object.assign(null, new Proxy({}, {
46
        getOwnPropertyNames: () => { throw new Error("not called"); }
47
    })), TypeError);
48
49
    var ownKeysCalled = false;
50
    Object.assign({}, new Proxy({}, {
51
        ownKeys: function() {
52
            ownKeysCalled = true;
53
            return [];
54
        }
55
    }));
56
    assertEq(ownKeysCalled, true);
57
};
58
testOwnPropertyKeys();
59
60
// Ensure correct property traversal
61
function correctPropertyTraversal() {
62
    var log = "";
63
    var source = new Proxy({a: 1, b: 2}, {
64
        ownKeys: () => ["b", "c", "a"],
65
        getOwnPropertyDescriptor: function(t, pk) {
66
            log += "#" + pk;
67
            return Object.getOwnPropertyDescriptor(t, pk);
68
        },
69
        get: function(t, pk, r) {
70
            log += "-" + pk;
71
            return t[pk];
72
        },
73
    });
74
    Object.assign({}, source);
75
    assertEq(log, "#b-b#c#a-a");
76
}
77
correctPropertyTraversal();
78
79
// Only [[Enumerable]] properties are assigned to target
80
function onlyEnumerablePropertiesAssigned() {
81
    var source = Object.defineProperties({}, {
82
        a: {value: 1, enumerable: true},
83
        b: {value: 2, enumerable: false},
84
    });
85
    var target = Object.assign({}, source);
86
    assertEq("a" in target, true);
87
    assertEq("b" in target, false);
88
}
89
onlyEnumerablePropertiesAssigned();
90
91
92
// Enumerability is decided on-time, not before main loop (1)
93
function testEnumerabilityDeterminedInLoop1()
94
{
95
    var getterCalled = false;
96
    var sourceTarget = {
97
        get a() { getterCalled = true },
98
        get b() { Object.defineProperty(sourceTarget, "a", {enumerable: false}) },
99
    };
100
    var source = new Proxy(sourceTarget, { ownKeys: () => ["b", "a"] });
101
    Object.assign({}, source);
102
    assertEq(getterCalled, false);
103
}
104
testEnumerabilityDeterminedInLoop1();
105
106
// Enumerability is decided on-time, not before main loop (2)
107
function testEnumerabilityDeterminedInLoop2()
108
{
109
    var getterCalled = false;
110
    var sourceTarget = {
111
        get a() { getterCalled = true },
112
        get b() { Object.defineProperty(sourceTarget, "a", {enumerable: true}) },
113
    };
114
    var source = new Proxy(sourceTarget, {
115
        ownKeys: () => ["b", "a"]
116
    });
117
    Object.defineProperty(sourceTarget, "a", {enumerable: false});
118
    Object.assign({}, source);
119
    assertEq(getterCalled, true);
120
}
121
testEnumerabilityDeterminedInLoop2();
122
123
// Properties are retrieved through Get() and assigned onto
124
// the target as data properties, not in any sense cloned over as descriptors
125
function testPropertiesRetrievedThroughGet() {
126
    var getterCalled = false;
127
    Object.assign({}, {get a() { getterCalled = true }});
128
    assertEq(getterCalled, true);
129
}
130
testPropertiesRetrievedThroughGet();
131
132
// Properties are retrieved through Get()
133
// Properties are assigned through Put()
134
function testPropertiesAssignedThroughPut() {
135
    var setterCalled = false;
136
    Object.assign({set a(v) { setterCalled = v }}, {a: true});
137
    assertEq(setterCalled, true);
138
}
139
testPropertiesAssignedThroughPut();
140
141
// Properties are retrieved through Get()
142
// Properties are assigned through Put(): Existing property attributes are not altered
143
function propertiesAssignedExistingNotAltered() {
144
    var source = {a: 1, b: 2, c: 3};
145
    var target = {a: 0, b: 0, c: 0};
146
    Object.defineProperty(target, "a", {enumerable: false});
147
    Object.defineProperty(target, "b", {configurable: false});
148
    Object.defineProperty(target, "c", {enumerable: false, configurable: false});
149
    Object.assign(target, source);
150
    checkDataProperty(target, "a", 1, true, false, true);
151
    checkDataProperty(target, "b", 2, true, true, false);
152
    checkDataProperty(target, "c", 3, true, false, false);
153
}
154
propertiesAssignedExistingNotAltered();
155
156
// Properties are retrieved through Get()
157
// Properties are assigned through Put(): Throws TypeError if non-writable
158
function propertiesAssignedTypeErrorNonWritable() {
159
    var source = {a: 1};
160
    var target = {a: 0};
161
    Object.defineProperty(target, "a", {writable: false});
162
    assertThrowsInstanceOf(() => Object.assign(target, source), TypeError);
163
    checkDataProperty(target, "a", 0, false, true, true);
164
}
165
propertiesAssignedTypeErrorNonWritable();
166
167
// Properties are retrieved through Get()
168
// Put() creates standard properties; Property attributes from source are ignored
169
function createsStandardProperties() {
170
    var source = {a: 1, b: 2, c: 3, get d() { return 4 }};
171
    Object.defineProperty(source, "b", {writable: false});
172
    Object.defineProperty(source, "c", {configurable: false});
173
    var target = Object.assign({}, source);
174
    checkDataProperty(target, "a", 1, true, true, true);
175
    checkDataProperty(target, "b", 2, true, true, true);
176
    checkDataProperty(target, "c", 3, true, true, true);
177
    checkDataProperty(target, "d", 4, true, true, true);
178
}
179
createsStandardProperties();
180
181
// Properties created during traversal are not copied
182
function propertiesCreatedDuringTraversalNotCopied() {
183
    var source = {get a() { this.b = 2 }};
184
    var target = Object.assign({}, source);
185
    assertEq("a" in target, true);
186
    assertEq("b" in target, false);
187
}
188
propertiesCreatedDuringTraversalNotCopied();
189
190
// Properties deleted during traversal are not copied
191
function testDeletePropertiesNotCopied() {
192
    var source = new Proxy({
193
        get a() { delete this.b },
194
        b: 2,
195
    }, {
196
        getOwnPropertyNames: () => ["a", "b"]
197
    });
198
    var target = Object.assign({}, source);
199
    assertEq("a" in target, true);
200
    assertEq("b" in target, false);
201
}
202
testDeletePropertiesNotCopied();
203
204
function testDeletionExposingShadowedProperty()
205
{
206
    var srcProto = { b: 42 };
207
    var src =
208
        Object.create(srcProto,
209
                        { a: { enumerable: true, get: function() { delete this.b; } },
210
                          b: { value: 2, configurable: true, enumerable: true } });
211
    var source = new Proxy(src, { getOwnPropertyNames: () => ["a", "b"] });
212
    var target = Object.assign({}, source);
213
    assertEq("a" in target, true);
214
    assertEq("b" in target, false);
215
}
216
testDeletionExposingShadowedProperty();
217
218
// Properties first deleted and then recreated during traversal are copied (1)
219
function testDeletedAndRecreatedPropertiesCopied1() {
220
    var source = new Proxy({
221
        get a() { delete this.c },
222
        get b() { this.c = 4 },
223
        c: 3,
224
    }, {
225
        getOwnPropertyNames: () => ["a", "b", "c"]
226
    });
227
    var target = Object.assign({}, source);
228
    assertEq("a" in target, true);
229
    assertEq("b" in target, true);
230
    assertEq("c" in target, true);
231
    checkDataProperty(target, "c", 4, true, true, true);
232
}
233
testDeletedAndRecreatedPropertiesCopied1();
234
235
// Properties first deleted and then recreated during traversal are copied (2)
236
function testDeletedAndRecreatedPropertiesCopied2() {
237
    var source = new Proxy({
238
        get a() { delete this.c },
239
        get b() { this.c = 4 },
240
        c: 3,
241
    }, {
242
        ownKeys: () => ["a", "c", "b"]
243
    });
244
    var target = Object.assign({}, source);
245
    assertEq("a" in target, true);
246
    assertEq("b" in target, true);
247
    assertEq("c" in target, false);
248
}
249
testDeletedAndRecreatedPropertiesCopied2();
250
251
// String and Symbol valued properties are copied
252
function testStringAndSymbolPropertiesCopied() {
253
    var keyA = "str-prop";
254
    var source = {"str-prop": 1};
255
    var target = Object.assign({}, source);
256
    checkDataProperty(target, keyA, 1, true, true, true);
257
}
258
testStringAndSymbolPropertiesCopied();
259
260
// Intermediate exceptions do not stop property traversal, first exception is reported (1)
261
function testExceptionsDoNotStopFirstReported1() {
262
    var ErrorA = function ErrorA() {};
263
    var ErrorB = function ErrorB() {};
264
    var log = "";
265
    var source = new Proxy({}, {
266
        getOwnPropertyDescriptor: function(t, pk) {
267
            log += pk;
268
            throw new (pk === "a" ? ErrorA : ErrorB);
269
        },
270
        ownKeys: () => ["b", "a"]
271
    });
272
    assertThrowsInstanceOf(() => Object.assign({}, source), ErrorB);
273
    assertEq(log, "ba");
274
}
275
testExceptionsDoNotStopFirstReported1();
276
277
// Properties are retrieved through Get()
278
// Intermediate exceptions do not stop property traversal, first exception is reported (2)
279
function testExceptionsDoNotStopFirstReported2() {
280
    var ErrorA = function ErrorA() {};
281
    var ErrorB = function ErrorB() {};
282
    var log = "";
283
    var source = new Proxy({
284
        get a() { log += "a"; throw new ErrorA },
285
        get b() { log += "b"; throw new ErrorB },
286
    }, {
287
        ownKeys: () => ["b", "a"]
288
    });
289
    assertThrowsInstanceOf(() => Object.assign({}, source), ErrorB);
290
    assertEq(log, "ba");
291
}
292
testExceptionsDoNotStopFirstReported2();
293
294
// Intermediate exceptions do not stop property traversal, first exception is reported (3)
295
function testExceptionsDoNotStopFirstReported3() {
296
    var ErrorA = function ErrorA() {};
297
    var ErrorB = function ErrorB() {};
298
    var log = "";
299
    var source = new Proxy({a: 1, b: 2}, {
300
        ownKeys: () => ["b", "a"]
301
    });
302
    var target = {
303
        set a(v) { log += "a"; throw new ErrorA },
304
        set b(v) { log += "b"; throw new ErrorB },
305
    };
306
    assertThrowsInstanceOf(() => Object.assign(target, source), ErrorB);
307
    assertEq(log, "ba");
308
}
309
testExceptionsDoNotStopFirstReported3();
310
311
// Intermediate exceptions do not stop property traversal, first exception is reported (4)
312
function testExceptionsDoNotStopFirstReported4() {
313
    var ErrorGetOwnProperty = function ErrorGetOwnProperty() {};
314
    var ErrorGet = function ErrorGet() {};
315
    var ErrorSet = function ErrorSet() {};
316
    var source = new Proxy({
317
        get a() { throw new ErrorGet }
318
    }, {
319
        getOwnPropertyDescriptor: function(t, pk) {
320
            throw new ErrorGetOwnProperty;
321
        }
322
    });
323
    var target = {
324
        set a(v) { throw new ErrorSet }
325
    };
326
    assertThrowsInstanceOf(() => Object.assign({}, source), ErrorGetOwnProperty);
327
}
328
testExceptionsDoNotStopFirstReported4();
329
330
if (typeof reportCompare == "function")
331
    reportCompare(true, true);

Return to bug 937855