Umama-at-Bluchip/Quick-UI
0
1'use strict';2 3const assert = require('assert');4const { inspect } = require('util');5 6const mustCallChecks = [];7 8function noop() {}9 10function runCallChecks(exitCode) {11 if (exitCode !== 0) return;12 13 const failed = mustCallChecks.filter((context) => {14 if ('minimum' in context) {15 context.messageSegment = `at least ${context.minimum}`;16 return context.actual < context.minimum;17 }18 context.messageSegment = `exactly ${context.exact}`;19 return context.actual !== context.exact;20 });21 22 failed.forEach((context) => {23 console.error('Mismatched %s function calls. Expected %s, actual %d.',24 context.name,25 context.messageSegment,26 context.actual);27 console.error(context.stack.split('\n').slice(2).join('\n'));28 });29 30 if (failed.length)31 process.exit(1);32}33 34function mustCall(fn, exact) {35 return _mustCallInner(fn, exact, 'exact');36}37 38function mustCallAtLeast(fn, minimum) {39 return _mustCallInner(fn, minimum, 'minimum');40}41 42function _mustCallInner(fn, criteria = 1, field) {43 if (process._exiting)44 throw new Error('Cannot use common.mustCall*() in process exit handler');45 46 if (typeof fn === 'number') {47 criteria = fn;48 fn = noop;49 } else if (fn === undefined) {50 fn = noop;51 }52 53 if (typeof criteria !== 'number')54 throw new TypeError(`Invalid ${field} value: ${criteria}`);55 56 const context = {57 [field]: criteria,58 actual: 0,59 stack: inspect(new Error()),60 name: fn.name || '<anonymous>'61 };62 63 // Add the exit listener only once to avoid listener leak warnings64 if (mustCallChecks.length === 0)65 process.on('exit', runCallChecks);66 67 mustCallChecks.push(context);68 69 function wrapped(...args) {70 ++context.actual;71 return fn.call(this, ...args);72 }73 // TODO: remove origFn?74 wrapped.origFn = fn;75 76 return wrapped;77}78 79function getCallSite(top) {80 const originalStackFormatter = Error.prepareStackTrace;81 Error.prepareStackTrace = (err, stack) =>82 `${stack[0].getFileName()}:${stack[0].getLineNumber()}`;83 const err = new Error();84 Error.captureStackTrace(err, top);85 // With the V8 Error API, the stack is not formatted until it is accessed86 // eslint-disable-next-line no-unused-expressions87 err.stack;88 Error.prepareStackTrace = originalStackFormatter;89 return err.stack;90}91 92function mustNotCall(msg) {93 const callSite = getCallSite(mustNotCall);94 return function mustNotCall(...args) {95 args = args.map(inspect).join(', ');96 const argsInfo = (args.length > 097 ? `\ncalled with arguments: ${args}`98 : '');99 assert.fail(100 `${msg || 'function should not have been called'} at ${callSite}`101 + argsInfo);102 };103}104 105module.exports = {106 mustCall,107 mustCallAtLeast,108 mustNotCall,109};110 