tor-browser

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

bug1403679.js (6335B)


      1 load(libdir + "asserts.js");
      2 
      3 const thisGlobal = this;
      4 const otherGlobalSameCompartment = newGlobal({sameCompartmentAs: thisGlobal});
      5 const otherGlobalNewCompartment = newGlobal({newCompartment: true});
      6 
      7 const globals = [thisGlobal, otherGlobalSameCompartment, otherGlobalNewCompartment];
      8 
      9 function testWithOptions(fn, variants = [undefined]) {
     10    for (let variant of variants) {
     11        for (let global of globals) {
     12            for (let options of [
     13                {},
     14                {proxy: true},
     15                {object: new FakeDOMObject()},
     16            ]) {
     17                fn(options, global, variant);
     18            }
     19        }
     20    }
     21 }
     22 
     23 function testWithGlobals(fn) {
     24    for (let global of globals) {
     25        fn(global);
     26    }
     27 }
     28 
     29 function testBasic(options, global) {
     30    let {object: source, transplant} = transplantableObject(options);
     31 
     32    // Validate that |source| is an object and |transplant| is a function.
     33    assertEq(typeof source, "object");
     34    assertEq(typeof transplant, "function");
     35 
     36    // |source| is created in the current global.
     37    assertEq(objectGlobal(source), this);
     38 
     39    // |source|'s prototype is %ObjectPrototype%, unless it's a FakeDOMObject.
     40    let oldPrototype;
     41    if (options.object) {
     42        oldPrototype = FakeDOMObject.prototype;
     43    } else {
     44        oldPrototype = Object.prototype;
     45    }
     46    assertEq(Object.getPrototypeOf(source), oldPrototype);
     47 
     48    // Properties can be created on |source|.
     49    assertEq(source.foo, undefined);
     50    source.foo = 1;
     51    assertEq(source.foo, 1);
     52 
     53    // Calling |transplant| transplants the object and then returns undefined.
     54    assertEq(transplant(global), undefined);
     55 
     56    // |source| was moved into the new global. If the new global is in a
     57    // different compartment, |source| is a now a CCW.
     58    if (global !== otherGlobalNewCompartment) {
     59        assertEq(objectGlobal(source), global);
     60    } else {
     61        assertEq(objectGlobal(source), null);
     62        assertEq(isProxy(source), true);
     63    }
     64 
     65    // The properties are copied over to the swapped object.
     66    assertEq(source.foo, 1);
     67 
     68    // The prototype was changed to %ObjectPrototype% of |global| or the
     69    // FakeDOMObject.prototype.
     70    let newPrototype;
     71    if (options.object) {
     72        newPrototype = global.FakeDOMObject.prototype;
     73    } else {
     74        newPrototype = global.Object.prototype;
     75    }
     76    assertEq(Object.getPrototypeOf(source), newPrototype);
     77 }
     78 testWithOptions(testBasic);
     79 
     80 // Objects can be transplanted multiple times between globals.
     81 function testTransplantMulti(options, global1, global2) {
     82    let {object: source, transplant} = transplantableObject(options);
     83 
     84    transplant(global1);
     85    transplant(global2);
     86 }
     87 testWithOptions(testTransplantMulti, globals);
     88 
     89 // Test the case when the source object already has a wrapper in the target global.
     90 function testHasWrapperInTarget(options, global) {
     91    let {object: source, transplant} = transplantableObject(options);
     92 
     93    // Create a wrapper for |source| in the other global.
     94    global.p = source;
     95    assertEq(global.eval("p"), source);
     96 
     97    if (options.proxy) {
     98        // It's a proxy object either way.
     99        assertEq(global.eval("isProxy(p)"), true);
    100    } else {
    101        if (global === otherGlobalNewCompartment) {
    102            // |isProxy| returns true because |p| is a CCW.
    103            assertEq(global.eval("isProxy(p)"), true);
    104        } else {
    105            // |isProxy| returns false because |p| is not a CCW.
    106            assertEq(global.eval("isProxy(p)"), false);
    107        }
    108    }
    109 
    110    // And now transplant it into that global.
    111    transplant(global);
    112 
    113    assertEq(global.eval("p"), source);
    114 
    115    if (options.proxy) {
    116        // It's a proxy object either way.
    117        assertEq(global.eval("isProxy(p)"), true);
    118    } else {
    119        // The previous CCW was replaced with a same-compartment object.
    120        assertEq(global.eval("isProxy(p)"), false);
    121    }
    122 }
    123 testWithOptions(testHasWrapperInTarget);
    124 
    125 // Test the case when the source object has a wrapper, but in a different compartment.
    126 function testHasWrapperOtherCompartment(options, global) {
    127    let thirdGlobal = newGlobal({newCompartment: true});
    128    let {object: source, transplant} = transplantableObject(options);
    129 
    130    // Create a wrapper for |source| in the new global.
    131    thirdGlobal.p = source;
    132    assertEq(thirdGlobal.eval("p"), source);
    133 
    134    // And now transplant the object.
    135    transplant(global);
    136 
    137    assertEq(thirdGlobal.eval("p"), source);
    138 }
    139 testWithOptions(testHasWrapperOtherCompartment);
    140 
    141 // Ensure a transplanted object is correctly handled by (weak) collections.
    142 function testCollections(options, global, AnySet) {
    143    let {object, transplant} = transplantableObject(options);
    144 
    145    let set = new AnySet();
    146 
    147    assertEq(set.has(object), false);
    148    set.add(object);
    149    assertEq(set.has(object), true);
    150 
    151    transplant(global);
    152 
    153    assertEq(set.has(object), true);
    154 }
    155 testWithOptions(testCollections, [Set, WeakSet]);
    156 
    157 // Ensure DOM object slot is correctly transplanted.
    158 function testDOMObjectSlot(global) {
    159    let domObject = new FakeDOMObject();
    160    let expectedValue = domObject.x;
    161    assertEq(typeof expectedValue, "number");
    162 
    163    let {object, transplant} = transplantableObject({object: domObject});
    164    assertEq(object, domObject);
    165 
    166    transplant(global);
    167 
    168    assertEq(object, domObject);
    169    assertEq(domObject.x, expectedValue);
    170 }
    171 testWithGlobals(testDOMObjectSlot);
    172 
    173 function testArgumentValidation() {
    174    // Throws an error if too many arguments are present.
    175    assertThrowsInstanceOf(() => transplantableObject(thisGlobal, {}), Error);
    176 
    177    let {object, transplant} = transplantableObject();
    178 
    179    // Throws an error if called with no arguments.
    180    assertThrowsInstanceOf(() => transplant(), Error);
    181 
    182    // Throws an error if called with too many arguments.
    183    assertThrowsInstanceOf(() => transplant(thisGlobal, {}), Error);
    184 
    185    // Throws an error if the first argument isn't an object
    186    assertThrowsInstanceOf(() => transplant(null), Error);
    187 
    188    // Throws an error if the argument isn't a global object.
    189    assertThrowsInstanceOf(() => transplant({}), Error);
    190 
    191    // Throws an error if the 'object' option isn't a FakeDOMObject.
    192    assertThrowsInstanceOf(() => transplant({object: null}), Error);
    193    assertThrowsInstanceOf(() => transplant({object: {}}), Error);
    194 }
    195 testArgumentValidation();