11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst {
31cb0ef41Sopenharmony_ci  ArrayPrototypePush,
41cb0ef41Sopenharmony_ci  ArrayPrototypePushApply,
51cb0ef41Sopenharmony_ci  ArrayPrototypeReduce,
61cb0ef41Sopenharmony_ci  ArrayPrototypeShift,
71cb0ef41Sopenharmony_ci  ArrayPrototypeSlice,
81cb0ef41Sopenharmony_ci  ArrayPrototypeSome,
91cb0ef41Sopenharmony_ci  ArrayPrototypeUnshift,
101cb0ef41Sopenharmony_ci  FunctionPrototype,
111cb0ef41Sopenharmony_ci  MathMax,
121cb0ef41Sopenharmony_ci  Number,
131cb0ef41Sopenharmony_ci  ObjectSeal,
141cb0ef41Sopenharmony_ci  PromisePrototypeThen,
151cb0ef41Sopenharmony_ci  PromiseResolve,
161cb0ef41Sopenharmony_ci  SafePromisePrototypeFinally,
171cb0ef41Sopenharmony_ci  ReflectApply,
181cb0ef41Sopenharmony_ci  RegExpPrototypeExec,
191cb0ef41Sopenharmony_ci  SafeMap,
201cb0ef41Sopenharmony_ci  SafeSet,
211cb0ef41Sopenharmony_ci  SafePromiseAll,
221cb0ef41Sopenharmony_ci  SafePromiseRace,
231cb0ef41Sopenharmony_ci  SymbolDispose,
241cb0ef41Sopenharmony_ci  ObjectDefineProperty,
251cb0ef41Sopenharmony_ci  Symbol,
261cb0ef41Sopenharmony_ci} = primordials;
271cb0ef41Sopenharmony_ciconst { getCallerLocation } = internalBinding('util');
281cb0ef41Sopenharmony_ciconst { addAbortListener } = require('events');
291cb0ef41Sopenharmony_ciconst { AsyncResource } = require('async_hooks');
301cb0ef41Sopenharmony_ciconst { AbortController } = require('internal/abort_controller');
311cb0ef41Sopenharmony_ciconst {
321cb0ef41Sopenharmony_ci  codes: {
331cb0ef41Sopenharmony_ci    ERR_INVALID_ARG_TYPE,
341cb0ef41Sopenharmony_ci    ERR_TEST_FAILURE,
351cb0ef41Sopenharmony_ci  },
361cb0ef41Sopenharmony_ci  AbortError,
371cb0ef41Sopenharmony_ci} = require('internal/errors');
381cb0ef41Sopenharmony_ciconst { MockTracker } = require('internal/test_runner/mock/mock');
391cb0ef41Sopenharmony_ciconst { TestsStream } = require('internal/test_runner/tests_stream');
401cb0ef41Sopenharmony_ciconst {
411cb0ef41Sopenharmony_ci  createDeferredCallback,
421cb0ef41Sopenharmony_ci  countCompletedTest,
431cb0ef41Sopenharmony_ci  isTestFailureError,
441cb0ef41Sopenharmony_ci  parseCommandLine,
451cb0ef41Sopenharmony_ci} = require('internal/test_runner/utils');
461cb0ef41Sopenharmony_ciconst {
471cb0ef41Sopenharmony_ci  createDeferredPromise,
481cb0ef41Sopenharmony_ci  kEmptyObject,
491cb0ef41Sopenharmony_ci  once: runOnce,
501cb0ef41Sopenharmony_ci} = require('internal/util');
511cb0ef41Sopenharmony_ciconst { isPromise } = require('internal/util/types');
521cb0ef41Sopenharmony_ciconst {
531cb0ef41Sopenharmony_ci  validateAbortSignal,
541cb0ef41Sopenharmony_ci  validateNumber,
551cb0ef41Sopenharmony_ci  validateOneOf,
561cb0ef41Sopenharmony_ci  validateUint32,
571cb0ef41Sopenharmony_ci} = require('internal/validators');
581cb0ef41Sopenharmony_ciconst { setTimeout } = require('timers');
591cb0ef41Sopenharmony_ciconst { TIMEOUT_MAX } = require('internal/timers');
601cb0ef41Sopenharmony_ciconst { availableParallelism } = require('os');
611cb0ef41Sopenharmony_ciconst { bigint: hrtime } = process.hrtime;
621cb0ef41Sopenharmony_ciconst kCallbackAndPromisePresent = 'callbackAndPromisePresent';
631cb0ef41Sopenharmony_ciconst kCancelledByParent = 'cancelledByParent';
641cb0ef41Sopenharmony_ciconst kAborted = 'testAborted';
651cb0ef41Sopenharmony_ciconst kParentAlreadyFinished = 'parentAlreadyFinished';
661cb0ef41Sopenharmony_ciconst kSubtestsFailed = 'subtestsFailed';
671cb0ef41Sopenharmony_ciconst kTestCodeFailure = 'testCodeFailure';
681cb0ef41Sopenharmony_ciconst kTestTimeoutFailure = 'testTimeoutFailure';
691cb0ef41Sopenharmony_ciconst kHookFailure = 'hookFailed';
701cb0ef41Sopenharmony_ciconst kDefaultTimeout = null;
711cb0ef41Sopenharmony_ciconst noop = FunctionPrototype;
721cb0ef41Sopenharmony_ciconst kShouldAbort = Symbol('kShouldAbort');
731cb0ef41Sopenharmony_ciconst kFilename = process.argv?.[1];
741cb0ef41Sopenharmony_ciconst kHookNames = ObjectSeal(['before', 'after', 'beforeEach', 'afterEach']);
751cb0ef41Sopenharmony_ciconst kUnwrapErrors = new SafeSet()
761cb0ef41Sopenharmony_ci  .add(kTestCodeFailure).add(kHookFailure)
771cb0ef41Sopenharmony_ci  .add('uncaughtException').add('unhandledRejection');
781cb0ef41Sopenharmony_ciconst { testNamePatterns, testOnlyFlag } = parseCommandLine();
791cb0ef41Sopenharmony_cilet kResistStopPropagation;
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_cifunction stopTest(timeout, signal) {
821cb0ef41Sopenharmony_ci  const deferred = createDeferredPromise();
831cb0ef41Sopenharmony_ci  const abortListener = addAbortListener(signal, deferred.resolve);
841cb0ef41Sopenharmony_ci  let timer;
851cb0ef41Sopenharmony_ci  let disposeFunction;
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  if (timeout === kDefaultTimeout) {
881cb0ef41Sopenharmony_ci    disposeFunction = abortListener[SymbolDispose];
891cb0ef41Sopenharmony_ci  } else {
901cb0ef41Sopenharmony_ci    timer = setTimeout(() => deferred.resolve(), timeout);
911cb0ef41Sopenharmony_ci    timer.unref();
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci    ObjectDefineProperty(deferred, 'promise', {
941cb0ef41Sopenharmony_ci      __proto__: null,
951cb0ef41Sopenharmony_ci      configurable: true,
961cb0ef41Sopenharmony_ci      writable: true,
971cb0ef41Sopenharmony_ci      value: PromisePrototypeThen(deferred.promise, () => {
981cb0ef41Sopenharmony_ci        throw new ERR_TEST_FAILURE(
991cb0ef41Sopenharmony_ci          `test timed out after ${timeout}ms`,
1001cb0ef41Sopenharmony_ci          kTestTimeoutFailure,
1011cb0ef41Sopenharmony_ci        );
1021cb0ef41Sopenharmony_ci      }),
1031cb0ef41Sopenharmony_ci    });
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci    disposeFunction = () => {
1061cb0ef41Sopenharmony_ci      abortListener[SymbolDispose]();
1071cb0ef41Sopenharmony_ci      timer[SymbolDispose]();
1081cb0ef41Sopenharmony_ci    };
1091cb0ef41Sopenharmony_ci  }
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci  ObjectDefineProperty(deferred.promise, SymbolDispose, {
1121cb0ef41Sopenharmony_ci    __proto__: null,
1131cb0ef41Sopenharmony_ci    configurable: true,
1141cb0ef41Sopenharmony_ci    writable: true,
1151cb0ef41Sopenharmony_ci    value: disposeFunction,
1161cb0ef41Sopenharmony_ci  });
1171cb0ef41Sopenharmony_ci  return deferred.promise;
1181cb0ef41Sopenharmony_ci}
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ciclass TestContext {
1211cb0ef41Sopenharmony_ci  #test;
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  constructor(test) {
1241cb0ef41Sopenharmony_ci    this.#test = test;
1251cb0ef41Sopenharmony_ci  }
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci  get signal() {
1281cb0ef41Sopenharmony_ci    return this.#test.signal;
1291cb0ef41Sopenharmony_ci  }
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci  get name() {
1321cb0ef41Sopenharmony_ci    return this.#test.name;
1331cb0ef41Sopenharmony_ci  }
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci  diagnostic(message) {
1361cb0ef41Sopenharmony_ci    this.#test.diagnostic(message);
1371cb0ef41Sopenharmony_ci  }
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci  get mock() {
1401cb0ef41Sopenharmony_ci    this.#test.mock ??= new MockTracker();
1411cb0ef41Sopenharmony_ci    return this.#test.mock;
1421cb0ef41Sopenharmony_ci  }
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci  runOnly(value) {
1451cb0ef41Sopenharmony_ci    this.#test.runOnlySubtests = !!value;
1461cb0ef41Sopenharmony_ci  }
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci  skip(message) {
1491cb0ef41Sopenharmony_ci    this.#test.skip(message);
1501cb0ef41Sopenharmony_ci  }
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci  todo(message) {
1531cb0ef41Sopenharmony_ci    this.#test.todo(message);
1541cb0ef41Sopenharmony_ci  }
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci  test(name, options, fn) {
1571cb0ef41Sopenharmony_ci    const overrides = {
1581cb0ef41Sopenharmony_ci      __proto__: null,
1591cb0ef41Sopenharmony_ci      loc: getCallerLocation(),
1601cb0ef41Sopenharmony_ci    };
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci    const subtest = this.#test.createSubtest(
1631cb0ef41Sopenharmony_ci      // eslint-disable-next-line no-use-before-define
1641cb0ef41Sopenharmony_ci      Test, name, options, fn, overrides,
1651cb0ef41Sopenharmony_ci    );
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci    return subtest.start();
1681cb0ef41Sopenharmony_ci  }
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci  before(fn, options) {
1711cb0ef41Sopenharmony_ci    this.#test.createHook('before', fn, options);
1721cb0ef41Sopenharmony_ci  }
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  after(fn, options) {
1751cb0ef41Sopenharmony_ci    this.#test.createHook('after', fn, options);
1761cb0ef41Sopenharmony_ci  }
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ci  beforeEach(fn, options) {
1791cb0ef41Sopenharmony_ci    this.#test.createHook('beforeEach', fn, options);
1801cb0ef41Sopenharmony_ci  }
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci  afterEach(fn, options) {
1831cb0ef41Sopenharmony_ci    this.#test.createHook('afterEach', fn, options);
1841cb0ef41Sopenharmony_ci  }
1851cb0ef41Sopenharmony_ci}
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ciclass SuiteContext {
1881cb0ef41Sopenharmony_ci  #suite;
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci  constructor(suite) {
1911cb0ef41Sopenharmony_ci    this.#suite = suite;
1921cb0ef41Sopenharmony_ci  }
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_ci  get signal() {
1951cb0ef41Sopenharmony_ci    return this.#suite.signal;
1961cb0ef41Sopenharmony_ci  }
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci  get name() {
1991cb0ef41Sopenharmony_ci    return this.#suite.name;
2001cb0ef41Sopenharmony_ci  }
2011cb0ef41Sopenharmony_ci}
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ciclass Test extends AsyncResource {
2041cb0ef41Sopenharmony_ci  abortController;
2051cb0ef41Sopenharmony_ci  outerSignal;
2061cb0ef41Sopenharmony_ci  #reportedSubtest;
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci  constructor(options) {
2091cb0ef41Sopenharmony_ci    super('Test');
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci    let { fn, name, parent, skip } = options;
2121cb0ef41Sopenharmony_ci    const { concurrency, loc, only, timeout, todo, signal } = options;
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci    if (typeof fn !== 'function') {
2151cb0ef41Sopenharmony_ci      fn = noop;
2161cb0ef41Sopenharmony_ci    }
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci    if (typeof name !== 'string' || name === '') {
2191cb0ef41Sopenharmony_ci      name = fn.name || '<anonymous>';
2201cb0ef41Sopenharmony_ci    }
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci    if (!(parent instanceof Test)) {
2231cb0ef41Sopenharmony_ci      parent = null;
2241cb0ef41Sopenharmony_ci    }
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci    if (parent === null) {
2271cb0ef41Sopenharmony_ci      this.concurrency = 1;
2281cb0ef41Sopenharmony_ci      this.nesting = 0;
2291cb0ef41Sopenharmony_ci      this.only = testOnlyFlag;
2301cb0ef41Sopenharmony_ci      this.reporter = new TestsStream();
2311cb0ef41Sopenharmony_ci      this.runOnlySubtests = this.only;
2321cb0ef41Sopenharmony_ci      this.testNumber = 0;
2331cb0ef41Sopenharmony_ci      this.timeout = kDefaultTimeout;
2341cb0ef41Sopenharmony_ci      this.root = this;
2351cb0ef41Sopenharmony_ci      this.hooks = {
2361cb0ef41Sopenharmony_ci        __proto__: null,
2371cb0ef41Sopenharmony_ci        before: [],
2381cb0ef41Sopenharmony_ci        after: [],
2391cb0ef41Sopenharmony_ci        beforeEach: [],
2401cb0ef41Sopenharmony_ci        afterEach: [],
2411cb0ef41Sopenharmony_ci      };
2421cb0ef41Sopenharmony_ci    } else {
2431cb0ef41Sopenharmony_ci      const nesting = parent.parent === null ? parent.nesting :
2441cb0ef41Sopenharmony_ci        parent.nesting + 1;
2451cb0ef41Sopenharmony_ci
2461cb0ef41Sopenharmony_ci      this.concurrency = parent.concurrency;
2471cb0ef41Sopenharmony_ci      this.nesting = nesting;
2481cb0ef41Sopenharmony_ci      this.only = only ?? !parent.runOnlySubtests;
2491cb0ef41Sopenharmony_ci      this.reporter = parent.reporter;
2501cb0ef41Sopenharmony_ci      this.runOnlySubtests = !this.only;
2511cb0ef41Sopenharmony_ci      this.testNumber = parent.subtests.length + 1;
2521cb0ef41Sopenharmony_ci      this.timeout = parent.timeout;
2531cb0ef41Sopenharmony_ci      this.root = parent.root;
2541cb0ef41Sopenharmony_ci      this.hooks = {
2551cb0ef41Sopenharmony_ci        __proto__: null,
2561cb0ef41Sopenharmony_ci        before: [],
2571cb0ef41Sopenharmony_ci        after: [],
2581cb0ef41Sopenharmony_ci        beforeEach: ArrayPrototypeSlice(parent.hooks.beforeEach),
2591cb0ef41Sopenharmony_ci        afterEach: ArrayPrototypeSlice(parent.hooks.afterEach),
2601cb0ef41Sopenharmony_ci      };
2611cb0ef41Sopenharmony_ci    }
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci    switch (typeof concurrency) {
2641cb0ef41Sopenharmony_ci      case 'number':
2651cb0ef41Sopenharmony_ci        validateUint32(concurrency, 'options.concurrency', 1);
2661cb0ef41Sopenharmony_ci        this.concurrency = concurrency;
2671cb0ef41Sopenharmony_ci        break;
2681cb0ef41Sopenharmony_ci
2691cb0ef41Sopenharmony_ci      case 'boolean':
2701cb0ef41Sopenharmony_ci        if (concurrency) {
2711cb0ef41Sopenharmony_ci          this.concurrency = parent === null ?
2721cb0ef41Sopenharmony_ci            MathMax(availableParallelism() - 1, 1) : Infinity;
2731cb0ef41Sopenharmony_ci        } else {
2741cb0ef41Sopenharmony_ci          this.concurrency = 1;
2751cb0ef41Sopenharmony_ci        }
2761cb0ef41Sopenharmony_ci        break;
2771cb0ef41Sopenharmony_ci
2781cb0ef41Sopenharmony_ci      default:
2791cb0ef41Sopenharmony_ci        if (concurrency != null)
2801cb0ef41Sopenharmony_ci          throw new ERR_INVALID_ARG_TYPE('options.concurrency', ['boolean', 'number'], concurrency);
2811cb0ef41Sopenharmony_ci    }
2821cb0ef41Sopenharmony_ci
2831cb0ef41Sopenharmony_ci    if (timeout != null && timeout !== Infinity) {
2841cb0ef41Sopenharmony_ci      validateNumber(timeout, 'options.timeout', 0, TIMEOUT_MAX);
2851cb0ef41Sopenharmony_ci      this.timeout = timeout;
2861cb0ef41Sopenharmony_ci    }
2871cb0ef41Sopenharmony_ci
2881cb0ef41Sopenharmony_ci    this.name = name;
2891cb0ef41Sopenharmony_ci    this.parent = parent;
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci    if (testNamePatterns !== null && !this.matchesTestNamePatterns()) {
2921cb0ef41Sopenharmony_ci      skip = 'test name does not match pattern';
2931cb0ef41Sopenharmony_ci    }
2941cb0ef41Sopenharmony_ci
2951cb0ef41Sopenharmony_ci    if (testOnlyFlag && !this.only) {
2961cb0ef41Sopenharmony_ci      skip = '\'only\' option not set';
2971cb0ef41Sopenharmony_ci    }
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_ci    if (skip) {
3001cb0ef41Sopenharmony_ci      fn = noop;
3011cb0ef41Sopenharmony_ci    }
3021cb0ef41Sopenharmony_ci
3031cb0ef41Sopenharmony_ci    this.abortController = new AbortController();
3041cb0ef41Sopenharmony_ci    this.outerSignal = signal;
3051cb0ef41Sopenharmony_ci    this.signal = this.abortController.signal;
3061cb0ef41Sopenharmony_ci
3071cb0ef41Sopenharmony_ci    validateAbortSignal(signal, 'options.signal');
3081cb0ef41Sopenharmony_ci    if (signal) {
3091cb0ef41Sopenharmony_ci      kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation;
3101cb0ef41Sopenharmony_ci    }
3111cb0ef41Sopenharmony_ci
3121cb0ef41Sopenharmony_ci    this.outerSignal?.addEventListener(
3131cb0ef41Sopenharmony_ci      'abort',
3141cb0ef41Sopenharmony_ci      this.#abortHandler,
3151cb0ef41Sopenharmony_ci      { __proto__: null, [kResistStopPropagation]: true },
3161cb0ef41Sopenharmony_ci    );
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_ci    this.fn = fn;
3191cb0ef41Sopenharmony_ci    this.harness = null; // Configured on the root test by the test harness.
3201cb0ef41Sopenharmony_ci    this.mock = null;
3211cb0ef41Sopenharmony_ci    this.cancelled = false;
3221cb0ef41Sopenharmony_ci    this.skipped = skip !== undefined && skip !== false;
3231cb0ef41Sopenharmony_ci    this.isTodo = todo !== undefined && todo !== false;
3241cb0ef41Sopenharmony_ci    this.startTime = null;
3251cb0ef41Sopenharmony_ci    this.endTime = null;
3261cb0ef41Sopenharmony_ci    this.passed = false;
3271cb0ef41Sopenharmony_ci    this.error = null;
3281cb0ef41Sopenharmony_ci    this.diagnostics = [];
3291cb0ef41Sopenharmony_ci    this.message = typeof skip === 'string' ? skip :
3301cb0ef41Sopenharmony_ci      typeof todo === 'string' ? todo : null;
3311cb0ef41Sopenharmony_ci    this.activeSubtests = 0;
3321cb0ef41Sopenharmony_ci    this.pendingSubtests = [];
3331cb0ef41Sopenharmony_ci    this.readySubtests = new SafeMap();
3341cb0ef41Sopenharmony_ci    this.subtests = [];
3351cb0ef41Sopenharmony_ci    this.waitingOn = 0;
3361cb0ef41Sopenharmony_ci    this.finished = false;
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_ci    if (!testOnlyFlag && (only || this.runOnlySubtests)) {
3391cb0ef41Sopenharmony_ci      const warning =
3401cb0ef41Sopenharmony_ci        "'only' and 'runOnly' require the --test-only command-line option.";
3411cb0ef41Sopenharmony_ci      this.diagnostic(warning);
3421cb0ef41Sopenharmony_ci    }
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ci    if (loc === undefined || kFilename === undefined) {
3451cb0ef41Sopenharmony_ci      this.loc = undefined;
3461cb0ef41Sopenharmony_ci    } else {
3471cb0ef41Sopenharmony_ci      this.loc = {
3481cb0ef41Sopenharmony_ci        __proto__: null,
3491cb0ef41Sopenharmony_ci        line: loc[0],
3501cb0ef41Sopenharmony_ci        column: loc[1],
3511cb0ef41Sopenharmony_ci        file: loc[2],
3521cb0ef41Sopenharmony_ci      };
3531cb0ef41Sopenharmony_ci    }
3541cb0ef41Sopenharmony_ci  }
3551cb0ef41Sopenharmony_ci
3561cb0ef41Sopenharmony_ci  matchesTestNamePatterns() {
3571cb0ef41Sopenharmony_ci    return ArrayPrototypeSome(testNamePatterns, (re) => RegExpPrototypeExec(re, this.name) !== null) ||
3581cb0ef41Sopenharmony_ci      this.parent?.matchesTestNamePatterns();
3591cb0ef41Sopenharmony_ci  }
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_ci  hasConcurrency() {
3621cb0ef41Sopenharmony_ci    return this.concurrency > this.activeSubtests;
3631cb0ef41Sopenharmony_ci  }
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_ci  addPendingSubtest(deferred) {
3661cb0ef41Sopenharmony_ci    ArrayPrototypePush(this.pendingSubtests, deferred);
3671cb0ef41Sopenharmony_ci  }
3681cb0ef41Sopenharmony_ci
3691cb0ef41Sopenharmony_ci  async processPendingSubtests() {
3701cb0ef41Sopenharmony_ci    while (this.pendingSubtests.length > 0 && this.hasConcurrency()) {
3711cb0ef41Sopenharmony_ci      const deferred = ArrayPrototypeShift(this.pendingSubtests);
3721cb0ef41Sopenharmony_ci      const test = deferred.test;
3731cb0ef41Sopenharmony_ci      this.reporter.dequeue(test.nesting, test.loc, test.name);
3741cb0ef41Sopenharmony_ci      await test.run();
3751cb0ef41Sopenharmony_ci      deferred.resolve();
3761cb0ef41Sopenharmony_ci    }
3771cb0ef41Sopenharmony_ci  }
3781cb0ef41Sopenharmony_ci
3791cb0ef41Sopenharmony_ci  addReadySubtest(subtest) {
3801cb0ef41Sopenharmony_ci    this.readySubtests.set(subtest.testNumber, subtest);
3811cb0ef41Sopenharmony_ci  }
3821cb0ef41Sopenharmony_ci
3831cb0ef41Sopenharmony_ci  processReadySubtestRange(canSend) {
3841cb0ef41Sopenharmony_ci    const start = this.waitingOn;
3851cb0ef41Sopenharmony_ci    const end = start + this.readySubtests.size;
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_ci    for (let i = start; i < end; i++) {
3881cb0ef41Sopenharmony_ci      const subtest = this.readySubtests.get(i);
3891cb0ef41Sopenharmony_ci
3901cb0ef41Sopenharmony_ci      // Check if the specified subtest is in the map. If it is not, return
3911cb0ef41Sopenharmony_ci      // early to avoid trying to process any more tests since they would be
3921cb0ef41Sopenharmony_ci      // out of order.
3931cb0ef41Sopenharmony_ci      if (subtest === undefined) {
3941cb0ef41Sopenharmony_ci        return;
3951cb0ef41Sopenharmony_ci      }
3961cb0ef41Sopenharmony_ci
3971cb0ef41Sopenharmony_ci      // Call isClearToSend() in the loop so that it is:
3981cb0ef41Sopenharmony_ci      // - Only called if there are results to report in the correct order.
3991cb0ef41Sopenharmony_ci      // - Guaranteed to only be called a maximum of once per call to
4001cb0ef41Sopenharmony_ci      //   processReadySubtestRange().
4011cb0ef41Sopenharmony_ci      canSend = canSend || this.isClearToSend();
4021cb0ef41Sopenharmony_ci
4031cb0ef41Sopenharmony_ci      if (!canSend) {
4041cb0ef41Sopenharmony_ci        return;
4051cb0ef41Sopenharmony_ci      }
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_ci      if (i === 1 && this.parent !== null) {
4081cb0ef41Sopenharmony_ci        this.reportStarted();
4091cb0ef41Sopenharmony_ci      }
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci      // Report the subtest's results and remove it from the ready map.
4121cb0ef41Sopenharmony_ci      subtest.finalize();
4131cb0ef41Sopenharmony_ci      this.readySubtests.delete(i);
4141cb0ef41Sopenharmony_ci    }
4151cb0ef41Sopenharmony_ci  }
4161cb0ef41Sopenharmony_ci
4171cb0ef41Sopenharmony_ci  createSubtest(Factory, name, options, fn, overrides) {
4181cb0ef41Sopenharmony_ci    if (typeof name === 'function') {
4191cb0ef41Sopenharmony_ci      fn = name;
4201cb0ef41Sopenharmony_ci    } else if (name !== null && typeof name === 'object') {
4211cb0ef41Sopenharmony_ci      fn = options;
4221cb0ef41Sopenharmony_ci      options = name;
4231cb0ef41Sopenharmony_ci    } else if (typeof options === 'function') {
4241cb0ef41Sopenharmony_ci      fn = options;
4251cb0ef41Sopenharmony_ci    }
4261cb0ef41Sopenharmony_ci
4271cb0ef41Sopenharmony_ci    if (options === null || typeof options !== 'object') {
4281cb0ef41Sopenharmony_ci      options = kEmptyObject;
4291cb0ef41Sopenharmony_ci    }
4301cb0ef41Sopenharmony_ci
4311cb0ef41Sopenharmony_ci    let parent = this;
4321cb0ef41Sopenharmony_ci
4331cb0ef41Sopenharmony_ci    // If this test has already ended, attach this test to the root test so
4341cb0ef41Sopenharmony_ci    // that the error can be properly reported.
4351cb0ef41Sopenharmony_ci    const preventAddingSubtests = this.finished || this.buildPhaseFinished;
4361cb0ef41Sopenharmony_ci    if (preventAddingSubtests) {
4371cb0ef41Sopenharmony_ci      while (parent.parent !== null) {
4381cb0ef41Sopenharmony_ci        parent = parent.parent;
4391cb0ef41Sopenharmony_ci      }
4401cb0ef41Sopenharmony_ci    }
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_ci    const test = new Factory({ __proto__: null, fn, name, parent, ...options, ...overrides });
4431cb0ef41Sopenharmony_ci
4441cb0ef41Sopenharmony_ci    if (parent.waitingOn === 0) {
4451cb0ef41Sopenharmony_ci      parent.waitingOn = test.testNumber;
4461cb0ef41Sopenharmony_ci    }
4471cb0ef41Sopenharmony_ci
4481cb0ef41Sopenharmony_ci    if (preventAddingSubtests) {
4491cb0ef41Sopenharmony_ci      test.startTime = test.startTime || hrtime();
4501cb0ef41Sopenharmony_ci      test.fail(
4511cb0ef41Sopenharmony_ci        new ERR_TEST_FAILURE(
4521cb0ef41Sopenharmony_ci          'test could not be started because its parent finished',
4531cb0ef41Sopenharmony_ci          kParentAlreadyFinished,
4541cb0ef41Sopenharmony_ci        ),
4551cb0ef41Sopenharmony_ci      );
4561cb0ef41Sopenharmony_ci    }
4571cb0ef41Sopenharmony_ci
4581cb0ef41Sopenharmony_ci    ArrayPrototypePush(parent.subtests, test);
4591cb0ef41Sopenharmony_ci    return test;
4601cb0ef41Sopenharmony_ci  }
4611cb0ef41Sopenharmony_ci
4621cb0ef41Sopenharmony_ci  #abortHandler = () => {
4631cb0ef41Sopenharmony_ci    const error = this.outerSignal?.reason || new AbortError('The test was aborted');
4641cb0ef41Sopenharmony_ci    error.failureType = kAborted;
4651cb0ef41Sopenharmony_ci    this.#cancel(error);
4661cb0ef41Sopenharmony_ci  };
4671cb0ef41Sopenharmony_ci
4681cb0ef41Sopenharmony_ci  #cancel(error) {
4691cb0ef41Sopenharmony_ci    if (this.endTime !== null) {
4701cb0ef41Sopenharmony_ci      return;
4711cb0ef41Sopenharmony_ci    }
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_ci    this.fail(error ||
4741cb0ef41Sopenharmony_ci      new ERR_TEST_FAILURE(
4751cb0ef41Sopenharmony_ci        'test did not finish before its parent and was cancelled',
4761cb0ef41Sopenharmony_ci        kCancelledByParent,
4771cb0ef41Sopenharmony_ci      ),
4781cb0ef41Sopenharmony_ci    );
4791cb0ef41Sopenharmony_ci    this.startTime = this.startTime || this.endTime; // If a test was canceled before it was started, e.g inside a hook
4801cb0ef41Sopenharmony_ci    this.cancelled = true;
4811cb0ef41Sopenharmony_ci    this.abortController.abort();
4821cb0ef41Sopenharmony_ci  }
4831cb0ef41Sopenharmony_ci
4841cb0ef41Sopenharmony_ci  createHook(name, fn, options) {
4851cb0ef41Sopenharmony_ci    validateOneOf(name, 'hook name', kHookNames);
4861cb0ef41Sopenharmony_ci    // eslint-disable-next-line no-use-before-define
4871cb0ef41Sopenharmony_ci    const hook = new TestHook(fn, options);
4881cb0ef41Sopenharmony_ci    if (name === 'before' || name === 'after') {
4891cb0ef41Sopenharmony_ci      hook.run = runOnce(hook.run);
4901cb0ef41Sopenharmony_ci    }
4911cb0ef41Sopenharmony_ci    ArrayPrototypePush(this.hooks[name], hook);
4921cb0ef41Sopenharmony_ci    return hook;
4931cb0ef41Sopenharmony_ci  }
4941cb0ef41Sopenharmony_ci
4951cb0ef41Sopenharmony_ci  fail(err) {
4961cb0ef41Sopenharmony_ci    if (this.error !== null) {
4971cb0ef41Sopenharmony_ci      return;
4981cb0ef41Sopenharmony_ci    }
4991cb0ef41Sopenharmony_ci
5001cb0ef41Sopenharmony_ci    this.endTime = hrtime();
5011cb0ef41Sopenharmony_ci    this.passed = false;
5021cb0ef41Sopenharmony_ci    this.error = err;
5031cb0ef41Sopenharmony_ci  }
5041cb0ef41Sopenharmony_ci
5051cb0ef41Sopenharmony_ci  pass() {
5061cb0ef41Sopenharmony_ci    if (this.endTime !== null) {
5071cb0ef41Sopenharmony_ci      return;
5081cb0ef41Sopenharmony_ci    }
5091cb0ef41Sopenharmony_ci
5101cb0ef41Sopenharmony_ci    this.endTime = hrtime();
5111cb0ef41Sopenharmony_ci    this.passed = true;
5121cb0ef41Sopenharmony_ci  }
5131cb0ef41Sopenharmony_ci
5141cb0ef41Sopenharmony_ci  skip(message) {
5151cb0ef41Sopenharmony_ci    this.skipped = true;
5161cb0ef41Sopenharmony_ci    this.message = message;
5171cb0ef41Sopenharmony_ci  }
5181cb0ef41Sopenharmony_ci
5191cb0ef41Sopenharmony_ci  todo(message) {
5201cb0ef41Sopenharmony_ci    this.isTodo = true;
5211cb0ef41Sopenharmony_ci    this.message = message;
5221cb0ef41Sopenharmony_ci  }
5231cb0ef41Sopenharmony_ci
5241cb0ef41Sopenharmony_ci  diagnostic(message) {
5251cb0ef41Sopenharmony_ci    ArrayPrototypePush(this.diagnostics, message);
5261cb0ef41Sopenharmony_ci  }
5271cb0ef41Sopenharmony_ci
5281cb0ef41Sopenharmony_ci  start() {
5291cb0ef41Sopenharmony_ci    // If there is enough available concurrency to run the test now, then do
5301cb0ef41Sopenharmony_ci    // it. Otherwise, return a Promise to the caller and mark the test as
5311cb0ef41Sopenharmony_ci    // pending for later execution.
5321cb0ef41Sopenharmony_ci    this.reporter.enqueue(this.nesting, this.loc, this.name);
5331cb0ef41Sopenharmony_ci    if (!this.parent.hasConcurrency()) {
5341cb0ef41Sopenharmony_ci      const deferred = createDeferredPromise();
5351cb0ef41Sopenharmony_ci
5361cb0ef41Sopenharmony_ci      deferred.test = this;
5371cb0ef41Sopenharmony_ci      this.parent.addPendingSubtest(deferred);
5381cb0ef41Sopenharmony_ci      return deferred.promise;
5391cb0ef41Sopenharmony_ci    }
5401cb0ef41Sopenharmony_ci
5411cb0ef41Sopenharmony_ci    this.reporter.dequeue(this.nesting, this.loc, this.name);
5421cb0ef41Sopenharmony_ci    return this.run();
5431cb0ef41Sopenharmony_ci  }
5441cb0ef41Sopenharmony_ci
5451cb0ef41Sopenharmony_ci  [kShouldAbort]() {
5461cb0ef41Sopenharmony_ci    if (this.signal.aborted) {
5471cb0ef41Sopenharmony_ci      return true;
5481cb0ef41Sopenharmony_ci    }
5491cb0ef41Sopenharmony_ci    if (this.outerSignal?.aborted) {
5501cb0ef41Sopenharmony_ci      this.#abortHandler();
5511cb0ef41Sopenharmony_ci      return true;
5521cb0ef41Sopenharmony_ci    }
5531cb0ef41Sopenharmony_ci  }
5541cb0ef41Sopenharmony_ci
5551cb0ef41Sopenharmony_ci  getRunArgs() {
5561cb0ef41Sopenharmony_ci    const ctx = new TestContext(this);
5571cb0ef41Sopenharmony_ci    return { __proto__: null, ctx, args: [ctx] };
5581cb0ef41Sopenharmony_ci  }
5591cb0ef41Sopenharmony_ci
5601cb0ef41Sopenharmony_ci  async runHook(hook, args) {
5611cb0ef41Sopenharmony_ci    validateOneOf(hook, 'hook name', kHookNames);
5621cb0ef41Sopenharmony_ci    try {
5631cb0ef41Sopenharmony_ci      await ArrayPrototypeReduce(this.hooks[hook], async (prev, hook) => {
5641cb0ef41Sopenharmony_ci        await prev;
5651cb0ef41Sopenharmony_ci        await hook.run(args);
5661cb0ef41Sopenharmony_ci        if (hook.error) {
5671cb0ef41Sopenharmony_ci          throw hook.error;
5681cb0ef41Sopenharmony_ci        }
5691cb0ef41Sopenharmony_ci      }, PromiseResolve());
5701cb0ef41Sopenharmony_ci    } catch (err) {
5711cb0ef41Sopenharmony_ci      const error = new ERR_TEST_FAILURE(`failed running ${hook} hook`, kHookFailure);
5721cb0ef41Sopenharmony_ci      error.cause = isTestFailureError(err) ? err.cause : err;
5731cb0ef41Sopenharmony_ci      throw error;
5741cb0ef41Sopenharmony_ci    }
5751cb0ef41Sopenharmony_ci  }
5761cb0ef41Sopenharmony_ci
5771cb0ef41Sopenharmony_ci  async run() {
5781cb0ef41Sopenharmony_ci    if (this.parent !== null) {
5791cb0ef41Sopenharmony_ci      this.parent.activeSubtests++;
5801cb0ef41Sopenharmony_ci    }
5811cb0ef41Sopenharmony_ci    this.startTime = hrtime();
5821cb0ef41Sopenharmony_ci
5831cb0ef41Sopenharmony_ci    if (this[kShouldAbort]()) {
5841cb0ef41Sopenharmony_ci      this.postRun();
5851cb0ef41Sopenharmony_ci      return;
5861cb0ef41Sopenharmony_ci    }
5871cb0ef41Sopenharmony_ci
5881cb0ef41Sopenharmony_ci    const { args, ctx } = this.getRunArgs();
5891cb0ef41Sopenharmony_ci    const after = async () => {
5901cb0ef41Sopenharmony_ci      if (this.hooks.after.length > 0) {
5911cb0ef41Sopenharmony_ci        await this.runHook('after', { __proto__: null, args, ctx });
5921cb0ef41Sopenharmony_ci      }
5931cb0ef41Sopenharmony_ci    };
5941cb0ef41Sopenharmony_ci    const afterEach = runOnce(async () => {
5951cb0ef41Sopenharmony_ci      if (this.parent?.hooks.afterEach.length > 0) {
5961cb0ef41Sopenharmony_ci        await this.parent.runHook('afterEach', { __proto__: null, args, ctx });
5971cb0ef41Sopenharmony_ci      }
5981cb0ef41Sopenharmony_ci    });
5991cb0ef41Sopenharmony_ci
6001cb0ef41Sopenharmony_ci    let stopPromise;
6011cb0ef41Sopenharmony_ci
6021cb0ef41Sopenharmony_ci    try {
6031cb0ef41Sopenharmony_ci      if (this.parent?.hooks.before.length > 0) {
6041cb0ef41Sopenharmony_ci        await this.parent.runHook('before', this.parent.getRunArgs());
6051cb0ef41Sopenharmony_ci      }
6061cb0ef41Sopenharmony_ci      if (this.parent?.hooks.beforeEach.length > 0) {
6071cb0ef41Sopenharmony_ci        await this.parent.runHook('beforeEach', { __proto__: null, args, ctx });
6081cb0ef41Sopenharmony_ci      }
6091cb0ef41Sopenharmony_ci      stopPromise = stopTest(this.timeout, this.signal);
6101cb0ef41Sopenharmony_ci      const runArgs = ArrayPrototypeSlice(args);
6111cb0ef41Sopenharmony_ci      ArrayPrototypeUnshift(runArgs, this.fn, ctx);
6121cb0ef41Sopenharmony_ci
6131cb0ef41Sopenharmony_ci      if (this.fn.length === runArgs.length - 1) {
6141cb0ef41Sopenharmony_ci        // This test is using legacy Node.js error first callbacks.
6151cb0ef41Sopenharmony_ci        const { promise, cb } = createDeferredCallback();
6161cb0ef41Sopenharmony_ci
6171cb0ef41Sopenharmony_ci        ArrayPrototypePush(runArgs, cb);
6181cb0ef41Sopenharmony_ci        const ret = ReflectApply(this.runInAsyncScope, this, runArgs);
6191cb0ef41Sopenharmony_ci
6201cb0ef41Sopenharmony_ci        if (isPromise(ret)) {
6211cb0ef41Sopenharmony_ci          this.fail(new ERR_TEST_FAILURE(
6221cb0ef41Sopenharmony_ci            'passed a callback but also returned a Promise',
6231cb0ef41Sopenharmony_ci            kCallbackAndPromisePresent,
6241cb0ef41Sopenharmony_ci          ));
6251cb0ef41Sopenharmony_ci          await SafePromiseRace([ret, stopPromise]);
6261cb0ef41Sopenharmony_ci        } else {
6271cb0ef41Sopenharmony_ci          await SafePromiseRace([PromiseResolve(promise), stopPromise]);
6281cb0ef41Sopenharmony_ci        }
6291cb0ef41Sopenharmony_ci      } else {
6301cb0ef41Sopenharmony_ci        // This test is synchronous or using Promises.
6311cb0ef41Sopenharmony_ci        const promise = ReflectApply(this.runInAsyncScope, this, runArgs);
6321cb0ef41Sopenharmony_ci        await SafePromiseRace([PromiseResolve(promise), stopPromise]);
6331cb0ef41Sopenharmony_ci      }
6341cb0ef41Sopenharmony_ci
6351cb0ef41Sopenharmony_ci      if (this[kShouldAbort]()) {
6361cb0ef41Sopenharmony_ci        this.postRun();
6371cb0ef41Sopenharmony_ci        return;
6381cb0ef41Sopenharmony_ci      }
6391cb0ef41Sopenharmony_ci
6401cb0ef41Sopenharmony_ci      await afterEach();
6411cb0ef41Sopenharmony_ci      await after();
6421cb0ef41Sopenharmony_ci      this.pass();
6431cb0ef41Sopenharmony_ci    } catch (err) {
6441cb0ef41Sopenharmony_ci      try { await afterEach(); } catch { /* test is already failing, let's ignore the error */ }
6451cb0ef41Sopenharmony_ci      try { await after(); } catch { /* Ignore error. */ }
6461cb0ef41Sopenharmony_ci      if (isTestFailureError(err)) {
6471cb0ef41Sopenharmony_ci        if (err.failureType === kTestTimeoutFailure) {
6481cb0ef41Sopenharmony_ci          this.#cancel(err);
6491cb0ef41Sopenharmony_ci        } else {
6501cb0ef41Sopenharmony_ci          this.fail(err);
6511cb0ef41Sopenharmony_ci        }
6521cb0ef41Sopenharmony_ci      } else {
6531cb0ef41Sopenharmony_ci        this.fail(new ERR_TEST_FAILURE(err, kTestCodeFailure));
6541cb0ef41Sopenharmony_ci      }
6551cb0ef41Sopenharmony_ci    } finally {
6561cb0ef41Sopenharmony_ci      stopPromise?.[SymbolDispose]();
6571cb0ef41Sopenharmony_ci
6581cb0ef41Sopenharmony_ci      // Do not abort hooks and the root test as hooks instance are shared between tests suite so aborting them will
6591cb0ef41Sopenharmony_ci      // cause them to not run for further tests.
6601cb0ef41Sopenharmony_ci      if (this.parent !== null) {
6611cb0ef41Sopenharmony_ci        this.abortController.abort();
6621cb0ef41Sopenharmony_ci      }
6631cb0ef41Sopenharmony_ci    }
6641cb0ef41Sopenharmony_ci
6651cb0ef41Sopenharmony_ci    if (this.parent !== null || typeof this.hookType === 'string') {
6661cb0ef41Sopenharmony_ci      // Clean up the test. Then, try to report the results and execute any
6671cb0ef41Sopenharmony_ci      // tests that were pending due to available concurrency.
6681cb0ef41Sopenharmony_ci      //
6691cb0ef41Sopenharmony_ci      // The root test is skipped here because it is a special case. Its
6701cb0ef41Sopenharmony_ci      // postRun() method is called when the process is getting ready to exit.
6711cb0ef41Sopenharmony_ci      // This helps catch any asynchronous activity that occurs after the tests
6721cb0ef41Sopenharmony_ci      // have finished executing.
6731cb0ef41Sopenharmony_ci      this.postRun();
6741cb0ef41Sopenharmony_ci    }
6751cb0ef41Sopenharmony_ci  }
6761cb0ef41Sopenharmony_ci
6771cb0ef41Sopenharmony_ci  postRun(pendingSubtestsError) {
6781cb0ef41Sopenharmony_ci    // If the test was failed before it even started, then the end time will
6791cb0ef41Sopenharmony_ci    // be earlier than the start time. Correct that here.
6801cb0ef41Sopenharmony_ci    if (this.endTime < this.startTime) {
6811cb0ef41Sopenharmony_ci      this.endTime = hrtime();
6821cb0ef41Sopenharmony_ci    }
6831cb0ef41Sopenharmony_ci    this.startTime ??= this.endTime;
6841cb0ef41Sopenharmony_ci
6851cb0ef41Sopenharmony_ci    // The test has run, so recursively cancel any outstanding subtests and
6861cb0ef41Sopenharmony_ci    // mark this test as failed if any subtests failed.
6871cb0ef41Sopenharmony_ci    this.pendingSubtests = [];
6881cb0ef41Sopenharmony_ci    let failed = 0;
6891cb0ef41Sopenharmony_ci    for (let i = 0; i < this.subtests.length; i++) {
6901cb0ef41Sopenharmony_ci      const subtest = this.subtests[i];
6911cb0ef41Sopenharmony_ci
6921cb0ef41Sopenharmony_ci      if (!subtest.finished) {
6931cb0ef41Sopenharmony_ci        subtest.#cancel(pendingSubtestsError);
6941cb0ef41Sopenharmony_ci        subtest.postRun(pendingSubtestsError);
6951cb0ef41Sopenharmony_ci      }
6961cb0ef41Sopenharmony_ci      if (!subtest.passed && !subtest.isTodo) {
6971cb0ef41Sopenharmony_ci        failed++;
6981cb0ef41Sopenharmony_ci      }
6991cb0ef41Sopenharmony_ci    }
7001cb0ef41Sopenharmony_ci
7011cb0ef41Sopenharmony_ci    if ((this.passed || this.parent === null) && failed > 0) {
7021cb0ef41Sopenharmony_ci      const subtestString = `subtest${failed > 1 ? 's' : ''}`;
7031cb0ef41Sopenharmony_ci      const msg = `${failed} ${subtestString} failed`;
7041cb0ef41Sopenharmony_ci
7051cb0ef41Sopenharmony_ci      this.fail(new ERR_TEST_FAILURE(msg, kSubtestsFailed));
7061cb0ef41Sopenharmony_ci    }
7071cb0ef41Sopenharmony_ci
7081cb0ef41Sopenharmony_ci    this.outerSignal?.removeEventListener('abort', this.#abortHandler);
7091cb0ef41Sopenharmony_ci    this.mock?.reset();
7101cb0ef41Sopenharmony_ci
7111cb0ef41Sopenharmony_ci    if (this.parent !== null) {
7121cb0ef41Sopenharmony_ci      this.parent.activeSubtests--;
7131cb0ef41Sopenharmony_ci      this.parent.addReadySubtest(this);
7141cb0ef41Sopenharmony_ci      this.parent.processReadySubtestRange(false);
7151cb0ef41Sopenharmony_ci      this.parent.processPendingSubtests();
7161cb0ef41Sopenharmony_ci
7171cb0ef41Sopenharmony_ci      if (this.parent === this.root &&
7181cb0ef41Sopenharmony_ci          this.root.activeSubtests === 0 &&
7191cb0ef41Sopenharmony_ci          this.root.pendingSubtests.length === 0 &&
7201cb0ef41Sopenharmony_ci          this.root.readySubtests.size === 0 &&
7211cb0ef41Sopenharmony_ci          this.root.hooks.after.length > 0) {
7221cb0ef41Sopenharmony_ci        // This is done so that any global after() hooks are run. At this point
7231cb0ef41Sopenharmony_ci        // all of the tests have finished running. However, there might be
7241cb0ef41Sopenharmony_ci        // ref'ed handles keeping the event loop alive. This gives the global
7251cb0ef41Sopenharmony_ci        // after() hook a chance to clean them up.
7261cb0ef41Sopenharmony_ci        this.root.run();
7271cb0ef41Sopenharmony_ci      }
7281cb0ef41Sopenharmony_ci    } else if (!this.reported) {
7291cb0ef41Sopenharmony_ci      const {
7301cb0ef41Sopenharmony_ci        diagnostics,
7311cb0ef41Sopenharmony_ci        harness,
7321cb0ef41Sopenharmony_ci        loc,
7331cb0ef41Sopenharmony_ci        nesting,
7341cb0ef41Sopenharmony_ci        reporter,
7351cb0ef41Sopenharmony_ci      } = this;
7361cb0ef41Sopenharmony_ci
7371cb0ef41Sopenharmony_ci      this.reported = true;
7381cb0ef41Sopenharmony_ci      reporter.plan(nesting, loc, harness.counters.topLevel);
7391cb0ef41Sopenharmony_ci
7401cb0ef41Sopenharmony_ci      // Call this harness.coverage() before collecting diagnostics, since failure to collect coverage is a diagnostic.
7411cb0ef41Sopenharmony_ci      const coverage = harness.coverage();
7421cb0ef41Sopenharmony_ci      for (let i = 0; i < diagnostics.length; i++) {
7431cb0ef41Sopenharmony_ci        reporter.diagnostic(nesting, loc, diagnostics[i]);
7441cb0ef41Sopenharmony_ci      }
7451cb0ef41Sopenharmony_ci
7461cb0ef41Sopenharmony_ci      reporter.diagnostic(nesting, loc, `tests ${harness.counters.all}`);
7471cb0ef41Sopenharmony_ci      reporter.diagnostic(nesting, loc, `suites ${harness.counters.suites}`);
7481cb0ef41Sopenharmony_ci      reporter.diagnostic(nesting, loc, `pass ${harness.counters.passed}`);
7491cb0ef41Sopenharmony_ci      reporter.diagnostic(nesting, loc, `fail ${harness.counters.failed}`);
7501cb0ef41Sopenharmony_ci      reporter.diagnostic(nesting, loc, `cancelled ${harness.counters.cancelled}`);
7511cb0ef41Sopenharmony_ci      reporter.diagnostic(nesting, loc, `skipped ${harness.counters.skipped}`);
7521cb0ef41Sopenharmony_ci      reporter.diagnostic(nesting, loc, `todo ${harness.counters.todo}`);
7531cb0ef41Sopenharmony_ci      reporter.diagnostic(nesting, loc, `duration_ms ${this.duration()}`);
7541cb0ef41Sopenharmony_ci
7551cb0ef41Sopenharmony_ci      if (coverage) {
7561cb0ef41Sopenharmony_ci        reporter.coverage(nesting, loc, coverage);
7571cb0ef41Sopenharmony_ci      }
7581cb0ef41Sopenharmony_ci
7591cb0ef41Sopenharmony_ci      reporter.end();
7601cb0ef41Sopenharmony_ci    }
7611cb0ef41Sopenharmony_ci  }
7621cb0ef41Sopenharmony_ci
7631cb0ef41Sopenharmony_ci  isClearToSend() {
7641cb0ef41Sopenharmony_ci    return this.parent === null ||
7651cb0ef41Sopenharmony_ci      (
7661cb0ef41Sopenharmony_ci        this.parent.waitingOn === this.testNumber && this.parent.isClearToSend()
7671cb0ef41Sopenharmony_ci      );
7681cb0ef41Sopenharmony_ci  }
7691cb0ef41Sopenharmony_ci
7701cb0ef41Sopenharmony_ci  finalize() {
7711cb0ef41Sopenharmony_ci    // By the time this function is called, the following can be relied on:
7721cb0ef41Sopenharmony_ci    // - The current test has completed or been cancelled.
7731cb0ef41Sopenharmony_ci    // - All of this test's subtests have completed or been cancelled.
7741cb0ef41Sopenharmony_ci    // - It is the current test's turn to report its results.
7751cb0ef41Sopenharmony_ci
7761cb0ef41Sopenharmony_ci    // Report any subtests that have not been reported yet. Since all of the
7771cb0ef41Sopenharmony_ci    // subtests have finished, it's safe to pass true to
7781cb0ef41Sopenharmony_ci    // processReadySubtestRange(), which will finalize all remaining subtests.
7791cb0ef41Sopenharmony_ci    this.processReadySubtestRange(true);
7801cb0ef41Sopenharmony_ci
7811cb0ef41Sopenharmony_ci    // Output this test's results and update the parent's waiting counter.
7821cb0ef41Sopenharmony_ci    this.report();
7831cb0ef41Sopenharmony_ci    this.parent.waitingOn++;
7841cb0ef41Sopenharmony_ci    this.finished = true;
7851cb0ef41Sopenharmony_ci  }
7861cb0ef41Sopenharmony_ci
7871cb0ef41Sopenharmony_ci  duration() {
7881cb0ef41Sopenharmony_ci    // Duration is recorded in BigInt nanoseconds. Convert to milliseconds.
7891cb0ef41Sopenharmony_ci    return Number(this.endTime - this.startTime) / 1_000_000;
7901cb0ef41Sopenharmony_ci  }
7911cb0ef41Sopenharmony_ci
7921cb0ef41Sopenharmony_ci  report() {
7931cb0ef41Sopenharmony_ci    countCompletedTest(this);
7941cb0ef41Sopenharmony_ci    if (this.subtests.length > 0) {
7951cb0ef41Sopenharmony_ci      this.reporter.plan(this.subtests[0].nesting, this.loc, this.subtests.length);
7961cb0ef41Sopenharmony_ci    } else {
7971cb0ef41Sopenharmony_ci      this.reportStarted();
7981cb0ef41Sopenharmony_ci    }
7991cb0ef41Sopenharmony_ci    let directive;
8001cb0ef41Sopenharmony_ci    const details = { __proto__: null, duration_ms: this.duration() };
8011cb0ef41Sopenharmony_ci
8021cb0ef41Sopenharmony_ci    if (this.skipped) {
8031cb0ef41Sopenharmony_ci      directive = this.reporter.getSkip(this.message);
8041cb0ef41Sopenharmony_ci    } else if (this.isTodo) {
8051cb0ef41Sopenharmony_ci      directive = this.reporter.getTodo(this.message);
8061cb0ef41Sopenharmony_ci    }
8071cb0ef41Sopenharmony_ci
8081cb0ef41Sopenharmony_ci    if (this.reportedType) {
8091cb0ef41Sopenharmony_ci      details.type = this.reportedType;
8101cb0ef41Sopenharmony_ci    }
8111cb0ef41Sopenharmony_ci
8121cb0ef41Sopenharmony_ci    if (this.passed) {
8131cb0ef41Sopenharmony_ci      this.reporter.ok(this.nesting, this.loc, this.testNumber, this.name, details, directive);
8141cb0ef41Sopenharmony_ci    } else {
8151cb0ef41Sopenharmony_ci      details.error = this.error;
8161cb0ef41Sopenharmony_ci      this.reporter.fail(this.nesting, this.loc, this.testNumber, this.name, details, directive);
8171cb0ef41Sopenharmony_ci    }
8181cb0ef41Sopenharmony_ci
8191cb0ef41Sopenharmony_ci    for (let i = 0; i < this.diagnostics.length; i++) {
8201cb0ef41Sopenharmony_ci      this.reporter.diagnostic(this.nesting, this.loc, this.diagnostics[i]);
8211cb0ef41Sopenharmony_ci    }
8221cb0ef41Sopenharmony_ci  }
8231cb0ef41Sopenharmony_ci
8241cb0ef41Sopenharmony_ci  reportStarted() {
8251cb0ef41Sopenharmony_ci    if (this.#reportedSubtest || this.parent === null) {
8261cb0ef41Sopenharmony_ci      return;
8271cb0ef41Sopenharmony_ci    }
8281cb0ef41Sopenharmony_ci    this.#reportedSubtest = true;
8291cb0ef41Sopenharmony_ci    this.parent.reportStarted();
8301cb0ef41Sopenharmony_ci    this.reporter.start(this.nesting, this.loc, this.name);
8311cb0ef41Sopenharmony_ci  }
8321cb0ef41Sopenharmony_ci}
8331cb0ef41Sopenharmony_ci
8341cb0ef41Sopenharmony_ciclass TestHook extends Test {
8351cb0ef41Sopenharmony_ci  #args;
8361cb0ef41Sopenharmony_ci  constructor(fn, options) {
8371cb0ef41Sopenharmony_ci    if (options === null || typeof options !== 'object') {
8381cb0ef41Sopenharmony_ci      options = kEmptyObject;
8391cb0ef41Sopenharmony_ci    }
8401cb0ef41Sopenharmony_ci    const { loc, timeout, signal } = options;
8411cb0ef41Sopenharmony_ci    super({ __proto__: null, fn, loc, timeout, signal });
8421cb0ef41Sopenharmony_ci
8431cb0ef41Sopenharmony_ci    this.parentTest = options.parent ?? null;
8441cb0ef41Sopenharmony_ci    this.hookType = options.hookType;
8451cb0ef41Sopenharmony_ci  }
8461cb0ef41Sopenharmony_ci  run(args) {
8471cb0ef41Sopenharmony_ci    if (this.error && !this.outerSignal?.aborted) {
8481cb0ef41Sopenharmony_ci      this.passed = false;
8491cb0ef41Sopenharmony_ci      this.error = null;
8501cb0ef41Sopenharmony_ci      this.abortController.abort();
8511cb0ef41Sopenharmony_ci      this.abortController = new AbortController();
8521cb0ef41Sopenharmony_ci      this.signal = this.abortController.signal;
8531cb0ef41Sopenharmony_ci    }
8541cb0ef41Sopenharmony_ci
8551cb0ef41Sopenharmony_ci    this.#args = args;
8561cb0ef41Sopenharmony_ci    return super.run();
8571cb0ef41Sopenharmony_ci  }
8581cb0ef41Sopenharmony_ci  getRunArgs() {
8591cb0ef41Sopenharmony_ci    return this.#args;
8601cb0ef41Sopenharmony_ci  }
8611cb0ef41Sopenharmony_ci  matchesTestNamePatterns() {
8621cb0ef41Sopenharmony_ci    return true;
8631cb0ef41Sopenharmony_ci  }
8641cb0ef41Sopenharmony_ci  postRun() {
8651cb0ef41Sopenharmony_ci    const { error, loc, parentTest: parent } = this;
8661cb0ef41Sopenharmony_ci
8671cb0ef41Sopenharmony_ci    // Report failures in the root test's after() hook.
8681cb0ef41Sopenharmony_ci    if (error && parent !== null &&
8691cb0ef41Sopenharmony_ci        parent === parent.root && this.hookType === 'after') {
8701cb0ef41Sopenharmony_ci
8711cb0ef41Sopenharmony_ci      if (isTestFailureError(error)) {
8721cb0ef41Sopenharmony_ci        error.failureType = kHookFailure;
8731cb0ef41Sopenharmony_ci      }
8741cb0ef41Sopenharmony_ci
8751cb0ef41Sopenharmony_ci      parent.reporter.fail(0, loc, parent.subtests.length + 1, loc.file, {
8761cb0ef41Sopenharmony_ci        __proto__: null,
8771cb0ef41Sopenharmony_ci        duration_ms: this.duration(),
8781cb0ef41Sopenharmony_ci        error,
8791cb0ef41Sopenharmony_ci      }, undefined);
8801cb0ef41Sopenharmony_ci    }
8811cb0ef41Sopenharmony_ci  }
8821cb0ef41Sopenharmony_ci}
8831cb0ef41Sopenharmony_ci
8841cb0ef41Sopenharmony_ciclass Suite extends Test {
8851cb0ef41Sopenharmony_ci  reportedType = 'suite';
8861cb0ef41Sopenharmony_ci  constructor(options) {
8871cb0ef41Sopenharmony_ci    super(options);
8881cb0ef41Sopenharmony_ci
8891cb0ef41Sopenharmony_ci    if (testNamePatterns !== null && !options.skip && !options.todo) {
8901cb0ef41Sopenharmony_ci      this.fn = options.fn || this.fn;
8911cb0ef41Sopenharmony_ci      this.skipped = false;
8921cb0ef41Sopenharmony_ci    }
8931cb0ef41Sopenharmony_ci    this.runOnlySubtests = testOnlyFlag;
8941cb0ef41Sopenharmony_ci
8951cb0ef41Sopenharmony_ci    try {
8961cb0ef41Sopenharmony_ci      const { ctx, args } = this.getRunArgs();
8971cb0ef41Sopenharmony_ci      const runArgs = [this.fn, ctx];
8981cb0ef41Sopenharmony_ci      ArrayPrototypePushApply(runArgs, args);
8991cb0ef41Sopenharmony_ci      this.buildSuite = SafePromisePrototypeFinally(
9001cb0ef41Sopenharmony_ci        PromisePrototypeThen(
9011cb0ef41Sopenharmony_ci          PromiseResolve(ReflectApply(this.runInAsyncScope, this, runArgs)),
9021cb0ef41Sopenharmony_ci          undefined,
9031cb0ef41Sopenharmony_ci          (err) => {
9041cb0ef41Sopenharmony_ci            this.fail(new ERR_TEST_FAILURE(err, kTestCodeFailure));
9051cb0ef41Sopenharmony_ci          }),
9061cb0ef41Sopenharmony_ci        () => {
9071cb0ef41Sopenharmony_ci          this.buildPhaseFinished = true;
9081cb0ef41Sopenharmony_ci        },
9091cb0ef41Sopenharmony_ci      );
9101cb0ef41Sopenharmony_ci    } catch (err) {
9111cb0ef41Sopenharmony_ci      this.fail(new ERR_TEST_FAILURE(err, kTestCodeFailure));
9121cb0ef41Sopenharmony_ci
9131cb0ef41Sopenharmony_ci      this.buildPhaseFinished = true;
9141cb0ef41Sopenharmony_ci    }
9151cb0ef41Sopenharmony_ci    this.fn = () => {};
9161cb0ef41Sopenharmony_ci  }
9171cb0ef41Sopenharmony_ci
9181cb0ef41Sopenharmony_ci  getRunArgs() {
9191cb0ef41Sopenharmony_ci    const ctx = new SuiteContext(this);
9201cb0ef41Sopenharmony_ci    return { __proto__: null, ctx, args: [ctx] };
9211cb0ef41Sopenharmony_ci  }
9221cb0ef41Sopenharmony_ci
9231cb0ef41Sopenharmony_ci  async run() {
9241cb0ef41Sopenharmony_ci    const hookArgs = this.getRunArgs();
9251cb0ef41Sopenharmony_ci
9261cb0ef41Sopenharmony_ci    let stopPromise;
9271cb0ef41Sopenharmony_ci    try {
9281cb0ef41Sopenharmony_ci      this.parent.activeSubtests++;
9291cb0ef41Sopenharmony_ci      await this.buildSuite;
9301cb0ef41Sopenharmony_ci      this.startTime = hrtime();
9311cb0ef41Sopenharmony_ci
9321cb0ef41Sopenharmony_ci      if (this[kShouldAbort]()) {
9331cb0ef41Sopenharmony_ci        this.subtests = [];
9341cb0ef41Sopenharmony_ci        this.postRun();
9351cb0ef41Sopenharmony_ci        return;
9361cb0ef41Sopenharmony_ci      }
9371cb0ef41Sopenharmony_ci
9381cb0ef41Sopenharmony_ci      if (this.parent.hooks.before.length > 0) {
9391cb0ef41Sopenharmony_ci        await this.parent.runHook('before', this.parent.getRunArgs());
9401cb0ef41Sopenharmony_ci      }
9411cb0ef41Sopenharmony_ci
9421cb0ef41Sopenharmony_ci      await this.runHook('before', hookArgs);
9431cb0ef41Sopenharmony_ci
9441cb0ef41Sopenharmony_ci      stopPromise = stopTest(this.timeout, this.signal);
9451cb0ef41Sopenharmony_ci      const subtests = this.skipped || this.error ? [] : this.subtests;
9461cb0ef41Sopenharmony_ci      const promise = SafePromiseAll(subtests, (subtests) => subtests.start());
9471cb0ef41Sopenharmony_ci
9481cb0ef41Sopenharmony_ci      await SafePromiseRace([promise, stopPromise]);
9491cb0ef41Sopenharmony_ci      await this.runHook('after', hookArgs);
9501cb0ef41Sopenharmony_ci
9511cb0ef41Sopenharmony_ci      this.pass();
9521cb0ef41Sopenharmony_ci    } catch (err) {
9531cb0ef41Sopenharmony_ci      if (isTestFailureError(err)) {
9541cb0ef41Sopenharmony_ci        this.fail(err);
9551cb0ef41Sopenharmony_ci      } else {
9561cb0ef41Sopenharmony_ci        this.fail(new ERR_TEST_FAILURE(err, kTestCodeFailure));
9571cb0ef41Sopenharmony_ci      }
9581cb0ef41Sopenharmony_ci    } finally {
9591cb0ef41Sopenharmony_ci      stopPromise?.[SymbolDispose]();
9601cb0ef41Sopenharmony_ci    }
9611cb0ef41Sopenharmony_ci
9621cb0ef41Sopenharmony_ci    this.postRun();
9631cb0ef41Sopenharmony_ci  }
9641cb0ef41Sopenharmony_ci}
9651cb0ef41Sopenharmony_ci
9661cb0ef41Sopenharmony_cimodule.exports = {
9671cb0ef41Sopenharmony_ci  kCancelledByParent,
9681cb0ef41Sopenharmony_ci  kSubtestsFailed,
9691cb0ef41Sopenharmony_ci  kTestCodeFailure,
9701cb0ef41Sopenharmony_ci  kTestTimeoutFailure,
9711cb0ef41Sopenharmony_ci  kAborted,
9721cb0ef41Sopenharmony_ci  kUnwrapErrors,
9731cb0ef41Sopenharmony_ci  Suite,
9741cb0ef41Sopenharmony_ci  Test,
9751cb0ef41Sopenharmony_ci};
976