bigint-crypto-utils/node_modules/mocha/lib/reporters/base.js

524 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use strict';
/**
* @module Base
*/
/**
* Module dependencies.
*/
var tty = require('tty');
var diff = require('diff');
var milliseconds = require('ms');
var utils = require('../utils');
var supportsColor = process.browser ? null : require('supports-color');
var constants = require('../runner').constants;
var EVENT_TEST_PASS = constants.EVENT_TEST_PASS;
var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL;
/**
* Expose `Base`.
*/
exports = module.exports = Base;
/**
* Check if both stdio streams are associated with a tty.
*/
var isatty = process.stdout.isTTY && process.stderr.isTTY;
/**
* Save log references to avoid tests interfering (see GH-3604).
*/
var consoleLog = console.log;
/**
* Enable coloring by default, except in the browser interface.
*/
exports.useColors =
!process.browser &&
(supportsColor.stdout || process.env.MOCHA_COLORS !== undefined);
/**
* Inline diffs instead of +/-
*/
exports.inlineDiffs = false;
/**
* Default color map.
*/
exports.colors = {
pass: 90,
fail: 31,
'bright pass': 92,
'bright fail': 91,
'bright yellow': 93,
pending: 36,
suite: 0,
'error title': 0,
'error message': 31,
'error stack': 90,
checkmark: 32,
fast: 90,
medium: 33,
slow: 31,
green: 32,
light: 90,
'diff gutter': 90,
'diff added': 32,
'diff removed': 31
};
/**
* Default symbol map.
*/
exports.symbols = {
ok: '✓',
err: '✖',
dot: '',
comma: ',',
bang: '!'
};
// With node.js on Windows: use symbols available in terminal default fonts
if (process.platform === 'win32') {
exports.symbols.ok = '\u221A';
exports.symbols.err = '\u00D7';
exports.symbols.dot = '.';
}
/**
* Color `str` with the given `type`,
* allowing colors to be disabled,
* as well as user-defined color
* schemes.
*
* @private
* @param {string} type
* @param {string} str
* @return {string}
*/
var color = (exports.color = function(type, str) {
if (!exports.useColors) {
return String(str);
}
return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
});
/**
* Expose term window size, with some defaults for when stderr is not a tty.
*/
exports.window = {
width: 75
};
if (isatty) {
exports.window.width = process.stdout.getWindowSize
? process.stdout.getWindowSize(1)[0]
: tty.getWindowSize()[1];
}
/**
* Expose some basic cursor interactions that are common among reporters.
*/
exports.cursor = {
hide: function() {
isatty && process.stdout.write('\u001b[?25l');
},
show: function() {
isatty && process.stdout.write('\u001b[?25h');
},
deleteLine: function() {
isatty && process.stdout.write('\u001b[2K');
},
beginningOfLine: function() {
isatty && process.stdout.write('\u001b[0G');
},
CR: function() {
if (isatty) {
exports.cursor.deleteLine();
exports.cursor.beginningOfLine();
} else {
process.stdout.write('\r');
}
}
};
var showDiff = (exports.showDiff = function(err) {
return (
err &&
err.showDiff !== false &&
sameType(err.actual, err.expected) &&
err.expected !== undefined
);
});
function stringifyDiffObjs(err) {
if (!utils.isString(err.actual) || !utils.isString(err.expected)) {
err.actual = utils.stringify(err.actual);
err.expected = utils.stringify(err.expected);
}
}
/**
* Returns a diff between 2 strings with coloured ANSI output.
*
* @description
* The diff will be either inline or unified dependent on the value
* of `Base.inlineDiff`.
*
* @param {string} actual
* @param {string} expected
* @return {string} Diff
*/
var generateDiff = (exports.generateDiff = function(actual, expected) {
try {
return exports.inlineDiffs
? inlineDiff(actual, expected)
: unifiedDiff(actual, expected);
} catch (err) {
var msg =
'\n ' +
color('diff added', '+ expected') +
' ' +
color('diff removed', '- actual: failed to generate Mocha diff') +
'\n';
return msg;
}
});
/**
* Outputs the given `failures` as a list.
*
* @public
* @memberof Mocha.reporters.Base
* @variation 1
* @param {Object[]} failures - Each is Test instance with corresponding
* Error property
*/
exports.list = function(failures) {
var multipleErr, multipleTest;
Base.consoleLog();
failures.forEach(function(test, i) {
// format
var fmt =
color('error title', ' %s) %s:\n') +
color('error message', ' %s') +
color('error stack', '\n%s\n');
// msg
var msg;
var err;
if (test.err && test.err.multiple) {
if (multipleTest !== test) {
multipleTest = test;
multipleErr = [test.err].concat(test.err.multiple);
}
err = multipleErr.shift();
} else {
err = test.err;
}
var message;
if (err.message && typeof err.message.toString === 'function') {
message = err.message + '';
} else if (typeof err.inspect === 'function') {
message = err.inspect() + '';
} else {
message = '';
}
var stack = err.stack || message;
var index = message ? stack.indexOf(message) : -1;
if (index === -1) {
msg = message;
} else {
index += message.length;
msg = stack.slice(0, index);
// remove msg from stack
stack = stack.slice(index + 1);
}
// uncaught
if (err.uncaught) {
msg = 'Uncaught ' + msg;
}
// explicitly show diff
if (!exports.hideDiff && showDiff(err)) {
stringifyDiffObjs(err);
fmt =
color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n');
var match = message.match(/^([^:]+): expected/);
msg = '\n ' + color('error message', match ? match[1] : msg);
msg += generateDiff(err.actual, err.expected);
}
// indent stack trace
stack = stack.replace(/^/gm, ' ');
// indented test title
var testTitle = '';
test.titlePath().forEach(function(str, index) {
if (index !== 0) {
testTitle += '\n ';
}
for (var i = 0; i < index; i++) {
testTitle += ' ';
}
testTitle += str;
});
Base.consoleLog(fmt, i + 1, testTitle, msg, stack);
});
};
/**
* Constructs a new `Base` reporter instance.
*
* @description
* All other reporters generally inherit from this reporter.
*
* @public
* @class
* @memberof Mocha.reporters
* @param {Runner} runner - Instance triggers reporter actions.
* @param {Object} [options] - runner options
*/
function Base(runner, options) {
var failures = (this.failures = []);
if (!runner) {
throw new TypeError('Missing runner argument');
}
this.options = options || {};
this.runner = runner;
this.stats = runner.stats; // assigned so Reporters keep a closer reference
runner.on(EVENT_TEST_PASS, function(test) {
if (test.duration > test.slow()) {
test.speed = 'slow';
} else if (test.duration > test.slow() / 2) {
test.speed = 'medium';
} else {
test.speed = 'fast';
}
});
runner.on(EVENT_TEST_FAIL, function(test, err) {
if (showDiff(err)) {
stringifyDiffObjs(err);
}
// more than one error per test
if (test.err && err instanceof Error) {
test.err.multiple = (test.err.multiple || []).concat(err);
} else {
test.err = err;
}
failures.push(test);
});
}
/**
* Outputs common epilogue used by many of the bundled reporters.
*
* @public
* @memberof Mocha.reporters
*/
Base.prototype.epilogue = function() {
var stats = this.stats;
var fmt;
Base.consoleLog();
// passes
fmt =
color('bright pass', ' ') +
color('green', ' %d passing') +
color('light', ' (%s)');
Base.consoleLog(fmt, stats.passes || 0, milliseconds(stats.duration));
// pending
if (stats.pending) {
fmt = color('pending', ' ') + color('pending', ' %d pending');
Base.consoleLog(fmt, stats.pending);
}
// failures
if (stats.failures) {
fmt = color('fail', ' %d failing');
Base.consoleLog(fmt, stats.failures);
Base.list(this.failures);
Base.consoleLog();
}
Base.consoleLog();
};
/**
* Pads the given `str` to `len`.
*
* @private
* @param {string} str
* @param {string} len
* @return {string}
*/
function pad(str, len) {
str = String(str);
return Array(len - str.length + 1).join(' ') + str;
}
/**
* Returns inline diff between 2 strings with coloured ANSI output.
*
* @private
* @param {String} actual
* @param {String} expected
* @return {string} Diff
*/
function inlineDiff(actual, expected) {
var msg = errorDiff(actual, expected);
// linenos
var lines = msg.split('\n');
if (lines.length > 4) {
var width = String(lines.length).length;
msg = lines
.map(function(str, i) {
return pad(++i, width) + ' |' + ' ' + str;
})
.join('\n');
}
// legend
msg =
'\n' +
color('diff removed', 'actual') +
' ' +
color('diff added', 'expected') +
'\n\n' +
msg +
'\n';
// indent
msg = msg.replace(/^/gm, ' ');
return msg;
}
/**
* Returns unified diff between two strings with coloured ANSI output.
*
* @private
* @param {String} actual
* @param {String} expected
* @return {string} The diff.
*/
function unifiedDiff(actual, expected) {
var indent = ' ';
function cleanUp(line) {
if (line[0] === '+') {
return indent + colorLines('diff added', line);
}
if (line[0] === '-') {
return indent + colorLines('diff removed', line);
}
if (line.match(/@@/)) {
return '--';
}
if (line.match(/\\ No newline/)) {
return null;
}
return indent + line;
}
function notBlank(line) {
return typeof line !== 'undefined' && line !== null;
}
var msg = diff.createPatch('string', actual, expected);
var lines = msg.split('\n').splice(5);
return (
'\n ' +
colorLines('diff added', '+ expected') +
' ' +
colorLines('diff removed', '- actual') +
'\n\n' +
lines
.map(cleanUp)
.filter(notBlank)
.join('\n')
);
}
/**
* Returns character diff for `err`.
*
* @private
* @param {String} actual
* @param {String} expected
* @return {string} the diff
*/
function errorDiff(actual, expected) {
return diff
.diffWordsWithSpace(actual, expected)
.map(function(str) {
if (str.added) {
return colorLines('diff added', str.value);
}
if (str.removed) {
return colorLines('diff removed', str.value);
}
return str.value;
})
.join('');
}
/**
* Colors lines for `str`, using the color `name`.
*
* @private
* @param {string} name
* @param {string} str
* @return {string}
*/
function colorLines(name, str) {
return str
.split('\n')
.map(function(str) {
return color(name, str);
})
.join('\n');
}
/**
* Object#toString reference.
*/
var objToString = Object.prototype.toString;
/**
* Checks that a / b have the same type.
*
* @private
* @param {Object} a
* @param {Object} b
* @return {boolean}
*/
function sameType(a, b) {
return objToString.call(a) === objToString.call(b);
}
Base.consoleLog = consoleLog;
Base.abstract = true;