tor-browser

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

Assert.sys.mjs (15352B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 const lazy = {};
      6 
      7 ChromeUtils.defineESModuleGetters(lazy, {
      8  AppInfo: "chrome://remote/content/shared/AppInfo.sys.mjs",
      9  error: "chrome://remote/content/shared/webdriver/Errors.sys.mjs",
     10  pprint: "chrome://remote/content/shared/Format.sys.mjs",
     11  RemoteAgent: "chrome://remote/content/components/RemoteAgent.sys.mjs",
     12 });
     13 
     14 /**
     15 * Shorthands for common assertions made in WebDriver.
     16 *
     17 * @namespace
     18 */
     19 export const assert = {};
     20 
     21 /**
     22 * Asserts that WebDriver has an active session.
     23 *
     24 * @param {WebDriverSession} session
     25 *     WebDriver session instance.
     26 * @param {string=} msg
     27 *     Custom error message.
     28 *
     29 * @throws {InvalidSessionIDError}
     30 *     If session does not exist, or has an invalid id.
     31 */
     32 assert.session = function (session, msg = "") {
     33  msg = msg || "WebDriver session does not exist, or is not active";
     34  assert.that(
     35    session => session && typeof session.id == "string",
     36    msg,
     37    lazy.error.InvalidSessionIDError
     38  )(session);
     39 };
     40 
     41 /**
     42 * Asserts that the current browser is Firefox Desktop.
     43 *
     44 * @param {string=} msg
     45 *     Custom error message.
     46 *
     47 * @throws {UnsupportedOperationError}
     48 *     If current browser is not Firefox.
     49 */
     50 assert.firefox = function (msg = "") {
     51  msg = msg || "Only supported in Firefox";
     52  assert.that(
     53    isFirefox => isFirefox,
     54    msg,
     55    lazy.error.UnsupportedOperationError
     56  )(lazy.AppInfo.isFirefox);
     57 };
     58 
     59 /**
     60 * Asserts that the current application is Firefox Desktop or Thunderbird.
     61 *
     62 * @param {string=} msg
     63 *     Custom error message.
     64 *
     65 * @throws {UnsupportedOperationError}
     66 *     If current application is not running on desktop.
     67 */
     68 assert.desktop = function (msg = "") {
     69  msg = msg || "Only supported in desktop applications";
     70  assert.that(
     71    isDesktop => isDesktop,
     72    msg,
     73    lazy.error.UnsupportedOperationError
     74  )(!lazy.AppInfo.isAndroid);
     75 };
     76 
     77 /**
     78 * Asserts that the current application runs on Android.
     79 *
     80 * @param {string=} msg
     81 *     Custom error message.
     82 *
     83 * @throws {UnsupportedOperationError}
     84 *     If current application is not running on Android.
     85 */
     86 assert.mobile = function (msg = "") {
     87  msg = msg || "Only supported on Android";
     88  assert.that(
     89    isAndroid => isAndroid,
     90    msg,
     91    lazy.error.UnsupportedOperationError
     92  )(lazy.AppInfo.isAndroid);
     93 };
     94 
     95 /**
     96 * Asserts that the current <var>context</var> is content.
     97 *
     98 * @param {string} context
     99 *     Context to test.
    100 * @param {string=} msg
    101 *     Custom error message.
    102 *
    103 * @returns {string}
    104 *     <var>context</var> is returned unaltered.
    105 *
    106 * @throws {UnsupportedOperationError}
    107 *     If <var>context</var> is not content.
    108 */
    109 assert.content = function (context, msg = "") {
    110  msg = msg || "Only supported in content context";
    111  assert.that(
    112    c => c.toString() == "content",
    113    msg,
    114    lazy.error.UnsupportedOperationError
    115  )(context);
    116 };
    117 
    118 /**
    119 * Asserts that system access is available.
    120 *
    121 * @param {string=} msg
    122 *     Custom error message.
    123 *
    124 * @throws {UnsupportedOperationError}
    125 *     If system access is not available.
    126 */
    127 assert.hasSystemAccess = function (msg = "") {
    128  msg =
    129    msg ||
    130    `System access is required. Start ${lazy.AppInfo.name} with "-remote-allow-system-access" to enable it.`;
    131 
    132  assert.that(
    133    hasSystemAccess => hasSystemAccess,
    134    msg,
    135    lazy.error.UnsupportedOperationError
    136  )(lazy.RemoteAgent.allowSystemAccess);
    137 };
    138 
    139 /**
    140 * Asserts that the {@link CanonicalBrowsingContext} is open.
    141 *
    142 * @param {CanonicalBrowsingContext} browsingContext
    143 *     Canonical browsing context to check.
    144 * @param {string=} msg
    145 *     Custom error message.
    146 *
    147 * @returns {CanonicalBrowsingContext}
    148 *     <var>browsingContext</var> is returned unaltered.
    149 *
    150 * @throws {NoSuchWindowError}
    151 *     If <var>browsingContext</var> is no longer open.
    152 */
    153 assert.open = function (browsingContext, msg = "") {
    154  msg = msg || "Browsing context has been discarded";
    155  return assert.that(
    156    browsingContext => {
    157      if (!browsingContext?.currentWindowGlobal) {
    158        return false;
    159      }
    160 
    161      if (browsingContext.isContent && !browsingContext.top.embedderElement) {
    162        return false;
    163      }
    164 
    165      return true;
    166    },
    167    msg,
    168    lazy.error.NoSuchWindowError
    169  )(browsingContext);
    170 };
    171 
    172 /**
    173 * Asserts that the browsing context is top-level.
    174 *
    175 * @param {BrowsingContext} browsingContext
    176 *     Browsing context to check.
    177 * @param {string=} msg
    178 *     Custom error message.
    179 *
    180 * @returns {BrowsingContext}
    181 *     <var>browsingContext</var> is returned unaltered.
    182 *
    183 * @throws {InvalidArgumentError}
    184 *     If <var>browsingContext</var> is not top-level.
    185 */
    186 assert.topLevel = function (browsingContext, msg = "") {
    187  msg = msg || `Browsing context is not top-level`;
    188  return assert.that(
    189    () => !browsingContext.parent,
    190    msg,
    191    lazy.error.InvalidArgumentError
    192  )(browsingContext);
    193 };
    194 
    195 /**
    196 * Asserts that there is no current user prompt.
    197 *
    198 * @param {modal.Dialog} dialog
    199 *     Reference to current dialogue.
    200 * @param {string=} msg
    201 *     Custom error message.
    202 *
    203 * @throws {UnexpectedAlertOpenError}
    204 *     If there is a user prompt.
    205 */
    206 assert.noUserPrompt = function (dialog, msg = "") {
    207  assert.that(
    208    d => d === null || typeof d == "undefined",
    209    msg,
    210    lazy.error.UnexpectedAlertOpenError
    211  )(dialog);
    212 };
    213 
    214 /**
    215 * Asserts that <var>obj</var> is defined.
    216 *
    217 * @param {?} obj
    218 *     Value to test.
    219 * @param {string=} msg
    220 *     Custom error message.
    221 *
    222 * @returns {?}
    223 *     <var>obj</var> is returned unaltered.
    224 *
    225 * @throws {InvalidArgumentError}
    226 *     If <var>obj</var> is not defined.
    227 */
    228 assert.defined = function (obj, msg = "") {
    229  msg = msg || lazy.pprint`Expected ${obj} to be defined`;
    230  return assert.that(o => typeof o != "undefined", msg)(obj);
    231 };
    232 
    233 /**
    234 * Asserts that <var>obj</var> is a finite number.
    235 *
    236 * @param {?} obj
    237 *     Value to test.
    238 * @param {string=} msg
    239 *     Custom error message.
    240 *
    241 * @returns {number}
    242 *     <var>obj</var> is returned unaltered.
    243 *
    244 * @throws {InvalidArgumentError}
    245 *     If <var>obj</var> is not a number.
    246 */
    247 assert.number = function (obj, msg = "") {
    248  msg = msg || lazy.pprint`Expected ${obj} to be finite number`;
    249  return assert.that(Number.isFinite, msg)(obj);
    250 };
    251 
    252 /**
    253 * Asserts that <var>obj</var> is a positive number.
    254 *
    255 * @param {?} obj
    256 *     Value to test.
    257 * @param {string=} msg
    258 *     Custom error message.
    259 *
    260 * @returns {number}
    261 *     <var>obj</var> is returned unaltered.
    262 *
    263 * @throws {InvalidArgumentError}
    264 *     If <var>obj</var> is not a positive integer.
    265 */
    266 assert.positiveNumber = function (obj, msg = "") {
    267  assert.number(obj, msg);
    268  msg = msg || lazy.pprint`Expected ${obj} to be >= 0`;
    269  return assert.that(n => n >= 0, msg)(obj);
    270 };
    271 
    272 /**
    273 * Asserts that <var>obj</var> is a number in the inclusive range <var>lower</var> to <var>upper</var>.
    274 *
    275 * @param {?} obj
    276 *     Value to test.
    277 * @param {Array<number>} range
    278 *     Array range [lower, upper]
    279 * @param {string=} msg
    280 *     Custom error message.
    281 *
    282 * @returns {number}
    283 *     <var>obj</var> is returned unaltered.
    284 *
    285 * @throws {InvalidArgumentError}
    286 *     If <var>obj</var> is not a number in the specified range.
    287 */
    288 assert.numberInRange = function (obj, range, msg = "") {
    289  const [lower, upper] = range;
    290  assert.number(obj, msg);
    291  msg = msg || lazy.pprint`Expected ${obj} to be >= ${lower} and <= ${upper}`;
    292  return assert.that(n => n >= lower && n <= upper, msg)(obj);
    293 };
    294 
    295 /**
    296 * Asserts that <var>obj</var> is callable.
    297 *
    298 * @param {?} obj
    299 *     Value to test.
    300 * @param {string=} msg
    301 *     Custom error message.
    302 *
    303 * @returns {Function}
    304 *     <var>obj</var> is returned unaltered.
    305 *
    306 * @throws {InvalidArgumentError}
    307 *     If <var>obj</var> is not callable.
    308 */
    309 assert.callable = function (obj, msg = "") {
    310  msg = msg || lazy.pprint`${obj} is not callable`;
    311  return assert.that(o => typeof o == "function", msg)(obj);
    312 };
    313 
    314 /**
    315 * Asserts that <var>obj</var> is an unsigned short number.
    316 *
    317 * @param {?} obj
    318 *     Value to test.
    319 * @param {string=} msg
    320 *     Custom error message.
    321 *
    322 * @returns {number}
    323 *     <var>obj</var> is returned unaltered.
    324 *
    325 * @throws {InvalidArgumentError}
    326 *     If <var>obj</var> is not an unsigned short.
    327 */
    328 assert.unsignedShort = function (obj, msg = "") {
    329  msg = msg || lazy.pprint`Expected ${obj} to be >= 0 and < 65536`;
    330  return assert.that(n => n >= 0 && n < 65536, msg)(obj);
    331 };
    332 
    333 /**
    334 * Asserts that <var>obj</var> is an integer.
    335 *
    336 * @param {?} obj
    337 *     Value to test.
    338 * @param {string=} msg
    339 *     Custom error message.
    340 *
    341 * @returns {number}
    342 *     <var>obj</var> is returned unaltered.
    343 *
    344 * @throws {InvalidArgumentError}
    345 *     If <var>obj</var> is not an integer.
    346 */
    347 assert.integer = function (obj, msg = "") {
    348  msg = msg || lazy.pprint`Expected ${obj} to be an integer`;
    349  return assert.that(Number.isSafeInteger, msg)(obj);
    350 };
    351 
    352 /**
    353 * Asserts that <var>obj</var> is a positive integer.
    354 *
    355 * @param {?} obj
    356 *     Value to test.
    357 * @param {string=} msg
    358 *     Custom error message.
    359 *
    360 * @returns {number}
    361 *     <var>obj</var> is returned unaltered.
    362 *
    363 * @throws {InvalidArgumentError}
    364 *     If <var>obj</var> is not a positive integer.
    365 */
    366 assert.positiveInteger = function (obj, msg = "") {
    367  assert.integer(obj, msg);
    368  msg = msg || lazy.pprint`Expected ${obj} to be >= 0`;
    369  return assert.that(n => n >= 0, msg)(obj);
    370 };
    371 
    372 /**
    373 * Asserts that <var>obj</var> is an integer in the inclusive range <var>lower</var> to <var>upper</var>.
    374 *
    375 * @param {?} obj
    376 *     Value to test.
    377 * @param {Array<number>} range
    378 *     Array range [lower, upper]
    379 * @param {string=} msg
    380 *     Custom error message.
    381 *
    382 * @returns {number}
    383 *     <var>obj</var> is returned unaltered.
    384 *
    385 * @throws {InvalidArgumentError}
    386 *     If <var>obj</var> is not a number in the specified range.
    387 */
    388 assert.integerInRange = function (obj, range, msg = "") {
    389  const [lower, upper] = range;
    390  assert.integer(obj, msg);
    391  msg = msg || lazy.pprint`Expected ${obj} to be >= ${lower} and <= ${upper}`;
    392  return assert.that(n => n >= lower && n <= upper, msg)(obj);
    393 };
    394 
    395 /**
    396 * Asserts that <var>obj</var> is a boolean.
    397 *
    398 * @param {?} obj
    399 *     Value to test.
    400 * @param {string=} msg
    401 *     Custom error message.
    402 *
    403 * @returns {boolean}
    404 *     <var>obj</var> is returned unaltered.
    405 *
    406 * @throws {InvalidArgumentError}
    407 *     If <var>obj</var> is not a boolean.
    408 */
    409 assert.boolean = function (obj, msg = "") {
    410  msg = msg || lazy.pprint`Expected ${obj} to be boolean`;
    411  return assert.that(b => typeof b == "boolean", msg)(obj);
    412 };
    413 
    414 /**
    415 * Asserts that <var>obj</var> is a string.
    416 *
    417 * @param {?} obj
    418 *     Value to test.
    419 * @param {string=} msg
    420 *     Custom error message.
    421 *
    422 * @returns {string}
    423 *     <var>obj</var> is returned unaltered.
    424 *
    425 * @throws {InvalidArgumentError}
    426 *     If <var>obj</var> is not a string.
    427 */
    428 assert.string = function (obj, msg = "") {
    429  msg = msg || lazy.pprint`Expected ${obj} to be a string`;
    430  return assert.that(s => typeof s == "string", msg)(obj);
    431 };
    432 
    433 /**
    434 * Asserts that <var>obj</var> is an object.
    435 *
    436 * @param {?} obj
    437 *     Value to test.
    438 * @param {string=} msg
    439 *     Custom error message.
    440 *
    441 * @returns {object}
    442 *     obj| is returned unaltered.
    443 *
    444 * @throws {InvalidArgumentError}
    445 *     If <var>obj</var> is not an object.
    446 */
    447 assert.object = function (obj, msg = "") {
    448  msg = msg || lazy.pprint`Expected ${obj} to be an object`;
    449  return assert.that(o => {
    450    // unable to use instanceof because LHS and RHS may come from
    451    // different globals
    452    let s = Object.prototype.toString.call(o);
    453    return s == "[object Object]" || s == "[object nsJSIID]";
    454  }, msg)(obj);
    455 };
    456 
    457 /**
    458 * Asserts that <var>obj</var> is an instance of a specified class.
    459 * <var>constructor</var> should have a static isInstance method implemented.
    460 *
    461 * @param {?} obj
    462 *     Value to test.
    463 * @param {?} constructor
    464 *     Class constructor.
    465 * @param {string=} msg
    466 *     Custom error message.
    467 *
    468 * @returns {object}
    469 *     <var>obj</var> is returned unaltered.
    470 *
    471 * @throws {InvalidArgumentError}
    472 *     If <var>obj</var> is not an instance of a specified class.
    473 */
    474 assert.isInstance = function (obj, constructor, msg = "") {
    475  assert.object(obj, msg);
    476  assert.object(constructor.prototype, msg);
    477 
    478  msg =
    479    msg ||
    480    lazy.pprint`Expected ${obj} to be an instance of ${constructor.name}`;
    481  return assert.that(
    482    o => Object.hasOwn(constructor, "isInstance") && constructor.isInstance(o),
    483    msg
    484  )(obj);
    485 };
    486 
    487 /**
    488 * Asserts that <var>prop</var> is in <var>obj</var>.
    489 *
    490 * @param {?} prop
    491 *     An array element or own property to test if is in <var>obj</var>.
    492 * @param {?} obj
    493 *     An array or an Object that is being tested.
    494 * @param {string=} msg
    495 *     Custom error message.
    496 *
    497 * @returns {?}
    498 *     The array element, or the value of <var>obj</var>'s own property
    499 *     <var>prop</var>.
    500 *
    501 * @throws {InvalidArgumentError}
    502 *     If the <var>obj</var> was an array and did not contain <var>prop</var>.
    503 *     Otherwise if <var>prop</var> is not in <var>obj</var>, or <var>obj</var>
    504 *     is not an object.
    505 */
    506 assert.in = function (prop, obj, msg = "") {
    507  if (Array.isArray(obj)) {
    508    assert.that(p => obj.includes(p), msg)(prop);
    509    return prop;
    510  }
    511  assert.object(obj, msg);
    512  msg = msg || lazy.pprint`Expected ${prop} in ${obj}`;
    513  assert.that(p => obj.hasOwnProperty(p), msg)(prop);
    514  return obj[prop];
    515 };
    516 
    517 /**
    518 * Asserts that <var>obj</var> is an Array.
    519 *
    520 * @param {?} obj
    521 *     Value to test.
    522 * @param {string=} msg
    523 *     Custom error message.
    524 *
    525 * @returns {object}
    526 *     <var>obj</var> is returned unaltered.
    527 *
    528 * @throws {InvalidArgumentError}
    529 *     If <var>obj</var> is not an Array.
    530 */
    531 assert.array = function (obj, msg = "") {
    532  msg = msg || lazy.pprint`Expected ${obj} to be an Array`;
    533  return assert.that(Array.isArray, msg)(obj);
    534 };
    535 
    536 /**
    537 * Asserts that <var>obj</var> is a non-empty Array.
    538 *
    539 * @param {?} obj
    540 *     Value to test.
    541 * @param {string=} msg
    542 *     Custom error message.
    543 *
    544 * @returns {object}
    545 *     <var>obj</var> is returned unaltered.
    546 *
    547 * @throws {InvalidArgumentError}
    548 *     If <var>obj</var> is not a non-empty Array.
    549 */
    550 assert.isNonEmptyArray = function (obj, msg = "") {
    551  msg = msg || lazy.pprint`Expected ${obj} to be a non-empty Array`;
    552  assert.array(obj, msg);
    553  assert.that(assertObj => !!assertObj.length, msg)(obj);
    554  return obj;
    555 };
    556 
    557 /**
    558 * Returns a function that is used to assert the |predicate|.
    559 *
    560 * @param {function(?): boolean} predicate
    561 *     Evaluated on calling the return value of this function.  If its
    562 *     return value of the inner function is false, <var>error</var>
    563 *     is thrown with <var>message</var>.
    564 * @param {string=} message
    565 *     Custom error message.
    566 * @param {Error=} err
    567 *     Custom error type by its class.
    568 *
    569 * @returns {function(?): ?}
    570 *     Function that takes and returns the passed in value unaltered,
    571 *     and which may throw <var>error</var> with <var>message</var>
    572 *     if <var>predicate</var> evaluates to false.
    573 */
    574 assert.that = function (
    575  predicate,
    576  message = "",
    577  err = lazy.error.InvalidArgumentError
    578 ) {
    579  return obj => {
    580    if (!predicate(obj)) {
    581      throw new err(message);
    582    }
    583    return obj;
    584  };
    585 };