1 | // Copyright Joyent, Inc. and other Node contributors.
|
---|
2 | //
|
---|
3 | // Permission is hereby granted, free of charge, to any person obtaining a
|
---|
4 | // copy of this software and associated documentation files (the
|
---|
5 | // "Software"), to deal in the Software without restriction, including
|
---|
6 | // without limitation the rights to use, copy, modify, merge, publish,
|
---|
7 | // distribute, sublicense, and/or sell copies of the Software, and to permit
|
---|
8 | // persons to whom the Software is furnished to do so, subject to the
|
---|
9 | // following conditions:
|
---|
10 | //
|
---|
11 | // The above copyright notice and this permission notice shall be included
|
---|
12 | // in all copies or substantial portions of the Software.
|
---|
13 | //
|
---|
14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
---|
15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
---|
16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
---|
17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
---|
18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
---|
19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
---|
20 | // USE OR OTHER DEALINGS IN THE SOFTWARE.
|
---|
21 |
|
---|
22 | var test = require('tape');
|
---|
23 | var assert = require('assert');
|
---|
24 |
|
---|
25 | var noop = function() {};
|
---|
26 |
|
---|
27 | var mustCallChecks = [];
|
---|
28 |
|
---|
29 | function runCallChecks(exitCode) {
|
---|
30 | if (exitCode !== 0) return;
|
---|
31 |
|
---|
32 | var failed = filter(mustCallChecks, function(context) {
|
---|
33 | if ('minimum' in context) {
|
---|
34 | context.messageSegment = 'at least ' + context.minimum;
|
---|
35 | return context.actual < context.minimum;
|
---|
36 | } else {
|
---|
37 | context.messageSegment = 'exactly ' + context.exact;
|
---|
38 | return context.actual !== context.exact;
|
---|
39 | }
|
---|
40 | });
|
---|
41 |
|
---|
42 | for (var i = 0; i < failed.length; i++) {
|
---|
43 | var context = failed[i];
|
---|
44 | console.log('Mismatched %s function calls. Expected %s, actual %d.',
|
---|
45 | context.name,
|
---|
46 | context.messageSegment,
|
---|
47 | context.actual);
|
---|
48 | // IE8 has no .stack
|
---|
49 | if (context.stack) console.log(context.stack.split('\n').slice(2).join('\n'));
|
---|
50 | }
|
---|
51 |
|
---|
52 | assert.strictEqual(failed.length, 0);
|
---|
53 | }
|
---|
54 |
|
---|
55 | exports.mustCall = function(fn, exact) {
|
---|
56 | return _mustCallInner(fn, exact, 'exact');
|
---|
57 | };
|
---|
58 |
|
---|
59 | function _mustCallInner(fn, criteria, field) {
|
---|
60 | if (typeof criteria == 'undefined') criteria = 1;
|
---|
61 |
|
---|
62 | if (typeof fn === 'number') {
|
---|
63 | criteria = fn;
|
---|
64 | fn = noop;
|
---|
65 | } else if (fn === undefined) {
|
---|
66 | fn = noop;
|
---|
67 | }
|
---|
68 |
|
---|
69 | if (typeof criteria !== 'number')
|
---|
70 | throw new TypeError('Invalid ' + field + ' value: ' + criteria);
|
---|
71 |
|
---|
72 | var context = {
|
---|
73 | actual: 0,
|
---|
74 | stack: (new Error()).stack,
|
---|
75 | name: fn.name || '<anonymous>'
|
---|
76 | };
|
---|
77 |
|
---|
78 | context[field] = criteria;
|
---|
79 |
|
---|
80 | // add the exit listener only once to avoid listener leak warnings
|
---|
81 | if (mustCallChecks.length === 0) test.onFinish(function() { runCallChecks(0); });
|
---|
82 |
|
---|
83 | mustCallChecks.push(context);
|
---|
84 |
|
---|
85 | return function() {
|
---|
86 | context.actual++;
|
---|
87 | return fn.apply(this, arguments);
|
---|
88 | };
|
---|
89 | }
|
---|
90 |
|
---|
91 | exports.mustNotCall = function(msg) {
|
---|
92 | return function mustNotCall() {
|
---|
93 | assert.fail(msg || 'function should not have been called');
|
---|
94 | };
|
---|
95 | };
|
---|
96 |
|
---|
97 | function filter(arr, fn) {
|
---|
98 | if (arr.filter) return arr.filter(fn);
|
---|
99 | var filtered = [];
|
---|
100 | for (var i = 0; i < arr.length; i++) {
|
---|
101 | if (fn(arr[i], i, arr)) filtered.push(arr[i]);
|
---|
102 | }
|
---|
103 | return filtered
|
---|
104 | }
|
---|