8134986917
Implements the change proposed at https://github.com/tc39/ecma262/pull/593. In summary, Object.getOwnPropertyDescriptors can produce results which cause Object.defineProperties() to throw, by inserting a property with an undefined descriptor into the result object. This change to the algorithm requires that the descriptor only be added to the result object if it is not undefined. BUG=v8:4725 R=littledan@chromium.org, adamk@chromium.org, jwolfe@igalia.com Review-Url: https://codereview.chromium.org/2118613003 Cr-Commit-Position: refs/heads/master@{#37504}
236 lines
5.3 KiB
JavaScript
236 lines
5.3 KiB
JavaScript
// Copyright 2016 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.
|
|
|
|
// Flags: --harmony-object-own-property-descriptors
|
|
// Flags: --allow-natives-syntax
|
|
|
|
function DataDescriptor(value) {
|
|
return { "enumerable": true, "configurable": true, "writable": true, value };
|
|
}
|
|
|
|
|
|
function TestMeta() {
|
|
assertEquals(1, Object.getOwnPropertyDescriptors.length);
|
|
assertEquals(Function.prototype,
|
|
Object.getPrototypeOf(Object.getOwnPropertyDescriptors));
|
|
assertEquals(
|
|
'getOwnPropertyDescriptors', Object.getOwnPropertyDescriptors.name);
|
|
var desc = Reflect.getOwnPropertyDescriptor(
|
|
Object, 'getOwnPropertyDescriptors');
|
|
assertFalse(desc.enumerable);
|
|
assertTrue(desc.writable);
|
|
assertTrue(desc.configurable);
|
|
}
|
|
TestMeta();
|
|
|
|
|
|
function TestToObject() {
|
|
assertThrows(function() {
|
|
Object.getOwnPropertyDescriptors(null);
|
|
}, TypeError);
|
|
|
|
assertThrows(function() {
|
|
Object.getOwnPropertyDescriptors(undefined);
|
|
}, TypeError);
|
|
|
|
assertThrows(function() {
|
|
Object.getOwnPropertyDescriptors();
|
|
}, TypeError);
|
|
}
|
|
TestToObject();
|
|
|
|
|
|
function TestPrototypeProperties() {
|
|
function F() {};
|
|
F.prototype.a = "A";
|
|
F.prototype.b = "B";
|
|
|
|
var F2 = new F();
|
|
Object.defineProperties(F2, {
|
|
"b": {
|
|
enumerable: false,
|
|
configurable: true,
|
|
writable: false,
|
|
value: "Shadowed 'B'"
|
|
},
|
|
"c": {
|
|
enumerable: false,
|
|
configurable: true,
|
|
writable: false,
|
|
value: "C"
|
|
}
|
|
});
|
|
|
|
assertEquals({
|
|
"b": {
|
|
enumerable: false,
|
|
configurable: true,
|
|
writable: false,
|
|
value: "Shadowed 'B'"
|
|
},
|
|
"c": {
|
|
enumerable: false,
|
|
configurable: true,
|
|
writable: false,
|
|
value: "C"
|
|
}
|
|
}, Object.getOwnPropertyDescriptors(F2));
|
|
}
|
|
TestPrototypeProperties();
|
|
|
|
|
|
function TestPrototypeProperties() {
|
|
function F() {};
|
|
F.prototype.a = "A";
|
|
F.prototype.b = "B";
|
|
|
|
var F2 = new F();
|
|
Object.defineProperties(F2, {
|
|
"b": {
|
|
enumerable: false,
|
|
configurable: true,
|
|
writable: false,
|
|
value: "Shadowed 'B'"
|
|
},
|
|
"c": {
|
|
enumerable: false,
|
|
configurable: true,
|
|
writable: false,
|
|
value: "C"
|
|
}
|
|
});
|
|
|
|
assertEquals({
|
|
"b": {
|
|
enumerable: false,
|
|
configurable: true,
|
|
writable: false,
|
|
value: "Shadowed 'B'"
|
|
},
|
|
"c": {
|
|
enumerable: false,
|
|
configurable: true,
|
|
writable: false,
|
|
value: "C"
|
|
}
|
|
}, Object.getOwnPropertyDescriptors(F2));
|
|
}
|
|
TestPrototypeProperties();
|
|
|
|
|
|
function TestTypeFilteringAndOrder() {
|
|
var log = [];
|
|
var sym = Symbol("foo");
|
|
var psym = %CreatePrivateSymbol("private");
|
|
var O = {
|
|
0: 0,
|
|
[sym]: 3,
|
|
"a": 2,
|
|
[psym]: 4,
|
|
1: 1,
|
|
};
|
|
var P = new Proxy(O, {
|
|
ownKeys(target) {
|
|
log.push("ownKeys()");
|
|
return Reflect.ownKeys(target);
|
|
},
|
|
getOwnPropertyDescriptor(target, name) {
|
|
log.push(`getOwnPropertyDescriptor(${String(name)})`);
|
|
return Reflect.getOwnPropertyDescriptor(target, name);
|
|
},
|
|
get(target, name) { assertUnreachable(); },
|
|
set(target, name, value) { assertUnreachable(); },
|
|
deleteProperty(target, name) { assertUnreachable(); },
|
|
defineProperty(target, name, desc) { assertUnreachable(); }
|
|
});
|
|
|
|
var result1 = Object.getOwnPropertyDescriptors(O);
|
|
assertEquals({
|
|
0: DataDescriptor(0),
|
|
1: DataDescriptor(1),
|
|
"a": DataDescriptor(2),
|
|
[sym]: DataDescriptor(3)
|
|
}, result1);
|
|
|
|
var result2 = Object.getOwnPropertyDescriptors(P);
|
|
assertEquals([
|
|
"ownKeys()",
|
|
"getOwnPropertyDescriptor(0)",
|
|
"getOwnPropertyDescriptor(1)",
|
|
"getOwnPropertyDescriptor(a)",
|
|
"getOwnPropertyDescriptor(Symbol(foo))"
|
|
], log);
|
|
assertEquals({
|
|
0: DataDescriptor(0),
|
|
1: DataDescriptor(1),
|
|
"a": DataDescriptor(2),
|
|
[sym]: DataDescriptor(3)
|
|
}, result2);
|
|
}
|
|
TestTypeFilteringAndOrder();
|
|
|
|
|
|
function TestDuplicateKeys() {
|
|
var i = 0;
|
|
var log = [];
|
|
var P = new Proxy({}, {
|
|
ownKeys() {
|
|
log.push(`ownKeys()`);
|
|
return ["A", "A"];
|
|
},
|
|
getOwnPropertyDescriptor(t, name) {
|
|
log.push(`getOwnPropertyDescriptor(${name})`);
|
|
if (i++) return;
|
|
return {
|
|
configurable: true,
|
|
writable: false,
|
|
value: "VALUE"
|
|
};
|
|
},
|
|
get(target, name) { assertUnreachable(); },
|
|
set(target, name, value) { assertUnreachable(); },
|
|
deleteProperty(target, name) { assertUnreachable(); },
|
|
defineProperty(target, name, desc) { assertUnreachable(); }
|
|
});
|
|
|
|
var result = Object.getOwnPropertyDescriptors(P);
|
|
assertEquals({
|
|
"A": {
|
|
"value": "VALUE",
|
|
"writable": false,
|
|
"enumerable": false,
|
|
"configurable": true
|
|
}
|
|
}, result);
|
|
assertTrue(result.hasOwnProperty("A"));
|
|
assertEquals([
|
|
"ownKeys()",
|
|
"getOwnPropertyDescriptor(A)",
|
|
"getOwnPropertyDescriptor(A)"
|
|
], log);
|
|
}
|
|
TestDuplicateKeys();
|
|
|
|
function TestFakeProperty() {
|
|
var log = [];
|
|
var P = new Proxy({}, {
|
|
ownKeys() {
|
|
log.push(`ownKeys()`);
|
|
return ["fakeProperty"];
|
|
},
|
|
getOwnPropertyDescriptor(target, name) {
|
|
log.push(`getOwnPropertyDescriptor(${name})`);
|
|
return;
|
|
}
|
|
});
|
|
var result = Object.getOwnPropertyDescriptors(P);
|
|
assertEquals({}, result);
|
|
assertFalse(result.hasOwnProperty("fakeProperty"));
|
|
assertEquals([
|
|
"ownKeys()",
|
|
"getOwnPropertyDescriptor(fakeProperty)"
|
|
], log);
|
|
}
|
|
TestFakeProperty();
|