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