1// Originally from narwhal.js (http://narwhaljs.org) 2// Copyright (c) 2009 Thomas Robinson <280north.com> 3// 4// Permission is hereby granted, free of charge, to any person obtaining a copy 5// of this software and associated documentation files (the 'Software'), to 6// deal in the Software without restriction, including without limitation the 7// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8// sell copies of the Software, and to permit persons to whom the Software is 9// furnished to do so, subject to the following conditions: 10// 11// The above copyright notice and this permission notice shall be included in 12// all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 18// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 19// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21'use strict'; 22 23const { 24 Error, 25 ObjectAssign, 26 ObjectIs, 27 ObjectKeys, 28 ObjectPrototypeIsPrototypeOf, 29 Map, 30 RegExpPrototypeTest, 31} = primordials; 32 33const { Buffer } = require('buffer'); 34const { 35 codes: { 36 ERR_AMBIGUOUS_ARGUMENT, 37 ERR_INVALID_ARG_TYPE, 38 ERR_INVALID_ARG_VALUE, 39 ERR_INVALID_RETURN_VALUE, 40 ERR_MISSING_ARGS, 41 }, 42 overrideStackTrace, 43} = require('internal/errors'); 44const AssertionError = require('internal/assert/assertion_error'); 45const { openSync, closeSync, readSync } = require('fs'); 46const { inspect } = require('internal/util/inspect'); 47const { isPromise, isRegExp } = require('internal/util/types'); 48const { EOL } = require('internal/constants'); 49const { NativeModule } = require('internal/bootstrap/loaders'); 50 51const errorCache = new Map(); 52const CallTracker = require('internal/assert/calltracker'); 53 54let isDeepEqual; 55let isDeepStrictEqual; 56let parseExpressionAt; 57let findNodeAround; 58let decoder; 59 60function lazyLoadComparison() { 61 const comparison = require('internal/util/comparisons'); 62 isDeepEqual = comparison.isDeepEqual; 63 isDeepStrictEqual = comparison.isDeepStrictEqual; 64} 65 66// Escape control characters but not \n and \t to keep the line breaks and 67// indentation intact. 68// eslint-disable-next-line no-control-regex 69const escapeSequencesRegExp = /[\x00-\x08\x0b\x0c\x0e-\x1f]/g; 70const meta = [ 71 '\\u0000', '\\u0001', '\\u0002', '\\u0003', '\\u0004', 72 '\\u0005', '\\u0006', '\\u0007', '\\b', '', 73 '', '\\u000b', '\\f', '', '\\u000e', 74 '\\u000f', '\\u0010', '\\u0011', '\\u0012', '\\u0013', 75 '\\u0014', '\\u0015', '\\u0016', '\\u0017', '\\u0018', 76 '\\u0019', '\\u001a', '\\u001b', '\\u001c', '\\u001d', 77 '\\u001e', '\\u001f' 78]; 79 80const escapeFn = (str) => meta[str.charCodeAt(0)]; 81 82let warned = false; 83 84// The assert module provides functions that throw 85// AssertionError's when particular conditions are not met. The 86// assert module must conform to the following interface. 87 88const assert = module.exports = ok; 89 90const NO_EXCEPTION_SENTINEL = {}; 91 92// All of the following functions must throw an AssertionError 93// when a corresponding condition is not met, with a message that 94// may be undefined if not provided. All assertion methods provide 95// both the actual and expected values to the assertion error for 96// display purposes. 97 98function innerFail(obj) { 99 if (obj.message instanceof Error) throw obj.message; 100 101 throw new AssertionError(obj); 102} 103 104function fail(actual, expected, message, operator, stackStartFn) { 105 const argsLen = arguments.length; 106 107 let internalMessage = false; 108 if (actual == null && argsLen <= 1) { 109 internalMessage = true; 110 message = 'Failed'; 111 } else if (argsLen === 1) { 112 message = actual; 113 actual = undefined; 114 } else { 115 if (warned === false) { 116 warned = true; 117 process.emitWarning( 118 'assert.fail() with more than one argument is deprecated. ' + 119 'Please use assert.strictEqual() instead or only pass a message.', 120 'DeprecationWarning', 121 'DEP0094' 122 ); 123 } 124 if (argsLen === 2) 125 operator = '!='; 126 } 127 128 if (message instanceof Error) throw message; 129 130 const errArgs = { 131 actual, 132 expected, 133 operator: operator === undefined ? 'fail' : operator, 134 stackStartFn: stackStartFn || fail, 135 message 136 }; 137 const err = new AssertionError(errArgs); 138 if (internalMessage) { 139 err.generatedMessage = true; 140 } 141 throw err; 142} 143 144assert.fail = fail; 145 146// The AssertionError is defined in internal/error. 147assert.AssertionError = AssertionError; 148 149function findColumn(fd, column, code) { 150 if (code.length > column + 100) { 151 try { 152 return parseCode(code, column); 153 } catch { 154 // End recursion in case no code could be parsed. The expression should 155 // have been found after 2500 characters, so stop trying. 156 if (code.length - column > 2500) { 157 // eslint-disable-next-line no-throw-literal 158 throw null; 159 } 160 } 161 } 162 // Read up to 2500 bytes more than necessary in columns. That way we address 163 // multi byte characters and read enough data to parse the code. 164 const bytesToRead = column - code.length + 2500; 165 const buffer = Buffer.allocUnsafe(bytesToRead); 166 const bytesRead = readSync(fd, buffer, 0, bytesToRead); 167 code += decoder.write(buffer.slice(0, bytesRead)); 168 // EOF: fast path. 169 if (bytesRead < bytesToRead) { 170 return parseCode(code, column); 171 } 172 // Read potentially missing code. 173 return findColumn(fd, column, code); 174} 175 176function getCode(fd, line, column) { 177 let bytesRead = 0; 178 if (line === 0) { 179 // Special handle line number one. This is more efficient and simplifies the 180 // rest of the algorithm. Read more than the regular column number in bytes 181 // to prevent multiple reads in case multi byte characters are used. 182 return findColumn(fd, column, ''); 183 } 184 let lines = 0; 185 // Prevent blocking the event loop by limiting the maximum amount of 186 // data that may be read. 187 let maxReads = 32; // bytesPerRead * maxReads = 512 kb 188 const bytesPerRead = 16384; 189 // Use a single buffer up front that is reused until the call site is found. 190 let buffer = Buffer.allocUnsafe(bytesPerRead); 191 while (maxReads-- !== 0) { 192 // Only allocate a new buffer in case the needed line is found. All data 193 // before that can be discarded. 194 buffer = lines < line ? buffer : Buffer.allocUnsafe(bytesPerRead); 195 bytesRead = readSync(fd, buffer, 0, bytesPerRead); 196 // Read the buffer until the required code line is found. 197 for (let i = 0; i < bytesRead; i++) { 198 if (buffer[i] === 10 && ++lines === line) { 199 // If the end of file is reached, directly parse the code and return. 200 if (bytesRead < bytesPerRead) { 201 return parseCode(buffer.toString('utf8', i + 1, bytesRead), column); 202 } 203 // Check if the read code is sufficient or read more until the whole 204 // expression is read. Make sure multi byte characters are preserved 205 // properly by using the decoder. 206 const code = decoder.write(buffer.slice(i + 1, bytesRead)); 207 return findColumn(fd, column, code); 208 } 209 } 210 } 211} 212 213function parseCode(code, offset) { 214 // Lazy load acorn. 215 if (parseExpressionAt === undefined) { 216 const acorn = require('internal/deps/acorn/acorn/dist/acorn'); 217 const privateMethods = 218 require('internal/deps/acorn-plugins/acorn-private-methods/index'); 219 const classFields = 220 require('internal/deps/acorn-plugins/acorn-class-fields/index'); 221 const numericSeparator = 222 require('internal/deps/acorn-plugins/acorn-numeric-separator/index'); 223 const staticClassFeatures = 224 require('internal/deps/acorn-plugins/acorn-static-class-features/index'); 225 226 ({ findNodeAround } = require('internal/deps/acorn/acorn-walk/dist/walk')); 227 228 const Parser = acorn.Parser.extend( 229 privateMethods, 230 classFields, 231 numericSeparator, 232 staticClassFeatures 233 ); 234 parseExpressionAt = Parser.parseExpressionAt.bind(Parser); 235 } 236 let node; 237 let start = 0; 238 // Parse the read code until the correct expression is found. 239 do { 240 try { 241 node = parseExpressionAt(code, start, { ecmaVersion: 11 }); 242 start = node.end + 1 || start; 243 // Find the CallExpression in the tree. 244 node = findNodeAround(node, offset, 'CallExpression'); 245 } catch (err) { 246 // Unexpected token error and the like. 247 start += err.raisedAt || 1; 248 if (start > offset) { 249 // No matching expression found. This could happen if the assert 250 // expression is bigger than the provided buffer. 251 // eslint-disable-next-line no-throw-literal 252 throw null; 253 } 254 } 255 } while (node === undefined || node.node.end < offset); 256 257 return [ 258 node.node.start, 259 code.slice(node.node.start, node.node.end) 260 .replace(escapeSequencesRegExp, escapeFn) 261 ]; 262} 263 264function getErrMessage(message, fn) { 265 const tmpLimit = Error.stackTraceLimit; 266 // Make sure the limit is set to 1. Otherwise it could fail (<= 0) or it 267 // does to much work. 268 Error.stackTraceLimit = 1; 269 // We only need the stack trace. To minimize the overhead use an object 270 // instead of an error. 271 const err = {}; 272 // eslint-disable-next-line no-restricted-syntax 273 Error.captureStackTrace(err, fn); 274 Error.stackTraceLimit = tmpLimit; 275 276 overrideStackTrace.set(err, (_, stack) => stack); 277 const call = err.stack[0]; 278 279 const filename = call.getFileName(); 280 let line = call.getLineNumber() - 1; 281 let column = call.getColumnNumber() - 1; 282 let identifier; 283 let code; 284 285 if (filename) { 286 identifier = `${filename}${line}${column}`; 287 288 // Skip Node.js modules! 289 if (filename.endsWith('.js') && 290 NativeModule.exists(filename.slice(0, -3))) { 291 errorCache.set(identifier, undefined); 292 return; 293 } 294 } else { 295 const fn = call.getFunction(); 296 if (!fn) { 297 return message; 298 } 299 code = String(fn); 300 // For functions created with the Function constructor, V8 does not count 301 // the lines containing the function header. 302 line += 2; 303 identifier = `${code}${line}${column}`; 304 } 305 306 if (errorCache.has(identifier)) { 307 return errorCache.get(identifier); 308 } 309 310 let fd; 311 try { 312 // Set the stack trace limit to zero. This makes sure unexpected token 313 // errors are handled faster. 314 Error.stackTraceLimit = 0; 315 316 if (filename) { 317 if (decoder === undefined) { 318 const { StringDecoder } = require('string_decoder'); 319 decoder = new StringDecoder('utf8'); 320 } 321 fd = openSync(filename, 'r', 0o666); 322 // Reset column and message. 323 [column, message] = getCode(fd, line, column); 324 // Flush unfinished multi byte characters. 325 decoder.end(); 326 } else { 327 for (let i = 0; i < line; i++) { 328 code = code.slice(code.indexOf('\n') + 1); 329 } 330 [column, message] = parseCode(code, column); 331 } 332 // Always normalize indentation, otherwise the message could look weird. 333 if (message.includes('\n')) { 334 if (EOL === '\r\n') { 335 message = message.replace(/\r\n/g, '\n'); 336 } 337 const frames = message.split('\n'); 338 message = frames.shift(); 339 for (const frame of frames) { 340 let pos = 0; 341 while (pos < column && (frame[pos] === ' ' || frame[pos] === '\t')) { 342 pos++; 343 } 344 message += `\n ${frame.slice(pos)}`; 345 } 346 } 347 message = `The expression evaluated to a falsy value:\n\n ${message}\n`; 348 // Make sure to always set the cache! No matter if the message is 349 // undefined or not 350 errorCache.set(identifier, message); 351 352 return message; 353 } catch { 354 // Invalidate cache to prevent trying to read this part again. 355 errorCache.set(identifier, undefined); 356 } finally { 357 // Reset limit. 358 Error.stackTraceLimit = tmpLimit; 359 if (fd !== undefined) 360 closeSync(fd); 361 } 362} 363 364function innerOk(fn, argLen, value, message) { 365 if (!value) { 366 let generatedMessage = false; 367 368 if (argLen === 0) { 369 generatedMessage = true; 370 message = 'No value argument passed to `assert.ok()`'; 371 } else if (message == null) { 372 generatedMessage = true; 373 message = getErrMessage(message, fn); 374 } else if (message instanceof Error) { 375 throw message; 376 } 377 378 const err = new AssertionError({ 379 actual: value, 380 expected: true, 381 message, 382 operator: '==', 383 stackStartFn: fn 384 }); 385 err.generatedMessage = generatedMessage; 386 throw err; 387 } 388} 389 390// Pure assertion tests whether a value is truthy, as determined 391// by !!value. 392function ok(...args) { 393 innerOk(ok, args.length, ...args); 394} 395assert.ok = ok; 396 397// The equality assertion tests shallow, coercive equality with ==. 398/* eslint-disable no-restricted-properties */ 399assert.equal = function equal(actual, expected, message) { 400 if (arguments.length < 2) { 401 throw new ERR_MISSING_ARGS('actual', 'expected'); 402 } 403 // eslint-disable-next-line eqeqeq 404 if (actual != expected) { 405 innerFail({ 406 actual, 407 expected, 408 message, 409 operator: '==', 410 stackStartFn: equal 411 }); 412 } 413}; 414 415// The non-equality assertion tests for whether two objects are not 416// equal with !=. 417assert.notEqual = function notEqual(actual, expected, message) { 418 if (arguments.length < 2) { 419 throw new ERR_MISSING_ARGS('actual', 'expected'); 420 } 421 // eslint-disable-next-line eqeqeq 422 if (actual == expected) { 423 innerFail({ 424 actual, 425 expected, 426 message, 427 operator: '!=', 428 stackStartFn: notEqual 429 }); 430 } 431}; 432 433// The equivalence assertion tests a deep equality relation. 434assert.deepEqual = function deepEqual(actual, expected, message) { 435 if (arguments.length < 2) { 436 throw new ERR_MISSING_ARGS('actual', 'expected'); 437 } 438 if (isDeepEqual === undefined) lazyLoadComparison(); 439 if (!isDeepEqual(actual, expected)) { 440 innerFail({ 441 actual, 442 expected, 443 message, 444 operator: 'deepEqual', 445 stackStartFn: deepEqual 446 }); 447 } 448}; 449 450// The non-equivalence assertion tests for any deep inequality. 451assert.notDeepEqual = function notDeepEqual(actual, expected, message) { 452 if (arguments.length < 2) { 453 throw new ERR_MISSING_ARGS('actual', 'expected'); 454 } 455 if (isDeepEqual === undefined) lazyLoadComparison(); 456 if (isDeepEqual(actual, expected)) { 457 innerFail({ 458 actual, 459 expected, 460 message, 461 operator: 'notDeepEqual', 462 stackStartFn: notDeepEqual 463 }); 464 } 465}; 466/* eslint-enable */ 467 468assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) { 469 if (arguments.length < 2) { 470 throw new ERR_MISSING_ARGS('actual', 'expected'); 471 } 472 if (isDeepEqual === undefined) lazyLoadComparison(); 473 if (!isDeepStrictEqual(actual, expected)) { 474 innerFail({ 475 actual, 476 expected, 477 message, 478 operator: 'deepStrictEqual', 479 stackStartFn: deepStrictEqual 480 }); 481 } 482}; 483 484assert.notDeepStrictEqual = notDeepStrictEqual; 485function notDeepStrictEqual(actual, expected, message) { 486 if (arguments.length < 2) { 487 throw new ERR_MISSING_ARGS('actual', 'expected'); 488 } 489 if (isDeepEqual === undefined) lazyLoadComparison(); 490 if (isDeepStrictEqual(actual, expected)) { 491 innerFail({ 492 actual, 493 expected, 494 message, 495 operator: 'notDeepStrictEqual', 496 stackStartFn: notDeepStrictEqual 497 }); 498 } 499} 500 501assert.strictEqual = function strictEqual(actual, expected, message) { 502 if (arguments.length < 2) { 503 throw new ERR_MISSING_ARGS('actual', 'expected'); 504 } 505 if (!ObjectIs(actual, expected)) { 506 innerFail({ 507 actual, 508 expected, 509 message, 510 operator: 'strictEqual', 511 stackStartFn: strictEqual 512 }); 513 } 514}; 515 516assert.notStrictEqual = function notStrictEqual(actual, expected, message) { 517 if (arguments.length < 2) { 518 throw new ERR_MISSING_ARGS('actual', 'expected'); 519 } 520 if (ObjectIs(actual, expected)) { 521 innerFail({ 522 actual, 523 expected, 524 message, 525 operator: 'notStrictEqual', 526 stackStartFn: notStrictEqual 527 }); 528 } 529}; 530 531class Comparison { 532 constructor(obj, keys, actual) { 533 for (const key of keys) { 534 if (key in obj) { 535 if (actual !== undefined && 536 typeof actual[key] === 'string' && 537 isRegExp(obj[key]) && 538 RegExpPrototypeTest(obj[key], actual[key])) { 539 this[key] = actual[key]; 540 } else { 541 this[key] = obj[key]; 542 } 543 } 544 } 545 } 546} 547 548function compareExceptionKey(actual, expected, key, message, keys, fn) { 549 if (!(key in actual) || !isDeepStrictEqual(actual[key], expected[key])) { 550 if (!message) { 551 // Create placeholder objects to create a nice output. 552 const a = new Comparison(actual, keys); 553 const b = new Comparison(expected, keys, actual); 554 555 const err = new AssertionError({ 556 actual: a, 557 expected: b, 558 operator: 'deepStrictEqual', 559 stackStartFn: fn 560 }); 561 err.actual = actual; 562 err.expected = expected; 563 err.operator = fn.name; 564 throw err; 565 } 566 innerFail({ 567 actual, 568 expected, 569 message, 570 operator: fn.name, 571 stackStartFn: fn 572 }); 573 } 574} 575 576function expectedException(actual, expected, message, fn) { 577 let generatedMessage = false; 578 let throwError = false; 579 580 if (typeof expected !== 'function') { 581 // Handle regular expressions. 582 if (isRegExp(expected)) { 583 const str = String(actual); 584 if (RegExpPrototypeTest(expected, str)) 585 return; 586 587 if (!message) { 588 generatedMessage = true; 589 message = 'The input did not match the regular expression ' + 590 `${inspect(expected)}. Input:\n\n${inspect(str)}\n`; 591 } 592 throwError = true; 593 // Handle primitives properly. 594 } else if (typeof actual !== 'object' || actual === null) { 595 const err = new AssertionError({ 596 actual, 597 expected, 598 message, 599 operator: 'deepStrictEqual', 600 stackStartFn: fn 601 }); 602 err.operator = fn.name; 603 throw err; 604 } else { 605 // Handle validation objects. 606 const keys = ObjectKeys(expected); 607 // Special handle errors to make sure the name and the message are 608 // compared as well. 609 if (expected instanceof Error) { 610 keys.push('name', 'message'); 611 } else if (keys.length === 0) { 612 throw new ERR_INVALID_ARG_VALUE('error', 613 expected, 'may not be an empty object'); 614 } 615 if (isDeepEqual === undefined) lazyLoadComparison(); 616 for (const key of keys) { 617 if (typeof actual[key] === 'string' && 618 isRegExp(expected[key]) && 619 RegExpPrototypeTest(expected[key], actual[key])) { 620 continue; 621 } 622 compareExceptionKey(actual, expected, key, message, keys, fn); 623 } 624 return; 625 } 626 // Guard instanceof against arrow functions as they don't have a prototype. 627 // Check for matching Error classes. 628 } else if (expected.prototype !== undefined && actual instanceof expected) { 629 return; 630 } else if (ObjectPrototypeIsPrototypeOf(Error, expected)) { 631 throw actual; 632 } else { 633 // Check validation functions return value. 634 const res = expected.call({}, actual); 635 if (res !== true) { 636 throw actual; 637 } 638 } 639 640 if (throwError) { 641 const err = new AssertionError({ 642 actual, 643 expected, 644 message, 645 operator: fn.name, 646 stackStartFn: fn 647 }); 648 err.generatedMessage = generatedMessage; 649 throw err; 650 } 651} 652 653function getActual(fn) { 654 if (typeof fn !== 'function') { 655 throw new ERR_INVALID_ARG_TYPE('fn', 'Function', fn); 656 } 657 try { 658 fn(); 659 } catch (e) { 660 return e; 661 } 662 return NO_EXCEPTION_SENTINEL; 663} 664 665function checkIsPromise(obj) { 666 // Accept native ES6 promises and promises that are implemented in a similar 667 // way. Do not accept thenables that use a function as `obj` and that have no 668 // `catch` handler. 669 return isPromise(obj) || 670 (obj !== null && typeof obj === 'object' && 671 typeof obj.then === 'function' && 672 typeof obj.catch === 'function'); 673} 674 675async function waitForActual(promiseFn) { 676 let resultPromise; 677 if (typeof promiseFn === 'function') { 678 // Return a rejected promise if `promiseFn` throws synchronously. 679 resultPromise = promiseFn(); 680 // Fail in case no promise is returned. 681 if (!checkIsPromise(resultPromise)) { 682 throw new ERR_INVALID_RETURN_VALUE('instance of Promise', 683 'promiseFn', resultPromise); 684 } 685 } else if (checkIsPromise(promiseFn)) { 686 resultPromise = promiseFn; 687 } else { 688 throw new ERR_INVALID_ARG_TYPE( 689 'promiseFn', ['Function', 'Promise'], promiseFn); 690 } 691 692 try { 693 await resultPromise; 694 } catch (e) { 695 return e; 696 } 697 return NO_EXCEPTION_SENTINEL; 698} 699 700function expectsError(stackStartFn, actual, error, message) { 701 if (typeof error === 'string') { 702 if (arguments.length === 4) { 703 throw new ERR_INVALID_ARG_TYPE('error', 704 ['Object', 'Error', 'Function', 'RegExp'], 705 error); 706 } 707 if (typeof actual === 'object' && actual !== null) { 708 if (actual.message === error) { 709 throw new ERR_AMBIGUOUS_ARGUMENT( 710 'error/message', 711 `The error message "${actual.message}" is identical to the message.` 712 ); 713 } 714 } else if (actual === error) { 715 throw new ERR_AMBIGUOUS_ARGUMENT( 716 'error/message', 717 `The error "${actual}" is identical to the message.` 718 ); 719 } 720 message = error; 721 error = undefined; 722 } else if (error != null && 723 typeof error !== 'object' && 724 typeof error !== 'function') { 725 throw new ERR_INVALID_ARG_TYPE('error', 726 ['Object', 'Error', 'Function', 'RegExp'], 727 error); 728 } 729 730 if (actual === NO_EXCEPTION_SENTINEL) { 731 let details = ''; 732 if (error && error.name) { 733 details += ` (${error.name})`; 734 } 735 details += message ? `: ${message}` : '.'; 736 const fnType = stackStartFn.name === 'rejects' ? 'rejection' : 'exception'; 737 innerFail({ 738 actual: undefined, 739 expected: error, 740 operator: stackStartFn.name, 741 message: `Missing expected ${fnType}${details}`, 742 stackStartFn 743 }); 744 } 745 746 if (!error) 747 return; 748 749 expectedException(actual, error, message, stackStartFn); 750} 751 752function hasMatchingError(actual, expected) { 753 if (typeof expected !== 'function') { 754 if (isRegExp(expected)) { 755 const str = String(actual); 756 return RegExpPrototypeTest(expected, str); 757 } 758 throw new ERR_INVALID_ARG_TYPE( 759 'expected', ['Function', 'RegExp'], expected 760 ); 761 } 762 // Guard instanceof against arrow functions as they don't have a prototype. 763 if (expected.prototype !== undefined && actual instanceof expected) { 764 return true; 765 } 766 if (Error.isPrototypeOf(expected)) { 767 return false; 768 } 769 return expected.call({}, actual) === true; 770} 771 772function expectsNoError(stackStartFn, actual, error, message) { 773 if (actual === NO_EXCEPTION_SENTINEL) 774 return; 775 776 if (typeof error === 'string') { 777 message = error; 778 error = undefined; 779 } 780 781 if (!error || hasMatchingError(actual, error)) { 782 const details = message ? `: ${message}` : '.'; 783 const fnType = stackStartFn.name === 'doesNotReject' ? 784 'rejection' : 'exception'; 785 innerFail({ 786 actual, 787 expected: error, 788 operator: stackStartFn.name, 789 message: `Got unwanted ${fnType}${details}\n` + 790 `Actual message: "${actual && actual.message}"`, 791 stackStartFn 792 }); 793 } 794 throw actual; 795} 796 797assert.throws = function throws(promiseFn, ...args) { 798 expectsError(throws, getActual(promiseFn), ...args); 799}; 800 801assert.rejects = async function rejects(promiseFn, ...args) { 802 expectsError(rejects, await waitForActual(promiseFn), ...args); 803}; 804 805assert.doesNotThrow = function doesNotThrow(fn, ...args) { 806 expectsNoError(doesNotThrow, getActual(fn), ...args); 807}; 808 809assert.doesNotReject = async function doesNotReject(fn, ...args) { 810 expectsNoError(doesNotReject, await waitForActual(fn), ...args); 811}; 812 813assert.ifError = function ifError(err) { 814 if (err !== null && err !== undefined) { 815 let message = 'ifError got unwanted exception: '; 816 if (typeof err === 'object' && typeof err.message === 'string') { 817 if (err.message.length === 0 && err.constructor) { 818 message += err.constructor.name; 819 } else { 820 message += err.message; 821 } 822 } else { 823 message += inspect(err); 824 } 825 826 const newErr = new AssertionError({ 827 actual: err, 828 expected: null, 829 operator: 'ifError', 830 message, 831 stackStartFn: ifError 832 }); 833 834 // Make sure we actually have a stack trace! 835 const origStack = err.stack; 836 837 if (typeof origStack === 'string') { 838 // This will remove any duplicated frames from the error frames taken 839 // from within `ifError` and add the original error frames to the newly 840 // created ones. 841 const tmp2 = origStack.split('\n'); 842 tmp2.shift(); 843 // Filter all frames existing in err.stack. 844 let tmp1 = newErr.stack.split('\n'); 845 for (const errFrame of tmp2) { 846 // Find the first occurrence of the frame. 847 const pos = tmp1.indexOf(errFrame); 848 if (pos !== -1) { 849 // Only keep new frames. 850 tmp1 = tmp1.slice(0, pos); 851 break; 852 } 853 } 854 newErr.stack = `${tmp1.join('\n')}\n${tmp2.join('\n')}`; 855 } 856 857 throw newErr; 858 } 859}; 860 861function internalMatch(string, regexp, message, fn) { 862 if (!isRegExp(regexp)) { 863 throw new ERR_INVALID_ARG_TYPE( 864 'regexp', 'RegExp', regexp 865 ); 866 } 867 const match = fn.name === 'match'; 868 if (typeof string !== 'string' || 869 RegExpPrototypeTest(regexp, string) !== match) { 870 if (message instanceof Error) { 871 throw message; 872 } 873 874 const generatedMessage = !message; 875 876 // 'The input was expected to not match the regular expression ' + 877 message = message || (typeof string !== 'string' ? 878 'The "string" argument must be of type string. Received type ' + 879 `${typeof string} (${inspect(string)})` : 880 (match ? 881 'The input did not match the regular expression ' : 882 'The input was expected to not match the regular expression ') + 883 `${inspect(regexp)}. Input:\n\n${inspect(string)}\n`); 884 const err = new AssertionError({ 885 actual: string, 886 expected: regexp, 887 message, 888 operator: fn.name, 889 stackStartFn: fn 890 }); 891 err.generatedMessage = generatedMessage; 892 throw err; 893 } 894} 895 896assert.match = function match(string, regexp, message) { 897 internalMatch(string, regexp, message, match); 898}; 899 900assert.doesNotMatch = function doesNotMatch(string, regexp, message) { 901 internalMatch(string, regexp, message, doesNotMatch); 902}; 903 904assert.CallTracker = CallTracker; 905 906// Expose a strict only variant of assert 907function strict(...args) { 908 innerOk(strict, args.length, ...args); 909} 910assert.strict = ObjectAssign(strict, assert, { 911 equal: assert.strictEqual, 912 deepEqual: assert.deepStrictEqual, 913 notEqual: assert.notStrictEqual, 914 notDeepEqual: assert.notDeepStrictEqual 915}); 916assert.strict.strict = assert.strict; 917