mirror of
https://github.com/nodejs/node.git
synced 2025-05-05 21:04:16 +00:00

PR-URL: https://github.com/nodejs/node/pull/43640 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Nitzan Uziely <linkgoron@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
105 lines
2.5 KiB
JavaScript
105 lines
2.5 KiB
JavaScript
'use strict';
|
|
|
|
const {
|
|
ArrayPrototypePush,
|
|
Error,
|
|
FunctionPrototype,
|
|
Proxy,
|
|
ReflectApply,
|
|
SafeSet,
|
|
} = primordials;
|
|
|
|
const {
|
|
codes: {
|
|
ERR_UNAVAILABLE_DURING_EXIT,
|
|
},
|
|
} = require('internal/errors');
|
|
const AssertionError = require('internal/assert/assertion_error');
|
|
const {
|
|
validateUint32,
|
|
} = require('internal/validators');
|
|
|
|
const noop = FunctionPrototype;
|
|
|
|
class CallTracker {
|
|
|
|
#callChecks = new SafeSet();
|
|
|
|
calls(fn, exact = 1) {
|
|
if (process._exiting)
|
|
throw new ERR_UNAVAILABLE_DURING_EXIT();
|
|
if (typeof fn === 'number') {
|
|
exact = fn;
|
|
fn = noop;
|
|
} else if (fn === undefined) {
|
|
fn = noop;
|
|
}
|
|
|
|
validateUint32(exact, 'exact', true);
|
|
|
|
const context = {
|
|
exact,
|
|
actual: 0,
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
stackTrace: new Error(),
|
|
name: fn.name || 'calls'
|
|
};
|
|
const callChecks = this.#callChecks;
|
|
callChecks.add(context);
|
|
|
|
return new Proxy(fn, {
|
|
__proto__: null,
|
|
apply(fn, thisArg, argList) {
|
|
context.actual++;
|
|
if (context.actual === context.exact) {
|
|
// Once function has reached its call count remove it from
|
|
// callChecks set to prevent memory leaks.
|
|
callChecks.delete(context);
|
|
}
|
|
// If function has been called more than expected times, add back into
|
|
// callchecks.
|
|
if (context.actual === context.exact + 1) {
|
|
callChecks.add(context);
|
|
}
|
|
return ReflectApply(fn, thisArg, argList);
|
|
},
|
|
});
|
|
}
|
|
|
|
report() {
|
|
const errors = [];
|
|
for (const context of this.#callChecks) {
|
|
// If functions have not been called exact times
|
|
if (context.actual !== context.exact) {
|
|
const message = `Expected the ${context.name} function to be ` +
|
|
`executed ${context.exact} time(s) but was ` +
|
|
`executed ${context.actual} time(s).`;
|
|
ArrayPrototypePush(errors, {
|
|
message,
|
|
actual: context.actual,
|
|
expected: context.exact,
|
|
operator: context.name,
|
|
stack: context.stackTrace
|
|
});
|
|
}
|
|
}
|
|
return errors;
|
|
}
|
|
|
|
verify() {
|
|
const errors = this.report();
|
|
if (errors.length === 0) {
|
|
return;
|
|
}
|
|
const message = errors.length === 1 ?
|
|
errors[0].message :
|
|
'Functions were not called the expected number of times';
|
|
throw new AssertionError({
|
|
message,
|
|
details: errors,
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = CallTracker;
|