tor-browser

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

shell.js (14108B)


      1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
      2 
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /*---
      8 defines: [completesNormally, raisesException, deepEqual, makeIterator, Permutations, assertThrowsValue, assertThrownErrorContains, assertThrowsInstanceOfWithMessageCheck, assertThrowsInstanceOf, assertThrowsInstanceOfWithMessage, assertThrowsInstanceOfWithMessageContains, assertDeepEq]
      9 allow_unused: True
     10 ---*/
     11 
     12 (function() {
     13  const undefined = void 0;
     14 
     15  /*
     16   * completesNormally(CODE) returns true if evaluating CODE (as eval
     17   * code) completes normally (rather than throwing an exception).
     18   */
     19  globalThis.completesNormally = function completesNormally(code) {
     20    try {
     21      eval(code);
     22      return true;
     23    } catch (exception) {
     24      return false;
     25    }
     26  }
     27 
     28  /*
     29   * raisesException(EXCEPTION)(CODE) returns true if evaluating CODE (as
     30   * eval code) throws an exception object that is an instance of EXCEPTION,
     31   * and returns false if it throws any other error or evaluates
     32   * successfully. For example: raises(TypeError)("0()") == true.
     33   */
     34  globalThis.raisesException = function raisesException(exception) {
     35    return function (code) {
     36      try {
     37        eval(code);
     38        return false;
     39      } catch (actual) {
     40        return actual instanceof exception;
     41      }
     42    };
     43  };
     44 
     45  /*
     46   * Return true if A is equal to B, where equality on arrays and objects
     47   * means that they have the same set of enumerable properties, the values
     48   * of each property are deep_equal, and their 'length' properties are
     49   * equal. Equality on other types is ==.
     50   */
     51  globalThis.deepEqual = function deepEqual(a, b) {
     52    if (typeof a != typeof b)
     53      return false;
     54 
     55    if (typeof a == 'object') {
     56      var props = {};
     57      // For every property of a, does b have that property with an equal value?
     58      for (var prop in a) {
     59        if (!deepEqual(a[prop], b[prop]))
     60          return false;
     61        props[prop] = true;
     62      }
     63      // Are all of b's properties present on a?
     64      for (var prop in b)
     65        if (!props[prop])
     66          return false;
     67      // length isn't enumerable, but we want to check it, too.
     68      return a.length == b.length;
     69    }
     70 
     71    if (a === b) {
     72      // Distinguish 0 from -0, even though they are ===.
     73      return a !== 0 || 1/a === 1/b;
     74    }
     75 
     76    // Treat NaNs as equal, even though NaN !== NaN.
     77    // NaNs are the only non-reflexive values, i.e., if a !== a, then a is a NaN.
     78    // isNaN is broken: it converts its argument to number, so isNaN("foo") => true
     79    return a !== a && b !== b;
     80  }
     81 
     82  /** Make an iterator with a return method. */
     83  globalThis.makeIterator = function makeIterator(overrides) {
     84    var throwMethod;
     85    if (overrides && overrides.throw)
     86      throwMethod = overrides.throw;
     87    var iterator = {
     88      throw: throwMethod,
     89      next: function(x) {
     90        if (overrides && overrides.next)
     91          return overrides.next(x);
     92        return { done: false };
     93      },
     94      return: function(x) {
     95        if (overrides && overrides.ret)
     96          return overrides.ret(x);
     97        return { done: true };
     98      }
     99    };
    100 
    101    return function() { return iterator; };
    102  };
    103 
    104  /** Yield every permutation of the elements in some array. */
    105  globalThis.Permutations = function* Permutations(items) {
    106    if (items.length == 0) {
    107      yield [];
    108    } else {
    109      items = items.slice(0);
    110      for (let i = 0; i < items.length; i++) {
    111        let swap = items[0];
    112        items[0] = items[i];
    113        items[i] = swap;
    114        for (let e of Permutations(items.slice(1, items.length)))
    115          yield [items[0]].concat(e);
    116      }
    117    }
    118  };
    119 
    120  if (typeof globalThis.assertThrowsValue === 'undefined') {
    121    globalThis.assertThrowsValue = function assertThrowsValue(f, val, msg) {
    122      var fullmsg;
    123      try {
    124        f();
    125      } catch (exc) {
    126        if ((exc === val) === (val === val) && (val !== 0 || 1 / exc === 1 / val))
    127          return;
    128        fullmsg = "Assertion failed: expected exception " + val + ", got " + exc;
    129      }
    130      if (fullmsg === undefined)
    131        fullmsg = "Assertion failed: expected exception " + val + ", no exception thrown";
    132      if (msg !== undefined)
    133        fullmsg += " - " + msg;
    134      throw new Error(fullmsg);
    135    };
    136  }
    137 
    138  if (typeof globalThis.assertThrownErrorContains === 'undefined') {
    139    globalThis.assertThrownErrorContains = function assertThrownErrorContains(thunk, substr) {
    140      try {
    141        thunk();
    142      } catch (e) {
    143        if (e.message.indexOf(substr) !== -1)
    144          return;
    145        throw new Error("Expected error containing " + substr + ", got " + e);
    146      }
    147      throw new Error("Expected error containing " + substr + ", no exception thrown");
    148    };
    149  }
    150 
    151  if (typeof globalThis.assertThrowsInstanceOfWithMessageCheck === 'undefined') {
    152    globalThis.assertThrowsInstanceOfWithMessageCheck = function assertThrowsInstanceOfWithMessageCheck(f, ctor, check, msg) {
    153      var fullmsg;
    154      try {
    155        f();
    156      } catch (exc) {
    157        if (!(exc instanceof ctor))
    158          fullmsg = `Assertion failed: expected exception ${ctor.name}, got ${exc}`;
    159        else {
    160          var result = check(exc.message);
    161          if (!result)
    162            fullmsg = `Assertion failed: expected exception with message, got ${exc}`;
    163          else
    164            return;
    165        }
    166      }
    167 
    168      if (fullmsg === undefined)
    169        fullmsg = `Assertion failed: expected exception ${ctor.name}, no exception thrown`;
    170      if (msg !== undefined)
    171        fullmsg += " - " + msg;
    172 
    173      throw new Error(fullmsg);
    174    };
    175  }
    176 
    177  if (typeof globalThis.assertThrowsInstanceOf === 'undefined') {
    178    globalThis.assertThrowsInstanceOf = function assertThrowsInstanceOf(f, ctor, msg) {
    179      assertThrowsInstanceOfWithMessageCheck(f, ctor, _ => true, msg);
    180    };
    181  }
    182 
    183  if (typeof globalThis.assertThrowsInstanceOfWithMessage === 'undefined') {
    184    globalThis.assertThrowsInstanceOfWithMessage = function assertThrowsInstanceOfWithMessage(f, ctor, expected, msg) {
    185      assertThrowsInstanceOfWithMessageCheck(f, ctor, message => message === expected, msg);
    186    }
    187  }
    188 
    189  if (typeof globalThis.assertThrowsInstanceOfWithMessageContains === 'undefined') {
    190    globalThis.assertThrowsInstanceOfWithMessageContains = function assertThrowsInstanceOfWithMessageContains(f, ctor, substr, msg) {
    191      assertThrowsInstanceOfWithMessageCheck(f, ctor, message => message.indexOf(substr) !== -1, msg);
    192    }
    193  }
    194 
    195  globalThis.assertDeepEq = (function(){
    196    var call = Function.prototype.call,
    197      Array_isArray = Array.isArray,
    198      Array_includes = call.bind(Array.prototype.includes),
    199      Map_ = Map,
    200      Error_ = Error,
    201      Symbol_ = Symbol,
    202      Symbol_keyFor = Symbol.keyFor,
    203      Symbol_description = call.bind(Object.getOwnPropertyDescriptor(Symbol.prototype, "description").get),
    204      Map_has = call.bind(Map.prototype.has),
    205      Map_get = call.bind(Map.prototype.get),
    206      Map_set = call.bind(Map.prototype.set),
    207      Object_toString = call.bind(Object.prototype.toString),
    208      Function_toString = call.bind(Function.prototype.toString),
    209      Object_getPrototypeOf = Object.getPrototypeOf,
    210      Object_hasOwnProperty = call.bind(Object.prototype.hasOwnProperty),
    211      Object_getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor,
    212      Object_isExtensible = Object.isExtensible,
    213      Object_getOwnPropertyNames = Object.getOwnPropertyNames;
    214 
    215    // Return true iff ES6 Type(v) isn't Object.
    216    // Note that `typeof document.all === "undefined"`.
    217    function isPrimitive(v) {
    218      return (v === null ||
    219          v === undefined ||
    220          typeof v === "boolean" ||
    221          typeof v === "number" ||
    222          typeof v === "string" ||
    223          typeof v === "symbol");
    224    }
    225 
    226    function assertSameValue(a, b, msg) {
    227      try {
    228        assertEq(a, b);
    229      } catch (exc) {
    230        throw Error_(exc.message + (msg ? " " + msg : ""));
    231      }
    232    }
    233 
    234    function assertSameClass(a, b, msg) {
    235      var ac = Object_toString(a), bc = Object_toString(b);
    236      assertSameValue(ac, bc, msg);
    237      switch (ac) {
    238      case "[object Function]":
    239        if (typeof isProxy !== "undefined" && !isProxy(a) && !isProxy(b))
    240          assertSameValue(Function_toString(a), Function_toString(b), msg);
    241      }
    242    }
    243 
    244    function at(prevmsg, segment) {
    245      return prevmsg ? prevmsg + segment : "at _" + segment;
    246    }
    247 
    248    // Assert that the arguments a and b are thoroughly structurally equivalent.
    249    //
    250    // For the sake of speed, we cut a corner:
    251    //    var x = {}, y = {}, ax = [x];
    252    //    assertDeepEq([ax, x], [ax, y]);  // passes (?!)
    253    //
    254    // Technically this should fail, since the two object graphs are different.
    255    // (The graph of [ax, y] contains one more object than the graph of [ax, x].)
    256    //
    257    // To get technically correct behavior, pass {strictEquivalence: true}.
    258    // This is slower because we have to walk the entire graph, and Object.prototype
    259    // is big.
    260    //
    261    return function assertDeepEq(a, b, options) {
    262      var strictEquivalence = options ? options.strictEquivalence : false;
    263 
    264      function assertSameProto(a, b, msg) {
    265        check(Object_getPrototypeOf(a), Object_getPrototypeOf(b), at(msg, ".__proto__"));
    266      }
    267 
    268      function failPropList(na, nb, msg) {
    269        throw Error_("got own properties " + JSON.stringify(na) + ", expected " + JSON.stringify(nb) +
    270               (msg ? " " + msg : ""));
    271      }
    272 
    273      function assertSameProps(a, b, msg) {
    274        var na = Object_getOwnPropertyNames(a),
    275          nb = Object_getOwnPropertyNames(b);
    276        if (na.length !== nb.length)
    277          failPropList(na, nb, msg);
    278 
    279        // Ignore differences in whether Array elements are stored densely.
    280        if (Array_isArray(a)) {
    281          na.sort();
    282          nb.sort();
    283        }
    284 
    285        for (var i = 0; i < na.length; i++) {
    286          var name = na[i];
    287          if (name !== nb[i])
    288            failPropList(na, nb, msg);
    289          var da = Object_getOwnPropertyDescriptor(a, name),
    290            db = Object_getOwnPropertyDescriptor(b, name);
    291          var pmsg = at(msg, /^[_$A-Za-z0-9]+$/.test(name)
    292                     ? /0|[1-9][0-9]*/.test(name) ? "[" + name + "]" : "." + name
    293                     : "[" + JSON.stringify(name) + "]");
    294          assertSameValue(da.configurable, db.configurable, at(pmsg, ".[[Configurable]]"));
    295          assertSameValue(da.enumerable, db.enumerable, at(pmsg, ".[[Enumerable]]"));
    296          if (Object_hasOwnProperty(da, "value")) {
    297            if (!Object_hasOwnProperty(db, "value"))
    298              throw Error_("got data property, expected accessor property" + pmsg);
    299            check(da.value, db.value, pmsg);
    300          } else {
    301            if (Object_hasOwnProperty(db, "value"))
    302              throw Error_("got accessor property, expected data property" + pmsg);
    303            check(da.get, db.get, at(pmsg, ".[[Get]]"));
    304            check(da.set, db.set, at(pmsg, ".[[Set]]"));
    305          }
    306        }
    307      };
    308 
    309      const wellKnownSymbols = Reflect.ownKeys(Symbol)
    310                                      .map(key => Symbol[key])
    311                                      .filter(value => typeof value === "symbol");
    312 
    313      // The standard doesn't offer a convenient way to distinguish well-known
    314      // symbols from user-created symbols.
    315      function isSimilarSymbol(a, b) {
    316        // Fast path for same symbols.
    317        if (a === b) {
    318          return true;
    319        }
    320 
    321        // 1. Symbol descriptions must match.
    322        // 2. Either both symbols are in the registry or none is.
    323        // 3. Neither symbol must be a well-known symbol, because those are
    324        //    already handled through the fast path.
    325        return Symbol_description(a) === Symbol_description(b) &&
    326               Symbol_keyFor(a) === Symbol_keyFor(b) &&
    327               !Array_includes(wellKnownSymbols, a) &&
    328               !Array_includes(wellKnownSymbols, b);
    329      }
    330 
    331      var ab = new Map_();
    332      var bpath = new Map_();
    333 
    334      function check(a, b, path) {
    335        if (typeof a === "symbol") {
    336          // Symbols are primitives, but they have identity.
    337          // Symbol("x") !== Symbol("x") but
    338          // assertDeepEq(Symbol("x"), Symbol("x")) should pass.
    339          if (typeof b !== "symbol") {
    340            throw Error_("got " + String(a) + ", expected " + String(b) + " " + path);
    341          } else if (!isSimilarSymbol(a, b)) {
    342            throw Error_("got " + String(a) + ", expected " + String(b) + " " + path);
    343          } else if (Map_has(ab, a)) {
    344            assertSameValue(Map_get(ab, a), b, path);
    345          } else if (Map_has(bpath, b)) {
    346            var bPrevPath = Map_get(bpath, b) || "_";
    347            throw Error_("got distinct symbols " + at(path, "") + " and " +
    348                   at(bPrevPath, "") + ", expected the same symbol both places");
    349          } else {
    350            Map_set(ab, a, b);
    351            Map_set(bpath, b, path);
    352          }
    353        } else if (isPrimitive(a)) {
    354          assertSameValue(a, b, path);
    355        } else if (isPrimitive(b)) {
    356          throw Error_("got " + Object_toString(a) + ", expected " + String(b) + " " + path);
    357        } else if (Map_has(ab, a)) {
    358          assertSameValue(Map_get(ab, a), b, path);
    359        } else if (Map_has(bpath, b)) {
    360          var bPrevPath = Map_get(bpath, b) || "_";
    361          throw Error_("got distinct objects " + at(path, "") + " and " + at(bPrevPath, "") +
    362                 ", expected the same object both places");
    363        } else {
    364          Map_set(ab, a, b);
    365          Map_set(bpath, b, path);
    366          if (a !== b || strictEquivalence) {
    367            assertSameClass(a, b, path);
    368            assertSameProto(a, b, path);
    369            assertSameProps(a, b, path);
    370            assertSameValue(Object_isExtensible(a),
    371                    Object_isExtensible(b),
    372                    at(path, ".[[Extensible]]"));
    373          }
    374        }
    375      }
    376 
    377      check(a, b, "");
    378    };
    379  })();
    380 
    381 })();