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