mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:07:47 +00:00
LibJS: Add Proxy objects
Includes all traps except the following: [[Call]], [[Construct]], [[OwnPropertyKeys]]. An important implication of this commit is that any call to any virtual Object method has the potential to throw an exception. These methods were not checked in this commit -- a future commit will have to protect these various method calls throughout the codebase.
This commit is contained in:
parent
58a72e9b81
commit
39ad42defd
29 changed files with 1697 additions and 54 deletions
|
@ -23,7 +23,13 @@ try {
|
|||
o.baz = "baz";
|
||||
assert(o.baz === undefined);
|
||||
|
||||
Object.defineProperty(o, "baz", { value: "baz" });
|
||||
assertThrowsError(() => {
|
||||
Object.defineProperty(o, "baz", { value: "baz" });
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Unable to define property on non-extensible object",
|
||||
});
|
||||
|
||||
assert(o.baz === undefined);
|
||||
|
||||
assertThrowsError(() => {
|
||||
|
|
|
@ -4,12 +4,19 @@ try {
|
|||
assert(Object.setPrototypeOf.length === 2);
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.setPrototypeOf({}, "foo");
|
||||
Object.setPrototypeOf();
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Prototype must be null or object"
|
||||
message: "Object.setPrototypeOf requires at least two arguments",
|
||||
});
|
||||
|
||||
// assertThrowsError(() => {
|
||||
// Object.setPrototypeOf({}, "foo");
|
||||
// }, {
|
||||
// error: TypeError,
|
||||
// message: "Prototype must be null or object"
|
||||
// });
|
||||
|
||||
o = {};
|
||||
p = {};
|
||||
assert(Object.setPrototypeOf(o, p) === o);
|
||||
|
@ -19,7 +26,7 @@ try {
|
|||
Object.setPrototypeOf(o, {});
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Can't set prototype of non-extensible object"
|
||||
message: "Object's setPrototypeOf method returned false"
|
||||
});
|
||||
assert(Object.setPrototypeOf(o, p) === o);
|
||||
|
||||
|
|
107
Libraries/LibJS/Tests/Proxy.handler-defineProperty.js
Normal file
107
Libraries/LibJS/Tests/Proxy.handler-defineProperty.js
Normal file
|
@ -0,0 +1,107 @@
|
|||
load("test-common.js");
|
||||
|
||||
try {
|
||||
let p = new Proxy({}, { defineProperty: null });
|
||||
assert(Object.defineProperty(p, "foo", {}) === p);
|
||||
p = new Proxy({}, { defineProperty: undefined });
|
||||
assert(Object.defineProperty(p, "foo", {}) === p);
|
||||
p = new Proxy({}, {});
|
||||
assert(Object.defineProperty(p, "foo", {}) == p);
|
||||
|
||||
let o = {};
|
||||
p = new Proxy(o, {
|
||||
defineProperty(target, name, descriptor) {
|
||||
assert(target === o);
|
||||
assert(name === "foo");
|
||||
assert(descriptor.configurable === true);
|
||||
assert(descriptor.enumerable === undefined);
|
||||
assert(descriptor.writable === true);
|
||||
assert(descriptor.value === 10);
|
||||
assert(descriptor.get === undefined);
|
||||
assert(descriptor.set === undefined);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(p, "foo", { configurable: true, writable: true, value: 10 });
|
||||
|
||||
p = new Proxy(o, {
|
||||
defineProperty(target, name, descriptor) {
|
||||
if (target[name] === undefined)
|
||||
Object.defineProperty(target, name, descriptor);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(p, "foo", { value: 10, enumerable: true, configurable: false, writable: true });
|
||||
let d = Object.getOwnPropertyDescriptor(p, "foo");
|
||||
assert(d.enumerable === true);
|
||||
assert(d.configurable === false);
|
||||
assert(d.writable === true);
|
||||
assert(d.value === 10);
|
||||
assert(d.get === undefined);
|
||||
assert(d.set === undefined);
|
||||
|
||||
Object.defineProperty(p, "foo", { value: 20, enumerable: true, configurable: false, writable: true });
|
||||
d = Object.getOwnPropertyDescriptor(p, "foo");
|
||||
assert(d.enumerable === true);
|
||||
assert(d.configurable === false);
|
||||
assert(d.writable === true);
|
||||
assert(d.value === 10);
|
||||
assert(d.get === undefined);
|
||||
assert(d.set === undefined);
|
||||
|
||||
|
||||
// Invariants
|
||||
|
||||
p = new Proxy({}, {
|
||||
defineProperty() { return false; }
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.defineProperty(p, "foo", {});
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's defineProperty method returned false",
|
||||
});
|
||||
|
||||
o = {};
|
||||
Object.preventExtensions(o);
|
||||
p = new Proxy(o, {
|
||||
defineProperty() {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
assertThrowsError(() => {
|
||||
Object.defineProperty(p, "foo", {});
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's defineProperty trap violates invariant: a property cannot be reported as being defined if the property does not exist on the target and the target is non-extensible",
|
||||
});
|
||||
|
||||
o = {};
|
||||
Object.defineProperty(o, "foo", { value: 10, configurable: true });
|
||||
p = new Proxy(o, {
|
||||
defineProperty() {
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.defineProperty(p, "bar", { value: 6, configurable: false });
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's defineProperty trap violates invariant: a property cannot be defined as non-configurable if it does not already exist on the target object",
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.defineProperty(p, "foo", { value: 6, configurable: false });
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's defineProperty trap violates invariant: a property cannot be defined as non-configurable if it already exists on the target object as a configurable property",
|
||||
});
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
56
Libraries/LibJS/Tests/Proxy.handler-deleteProperty.js
Normal file
56
Libraries/LibJS/Tests/Proxy.handler-deleteProperty.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
load("test-common.js");
|
||||
|
||||
try {
|
||||
assert(delete (new Proxy({}, { deleteProperty: undefined })).foo === true);
|
||||
assert(delete (new Proxy({}, { deleteProperty: null })).foo === true);
|
||||
assert(delete (new Proxy({}, {})).foo === true);
|
||||
|
||||
let o = {};
|
||||
let p = new Proxy(o, {
|
||||
deleteProperty(target, property) {
|
||||
assert(target === o);
|
||||
assert(property === "foo");
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
delete p.foo;
|
||||
|
||||
o = { foo: 1, bar: 2 };
|
||||
p = new Proxy(o, {
|
||||
deleteProperty(target, property) {
|
||||
if (property === "foo") {
|
||||
delete target[property];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
assert(delete p.foo === true);
|
||||
assert(delete p.bar === false);
|
||||
|
||||
assert(o.foo === undefined);
|
||||
assert(o.bar === 2);
|
||||
|
||||
// Invariants
|
||||
|
||||
o = {};
|
||||
Object.defineProperty(o, "foo", { configurable: false });
|
||||
p = new Proxy(o, {
|
||||
deleteProperty() {
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
delete p.foo;
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's delete trap violates invariant: cannot report a non-configurable own property of the target as deleted",
|
||||
});
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
71
Libraries/LibJS/Tests/Proxy.handler-get.js
Normal file
71
Libraries/LibJS/Tests/Proxy.handler-get.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
load("test-common.js");
|
||||
|
||||
try {
|
||||
assert((new Proxy({}, { get: undefined })).foo === undefined);
|
||||
assert((new Proxy({}, { get: null })).foo === undefined);
|
||||
assert((new Proxy({}, {})).foo === undefined);
|
||||
|
||||
let o = {};
|
||||
let p = new Proxy(o, {
|
||||
get(target, property, receiver) {
|
||||
assert(target === o);
|
||||
assert(property === "foo");
|
||||
assert(receiver === p);
|
||||
},
|
||||
});
|
||||
|
||||
p.foo;
|
||||
|
||||
o = { foo: 1 };
|
||||
p = new Proxy(o, {
|
||||
get(target, property, receiver) {
|
||||
if (property === "bar") {
|
||||
return 2;
|
||||
} else if (property === "baz") {
|
||||
return receiver.qux;
|
||||
} else if (property === "qux") {
|
||||
return 3;
|
||||
}
|
||||
return target[property];
|
||||
}
|
||||
});
|
||||
|
||||
assert(p.foo === 1);
|
||||
assert(p.bar === 2);
|
||||
assert(p.baz === 3);
|
||||
assert(p.qux === 3);
|
||||
assert(p.test === undefined);
|
||||
|
||||
// Invariants
|
||||
|
||||
o = {};
|
||||
Object.defineProperty(o, "foo", { value: 5, configurable: false, writable: true });
|
||||
Object.defineProperty(o, "bar", { value: 10, configurable: false, writable: false });
|
||||
|
||||
p = new Proxy(o, {
|
||||
get() {
|
||||
return 8;
|
||||
},
|
||||
});
|
||||
|
||||
assert(p.foo === 8);
|
||||
|
||||
assertThrowsError(() => {
|
||||
p.bar;
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's get trap violates invariant: the returned value must match the value on the target if the property exists on the target as a non-writable, non-configurable own data property",
|
||||
});
|
||||
|
||||
Object.defineProperty(o, "baz", { configurable: false, set(_) {} });
|
||||
assertThrowsError(() => {
|
||||
p.baz;
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's get trap violates invariant: the returned value must be undefined if the property exists on the target as a non-configurable accessor property with an undefined get attribute",
|
||||
});
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
159
Libraries/LibJS/Tests/Proxy.handler-getOwnPropertyDescriptor.js
Normal file
159
Libraries/LibJS/Tests/Proxy.handler-getOwnPropertyDescriptor.js
Normal file
|
@ -0,0 +1,159 @@
|
|||
load("test-common.js");
|
||||
|
||||
try {
|
||||
assert(Object.getOwnPropertyDescriptor(new Proxy({}, { getOwnPropertyDescriptor: null }), "a") === undefined);
|
||||
assert(Object.getOwnPropertyDescriptor(new Proxy({}, { getOwnPropertyDescriptor: undefined }), "a") === undefined);
|
||||
assert(Object.getOwnPropertyDescriptor(new Proxy({}, {}), "a") === undefined);
|
||||
|
||||
let o = {};
|
||||
let p = new Proxy(o, {
|
||||
getOwnPropertyDescriptor(target, property) {
|
||||
assert(target === o);
|
||||
assert(property === "foo");
|
||||
}
|
||||
});
|
||||
|
||||
Object.getOwnPropertyDescriptor(p, "foo");
|
||||
|
||||
o = { foo: "bar" };
|
||||
Object.defineProperty(o, "baz", { value: "qux", enumerable: false, configurable: true, writable: false });
|
||||
p = new Proxy(o, {
|
||||
getOwnPropertyDescriptor(target, property) {
|
||||
if (property === "baz")
|
||||
return Object.getOwnPropertyDescriptor(target, "baz");
|
||||
return { value: target[property], enumerable: false, configurable: true, writable: true };
|
||||
}
|
||||
});
|
||||
|
||||
let d = Object.getOwnPropertyDescriptor(p, "baz");
|
||||
assert(d.configurable === true);
|
||||
assert(d.enumerable === false);
|
||||
assert(d.writable === false);
|
||||
assert(d.value === "qux");
|
||||
assert(d.get === undefined);
|
||||
assert(d.set === undefined);
|
||||
|
||||
d = Object.getOwnPropertyDescriptor(p, "foo");
|
||||
assert(d.configurable === true);
|
||||
assert(d.enumerable === false);
|
||||
assert(d.writable === true);
|
||||
assert(d.value === "bar");
|
||||
assert(d.get === undefined);
|
||||
assert(d.set === undefined);
|
||||
|
||||
// Invariants
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.getOwnPropertyDescriptor(new Proxy({}, {
|
||||
getOwnPropertyDescriptor: 1
|
||||
}));
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's getOwnPropertyDescriptor trap wasn't undefined, null, or callable",
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.getOwnPropertyDescriptor(new Proxy({}, {
|
||||
getOwnPropertyDescriptor() {
|
||||
return 1;
|
||||
},
|
||||
}));
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's getOwnPropertyDescriptor trap violates invariant: must return an object or undefined",
|
||||
});
|
||||
|
||||
o = {};
|
||||
Object.defineProperty(o, "foo", { value: 10, configurable: false });
|
||||
p = new Proxy(o, {
|
||||
getOwnPropertyDescriptor() {
|
||||
return undefined;
|
||||
},
|
||||
});
|
||||
|
||||
assert(Object.getOwnPropertyDescriptor(p, "bar") === undefined);
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.getOwnPropertyDescriptor(p, "foo");
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's getOwnPropertyDescriptor trap violates invariant: cannot return undefined for a property on the target which is a non-configurable property",
|
||||
});
|
||||
|
||||
Object.defineProperty(o, "baz", { value: 20, configurable: true, writable: true, enumerable: true });
|
||||
Object.preventExtensions(o);
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.getOwnPropertyDescriptor(p, "baz");
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's getOwnPropertyDescriptor trap violates invariant: cannot report a property as being undefined if it exists as an own property of the target and the target is non-extensible",
|
||||
});
|
||||
|
||||
o = {};
|
||||
Object.defineProperty(o, "v1", { value: 10, configurable: false });
|
||||
Object.defineProperty(o, "v2", { value: 10, configurable: false, enumerable: true });
|
||||
Object.defineProperty(o, "v3", { configurable: false, get() { return 1; } });
|
||||
Object.defineProperty(o, "v4", { value: 10, configurable: false, writable: false, enumerable: true });
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.getOwnPropertyDescriptor(new Proxy(o, {
|
||||
getOwnPropertyDescriptor() {
|
||||
return { configurable: true };
|
||||
},
|
||||
}), "v1");
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's getOwnPropertyDescriptor trap violates invariant: invalid property descriptor for existing property on the target",
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.getOwnPropertyDescriptor(new Proxy(o, {
|
||||
getOwnPropertyDescriptor() {
|
||||
return { enumerable: false };
|
||||
},
|
||||
}), "v2");
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's getOwnPropertyDescriptor trap violates invariant: invalid property descriptor for existing property on the target",
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.getOwnPropertyDescriptor(new Proxy(o, {
|
||||
getOwnPropertyDescriptor() {
|
||||
return { value: 10 };
|
||||
},
|
||||
}), "v3");
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's getOwnPropertyDescriptor trap violates invariant: invalid property descriptor for existing property on the target",
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.getOwnPropertyDescriptor(new Proxy(o, {
|
||||
getOwnPropertyDescriptor() {
|
||||
return { value: 10, writable: true };
|
||||
},
|
||||
}), "v4");
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's getOwnPropertyDescriptor trap violates invariant: invalid property descriptor for existing property on the target",
|
||||
});
|
||||
|
||||
o = {};
|
||||
Object.defineProperty(o, "v", { configurable: true });
|
||||
assertThrowsError(() => {
|
||||
Object.getOwnPropertyDescriptor(new Proxy(o, {
|
||||
getOwnPropertyDescriptor() {
|
||||
return { configurable: false };
|
||||
},
|
||||
}), "v");
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's getOwnPropertyDescriptor trap violates invariant: cannot report target's property as non-configurable if the property does not exist, or if it is configurable",
|
||||
});
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
87
Libraries/LibJS/Tests/Proxy.handler-getPrototypeOf.js
Normal file
87
Libraries/LibJS/Tests/Proxy.handler-getPrototypeOf.js
Normal file
|
@ -0,0 +1,87 @@
|
|||
load("test-common.js");
|
||||
|
||||
try {
|
||||
const child = {};
|
||||
const childProto = { foo: "bar" };
|
||||
|
||||
Object.setPrototypeOf(child, childProto);
|
||||
assert(child.foo === "bar");
|
||||
|
||||
Object.getPrototypeOf(new Proxy(child, { getPrototypeOf: null }));
|
||||
Object.getPrototypeOf(new Proxy(child, { getPrototypeOf: undefined }));
|
||||
|
||||
let o = {};
|
||||
let p = new Proxy(o, {
|
||||
getPrototypeOf(target) {
|
||||
assert(target === o);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
Object.getPrototypeOf(p);
|
||||
|
||||
p = new Proxy(o, {
|
||||
getPrototypeOf(target) {
|
||||
if (target.foo)
|
||||
return { bar: 1 };
|
||||
return { bar: 2 };
|
||||
},
|
||||
});
|
||||
|
||||
assert(Object.getPrototypeOf(p).bar === 2);
|
||||
o.foo = 20
|
||||
assert(Object.getPrototypeOf(p).bar === 1);
|
||||
|
||||
// Invariants
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.getPrototypeOf(new Proxy(child, { getPrototypeOf: 1 }));
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's getPrototypeOf trap wasn't undefined, null, or callable",
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.getPrototypeOf(new Proxy(child, { getPrototypeOf() { return 1; } }));
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's getPrototypeOf trap violates invariant: must return an object or null",
|
||||
});
|
||||
|
||||
p = new Proxy(child, {
|
||||
getPrototypeOf(target) {
|
||||
assert(target === child);
|
||||
return { baz: "qux" };
|
||||
},
|
||||
});
|
||||
|
||||
assert(Object.getPrototypeOf(p).baz === "qux");
|
||||
|
||||
Object.preventExtensions(child);
|
||||
p = new Proxy(child, {
|
||||
getPrototypeOf(target) {
|
||||
assert(target === child);
|
||||
return childProto;
|
||||
}
|
||||
});
|
||||
|
||||
assert(Object.getPrototypeOf(p).foo === "bar");
|
||||
|
||||
p = new Proxy(child, {
|
||||
getPrototypeOf(target) {
|
||||
assert(target === child);
|
||||
return { baz: "qux" };
|
||||
}
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.getPrototypeOf(p);
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's getPrototypeOf trap violates invariant: cannot return a different prototype object for a non-extensible target"
|
||||
});
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
62
Libraries/LibJS/Tests/Proxy.handler-has.js
Normal file
62
Libraries/LibJS/Tests/Proxy.handler-has.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
load("test-common.js");
|
||||
|
||||
try {
|
||||
assert("foo" in new Proxy({}, { has: null }) === false);
|
||||
assert("foo" in new Proxy({}, { has: undefined}) === false);
|
||||
assert("foo" in new Proxy({}, {}) === false);
|
||||
|
||||
let o = {};
|
||||
let p = new Proxy(o, {
|
||||
has(target, prop) {
|
||||
assert(target === o);
|
||||
assert(prop === "foo");
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
"foo" in p;
|
||||
|
||||
p = new Proxy(o, {
|
||||
has(target, prop) {
|
||||
if (target.checkedFoo)
|
||||
return true;
|
||||
if (prop === "foo")
|
||||
target.checkedFoo = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
assert("foo" in p === false);
|
||||
assert("foo" in p === true);
|
||||
|
||||
// Invariants
|
||||
|
||||
o = {};
|
||||
Object.defineProperty(o, "foo", { configurable: false });
|
||||
Object.defineProperty(o, "bar", { value: 10, configurable: true });
|
||||
p = new Proxy(o, {
|
||||
has() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
"foo" in p;
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's has trap violates invariant: a property cannot be reported as non-existent if it exists on the target as a non-configurable property",
|
||||
});
|
||||
|
||||
Object.preventExtensions(o);
|
||||
|
||||
assertThrowsError(() => {
|
||||
"bar" in p;
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's has trap violates invariant: a property cannot be reported as non-existent if it exist on the target and the target is non-extensible",
|
||||
});
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
49
Libraries/LibJS/Tests/Proxy.handler-isExtensible.js
Normal file
49
Libraries/LibJS/Tests/Proxy.handler-isExtensible.js
Normal file
|
@ -0,0 +1,49 @@
|
|||
load("test-common.js");
|
||||
|
||||
try {
|
||||
assert(Object.isExtensible(new Proxy({}, { isExtensible: null })) === true);
|
||||
assert(Object.isExtensible(new Proxy({}, { isExtensible: undefined })) === true);
|
||||
assert(Object.isExtensible(new Proxy({}, {})) === true);
|
||||
|
||||
let o = {};
|
||||
let p = new Proxy(o, {
|
||||
isExtensible(target) {
|
||||
assert(target === o);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
Object.isExtensible(p);
|
||||
|
||||
// Invariants
|
||||
|
||||
o = {};
|
||||
p = new Proxy(o, {
|
||||
isExtensible(proxyTarget) {
|
||||
assert(proxyTarget === o);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
assert(Object.isExtensible(p) === true);
|
||||
Object.preventExtensions(o);
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.isExtensible(p);
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's isExtensible trap violates invariant: return value must match the target's extensibility",
|
||||
});
|
||||
|
||||
p = new Proxy(o, {
|
||||
isExtensible(proxyTarget) {
|
||||
assert(proxyTarget === o);
|
||||
return false;
|
||||
},
|
||||
});
|
||||
assert(Object.isExtensible(p) === false);
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
55
Libraries/LibJS/Tests/Proxy.handler-preventExtensions.js
Normal file
55
Libraries/LibJS/Tests/Proxy.handler-preventExtensions.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
load("test-common.js");
|
||||
|
||||
try {
|
||||
let p = new Proxy({}, { preventExtensions: null });
|
||||
assert(Object.preventExtensions(p) === p);
|
||||
p = new Proxy({}, { preventExtensions: undefined });
|
||||
assert(Object.preventExtensions(p) === p);
|
||||
p = new Proxy({}, {});
|
||||
assert(Object.preventExtensions(p) == p);
|
||||
|
||||
let o = {};
|
||||
p = new Proxy(o, {
|
||||
preventExtensions(target) {
|
||||
assert(target === o);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
Object.preventExtensions(o);
|
||||
Object.preventExtensions(p);
|
||||
|
||||
// Invariants
|
||||
|
||||
p = new Proxy({}, {
|
||||
preventExtensions() {
|
||||
return false;
|
||||
},
|
||||
});
|
||||
assertThrowsError(() => {
|
||||
Object.preventExtensions(p);
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy preventExtensions handler returned false",
|
||||
});
|
||||
|
||||
o = {};
|
||||
p = new Proxy(o, {
|
||||
preventExtensions() {
|
||||
return true;
|
||||
},
|
||||
});
|
||||
assertThrowsError(() => {
|
||||
Object.preventExtensions(p);
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's preventExtensions trap violates invariant: cannot return true if the target object is extensible"
|
||||
});
|
||||
|
||||
Object.preventExtensions(o);
|
||||
assert(Object.preventExtensions(p) === p);
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
66
Libraries/LibJS/Tests/Proxy.handler-set.js
Normal file
66
Libraries/LibJS/Tests/Proxy.handler-set.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
load("test-common.js");
|
||||
|
||||
try {
|
||||
assert((new Proxy({}, { set: undefined }).foo = 1) === 1);
|
||||
assert((new Proxy({}, { set: null }).foo = 1) === 1);
|
||||
assert((new Proxy({}, {}).foo = 1) === 1);
|
||||
|
||||
let o = {};
|
||||
let p = new Proxy(o, {
|
||||
set(target, prop, value, receiver) {
|
||||
assert(target === o);
|
||||
assert(prop === "foo");
|
||||
assert(value === 10);
|
||||
assert(receiver === p);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
p.foo = 10;
|
||||
|
||||
p = new Proxy(o, {
|
||||
set(target, prop, value, receiver) {
|
||||
if (target[prop] === value) {
|
||||
target[prop] *= 2;
|
||||
} else {
|
||||
target[prop] = value;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
p.foo = 10;
|
||||
assert(p.foo === 10);
|
||||
p.foo = 10;
|
||||
assert(p.foo === 20);
|
||||
p.foo = 10;
|
||||
assert(p.foo === 10);
|
||||
|
||||
// Invariants
|
||||
|
||||
o = {};
|
||||
Object.defineProperty(o, "foo", { value: 10 });
|
||||
p = new Proxy(o, {
|
||||
set() {
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
p.foo = 12;
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's set trap violates invariant: cannot return true for a property on the target which is a non-configurable, non-writable own data property",
|
||||
});
|
||||
|
||||
Object.defineProperty(o, "bar", { get() {} });
|
||||
assertThrowsError(() => {
|
||||
p.bar = 12;
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's set trap violates invariant: cannot return true for a property on the target which is a non-configurable own accessor property with an undefined set attribute",
|
||||
});
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
95
Libraries/LibJS/Tests/Proxy.handler-setPrototypeOf.js
Normal file
95
Libraries/LibJS/Tests/Proxy.handler-setPrototypeOf.js
Normal file
|
@ -0,0 +1,95 @@
|
|||
load("test-common.js");
|
||||
|
||||
try {
|
||||
const child = {};
|
||||
const childProto = { foo: "bar" };
|
||||
|
||||
Object.setPrototypeOf(child, childProto);
|
||||
assert(child.foo === "bar");
|
||||
|
||||
Object.setPrototypeOf(new Proxy(child, { setPrototypeOf: null }), childProto);
|
||||
Object.setPrototypeOf(new Proxy(child, { setPrototypeOf: undefined }), childProto);
|
||||
|
||||
let o = {};
|
||||
let theNewProto = { foo: "bar" };
|
||||
let p = new Proxy(o, {
|
||||
setPrototypeOf(target, newProto) {
|
||||
assert(target === o);
|
||||
assert(newProto === theNewProto);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
Object.setPrototypeOf(p, theNewProto);
|
||||
|
||||
p = new Proxy(o, {
|
||||
setPrototypeOf(target, newProto) {
|
||||
if (target.shouldSet)
|
||||
Object.setPrototypeOf(target, newProto);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
Object.setPrototypeOf(p, { foo: 1 });
|
||||
assert(Object.getPrototypeOf(p).foo === undefined);
|
||||
p.shouldSet = true;
|
||||
assert(o.shouldSet === true);
|
||||
Object.setPrototypeOf(p, { foo: 1 });
|
||||
assert(Object.getPrototypeOf(p).foo === 1);
|
||||
|
||||
// Invariants
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.setPrototypeOf(new Proxy(child, { setPrototypeOf: 1 }), {});
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's setPrototypeOf trap wasn't undefined, null, or callable",
|
||||
});
|
||||
|
||||
p = new Proxy(child, {
|
||||
setPrototypeOf(target, newProto) {
|
||||
assert(target === child);
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.setPrototypeOf(p, {});
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Object's setPrototypeOf method returned false"
|
||||
});
|
||||
assert(Object.getPrototypeOf(p) === childProto);
|
||||
|
||||
p = new Proxy(child, {
|
||||
setPrototypeOf(target, newProto) {
|
||||
assert(target === child);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
assert(Object.setPrototypeOf(p, {}) === p);
|
||||
assert(Object.getPrototypeOf(p) === childProto);
|
||||
|
||||
Object.preventExtensions(child);
|
||||
p = new Proxy(child, {
|
||||
setPrototypeOf(target, newProto) {
|
||||
assert(target === child);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
assert(Object.setPrototypeOf(p, childProto) === p);
|
||||
assert(Object.getPrototypeOf(p) === childProto);
|
||||
|
||||
assertThrowsError(() => {
|
||||
Object.setPrototypeOf(p, {});
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy handler's setPrototypeOf trap violates invariant: the argument must match the prototype of the target if the target is non-extensible",
|
||||
});
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
30
Libraries/LibJS/Tests/Proxy.js
Normal file
30
Libraries/LibJS/Tests/Proxy.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
load("test-common.js");
|
||||
|
||||
try {
|
||||
new Proxy({}, {});
|
||||
|
||||
assertThrowsError(() => {
|
||||
new Proxy();
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy requires at least two arguments",
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
Proxy();
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Proxy must be called with the \"new\" operator",
|
||||
});
|
||||
|
||||
assertThrowsError(() => {
|
||||
new Proxy(1, {});
|
||||
}, {
|
||||
error: TypeError,
|
||||
message: "Expected target argument of Proxy constructor to be object, got 1",
|
||||
});
|
||||
|
||||
console.log("PASS");
|
||||
} catch (e) {
|
||||
console.log("FAIL: " + e);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue