tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }