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