test: common.expectsError should be a must call

Wrap expectsError in mustCall to make sure it's really called
as expected.

PR-URL: https://github.com/nodejs/node/pull/14088
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
This commit is contained in:
Ruben Bridgewater 2017-07-05 15:04:24 +02:00 committed by Refael Ackermann
parent be20e9ecfe
commit 1b2733f272
No known key found for this signature in database
GPG Key ID: CD704BD80FDDDB64
18 changed files with 49 additions and 60 deletions

View File

@ -50,7 +50,7 @@ Platform normalizes the `dd` command
Check if there is more than 1gb of total memory. Check if there is more than 1gb of total memory.
### expectsError([fn, ]settings) ### expectsError([fn, ]settings[, exact])
* `fn` [&lt;Function>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) * `fn` [&lt;Function>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function)
* `settings` [&lt;Object>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) * `settings` [&lt;Object>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)
with the following optional properties: with the following optional properties:
@ -63,9 +63,12 @@ Check if there is more than 1gb of total memory.
if a string is provided for `message`, expected error must have it for its if a string is provided for `message`, expected error must have it for its
`message` property; if a regular expression is provided for `message`, the `message` property; if a regular expression is provided for `message`, the
regular expression must match the `message` property of the expected error regular expression must match the `message` property of the expected error
* `exact` [&lt;Number>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type) default = 1
* return function suitable for use as a validation function passed as the second * return function suitable for use as a validation function passed as the second
argument to `assert.throws()` argument to e.g. `assert.throws()`. If the returned function has not been called
exactly `exact` number of times when the test is complete, then the test will
fail.
If `fn` is provided, it will be passed to `assert.throws` as first argument. If `fn` is provided, it will be passed to `assert.throws` as first argument.
@ -217,7 +220,7 @@ Array of IPV6 hosts.
* return [&lt;Function>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) * return [&lt;Function>](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function)
Returns a function that calls `fn`. If the returned function has not been called Returns a function that calls `fn`. If the returned function has not been called
exactly `expected` number of times when the test is complete, then the test will exactly `exact` number of times when the test is complete, then the test will
fail. fail.
If `fn` is not provided, an empty function will be used. If `fn` is not provided, an empty function will be used.

View File

@ -488,7 +488,7 @@ exports.mustCallAtLeast = function(fn, minimum) {
return _mustCallInner(fn, minimum, 'minimum'); return _mustCallInner(fn, minimum, 'minimum');
}; };
function _mustCallInner(fn, criteria, field) { function _mustCallInner(fn, criteria = 1, field) {
if (typeof fn === 'number') { if (typeof fn === 'number') {
criteria = fn; criteria = fn;
fn = noop; fn = noop;
@ -496,9 +496,7 @@ function _mustCallInner(fn, criteria, field) {
fn = noop; fn = noop;
} }
if (criteria === undefined) if (typeof criteria !== 'number')
criteria = 1;
else if (typeof criteria !== 'number')
throw new TypeError(`Invalid ${field} value: ${criteria}`); throw new TypeError(`Invalid ${field} value: ${criteria}`);
const context = { const context = {
@ -702,13 +700,14 @@ Object.defineProperty(exports, 'hasSmallICU', {
}); });
// Useful for testing expected internal/error objects // Useful for testing expected internal/error objects
exports.expectsError = function expectsError(fn, options) { exports.expectsError = function expectsError(fn, options, exact) {
if (typeof fn !== 'function') { if (typeof fn !== 'function') {
exact = options;
options = fn; options = fn;
fn = undefined; fn = undefined;
} }
const { code, type, message } = options; const { code, type, message } = options;
function innerFn(error) { const innerFn = exports.mustCall(function(error) {
assert.strictEqual(error.code, code); assert.strictEqual(error.code, code);
if (type !== undefined) { if (type !== undefined) {
assert(error instanceof type, assert(error instanceof type,
@ -721,7 +720,7 @@ exports.expectsError = function expectsError(fn, options) {
assert.strictEqual(error.message, message); assert.strictEqual(error.message, message);
} }
return true; return true;
} }, exact);
if (fn) { if (fn) {
assert.throws(fn, innerFn); assert.throws(fn, innerFn);
return; return;

View File

@ -153,11 +153,7 @@ assert.throws(makeBlock(a.deepEqual, /a/igm, /a/im),
{ {
const re1 = /a/g; const re1 = /a/g;
re1.lastIndex = 3; re1.lastIndex = 3;
assert.doesNotThrow(makeBlock(a.deepEqual, re1, /a/g), assert.doesNotThrow(makeBlock(a.deepEqual, re1, /a/g));
common.expectsError({
code: 'ERR_ASSERTION',
message: /^\/a\/g deepEqual \/a\/g$/
}));
} }
assert.doesNotThrow(makeBlock(a.deepEqual, 4, '4'), 'deepEqual(4, \'4\')'); assert.doesNotThrow(makeBlock(a.deepEqual, 4, '4'), 'deepEqual(4, \'4\')');

View File

@ -57,7 +57,7 @@ assert.strictEqual(1, a.compare(b, Infinity, -Infinity));
// zero length target because default for targetEnd <= targetSource // zero length target because default for targetEnd <= targetSource
assert.strictEqual(1, a.compare(b, '0xff')); assert.strictEqual(1, a.compare(b, '0xff'));
const oor = common.expectsError({code: 'ERR_INDEX_OUT_OF_RANGE'}); const oor = common.expectsError({code: 'ERR_INDEX_OUT_OF_RANGE'}, 7);
assert.throws(() => a.compare(b, 0, 100, 0), oor); assert.throws(() => a.compare(b, 0, 100, 0), oor);
assert.throws(() => a.compare(b, 0, 1, 0, 100), oor); assert.throws(() => a.compare(b, 0, 1, 0, 100), oor);

View File

@ -14,9 +14,9 @@ child.on('close', common.mustCall((code, signal) => {
type: Error, type: Error,
message: 'Channel closed', message: 'Channel closed',
code: 'ERR_IPC_CHANNEL_CLOSED' code: 'ERR_IPC_CHANNEL_CLOSED'
}); }, 2);
child.on('error', common.mustCall(testError)); child.on('error', testError);
{ {
const result = child.send('ping'); const result = child.send('ping');
@ -24,7 +24,7 @@ child.on('close', common.mustCall((code, signal) => {
} }
{ {
const result = child.send('pong', common.mustCall(testError)); const result = child.send('pong', testError);
assert.strictEqual(result, false); assert.strictEqual(result, false);
} }
})); }));

View File

@ -186,7 +186,7 @@ if (!common.isWindows) {
// Validate the killSignal option // Validate the killSignal option
const typeErr = /^TypeError: "killSignal" must be a string or number$/; const typeErr = /^TypeError: "killSignal" must be a string or number$/;
const unknownSignalErr = const unknownSignalErr =
common.expectsError({ code: 'ERR_UNKNOWN_SIGNAL', type: TypeError }); common.expectsError({ code: 'ERR_UNKNOWN_SIGNAL', type: TypeError }, 17);
pass('killSignal', undefined); pass('killSignal', undefined);
pass('killSignal', null); pass('killSignal', null);

View File

@ -6,7 +6,7 @@ const assert = require('assert');
const _validateStdio = require('internal/child_process')._validateStdio; const _validateStdio = require('internal/child_process')._validateStdio;
const expectedError = const expectedError =
common.expectsError({code: 'ERR_INVALID_OPT_VALUE', type: TypeError}); common.expectsError({code: 'ERR_INVALID_OPT_VALUE', type: TypeError}, 2);
// should throw if string and not ignore, pipe, or inherit // should throw if string and not ignore, pipe, or inherit
assert.throws(() => _validateStdio('foo'), expectedError); assert.throws(() => _validateStdio('foo'), expectedError);

View File

@ -28,12 +28,10 @@ fs.readFile(url, common.mustCall((err, data) => {
// Check that using a non file:// URL reports an error // Check that using a non file:// URL reports an error
const httpUrl = new URL('http://example.org'); const httpUrl = new URL('http://example.org');
fs.readFile(httpUrl, common.mustCall((err) => { fs.readFile(httpUrl, common.expectsError({
common.expectsError({ code: 'ERR_INVALID_URL_SCHEME',
code: 'ERR_INVALID_URL_SCHEME', type: TypeError,
type: TypeError, message: 'The URL must be of scheme file'
message: 'The URL must be of scheme file'
})(err);
})); }));
// pct-encoded characters in the path will be decoded and checked // pct-encoded characters in the path will be decoded and checked
@ -46,31 +44,25 @@ fs.readFile(new URL('file:///c:/tmp/%00test'), common.mustCall((err) => {
if (common.isWindows) { if (common.isWindows) {
// encoded back and forward slashes are not permitted on windows // encoded back and forward slashes are not permitted on windows
['%2f', '%2F', '%5c', '%5C'].forEach((i) => { ['%2f', '%2F', '%5c', '%5C'].forEach((i) => {
fs.readFile(new URL(`file:///c:/tmp/${i}`), common.mustCall((err) => { fs.readFile(new URL(`file:///c:/tmp/${i}`), common.expectsError({
common.expectsError({ code: 'ERR_INVALID_FILE_URL_PATH',
code: 'ERR_INVALID_FILE_URL_PATH', type: TypeError,
type: TypeError, message: 'File URL path must not include encoded \\ or / characters'
message: 'File URL path must not include encoded \\ or / characters'
})(err);
})); }));
}); });
} else { } else {
// encoded forward slashes are not permitted on other platforms // encoded forward slashes are not permitted on other platforms
['%2f', '%2F'].forEach((i) => { ['%2f', '%2F'].forEach((i) => {
fs.readFile(new URL(`file:///c:/tmp/${i}`), common.mustCall((err) => { fs.readFile(new URL(`file:///c:/tmp/${i}`), common.expectsError({
common.expectsError({ code: 'ERR_INVALID_FILE_URL_PATH',
code: 'ERR_INVALID_FILE_URL_PATH', type: TypeError,
type: TypeError, message: 'File URL path must not include encoded / characters'
message: 'File URL path must not include encoded / characters'
})(err);
})); }));
}); });
fs.readFile(new URL('file://hostname/a/b/c'), common.mustCall((err) => { fs.readFile(new URL('file://hostname/a/b/c'), common.expectsError({
common.expectsError({ code: 'ERR_INVALID_FILE_URL_HOST',
code: 'ERR_INVALID_FILE_URL_HOST', type: TypeError,
type: TypeError, message: `File URL host must be "localhost" or empty on ${os.platform()}`
message: `File URL host must be "localhost" or empty on ${os.platform()}`
})(err);
})); }));
} }

View File

@ -4,12 +4,11 @@ const common = require('../common');
const assert = require('assert'); const assert = require('assert');
const util = require('internal/util'); const util = require('internal/util');
const expectedError = common.expectsError({
code: 'ERR_NO_CRYPTO',
type: Error
});
if (!process.versions.openssl) { if (!process.versions.openssl) {
const expectedError = common.expectsError({
code: 'ERR_NO_CRYPTO',
type: Error
});
assert.throws(() => util.assertCrypto(), expectedError); assert.throws(() => util.assertCrypto(), expectedError);
} else { } else {
assert.doesNotThrow(() => util.assertCrypto()); assert.doesNotThrow(() => util.assertCrypto());

View File

@ -91,7 +91,7 @@ const unixSpecialCaseFormatTests = [
const expectedMessage = common.expectsError({ const expectedMessage = common.expectsError({
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError type: TypeError
}); }, 18);
const errors = [ const errors = [
{method: 'parse', input: [null], message: expectedMessage}, {method: 'parse', input: [null], message: expectedMessage},

View File

@ -35,13 +35,13 @@ const invalidUserArgument = common.expectsError({
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, type: TypeError,
message: 'The "preValue.user" property must be of type Number' message: 'The "preValue.user" property must be of type Number'
}); }, 8);
const invalidSystemArgument = common.expectsError({ const invalidSystemArgument = common.expectsError({
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, type: TypeError,
message: 'The "preValue.system" property must be of type Number' message: 'The "preValue.system" property must be of type Number'
}); }, 2);
// Ensure that an invalid shape for the previous value argument throws an error. // Ensure that an invalid shape for the previous value argument throws an error.

View File

@ -58,7 +58,7 @@ warningThrowToString.toString = function() {
process.emitWarning(warningThrowToString); process.emitWarning(warningThrowToString);
const expectedError = const expectedError =
common.expectsError({code: 'ERR_INVALID_ARG_TYPE', type: TypeError}); common.expectsError({code: 'ERR_INVALID_ARG_TYPE', type: TypeError}, 11);
// TypeError is thrown on invalid input // TypeError is thrown on invalid input
assert.throws(() => process.emitWarning(1), expectedError); assert.throws(() => process.emitWarning(1), expectedError);

View File

@ -42,7 +42,7 @@ const invalidPidArgument = common.expectsError({
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, type: TypeError,
message: 'The "pid" argument must be of type Number' message: 'The "pid" argument must be of type Number'
}); }, 6);
assert.throws(function() { process.kill('SIGTERM'); }, assert.throws(function() { process.kill('SIGTERM'); },
invalidPidArgument); invalidPidArgument);

View File

@ -25,7 +25,7 @@ assert.strictEqual(
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, type: TypeError,
message: 'The "options" argument must be of type object' message: 'The "options" argument must be of type object'
}); }, 4);
assert.throws(() => url.format(myURL, true), expectedErr); assert.throws(() => url.format(myURL, true), expectedErr);
assert.throws(() => url.format(myURL, 1), expectedErr); assert.throws(() => url.format(myURL, 1), expectedErr);
assert.throws(() => url.format(myURL, 'test'), expectedErr); assert.throws(() => url.format(myURL, 'test'), expectedErr);

View File

@ -13,7 +13,7 @@ const wptToASCIITests = require('../fixtures/url-toascii.js');
{ {
const expectedError = common.expectsError( const expectedError = common.expectsError(
{ code: 'ERR_MISSING_ARGS', type: TypeError }); { code: 'ERR_MISSING_ARGS', type: TypeError }, 2);
assert.throws(() => domainToASCII(), expectedError); assert.throws(() => domainToASCII(), expectedError);
assert.throws(() => domainToUnicode(), expectedError); assert.throws(() => domainToUnicode(), expectedError);
assert.strictEqual(domainToASCII(undefined), 'undefined'); assert.strictEqual(domainToASCII(undefined), 'undefined');

View File

@ -26,7 +26,7 @@ const failureTests = tests.filter((test) => test.failure).concat([
]); ]);
const expectedError = common.expectsError( const expectedError = common.expectsError(
{ code: 'ERR_INVALID_URL', type: TypeError }); { code: 'ERR_INVALID_URL', type: TypeError }, 102);
for (const test of failureTests) { for (const test of failureTests) {
assert.throws( assert.throws(

View File

@ -209,7 +209,7 @@ function makeIterableFunc(array) {
code: 'ERR_INVALID_TUPLE', code: 'ERR_INVALID_TUPLE',
type: TypeError, type: TypeError,
message: 'Each query pair must be an iterable [name, value] tuple' message: 'Each query pair must be an iterable [name, value] tuple'
}); }, 6);
let params; let params;
params = new URLSearchParams(undefined); params = new URLSearchParams(undefined);

View File

@ -76,7 +76,7 @@ sp.forEach(function() {
const callbackErr = common.expectsError({ const callbackErr = common.expectsError({
code: 'ERR_INVALID_CALLBACK', code: 'ERR_INVALID_CALLBACK',
type: TypeError type: TypeError
}); }, 2);
assert.throws(() => sp.forEach(), callbackErr); assert.throws(() => sp.forEach(), callbackErr);
assert.throws(() => sp.forEach(1), callbackErr); assert.throws(() => sp.forEach(1), callbackErr);
} }