assert.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. // Currently in sync with Node.js lib/assert.js
  2. // https://github.com/nodejs/node/commit/2a51ae424a513ec9a6aa3466baa0cc1d55dd4f3b
  3. // Originally from narwhal.js (http://narwhaljs.org)
  4. // Copyright (c) 2009 Thomas Robinson <280north.com>
  5. //
  6. // Permission is hereby granted, free of charge, to any person obtaining a copy
  7. // of this software and associated documentation files (the 'Software'), to
  8. // deal in the Software without restriction, including without limitation the
  9. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10. // sell copies of the Software, and to permit persons to whom the Software is
  11. // furnished to do so, subject to the following conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be included in
  14. // all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  20. // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. 'use strict';
  23. function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  24. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  25. var _require = require('./internal/errors'),
  26. _require$codes = _require.codes,
  27. ERR_AMBIGUOUS_ARGUMENT = _require$codes.ERR_AMBIGUOUS_ARGUMENT,
  28. ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE,
  29. ERR_INVALID_ARG_VALUE = _require$codes.ERR_INVALID_ARG_VALUE,
  30. ERR_INVALID_RETURN_VALUE = _require$codes.ERR_INVALID_RETURN_VALUE,
  31. ERR_MISSING_ARGS = _require$codes.ERR_MISSING_ARGS;
  32. var AssertionError = require('./internal/assert/assertion_error');
  33. var _require2 = require('util/'),
  34. inspect = _require2.inspect;
  35. var _require$types = require('util/').types,
  36. isPromise = _require$types.isPromise,
  37. isRegExp = _require$types.isRegExp;
  38. var objectAssign = Object.assign ? Object.assign : require('es6-object-assign').assign;
  39. var objectIs = Object.is ? Object.is : require('object-is');
  40. var errorCache = new Map();
  41. var isDeepEqual;
  42. var isDeepStrictEqual;
  43. var parseExpressionAt;
  44. var findNodeAround;
  45. var decoder;
  46. function lazyLoadComparison() {
  47. var comparison = require('./internal/util/comparisons');
  48. isDeepEqual = comparison.isDeepEqual;
  49. isDeepStrictEqual = comparison.isDeepStrictEqual;
  50. } // Escape control characters but not \n and \t to keep the line breaks and
  51. // indentation intact.
  52. // eslint-disable-next-line no-control-regex
  53. var escapeSequencesRegExp = /[\x00-\x08\x0b\x0c\x0e-\x1f]/g;
  54. var meta = ["\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005", "\\u0006", "\\u0007", '\\b', '', '', "\\u000b", '\\f', '', "\\u000e", "\\u000f", "\\u0010", "\\u0011", "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f"];
  55. var escapeFn = function escapeFn(str) {
  56. return meta[str.charCodeAt(0)];
  57. };
  58. var warned = false; // The assert module provides functions that throw
  59. // AssertionError's when particular conditions are not met. The
  60. // assert module must conform to the following interface.
  61. var assert = module.exports = ok;
  62. var NO_EXCEPTION_SENTINEL = {}; // All of the following functions must throw an AssertionError
  63. // when a corresponding condition is not met, with a message that
  64. // may be undefined if not provided. All assertion methods provide
  65. // both the actual and expected values to the assertion error for
  66. // display purposes.
  67. function innerFail(obj) {
  68. if (obj.message instanceof Error) throw obj.message;
  69. throw new AssertionError(obj);
  70. }
  71. function fail(actual, expected, message, operator, stackStartFn) {
  72. var argsLen = arguments.length;
  73. var internalMessage;
  74. if (argsLen === 0) {
  75. internalMessage = 'Failed';
  76. } else if (argsLen === 1) {
  77. message = actual;
  78. actual = undefined;
  79. } else {
  80. if (warned === false) {
  81. warned = true;
  82. var warn = process.emitWarning ? process.emitWarning : console.warn.bind(console);
  83. warn('assert.fail() with more than one argument is deprecated. ' + 'Please use assert.strictEqual() instead or only pass a message.', 'DeprecationWarning', 'DEP0094');
  84. }
  85. if (argsLen === 2) operator = '!=';
  86. }
  87. if (message instanceof Error) throw message;
  88. var errArgs = {
  89. actual: actual,
  90. expected: expected,
  91. operator: operator === undefined ? 'fail' : operator,
  92. stackStartFn: stackStartFn || fail
  93. };
  94. if (message !== undefined) {
  95. errArgs.message = message;
  96. }
  97. var err = new AssertionError(errArgs);
  98. if (internalMessage) {
  99. err.message = internalMessage;
  100. err.generatedMessage = true;
  101. }
  102. throw err;
  103. }
  104. assert.fail = fail; // The AssertionError is defined in internal/error.
  105. assert.AssertionError = AssertionError;
  106. function innerOk(fn, argLen, value, message) {
  107. if (!value) {
  108. var generatedMessage = false;
  109. if (argLen === 0) {
  110. generatedMessage = true;
  111. message = 'No value argument passed to `assert.ok()`';
  112. } else if (message instanceof Error) {
  113. throw message;
  114. }
  115. var err = new AssertionError({
  116. actual: value,
  117. expected: true,
  118. message: message,
  119. operator: '==',
  120. stackStartFn: fn
  121. });
  122. err.generatedMessage = generatedMessage;
  123. throw err;
  124. }
  125. } // Pure assertion tests whether a value is truthy, as determined
  126. // by !!value.
  127. function ok() {
  128. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  129. args[_key] = arguments[_key];
  130. }
  131. innerOk.apply(void 0, [ok, args.length].concat(args));
  132. }
  133. assert.ok = ok; // The equality assertion tests shallow, coercive equality with ==.
  134. /* eslint-disable no-restricted-properties */
  135. assert.equal = function equal(actual, expected, message) {
  136. if (arguments.length < 2) {
  137. throw new ERR_MISSING_ARGS('actual', 'expected');
  138. } // eslint-disable-next-line eqeqeq
  139. if (actual != expected) {
  140. innerFail({
  141. actual: actual,
  142. expected: expected,
  143. message: message,
  144. operator: '==',
  145. stackStartFn: equal
  146. });
  147. }
  148. }; // The non-equality assertion tests for whether two objects are not
  149. // equal with !=.
  150. assert.notEqual = function notEqual(actual, expected, message) {
  151. if (arguments.length < 2) {
  152. throw new ERR_MISSING_ARGS('actual', 'expected');
  153. } // eslint-disable-next-line eqeqeq
  154. if (actual == expected) {
  155. innerFail({
  156. actual: actual,
  157. expected: expected,
  158. message: message,
  159. operator: '!=',
  160. stackStartFn: notEqual
  161. });
  162. }
  163. }; // The equivalence assertion tests a deep equality relation.
  164. assert.deepEqual = function deepEqual(actual, expected, message) {
  165. if (arguments.length < 2) {
  166. throw new ERR_MISSING_ARGS('actual', 'expected');
  167. }
  168. if (isDeepEqual === undefined) lazyLoadComparison();
  169. if (!isDeepEqual(actual, expected)) {
  170. innerFail({
  171. actual: actual,
  172. expected: expected,
  173. message: message,
  174. operator: 'deepEqual',
  175. stackStartFn: deepEqual
  176. });
  177. }
  178. }; // The non-equivalence assertion tests for any deep inequality.
  179. assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
  180. if (arguments.length < 2) {
  181. throw new ERR_MISSING_ARGS('actual', 'expected');
  182. }
  183. if (isDeepEqual === undefined) lazyLoadComparison();
  184. if (isDeepEqual(actual, expected)) {
  185. innerFail({
  186. actual: actual,
  187. expected: expected,
  188. message: message,
  189. operator: 'notDeepEqual',
  190. stackStartFn: notDeepEqual
  191. });
  192. }
  193. };
  194. /* eslint-enable */
  195. assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) {
  196. if (arguments.length < 2) {
  197. throw new ERR_MISSING_ARGS('actual', 'expected');
  198. }
  199. if (isDeepEqual === undefined) lazyLoadComparison();
  200. if (!isDeepStrictEqual(actual, expected)) {
  201. innerFail({
  202. actual: actual,
  203. expected: expected,
  204. message: message,
  205. operator: 'deepStrictEqual',
  206. stackStartFn: deepStrictEqual
  207. });
  208. }
  209. };
  210. assert.notDeepStrictEqual = notDeepStrictEqual;
  211. function notDeepStrictEqual(actual, expected, message) {
  212. if (arguments.length < 2) {
  213. throw new ERR_MISSING_ARGS('actual', 'expected');
  214. }
  215. if (isDeepEqual === undefined) lazyLoadComparison();
  216. if (isDeepStrictEqual(actual, expected)) {
  217. innerFail({
  218. actual: actual,
  219. expected: expected,
  220. message: message,
  221. operator: 'notDeepStrictEqual',
  222. stackStartFn: notDeepStrictEqual
  223. });
  224. }
  225. }
  226. assert.strictEqual = function strictEqual(actual, expected, message) {
  227. if (arguments.length < 2) {
  228. throw new ERR_MISSING_ARGS('actual', 'expected');
  229. }
  230. if (!objectIs(actual, expected)) {
  231. innerFail({
  232. actual: actual,
  233. expected: expected,
  234. message: message,
  235. operator: 'strictEqual',
  236. stackStartFn: strictEqual
  237. });
  238. }
  239. };
  240. assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
  241. if (arguments.length < 2) {
  242. throw new ERR_MISSING_ARGS('actual', 'expected');
  243. }
  244. if (objectIs(actual, expected)) {
  245. innerFail({
  246. actual: actual,
  247. expected: expected,
  248. message: message,
  249. operator: 'notStrictEqual',
  250. stackStartFn: notStrictEqual
  251. });
  252. }
  253. };
  254. var Comparison = function Comparison(obj, keys, actual) {
  255. var _this = this;
  256. _classCallCheck(this, Comparison);
  257. keys.forEach(function (key) {
  258. if (key in obj) {
  259. if (actual !== undefined && typeof actual[key] === 'string' && isRegExp(obj[key]) && obj[key].test(actual[key])) {
  260. _this[key] = actual[key];
  261. } else {
  262. _this[key] = obj[key];
  263. }
  264. }
  265. });
  266. };
  267. function compareExceptionKey(actual, expected, key, message, keys, fn) {
  268. if (!(key in actual) || !isDeepStrictEqual(actual[key], expected[key])) {
  269. if (!message) {
  270. // Create placeholder objects to create a nice output.
  271. var a = new Comparison(actual, keys);
  272. var b = new Comparison(expected, keys, actual);
  273. var err = new AssertionError({
  274. actual: a,
  275. expected: b,
  276. operator: 'deepStrictEqual',
  277. stackStartFn: fn
  278. });
  279. err.actual = actual;
  280. err.expected = expected;
  281. err.operator = fn.name;
  282. throw err;
  283. }
  284. innerFail({
  285. actual: actual,
  286. expected: expected,
  287. message: message,
  288. operator: fn.name,
  289. stackStartFn: fn
  290. });
  291. }
  292. }
  293. function expectedException(actual, expected, msg, fn) {
  294. if (typeof expected !== 'function') {
  295. if (isRegExp(expected)) return expected.test(actual); // assert.doesNotThrow does not accept objects.
  296. if (arguments.length === 2) {
  297. throw new ERR_INVALID_ARG_TYPE('expected', ['Function', 'RegExp'], expected);
  298. } // Handle primitives properly.
  299. if (_typeof(actual) !== 'object' || actual === null) {
  300. var err = new AssertionError({
  301. actual: actual,
  302. expected: expected,
  303. message: msg,
  304. operator: 'deepStrictEqual',
  305. stackStartFn: fn
  306. });
  307. err.operator = fn.name;
  308. throw err;
  309. }
  310. var keys = Object.keys(expected); // Special handle errors to make sure the name and the message are compared
  311. // as well.
  312. if (expected instanceof Error) {
  313. keys.push('name', 'message');
  314. } else if (keys.length === 0) {
  315. throw new ERR_INVALID_ARG_VALUE('error', expected, 'may not be an empty object');
  316. }
  317. if (isDeepEqual === undefined) lazyLoadComparison();
  318. keys.forEach(function (key) {
  319. if (typeof actual[key] === 'string' && isRegExp(expected[key]) && expected[key].test(actual[key])) {
  320. return;
  321. }
  322. compareExceptionKey(actual, expected, key, msg, keys, fn);
  323. });
  324. return true;
  325. } // Guard instanceof against arrow functions as they don't have a prototype.
  326. if (expected.prototype !== undefined && actual instanceof expected) {
  327. return true;
  328. }
  329. if (Error.isPrototypeOf(expected)) {
  330. return false;
  331. }
  332. return expected.call({}, actual) === true;
  333. }
  334. function getActual(fn) {
  335. if (typeof fn !== 'function') {
  336. throw new ERR_INVALID_ARG_TYPE('fn', 'Function', fn);
  337. }
  338. try {
  339. fn();
  340. } catch (e) {
  341. return e;
  342. }
  343. return NO_EXCEPTION_SENTINEL;
  344. }
  345. function checkIsPromise(obj) {
  346. // Accept native ES6 promises and promises that are implemented in a similar
  347. // way. Do not accept thenables that use a function as `obj` and that have no
  348. // `catch` handler.
  349. // TODO: thenables are checked up until they have the correct methods,
  350. // but according to documentation, the `then` method should receive
  351. // the `fulfill` and `reject` arguments as well or it may be never resolved.
  352. return isPromise(obj) || obj !== null && _typeof(obj) === 'object' && typeof obj.then === 'function' && typeof obj.catch === 'function';
  353. }
  354. function waitForActual(promiseFn) {
  355. return Promise.resolve().then(function () {
  356. var resultPromise;
  357. if (typeof promiseFn === 'function') {
  358. // Return a rejected promise if `promiseFn` throws synchronously.
  359. resultPromise = promiseFn(); // Fail in case no promise is returned.
  360. if (!checkIsPromise(resultPromise)) {
  361. throw new ERR_INVALID_RETURN_VALUE('instance of Promise', 'promiseFn', resultPromise);
  362. }
  363. } else if (checkIsPromise(promiseFn)) {
  364. resultPromise = promiseFn;
  365. } else {
  366. throw new ERR_INVALID_ARG_TYPE('promiseFn', ['Function', 'Promise'], promiseFn);
  367. }
  368. return Promise.resolve().then(function () {
  369. return resultPromise;
  370. }).then(function () {
  371. return NO_EXCEPTION_SENTINEL;
  372. }).catch(function (e) {
  373. return e;
  374. });
  375. });
  376. }
  377. function expectsError(stackStartFn, actual, error, message) {
  378. if (typeof error === 'string') {
  379. if (arguments.length === 4) {
  380. throw new ERR_INVALID_ARG_TYPE('error', ['Object', 'Error', 'Function', 'RegExp'], error);
  381. }
  382. if (_typeof(actual) === 'object' && actual !== null) {
  383. if (actual.message === error) {
  384. throw new ERR_AMBIGUOUS_ARGUMENT('error/message', "The error message \"".concat(actual.message, "\" is identical to the message."));
  385. }
  386. } else if (actual === error) {
  387. throw new ERR_AMBIGUOUS_ARGUMENT('error/message', "The error \"".concat(actual, "\" is identical to the message."));
  388. }
  389. message = error;
  390. error = undefined;
  391. } else if (error != null && _typeof(error) !== 'object' && typeof error !== 'function') {
  392. throw new ERR_INVALID_ARG_TYPE('error', ['Object', 'Error', 'Function', 'RegExp'], error);
  393. }
  394. if (actual === NO_EXCEPTION_SENTINEL) {
  395. var details = '';
  396. if (error && error.name) {
  397. details += " (".concat(error.name, ")");
  398. }
  399. details += message ? ": ".concat(message) : '.';
  400. var fnType = stackStartFn.name === 'rejects' ? 'rejection' : 'exception';
  401. innerFail({
  402. actual: undefined,
  403. expected: error,
  404. operator: stackStartFn.name,
  405. message: "Missing expected ".concat(fnType).concat(details),
  406. stackStartFn: stackStartFn
  407. });
  408. }
  409. if (error && !expectedException(actual, error, message, stackStartFn)) {
  410. throw actual;
  411. }
  412. }
  413. function expectsNoError(stackStartFn, actual, error, message) {
  414. if (actual === NO_EXCEPTION_SENTINEL) return;
  415. if (typeof error === 'string') {
  416. message = error;
  417. error = undefined;
  418. }
  419. if (!error || expectedException(actual, error)) {
  420. var details = message ? ": ".concat(message) : '.';
  421. var fnType = stackStartFn.name === 'doesNotReject' ? 'rejection' : 'exception';
  422. innerFail({
  423. actual: actual,
  424. expected: error,
  425. operator: stackStartFn.name,
  426. message: "Got unwanted ".concat(fnType).concat(details, "\n") + "Actual message: \"".concat(actual && actual.message, "\""),
  427. stackStartFn: stackStartFn
  428. });
  429. }
  430. throw actual;
  431. }
  432. assert.throws = function throws(promiseFn) {
  433. for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
  434. args[_key2 - 1] = arguments[_key2];
  435. }
  436. expectsError.apply(void 0, [throws, getActual(promiseFn)].concat(args));
  437. };
  438. assert.rejects = function rejects(promiseFn) {
  439. for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
  440. args[_key3 - 1] = arguments[_key3];
  441. }
  442. return waitForActual(promiseFn).then(function (result) {
  443. return expectsError.apply(void 0, [rejects, result].concat(args));
  444. });
  445. };
  446. assert.doesNotThrow = function doesNotThrow(fn) {
  447. for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
  448. args[_key4 - 1] = arguments[_key4];
  449. }
  450. expectsNoError.apply(void 0, [doesNotThrow, getActual(fn)].concat(args));
  451. };
  452. assert.doesNotReject = function doesNotReject(fn) {
  453. for (var _len5 = arguments.length, args = new Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) {
  454. args[_key5 - 1] = arguments[_key5];
  455. }
  456. return waitForActual(fn).then(function (result) {
  457. return expectsNoError.apply(void 0, [doesNotReject, result].concat(args));
  458. });
  459. };
  460. assert.ifError = function ifError(err) {
  461. if (err !== null && err !== undefined) {
  462. var message = 'ifError got unwanted exception: ';
  463. if (_typeof(err) === 'object' && typeof err.message === 'string') {
  464. if (err.message.length === 0 && err.constructor) {
  465. message += err.constructor.name;
  466. } else {
  467. message += err.message;
  468. }
  469. } else {
  470. message += inspect(err);
  471. }
  472. var newErr = new AssertionError({
  473. actual: err,
  474. expected: null,
  475. operator: 'ifError',
  476. message: message,
  477. stackStartFn: ifError
  478. }); // Make sure we actually have a stack trace!
  479. var origStack = err.stack;
  480. if (typeof origStack === 'string') {
  481. // This will remove any duplicated frames from the error frames taken
  482. // from within `ifError` and add the original error frames to the newly
  483. // created ones.
  484. var tmp2 = origStack.split('\n');
  485. tmp2.shift(); // Filter all frames existing in err.stack.
  486. var tmp1 = newErr.stack.split('\n');
  487. for (var i = 0; i < tmp2.length; i++) {
  488. // Find the first occurrence of the frame.
  489. var pos = tmp1.indexOf(tmp2[i]);
  490. if (pos !== -1) {
  491. // Only keep new frames.
  492. tmp1 = tmp1.slice(0, pos);
  493. break;
  494. }
  495. }
  496. newErr.stack = "".concat(tmp1.join('\n'), "\n").concat(tmp2.join('\n'));
  497. }
  498. throw newErr;
  499. }
  500. }; // Expose a strict only variant of assert
  501. function strict() {
  502. for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) {
  503. args[_key6] = arguments[_key6];
  504. }
  505. innerOk.apply(void 0, [strict, args.length].concat(args));
  506. }
  507. assert.strict = objectAssign(strict, assert, {
  508. equal: assert.strictEqual,
  509. deepEqual: assert.deepStrictEqual,
  510. notEqual: assert.notStrictEqual,
  511. notDeepEqual: assert.notDeepStrictEqual
  512. });
  513. assert.strict.strict = assert.strict;