1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 | 'use strict';
|
34 |
|
35 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
36 |
|
37 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
38 |
|
39 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
|
40 |
|
41 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
42 |
|
43 | var assert = void 0;
|
44 |
|
45 | var isEqual = require('lodash.isequal');
|
46 |
|
47 | var toString = Object.prototype.toString;
|
48 |
|
49 | var green = function green(x) {
|
50 | return '\x1B[32m' + x + '\x1B[39m';
|
51 | };
|
52 | var red = function red(x) {
|
53 | return '\x1B[31m' + x + '\x1B[39m';
|
54 | };
|
55 | var clear = '\x1b[39;49;00m';
|
56 |
|
57 | if (!((typeof process === 'undefined' ? 'undefined' : _typeof(process)) === 'object' && process.stdout && process.stdout.isTTY)) {
|
58 | red = function red(x) {
|
59 | return '' + x;
|
60 | };
|
61 | green = red;
|
62 | clear = '';
|
63 | }
|
64 |
|
65 |
|
66 | var is = ['Array', 'RegExp', 'String', 'Number', 'Date', 'Function'].reduce(function (o, t) {
|
67 | return _extends({}, o, _defineProperty({}, t, function (obj) {
|
68 | return toString.call(obj) === '[object ' + t + ']';
|
69 | }));
|
70 | }, {
|
71 | NaN: function NaN(obj) {
|
72 | return is.Number(obj) && isNaN(obj);
|
73 | },
|
74 | Object: function Object(obj) {
|
75 | var t = typeof obj === 'undefined' ? 'undefined' : _typeof(obj);
|
76 | return t === 'function' || t === 'object' && !!obj;
|
77 | },
|
78 | Boolean: function Boolean(obj) {
|
79 | return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
|
80 | },
|
81 | Undefined: function Undefined(obj) {
|
82 | return obj === undefined;
|
83 | },
|
84 | Null: function Null(obj) {
|
85 | return obj === null;
|
86 | }
|
87 | });
|
88 | if (Array.isArray) is.Array = Array.isArray;
|
89 |
|
90 | function error(message, explanation, errProps) {
|
91 | if (explanation != null) {
|
92 | message = 'Assertion failed: ' + explanation + '\n' + clear + message;
|
93 | }
|
94 | var err = new Error(message);
|
95 | if (errProps) {
|
96 | Object.keys(errProps).forEach(function (prop) {
|
97 | err[prop] = errProps[prop];
|
98 | });
|
99 | }
|
100 | return err;
|
101 | }
|
102 |
|
103 | function nameNegative(name) {
|
104 | if (name === 'truthy') {
|
105 | return 'falsey';
|
106 | }
|
107 | if (name === 'resolves') {
|
108 | return 'rejects';
|
109 | }
|
110 | return 'not' + name.charAt().toUpperCase() + name.slice(1);
|
111 | }
|
112 |
|
113 | function asRegExp(re) {
|
114 | var flags = '';
|
115 | if (re.global) flags += 'g';
|
116 | if (re.multiline) flags += 'm';
|
117 | if (re.ignoreCase) flags += 'i';
|
118 | return '/' + re.source + '/' + flags;
|
119 | }
|
120 |
|
121 | function stringifyReplacer(key, val) {
|
122 | if (typeof val === 'function') return toString.call(val);
|
123 | if (is.RegExp(val)) return asRegExp(val);
|
124 | if (is.Object(val) && !is.Array(val)) {
|
125 | return Object.keys(val).sort().reduce(function (o, p) {
|
126 | return _extends({}, o, _defineProperty({}, p, val[p]));
|
127 | }, {});
|
128 | }
|
129 | return val;
|
130 | }
|
131 |
|
132 | function stringify(x) {
|
133 | if (x == null) return '' + x;
|
134 | if (is.NaN(x)) return 'NaN';
|
135 | if (is.RegExp(x)) return asRegExp(x);
|
136 | if ((typeof x === 'undefined' ? 'undefined' : _typeof(x)) === 'symbol') return x.toString();
|
137 | var json = JSON.stringify(x, stringifyReplacer, 2);
|
138 | var className = x && x.constructor && x.constructor.name;
|
139 | if ((typeof x === 'undefined' ? 'undefined' : _typeof(x)) !== 'object' || className === 'Object' || className === 'Array') {
|
140 | return json;
|
141 | }
|
142 |
|
143 | if (x instanceof Error || /Error/.test(className)) {
|
144 | if (json === '{}') {
|
145 | return x.stack;
|
146 | }
|
147 | return x.stack + '\nwith error metadata:\n' + json;
|
148 | }
|
149 | if (x.toString === toString) {
|
150 | return className;
|
151 | }
|
152 | try {
|
153 | return className + '[' + x + ']';
|
154 | } catch (e) {
|
155 | return className;
|
156 | }
|
157 | }
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 | function handleArgs(self, count, args, name, help) {
|
164 | var negated = false;
|
165 | if (is.String(self)) {
|
166 | negated = true;
|
167 | name = nameNegative(name);
|
168 | }
|
169 |
|
170 | var argc = args.length;
|
171 | if (argc === count) return [name, negated];
|
172 |
|
173 | var max = '';
|
174 | if (is.Array(count) && count.indexOf(argc) !== -1) {
|
175 | var n = count[count.length - 1];
|
176 | if (argc !== n || is.String(args[0])) return [name, negated];
|
177 | max = ',\nand when called with ' + n + ' args, the first arg must be a docstring';
|
178 | }
|
179 |
|
180 | var wantedArgCount = void 0;
|
181 | if (is.Number(count)) {
|
182 | wantedArgCount = count + ' argument';
|
183 | } else {
|
184 | wantedArgCount = count.slice(0, -1).join(', ');
|
185 | count = count.pop();
|
186 | wantedArgCount = wantedArgCount + ' or ' + count + ' argument';
|
187 | }
|
188 | if (count !== 1) wantedArgCount += 's';
|
189 |
|
190 | var actualArgs = stringify([].slice.call(args)).slice(1, -1);
|
191 |
|
192 | var functionSource = Function.prototype.toString.call(assert[name]);
|
193 | var wantedArgNames = functionSource.match(/^function\s*[^(]*\s*\(([^)]*)/)[1];
|
194 | if (max) {
|
195 | wantedArgNames = 'explanation, ' + wantedArgNames;
|
196 | }
|
197 |
|
198 | var wanted = name + '(' + wantedArgNames + ')';
|
199 | var actual = name + '(' + actualArgs + ')';
|
200 | var message = green(wanted) + ' needs ' + (wantedArgCount + max) + '\nyour usage: ' + red(actual);
|
201 |
|
202 | if (typeof help === 'function') {
|
203 | help = help();
|
204 | }
|
205 | throw error(message, help);
|
206 | }
|
207 |
|
208 | function type(x) {
|
209 | if (is.String(x)) return 'String';
|
210 | if (is.Number(x)) return 'Number';
|
211 | if (is.RegExp(x)) return 'RegExp';
|
212 | if (is.Array(x)) return 'Array';
|
213 | throw new TypeError('unsupported type: ' + x);
|
214 | }
|
215 |
|
216 | function abbreviate(name, value, threshold) {
|
217 | var str = stringify(value);
|
218 | if (str.length <= (threshold || 1024)) return str;
|
219 | var desc = 'length: ' + value.length;
|
220 | if (is.Array(value)) desc += '; ' + str.length + ' JSON encoded';
|
221 | if (name) name += ' ';
|
222 | return '' + name + type(value) + '[' + desc + ']';
|
223 | }
|
224 |
|
225 |
|
226 | function getNameOfType(x) {
|
227 | switch (false) {
|
228 | case !(x == null):
|
229 | return '' + x;
|
230 | case !is.String(x):
|
231 | return x;
|
232 | case !is.Function(x):
|
233 | return x.name;
|
234 | case !is.NaN(x):
|
235 | return 'NaN';
|
236 | default:
|
237 | return x;
|
238 | }
|
239 | }
|
240 |
|
241 |
|
242 |
|
243 | var types = ['null', 'Date', 'Array', 'String', 'RegExp', 'Boolean', 'Function', 'Object', 'NaN', 'Number', 'undefined'];
|
244 |
|
245 | function implodeNicely(list, conjunction) {
|
246 | var first = list.slice(0, -1).join(', ');
|
247 | var last = list[list.length - 1];
|
248 | return first + ' ' + (conjunction || 'and') + ' ' + last;
|
249 | }
|
250 |
|
251 | function isType(value, typeName) {
|
252 | if (typeName === 'Date') return is.Date(value) && !is.NaN(+value);
|
253 | return is['' + typeName[0].toUpperCase() + typeName.slice(1)](value);
|
254 | }
|
255 |
|
256 |
|
257 | function getTypeName(value) {
|
258 | return types.filter(isType.bind(null, value))[0];
|
259 | }
|
260 |
|
261 | var assertSync = {
|
262 | truthy: function truthy(bool) {
|
263 | var args = handleArgs(this, [1, 2], arguments, 'truthy');
|
264 | var name = args[0];
|
265 | var negated = args[1];
|
266 | var explanation = void 0;
|
267 | if (arguments.length === 2) {
|
268 | explanation = arguments[0];
|
269 | bool = arguments[1];
|
270 | }
|
271 | if (!bool && !negated || bool && negated) {
|
272 | throw error('Expected ' + red(stringify(bool)) + ' to be ' + name, explanation);
|
273 | }
|
274 | },
|
275 | expect: function expect(bool) {
|
276 | var explanation = void 0;
|
277 | if (arguments.length === 2) {
|
278 | explanation = arguments[0];
|
279 | bool = arguments[1];
|
280 | }
|
281 | if (explanation) return assertSync.equal(explanation, true, bool);
|
282 | return assertSync.equal(true, bool);
|
283 | },
|
284 | equal: function equal(expected, actual) {
|
285 | var explanation = void 0;
|
286 | var negated = handleArgs(this, [2, 3], arguments, 'equal')[1];
|
287 | if (arguments.length === 3) {
|
288 | explanation = arguments[0];
|
289 | expected = arguments[1];
|
290 | actual = arguments[2];
|
291 | }
|
292 | if (negated) {
|
293 | if (expected === actual) {
|
294 | throw error('notEqual assertion expected ' + red(stringify(actual)) + ' to be exactly anything else', explanation);
|
295 | }
|
296 | } else if (expected !== actual) {
|
297 | throw error('Expected: ' + green(stringify(expected)) + '\nActually: ' + ('' + red(stringify(actual))), explanation, { actual: actual, expected: expected });
|
298 | }
|
299 | },
|
300 | deepEqual: function deepEqual(expected, actual) {
|
301 | var explanation = void 0;
|
302 | var negated = handleArgs(this, [2, 3], arguments, 'deepEqual')[1];
|
303 | if (arguments.length === 3) {
|
304 | explanation = arguments[0];
|
305 | expected = arguments[1];
|
306 | actual = arguments[2];
|
307 | }
|
308 | var isEq = isEqual(expected, actual);
|
309 | if (isEq && !negated || !isEq && negated) return;
|
310 |
|
311 | var wrongLooks = stringify(actual);
|
312 | if (negated) {
|
313 | throw error('notDeepEqual assertion expected exactly anything else but\n' + red(wrongLooks), explanation);
|
314 | }
|
315 |
|
316 | var rightLooks = stringify(expected);
|
317 | var message = void 0;
|
318 | if (wrongLooks === rightLooks) {
|
319 | message = 'deepEqual ' + green(rightLooks) + ' failed on something that\n' + 'serializes to the same result (likely some function)';
|
320 | } else {
|
321 | message = 'Expected: ' + wrongLooks + ' to deepEqual ' + rightLooks;
|
322 | }
|
323 |
|
324 | throw error(message, explanation, { expected: expected, actual: actual });
|
325 | },
|
326 | include: function include(needle, haystack) {
|
327 | var args = handleArgs(this, [2, 3], arguments, 'include');
|
328 | var name = args[0];
|
329 | var negated = args[1];
|
330 | var explanation = void 0;
|
331 | if (arguments.length === 3) {
|
332 | explanation = arguments[0];
|
333 | needle = arguments[1];
|
334 | haystack = arguments[2];
|
335 | }
|
336 | if (is.String(haystack)) {
|
337 | if (needle === '') {
|
338 | var what = negated ? 'always-failing test' : 'no-op test';
|
339 | throw error(what + ' detected: all strings contain the empty string!');
|
340 | }
|
341 | if (!is.String(needle) && !is.Number(needle) && !is.RegExp(needle)) {
|
342 | var problem = 'needs a RegExp/String/Number needle for a String haystack';
|
343 | throw new TypeError(name + ' ' + problem + '; you used:\n' + (name + ' ' + green(stringify(haystack)) + ', ' + red(stringify(needle))));
|
344 | }
|
345 | } else if (!is.Array(haystack)) {
|
346 | needle = stringify(needle);
|
347 | throw new TypeError(name + ' takes a String or Array haystack; you used:\n' + name + ' ' + red(stringify(haystack)) + ', ' + needle);
|
348 | }
|
349 |
|
350 | var contained = is.String(haystack) && is.RegExp(needle) ? haystack.match(needle) : haystack.indexOf(needle) > -1;
|
351 |
|
352 | if (negated) {
|
353 | if (contained) {
|
354 | var message = '' + ('notInclude expected needle not to be found in ' + ('haystack\n- needle: ' + stringify(needle) + '\n haystack: ')) + abbreviate('', haystack);
|
355 | if (is.String(haystack) && is.RegExp(needle)) {
|
356 | message += ', but found:\n';
|
357 | if (needle.global) {
|
358 | message += contained.map(function (s) {
|
359 | return '* ' + red(stringify(s));
|
360 | }).join('\n');
|
361 | } else {
|
362 | message += '* ' + red(stringify(contained[0]));
|
363 | }
|
364 | }
|
365 | throw error(message, explanation);
|
366 | }
|
367 | } else if (!contained) {
|
368 | throw error(name + ' expected needle to be found in haystack\n' + ('- needle: ' + stringify(needle) + '\n') + ('haystack: ' + abbreviate('', haystack)), explanation);
|
369 | }
|
370 | },
|
371 | match: function match(regexp, string) {
|
372 | var args = handleArgs(this, [2, 3], arguments, 'match');
|
373 | var name = args[0];
|
374 | var negated = args[1];
|
375 | var explanation = void 0;
|
376 | if (arguments.length === 3) {
|
377 | explanation = arguments[0];
|
378 | regexp = arguments[1];
|
379 | string = arguments[2];
|
380 | }
|
381 |
|
382 | var re = is.RegExp(regexp);
|
383 | if (!re || !is.String(string)) {
|
384 | string = abbreviate('string', string);
|
385 | var oops = re ? 'string arg is not a String' : 'regexp arg is not a RegExp';
|
386 | var called = name + ' ' + stringify(regexp) + ', ' + red(string);
|
387 | throw new TypeError(name + ': ' + oops + '; you used:\n' + called);
|
388 | }
|
389 |
|
390 | var matched = regexp.test(string);
|
391 | if (negated) {
|
392 | if (!matched) return;
|
393 | var message = 'Expected: ' + stringify(regexp) + '\nnot to match: ' + ('' + red(abbreviate('string', string)));
|
394 | if (regexp.global) {
|
395 | var count = string.match(regexp).length;
|
396 | message += '\nMatches: ' + red(count);
|
397 | }
|
398 | throw error(message, explanation);
|
399 | }
|
400 | if (!matched) {
|
401 | throw error('Expected: ' + stringify(regexp) + '\nto match: ' + ('' + red(abbreviate('string', string))), explanation);
|
402 | }
|
403 | },
|
404 | throws: function throws(fn) {
|
405 | var args = handleArgs(this, [1, 2], arguments, 'throws');
|
406 | var name = args[0];
|
407 | var negated = args[1];
|
408 | var explanation = void 0;
|
409 | if (arguments.length === 2) {
|
410 | explanation = arguments[0];
|
411 | fn = arguments[1];
|
412 | }
|
413 | if (typeof explanation === 'function') {
|
414 | fn = explanation;
|
415 | explanation = undefined;
|
416 | }
|
417 | if (typeof fn !== 'function') {
|
418 | throw error(name + ' expects ' + green('a function') + ' but got ' + red(fn));
|
419 | }
|
420 |
|
421 | try {
|
422 | fn();
|
423 | } catch (err) {
|
424 | if (negated) {
|
425 | throw error('Threw an exception despite ' + name + ' assertion:\n' + ('' + err.message), explanation);
|
426 | }
|
427 | return err;
|
428 | }
|
429 |
|
430 | if (negated) return undefined;
|
431 | throw error("Didn't throw an exception as expected to", explanation);
|
432 | },
|
433 | hasType: function hasType(expectedType, value) {
|
434 | var args = handleArgs(this, [2, 3], arguments, 'hasType');
|
435 | var name = args[0];
|
436 | var negated = args[1];
|
437 | var explanation = void 0;
|
438 | if (arguments.length === 3) {
|
439 | explanation = arguments[0];
|
440 | expectedType = arguments[1];
|
441 | value = arguments[2];
|
442 | }
|
443 |
|
444 | var stringType = getNameOfType(expectedType);
|
445 | if (types.indexOf(stringType) === -1) {
|
446 | var badArg = stringify(expectedType);
|
447 | var suggestions = implodeNicely(types, 'or');
|
448 | throw new TypeError(name + ': unknown expectedType ' + badArg + '; you used:\n' + name + ' ' + (red(badArg) + ', ' + stringify(value) + '\nDid you mean ' + suggestions + '?'));
|
449 | }
|
450 |
|
451 | var typeMatches = stringType === getTypeName(value);
|
452 | if (!typeMatches && !negated || typeMatches && negated) {
|
453 | value = red(stringify(value));
|
454 | var toBeOrNotToBe = (negated ? 'not ' : '') + 'to be';
|
455 | var message = 'Expected value ' + value + ' ' + toBeOrNotToBe + ' of type ' + stringType;
|
456 | throw error(message, explanation);
|
457 | }
|
458 | }
|
459 | };
|
460 |
|
461 |
|
462 | var positiveAssertions = ['truthy', 'equal', 'deepEqual', 'include', 'match', 'throws', 'hasType'];
|
463 | positiveAssertions.forEach(function (name) {
|
464 | assertSync[nameNegative(name)] = function _oneTest() {
|
465 | return assertSync[name].apply('!', arguments);
|
466 | };
|
467 | });
|
468 |
|
469 |
|
470 | function isPromiseAlike(p) {
|
471 | return p === Object(p) && typeof p.then === 'function';
|
472 | }
|
473 |
|
474 |
|
475 | assert = {
|
476 | resolves: function resolves(testee) {
|
477 | var name = handleArgs(this, [1, 2], arguments, 'resolves')[0];
|
478 | var explanation = void 0;
|
479 | if (arguments.length === 2) {
|
480 | explanation = arguments[0];
|
481 | testee = arguments[1];
|
482 | }
|
483 |
|
484 | if (!isPromiseAlike(testee)) {
|
485 | throw error(name + ' expects ' + green('a promise') + ' but got ' + red(stringify(testee)));
|
486 | }
|
487 |
|
488 | if (name === 'rejects') {
|
489 | return testee.then(function () {
|
490 | throw error("Promise wasn't rejected as expected to", explanation);
|
491 | }, function (x) {
|
492 | return x;
|
493 | });
|
494 | }
|
495 | return testee.catch(function (err) {
|
496 | throw error('Promise was rejected despite resolves assertion:\n' + ('' + (err && err.message || err)), explanation);
|
497 | });
|
498 | },
|
499 | rejects: function rejects() {
|
500 | return assert.resolves.apply('!', arguments);
|
501 | }
|
502 | };
|
503 |
|
504 |
|
505 | if (assertSync) {
|
506 | Object.keys(assertSync).forEach(function (name) {
|
507 | var fn = assertSync[name];
|
508 | assert[name] = function _oneTest() {
|
509 | if (arguments.length === 0) return fn();
|
510 | var args = [].slice.call(arguments);
|
511 | var testee = args.pop();
|
512 | if (isPromiseAlike(testee)) {
|
513 | return testee.then(function (val) {
|
514 | return fn.apply(undefined, _toConsumableArray(args).concat([val]));
|
515 | });
|
516 | }
|
517 | return fn.apply(undefined, _toConsumableArray(args).concat([testee]));
|
518 | };
|
519 | });
|
520 | }
|
521 |
|
522 | module.exports = assert;
|
523 |
|
\ | No newline at end of file |