assert: move AssertionError into own file
This moves the `assert` parts from `internal/errors` into an own file. `internal/errors` got bigger and bigger and it was difficult to keep a good overview of what was going on. While doing so it also removes the `internalAssert` function and just lazy loads `assert`. PR-URL: https://github.com/nodejs/node/pull/20486 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
This commit is contained in:
parent
4c6df73ae4
commit
b304096a14
@ -25,15 +25,12 @@ const {
|
|||||||
isDeepEqual,
|
isDeepEqual,
|
||||||
isDeepStrictEqual
|
isDeepStrictEqual
|
||||||
} = require('internal/util/comparisons');
|
} = require('internal/util/comparisons');
|
||||||
const {
|
const { codes: {
|
||||||
AssertionError,
|
ERR_AMBIGUOUS_ARGUMENT,
|
||||||
errorCache,
|
ERR_INVALID_ARG_TYPE,
|
||||||
codes: {
|
ERR_INVALID_RETURN_VALUE
|
||||||
ERR_AMBIGUOUS_ARGUMENT,
|
} } = require('internal/errors');
|
||||||
ERR_INVALID_ARG_TYPE,
|
const { AssertionError, errorCache } = require('internal/assert');
|
||||||
ERR_INVALID_RETURN_VALUE
|
|
||||||
}
|
|
||||||
} = require('internal/errors');
|
|
||||||
const { openSync, closeSync, readSync } = require('fs');
|
const { openSync, closeSync, readSync } = require('fs');
|
||||||
const { inspect, types: { isPromise, isRegExp } } = require('util');
|
const { inspect, types: { isPromise, isRegExp } } = require('util');
|
||||||
const { EOL } = require('os');
|
const { EOL } = require('os');
|
||||||
|
275
lib/internal/assert.js
Normal file
275
lib/internal/assert.js
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { inspect } = require('util');
|
||||||
|
const { codes: {
|
||||||
|
ERR_INVALID_ARG_TYPE
|
||||||
|
} } = require('internal/errors');
|
||||||
|
|
||||||
|
let blue = '';
|
||||||
|
let green = '';
|
||||||
|
let red = '';
|
||||||
|
let white = '';
|
||||||
|
|
||||||
|
const READABLE_OPERATOR = {
|
||||||
|
deepStrictEqual: 'Input A expected to strictly deep-equal input B',
|
||||||
|
notDeepStrictEqual: 'Input A expected to strictly not deep-equal input B',
|
||||||
|
strictEqual: 'Input A expected to strictly equal input B',
|
||||||
|
notStrictEqual: 'Input A expected to strictly not equal input B'
|
||||||
|
};
|
||||||
|
|
||||||
|
function copyError(source) {
|
||||||
|
const keys = Object.keys(source);
|
||||||
|
const target = Object.create(Object.getPrototypeOf(source));
|
||||||
|
for (const key of keys) {
|
||||||
|
target[key] = source[key];
|
||||||
|
}
|
||||||
|
Object.defineProperty(target, 'message', { value: source.message });
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inspectValue(val) {
|
||||||
|
// The util.inspect default values could be changed. This makes sure the
|
||||||
|
// error messages contain the necessary information nevertheless.
|
||||||
|
return inspect(
|
||||||
|
val,
|
||||||
|
{
|
||||||
|
compact: false,
|
||||||
|
customInspect: false,
|
||||||
|
depth: 1000,
|
||||||
|
maxArrayLength: Infinity,
|
||||||
|
// Assert compares only enumerable properties (with a few exceptions).
|
||||||
|
showHidden: false,
|
||||||
|
// Having a long line as error is better than wrapping the line for
|
||||||
|
// comparison.
|
||||||
|
breakLength: Infinity,
|
||||||
|
// Assert does not detect proxies currently.
|
||||||
|
showProxy: false
|
||||||
|
}
|
||||||
|
).split('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
function createErrDiff(actual, expected, operator) {
|
||||||
|
var other = '';
|
||||||
|
var res = '';
|
||||||
|
var lastPos = 0;
|
||||||
|
var end = '';
|
||||||
|
var skipped = false;
|
||||||
|
const actualLines = inspectValue(actual);
|
||||||
|
const expectedLines = inspectValue(expected);
|
||||||
|
const msg = READABLE_OPERATOR[operator] +
|
||||||
|
`:\n${green}+ expected${white} ${red}- actual${white}`;
|
||||||
|
const skippedMsg = ` ${blue}...${white} 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();
|
||||||
|
if (actualLines.length === 0 || expectedLines.length === 0)
|
||||||
|
break;
|
||||||
|
a = actualLines[actualLines.length - 1];
|
||||||
|
b = expectedLines[expectedLines.length - 1];
|
||||||
|
}
|
||||||
|
if (i > 3) {
|
||||||
|
end = `\n${blue}...${white}${end}`;
|
||||||
|
skipped = true;
|
||||||
|
}
|
||||||
|
if (other !== '') {
|
||||||
|
end = `\n ${other}${end}`;
|
||||||
|
other = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxLines = Math.max(actualLines.length, expectedLines.length);
|
||||||
|
var printedLines = 0;
|
||||||
|
var identical = 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${blue}...${white}`;
|
||||||
|
skipped = true;
|
||||||
|
} else if (cur > 3) {
|
||||||
|
res += `\n ${expectedLines[i - 2]}`;
|
||||||
|
printedLines++;
|
||||||
|
}
|
||||||
|
res += `\n ${expectedLines[i - 1]}`;
|
||||||
|
printedLines++;
|
||||||
|
}
|
||||||
|
lastPos = i;
|
||||||
|
other += `\n${green}+${white} ${expectedLines[i]}`;
|
||||||
|
printedLines++;
|
||||||
|
// Only extra actual lines exist
|
||||||
|
} else if (expectedLines.length < i + 1) {
|
||||||
|
if (cur > 1 && i > 2) {
|
||||||
|
if (cur > 4) {
|
||||||
|
res += `\n${blue}...${white}`;
|
||||||
|
skipped = true;
|
||||||
|
} else if (cur > 3) {
|
||||||
|
res += `\n ${actualLines[i - 2]}`;
|
||||||
|
printedLines++;
|
||||||
|
}
|
||||||
|
res += `\n ${actualLines[i - 1]}`;
|
||||||
|
printedLines++;
|
||||||
|
}
|
||||||
|
lastPos = i;
|
||||||
|
res += `\n${red}-${white} ${actualLines[i]}`;
|
||||||
|
printedLines++;
|
||||||
|
// Lines diverge
|
||||||
|
} else if (actualLines[i] !== expectedLines[i]) {
|
||||||
|
if (cur > 1 && i > 2) {
|
||||||
|
if (cur > 4) {
|
||||||
|
res += `\n${blue}...${white}`;
|
||||||
|
skipped = true;
|
||||||
|
} else if (cur > 3) {
|
||||||
|
res += `\n ${actualLines[i - 2]}`;
|
||||||
|
printedLines++;
|
||||||
|
}
|
||||||
|
res += `\n ${actualLines[i - 1]}`;
|
||||||
|
printedLines++;
|
||||||
|
}
|
||||||
|
lastPos = i;
|
||||||
|
res += `\n${red}-${white} ${actualLines[i]}`;
|
||||||
|
other += `\n${green}+${white} ${expectedLines[i]}`;
|
||||||
|
printedLines += 2;
|
||||||
|
// Lines are identical
|
||||||
|
} else {
|
||||||
|
res += other;
|
||||||
|
other = '';
|
||||||
|
if (cur === 1 || i === 0) {
|
||||||
|
res += `\n ${actualLines[i]}`;
|
||||||
|
printedLines++;
|
||||||
|
}
|
||||||
|
identical++;
|
||||||
|
}
|
||||||
|
// Inspected object to big (Show ~20 rows max)
|
||||||
|
if (printedLines > 20 && i < maxLines - 2) {
|
||||||
|
return `${msg}${skippedMsg}\n${res}\n${blue}...${white}${other}\n` +
|
||||||
|
`${blue}...${white}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strict equal with identical objects that are not identical by reference.
|
||||||
|
if (identical === maxLines) {
|
||||||
|
// E.g., assert.deepStrictEqual(Symbol(), Symbol())
|
||||||
|
const base = operator === 'strictEqual' ?
|
||||||
|
'Input objects identical but not reference equal:' :
|
||||||
|
'Input objects not identical:';
|
||||||
|
|
||||||
|
// We have to get the result again. The lines were all removed before.
|
||||||
|
const actualLines = inspectValue(actual);
|
||||||
|
|
||||||
|
// Only remove lines in case it makes sense to collapse those.
|
||||||
|
// TODO: Accept env to always show the full error.
|
||||||
|
if (actualLines.length > 30) {
|
||||||
|
actualLines[26] = `${blue}...${white}`;
|
||||||
|
while (actualLines.length > 27) {
|
||||||
|
actualLines.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${base}\n\n${actualLines.join('\n')}\n`;
|
||||||
|
}
|
||||||
|
return `${msg}${skipped ? skippedMsg : ''}\n${res}${other}${end}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssertionError extends Error {
|
||||||
|
constructor(options) {
|
||||||
|
if (typeof options !== 'object' || options === null) {
|
||||||
|
throw new ERR_INVALID_ARG_TYPE('options', 'Object', options);
|
||||||
|
}
|
||||||
|
var {
|
||||||
|
actual,
|
||||||
|
expected,
|
||||||
|
message,
|
||||||
|
operator,
|
||||||
|
stackStartFn
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
if (message != null) {
|
||||||
|
super(message);
|
||||||
|
} else {
|
||||||
|
if (process.stdout.isTTY) {
|
||||||
|
// Reset on each call to make sure we handle dynamically set environment
|
||||||
|
// variables correct.
|
||||||
|
if (process.stdout.getColorDepth() !== 1) {
|
||||||
|
blue = '\u001b[34m';
|
||||||
|
green = '\u001b[32m';
|
||||||
|
white = '\u001b[39m';
|
||||||
|
red = '\u001b[31m';
|
||||||
|
} else {
|
||||||
|
blue = '';
|
||||||
|
green = '';
|
||||||
|
white = '';
|
||||||
|
red = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Prevent the error stack from being visible by duplicating the error
|
||||||
|
// in a very close way to the original in case both sides are actually
|
||||||
|
// instances of Error.
|
||||||
|
if (typeof actual === 'object' && actual !== null &&
|
||||||
|
typeof expected === 'object' && expected !== null &&
|
||||||
|
'stack' in actual && actual instanceof Error &&
|
||||||
|
'stack' in expected && expected instanceof Error) {
|
||||||
|
actual = copyError(actual);
|
||||||
|
expected = copyError(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operator === 'deepStrictEqual' || operator === 'strictEqual') {
|
||||||
|
super(createErrDiff(actual, expected, operator));
|
||||||
|
} else if (operator === 'notDeepStrictEqual' ||
|
||||||
|
operator === 'notStrictEqual') {
|
||||||
|
// In case the objects are equal but the operator requires unequal, show
|
||||||
|
// the first object and say A equals B
|
||||||
|
const res = inspectValue(actual);
|
||||||
|
const base = `Identical input passed to ${operator}:`;
|
||||||
|
|
||||||
|
// Only remove lines in case it makes sense to collapse those.
|
||||||
|
// TODO: Accept env to always show the full error.
|
||||||
|
if (res.length > 30) {
|
||||||
|
res[26] = `${blue}...${white}`;
|
||||||
|
while (res.length > 27) {
|
||||||
|
res.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only print a single input.
|
||||||
|
if (res.length === 1) {
|
||||||
|
super(`${base} ${res[0]}`);
|
||||||
|
} else {
|
||||||
|
super(`${base}\n\n${res.join('\n')}\n`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let res = inspect(actual);
|
||||||
|
let other = inspect(expected);
|
||||||
|
if (res.length > 128)
|
||||||
|
res = `${res.slice(0, 125)}...`;
|
||||||
|
if (other.length > 128)
|
||||||
|
other = `${other.slice(0, 125)}...`;
|
||||||
|
super(`${res} ${operator} ${other}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.generatedMessage = !message;
|
||||||
|
this.name = 'AssertionError [ERR_ASSERTION]';
|
||||||
|
this.code = 'ERR_ASSERTION';
|
||||||
|
this.actual = actual;
|
||||||
|
this.expected = expected;
|
||||||
|
this.operator = operator;
|
||||||
|
Error.captureStackTrace(this, stackStartFn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
AssertionError,
|
||||||
|
errorCache: new Map()
|
||||||
|
};
|
@ -15,18 +15,6 @@ const kInfo = Symbol('info');
|
|||||||
const messages = new Map();
|
const messages = new Map();
|
||||||
const codes = {};
|
const codes = {};
|
||||||
|
|
||||||
let blue = '';
|
|
||||||
let green = '';
|
|
||||||
let red = '';
|
|
||||||
let white = '';
|
|
||||||
|
|
||||||
const READABLE_OPERATOR = {
|
|
||||||
deepStrictEqual: 'Input A expected to strictly deep-equal input B',
|
|
||||||
notDeepStrictEqual: 'Input A expected to strictly not deep-equal input B',
|
|
||||||
strictEqual: 'Input A expected to strictly equal input B',
|
|
||||||
notStrictEqual: 'Input A expected to strictly not equal input B'
|
|
||||||
};
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
errmap,
|
errmap,
|
||||||
UV_EAI_NODATA,
|
UV_EAI_NODATA,
|
||||||
@ -36,10 +24,10 @@ const { kMaxLength } = process.binding('buffer');
|
|||||||
const { defineProperty } = Object;
|
const { defineProperty } = Object;
|
||||||
|
|
||||||
// Lazily loaded
|
// Lazily loaded
|
||||||
var util;
|
let util;
|
||||||
var buffer;
|
let assert;
|
||||||
|
|
||||||
var internalUtil = null;
|
let internalUtil = null;
|
||||||
function lazyInternalUtil() {
|
function lazyInternalUtil() {
|
||||||
if (!internalUtil) {
|
if (!internalUtil) {
|
||||||
internalUtil = require('internal/util');
|
internalUtil = require('internal/util');
|
||||||
@ -47,35 +35,11 @@ function lazyInternalUtil() {
|
|||||||
return internalUtil;
|
return internalUtil;
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyError(source) {
|
let buffer;
|
||||||
const keys = Object.keys(source);
|
function lazyBuffer() {
|
||||||
const target = Object.create(Object.getPrototypeOf(source));
|
if (buffer === undefined)
|
||||||
for (const key of keys) {
|
buffer = require('buffer').Buffer;
|
||||||
target[key] = source[key];
|
return buffer;
|
||||||
}
|
|
||||||
Object.defineProperty(target, 'message', { value: source.message });
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
function inspectValue(val) {
|
|
||||||
// The util.inspect default values could be changed. This makes sure the
|
|
||||||
// error messages contain the necessary information nevertheless.
|
|
||||||
return util.inspect(
|
|
||||||
val,
|
|
||||||
{
|
|
||||||
compact: false,
|
|
||||||
customInspect: false,
|
|
||||||
depth: 1000,
|
|
||||||
maxArrayLength: Infinity,
|
|
||||||
// Assert compares only enumerable properties (with a few exceptions).
|
|
||||||
showHidden: false,
|
|
||||||
// Having a long line as error is better than wrapping the line for
|
|
||||||
// comparison.
|
|
||||||
breakLength: Infinity,
|
|
||||||
// Assert does not detect proxies currently.
|
|
||||||
showProxy: false
|
|
||||||
}
|
|
||||||
).split('\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A specialized Error that includes an additional info property with
|
// A specialized Error that includes an additional info property with
|
||||||
@ -240,254 +204,14 @@ function E(sym, val, def, ...otherClasses) {
|
|||||||
codes[sym] = def;
|
codes[sym] = def;
|
||||||
}
|
}
|
||||||
|
|
||||||
function lazyBuffer() {
|
|
||||||
if (buffer === undefined)
|
|
||||||
buffer = require('buffer').Buffer;
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createErrDiff(actual, expected, operator) {
|
|
||||||
var other = '';
|
|
||||||
var res = '';
|
|
||||||
var lastPos = 0;
|
|
||||||
var end = '';
|
|
||||||
var skipped = false;
|
|
||||||
if (util === undefined) util = require('util');
|
|
||||||
const actualLines = inspectValue(actual);
|
|
||||||
const expectedLines = inspectValue(expected);
|
|
||||||
const msg = READABLE_OPERATOR[operator] +
|
|
||||||
`:\n${green}+ expected${white} ${red}- actual${white}`;
|
|
||||||
const skippedMsg = ` ${blue}...${white} 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();
|
|
||||||
if (actualLines.length === 0 || expectedLines.length === 0)
|
|
||||||
break;
|
|
||||||
a = actualLines[actualLines.length - 1];
|
|
||||||
b = expectedLines[expectedLines.length - 1];
|
|
||||||
}
|
|
||||||
if (i > 3) {
|
|
||||||
end = `\n${blue}...${white}${end}`;
|
|
||||||
skipped = true;
|
|
||||||
}
|
|
||||||
if (other !== '') {
|
|
||||||
end = `\n ${other}${end}`;
|
|
||||||
other = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxLines = Math.max(actualLines.length, expectedLines.length);
|
|
||||||
var printedLines = 0;
|
|
||||||
var identical = 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${blue}...${white}`;
|
|
||||||
skipped = true;
|
|
||||||
} else if (cur > 3) {
|
|
||||||
res += `\n ${expectedLines[i - 2]}`;
|
|
||||||
printedLines++;
|
|
||||||
}
|
|
||||||
res += `\n ${expectedLines[i - 1]}`;
|
|
||||||
printedLines++;
|
|
||||||
}
|
|
||||||
lastPos = i;
|
|
||||||
other += `\n${green}+${white} ${expectedLines[i]}`;
|
|
||||||
printedLines++;
|
|
||||||
// Only extra actual lines exist
|
|
||||||
} else if (expectedLines.length < i + 1) {
|
|
||||||
if (cur > 1 && i > 2) {
|
|
||||||
if (cur > 4) {
|
|
||||||
res += `\n${blue}...${white}`;
|
|
||||||
skipped = true;
|
|
||||||
} else if (cur > 3) {
|
|
||||||
res += `\n ${actualLines[i - 2]}`;
|
|
||||||
printedLines++;
|
|
||||||
}
|
|
||||||
res += `\n ${actualLines[i - 1]}`;
|
|
||||||
printedLines++;
|
|
||||||
}
|
|
||||||
lastPos = i;
|
|
||||||
res += `\n${red}-${white} ${actualLines[i]}`;
|
|
||||||
printedLines++;
|
|
||||||
// Lines diverge
|
|
||||||
} else if (actualLines[i] !== expectedLines[i]) {
|
|
||||||
if (cur > 1 && i > 2) {
|
|
||||||
if (cur > 4) {
|
|
||||||
res += `\n${blue}...${white}`;
|
|
||||||
skipped = true;
|
|
||||||
} else if (cur > 3) {
|
|
||||||
res += `\n ${actualLines[i - 2]}`;
|
|
||||||
printedLines++;
|
|
||||||
}
|
|
||||||
res += `\n ${actualLines[i - 1]}`;
|
|
||||||
printedLines++;
|
|
||||||
}
|
|
||||||
lastPos = i;
|
|
||||||
res += `\n${red}-${white} ${actualLines[i]}`;
|
|
||||||
other += `\n${green}+${white} ${expectedLines[i]}`;
|
|
||||||
printedLines += 2;
|
|
||||||
// Lines are identical
|
|
||||||
} else {
|
|
||||||
res += other;
|
|
||||||
other = '';
|
|
||||||
if (cur === 1 || i === 0) {
|
|
||||||
res += `\n ${actualLines[i]}`;
|
|
||||||
printedLines++;
|
|
||||||
}
|
|
||||||
identical++;
|
|
||||||
}
|
|
||||||
// Inspected object to big (Show ~20 rows max)
|
|
||||||
if (printedLines > 20 && i < maxLines - 2) {
|
|
||||||
return `${msg}${skippedMsg}\n${res}\n${blue}...${white}${other}\n` +
|
|
||||||
`${blue}...${white}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strict equal with identical objects that are not identical by reference.
|
|
||||||
if (identical === maxLines) {
|
|
||||||
// E.g., assert.deepStrictEqual(Symbol(), Symbol())
|
|
||||||
const base = operator === 'strictEqual' ?
|
|
||||||
'Input objects identical but not reference equal:' :
|
|
||||||
'Input objects not identical:';
|
|
||||||
|
|
||||||
// We have to get the result again. The lines were all removed before.
|
|
||||||
const actualLines = inspectValue(actual);
|
|
||||||
|
|
||||||
// Only remove lines in case it makes sense to collapse those.
|
|
||||||
// TODO: Accept env to always show the full error.
|
|
||||||
if (actualLines.length > 30) {
|
|
||||||
actualLines[26] = `${blue}...${white}`;
|
|
||||||
while (actualLines.length > 27) {
|
|
||||||
actualLines.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${base}\n\n${actualLines.join('\n')}\n`;
|
|
||||||
}
|
|
||||||
return `${msg}${skipped ? skippedMsg : ''}\n${res}${other}${end}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
class AssertionError extends Error {
|
|
||||||
constructor(options) {
|
|
||||||
if (typeof options !== 'object' || options === null) {
|
|
||||||
throw new codes.ERR_INVALID_ARG_TYPE('options', 'Object', options);
|
|
||||||
}
|
|
||||||
var {
|
|
||||||
actual,
|
|
||||||
expected,
|
|
||||||
message,
|
|
||||||
operator,
|
|
||||||
stackStartFn
|
|
||||||
} = options;
|
|
||||||
|
|
||||||
if (message != null) {
|
|
||||||
super(message);
|
|
||||||
} else {
|
|
||||||
if (process.stdout.isTTY) {
|
|
||||||
// Reset on each call to make sure we handle dynamically set environment
|
|
||||||
// variables correct.
|
|
||||||
if (process.stdout.getColorDepth() !== 1) {
|
|
||||||
blue = '\u001b[34m';
|
|
||||||
green = '\u001b[32m';
|
|
||||||
white = '\u001b[39m';
|
|
||||||
red = '\u001b[31m';
|
|
||||||
} else {
|
|
||||||
blue = '';
|
|
||||||
green = '';
|
|
||||||
white = '';
|
|
||||||
red = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (util === undefined) util = require('util');
|
|
||||||
// Prevent the error stack from being visible by duplicating the error
|
|
||||||
// in a very close way to the original in case both sides are actually
|
|
||||||
// instances of Error.
|
|
||||||
if (typeof actual === 'object' && actual !== null &&
|
|
||||||
typeof expected === 'object' && expected !== null &&
|
|
||||||
'stack' in actual && actual instanceof Error &&
|
|
||||||
'stack' in expected && expected instanceof Error) {
|
|
||||||
actual = copyError(actual);
|
|
||||||
expected = copyError(expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operator === 'deepStrictEqual' || operator === 'strictEqual') {
|
|
||||||
super(createErrDiff(actual, expected, operator));
|
|
||||||
} else if (operator === 'notDeepStrictEqual' ||
|
|
||||||
operator === 'notStrictEqual') {
|
|
||||||
// In case the objects are equal but the operator requires unequal, show
|
|
||||||
// the first object and say A equals B
|
|
||||||
const res = inspectValue(actual);
|
|
||||||
const base = `Identical input passed to ${operator}:`;
|
|
||||||
|
|
||||||
// Only remove lines in case it makes sense to collapse those.
|
|
||||||
// TODO: Accept env to always show the full error.
|
|
||||||
if (res.length > 30) {
|
|
||||||
res[26] = `${blue}...${white}`;
|
|
||||||
while (res.length > 27) {
|
|
||||||
res.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only print a single input.
|
|
||||||
if (res.length === 1) {
|
|
||||||
super(`${base} ${res[0]}`);
|
|
||||||
} else {
|
|
||||||
super(`${base}\n\n${res.join('\n')}\n`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.generatedMessage = !message;
|
|
||||||
this.name = 'AssertionError [ERR_ASSERTION]';
|
|
||||||
this.code = 'ERR_ASSERTION';
|
|
||||||
this.actual = actual;
|
|
||||||
this.expected = expected;
|
|
||||||
this.operator = operator;
|
|
||||||
Error.captureStackTrace(this, stackStartFn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is defined here instead of using the assert module to avoid a
|
|
||||||
// circular dependency. The effect is largely the same.
|
|
||||||
function internalAssert(condition, message) {
|
|
||||||
if (!condition) {
|
|
||||||
throw new AssertionError({
|
|
||||||
message,
|
|
||||||
actual: false,
|
|
||||||
expected: true,
|
|
||||||
operator: '=='
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMessage(key, args) {
|
function getMessage(key, args) {
|
||||||
const msg = messages.get(key);
|
const msg = messages.get(key);
|
||||||
|
|
||||||
if (util === undefined) util = require('util');
|
if (util === undefined) util = require('util');
|
||||||
|
if (assert === undefined) assert = require('assert');
|
||||||
|
|
||||||
if (typeof msg === 'function') {
|
if (typeof msg === 'function') {
|
||||||
internalAssert(
|
assert(
|
||||||
msg.length <= args.length, // Default options do not count.
|
msg.length <= args.length, // Default options do not count.
|
||||||
`Code: ${key}; The provided arguments length (${args.length}) does not ` +
|
`Code: ${key}; The provided arguments length (${args.length}) does not ` +
|
||||||
`match the required ones (${msg.length}).`
|
`match the required ones (${msg.length}).`
|
||||||
@ -496,7 +220,7 @@ function getMessage(key, args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const expectedLength = (msg.match(/%[dfijoOs]/g) || []).length;
|
const expectedLength = (msg.match(/%[dfijoOs]/g) || []).length;
|
||||||
internalAssert(
|
assert(
|
||||||
expectedLength === args.length,
|
expectedLength === args.length,
|
||||||
`Code: ${key}; The provided arguments length (${args.length}) does not ` +
|
`Code: ${key}; The provided arguments length (${args.length}) does not ` +
|
||||||
`match the required ones (${expectedLength}).`
|
`match the required ones (${expectedLength}).`
|
||||||
@ -690,11 +414,9 @@ module.exports = {
|
|||||||
uvException,
|
uvException,
|
||||||
isStackOverflowError,
|
isStackOverflowError,
|
||||||
getMessage,
|
getMessage,
|
||||||
AssertionError,
|
|
||||||
SystemError,
|
SystemError,
|
||||||
codes,
|
codes,
|
||||||
E, // This is exported only to facilitate testing.
|
E // This is exported only to facilitate testing.
|
||||||
errorCache: new Map() // This is in here only to facilitate testing.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// To declare an error message, use the E(sym, val, def) function above. The sym
|
// To declare an error message, use the E(sym, val, def) function above. The sym
|
||||||
@ -1038,7 +760,7 @@ E('ERR_VM_MODULE_STATUS', 'Module status %s', Error);
|
|||||||
E('ERR_ZLIB_INITIALIZATION_FAILED', 'Initialization failed', Error);
|
E('ERR_ZLIB_INITIALIZATION_FAILED', 'Initialization failed', Error);
|
||||||
|
|
||||||
function invalidArgType(name, expected, actual) {
|
function invalidArgType(name, expected, actual) {
|
||||||
internalAssert(typeof name === 'string', 'name must be a string');
|
assert(typeof name === 'string', "'name' must be a string");
|
||||||
|
|
||||||
// determiner: 'must be' or 'must not be'
|
// determiner: 'must be' or 'must not be'
|
||||||
let determiner;
|
let determiner;
|
||||||
@ -1064,7 +786,7 @@ function invalidArgType(name, expected, actual) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function missingArgs(...args) {
|
function missingArgs(...args) {
|
||||||
internalAssert(args.length > 0, 'At least one arg needs to be specified');
|
assert(args.length > 0, 'At least one arg needs to be specified');
|
||||||
let msg = 'The ';
|
let msg = 'The ';
|
||||||
const len = args.length;
|
const len = args.length;
|
||||||
args = args.map((a) => `"${a}"`);
|
args = args.map((a) => `"${a}"`);
|
||||||
@ -1084,11 +806,11 @@ function missingArgs(...args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function oneOf(expected, thing) {
|
function oneOf(expected, thing) {
|
||||||
internalAssert(typeof thing === 'string', '`thing` has to be of type string');
|
assert(typeof thing === 'string', '`thing` has to be of type string');
|
||||||
if (Array.isArray(expected)) {
|
if (Array.isArray(expected)) {
|
||||||
const len = expected.length;
|
const len = expected.length;
|
||||||
internalAssert(len > 0,
|
assert(len > 0,
|
||||||
'At least one expected value needs to be specified');
|
'At least one expected value needs to be specified');
|
||||||
expected = expected.map((i) => String(i));
|
expected = expected.map((i) => String(i));
|
||||||
if (len > 2) {
|
if (len > 2) {
|
||||||
return `one of ${thing} ${expected.slice(0, len - 1).join(', ')}, or ` +
|
return `one of ${thing} ${expected.slice(0, len - 1).join(', ')}, or ` +
|
||||||
|
1
node.gyp
1
node.gyp
@ -79,6 +79,7 @@
|
|||||||
'lib/v8.js',
|
'lib/v8.js',
|
||||||
'lib/vm.js',
|
'lib/vm.js',
|
||||||
'lib/zlib.js',
|
'lib/zlib.js',
|
||||||
|
'lib/internal/assert.js',
|
||||||
'lib/internal/async_hooks.js',
|
'lib/internal/async_hooks.js',
|
||||||
'lib/internal/buffer.js',
|
'lib/internal/buffer.js',
|
||||||
'lib/internal/cli_table.js',
|
'lib/internal/cli_table.js',
|
||||||
|
@ -29,7 +29,7 @@ const common = require('../common');
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const { EOL } = require('os');
|
const { EOL } = require('os');
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const { errorCache } = require('internal/errors');
|
const { errorCache } = require('internal/assert');
|
||||||
const { writeFileSync, unlinkSync } = require('fs');
|
const { writeFileSync, unlinkSync } = require('fs');
|
||||||
const { inspect } = require('util');
|
const { inspect } = require('util');
|
||||||
const a = assert;
|
const a = assert;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user