tor-browser

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

util.js (12540B)


      1 /**
      2 * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
      3 **/import { Float16Array } from '../../external/petamoriken/float16/float16.js';import { SkipTestCase } from '../framework/fixture.js';import { globalTestConfig } from '../framework/test_config.js';
      4 
      5 import { keysOf } from './data_tables.js';
      6 import { timeout } from './timeout.js';
      7 
      8 /**
      9 * Error with arbitrary `extra` data attached, for debugging.
     10 * The extra data is omitted if not running the test in debug mode (`?debug=1`).
     11 */
     12 export class ErrorWithExtra extends Error {
     13 
     14 
     15  /**
     16   * `extra` function is only called if in debug mode.
     17   * If an `ErrorWithExtra` is passed, its message is used and its extras are passed through.
     18   */
     19 
     20 
     21  constructor(baseOrMessage, newExtra) {
     22    const message = typeof baseOrMessage === 'string' ? baseOrMessage : baseOrMessage.message;
     23    super(message);
     24 
     25    const oldExtras = baseOrMessage instanceof ErrorWithExtra ? baseOrMessage.extra : {};
     26    this.extra = globalTestConfig.enableDebugLogs ?
     27    { ...oldExtras, ...newExtra() } :
     28    { omitted: 'pass ?debug=1' };
     29  }
     30 }
     31 
     32 /**
     33 * Asserts `condition` is true. Otherwise, throws an `Error` with the provided message.
     34 */
     35 export function assert(condition, msg) {
     36  if (!condition) {
     37    throw new Error(msg && (typeof msg === 'string' ? msg : msg()));
     38  }
     39 }
     40 
     41 /** If the argument is an Error, throw it. Otherwise, pass it back. */
     42 export function assertOK(value) {
     43  if (value instanceof Error) {
     44    throw value;
     45  }
     46  return value;
     47 }
     48 
     49 /** Options for assertReject, shouldReject, and friends. */
     50 
     51 
     52 /**
     53 * Resolves if the provided promise rejects; rejects if it does not.
     54 */
     55 export async function assertReject(
     56 expectedName,
     57 p,
     58 { allowMissingStack = false, message } = {})
     59 {
     60  await p.then(
     61    () => {
     62      unreachable(message);
     63    },
     64    (ex) => {
     65      assert(ex instanceof Error, 'rejected with a non-Error object');
     66      assert(ex.name === expectedName, `rejected with name ${ex.name} instead of ${expectedName}`);
     67      // Asserted as expected
     68      if (!allowMissingStack) {
     69        const m = message ? ` (${message})` : '';
     70        assert(typeof ex.stack === 'string', 'threw as expected, but missing stack' + m);
     71      }
     72    }
     73  );
     74 }
     75 
     76 /**
     77 * Assert this code is unreachable. Unconditionally throws an `Error`.
     78 */
     79 export function unreachable(msg) {
     80  throw new Error(msg);
     81 }
     82 
     83 /**
     84 * Throw a `SkipTestCase` exception, which skips the test case.
     85 */
     86 export function skipTestCase(msg) {
     87  throw new SkipTestCase(msg);
     88 }
     89 
     90 /**
     91 * The `performance` interface.
     92 * It is available in all browsers, but it is not in scope by default in Node.
     93 */
     94 
     95 const perf = typeof performance !== 'undefined' ? performance : require('perf_hooks').performance;
     96 
     97 /**
     98 * Calls the appropriate `performance.now()` depending on whether running in a browser or Node.
     99 */
    100 export function now() {
    101  return perf.now();
    102 }
    103 
    104 /**
    105 * Returns a promise which resolves after the specified time.
    106 */
    107 export function resolveOnTimeout(ms) {
    108  return new Promise((resolve) => {
    109    timeout(() => {
    110      resolve();
    111    }, ms);
    112  });
    113 }
    114 
    115 export class PromiseTimeoutError extends Error {}
    116 
    117 /**
    118 * Returns a promise which rejects after the specified time.
    119 */
    120 export function rejectOnTimeout(ms, msg) {
    121  return new Promise((_resolve, reject) => {
    122    timeout(() => {
    123      reject(new PromiseTimeoutError(msg));
    124    }, ms);
    125  });
    126 }
    127 
    128 /**
    129 * Takes a promise `p`, and returns a new one which rejects if `p` takes too long,
    130 * and otherwise passes the result through.
    131 */
    132 export function raceWithRejectOnTimeout(p, ms, msg) {
    133  if (globalTestConfig.noRaceWithRejectOnTimeout) {
    134    return p;
    135  }
    136  // Setup a promise that will reject after `ms` milliseconds. We cancel this timeout when
    137  // `p` is finalized, so the JavaScript VM doesn't hang around waiting for the timer to
    138  // complete, once the test runner has finished executing the tests.
    139  const timeoutPromise = new Promise((_resolve, reject) => {
    140    const handle = timeout(() => {
    141      reject(new PromiseTimeoutError(msg));
    142    }, ms);
    143    p = p.finally(() => clearTimeout(handle));
    144  });
    145  return Promise.race([p, timeoutPromise]);
    146 }
    147 
    148 /**
    149 * Takes a promise `p` and returns a new one which rejects if `p` resolves or rejects,
    150 * and otherwise resolves after the specified time.
    151 */
    152 export function assertNotSettledWithinTime(
    153 p,
    154 ms,
    155 msg)
    156 {
    157  // Rejects regardless of whether p resolves or rejects.
    158  const rejectWhenSettled = p.then(() => Promise.reject(new Error(msg)));
    159  // Resolves after `ms` milliseconds.
    160  const timeoutPromise = new Promise((resolve) => {
    161    const handle = timeout(() => {
    162      resolve(undefined);
    163    }, ms);
    164    void p.finally(() => clearTimeout(handle));
    165  });
    166  return Promise.race([rejectWhenSettled, timeoutPromise]);
    167 }
    168 
    169 /**
    170 * Returns a `Promise.reject()`, but also registers a dummy `.catch()` handler so it doesn't count
    171 * as an uncaught promise rejection in the runtime.
    172 */
    173 export function rejectWithoutUncaught(err) {
    174  const p = Promise.reject(err);
    175  // Suppress uncaught promise rejection.
    176  p.catch(() => {});
    177  return p;
    178 }
    179 
    180 /**
    181 * Returns true if v is a plain JavaScript object.
    182 */
    183 export function isPlainObject(v) {
    184  return !!v && Object.getPrototypeOf(v).constructor === Object.prototype.constructor;
    185 }
    186 
    187 /**
    188 * Makes a copy of a JS `object`, with the keys reordered into sorted order.
    189 */
    190 export function sortObjectByKey(v) {
    191  const sortedObject = {};
    192  for (const k of Object.keys(v).sort()) {
    193    sortedObject[k] = v[k];
    194  }
    195  return sortedObject;
    196 }
    197 
    198 /**
    199 * Determines whether two JS values are equal, recursing into objects and arrays.
    200 * NaN is treated specially, such that `objectEquals(NaN, NaN)`. +/-0.0 are treated as equal
    201 * by default, but can be opted to be distinguished.
    202 * @param x the first JS values that get compared
    203 * @param y the second JS values that get compared
    204 * @param distinguishSignedZero if set to true, treat 0.0 and -0.0 as unequal. Default to false.
    205 */
    206 export function objectEquals(
    207 x,
    208 y,
    209 distinguishSignedZero = false)
    210 {
    211  if (typeof x !== 'object' || typeof y !== 'object') {
    212    if (typeof x === 'number' && typeof y === 'number' && Number.isNaN(x) && Number.isNaN(y)) {
    213      return true;
    214    }
    215    // Object.is(0.0, -0.0) is false while (0.0 === -0.0) is true. Other than +/-0.0 and NaN cases,
    216    // Object.is works in the same way as ===.
    217    return distinguishSignedZero ? Object.is(x, y) : x === y;
    218  }
    219  if (x === null || y === null) return x === y;
    220  if (x.constructor !== y.constructor) return false;
    221  if (x instanceof Function) return x === y;
    222  if (x instanceof RegExp) return x === y;
    223  if (x === y || x.valueOf() === y.valueOf()) return true;
    224  if (Array.isArray(x) && Array.isArray(y) && x.length !== y.length) return false;
    225  if (x instanceof Date) return false;
    226  if (!(x instanceof Object)) return false;
    227  if (!(y instanceof Object)) return false;
    228 
    229  const x1 = x;
    230  const y1 = y;
    231  const p = Object.keys(x);
    232  return Object.keys(y).every((i) => p.indexOf(i) !== -1) && p.every((i) => objectEquals(x1[i], y1[i]));
    233 }
    234 
    235 /**
    236 * Generates a range of values `fn(0)..fn(n-1)`.
    237 */
    238 export function range(n, fn) {
    239  return [...new Array(n)].map((_, i) => fn(i));
    240 }
    241 
    242 /**
    243 * Generates a range of values `fn(0)..fn(n-1)`.
    244 */
    245 export function* iterRange(n, fn) {
    246  for (let i = 0; i < n; ++i) {
    247    yield fn(i);
    248  }
    249 }
    250 
    251 /** Creates a (reusable) iterable object that maps `f` over `xs`, lazily. */
    252 export function mapLazy(xs, f) {
    253  return {
    254    *[Symbol.iterator]() {
    255      for (const x of xs) {
    256        yield f(x);
    257      }
    258    }
    259  };
    260 }
    261 
    262 /** Count the number of elements `x` for which `predicate(x)` is true. */
    263 export function count(xs, predicate) {
    264  let count = 0;
    265  for (const x of xs) {
    266    if (predicate(x)) count++;
    267  }
    268  return count;
    269 }
    270 
    271 const ReorderOrders = {
    272  forward: true,
    273  backward: true,
    274  shiftByHalf: true
    275 };
    276 
    277 export const kReorderOrderKeys = keysOf(ReorderOrders);
    278 
    279 /**
    280 * Creates a new array from the given array with the first half
    281 * swapped with the last half.
    282 */
    283 export function shiftByHalf(arr) {
    284  const len = arr.length;
    285  const half = len / 2 | 0;
    286  const firstHalf = arr.splice(0, half);
    287  return [...arr, ...firstHalf];
    288 }
    289 
    290 /**
    291 * Creates a reordered array from the input array based on the Order
    292 */
    293 export function reorder(order, arr) {
    294  switch (order) {
    295    case 'forward':
    296      return arr.slice();
    297    case 'backward':
    298      return arr.slice().reverse();
    299    case 'shiftByHalf':{
    300        // should this be pseudo random?
    301        return shiftByHalf(arr);
    302      }
    303  }
    304 }
    305 
    306 /**
    307 * A typed version of Object.entries
    308 */
    309 
    310 export function typedEntries(obj) {
    311  // The cast is done once, inside the helper function,
    312  // keeping the call site clean and type-safe.
    313  return Object.entries(obj);
    314 }
    315 
    316 const TypedArrayBufferViewInstances = [
    317 new Uint8Array(),
    318 new Uint8ClampedArray(),
    319 new Uint16Array(),
    320 new Uint32Array(),
    321 new Int8Array(),
    322 new Int16Array(),
    323 new Int32Array(),
    324 new Float16Array(),
    325 new Float32Array(),
    326 new Float64Array(),
    327 new BigInt64Array(),
    328 new BigUint64Array()];
    329 
    330 
    331 
    332 
    333 
    334 
    335 
    336 
    337 
    338 
    339 
    340 
    341 
    342 
    343 
    344 
    345 
    346 
    347 
    348 
    349 
    350 
    351 
    352 
    353 export const kTypedArrayBufferViews =
    354 
    355 {
    356  ...(() => {
    357 
    358    const result = {};
    359    for (const v of TypedArrayBufferViewInstances) {
    360      result[v.constructor.name] = v.constructor;
    361    }
    362    return result;
    363  })()
    364 };
    365 export const kTypedArrayBufferViewKeys = keysOf(kTypedArrayBufferViews);
    366 export const kTypedArrayBufferViewConstructors = Object.values(kTypedArrayBufferViews);
    367 
    368 
    369 
    370 
    371 
    372 
    373 
    374 
    375 
    376 
    377 
    378 
    379 
    380 
    381 
    382 
    383 
    384 
    385 
    386 
    387 /**
    388 * Creates a case parameter for a typedarray.
    389 *
    390 * You can't put typedarrays in case parameters directly so instead of
    391 *
    392 * ```
    393 * u.combine('data', [
    394 *   new Uint8Array([1, 2, 3]),
    395 *   new Float32Array([4, 5, 6]),
    396 * ])
    397 * ```
    398 *
    399 * You can use
    400 *
    401 * ```
    402 * u.combine('data', [
    403 *   typedArrayParam('Uint8Array' [1, 2, 3]),
    404 *   typedArrayParam('Float32Array' [4, 5, 6]),
    405 * ])
    406 * ```
    407 *
    408 * and then convert the params to typedarrays eg.
    409 *
    410 * ```
    411 *  .fn(t => {
    412 *    const data = t.params.data.map(v => typedArrayFromParam(v));
    413 *  })
    414 * ```
    415 */
    416 export function typedArrayParam(
    417 type,
    418 data)
    419 {
    420  return { type, data };
    421 }
    422 
    423 export function createTypedArray(
    424 type,
    425 data)
    426 {
    427  return new kTypedArrayBufferViews[type](data);
    428 }
    429 
    430 /**
    431 * Converts a TypedArrayParam to a typedarray. See typedArrayParam
    432 */
    433 export function typedArrayFromParam(
    434 param)
    435 {
    436  const { type, data } = param;
    437  return createTypedArray(type, data);
    438 }
    439 
    440 function subarrayAsU8(
    441 buf,
    442 { start = 0, length })
    443 {
    444  if (buf instanceof ArrayBuffer) {
    445    return new Uint8Array(buf, start, length);
    446  } else if (buf instanceof Uint8Array || buf instanceof Uint8ClampedArray) {
    447    // Don't wrap in new views if we don't need to.
    448    if (start === 0 && (length === undefined || length === buf.byteLength)) {
    449      return buf;
    450    }
    451  }
    452  const byteOffset = buf.byteOffset + start * buf.BYTES_PER_ELEMENT;
    453  const byteLength =
    454  length !== undefined ?
    455  length * buf.BYTES_PER_ELEMENT :
    456  buf.byteLength - (byteOffset - buf.byteOffset);
    457  return new Uint8Array(buf.buffer, byteOffset, byteLength);
    458 }
    459 
    460 /**
    461 * Copy a range of bytes from one ArrayBuffer or TypedArray to another.
    462 *
    463 * `start`/`length` are in elements (or in bytes, if ArrayBuffer).
    464 */
    465 export function memcpy(
    466 src,
    467 dst)
    468 {
    469  subarrayAsU8(dst.dst, dst).set(subarrayAsU8(src.src, src));
    470 }
    471 
    472 /**
    473 * Used to create a value that is specified by multiplying some runtime value
    474 * by a constant and then adding a constant to it.
    475 */
    476 
    477 
    478 
    479 
    480 
    481 /**
    482 * Filters out SpecValues that are the same.
    483 */
    484 export function filterUniqueValueTestVariants(valueTestVariants) {
    485  return new Map(
    486    valueTestVariants.map((v) => [`m:${v.mult},a:${v.add}`, v])
    487  ).values();
    488 }
    489 
    490 /**
    491 * Used to create a value that is specified by multiplied some runtime value
    492 * by a constant and then adding a constant to it. This happens often in test
    493 * with limits that can only be known at runtime and yet we need a way to
    494 * add parameters to a test and those parameters must be constants.
    495 */
    496 export function makeValueTestVariant(base, variant) {
    497  return base * variant.mult + variant.add;
    498 }
    499 
    500 /**
    501 * Use instead of features.has because feature's has takes any string
    502 * and we want to prevent typos.
    503 */
    504 export function hasFeature(features, feature) {
    505 
    506  return features.has(feature);
    507 }
    508 
    509 /** Convenience helper for combinations of 1-2 usage bits from a list of usage bits. */
    510 export function combinationsOfOneOrTwoUsages(usages) {
    511  const combinations = [];
    512  for (const usage0 of usages) {
    513    for (const usage1 of usages) {
    514      if (usage0 <= usage1) {
    515        combinations.push(usage0 | usage1);
    516      }
    517    }
    518  }
    519  return combinations;
    520 }