summaryrefslogtreecommitdiff
path: root/lib/internal/errors.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/internal/errors.js')
-rw-r--r--lib/internal/errors.js150
1 files changed, 146 insertions, 4 deletions
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index 6e6852f380..6bbb5d3548 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -132,22 +132,164 @@ class SystemError extends makeNodeError(Error) {
}
}
+function createErrDiff(actual, expected, operator) {
+ var other = '';
+ var res = '';
+ var lastPos = 0;
+ var end = '';
+ var skipped = false;
+ const actualLines = util
+ .inspect(actual, { compact: false }).split('\n');
+ const expectedLines = util
+ .inspect(expected, { compact: false }).split('\n');
+ const msg = `Input A expected to ${operator} input B:\n` +
+ '\u001b[32m+ expected\u001b[39m \u001b[31m- actual\u001b[39m';
+ const skippedMsg = ' ... Lines skipped';
+
+ // Remove all ending lines that match (this optimizes the output for
+ // readability by reducing the number of total changed lines).
+ var a = actualLines[actualLines.length - 1];
+ var b = expectedLines[expectedLines.length - 1];
+ var i = 0;
+ while (a === b) {
+ if (i++ < 2) {
+ end = `\n ${a}${end}`;
+ } else {
+ other = a;
+ }
+ actualLines.pop();
+ expectedLines.pop();
+ a = actualLines[actualLines.length - 1];
+ b = expectedLines[expectedLines.length - 1];
+ }
+ if (i > 3) {
+ end = `\n...${end}`;
+ skipped = true;
+ }
+ if (other !== '') {
+ end = `\n ${other}${end}`;
+ other = '';
+ }
+
+ const maxLines = Math.max(actualLines.length, expectedLines.length);
+ var printedLines = 0;
+ for (i = 0; i < maxLines; i++) {
+ // Only extra expected lines exist
+ const cur = i - lastPos;
+ if (actualLines.length < i + 1) {
+ if (cur > 1 && i > 2) {
+ if (cur > 4) {
+ res += '\n...';
+ skipped = true;
+ } else if (cur > 3) {
+ res += `\n ${expectedLines[i - 2]}`;
+ printedLines++;
+ }
+ res += `\n ${expectedLines[i - 1]}`;
+ printedLines++;
+ }
+ lastPos = i;
+ other += `\n\u001b[32m+\u001b[39m ${expectedLines[i]}`;
+ printedLines++;
+ // Only extra actual lines exist
+ } else if (expectedLines.length < i + 1) {
+ if (cur > 1 && i > 2) {
+ if (cur > 4) {
+ res += '\n...';
+ skipped = true;
+ } else if (cur > 3) {
+ res += `\n ${actualLines[i - 2]}`;
+ printedLines++;
+ }
+ res += `\n ${actualLines[i - 1]}`;
+ printedLines++;
+ }
+ lastPos = i;
+ res += `\n\u001b[31m-\u001b[39m ${actualLines[i]}`;
+ printedLines++;
+ // Lines diverge
+ } else if (actualLines[i] !== expectedLines[i]) {
+ if (cur > 1 && i > 2) {
+ if (cur > 4) {
+ res += '\n...';
+ skipped = true;
+ } else if (cur > 3) {
+ res += `\n ${actualLines[i - 2]}`;
+ printedLines++;
+ }
+ res += `\n ${actualLines[i - 1]}`;
+ printedLines++;
+ }
+ lastPos = i;
+ res += `\n\u001b[31m-\u001b[39m ${actualLines[i]}`;
+ other += `\n\u001b[32m+\u001b[39m ${expectedLines[i]}`;
+ printedLines += 2;
+ // Lines are identical
+ } else {
+ res += other;
+ other = '';
+ if (cur === 1 || i === 0) {
+ res += `\n ${actualLines[i]}`;
+ printedLines++;
+ }
+ }
+ // Inspected object to big (Show ~20 rows max)
+ if (printedLines > 20 && i < maxLines - 2) {
+ return `${msg}${skippedMsg}\n${res}\n...${other}\n...`;
+ }
+ }
+ return `${msg}${skipped ? skippedMsg : ''}\n${res}${other}${end}`;
+}
+
class AssertionError extends Error {
constructor(options) {
if (typeof options !== 'object' || options === null) {
throw new exports.TypeError('ERR_INVALID_ARG_TYPE', 'options', 'Object');
}
- var { actual, expected, message, operator, stackStartFn } = options;
+ var {
+ actual,
+ expected,
+ message,
+ operator,
+ stackStartFn,
+ errorDiff = 0
+ } = options;
+
if (message != null) {
super(message);
} else {
+ if (util === null) util = require('util');
+
if (actual && actual.stack && actual instanceof Error)
actual = `${actual.name}: ${actual.message}`;
if (expected && expected.stack && expected instanceof Error)
expected = `${expected.name}: ${expected.message}`;
- if (util === null) util = require('util');
- super(`${util.inspect(actual).slice(0, 128)} ` +
- `${operator} ${util.inspect(expected).slice(0, 128)}`);
+
+ if (errorDiff === 0) {
+ let res = util.inspect(actual);
+ let other = util.inspect(expected);
+ if (res.length > 128)
+ res = `${res.slice(0, 125)}...`;
+ if (other.length > 128)
+ other = `${other.slice(0, 125)}...`;
+ super(`${res} ${operator} ${other}`);
+ } else if (errorDiff === 1) {
+ // In case the objects are equal but the operator requires unequal, show
+ // the first object and say A equals B
+ const res = util
+ .inspect(actual, { compact: false }).split('\n');
+
+ if (res.length > 20) {
+ res[19] = '...';
+ while (res.length > 20) {
+ res.pop();
+ }
+ }
+ // Only print a single object.
+ super(`Identical input passed to ${operator}:\n${res.join('\n')}`);
+ } else {
+ super(createErrDiff(actual, expected, operator));
+ }
}
this.generatedMessage = !message;