11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ciconst {
31cb0ef41Sopenharmony_ci  ArrayPrototypePush,
41cb0ef41Sopenharmony_ci  ArrayPrototypeSlice,
51cb0ef41Sopenharmony_ci  Error,
61cb0ef41Sopenharmony_ci  FunctionPrototypeCall,
71cb0ef41Sopenharmony_ci  ObjectDefineProperty,
81cb0ef41Sopenharmony_ci  ObjectGetOwnPropertyDescriptor,
91cb0ef41Sopenharmony_ci  ObjectGetPrototypeOf,
101cb0ef41Sopenharmony_ci  Proxy,
111cb0ef41Sopenharmony_ci  ReflectApply,
121cb0ef41Sopenharmony_ci  ReflectConstruct,
131cb0ef41Sopenharmony_ci  ReflectGet,
141cb0ef41Sopenharmony_ci  SafeMap,
151cb0ef41Sopenharmony_ci} = primordials;
161cb0ef41Sopenharmony_ciconst {
171cb0ef41Sopenharmony_ci  codes: {
181cb0ef41Sopenharmony_ci    ERR_INVALID_ARG_TYPE,
191cb0ef41Sopenharmony_ci    ERR_INVALID_ARG_VALUE,
201cb0ef41Sopenharmony_ci  },
211cb0ef41Sopenharmony_ci} = require('internal/errors');
221cb0ef41Sopenharmony_ciconst { kEmptyObject } = require('internal/util');
231cb0ef41Sopenharmony_ciconst {
241cb0ef41Sopenharmony_ci  validateBoolean,
251cb0ef41Sopenharmony_ci  validateFunction,
261cb0ef41Sopenharmony_ci  validateInteger,
271cb0ef41Sopenharmony_ci  validateObject,
281cb0ef41Sopenharmony_ci} = require('internal/validators');
291cb0ef41Sopenharmony_ciconst { MockTimers } = require('internal/test_runner/mock/mock_timers');
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_cifunction kDefaultFunction() {}
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ciclass MockFunctionContext {
341cb0ef41Sopenharmony_ci  #calls;
351cb0ef41Sopenharmony_ci  #mocks;
361cb0ef41Sopenharmony_ci  #implementation;
371cb0ef41Sopenharmony_ci  #restore;
381cb0ef41Sopenharmony_ci  #times;
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci  constructor(implementation, restore, times) {
411cb0ef41Sopenharmony_ci    this.#calls = [];
421cb0ef41Sopenharmony_ci    this.#mocks = new SafeMap();
431cb0ef41Sopenharmony_ci    this.#implementation = implementation;
441cb0ef41Sopenharmony_ci    this.#restore = restore;
451cb0ef41Sopenharmony_ci    this.#times = times;
461cb0ef41Sopenharmony_ci  }
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci  /**
491cb0ef41Sopenharmony_ci   * Gets an array of recorded calls made to the mock function.
501cb0ef41Sopenharmony_ci   * @returns {Array} An array of recorded calls.
511cb0ef41Sopenharmony_ci   */
521cb0ef41Sopenharmony_ci  get calls() {
531cb0ef41Sopenharmony_ci    return ArrayPrototypeSlice(this.#calls, 0);
541cb0ef41Sopenharmony_ci  }
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci  /**
571cb0ef41Sopenharmony_ci   * Retrieves the number of times the mock function has been called.
581cb0ef41Sopenharmony_ci   * @returns {number} The call count.
591cb0ef41Sopenharmony_ci   */
601cb0ef41Sopenharmony_ci  callCount() {
611cb0ef41Sopenharmony_ci    return this.#calls.length;
621cb0ef41Sopenharmony_ci  }
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci  /**
651cb0ef41Sopenharmony_ci   * Sets a new implementation for the mock function.
661cb0ef41Sopenharmony_ci   * @param {Function} implementation - The new implementation for the mock function.
671cb0ef41Sopenharmony_ci   */
681cb0ef41Sopenharmony_ci  mockImplementation(implementation) {
691cb0ef41Sopenharmony_ci    validateFunction(implementation, 'implementation');
701cb0ef41Sopenharmony_ci    this.#implementation = implementation;
711cb0ef41Sopenharmony_ci  }
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  /**
741cb0ef41Sopenharmony_ci   * Replaces the implementation of the function only once.
751cb0ef41Sopenharmony_ci   * @param {Function} implementation - The substitute function.
761cb0ef41Sopenharmony_ci   * @param {number} [onCall] - The call index to be replaced.
771cb0ef41Sopenharmony_ci   */
781cb0ef41Sopenharmony_ci  mockImplementationOnce(implementation, onCall) {
791cb0ef41Sopenharmony_ci    validateFunction(implementation, 'implementation');
801cb0ef41Sopenharmony_ci    const nextCall = this.#calls.length;
811cb0ef41Sopenharmony_ci    const call = onCall ?? nextCall;
821cb0ef41Sopenharmony_ci    validateInteger(call, 'onCall', nextCall);
831cb0ef41Sopenharmony_ci    this.#mocks.set(call, implementation);
841cb0ef41Sopenharmony_ci  }
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci  /**
871cb0ef41Sopenharmony_ci   * Restores the original function that was mocked.
881cb0ef41Sopenharmony_ci   */
891cb0ef41Sopenharmony_ci  restore() {
901cb0ef41Sopenharmony_ci    const { descriptor, object, original, methodName } = this.#restore;
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci    if (typeof methodName === 'string') {
931cb0ef41Sopenharmony_ci      // This is an object method spy.
941cb0ef41Sopenharmony_ci      ObjectDefineProperty(object, methodName, descriptor);
951cb0ef41Sopenharmony_ci    } else {
961cb0ef41Sopenharmony_ci      // This is a bare function spy. There isn't much to do here but make
971cb0ef41Sopenharmony_ci      // the mock call the original function.
981cb0ef41Sopenharmony_ci      this.#implementation = original;
991cb0ef41Sopenharmony_ci    }
1001cb0ef41Sopenharmony_ci  }
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci  /**
1031cb0ef41Sopenharmony_ci   * Resets the recorded calls to the mock function
1041cb0ef41Sopenharmony_ci   */
1051cb0ef41Sopenharmony_ci  resetCalls() {
1061cb0ef41Sopenharmony_ci    this.#calls = [];
1071cb0ef41Sopenharmony_ci  }
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci  /**
1101cb0ef41Sopenharmony_ci   * Tracks a call made to the mock function.
1111cb0ef41Sopenharmony_ci   * @param {object} call - The call details.
1121cb0ef41Sopenharmony_ci   */
1131cb0ef41Sopenharmony_ci  trackCall(call) {
1141cb0ef41Sopenharmony_ci    ArrayPrototypePush(this.#calls, call);
1151cb0ef41Sopenharmony_ci  }
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  /**
1181cb0ef41Sopenharmony_ci   * Gets the next implementation to use for the mock function.
1191cb0ef41Sopenharmony_ci   * @returns {Function} The next implementation.
1201cb0ef41Sopenharmony_ci   */
1211cb0ef41Sopenharmony_ci  nextImpl() {
1221cb0ef41Sopenharmony_ci    const nextCall = this.#calls.length;
1231cb0ef41Sopenharmony_ci    const mock = this.#mocks.get(nextCall);
1241cb0ef41Sopenharmony_ci    const impl = mock ?? this.#implementation;
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci    if (nextCall + 1 === this.#times) {
1271cb0ef41Sopenharmony_ci      this.restore();
1281cb0ef41Sopenharmony_ci    }
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci    this.#mocks.delete(nextCall);
1311cb0ef41Sopenharmony_ci    return impl;
1321cb0ef41Sopenharmony_ci  }
1331cb0ef41Sopenharmony_ci}
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ciconst { nextImpl, restore, trackCall } = MockFunctionContext.prototype;
1361cb0ef41Sopenharmony_cidelete MockFunctionContext.prototype.trackCall;
1371cb0ef41Sopenharmony_cidelete MockFunctionContext.prototype.nextImpl;
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ciclass MockTracker {
1401cb0ef41Sopenharmony_ci  #mocks = [];
1411cb0ef41Sopenharmony_ci  #timers;
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci  /**
1441cb0ef41Sopenharmony_ci   * Returns the mock timers of this MockTracker instance.
1451cb0ef41Sopenharmony_ci   * @returns {MockTimers} The mock timers instance.
1461cb0ef41Sopenharmony_ci   */
1471cb0ef41Sopenharmony_ci  get timers() {
1481cb0ef41Sopenharmony_ci    this.#timers ??= new MockTimers();
1491cb0ef41Sopenharmony_ci    return this.#timers;
1501cb0ef41Sopenharmony_ci  }
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci  /**
1531cb0ef41Sopenharmony_ci   * Creates a mock function tracker.
1541cb0ef41Sopenharmony_ci   * @param {Function} [original] - The original function to be tracked.
1551cb0ef41Sopenharmony_ci   * @param {Function} [implementation] - An optional replacement function for the original one.
1561cb0ef41Sopenharmony_ci   * @param {object} [options] - Additional tracking options.
1571cb0ef41Sopenharmony_ci   * @param {number} [options.times=Infinity] - The maximum number of times the mock function can be called.
1581cb0ef41Sopenharmony_ci   * @returns {ProxyConstructor} The mock function tracker.
1591cb0ef41Sopenharmony_ci   */
1601cb0ef41Sopenharmony_ci  fn(
1611cb0ef41Sopenharmony_ci    original = function() {},
1621cb0ef41Sopenharmony_ci    implementation = original,
1631cb0ef41Sopenharmony_ci    options = kEmptyObject,
1641cb0ef41Sopenharmony_ci  ) {
1651cb0ef41Sopenharmony_ci    if (original !== null && typeof original === 'object') {
1661cb0ef41Sopenharmony_ci      options = original;
1671cb0ef41Sopenharmony_ci      original = function() {};
1681cb0ef41Sopenharmony_ci      implementation = original;
1691cb0ef41Sopenharmony_ci    } else if (implementation !== null && typeof implementation === 'object') {
1701cb0ef41Sopenharmony_ci      options = implementation;
1711cb0ef41Sopenharmony_ci      implementation = original;
1721cb0ef41Sopenharmony_ci    }
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci    validateFunction(original, 'original');
1751cb0ef41Sopenharmony_ci    validateFunction(implementation, 'implementation');
1761cb0ef41Sopenharmony_ci    validateObject(options, 'options');
1771cb0ef41Sopenharmony_ci    const { times = Infinity } = options;
1781cb0ef41Sopenharmony_ci    validateTimes(times, 'options.times');
1791cb0ef41Sopenharmony_ci    const ctx = new MockFunctionContext(implementation, { __proto__: null, original }, times);
1801cb0ef41Sopenharmony_ci    return this.#setupMock(ctx, original);
1811cb0ef41Sopenharmony_ci  }
1821cb0ef41Sopenharmony_ci
1831cb0ef41Sopenharmony_ci  /**
1841cb0ef41Sopenharmony_ci   * Creates a method tracker for a specified object or function.
1851cb0ef41Sopenharmony_ci   * @param {(object | Function)} objectOrFunction - The object or function containing the method to be tracked.
1861cb0ef41Sopenharmony_ci   * @param {string} methodName - The name of the method to be tracked.
1871cb0ef41Sopenharmony_ci   * @param {Function} [implementation] - An optional replacement function for the original method.
1881cb0ef41Sopenharmony_ci   * @param {object} [options] - Additional tracking options.
1891cb0ef41Sopenharmony_ci   * @param {boolean} [options.getter=false] - Indicates whether this is a getter method.
1901cb0ef41Sopenharmony_ci   * @param {boolean} [options.setter=false] - Indicates whether this is a setter method.
1911cb0ef41Sopenharmony_ci   * @param {number} [options.times=Infinity] - The maximum number of times the mock method can be called.
1921cb0ef41Sopenharmony_ci   * @returns {ProxyConstructor} The mock method tracker.
1931cb0ef41Sopenharmony_ci   */
1941cb0ef41Sopenharmony_ci  method(
1951cb0ef41Sopenharmony_ci    objectOrFunction,
1961cb0ef41Sopenharmony_ci    methodName,
1971cb0ef41Sopenharmony_ci    implementation = kDefaultFunction,
1981cb0ef41Sopenharmony_ci    options = kEmptyObject,
1991cb0ef41Sopenharmony_ci  ) {
2001cb0ef41Sopenharmony_ci    validateStringOrSymbol(methodName, 'methodName');
2011cb0ef41Sopenharmony_ci    if (typeof objectOrFunction !== 'function') {
2021cb0ef41Sopenharmony_ci      validateObject(objectOrFunction, 'object');
2031cb0ef41Sopenharmony_ci    }
2041cb0ef41Sopenharmony_ci
2051cb0ef41Sopenharmony_ci    if (implementation !== null && typeof implementation === 'object') {
2061cb0ef41Sopenharmony_ci      options = implementation;
2071cb0ef41Sopenharmony_ci      implementation = kDefaultFunction;
2081cb0ef41Sopenharmony_ci    }
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_ci    validateFunction(implementation, 'implementation');
2111cb0ef41Sopenharmony_ci    validateObject(options, 'options');
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci    const {
2141cb0ef41Sopenharmony_ci      getter = false,
2151cb0ef41Sopenharmony_ci      setter = false,
2161cb0ef41Sopenharmony_ci      times = Infinity,
2171cb0ef41Sopenharmony_ci    } = options;
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci    validateBoolean(getter, 'options.getter');
2201cb0ef41Sopenharmony_ci    validateBoolean(setter, 'options.setter');
2211cb0ef41Sopenharmony_ci    validateTimes(times, 'options.times');
2221cb0ef41Sopenharmony_ci
2231cb0ef41Sopenharmony_ci    if (setter && getter) {
2241cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE(
2251cb0ef41Sopenharmony_ci        'options.setter', setter, "cannot be used with 'options.getter'",
2261cb0ef41Sopenharmony_ci      );
2271cb0ef41Sopenharmony_ci    }
2281cb0ef41Sopenharmony_ci    const descriptor = findMethodOnPrototypeChain(objectOrFunction, methodName);
2291cb0ef41Sopenharmony_ci
2301cb0ef41Sopenharmony_ci    let original;
2311cb0ef41Sopenharmony_ci
2321cb0ef41Sopenharmony_ci    if (getter) {
2331cb0ef41Sopenharmony_ci      original = descriptor?.get;
2341cb0ef41Sopenharmony_ci    } else if (setter) {
2351cb0ef41Sopenharmony_ci      original = descriptor?.set;
2361cb0ef41Sopenharmony_ci    } else {
2371cb0ef41Sopenharmony_ci      original = descriptor?.value;
2381cb0ef41Sopenharmony_ci    }
2391cb0ef41Sopenharmony_ci
2401cb0ef41Sopenharmony_ci    if (typeof original !== 'function') {
2411cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE(
2421cb0ef41Sopenharmony_ci        'methodName', original, 'must be a method',
2431cb0ef41Sopenharmony_ci      );
2441cb0ef41Sopenharmony_ci    }
2451cb0ef41Sopenharmony_ci
2461cb0ef41Sopenharmony_ci    const restore = { __proto__: null, descriptor, object: objectOrFunction, methodName };
2471cb0ef41Sopenharmony_ci    const impl = implementation === kDefaultFunction ?
2481cb0ef41Sopenharmony_ci      original : implementation;
2491cb0ef41Sopenharmony_ci    const ctx = new MockFunctionContext(impl, restore, times);
2501cb0ef41Sopenharmony_ci    const mock = this.#setupMock(ctx, original);
2511cb0ef41Sopenharmony_ci    const mockDescriptor = {
2521cb0ef41Sopenharmony_ci      __proto__: null,
2531cb0ef41Sopenharmony_ci      configurable: descriptor.configurable,
2541cb0ef41Sopenharmony_ci      enumerable: descriptor.enumerable,
2551cb0ef41Sopenharmony_ci    };
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci    if (getter) {
2581cb0ef41Sopenharmony_ci      mockDescriptor.get = mock;
2591cb0ef41Sopenharmony_ci      mockDescriptor.set = descriptor.set;
2601cb0ef41Sopenharmony_ci    } else if (setter) {
2611cb0ef41Sopenharmony_ci      mockDescriptor.get = descriptor.get;
2621cb0ef41Sopenharmony_ci      mockDescriptor.set = mock;
2631cb0ef41Sopenharmony_ci    } else {
2641cb0ef41Sopenharmony_ci      mockDescriptor.writable = descriptor.writable;
2651cb0ef41Sopenharmony_ci      mockDescriptor.value = mock;
2661cb0ef41Sopenharmony_ci    }
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_ci    ObjectDefineProperty(objectOrFunction, methodName, mockDescriptor);
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci    return mock;
2711cb0ef41Sopenharmony_ci  }
2721cb0ef41Sopenharmony_ci
2731cb0ef41Sopenharmony_ci  /**
2741cb0ef41Sopenharmony_ci   * Mocks a getter method of an object.
2751cb0ef41Sopenharmony_ci   * This is a syntax sugar for the MockTracker.method with options.getter set to true
2761cb0ef41Sopenharmony_ci   * @param {object} object - The target object.
2771cb0ef41Sopenharmony_ci   * @param {string} methodName - The name of the getter method to be mocked.
2781cb0ef41Sopenharmony_ci   * @param {Function} [implementation] - An optional replacement function for the targeted method.
2791cb0ef41Sopenharmony_ci   * @param {object} [options] - Additional tracking options.
2801cb0ef41Sopenharmony_ci   * @param {boolean} [options.getter=true] - Indicates whether this is a getter method.
2811cb0ef41Sopenharmony_ci   * @param {boolean} [options.setter=false] - Indicates whether this is a setter method.
2821cb0ef41Sopenharmony_ci   * @param {number} [options.times=Infinity] - The maximum number of times the mock method can be called.
2831cb0ef41Sopenharmony_ci   * @returns {ProxyConstructor} The mock method tracker.
2841cb0ef41Sopenharmony_ci   */
2851cb0ef41Sopenharmony_ci  getter(
2861cb0ef41Sopenharmony_ci    object,
2871cb0ef41Sopenharmony_ci    methodName,
2881cb0ef41Sopenharmony_ci    implementation = kDefaultFunction,
2891cb0ef41Sopenharmony_ci    options = kEmptyObject,
2901cb0ef41Sopenharmony_ci  ) {
2911cb0ef41Sopenharmony_ci    if (implementation !== null && typeof implementation === 'object') {
2921cb0ef41Sopenharmony_ci      options = implementation;
2931cb0ef41Sopenharmony_ci      implementation = kDefaultFunction;
2941cb0ef41Sopenharmony_ci    } else {
2951cb0ef41Sopenharmony_ci      validateObject(options, 'options');
2961cb0ef41Sopenharmony_ci    }
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_ci    const { getter = true } = options;
2991cb0ef41Sopenharmony_ci
3001cb0ef41Sopenharmony_ci    if (getter === false) {
3011cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE(
3021cb0ef41Sopenharmony_ci        'options.getter', getter, 'cannot be false',
3031cb0ef41Sopenharmony_ci      );
3041cb0ef41Sopenharmony_ci    }
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_ci    return this.method(object, methodName, implementation, {
3071cb0ef41Sopenharmony_ci      __proto__: null,
3081cb0ef41Sopenharmony_ci      ...options,
3091cb0ef41Sopenharmony_ci      getter,
3101cb0ef41Sopenharmony_ci    });
3111cb0ef41Sopenharmony_ci  }
3121cb0ef41Sopenharmony_ci
3131cb0ef41Sopenharmony_ci  /**
3141cb0ef41Sopenharmony_ci   * Mocks a setter method of an object.
3151cb0ef41Sopenharmony_ci   * This function is a syntax sugar for MockTracker.method with options.setter set to true.
3161cb0ef41Sopenharmony_ci   * @param {object} object - The target object.
3171cb0ef41Sopenharmony_ci   * @param {string} methodName  - The setter method to be mocked.
3181cb0ef41Sopenharmony_ci   * @param {Function} [implementation] - An optional replacement function for the targeted method.
3191cb0ef41Sopenharmony_ci   * @param {object} [options] - Additional tracking options.
3201cb0ef41Sopenharmony_ci   * @param {boolean} [options.getter=false] - Indicates whether this is a getter method.
3211cb0ef41Sopenharmony_ci   * @param {boolean} [options.setter=true] - Indicates whether this is a setter method.
3221cb0ef41Sopenharmony_ci   * @param {number} [options.times=Infinity] - The maximum number of times the mock method can be called.
3231cb0ef41Sopenharmony_ci   * @returns {ProxyConstructor} The mock method tracker.
3241cb0ef41Sopenharmony_ci   */
3251cb0ef41Sopenharmony_ci  setter(
3261cb0ef41Sopenharmony_ci    object,
3271cb0ef41Sopenharmony_ci    methodName,
3281cb0ef41Sopenharmony_ci    implementation = kDefaultFunction,
3291cb0ef41Sopenharmony_ci    options = kEmptyObject,
3301cb0ef41Sopenharmony_ci  ) {
3311cb0ef41Sopenharmony_ci    if (implementation !== null && typeof implementation === 'object') {
3321cb0ef41Sopenharmony_ci      options = implementation;
3331cb0ef41Sopenharmony_ci      implementation = kDefaultFunction;
3341cb0ef41Sopenharmony_ci    } else {
3351cb0ef41Sopenharmony_ci      validateObject(options, 'options');
3361cb0ef41Sopenharmony_ci    }
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_ci    const { setter = true } = options;
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_ci    if (setter === false) {
3411cb0ef41Sopenharmony_ci      throw new ERR_INVALID_ARG_VALUE(
3421cb0ef41Sopenharmony_ci        'options.setter', setter, 'cannot be false',
3431cb0ef41Sopenharmony_ci      );
3441cb0ef41Sopenharmony_ci    }
3451cb0ef41Sopenharmony_ci
3461cb0ef41Sopenharmony_ci    return this.method(object, methodName, implementation, {
3471cb0ef41Sopenharmony_ci      __proto__: null,
3481cb0ef41Sopenharmony_ci      ...options,
3491cb0ef41Sopenharmony_ci      setter,
3501cb0ef41Sopenharmony_ci    });
3511cb0ef41Sopenharmony_ci  }
3521cb0ef41Sopenharmony_ci
3531cb0ef41Sopenharmony_ci  /**
3541cb0ef41Sopenharmony_ci   * Resets the mock tracker, restoring all mocks and clearing timers.
3551cb0ef41Sopenharmony_ci   */
3561cb0ef41Sopenharmony_ci  reset() {
3571cb0ef41Sopenharmony_ci    this.restoreAll();
3581cb0ef41Sopenharmony_ci    this.#timers?.reset();
3591cb0ef41Sopenharmony_ci    this.#mocks = [];
3601cb0ef41Sopenharmony_ci  }
3611cb0ef41Sopenharmony_ci
3621cb0ef41Sopenharmony_ci  /**
3631cb0ef41Sopenharmony_ci   * Restore all mocks created by this MockTracker instance.
3641cb0ef41Sopenharmony_ci   */
3651cb0ef41Sopenharmony_ci  restoreAll() {
3661cb0ef41Sopenharmony_ci    for (let i = 0; i < this.#mocks.length; i++) {
3671cb0ef41Sopenharmony_ci      FunctionPrototypeCall(restore, this.#mocks[i]);
3681cb0ef41Sopenharmony_ci    }
3691cb0ef41Sopenharmony_ci  }
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_ci  #setupMock(ctx, fnToMatch) {
3721cb0ef41Sopenharmony_ci    const mock = new Proxy(fnToMatch, {
3731cb0ef41Sopenharmony_ci      __proto__: null,
3741cb0ef41Sopenharmony_ci      apply(_fn, thisArg, argList) {
3751cb0ef41Sopenharmony_ci        const fn = FunctionPrototypeCall(nextImpl, ctx);
3761cb0ef41Sopenharmony_ci        let result;
3771cb0ef41Sopenharmony_ci        let error;
3781cb0ef41Sopenharmony_ci
3791cb0ef41Sopenharmony_ci        try {
3801cb0ef41Sopenharmony_ci          result = ReflectApply(fn, thisArg, argList);
3811cb0ef41Sopenharmony_ci        } catch (err) {
3821cb0ef41Sopenharmony_ci          error = err;
3831cb0ef41Sopenharmony_ci          throw err;
3841cb0ef41Sopenharmony_ci        } finally {
3851cb0ef41Sopenharmony_ci          FunctionPrototypeCall(trackCall, ctx, {
3861cb0ef41Sopenharmony_ci            __proto__: null,
3871cb0ef41Sopenharmony_ci            arguments: argList,
3881cb0ef41Sopenharmony_ci            error,
3891cb0ef41Sopenharmony_ci            result,
3901cb0ef41Sopenharmony_ci            // eslint-disable-next-line no-restricted-syntax
3911cb0ef41Sopenharmony_ci            stack: new Error(),
3921cb0ef41Sopenharmony_ci            target: undefined,
3931cb0ef41Sopenharmony_ci            this: thisArg,
3941cb0ef41Sopenharmony_ci          });
3951cb0ef41Sopenharmony_ci        }
3961cb0ef41Sopenharmony_ci
3971cb0ef41Sopenharmony_ci        return result;
3981cb0ef41Sopenharmony_ci      },
3991cb0ef41Sopenharmony_ci      construct(target, argList, newTarget) {
4001cb0ef41Sopenharmony_ci        const realTarget = FunctionPrototypeCall(nextImpl, ctx);
4011cb0ef41Sopenharmony_ci        let result;
4021cb0ef41Sopenharmony_ci        let error;
4031cb0ef41Sopenharmony_ci
4041cb0ef41Sopenharmony_ci        try {
4051cb0ef41Sopenharmony_ci          result = ReflectConstruct(realTarget, argList, newTarget);
4061cb0ef41Sopenharmony_ci        } catch (err) {
4071cb0ef41Sopenharmony_ci          error = err;
4081cb0ef41Sopenharmony_ci          throw err;
4091cb0ef41Sopenharmony_ci        } finally {
4101cb0ef41Sopenharmony_ci          FunctionPrototypeCall(trackCall, ctx, {
4111cb0ef41Sopenharmony_ci            __proto__: null,
4121cb0ef41Sopenharmony_ci            arguments: argList,
4131cb0ef41Sopenharmony_ci            error,
4141cb0ef41Sopenharmony_ci            result,
4151cb0ef41Sopenharmony_ci            // eslint-disable-next-line no-restricted-syntax
4161cb0ef41Sopenharmony_ci            stack: new Error(),
4171cb0ef41Sopenharmony_ci            target,
4181cb0ef41Sopenharmony_ci            this: result,
4191cb0ef41Sopenharmony_ci          });
4201cb0ef41Sopenharmony_ci        }
4211cb0ef41Sopenharmony_ci
4221cb0ef41Sopenharmony_ci        return result;
4231cb0ef41Sopenharmony_ci      },
4241cb0ef41Sopenharmony_ci      get(target, property, receiver) {
4251cb0ef41Sopenharmony_ci        if (property === 'mock') {
4261cb0ef41Sopenharmony_ci          return ctx;
4271cb0ef41Sopenharmony_ci        }
4281cb0ef41Sopenharmony_ci
4291cb0ef41Sopenharmony_ci        return ReflectGet(target, property, receiver);
4301cb0ef41Sopenharmony_ci      },
4311cb0ef41Sopenharmony_ci    });
4321cb0ef41Sopenharmony_ci
4331cb0ef41Sopenharmony_ci    ArrayPrototypePush(this.#mocks, ctx);
4341cb0ef41Sopenharmony_ci    return mock;
4351cb0ef41Sopenharmony_ci  }
4361cb0ef41Sopenharmony_ci}
4371cb0ef41Sopenharmony_ci
4381cb0ef41Sopenharmony_cifunction validateStringOrSymbol(value, name) {
4391cb0ef41Sopenharmony_ci  if (typeof value !== 'string' && typeof value !== 'symbol') {
4401cb0ef41Sopenharmony_ci    throw new ERR_INVALID_ARG_TYPE(name, ['string', 'symbol'], value);
4411cb0ef41Sopenharmony_ci  }
4421cb0ef41Sopenharmony_ci}
4431cb0ef41Sopenharmony_ci
4441cb0ef41Sopenharmony_cifunction validateTimes(value, name) {
4451cb0ef41Sopenharmony_ci  if (value === Infinity) {
4461cb0ef41Sopenharmony_ci    return;
4471cb0ef41Sopenharmony_ci  }
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci  validateInteger(value, name, 1);
4501cb0ef41Sopenharmony_ci}
4511cb0ef41Sopenharmony_ci
4521cb0ef41Sopenharmony_cifunction findMethodOnPrototypeChain(instance, methodName) {
4531cb0ef41Sopenharmony_ci  let host = instance;
4541cb0ef41Sopenharmony_ci  let descriptor;
4551cb0ef41Sopenharmony_ci
4561cb0ef41Sopenharmony_ci  while (host !== null) {
4571cb0ef41Sopenharmony_ci    descriptor = ObjectGetOwnPropertyDescriptor(host, methodName);
4581cb0ef41Sopenharmony_ci
4591cb0ef41Sopenharmony_ci    if (descriptor) {
4601cb0ef41Sopenharmony_ci      break;
4611cb0ef41Sopenharmony_ci    }
4621cb0ef41Sopenharmony_ci
4631cb0ef41Sopenharmony_ci    host = ObjectGetPrototypeOf(host);
4641cb0ef41Sopenharmony_ci  }
4651cb0ef41Sopenharmony_ci
4661cb0ef41Sopenharmony_ci  return descriptor;
4671cb0ef41Sopenharmony_ci}
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_cimodule.exports = { MockTracker };
470