11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst {
41cb0ef41Sopenharmony_ci  emitExperimentalWarning,
51cb0ef41Sopenharmony_ci} = require('internal/util');
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ciconst {
81cb0ef41Sopenharmony_ci  ArrayPrototypeForEach,
91cb0ef41Sopenharmony_ci  ArrayPrototypeIncludes,
101cb0ef41Sopenharmony_ci  DateNow,
111cb0ef41Sopenharmony_ci  FunctionPrototypeApply,
121cb0ef41Sopenharmony_ci  FunctionPrototypeBind,
131cb0ef41Sopenharmony_ci  ObjectDefineProperty,
141cb0ef41Sopenharmony_ci  ObjectGetOwnPropertyDescriptor,
151cb0ef41Sopenharmony_ci  Promise,
161cb0ef41Sopenharmony_ci  SymbolAsyncIterator,
171cb0ef41Sopenharmony_ci  SymbolDispose,
181cb0ef41Sopenharmony_ci  globalThis,
191cb0ef41Sopenharmony_ci} = primordials;
201cb0ef41Sopenharmony_ciconst {
211cb0ef41Sopenharmony_ci  validateAbortSignal,
221cb0ef41Sopenharmony_ci  validateArray,
231cb0ef41Sopenharmony_ci} = require('internal/validators');
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ciconst {
261cb0ef41Sopenharmony_ci  AbortError,
271cb0ef41Sopenharmony_ci  codes: {
281cb0ef41Sopenharmony_ci    ERR_INVALID_STATE,
291cb0ef41Sopenharmony_ci    ERR_INVALID_ARG_VALUE,
301cb0ef41Sopenharmony_ci  },
311cb0ef41Sopenharmony_ci} = require('internal/errors');
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ciconst PriorityQueue = require('internal/priority_queue');
341cb0ef41Sopenharmony_ciconst nodeTimers = require('timers');
351cb0ef41Sopenharmony_ciconst nodeTimersPromises = require('timers/promises');
361cb0ef41Sopenharmony_ciconst EventEmitter = require('events');
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_cilet kResistStopPropagation;
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_cifunction compareTimersLists(a, b) {
411cb0ef41Sopenharmony_ci  return (a.runAt - b.runAt) || (a.id - b.id);
421cb0ef41Sopenharmony_ci}
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_cifunction setPosition(node, pos) {
451cb0ef41Sopenharmony_ci  node.priorityQueuePosition = pos;
461cb0ef41Sopenharmony_ci}
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_cifunction abortIt(signal) {
491cb0ef41Sopenharmony_ci  return new AbortError(undefined, { __proto__: null, cause: signal.reason });
501cb0ef41Sopenharmony_ci}
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ciconst SUPPORTED_TIMERS = ['setTimeout', 'setInterval', 'setImmediate'];
531cb0ef41Sopenharmony_ciconst TIMERS_DEFAULT_INTERVAL = {
541cb0ef41Sopenharmony_ci  __proto__: null,
551cb0ef41Sopenharmony_ci  setImmediate: -1,
561cb0ef41Sopenharmony_ci};
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ciclass MockTimers {
591cb0ef41Sopenharmony_ci  #realSetTimeout;
601cb0ef41Sopenharmony_ci  #realClearTimeout;
611cb0ef41Sopenharmony_ci  #realSetInterval;
621cb0ef41Sopenharmony_ci  #realClearInterval;
631cb0ef41Sopenharmony_ci  #realSetImmediate;
641cb0ef41Sopenharmony_ci  #realClearImmediate;
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci  #realPromisifiedSetTimeout;
671cb0ef41Sopenharmony_ci  #realPromisifiedSetInterval;
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci  #realTimersSetTimeout;
701cb0ef41Sopenharmony_ci  #realTimersClearTimeout;
711cb0ef41Sopenharmony_ci  #realTimersSetInterval;
721cb0ef41Sopenharmony_ci  #realTimersClearInterval;
731cb0ef41Sopenharmony_ci  #realTimersSetImmediate;
741cb0ef41Sopenharmony_ci  #realTimersClearImmediate;
751cb0ef41Sopenharmony_ci  #realPromisifiedSetImmediate;
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  #timersInContext = [];
781cb0ef41Sopenharmony_ci  #isEnabled = false;
791cb0ef41Sopenharmony_ci  #currentTimer = 1;
801cb0ef41Sopenharmony_ci  #now = DateNow();
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci  #executionQueue = new PriorityQueue(compareTimersLists, setPosition);
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci  #setTimeout = FunctionPrototypeBind(this.#createTimer, this, false);
851cb0ef41Sopenharmony_ci  #clearTimeout = FunctionPrototypeBind(this.#clearTimer, this);
861cb0ef41Sopenharmony_ci  #setInterval = FunctionPrototypeBind(this.#createTimer, this, true);
871cb0ef41Sopenharmony_ci  #clearInterval = FunctionPrototypeBind(this.#clearTimer, this);
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci  #setImmediate = (callback, ...args) => {
901cb0ef41Sopenharmony_ci    return this.#createTimer(
911cb0ef41Sopenharmony_ci      false,
921cb0ef41Sopenharmony_ci      callback,
931cb0ef41Sopenharmony_ci      TIMERS_DEFAULT_INTERVAL.setImmediate,
941cb0ef41Sopenharmony_ci      ...args,
951cb0ef41Sopenharmony_ci    );
961cb0ef41Sopenharmony_ci  };
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci  #clearImmediate = FunctionPrototypeBind(this.#clearTimer, this);
991cb0ef41Sopenharmony_ci  constructor() {
1001cb0ef41Sopenharmony_ci    emitExperimentalWarning('The MockTimers API');
1011cb0ef41Sopenharmony_ci  }
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  #createTimer(isInterval, callback, delay, ...args) {
1041cb0ef41Sopenharmony_ci    const timerId = this.#currentTimer++;
1051cb0ef41Sopenharmony_ci    this.#executionQueue.insert({
1061cb0ef41Sopenharmony_ci      __proto__: null,
1071cb0ef41Sopenharmony_ci      id: timerId,
1081cb0ef41Sopenharmony_ci      callback,
1091cb0ef41Sopenharmony_ci      runAt: this.#now + delay,
1101cb0ef41Sopenharmony_ci      interval: isInterval,
1111cb0ef41Sopenharmony_ci      args,
1121cb0ef41Sopenharmony_ci    });
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci    return timerId;
1151cb0ef41Sopenharmony_ci  }
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  #clearTimer(position) {
1181cb0ef41Sopenharmony_ci    this.#executionQueue.removeAt(position);
1191cb0ef41Sopenharmony_ci  }
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci  async * #setIntervalPromisified(interval, startTime, options) {
1221cb0ef41Sopenharmony_ci    const context = this;
1231cb0ef41Sopenharmony_ci    const emitter = new EventEmitter();
1241cb0ef41Sopenharmony_ci    if (options?.signal) {
1251cb0ef41Sopenharmony_ci      validateAbortSignal(options.signal, 'options.signal');
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci      if (options.signal.aborted) {
1281cb0ef41Sopenharmony_ci        throw abortIt(options.signal);
1291cb0ef41Sopenharmony_ci      }
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci      const onAbort = (reason) => {
1321cb0ef41Sopenharmony_ci        emitter.emit('data', { __proto__: null, aborted: true, reason });
1331cb0ef41Sopenharmony_ci      };
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci      kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation;
1361cb0ef41Sopenharmony_ci      options.signal.addEventListener('abort', onAbort, {
1371cb0ef41Sopenharmony_ci        __proto__: null,
1381cb0ef41Sopenharmony_ci        once: true,
1391cb0ef41Sopenharmony_ci        [kResistStopPropagation]: true,
1401cb0ef41Sopenharmony_ci      });
1411cb0ef41Sopenharmony_ci    }
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci    const eventIt = EventEmitter.on(emitter, 'data');
1441cb0ef41Sopenharmony_ci    const callback = () => {
1451cb0ef41Sopenharmony_ci      startTime += interval;
1461cb0ef41Sopenharmony_ci      emitter.emit('data', startTime);
1471cb0ef41Sopenharmony_ci    };
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci    const timerId = this.#createTimer(true, callback, interval, options);
1501cb0ef41Sopenharmony_ci    const clearListeners = () => {
1511cb0ef41Sopenharmony_ci      emitter.removeAllListeners();
1521cb0ef41Sopenharmony_ci      context.#clearTimer(timerId);
1531cb0ef41Sopenharmony_ci    };
1541cb0ef41Sopenharmony_ci    const iterator = {
1551cb0ef41Sopenharmony_ci      __proto__: null,
1561cb0ef41Sopenharmony_ci      [SymbolAsyncIterator]() {
1571cb0ef41Sopenharmony_ci        return this;
1581cb0ef41Sopenharmony_ci      },
1591cb0ef41Sopenharmony_ci      async next() {
1601cb0ef41Sopenharmony_ci        const result = await eventIt.next();
1611cb0ef41Sopenharmony_ci        const value = result.value[0];
1621cb0ef41Sopenharmony_ci        if (value?.aborted) {
1631cb0ef41Sopenharmony_ci          iterator.return();
1641cb0ef41Sopenharmony_ci          throw abortIt(options.signal);
1651cb0ef41Sopenharmony_ci        }
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci        return {
1681cb0ef41Sopenharmony_ci          __proto__: null,
1691cb0ef41Sopenharmony_ci          done: result.done,
1701cb0ef41Sopenharmony_ci          value,
1711cb0ef41Sopenharmony_ci        };
1721cb0ef41Sopenharmony_ci      },
1731cb0ef41Sopenharmony_ci      async return() {
1741cb0ef41Sopenharmony_ci        clearListeners();
1751cb0ef41Sopenharmony_ci        return eventIt.return();
1761cb0ef41Sopenharmony_ci      },
1771cb0ef41Sopenharmony_ci    };
1781cb0ef41Sopenharmony_ci    yield* iterator;
1791cb0ef41Sopenharmony_ci  }
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci  #promisifyTimer({ timerFn, clearFn, ms, result, options }) {
1821cb0ef41Sopenharmony_ci    return new Promise((resolve, reject) => {
1831cb0ef41Sopenharmony_ci      if (options?.signal) {
1841cb0ef41Sopenharmony_ci        try {
1851cb0ef41Sopenharmony_ci          validateAbortSignal(options.signal, 'options.signal');
1861cb0ef41Sopenharmony_ci        } catch (err) {
1871cb0ef41Sopenharmony_ci          return reject(err);
1881cb0ef41Sopenharmony_ci        }
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci        if (options.signal.aborted) {
1911cb0ef41Sopenharmony_ci          return reject(abortIt(options.signal));
1921cb0ef41Sopenharmony_ci        }
1931cb0ef41Sopenharmony_ci      }
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci      const onabort = () => {
1961cb0ef41Sopenharmony_ci        clearFn(id);
1971cb0ef41Sopenharmony_ci        return reject(abortIt(options.signal));
1981cb0ef41Sopenharmony_ci      };
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ci      const id = timerFn(() => {
2011cb0ef41Sopenharmony_ci        return resolve(result);
2021cb0ef41Sopenharmony_ci      }, ms);
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_ci      if (options?.signal) {
2051cb0ef41Sopenharmony_ci        kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation;
2061cb0ef41Sopenharmony_ci        options.signal.addEventListener('abort', onabort, {
2071cb0ef41Sopenharmony_ci          __proto__: null,
2081cb0ef41Sopenharmony_ci          once: true,
2091cb0ef41Sopenharmony_ci          [kResistStopPropagation]: true,
2101cb0ef41Sopenharmony_ci        });
2111cb0ef41Sopenharmony_ci      }
2121cb0ef41Sopenharmony_ci    });
2131cb0ef41Sopenharmony_ci  }
2141cb0ef41Sopenharmony_ci
2151cb0ef41Sopenharmony_ci  #setImmediatePromisified(result, options) {
2161cb0ef41Sopenharmony_ci    return this.#promisifyTimer({
2171cb0ef41Sopenharmony_ci      __proto__: null,
2181cb0ef41Sopenharmony_ci      timerFn: FunctionPrototypeBind(this.#setImmediate, this),
2191cb0ef41Sopenharmony_ci      clearFn: FunctionPrototypeBind(this.#clearImmediate, this),
2201cb0ef41Sopenharmony_ci      ms: TIMERS_DEFAULT_INTERVAL.setImmediate,
2211cb0ef41Sopenharmony_ci      result,
2221cb0ef41Sopenharmony_ci      options,
2231cb0ef41Sopenharmony_ci    });
2241cb0ef41Sopenharmony_ci  }
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci  #setTimeoutPromisified(ms, result, options) {
2271cb0ef41Sopenharmony_ci    return this.#promisifyTimer({
2281cb0ef41Sopenharmony_ci      __proto__: null,
2291cb0ef41Sopenharmony_ci      timerFn: FunctionPrototypeBind(this.#setTimeout, this),
2301cb0ef41Sopenharmony_ci      clearFn: FunctionPrototypeBind(this.#clearTimeout, this),
2311cb0ef41Sopenharmony_ci      ms,
2321cb0ef41Sopenharmony_ci      result,
2331cb0ef41Sopenharmony_ci      options,
2341cb0ef41Sopenharmony_ci    });
2351cb0ef41Sopenharmony_ci  }
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci  #toggleEnableTimers(activate) {
2381cb0ef41Sopenharmony_ci    const options = {
2391cb0ef41Sopenharmony_ci      __proto__: null,
2401cb0ef41Sopenharmony_ci      toFake: {
2411cb0ef41Sopenharmony_ci        __proto__: null,
2421cb0ef41Sopenharmony_ci        setTimeout: () => {
2431cb0ef41Sopenharmony_ci          this.#storeOriginalSetTimeout();
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci          globalThis.setTimeout = this.#setTimeout;
2461cb0ef41Sopenharmony_ci          globalThis.clearTimeout = this.#clearTimeout;
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci          nodeTimers.setTimeout = this.#setTimeout;
2491cb0ef41Sopenharmony_ci          nodeTimers.clearTimeout = this.#clearTimeout;
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci          nodeTimersPromises.setTimeout = FunctionPrototypeBind(
2521cb0ef41Sopenharmony_ci            this.#setTimeoutPromisified,
2531cb0ef41Sopenharmony_ci            this,
2541cb0ef41Sopenharmony_ci          );
2551cb0ef41Sopenharmony_ci        },
2561cb0ef41Sopenharmony_ci        setInterval: () => {
2571cb0ef41Sopenharmony_ci          this.#storeOriginalSetInterval();
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_ci          globalThis.setInterval = this.#setInterval;
2601cb0ef41Sopenharmony_ci          globalThis.clearInterval = this.#clearInterval;
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_ci          nodeTimers.setInterval = this.#setInterval;
2631cb0ef41Sopenharmony_ci          nodeTimers.clearInterval = this.#clearInterval;
2641cb0ef41Sopenharmony_ci
2651cb0ef41Sopenharmony_ci          nodeTimersPromises.setInterval = FunctionPrototypeBind(
2661cb0ef41Sopenharmony_ci            this.#setIntervalPromisified,
2671cb0ef41Sopenharmony_ci            this,
2681cb0ef41Sopenharmony_ci          );
2691cb0ef41Sopenharmony_ci        },
2701cb0ef41Sopenharmony_ci        setImmediate: () => {
2711cb0ef41Sopenharmony_ci          this.#storeOriginalSetImmediate();
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ci          globalThis.setImmediate = this.#setImmediate;
2741cb0ef41Sopenharmony_ci          globalThis.clearImmediate = this.#clearImmediate;
2751cb0ef41Sopenharmony_ci
2761cb0ef41Sopenharmony_ci          nodeTimers.setImmediate = this.#setImmediate;
2771cb0ef41Sopenharmony_ci          nodeTimers.clearImmediate = this.#clearImmediate;
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_ci          nodeTimersPromises.setImmediate = FunctionPrototypeBind(
2801cb0ef41Sopenharmony_ci            this.#setImmediatePromisified,
2811cb0ef41Sopenharmony_ci            this,
2821cb0ef41Sopenharmony_ci          );
2831cb0ef41Sopenharmony_ci        },
2841cb0ef41Sopenharmony_ci      },
2851cb0ef41Sopenharmony_ci      toReal: {
2861cb0ef41Sopenharmony_ci        __proto__: null,
2871cb0ef41Sopenharmony_ci        setTimeout: () => {
2881cb0ef41Sopenharmony_ci          this.#restoreOriginalSetTimeout();
2891cb0ef41Sopenharmony_ci        },
2901cb0ef41Sopenharmony_ci        setInterval: () => {
2911cb0ef41Sopenharmony_ci          this.#restoreOriginalSetInterval();
2921cb0ef41Sopenharmony_ci        },
2931cb0ef41Sopenharmony_ci        setImmediate: () => {
2941cb0ef41Sopenharmony_ci          this.#restoreSetImmediate();
2951cb0ef41Sopenharmony_ci        },
2961cb0ef41Sopenharmony_ci      },
2971cb0ef41Sopenharmony_ci    };
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_ci    const target = activate ? options.toFake : options.toReal;
3001cb0ef41Sopenharmony_ci    ArrayPrototypeForEach(this.#timersInContext, (timer) => target[timer]());
3011cb0ef41Sopenharmony_ci    this.#isEnabled = activate;
3021cb0ef41Sopenharmony_ci  }
3031cb0ef41Sopenharmony_ci
3041cb0ef41Sopenharmony_ci  #restoreSetImmediate() {
3051cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3061cb0ef41Sopenharmony_ci      globalThis,
3071cb0ef41Sopenharmony_ci      'setImmediate',
3081cb0ef41Sopenharmony_ci      this.#realSetImmediate,
3091cb0ef41Sopenharmony_ci    );
3101cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3111cb0ef41Sopenharmony_ci      globalThis,
3121cb0ef41Sopenharmony_ci      'clearImmediate',
3131cb0ef41Sopenharmony_ci      this.#realClearImmediate,
3141cb0ef41Sopenharmony_ci    );
3151cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3161cb0ef41Sopenharmony_ci      nodeTimers,
3171cb0ef41Sopenharmony_ci      'setImmediate',
3181cb0ef41Sopenharmony_ci      this.#realTimersSetImmediate,
3191cb0ef41Sopenharmony_ci    );
3201cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3211cb0ef41Sopenharmony_ci      nodeTimers,
3221cb0ef41Sopenharmony_ci      'clearImmediate',
3231cb0ef41Sopenharmony_ci      this.#realTimersClearImmediate,
3241cb0ef41Sopenharmony_ci    );
3251cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3261cb0ef41Sopenharmony_ci      nodeTimersPromises,
3271cb0ef41Sopenharmony_ci      'setImmediate',
3281cb0ef41Sopenharmony_ci      this.#realPromisifiedSetImmediate,
3291cb0ef41Sopenharmony_ci    );
3301cb0ef41Sopenharmony_ci  }
3311cb0ef41Sopenharmony_ci
3321cb0ef41Sopenharmony_ci  #restoreOriginalSetInterval() {
3331cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3341cb0ef41Sopenharmony_ci      globalThis,
3351cb0ef41Sopenharmony_ci      'setInterval',
3361cb0ef41Sopenharmony_ci      this.#realSetInterval,
3371cb0ef41Sopenharmony_ci    );
3381cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3391cb0ef41Sopenharmony_ci      globalThis,
3401cb0ef41Sopenharmony_ci      'clearInterval',
3411cb0ef41Sopenharmony_ci      this.#realClearInterval,
3421cb0ef41Sopenharmony_ci    );
3431cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3441cb0ef41Sopenharmony_ci      nodeTimers,
3451cb0ef41Sopenharmony_ci      'setInterval',
3461cb0ef41Sopenharmony_ci      this.#realTimersSetInterval,
3471cb0ef41Sopenharmony_ci    );
3481cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3491cb0ef41Sopenharmony_ci      nodeTimers,
3501cb0ef41Sopenharmony_ci      'clearInterval',
3511cb0ef41Sopenharmony_ci      this.#realTimersClearInterval,
3521cb0ef41Sopenharmony_ci    );
3531cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3541cb0ef41Sopenharmony_ci      nodeTimersPromises,
3551cb0ef41Sopenharmony_ci      'setInterval',
3561cb0ef41Sopenharmony_ci      this.#realPromisifiedSetInterval,
3571cb0ef41Sopenharmony_ci    );
3581cb0ef41Sopenharmony_ci  }
3591cb0ef41Sopenharmony_ci
3601cb0ef41Sopenharmony_ci  #restoreOriginalSetTimeout() {
3611cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3621cb0ef41Sopenharmony_ci      globalThis,
3631cb0ef41Sopenharmony_ci      'setTimeout',
3641cb0ef41Sopenharmony_ci      this.#realSetTimeout,
3651cb0ef41Sopenharmony_ci    );
3661cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3671cb0ef41Sopenharmony_ci      globalThis,
3681cb0ef41Sopenharmony_ci      'clearTimeout',
3691cb0ef41Sopenharmony_ci      this.#realClearTimeout,
3701cb0ef41Sopenharmony_ci    );
3711cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3721cb0ef41Sopenharmony_ci      nodeTimers,
3731cb0ef41Sopenharmony_ci      'setTimeout',
3741cb0ef41Sopenharmony_ci      this.#realTimersSetTimeout,
3751cb0ef41Sopenharmony_ci    );
3761cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3771cb0ef41Sopenharmony_ci      nodeTimers,
3781cb0ef41Sopenharmony_ci      'clearTimeout',
3791cb0ef41Sopenharmony_ci      this.#realTimersClearTimeout,
3801cb0ef41Sopenharmony_ci    );
3811cb0ef41Sopenharmony_ci    ObjectDefineProperty(
3821cb0ef41Sopenharmony_ci      nodeTimersPromises,
3831cb0ef41Sopenharmony_ci      'setTimeout',
3841cb0ef41Sopenharmony_ci      this.#realPromisifiedSetTimeout,
3851cb0ef41Sopenharmony_ci    );
3861cb0ef41Sopenharmony_ci  }
3871cb0ef41Sopenharmony_ci
3881cb0ef41Sopenharmony_ci  #storeOriginalSetImmediate() {
3891cb0ef41Sopenharmony_ci    this.#realSetImmediate = ObjectGetOwnPropertyDescriptor(
3901cb0ef41Sopenharmony_ci      globalThis,
3911cb0ef41Sopenharmony_ci      'setImmediate',
3921cb0ef41Sopenharmony_ci    );
3931cb0ef41Sopenharmony_ci    this.#realClearImmediate = ObjectGetOwnPropertyDescriptor(
3941cb0ef41Sopenharmony_ci      globalThis,
3951cb0ef41Sopenharmony_ci      'clearImmediate',
3961cb0ef41Sopenharmony_ci    );
3971cb0ef41Sopenharmony_ci    this.#realTimersSetImmediate = ObjectGetOwnPropertyDescriptor(
3981cb0ef41Sopenharmony_ci      nodeTimers,
3991cb0ef41Sopenharmony_ci      'setImmediate',
4001cb0ef41Sopenharmony_ci    );
4011cb0ef41Sopenharmony_ci    this.#realTimersClearImmediate = ObjectGetOwnPropertyDescriptor(
4021cb0ef41Sopenharmony_ci      nodeTimers,
4031cb0ef41Sopenharmony_ci      'clearImmediate',
4041cb0ef41Sopenharmony_ci    );
4051cb0ef41Sopenharmony_ci    this.#realPromisifiedSetImmediate = ObjectGetOwnPropertyDescriptor(
4061cb0ef41Sopenharmony_ci      nodeTimersPromises,
4071cb0ef41Sopenharmony_ci      'setImmediate',
4081cb0ef41Sopenharmony_ci    );
4091cb0ef41Sopenharmony_ci  }
4101cb0ef41Sopenharmony_ci
4111cb0ef41Sopenharmony_ci  #storeOriginalSetInterval() {
4121cb0ef41Sopenharmony_ci    this.#realSetInterval = ObjectGetOwnPropertyDescriptor(
4131cb0ef41Sopenharmony_ci      globalThis,
4141cb0ef41Sopenharmony_ci      'setInterval',
4151cb0ef41Sopenharmony_ci    );
4161cb0ef41Sopenharmony_ci    this.#realClearInterval = ObjectGetOwnPropertyDescriptor(
4171cb0ef41Sopenharmony_ci      globalThis,
4181cb0ef41Sopenharmony_ci      'clearInterval',
4191cb0ef41Sopenharmony_ci    );
4201cb0ef41Sopenharmony_ci    this.#realTimersSetInterval = ObjectGetOwnPropertyDescriptor(
4211cb0ef41Sopenharmony_ci      nodeTimers,
4221cb0ef41Sopenharmony_ci      'setInterval',
4231cb0ef41Sopenharmony_ci    );
4241cb0ef41Sopenharmony_ci    this.#realTimersClearInterval = ObjectGetOwnPropertyDescriptor(
4251cb0ef41Sopenharmony_ci      nodeTimers,
4261cb0ef41Sopenharmony_ci      'clearInterval',
4271cb0ef41Sopenharmony_ci    );
4281cb0ef41Sopenharmony_ci    this.#realPromisifiedSetInterval = ObjectGetOwnPropertyDescriptor(
4291cb0ef41Sopenharmony_ci      nodeTimersPromises,
4301cb0ef41Sopenharmony_ci      'setInterval',
4311cb0ef41Sopenharmony_ci    );
4321cb0ef41Sopenharmony_ci  }
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_ci  #storeOriginalSetTimeout() {
4351cb0ef41Sopenharmony_ci    this.#realSetTimeout = ObjectGetOwnPropertyDescriptor(
4361cb0ef41Sopenharmony_ci      globalThis,
4371cb0ef41Sopenharmony_ci      'setTimeout',
4381cb0ef41Sopenharmony_ci    );
4391cb0ef41Sopenharmony_ci    this.#realClearTimeout = ObjectGetOwnPropertyDescriptor(
4401cb0ef41Sopenharmony_ci      globalThis,
4411cb0ef41Sopenharmony_ci      'clearTimeout',
4421cb0ef41Sopenharmony_ci    );
4431cb0ef41Sopenharmony_ci    this.#realTimersSetTimeout = ObjectGetOwnPropertyDescriptor(
4441cb0ef41Sopenharmony_ci      nodeTimers,
4451cb0ef41Sopenharmony_ci      'setTimeout',
4461cb0ef41Sopenharmony_ci    );
4471cb0ef41Sopenharmony_ci    this.#realTimersClearTimeout = ObjectGetOwnPropertyDescriptor(
4481cb0ef41Sopenharmony_ci      nodeTimers,
4491cb0ef41Sopenharmony_ci      'clearTimeout',
4501cb0ef41Sopenharmony_ci    );
4511cb0ef41Sopenharmony_ci    this.#realPromisifiedSetTimeout = ObjectGetOwnPropertyDescriptor(
4521cb0ef41Sopenharmony_ci      nodeTimersPromises,
4531cb0ef41Sopenharmony_ci      'setTimeout',
4541cb0ef41Sopenharmony_ci    );
4551cb0ef41Sopenharmony_ci  }
4561cb0ef41Sopenharmony_ci
4571cb0ef41Sopenharmony_ci  /**
4581cb0ef41Sopenharmony_ci   * Advances the virtual time of MockTimers by the specified duration (in milliseconds).
4591cb0ef41Sopenharmony_ci   * This method simulates the passage of time and triggers any scheduled timers that are due.
4601cb0ef41Sopenharmony_ci   * @param {number} [time=1] - The amount of time (in milliseconds) to advance the virtual time.
4611cb0ef41Sopenharmony_ci   * @throws {ERR_INVALID_STATE} If MockTimers are not enabled.
4621cb0ef41Sopenharmony_ci   * @throws {ERR_INVALID_ARG_VALUE} If a negative time value is provided.
4631cb0ef41Sopenharmony_ci   */
4641cb0ef41Sopenharmony_ci  tick(time = 1) {
4651cb0ef41Sopenharmony_ci    if (!this.#isEnabled) {
4661cb0ef41Sopenharmony_ci      throw new ERR_INVALID_STATE(
4671cb0ef41Sopenharmony_ci        'You should enable MockTimers first by calling the .enable function',
4681cb0ef41Sopenharmony_ci      );
4691cb0ef41Sopenharmony_ci    }
4701cb0ef41Sopenharmony_ci
4711cb0ef41Sopenharmony_ci    if (time < 0) {
4721cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE(
4731cb0ef41Sopenharmony_ci        'time',
4741cb0ef41Sopenharmony_ci        'positive integer',
4751cb0ef41Sopenharmony_ci        time,
4761cb0ef41Sopenharmony_ci      );
4771cb0ef41Sopenharmony_ci    }
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ci    this.#now += time;
4801cb0ef41Sopenharmony_ci    let timer = this.#executionQueue.peek();
4811cb0ef41Sopenharmony_ci    while (timer) {
4821cb0ef41Sopenharmony_ci      if (timer.runAt > this.#now) break;
4831cb0ef41Sopenharmony_ci      FunctionPrototypeApply(timer.callback, undefined, timer.args);
4841cb0ef41Sopenharmony_ci
4851cb0ef41Sopenharmony_ci      this.#executionQueue.shift();
4861cb0ef41Sopenharmony_ci
4871cb0ef41Sopenharmony_ci      if (timer.interval) {
4881cb0ef41Sopenharmony_ci        timer.runAt += timer.interval;
4891cb0ef41Sopenharmony_ci        this.#executionQueue.insert(timer);
4901cb0ef41Sopenharmony_ci        return;
4911cb0ef41Sopenharmony_ci      }
4921cb0ef41Sopenharmony_ci
4931cb0ef41Sopenharmony_ci      timer = this.#executionQueue.peek();
4941cb0ef41Sopenharmony_ci    }
4951cb0ef41Sopenharmony_ci  }
4961cb0ef41Sopenharmony_ci
4971cb0ef41Sopenharmony_ci  /**
4981cb0ef41Sopenharmony_ci   * Enables MockTimers for the specified timers.
4991cb0ef41Sopenharmony_ci   * @param {string[]} timers - An array of timer types to enable, e.g., ['setTimeout', 'setInterval'].
5001cb0ef41Sopenharmony_ci   * @throws {ERR_INVALID_STATE} If MockTimers are already enabled.
5011cb0ef41Sopenharmony_ci   * @throws {ERR_INVALID_ARG_VALUE} If an unsupported timer type is specified.
5021cb0ef41Sopenharmony_ci   */
5031cb0ef41Sopenharmony_ci  enable(timers = SUPPORTED_TIMERS) {
5041cb0ef41Sopenharmony_ci    if (this.#isEnabled) {
5051cb0ef41Sopenharmony_ci      throw new ERR_INVALID_STATE(
5061cb0ef41Sopenharmony_ci        'MockTimers is already enabled!',
5071cb0ef41Sopenharmony_ci      );
5081cb0ef41Sopenharmony_ci    }
5091cb0ef41Sopenharmony_ci
5101cb0ef41Sopenharmony_ci    validateArray(timers, 'timers');
5111cb0ef41Sopenharmony_ci
5121cb0ef41Sopenharmony_ci    // Check that the timers passed are supported
5131cb0ef41Sopenharmony_ci    ArrayPrototypeForEach(timers, (timer) => {
5141cb0ef41Sopenharmony_ci      if (!ArrayPrototypeIncludes(SUPPORTED_TIMERS, timer)) {
5151cb0ef41Sopenharmony_ci        throw new ERR_INVALID_ARG_VALUE(
5161cb0ef41Sopenharmony_ci          'timers',
5171cb0ef41Sopenharmony_ci          timer,
5181cb0ef41Sopenharmony_ci          `option ${timer} is not supported`,
5191cb0ef41Sopenharmony_ci        );
5201cb0ef41Sopenharmony_ci      }
5211cb0ef41Sopenharmony_ci    });
5221cb0ef41Sopenharmony_ci
5231cb0ef41Sopenharmony_ci    this.#timersInContext = timers;
5241cb0ef41Sopenharmony_ci    this.#now = DateNow();
5251cb0ef41Sopenharmony_ci    this.#toggleEnableTimers(true);
5261cb0ef41Sopenharmony_ci  }
5271cb0ef41Sopenharmony_ci
5281cb0ef41Sopenharmony_ci  /**
5291cb0ef41Sopenharmony_ci   * An alias for `this.reset()`, allowing the disposal of the `MockTimers` instance.
5301cb0ef41Sopenharmony_ci   */
5311cb0ef41Sopenharmony_ci  [SymbolDispose]() {
5321cb0ef41Sopenharmony_ci    this.reset();
5331cb0ef41Sopenharmony_ci  }
5341cb0ef41Sopenharmony_ci
5351cb0ef41Sopenharmony_ci  /**
5361cb0ef41Sopenharmony_ci   * Resets MockTimers, disabling any enabled timers and clearing the execution queue.
5371cb0ef41Sopenharmony_ci   * Does nothing if MockTimers are not enabled.
5381cb0ef41Sopenharmony_ci   */
5391cb0ef41Sopenharmony_ci  reset() {
5401cb0ef41Sopenharmony_ci    // Ignore if not enabled
5411cb0ef41Sopenharmony_ci    if (!this.#isEnabled) return;
5421cb0ef41Sopenharmony_ci
5431cb0ef41Sopenharmony_ci    this.#toggleEnableTimers(false);
5441cb0ef41Sopenharmony_ci    this.#timersInContext = [];
5451cb0ef41Sopenharmony_ci
5461cb0ef41Sopenharmony_ci    let timer = this.#executionQueue.peek();
5471cb0ef41Sopenharmony_ci    while (timer) {
5481cb0ef41Sopenharmony_ci      this.#executionQueue.shift();
5491cb0ef41Sopenharmony_ci      timer = this.#executionQueue.peek();
5501cb0ef41Sopenharmony_ci    }
5511cb0ef41Sopenharmony_ci  }
5521cb0ef41Sopenharmony_ci
5531cb0ef41Sopenharmony_ci  /**
5541cb0ef41Sopenharmony_ci   * Runs all scheduled timers until there are no more pending timers.
5551cb0ef41Sopenharmony_ci   * @throws {ERR_INVALID_STATE} If MockTimers are not enabled.
5561cb0ef41Sopenharmony_ci   */
5571cb0ef41Sopenharmony_ci  runAll() {
5581cb0ef41Sopenharmony_ci    if (!this.#isEnabled) {
5591cb0ef41Sopenharmony_ci      throw new ERR_INVALID_STATE(
5601cb0ef41Sopenharmony_ci        'You should enable MockTimers first by calling the .enable function',
5611cb0ef41Sopenharmony_ci      );
5621cb0ef41Sopenharmony_ci    }
5631cb0ef41Sopenharmony_ci
5641cb0ef41Sopenharmony_ci    this.tick(Infinity);
5651cb0ef41Sopenharmony_ci  }
5661cb0ef41Sopenharmony_ci}
5671cb0ef41Sopenharmony_ci
5681cb0ef41Sopenharmony_cimodule.exports = { MockTimers };
569