11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst { 41cb0ef41Sopenharmony_ci ArrayPrototypeJoin, 51cb0ef41Sopenharmony_ci ArrayPrototypePop, 61cb0ef41Sopenharmony_ci Error, 71cb0ef41Sopenharmony_ci ErrorCaptureStackTrace, 81cb0ef41Sopenharmony_ci MathMax, 91cb0ef41Sopenharmony_ci ObjectCreate, 101cb0ef41Sopenharmony_ci ObjectDefineProperty, 111cb0ef41Sopenharmony_ci ObjectGetPrototypeOf, 121cb0ef41Sopenharmony_ci ObjectKeys, 131cb0ef41Sopenharmony_ci String, 141cb0ef41Sopenharmony_ci StringPrototypeEndsWith, 151cb0ef41Sopenharmony_ci StringPrototypeRepeat, 161cb0ef41Sopenharmony_ci StringPrototypeSlice, 171cb0ef41Sopenharmony_ci StringPrototypeSplit, 181cb0ef41Sopenharmony_ci} = primordials; 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ciconst { inspect } = require('internal/util/inspect'); 211cb0ef41Sopenharmony_ciconst { 221cb0ef41Sopenharmony_ci removeColors, 231cb0ef41Sopenharmony_ci} = require('internal/util'); 241cb0ef41Sopenharmony_ciconst colors = require('internal/util/colors'); 251cb0ef41Sopenharmony_ciconst { 261cb0ef41Sopenharmony_ci validateObject, 271cb0ef41Sopenharmony_ci} = require('internal/validators'); 281cb0ef41Sopenharmony_ciconst { isErrorStackTraceLimitWritable } = require('internal/errors'); 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ciconst kReadableOperator = { 321cb0ef41Sopenharmony_ci deepStrictEqual: 'Expected values to be strictly deep-equal:', 331cb0ef41Sopenharmony_ci strictEqual: 'Expected values to be strictly equal:', 341cb0ef41Sopenharmony_ci strictEqualObject: 'Expected "actual" to be reference-equal to "expected":', 351cb0ef41Sopenharmony_ci deepEqual: 'Expected values to be loosely deep-equal:', 361cb0ef41Sopenharmony_ci notDeepStrictEqual: 'Expected "actual" not to be strictly deep-equal to:', 371cb0ef41Sopenharmony_ci notStrictEqual: 'Expected "actual" to be strictly unequal to:', 381cb0ef41Sopenharmony_ci notStrictEqualObject: 391cb0ef41Sopenharmony_ci 'Expected "actual" not to be reference-equal to "expected":', 401cb0ef41Sopenharmony_ci notDeepEqual: 'Expected "actual" not to be loosely deep-equal to:', 411cb0ef41Sopenharmony_ci notIdentical: 'Values have same structure but are not reference-equal:', 421cb0ef41Sopenharmony_ci notDeepEqualUnequal: 'Expected values not to be loosely deep-equal:', 431cb0ef41Sopenharmony_ci}; 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ci// Comparing short primitives should just show === / !== instead of using the 461cb0ef41Sopenharmony_ci// diff. 471cb0ef41Sopenharmony_ciconst kMaxShortLength = 12; 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_cifunction copyError(source) { 501cb0ef41Sopenharmony_ci const keys = ObjectKeys(source); 511cb0ef41Sopenharmony_ci const target = ObjectCreate(ObjectGetPrototypeOf(source)); 521cb0ef41Sopenharmony_ci for (const key of keys) { 531cb0ef41Sopenharmony_ci target[key] = source[key]; 541cb0ef41Sopenharmony_ci } 551cb0ef41Sopenharmony_ci ObjectDefineProperty(target, 'message', { __proto__: null, value: source.message }); 561cb0ef41Sopenharmony_ci return target; 571cb0ef41Sopenharmony_ci} 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_cifunction inspectValue(val) { 601cb0ef41Sopenharmony_ci // The util.inspect default values could be changed. This makes sure the 611cb0ef41Sopenharmony_ci // error messages contain the necessary information nevertheless. 621cb0ef41Sopenharmony_ci return inspect( 631cb0ef41Sopenharmony_ci val, 641cb0ef41Sopenharmony_ci { 651cb0ef41Sopenharmony_ci compact: false, 661cb0ef41Sopenharmony_ci customInspect: false, 671cb0ef41Sopenharmony_ci depth: 1000, 681cb0ef41Sopenharmony_ci maxArrayLength: Infinity, 691cb0ef41Sopenharmony_ci // Assert compares only enumerable properties (with a few exceptions). 701cb0ef41Sopenharmony_ci showHidden: false, 711cb0ef41Sopenharmony_ci // Assert does not detect proxies currently. 721cb0ef41Sopenharmony_ci showProxy: false, 731cb0ef41Sopenharmony_ci sorted: true, 741cb0ef41Sopenharmony_ci // Inspect getters as we also check them when comparing entries. 751cb0ef41Sopenharmony_ci getters: true, 761cb0ef41Sopenharmony_ci }, 771cb0ef41Sopenharmony_ci ); 781cb0ef41Sopenharmony_ci} 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_cifunction createErrDiff(actual, expected, operator) { 811cb0ef41Sopenharmony_ci let other = ''; 821cb0ef41Sopenharmony_ci let res = ''; 831cb0ef41Sopenharmony_ci let end = ''; 841cb0ef41Sopenharmony_ci let skipped = false; 851cb0ef41Sopenharmony_ci const actualInspected = inspectValue(actual); 861cb0ef41Sopenharmony_ci const actualLines = StringPrototypeSplit(actualInspected, '\n'); 871cb0ef41Sopenharmony_ci const expectedLines = StringPrototypeSplit(inspectValue(expected), '\n'); 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci let i = 0; 901cb0ef41Sopenharmony_ci let indicator = ''; 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci // In case both values are objects or functions explicitly mark them as not 931cb0ef41Sopenharmony_ci // reference equal for the `strictEqual` operator. 941cb0ef41Sopenharmony_ci if (operator === 'strictEqual' && 951cb0ef41Sopenharmony_ci ((typeof actual === 'object' && actual !== null && 961cb0ef41Sopenharmony_ci typeof expected === 'object' && expected !== null) || 971cb0ef41Sopenharmony_ci (typeof actual === 'function' && typeof expected === 'function'))) { 981cb0ef41Sopenharmony_ci operator = 'strictEqualObject'; 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci // If "actual" and "expected" fit on a single line and they are not strictly 1021cb0ef41Sopenharmony_ci // equal, check further special handling. 1031cb0ef41Sopenharmony_ci if (actualLines.length === 1 && expectedLines.length === 1 && 1041cb0ef41Sopenharmony_ci actualLines[0] !== expectedLines[0]) { 1051cb0ef41Sopenharmony_ci // Check for the visible length using the `removeColors()` function, if 1061cb0ef41Sopenharmony_ci // appropriate. 1071cb0ef41Sopenharmony_ci const c = inspect.defaultOptions.colors; 1081cb0ef41Sopenharmony_ci const actualRaw = c ? removeColors(actualLines[0]) : actualLines[0]; 1091cb0ef41Sopenharmony_ci const expectedRaw = c ? removeColors(expectedLines[0]) : expectedLines[0]; 1101cb0ef41Sopenharmony_ci const inputLength = actualRaw.length + expectedRaw.length; 1111cb0ef41Sopenharmony_ci // If the character length of "actual" and "expected" together is less than 1121cb0ef41Sopenharmony_ci // kMaxShortLength and if neither is an object and at least one of them is 1131cb0ef41Sopenharmony_ci // not `zero`, use the strict equal comparison to visualize the output. 1141cb0ef41Sopenharmony_ci if (inputLength <= kMaxShortLength) { 1151cb0ef41Sopenharmony_ci if ((typeof actual !== 'object' || actual === null) && 1161cb0ef41Sopenharmony_ci (typeof expected !== 'object' || expected === null) && 1171cb0ef41Sopenharmony_ci (actual !== 0 || expected !== 0)) { // -0 === +0 1181cb0ef41Sopenharmony_ci return `${kReadableOperator[operator]}\n\n` + 1191cb0ef41Sopenharmony_ci `${actualLines[0]} !== ${expectedLines[0]}\n`; 1201cb0ef41Sopenharmony_ci } 1211cb0ef41Sopenharmony_ci } else if (operator !== 'strictEqualObject') { 1221cb0ef41Sopenharmony_ci // If the stderr is a tty and the input length is lower than the current 1231cb0ef41Sopenharmony_ci // columns per line, add a mismatch indicator below the output. If it is 1241cb0ef41Sopenharmony_ci // not a tty, use a default value of 80 characters. 1251cb0ef41Sopenharmony_ci const maxLength = process.stderr.isTTY ? process.stderr.columns : 80; 1261cb0ef41Sopenharmony_ci if (inputLength < maxLength) { 1271cb0ef41Sopenharmony_ci while (actualRaw[i] === expectedRaw[i]) { 1281cb0ef41Sopenharmony_ci i++; 1291cb0ef41Sopenharmony_ci } 1301cb0ef41Sopenharmony_ci // Ignore the first characters. 1311cb0ef41Sopenharmony_ci if (i > 2) { 1321cb0ef41Sopenharmony_ci // Add position indicator for the first mismatch in case it is a 1331cb0ef41Sopenharmony_ci // single line and the input length is less than the column length. 1341cb0ef41Sopenharmony_ci indicator = `\n ${StringPrototypeRepeat(' ', i)}^`; 1351cb0ef41Sopenharmony_ci i = 0; 1361cb0ef41Sopenharmony_ci } 1371cb0ef41Sopenharmony_ci } 1381cb0ef41Sopenharmony_ci } 1391cb0ef41Sopenharmony_ci } 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci // Remove all ending lines that match (this optimizes the output for 1421cb0ef41Sopenharmony_ci // readability by reducing the number of total changed lines). 1431cb0ef41Sopenharmony_ci let a = actualLines[actualLines.length - 1]; 1441cb0ef41Sopenharmony_ci let b = expectedLines[expectedLines.length - 1]; 1451cb0ef41Sopenharmony_ci while (a === b) { 1461cb0ef41Sopenharmony_ci if (i++ < 3) { 1471cb0ef41Sopenharmony_ci end = `\n ${a}${end}`; 1481cb0ef41Sopenharmony_ci } else { 1491cb0ef41Sopenharmony_ci other = a; 1501cb0ef41Sopenharmony_ci } 1511cb0ef41Sopenharmony_ci ArrayPrototypePop(actualLines); 1521cb0ef41Sopenharmony_ci ArrayPrototypePop(expectedLines); 1531cb0ef41Sopenharmony_ci if (actualLines.length === 0 || expectedLines.length === 0) 1541cb0ef41Sopenharmony_ci break; 1551cb0ef41Sopenharmony_ci a = actualLines[actualLines.length - 1]; 1561cb0ef41Sopenharmony_ci b = expectedLines[expectedLines.length - 1]; 1571cb0ef41Sopenharmony_ci } 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci const maxLines = MathMax(actualLines.length, expectedLines.length); 1601cb0ef41Sopenharmony_ci // Strict equal with identical objects that are not identical by reference. 1611cb0ef41Sopenharmony_ci // E.g., assert.deepStrictEqual({ a: Symbol() }, { a: Symbol() }) 1621cb0ef41Sopenharmony_ci if (maxLines === 0) { 1631cb0ef41Sopenharmony_ci // We have to get the result again. The lines were all removed before. 1641cb0ef41Sopenharmony_ci const actualLines = StringPrototypeSplit(actualInspected, '\n'); 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci // Only remove lines in case it makes sense to collapse those. 1671cb0ef41Sopenharmony_ci // TODO: Accept env to always show the full error. 1681cb0ef41Sopenharmony_ci if (actualLines.length > 50) { 1691cb0ef41Sopenharmony_ci actualLines[46] = `${colors.blue}...${colors.white}`; 1701cb0ef41Sopenharmony_ci while (actualLines.length > 47) { 1711cb0ef41Sopenharmony_ci ArrayPrototypePop(actualLines); 1721cb0ef41Sopenharmony_ci } 1731cb0ef41Sopenharmony_ci } 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci return `${kReadableOperator.notIdentical}\n\n` + 1761cb0ef41Sopenharmony_ci `${ArrayPrototypeJoin(actualLines, '\n')}\n`; 1771cb0ef41Sopenharmony_ci } 1781cb0ef41Sopenharmony_ci 1791cb0ef41Sopenharmony_ci // There were at least five identical lines at the end. Mark a couple of 1801cb0ef41Sopenharmony_ci // skipped. 1811cb0ef41Sopenharmony_ci if (i >= 5) { 1821cb0ef41Sopenharmony_ci end = `\n${colors.blue}...${colors.white}${end}`; 1831cb0ef41Sopenharmony_ci skipped = true; 1841cb0ef41Sopenharmony_ci } 1851cb0ef41Sopenharmony_ci if (other !== '') { 1861cb0ef41Sopenharmony_ci end = `\n ${other}${end}`; 1871cb0ef41Sopenharmony_ci other = ''; 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci let printedLines = 0; 1911cb0ef41Sopenharmony_ci let identical = 0; 1921cb0ef41Sopenharmony_ci const msg = kReadableOperator[operator] + 1931cb0ef41Sopenharmony_ci `\n${colors.green}+ actual${colors.white} ${colors.red}- expected${colors.white}`; 1941cb0ef41Sopenharmony_ci const skippedMsg = ` ${colors.blue}...${colors.white} Lines skipped`; 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci let lines = actualLines; 1971cb0ef41Sopenharmony_ci let plusMinus = `${colors.green}+${colors.white}`; 1981cb0ef41Sopenharmony_ci let maxLength = expectedLines.length; 1991cb0ef41Sopenharmony_ci if (actualLines.length < maxLines) { 2001cb0ef41Sopenharmony_ci lines = expectedLines; 2011cb0ef41Sopenharmony_ci plusMinus = `${colors.red}-${colors.white}`; 2021cb0ef41Sopenharmony_ci maxLength = actualLines.length; 2031cb0ef41Sopenharmony_ci } 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci for (i = 0; i < maxLines; i++) { 2061cb0ef41Sopenharmony_ci if (maxLength < i + 1) { 2071cb0ef41Sopenharmony_ci // If more than two former lines are identical, print them. Collapse them 2081cb0ef41Sopenharmony_ci // in case more than five lines were identical. 2091cb0ef41Sopenharmony_ci if (identical > 2) { 2101cb0ef41Sopenharmony_ci if (identical > 3) { 2111cb0ef41Sopenharmony_ci if (identical > 4) { 2121cb0ef41Sopenharmony_ci if (identical === 5) { 2131cb0ef41Sopenharmony_ci res += `\n ${lines[i - 3]}`; 2141cb0ef41Sopenharmony_ci printedLines++; 2151cb0ef41Sopenharmony_ci } else { 2161cb0ef41Sopenharmony_ci res += `\n${colors.blue}...${colors.white}`; 2171cb0ef41Sopenharmony_ci skipped = true; 2181cb0ef41Sopenharmony_ci } 2191cb0ef41Sopenharmony_ci } 2201cb0ef41Sopenharmony_ci res += `\n ${lines[i - 2]}`; 2211cb0ef41Sopenharmony_ci printedLines++; 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci res += `\n ${lines[i - 1]}`; 2241cb0ef41Sopenharmony_ci printedLines++; 2251cb0ef41Sopenharmony_ci } 2261cb0ef41Sopenharmony_ci // No identical lines before. 2271cb0ef41Sopenharmony_ci identical = 0; 2281cb0ef41Sopenharmony_ci // Add the expected line to the cache. 2291cb0ef41Sopenharmony_ci if (lines === actualLines) { 2301cb0ef41Sopenharmony_ci res += `\n${plusMinus} ${lines[i]}`; 2311cb0ef41Sopenharmony_ci } else { 2321cb0ef41Sopenharmony_ci other += `\n${plusMinus} ${lines[i]}`; 2331cb0ef41Sopenharmony_ci } 2341cb0ef41Sopenharmony_ci printedLines++; 2351cb0ef41Sopenharmony_ci // Only extra actual lines exist 2361cb0ef41Sopenharmony_ci // Lines diverge 2371cb0ef41Sopenharmony_ci } else { 2381cb0ef41Sopenharmony_ci const expectedLine = expectedLines[i]; 2391cb0ef41Sopenharmony_ci let actualLine = actualLines[i]; 2401cb0ef41Sopenharmony_ci // If the lines diverge, specifically check for lines that only diverge by 2411cb0ef41Sopenharmony_ci // a trailing comma. In that case it is actually identical and we should 2421cb0ef41Sopenharmony_ci // mark it as such. 2431cb0ef41Sopenharmony_ci let divergingLines = 2441cb0ef41Sopenharmony_ci actualLine !== expectedLine && 2451cb0ef41Sopenharmony_ci (!StringPrototypeEndsWith(actualLine, ',') || 2461cb0ef41Sopenharmony_ci StringPrototypeSlice(actualLine, 0, -1) !== expectedLine); 2471cb0ef41Sopenharmony_ci // If the expected line has a trailing comma but is otherwise identical, 2481cb0ef41Sopenharmony_ci // add a comma at the end of the actual line. Otherwise the output could 2491cb0ef41Sopenharmony_ci // look weird as in: 2501cb0ef41Sopenharmony_ci // 2511cb0ef41Sopenharmony_ci // [ 2521cb0ef41Sopenharmony_ci // 1 // No comma at the end! 2531cb0ef41Sopenharmony_ci // + 2 2541cb0ef41Sopenharmony_ci // ] 2551cb0ef41Sopenharmony_ci // 2561cb0ef41Sopenharmony_ci if (divergingLines && 2571cb0ef41Sopenharmony_ci StringPrototypeEndsWith(expectedLine, ',') && 2581cb0ef41Sopenharmony_ci StringPrototypeSlice(expectedLine, 0, -1) === actualLine) { 2591cb0ef41Sopenharmony_ci divergingLines = false; 2601cb0ef41Sopenharmony_ci actualLine += ','; 2611cb0ef41Sopenharmony_ci } 2621cb0ef41Sopenharmony_ci if (divergingLines) { 2631cb0ef41Sopenharmony_ci // If more than two former lines are identical, print them. Collapse 2641cb0ef41Sopenharmony_ci // them in case more than five lines were identical. 2651cb0ef41Sopenharmony_ci if (identical > 2) { 2661cb0ef41Sopenharmony_ci if (identical > 3) { 2671cb0ef41Sopenharmony_ci if (identical > 4) { 2681cb0ef41Sopenharmony_ci if (identical === 5) { 2691cb0ef41Sopenharmony_ci res += `\n ${actualLines[i - 3]}`; 2701cb0ef41Sopenharmony_ci printedLines++; 2711cb0ef41Sopenharmony_ci } else { 2721cb0ef41Sopenharmony_ci res += `\n${colors.blue}...${colors.white}`; 2731cb0ef41Sopenharmony_ci skipped = true; 2741cb0ef41Sopenharmony_ci } 2751cb0ef41Sopenharmony_ci } 2761cb0ef41Sopenharmony_ci res += `\n ${actualLines[i - 2]}`; 2771cb0ef41Sopenharmony_ci printedLines++; 2781cb0ef41Sopenharmony_ci } 2791cb0ef41Sopenharmony_ci res += `\n ${actualLines[i - 1]}`; 2801cb0ef41Sopenharmony_ci printedLines++; 2811cb0ef41Sopenharmony_ci } 2821cb0ef41Sopenharmony_ci // No identical lines before. 2831cb0ef41Sopenharmony_ci identical = 0; 2841cb0ef41Sopenharmony_ci // Add the actual line to the result and cache the expected diverging 2851cb0ef41Sopenharmony_ci // line so consecutive diverging lines show up as +++--- and not +-+-+-. 2861cb0ef41Sopenharmony_ci res += `\n${colors.green}+${colors.white} ${actualLine}`; 2871cb0ef41Sopenharmony_ci other += `\n${colors.red}-${colors.white} ${expectedLine}`; 2881cb0ef41Sopenharmony_ci printedLines += 2; 2891cb0ef41Sopenharmony_ci // Lines are identical 2901cb0ef41Sopenharmony_ci } else { 2911cb0ef41Sopenharmony_ci // Add all cached information to the result before adding other things 2921cb0ef41Sopenharmony_ci // and reset the cache. 2931cb0ef41Sopenharmony_ci res += other; 2941cb0ef41Sopenharmony_ci other = ''; 2951cb0ef41Sopenharmony_ci identical++; 2961cb0ef41Sopenharmony_ci // The very first identical line since the last diverging line is be 2971cb0ef41Sopenharmony_ci // added to the result. 2981cb0ef41Sopenharmony_ci if (identical <= 2) { 2991cb0ef41Sopenharmony_ci res += `\n ${actualLine}`; 3001cb0ef41Sopenharmony_ci printedLines++; 3011cb0ef41Sopenharmony_ci } 3021cb0ef41Sopenharmony_ci } 3031cb0ef41Sopenharmony_ci } 3041cb0ef41Sopenharmony_ci // Inspected object to big (Show ~50 rows max) 3051cb0ef41Sopenharmony_ci if (printedLines > 50 && i < maxLines - 2) { 3061cb0ef41Sopenharmony_ci return `${msg}${skippedMsg}\n${res}\n${colors.blue}...${colors.white}${other}\n` + 3071cb0ef41Sopenharmony_ci `${colors.blue}...${colors.white}`; 3081cb0ef41Sopenharmony_ci } 3091cb0ef41Sopenharmony_ci } 3101cb0ef41Sopenharmony_ci 3111cb0ef41Sopenharmony_ci return `${msg}${skipped ? skippedMsg : ''}\n${res}${other}${end}${indicator}`; 3121cb0ef41Sopenharmony_ci} 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_cifunction addEllipsis(string) { 3151cb0ef41Sopenharmony_ci const lines = StringPrototypeSplit(string, '\n', 11); 3161cb0ef41Sopenharmony_ci if (lines.length > 10) { 3171cb0ef41Sopenharmony_ci lines.length = 10; 3181cb0ef41Sopenharmony_ci return `${ArrayPrototypeJoin(lines, '\n')}\n...`; 3191cb0ef41Sopenharmony_ci } else if (string.length > 512) { 3201cb0ef41Sopenharmony_ci return `${StringPrototypeSlice(string, 512)}...`; 3211cb0ef41Sopenharmony_ci } 3221cb0ef41Sopenharmony_ci return string; 3231cb0ef41Sopenharmony_ci} 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ciclass AssertionError extends Error { 3261cb0ef41Sopenharmony_ci constructor(options) { 3271cb0ef41Sopenharmony_ci validateObject(options, 'options'); 3281cb0ef41Sopenharmony_ci const { 3291cb0ef41Sopenharmony_ci message, 3301cb0ef41Sopenharmony_ci operator, 3311cb0ef41Sopenharmony_ci stackStartFn, 3321cb0ef41Sopenharmony_ci details, 3331cb0ef41Sopenharmony_ci // Compatibility with older versions. 3341cb0ef41Sopenharmony_ci stackStartFunction, 3351cb0ef41Sopenharmony_ci } = options; 3361cb0ef41Sopenharmony_ci let { 3371cb0ef41Sopenharmony_ci actual, 3381cb0ef41Sopenharmony_ci expected, 3391cb0ef41Sopenharmony_ci } = options; 3401cb0ef41Sopenharmony_ci 3411cb0ef41Sopenharmony_ci const limit = Error.stackTraceLimit; 3421cb0ef41Sopenharmony_ci if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0; 3431cb0ef41Sopenharmony_ci 3441cb0ef41Sopenharmony_ci if (message != null) { 3451cb0ef41Sopenharmony_ci super(String(message)); 3461cb0ef41Sopenharmony_ci } else { 3471cb0ef41Sopenharmony_ci // Reset colors on each call to make sure we handle dynamically set environment 3481cb0ef41Sopenharmony_ci // variables correct. 3491cb0ef41Sopenharmony_ci colors.refresh(); 3501cb0ef41Sopenharmony_ci // Prevent the error stack from being visible by duplicating the error 3511cb0ef41Sopenharmony_ci // in a very close way to the original in case both sides are actually 3521cb0ef41Sopenharmony_ci // instances of Error. 3531cb0ef41Sopenharmony_ci if (typeof actual === 'object' && actual !== null && 3541cb0ef41Sopenharmony_ci typeof expected === 'object' && expected !== null && 3551cb0ef41Sopenharmony_ci 'stack' in actual && actual instanceof Error && 3561cb0ef41Sopenharmony_ci 'stack' in expected && expected instanceof Error) { 3571cb0ef41Sopenharmony_ci actual = copyError(actual); 3581cb0ef41Sopenharmony_ci expected = copyError(expected); 3591cb0ef41Sopenharmony_ci } 3601cb0ef41Sopenharmony_ci 3611cb0ef41Sopenharmony_ci if (operator === 'deepStrictEqual' || operator === 'strictEqual') { 3621cb0ef41Sopenharmony_ci super(createErrDiff(actual, expected, operator)); 3631cb0ef41Sopenharmony_ci } else if (operator === 'notDeepStrictEqual' || 3641cb0ef41Sopenharmony_ci operator === 'notStrictEqual') { 3651cb0ef41Sopenharmony_ci // In case the objects are equal but the operator requires unequal, show 3661cb0ef41Sopenharmony_ci // the first object and say A equals B 3671cb0ef41Sopenharmony_ci let base = kReadableOperator[operator]; 3681cb0ef41Sopenharmony_ci const res = StringPrototypeSplit(inspectValue(actual), '\n'); 3691cb0ef41Sopenharmony_ci 3701cb0ef41Sopenharmony_ci // In case "actual" is an object or a function, it should not be 3711cb0ef41Sopenharmony_ci // reference equal. 3721cb0ef41Sopenharmony_ci if (operator === 'notStrictEqual' && 3731cb0ef41Sopenharmony_ci ((typeof actual === 'object' && actual !== null) || 3741cb0ef41Sopenharmony_ci typeof actual === 'function')) { 3751cb0ef41Sopenharmony_ci base = kReadableOperator.notStrictEqualObject; 3761cb0ef41Sopenharmony_ci } 3771cb0ef41Sopenharmony_ci 3781cb0ef41Sopenharmony_ci // Only remove lines in case it makes sense to collapse those. 3791cb0ef41Sopenharmony_ci // TODO: Accept env to always show the full error. 3801cb0ef41Sopenharmony_ci if (res.length > 50) { 3811cb0ef41Sopenharmony_ci res[46] = `${colors.blue}...${colors.white}`; 3821cb0ef41Sopenharmony_ci while (res.length > 47) { 3831cb0ef41Sopenharmony_ci ArrayPrototypePop(res); 3841cb0ef41Sopenharmony_ci } 3851cb0ef41Sopenharmony_ci } 3861cb0ef41Sopenharmony_ci 3871cb0ef41Sopenharmony_ci // Only print a single input. 3881cb0ef41Sopenharmony_ci if (res.length === 1) { 3891cb0ef41Sopenharmony_ci super(`${base}${res[0].length > 5 ? '\n\n' : ' '}${res[0]}`); 3901cb0ef41Sopenharmony_ci } else { 3911cb0ef41Sopenharmony_ci super(`${base}\n\n${ArrayPrototypeJoin(res, '\n')}\n`); 3921cb0ef41Sopenharmony_ci } 3931cb0ef41Sopenharmony_ci } else { 3941cb0ef41Sopenharmony_ci let res = inspectValue(actual); 3951cb0ef41Sopenharmony_ci let other = inspectValue(expected); 3961cb0ef41Sopenharmony_ci const knownOperator = kReadableOperator[operator]; 3971cb0ef41Sopenharmony_ci if (operator === 'notDeepEqual' && res === other) { 3981cb0ef41Sopenharmony_ci res = `${knownOperator}\n\n${res}`; 3991cb0ef41Sopenharmony_ci if (res.length > 1024) { 4001cb0ef41Sopenharmony_ci res = `${StringPrototypeSlice(res, 0, 1021)}...`; 4011cb0ef41Sopenharmony_ci } 4021cb0ef41Sopenharmony_ci super(res); 4031cb0ef41Sopenharmony_ci } else { 4041cb0ef41Sopenharmony_ci if (res.length > 512) { 4051cb0ef41Sopenharmony_ci res = `${StringPrototypeSlice(res, 0, 509)}...`; 4061cb0ef41Sopenharmony_ci } 4071cb0ef41Sopenharmony_ci if (other.length > 512) { 4081cb0ef41Sopenharmony_ci other = `${StringPrototypeSlice(other, 0, 509)}...`; 4091cb0ef41Sopenharmony_ci } 4101cb0ef41Sopenharmony_ci if (operator === 'deepEqual') { 4111cb0ef41Sopenharmony_ci res = `${knownOperator}\n\n${res}\n\nshould loosely deep-equal\n\n`; 4121cb0ef41Sopenharmony_ci } else { 4131cb0ef41Sopenharmony_ci const newOp = kReadableOperator[`${operator}Unequal`]; 4141cb0ef41Sopenharmony_ci if (newOp) { 4151cb0ef41Sopenharmony_ci res = `${newOp}\n\n${res}\n\nshould not loosely deep-equal\n\n`; 4161cb0ef41Sopenharmony_ci } else { 4171cb0ef41Sopenharmony_ci other = ` ${operator} ${other}`; 4181cb0ef41Sopenharmony_ci } 4191cb0ef41Sopenharmony_ci } 4201cb0ef41Sopenharmony_ci super(`${res}${other}`); 4211cb0ef41Sopenharmony_ci } 4221cb0ef41Sopenharmony_ci } 4231cb0ef41Sopenharmony_ci } 4241cb0ef41Sopenharmony_ci 4251cb0ef41Sopenharmony_ci if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit; 4261cb0ef41Sopenharmony_ci 4271cb0ef41Sopenharmony_ci this.generatedMessage = !message; 4281cb0ef41Sopenharmony_ci ObjectDefineProperty(this, 'name', { 4291cb0ef41Sopenharmony_ci __proto__: null, 4301cb0ef41Sopenharmony_ci value: 'AssertionError [ERR_ASSERTION]', 4311cb0ef41Sopenharmony_ci enumerable: false, 4321cb0ef41Sopenharmony_ci writable: true, 4331cb0ef41Sopenharmony_ci configurable: true, 4341cb0ef41Sopenharmony_ci }); 4351cb0ef41Sopenharmony_ci this.code = 'ERR_ASSERTION'; 4361cb0ef41Sopenharmony_ci if (details) { 4371cb0ef41Sopenharmony_ci this.actual = undefined; 4381cb0ef41Sopenharmony_ci this.expected = undefined; 4391cb0ef41Sopenharmony_ci this.operator = undefined; 4401cb0ef41Sopenharmony_ci for (let i = 0; i < details.length; i++) { 4411cb0ef41Sopenharmony_ci this['message ' + i] = details[i].message; 4421cb0ef41Sopenharmony_ci this['actual ' + i] = details[i].actual; 4431cb0ef41Sopenharmony_ci this['expected ' + i] = details[i].expected; 4441cb0ef41Sopenharmony_ci this['operator ' + i] = details[i].operator; 4451cb0ef41Sopenharmony_ci this['stack trace ' + i] = details[i].stack; 4461cb0ef41Sopenharmony_ci } 4471cb0ef41Sopenharmony_ci } else { 4481cb0ef41Sopenharmony_ci this.actual = actual; 4491cb0ef41Sopenharmony_ci this.expected = expected; 4501cb0ef41Sopenharmony_ci this.operator = operator; 4511cb0ef41Sopenharmony_ci } 4521cb0ef41Sopenharmony_ci ErrorCaptureStackTrace(this, stackStartFn || stackStartFunction); 4531cb0ef41Sopenharmony_ci // Create error message including the error code in the name. 4541cb0ef41Sopenharmony_ci this.stack; // eslint-disable-line no-unused-expressions 4551cb0ef41Sopenharmony_ci // Reset the name. 4561cb0ef41Sopenharmony_ci this.name = 'AssertionError'; 4571cb0ef41Sopenharmony_ci } 4581cb0ef41Sopenharmony_ci 4591cb0ef41Sopenharmony_ci toString() { 4601cb0ef41Sopenharmony_ci return `${this.name} [${this.code}]: ${this.message}`; 4611cb0ef41Sopenharmony_ci } 4621cb0ef41Sopenharmony_ci 4631cb0ef41Sopenharmony_ci [inspect.custom](recurseTimes, ctx) { 4641cb0ef41Sopenharmony_ci // Long strings should not be fully inspected. 4651cb0ef41Sopenharmony_ci const tmpActual = this.actual; 4661cb0ef41Sopenharmony_ci const tmpExpected = this.expected; 4671cb0ef41Sopenharmony_ci 4681cb0ef41Sopenharmony_ci if (typeof this.actual === 'string') { 4691cb0ef41Sopenharmony_ci this.actual = addEllipsis(this.actual); 4701cb0ef41Sopenharmony_ci } 4711cb0ef41Sopenharmony_ci if (typeof this.expected === 'string') { 4721cb0ef41Sopenharmony_ci this.expected = addEllipsis(this.expected); 4731cb0ef41Sopenharmony_ci } 4741cb0ef41Sopenharmony_ci 4751cb0ef41Sopenharmony_ci // This limits the `actual` and `expected` property default inspection to 4761cb0ef41Sopenharmony_ci // the minimum depth. Otherwise those values would be too verbose compared 4771cb0ef41Sopenharmony_ci // to the actual error message which contains a combined view of these two 4781cb0ef41Sopenharmony_ci // input values. 4791cb0ef41Sopenharmony_ci const result = inspect(this, { 4801cb0ef41Sopenharmony_ci ...ctx, 4811cb0ef41Sopenharmony_ci customInspect: false, 4821cb0ef41Sopenharmony_ci depth: 0, 4831cb0ef41Sopenharmony_ci }); 4841cb0ef41Sopenharmony_ci 4851cb0ef41Sopenharmony_ci // Reset the properties after inspection. 4861cb0ef41Sopenharmony_ci this.actual = tmpActual; 4871cb0ef41Sopenharmony_ci this.expected = tmpExpected; 4881cb0ef41Sopenharmony_ci 4891cb0ef41Sopenharmony_ci return result; 4901cb0ef41Sopenharmony_ci } 4911cb0ef41Sopenharmony_ci} 4921cb0ef41Sopenharmony_ci 4931cb0ef41Sopenharmony_cimodule.exports = AssertionError; 494