diff options
Diffstat (limited to 'js/src/tests/non262/Reflect/defineProperty.js')
-rw-r--r-- | js/src/tests/non262/Reflect/defineProperty.js | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/js/src/tests/non262/Reflect/defineProperty.js b/js/src/tests/non262/Reflect/defineProperty.js new file mode 100644 index 0000000000..1f299f4e85 --- /dev/null +++ b/js/src/tests/non262/Reflect/defineProperty.js @@ -0,0 +1,164 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ */ + +// Reflect.defineProperty defines properties. +var obj = {}; +assertEq(Reflect.defineProperty(obj, "x", {value: 7}), true); +assertEq(obj.x, 7); +var desc = Reflect.getOwnPropertyDescriptor(obj, "x"); +assertDeepEq(desc, {value: 7, + writable: false, + enumerable: false, + configurable: false}); + +// Reflect.defineProperty can define a symbol-keyed property. +var key = Symbol(":o)"); +assertEq(Reflect.defineProperty(obj, key, {value: 8}), true); +assertEq(obj[key], 8); + +// array .length property +obj = [1, 2, 3, 4, 5]; +assertEq(Reflect.defineProperty(obj, "length", {value: 4}), true); +assertDeepEq(obj, [1, 2, 3, 4]); + +// The target can be a proxy. +obj = {}; +var proxy = new Proxy(obj, { + defineProperty(t, id, desc) { + t[id] = 1; + return true; + } +}); +assertEq(Reflect.defineProperty(proxy, "prop", {value: 7}), true); +assertEq(obj.prop, 1); +assertEq(delete obj.prop, true); +assertEq("prop" in obj, false); + +// The attributes object is re-parsed, not passed through to the +// handler.defineProperty method. +obj = {}; +var attributes = { + configurable: 17, + enumerable: undefined, + value: null +}; +proxy = new Proxy(obj, { + defineProperty(t, id, desc) { + assertEq(desc !== attributes, true); + assertEq(desc.configurable, true); + assertEq(desc.enumerable, false); + assertEq(desc.value, null); + assertEq("writable" in desc, false); + return 15; // and the return value here is coerced to boolean + } +}); +assertEq(Reflect.defineProperty(proxy, "prop", attributes), true); + + +// === Failure and error cases +// +// Reflect.defineProperty behaves much like Object.defineProperty, which has +// extremely thorough tests elsewhere, and the implementation is largely +// shared. Duplicating those tests with Reflect.defineProperty would be a +// big waste. +// +// However, certain failures cause Reflect.defineProperty to return false +// without throwing a TypeError (unlike Object.defineProperty). So here we test +// many error cases to check that behavior. + +// missing attributes argument +assertThrowsInstanceOf(() => Reflect.defineProperty(obj, "y"), + TypeError); + +// non-object attributes argument +for (var attributes of SOME_PRIMITIVE_VALUES) { + assertThrowsInstanceOf(() => Reflect.defineProperty(obj, "y", attributes), + TypeError); +} + +// inextensible object +obj = Object.preventExtensions({}); +assertEq(Reflect.defineProperty(obj, "prop", {value: 4}), false); + +// inextensible object with irrelevant inherited property +obj = Object.preventExtensions(Object.create({"prop": 3})); +assertEq(Reflect.defineProperty(obj, "prop", {value: 4}), false); + +// redefine nonconfigurable to configurable +obj = Object.freeze({prop: 1}); +assertEq(Reflect.defineProperty(obj, "prop", {configurable: true}), false); + +// redefine enumerability of nonconfigurable property +obj = Object.freeze(Object.defineProperties({}, { + x: {enumerable: true, configurable: false, value: 0}, + y: {enumerable: false, configurable: false, value: 0}, +})); +assertEq(Reflect.defineProperty(obj, "x", {enumerable: false}), false); +assertEq(Reflect.defineProperty(obj, "y", {enumerable: true}), false); + +// redefine nonconfigurable data to accessor property, or vice versa +obj = Object.seal({x: 1, get y() { return 2; }}); +assertEq(Reflect.defineProperty(obj, "x", {get() { return 2; }}), false); +assertEq(Reflect.defineProperty(obj, "y", {value: 1}), false); + +// redefine nonwritable, nonconfigurable property as writable +obj = Object.freeze({prop: 0}); +assertEq(Reflect.defineProperty(obj, "prop", {writable: true}), false); +assertEq(Reflect.defineProperty(obj, "prop", {writable: false}), true); // no-op + +// change value of nonconfigurable nonwritable property +obj = Object.freeze({prop: 0}); +assertEq(Reflect.defineProperty(obj, "prop", {value: -0}), false); +assertEq(Reflect.defineProperty(obj, "prop", {value: +0}), true); // no-op + +// change getter or setter +function g() {} +function s(x) {} +obj = {}; +Object.defineProperty(obj, "prop", {get: g, set: s, configurable: false}); +assertEq(Reflect.defineProperty(obj, "prop", {get: s}), false); +assertEq(Reflect.defineProperty(obj, "prop", {get: g}), true); // no-op +assertEq(Reflect.defineProperty(obj, "prop", {set: g}), false); +assertEq(Reflect.defineProperty(obj, "prop", {set: s}), true); // no-op + +// Proxy defineProperty handler method that returns false +var falseValues = [false, 0, -0, "", NaN, null, undefined]; +if (typeof createIsHTMLDDA === "function") + falseValues.push(createIsHTMLDDA()); +var value; +proxy = new Proxy({}, { + defineProperty(t, id, desc) { + return value; + } +}); +for (value of falseValues) { + assertEq(Reflect.defineProperty(proxy, "prop", {value: 1}), false); +} + +// Proxy defineProperty handler method returns true, in violation of invariants. +// Per spec, this is a TypeError, not a false return. +obj = Object.freeze({x: 1}); +proxy = new Proxy(obj, { + defineProperty(t, id, desc) { + return true; + } +}); +assertThrowsInstanceOf(() => Reflect.defineProperty(proxy, "x", {value: 2}), TypeError); +assertThrowsInstanceOf(() => Reflect.defineProperty(proxy, "y", {value: 0}), TypeError); +assertEq(Reflect.defineProperty(proxy, "x", {value: 1}), true); + +// The second argument is converted ToPropertyKey before any internal methods +// are called on the first argument. +var poison = + (counter => new Proxy({}, new Proxy({}, { get() { throw counter++; } })))(42); +assertThrowsValue(() => { + Reflect.defineProperty(poison, { + toString() { throw 17; }, + valueOf() { throw 8675309; } + }, poison); +}, 17); + + +// For more Reflect.defineProperty tests, see target.js and propertyKeys.js. + +reportCompare(0, 0); |