testDirectProxyIsExtensible1.js (4193B)
1 load(libdir + "asserts.js"); 2 // Test ES6 Proxy trap compliance for Object.isExtensible() on exotic proxy 3 // objects. 4 var unsealed = {}; 5 var sealed = Object.seal({}); 6 var handler = {}; 7 8 assertEq(Object.isExtensible(unsealed), true); 9 assertEq(Object.isExtensible(sealed), false); 10 11 var targetSealed = new Proxy(sealed, handler); 12 var targetUnsealed = new Proxy(unsealed, handler); 13 14 var handlerCalled = false; 15 16 function testExtensible(target, expectedResult, shouldIgnoreHandler = false) 17 { 18 for (let p of [new Proxy(target, handler), Proxy.revocable(target, handler).proxy]) { 19 handlerCalled = false; 20 if (typeof expectedResult === "boolean") 21 assertEq(Object.isExtensible(p), expectedResult, "Must return the correct value."); 22 else 23 assertThrowsInstanceOf(() => Object.isExtensible(p), expectedResult); 24 assertEq(handlerCalled, !shouldIgnoreHandler, "Must call handler appropriately"); 25 } 26 } 27 28 // without traps, forward to the target 29 // First, make sure we get the obvious answer on a non-exotic target. 30 testExtensible(sealed, false, /* shouldIgnoreHandler = */true); 31 testExtensible(unsealed, true, /* shouldIgnoreHandler = */true); 32 33 // Now, keep everyone honest. What if the target itself is a proxy? 34 // Note that we cheat a little. |handlerCalled| is true in a sense, just not 35 // for the toplevel handler. 36 // While we're here, test that the argument is passed correctly. 37 var targetsTarget = {}; 38 function ensureCalled(target) { assertEq(target, targetsTarget); handlerCalled = true; return true; } 39 var proxyTarget = new Proxy(targetsTarget, { isExtensible : ensureCalled }); 40 testExtensible(proxyTarget, true); 41 42 // What if the trap says it's necessarily sealed? 43 function fakeSealed() { handlerCalled = true; return false; } 44 handler.isExtensible = fakeSealed; 45 testExtensible(targetSealed, false); 46 testExtensible(targetUnsealed, TypeError); 47 48 // What if the trap says it's never sealed? 49 function fakeUnsealed() { handlerCalled = true; return true; } 50 handler.isExtensible = fakeUnsealed; 51 testExtensible(targetSealed, TypeError); 52 testExtensible(targetUnsealed, true); 53 54 // make sure we are able to prevent further extensions mid-flight and throw if the 55 // hook tries to lie. 56 function makeSealedTruth(target) { handlerCalled = true; Object.preventExtensions(target); return false; } 57 function makeSealedLie(target) { handlerCalled = true; Object.preventExtensions(target); return true; } 58 handler.isExtensible = makeSealedTruth; 59 testExtensible({}, false); 60 handler.isExtensible = makeSealedLie; 61 testExtensible({}, TypeError); 62 63 // What if the trap doesn't directly return a boolean? 64 function falseyNonBool() { handlerCalled = true; return undefined; } 65 handler.isExtensible = falseyNonBool; 66 testExtensible(sealed, false); 67 testExtensible(unsealed, TypeError); 68 69 function truthyNonBool() { handlerCalled = true; return {}; } 70 handler.isExtensible = truthyNonBool; 71 testExtensible(sealed, TypeError); 72 testExtensible(unsealed, true); 73 74 // What if the trap throws? 75 function ExtensibleError() { } 76 ExtensibleError.prototype = new Error(); 77 ExtensibleError.prototype.constructor = ExtensibleError; 78 function throwFromTrap() { throw new ExtensibleError(); } 79 handler.isExtensible = throwFromTrap; 80 81 // exercise some other code paths and make sure that they invoke the trap and 82 // can handle the ensuing error. 83 for (let p of [new Proxy(sealed, handler), Proxy.revocable(sealed, handler).proxy]) { 84 assertThrowsInstanceOf(function () { Object.isExtensible(p); }, 85 ExtensibleError, "Must throw if the trap does."); 86 assertThrowsInstanceOf(function () { Object.isFrozen(p); }, 87 ExtensibleError, "Must throw if the trap does."); 88 assertThrowsInstanceOf(function () { Object.isSealed(p); }, 89 ExtensibleError, "Must throw if the trap does."); 90 } 91 92 // What if the trap likes to re-ask old questions? 93 for (let p of [new Proxy(sealed, handler), Proxy.revocable(sealed, handler).proxy]) { 94 handler.isExtensible = (() => Object.isExtensible(p)); 95 assertThrowsInstanceOf(() => Object.isExtensible(p), 96 InternalError, "Should allow and detect infinite recurison."); 97 }