Skip to content

Commit

Permalink
[Fix] throws: fix crash when throwing primitives with a non-empty e…
Browse files Browse the repository at this point in the history
…xpected object
  • Loading branch information
ljharb committed Jan 27, 2024
1 parent 9133c93 commit 1b2681d
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 15 deletions.
34 changes: 19 additions & 15 deletions lib/test.js
Expand Up @@ -838,22 +838,26 @@ Test.prototype['throws'] = function (fn, expected, msg, extra) {
passed = $exec(expected, caught.error) !== null;
expected = inspect(expected);
} else if (expected && typeof expected === 'object') { // Handle validation objects.
var keys = objectKeys(expected);
// Special handle errors to make sure the name and the message are compared as well.
if (expected instanceof Error) {
$push(keys, 'name', 'message');
} else if (keys.length === 0) {
throw new TypeError('`throws` validation object must not be empty');
}
passed = every(keys, function (key) {
if (typeof caught.error[key] === 'string' && isRegExp(expected[key]) && $exec(expected[key], caught.error[key]) !== null) {
return true;
}
if (key in caught.error && deepEqual(caught.error[key], expected[key], { strict: true })) {
return true;
if (caught.error && typeof caught.error === 'object') {
var keys = objectKeys(expected);
// Special handle errors to make sure the name and the message are compared as well.
if (expected instanceof Error) {
$push(keys, 'name', 'message');
} else if (keys.length === 0) {
throw new TypeError('`throws` validation object must not be empty');
}
return false;
});
passed = every(keys, function (key) {
if (typeof caught.error[key] === 'string' && isRegExp(expected[key]) && $exec(expected[key], caught.error[key]) !== null) {
return true;
}
if (key in caught.error && deepEqual(caught.error[key], expected[key], { strict: true })) {
return true;
}
return false;
});
} else {
passed = false;
}
}
}

Expand Down
98 changes: 98 additions & 0 deletions test/throws.js
Expand Up @@ -84,15 +84,112 @@ tap.test('failures', function (tt) {
'ok ' + ++count + ' unexpected error',
'# throwing primitives',
'ok ' + ++count + ' primitive: null, no expected',
'not ok ' + ++count + ' primitive: null, with non-empty expected object',
' ---',
' operator: throws',
' expected: |-',
' { a: \'b\' }',
' actual: |-',
' null',
' at: <anonymous> ($TEST/throws.js:$LINE:$COL)',
' ...',
'ok ' + ++count + ' primitive: undefined, no expected',
'not ok ' + ++count + ' primitive: undefined, with non-empty expected object',
' ---',
' operator: throws',
' expected: |-',
' { a: \'b\' }',
' actual: |-',
' undefined',
' at: <anonymous> ($TEST/throws.js:$LINE:$COL)',
' stack: |-',
' Error: primitive: undefined, with non-empty expected object',
' [... stack stripped ...]',
' at $TEST/throws.js:$LINE:$COL',
' [... stack stripped ...]',
' at Test.<anonymous> ($TEST/throws.js:$LINE:$COL)',
' [... stack stripped ...]',
' ...',
'ok ' + ++count + ' primitive: 0, no expected',
'not ok ' + ++count + ' primitive: 0, with non-empty expected object',
' ---',
' operator: throws',
' expected: |-',
' { a: \'b\' }',
' actual: |-',
' 0',
' at: <anonymous> ($TEST/throws.js:$LINE:$COL)',
' ...',
'ok ' + ++count + ' primitive: NaN, no expected',
'not ok ' + ++count + ' primitive: NaN, with non-empty expected object',
' ---',
' operator: throws',
' expected: |-',
' { a: \'b\' }',
' actual: |-',
' NaN',
' at: <anonymous> ($TEST/throws.js:$LINE:$COL)',
' ...',
'ok ' + ++count + ' primitive: 42, no expected',
'not ok ' + ++count + ' primitive: 42, with non-empty expected object',
' ---',
' operator: throws',
' expected: |-',
' { a: \'b\' }',
' actual: |-',
' 42',
' at: <anonymous> ($TEST/throws.js:$LINE:$COL)',
' ...',
'ok ' + ++count + ' primitive: Infinity, no expected',
'not ok ' + ++count + ' primitive: Infinity, with non-empty expected object',
' ---',
' operator: throws',
' expected: |-',
' { a: \'b\' }',
' actual: |-',
' Infinity',
' at: <anonymous> ($TEST/throws.js:$LINE:$COL)',
' ...',
'ok ' + ++count + ' primitive: \'\', no expected',
'not ok ' + ++count + ' primitive: \'\', with non-empty expected object',
' ---',
' operator: throws',
' expected: |-',
' { a: \'b\' }',
' actual: |-',
' \'\'',
' at: <anonymous> ($TEST/throws.js:$LINE:$COL)',
' ...',
'ok ' + ++count + ' primitive: \'foo\', no expected',
'not ok ' + ++count + ' primitive: \'foo\', with non-empty expected object',
' ---',
' operator: throws',
' expected: |-',
' { a: \'b\' }',
' actual: |-',
' \'foo\'',
' at: <anonymous> ($TEST/throws.js:$LINE:$COL)',
' ...',
'ok ' + ++count + ' primitive: true, no expected',
'not ok ' + ++count + ' primitive: true, with non-empty expected object',
' ---',
' operator: throws',
' expected: |-',
' { a: \'b\' }',
' actual: |-',
' true',
' at: <anonymous> ($TEST/throws.js:$LINE:$COL)',
' ...',
'ok ' + ++count + ' primitive: false, no expected',
'not ok ' + ++count + ' primitive: false, with non-empty expected object',
' ---',
' operator: throws',
' expected: |-',
' { a: \'b\' }',
' actual: |-',
' false',
' at: <anonymous> ($TEST/throws.js:$LINE:$COL)',
' ...',
'# ambiguous arguments',
'ok ' + ++count + ' Second',
'ok ' + ++count + ' Second',
Expand Down Expand Up @@ -283,6 +380,7 @@ tap.test('failures', function (tt) {
test('throwing primitives', function (t) {
[null, undefined, 0, NaN, 42, Infinity, '', 'foo', true, false].forEach(function (primitive) {
t.throws(function () { throw primitive; }, 'primitive: ' + inspect(primitive) + ', no expected');
t.throws(function () { throw primitive; }, { a: 'b' }, 'primitive: ' + inspect(primitive) + ', with non-empty expected object');
});

t.end();
Expand Down

0 comments on commit 1b2681d

Please sign in to comment.