tor-browser

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

call.js (6877B)


      1 // |reftest| skip-if(!this.hasOwnProperty("Intl"))
      2 
      3 function IsIntlService(c) {
      4    return typeof c === "function" &&
      5           c.hasOwnProperty("prototype") &&
      6           c.prototype.hasOwnProperty("resolvedOptions");
      7 }
      8 
      9 function IsObject(o) {
     10    return Object(o) === o;
     11 }
     12 
     13 function IsPrimitive(o) {
     14    return Object(o) !== o;
     15 }
     16 
     17 function thisValues() {
     18    const intlConstructors = Object.getOwnPropertyNames(Intl).map(name => Intl[name]).filter(IsIntlService);
     19 
     20    return [
     21        // Primitive values.
     22        ...[undefined, null, true, "abc", Symbol(), 123],
     23 
     24        // Object values.
     25        ...[{}, [], /(?:)/, function(){}, new Proxy({}, {})],
     26 
     27        // Intl objects.
     28        ...[].concat(...intlConstructors.map(ctor => {
     29            let args = [];
     30            if (ctor === Intl.DisplayNames) {
     31                // Intl.DisplayNames can't be constructed without any arguments.
     32                args = [undefined, {type: "language"}];
     33            }
     34 
     35            return [
     36                // Instance of an Intl constructor.
     37                new ctor(...args),
     38 
     39                // Instance of a subclassed Intl constructor.
     40                new class extends ctor {}(...args),
     41 
     42                // Object inheriting from an Intl constructor prototype.
     43                Object.create(ctor.prototype),
     44 
     45                // Intl object not inheriting from its default prototype.
     46                Object.setPrototypeOf(new ctor(...args), Object.prototype),
     47            ];
     48        })),
     49    ];
     50 }
     51 
     52 const intlFallbackSymbol = Object.getOwnPropertySymbols(Intl.DateTimeFormat.call(Object.create(Intl.DateTimeFormat.prototype)))[0];
     53 
     54 // Invoking [[Call]] for Intl.DateTimeFormat returns a new instance unless called
     55 // with an instance inheriting from Intl.DateTimeFormat.prototype.
     56 for (let thisValue of thisValues()) {
     57    let obj = Intl.DateTimeFormat.call(thisValue);
     58 
     59    if (!Intl.DateTimeFormat.prototype.isPrototypeOf(thisValue)) {
     60        assertEq(Object.is(obj, thisValue), false);
     61        assertEq(obj instanceof Intl.DateTimeFormat, true);
     62        if (IsObject(thisValue))
     63            assertEqArray(Object.getOwnPropertySymbols(thisValue), []);
     64    } else {
     65        assertEq(Object.is(obj, thisValue), true);
     66        assertEq(obj instanceof Intl.DateTimeFormat, true);
     67        assertEqArray(Object.getOwnPropertySymbols(thisValue), [intlFallbackSymbol]);
     68    }
     69 }
     70 
     71 // Intl.DateTimeFormat uses the legacy Intl constructor compromise semantics.
     72 // - Test when InstanceofOperator(thisValue, %DateTimeFormat%) returns true.
     73 for (let thisValue of thisValues().filter(IsObject)) {
     74    let isPrototypeOf = Intl.DateTimeFormat.prototype.isPrototypeOf(thisValue);
     75    let hasInstanceCalled = false;
     76    Object.defineProperty(Intl.DateTimeFormat, Symbol.hasInstance, {
     77        value() {
     78            assertEq(hasInstanceCalled, false);
     79            hasInstanceCalled = true;
     80            return true;
     81        }, configurable: true
     82    });
     83    let obj = Intl.DateTimeFormat.call(thisValue);
     84    delete Intl.DateTimeFormat[Symbol.hasInstance];
     85 
     86    assertEq(Object.is(obj, thisValue), isPrototypeOf);
     87    assertEq(hasInstanceCalled, false);
     88    assertEqArray(Object.getOwnPropertySymbols(thisValue), isPrototypeOf ? [intlFallbackSymbol] : []);
     89 }
     90 // - Test when InstanceofOperator(thisValue, %DateTimeFormat%) returns false.
     91 for (let thisValue of thisValues().filter(IsObject)) {
     92    let isPrototypeOf = Intl.DateTimeFormat.prototype.isPrototypeOf(thisValue);
     93    let hasInstanceCalled = false;
     94    Object.defineProperty(Intl.DateTimeFormat, Symbol.hasInstance, {
     95        value() {
     96            assertEq(hasInstanceCalled, false);
     97            hasInstanceCalled = true;
     98            return false;
     99        }, configurable: true
    100    });
    101    let obj = Intl.DateTimeFormat.call(thisValue);
    102    delete Intl.DateTimeFormat[Symbol.hasInstance];
    103 
    104    assertEq(Object.is(obj, thisValue), isPrototypeOf);
    105    assertEq(obj instanceof Intl.DateTimeFormat, true);
    106    assertEq(hasInstanceCalled, false);
    107    assertEqArray(Object.getOwnPropertySymbols(thisValue), isPrototypeOf ? [intlFallbackSymbol] : []);
    108 }
    109 // - Test with primitive values.
    110 for (let thisValue of thisValues().filter(IsPrimitive)) {
    111    // Ensure @@hasInstance is not called.
    112    Object.defineProperty(Intl.DateTimeFormat, Symbol.hasInstance, {
    113        value() { assertEq(true, false); }, configurable: true
    114    });
    115    let obj = Intl.DateTimeFormat.call(thisValue);
    116    delete Intl.DateTimeFormat[Symbol.hasInstance];
    117 
    118    assertEq(Object.is(obj, thisValue), false);
    119    assertEq(obj instanceof Intl.DateTimeFormat, true);
    120 }
    121 
    122 // Throws an error when attempting to install [[FallbackSymbol]] twice.
    123 {
    124    let thisValue = Object.create(Intl.DateTimeFormat.prototype);
    125    assertEqArray(Object.getOwnPropertySymbols(thisValue), []);
    126 
    127    assertEq(Intl.DateTimeFormat.call(thisValue), thisValue);
    128    assertEqArray(Object.getOwnPropertySymbols(thisValue), [intlFallbackSymbol]);
    129 
    130    assertThrowsInstanceOf(() => Intl.DateTimeFormat.call(thisValue), TypeError);
    131    assertEqArray(Object.getOwnPropertySymbols(thisValue), [intlFallbackSymbol]);
    132 }
    133 
    134 // Throws an error when the thisValue is non-extensible.
    135 {
    136    let thisValue = Object.create(Intl.DateTimeFormat.prototype);
    137    Object.preventExtensions(thisValue);
    138 
    139    assertThrowsInstanceOf(() => Intl.DateTimeFormat.call(thisValue), TypeError);
    140    assertEqArray(Object.getOwnPropertySymbols(thisValue), []);
    141 }
    142 
    143 // [[FallbackSymbol]] is installed as a frozen property holding an Intl.DateTimeFormat instance.
    144 {
    145    let thisValue = Object.create(Intl.DateTimeFormat.prototype);
    146    Intl.DateTimeFormat.call(thisValue);
    147 
    148    let desc = Object.getOwnPropertyDescriptor(thisValue, intlFallbackSymbol);
    149    assertEq(desc !== undefined, true);
    150    assertEq(desc.writable, false);
    151    assertEq(desc.enumerable, false);
    152    assertEq(desc.configurable, false);
    153    assertEq(desc.value instanceof Intl.DateTimeFormat, true);
    154 }
    155 
    156 // Ensure [[FallbackSymbol]] is installed last by changing the [[Prototype]]
    157 // during initialization.
    158 {
    159    let thisValue = {};
    160    let options = {
    161        get hour12() {
    162            Object.setPrototypeOf(thisValue, Intl.DateTimeFormat.prototype);
    163            return false;
    164        }
    165    };
    166    let obj = Intl.DateTimeFormat.call(thisValue, undefined, options);
    167    assertEq(Object.is(obj, thisValue), true);
    168    assertEqArray(Object.getOwnPropertySymbols(thisValue), [intlFallbackSymbol]);
    169 }
    170 {
    171    let thisValue = Object.create(Intl.DateTimeFormat.prototype);
    172    let options = {
    173        get hour12() {
    174            Object.setPrototypeOf(thisValue, Object.prototype);
    175            return false;
    176        }
    177    };
    178    let obj = Intl.DateTimeFormat.call(thisValue, undefined, options);
    179    assertEq(Object.is(obj, thisValue), false);
    180    assertEqArray(Object.getOwnPropertySymbols(thisValue), []);
    181 }
    182 
    183 if (typeof reportCompare === "function")
    184    reportCompare(true, true);