summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/proxy/testDirectProxyIsExtensible1.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/proxy/testDirectProxyIsExtensible1.js')
-rw-r--r--js/src/jit-test/tests/proxy/testDirectProxyIsExtensible1.js97
1 files changed, 97 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/proxy/testDirectProxyIsExtensible1.js b/js/src/jit-test/tests/proxy/testDirectProxyIsExtensible1.js
new file mode 100644
index 000000000..6d0bdc629
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyIsExtensible1.js
@@ -0,0 +1,97 @@
+load(libdir + "asserts.js");
+// Test ES6 Proxy trap compliance for Object.isExtensible() on exotic proxy
+// objects.
+var unsealed = {};
+var sealed = Object.seal({});
+var handler = {};
+
+assertEq(Object.isExtensible(unsealed), true);
+assertEq(Object.isExtensible(sealed), false);
+
+var targetSealed = new Proxy(sealed, handler);
+var targetUnsealed = new Proxy(unsealed, handler);
+
+var handlerCalled = false;
+
+function testExtensible(target, expectedResult, shouldIgnoreHandler = false)
+{
+ for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) {
+ handlerCalled = false;
+ if (typeof expectedResult === "boolean")
+ assertEq(Object.isExtensible(p), expectedResult, "Must return the correct value.");
+ else
+ assertThrowsInstanceOf(() => Object.isExtensible(p), expectedResult);
+ assertEq(handlerCalled, !shouldIgnoreHandler, "Must call handler appropriately");
+ }
+}
+
+// without traps, forward to the target
+// First, make sure we get the obvious answer on a non-exotic target.
+testExtensible(sealed, false, /* shouldIgnoreHandler = */true);
+testExtensible(unsealed, true, /* shouldIgnoreHandler = */true);
+
+// Now, keep everyone honest. What if the target itself is a proxy?
+// Note that we cheat a little. |handlerCalled| is true in a sense, just not
+// for the toplevel handler.
+// While we're here, test that the argument is passed correctly.
+var targetsTarget = {};
+function ensureCalled(target) { assertEq(target, targetsTarget); handlerCalled = true; return true; }
+var proxyTarget = new Proxy(targetsTarget, { isExtensible : ensureCalled });
+testExtensible(proxyTarget, true);
+
+// What if the trap says it's necessarily sealed?
+function fakeSealed() { handlerCalled = true; return false; }
+handler.isExtensible = fakeSealed;
+testExtensible(targetSealed, false);
+testExtensible(targetUnsealed, TypeError);
+
+// What if the trap says it's never sealed?
+function fakeUnsealed() { handlerCalled = true; return true; }
+handler.isExtensible = fakeUnsealed;
+testExtensible(targetSealed, TypeError);
+testExtensible(targetUnsealed, true);
+
+// make sure we are able to prevent further extensions mid-flight and throw if the
+// hook tries to lie.
+function makeSealedTruth(target) { handlerCalled = true; Object.preventExtensions(target); return false; }
+function makeSealedLie(target) { handlerCalled = true; Object.preventExtensions(target); return true; }
+handler.isExtensible = makeSealedTruth;
+testExtensible({}, false);
+handler.isExtensible = makeSealedLie;
+testExtensible({}, TypeError);
+
+// What if the trap doesn't directly return a boolean?
+function falseyNonBool() { handlerCalled = true; return undefined; }
+handler.isExtensible = falseyNonBool;
+testExtensible(sealed, false);
+testExtensible(unsealed, TypeError);
+
+function truthyNonBool() { handlerCalled = true; return {}; }
+handler.isExtensible = truthyNonBool;
+testExtensible(sealed, TypeError);
+testExtensible(unsealed, true);
+
+// What if the trap throws?
+function ExtensibleError() { }
+ExtensibleError.prototype = new Error();
+ExtensibleError.prototype.constructor = ExtensibleError;
+function throwFromTrap() { throw new ExtensibleError(); }
+handler.isExtensible = throwFromTrap;
+
+// exercise some other code paths and make sure that they invoke the trap and
+// can handle the ensuing error.
+for (let p of [new Proxy(sealed, handler), Proxy.revocable(sealed, handler).proxy]) {
+ assertThrowsInstanceOf(function () { Object.isExtensible(p); },
+ ExtensibleError, "Must throw if the trap does.");
+ assertThrowsInstanceOf(function () { Object.isFrozen(p); },
+ ExtensibleError, "Must throw if the trap does.");
+ assertThrowsInstanceOf(function () { Object.isSealed(p); },
+ ExtensibleError, "Must throw if the trap does.");
+}
+
+// What if the trap likes to re-ask old questions?
+for (let p of [new Proxy(sealed, handler), Proxy.revocable(sealed, handler).proxy]) {
+ handler.isExtensible = (() => Object.isExtensible(p));
+ assertThrowsInstanceOf(() => Object.isExtensible(p),
+ InternalError, "Should allow and detect infinite recurison.");
+}