Checkpoint before integration and package validation. Assisted-by: SurmAgent:unknown [read] [edit] [bash]
75 lines
3.5 KiB
JavaScript
75 lines
3.5 KiB
JavaScript
import { assert, assertArrayEquals, assertThrows } from "./assert.js";
|
|
|
|
/* The post-trap invariant checks of the proxy [[DefineOwnProperty]],
|
|
[[GetOwnProperty]] and [[HasProperty]] internal methods must obtain the
|
|
target's extensibility through IsExtensible(). When the target is itself a
|
|
proxy that is observable: its isExtensible trap runs, and it can throw. */
|
|
|
|
function innerProxy(target, isExtensible) {
|
|
return new Proxy(target, { isExtensible });
|
|
}
|
|
|
|
/* A non-callable isExtensible trap on the target proxy must surface as a
|
|
TypeError instead of being silently ignored. */
|
|
assertThrows(TypeError, () => Reflect.defineProperty(
|
|
new Proxy(innerProxy({}, 0), { defineProperty: () => true }), "x", {}));
|
|
|
|
/* IsExtensible(target) is performed whether or not the target already has
|
|
the property. */
|
|
assertThrows(TypeError, () => Reflect.defineProperty(
|
|
new Proxy(innerProxy({ x: 1 }, 0), { defineProperty: () => true }), "x", {}));
|
|
|
|
assertThrows(TypeError, () => Reflect.getOwnPropertyDescriptor(
|
|
new Proxy(innerProxy({ x: 1 }, 0), { getOwnPropertyDescriptor: () => undefined }), "x"));
|
|
|
|
assertThrows(TypeError, () => Reflect.has(
|
|
new Proxy(innerProxy({ x: 1 }, 0), { has: () => false }), "x"));
|
|
|
|
/* An isExtensible trap that lies about an extensible target is rejected. */
|
|
assertThrows(TypeError, () => Reflect.defineProperty(
|
|
new Proxy(innerProxy({}, () => false), { defineProperty: () => true }), "x", {}));
|
|
|
|
/* An exception thrown by the trap propagates unchanged. */
|
|
for (const op of [
|
|
(p) => Reflect.defineProperty(new Proxy(p, { defineProperty: () => true }), "x", {}),
|
|
(p) => Reflect.getOwnPropertyDescriptor(new Proxy(p, { getOwnPropertyDescriptor: () => undefined }), "x"),
|
|
(p) => Reflect.has(new Proxy(p, { has: () => false }), "x"),
|
|
]) {
|
|
assertThrows(RangeError, () => op(innerProxy({ x: 1 }, () => { throw new RangeError(); })));
|
|
}
|
|
|
|
/* A well-behaved target proxy still allows the operations to complete, and the
|
|
traps are called in the order the spec prescribes: [[GetOwnProperty]] on the
|
|
target first, then IsExtensible(target). */
|
|
function trapLog(target, op, expected) {
|
|
const log = [];
|
|
const p = new Proxy(target, {
|
|
getOwnPropertyDescriptor(t, k) { log.push("gOPD"); return Reflect.getOwnPropertyDescriptor(t, k); },
|
|
isExtensible(t) { log.push("isExtensible"); return Reflect.isExtensible(t); },
|
|
});
|
|
assert(op(p), expected);
|
|
return log;
|
|
}
|
|
|
|
assertArrayEquals(trapLog({ x: 1 }, (p) => Reflect.defineProperty(
|
|
new Proxy(p, { defineProperty: () => true }), "x", { value: 2 }), true), ["gOPD", "isExtensible"]);
|
|
|
|
assertArrayEquals(trapLog({ x: 1 }, (p) => Reflect.getOwnPropertyDescriptor(
|
|
new Proxy(p, { getOwnPropertyDescriptor: () => undefined }), "x"), undefined), ["gOPD", "isExtensible"]);
|
|
|
|
assertArrayEquals(trapLog({ x: 1 }, (p) => Reflect.has(
|
|
new Proxy(p, { has: () => false }), "x"), false), ["gOPD", "isExtensible"]);
|
|
|
|
/* When the property is absent from the target, the configurability check
|
|
cannot fail, so [[HasProperty]] and [[GetOwnProperty]] stop before
|
|
IsExtensible(). [[DefineOwnProperty]] always performs it. */
|
|
assertArrayEquals(trapLog({}, (p) => Reflect.has(
|
|
new Proxy(p, { has: () => false }), "x"), false), ["gOPD"]);
|
|
|
|
assertArrayEquals(trapLog({}, (p) => Reflect.getOwnPropertyDescriptor(
|
|
new Proxy(p, { getOwnPropertyDescriptor: () => undefined }), "x"), undefined), ["gOPD"]);
|
|
|
|
assertArrayEquals(trapLog({}, (p) => Reflect.defineProperty(
|
|
new Proxy(p, { defineProperty: () => true }), "x", { value: 1 }), true), ["gOPD", "isExtensible"]);
|
|
|