• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1const mustCallChecks = [];
2
3function runCallChecks(exitCode) {
4  if (exitCode !== 0) return;
5
6  const failed = mustCallChecks.filter(function(context) {
7    return context.actual !== context.expected;
8  });
9
10  failed.forEach(function(context) {
11    console.log('Mismatched %s function calls. Expected %d, actual %d.',
12                context.name,
13                context.expected,
14                context.actual);
15    console.log(context.stack.split('\n').slice(2).join('\n'));
16  });
17
18  if (failed.length) process.exit(1);
19}
20
21exports.mustCall = function(fn, expected) {
22  if (typeof fn === 'number') {
23    expected = fn;
24    fn = noop;
25  } else if (fn === undefined) {
26    fn = noop;
27  }
28
29  if (expected === undefined)
30    expected = 1;
31  else if (typeof expected !== 'number')
32    throw new TypeError(`Invalid expected value: ${expected}`);
33
34  const context = {
35    expected: expected,
36    actual: 0,
37    stack: (new Error()).stack,
38    name: fn.name || '<anonymous>'
39  };
40
41  // add the exit listener only once to avoid listener leak warnings
42  if (mustCallChecks.length === 0) process.on('exit', runCallChecks);
43
44  mustCallChecks.push(context);
45
46  return function() {
47    context.actual++;
48    return fn.apply(this, arguments);
49  };
50};
51
52// Crash the process on unhandled rejections.
53exports.crashOnUnhandledRejection = function() {
54  process.on('unhandledRejection',
55             (err) => process.nextTick(() => { throw err; }));
56};
57