From 2380533d73619fda6f08cdf468d77cd85bebfdcc Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Wed, 6 Nov 2024 01:33:10 +0100 Subject: [PATCH 1/3] assert: differentiate cases where `cause` is `undefined` or missing --- lib/internal/assert/assertion_error.js | 5 +-- lib/internal/util/comparisons.js | 9 +++-- test/parallel/test-assert-deep-with-error.js | 35 ++++++++++++++++++++ 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/lib/internal/assert/assertion_error.js b/lib/internal/assert/assertion_error.js index 5b4124e6b29700..d036248e45755e 100644 --- a/lib/internal/assert/assertion_error.js +++ b/lib/internal/assert/assertion_error.js @@ -9,6 +9,7 @@ const { ObjectAssign, ObjectDefineProperty, ObjectGetPrototypeOf, + ObjectPrototypeHasOwnProperty, String, StringPrototypeRepeat, StringPrototypeSlice, @@ -49,8 +50,8 @@ function copyError(source) { __proto__: null, value: source.message, }); - if (source.cause !== undefined) { - let cause = source.cause; + if (ObjectPrototypeHasOwnProperty(source, 'cause')) { + let { cause } = source; if (isError(cause)) { cause = copyError(cause); diff --git a/lib/internal/util/comparisons.js b/lib/internal/util/comparisons.js index b28860e9000ce8..554e513b96e9fe 100644 --- a/lib/internal/util/comparisons.js +++ b/lib/internal/util/comparisons.js @@ -28,6 +28,7 @@ const { const { compare } = internalBinding('buffer'); const assert = require('internal/assert'); const { isURL } = require('internal/url'); +const { isError } = require('internal/util'); const types = require('internal/util/types'); const { isAnyArrayBuffer, @@ -235,10 +236,10 @@ function innerDeepEqual(val1, val2, strict, memos) { if (!isAnyArrayBuffer(val2) || !areEqualArrayBuffers(val1, val2)) { return false; } - } else if (isNativeError(val1) || val1 instanceof Error) { + } else if (isError(val1)) { // Do not compare the stack as it might differ even though the error itself // is otherwise identical. - if (!isNativeError(val2) && !(val2 instanceof Error)) { + if (!isError(val2)) { return false; } @@ -252,7 +253,9 @@ function innerDeepEqual(val1, val2, strict, memos) { (name1Enumerable !== ObjectPrototypePropertyIsEnumerable(val2, 'name') || (!name1Enumerable && val1.name !== val2.name)) || (cause1Enumerable !== ObjectPrototypePropertyIsEnumerable(val2, 'cause') || - (!cause1Enumerable && !innerDeepEqual(val1.cause, val2.cause, strict, memos))) || + (!cause1Enumerable && ( + ObjectPrototypeHasOwnProperty(val1, 'cause') !== ObjectPrototypeHasOwnProperty(val2, 'cause') || + !innerDeepEqual(val1.cause, val2.cause, strict, memos)))) || (errors1Enumerable !== ObjectPrototypePropertyIsEnumerable(val2, 'errors') || (!errors1Enumerable && !innerDeepEqual(val1.errors, val2.errors, strict, memos)))) { return false; diff --git a/test/parallel/test-assert-deep-with-error.js b/test/parallel/test-assert-deep-with-error.js index b4186eb642302d..c83c4d60317070 100644 --- a/test/parallel/test-assert-deep-with-error.js +++ b/test/parallel/test-assert-deep-with-error.js @@ -15,6 +15,13 @@ test('Handle error causes', () => { '- [cause]: [Error: y]\n' + ' }\n' }); + assert.throws(() => { + assert.deepStrictEqual(new Error('a', { cause: new Error('x') }), new Error('a', { cause: new TypeError('x') })); + }, { message: defaultStartMessage + ' [Error: a] {\n' + + '+ [cause]: [Error: x]\n' + + '- [cause]: [TypeError: x]\n' + + ' }\n' }); + assert.throws(() => { assert.deepStrictEqual(new Error('a'), new Error('a', { cause: new Error('y') })); }, { message: defaultStartMessage + '+ [Error: a]\n' + @@ -37,3 +44,31 @@ test('Handle error causes', () => { new Error('a', { cause: { prop: 'a different value' } }) ); }); + +test('Handle undefined causes', () => { + assert.notDeepStrictEqual(new Error('a', { cause: 'undefined' }), new Error('a', { cause: undefined })); + assert.notDeepStrictEqual(new Error('a', { cause: undefined }), new Error('a')); + assert.notDeepStrictEqual(new Error('a'), new Error('a', { cause: undefined })); + + assert.throws(() => { + assert.deepStrictEqual(new Error('a'), new Error('a', { cause: undefined })); + }, { message: defaultStartMessage + + '+ [Error: a]\n' + + '- [Error: a] {\n' + + '- [cause]: undefined\n' + + '- }\n' }); + + assert.throws(() => { + assert.deepStrictEqual(new Error('a', { cause: undefined }), new Error('a')); + }, { message: defaultStartMessage + + '+ [Error: a] {\n' + + '+ [cause]: undefined\n' + + '+ }\n' + + '- [Error: a]\n' }); + assert.throws(() => { + assert.deepStrictEqual(new Error('a', { cause: undefined }), new Error('a', { cause: 'undefined' })); + }, { message: defaultStartMessage + ' [Error: a] {\n' + + '+ [cause]: undefined\n' + + '- [cause]: \'undefined\'\n' + + ' }\n' }); +}); From 6003a3e667a6adc97c4452ac36dc80640e42cb69 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Wed, 6 Nov 2024 10:47:54 +0100 Subject: [PATCH 2/3] fixup! assert: differentiate cases where `cause` is `undefined` or missing --- test/parallel/test-assert-deep-with-error.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/parallel/test-assert-deep-with-error.js b/test/parallel/test-assert-deep-with-error.js index c83c4d60317070..3c53066d6f9719 100644 --- a/test/parallel/test-assert-deep-with-error.js +++ b/test/parallel/test-assert-deep-with-error.js @@ -8,6 +8,9 @@ const defaultStartMessage = 'Expected values to be strictly deep-equal:\n' + '\n'; test('Handle error causes', () => { + assert.deepStrictEqual(new Error('a', { cause: new Error('x') }), new Error('a', { cause: new Error('x') })); + assert.deepStrictEqual(new Error('a', { cause: new RangeError('x') }), new Error('a', { cause: new RangeError('x') })); + assert.throws(() => { assert.deepStrictEqual(new Error('a', { cause: new Error('x') }), new Error('a', { cause: new Error('y') })); }, { message: defaultStartMessage + ' [Error: a] {\n' + @@ -46,6 +49,8 @@ test('Handle error causes', () => { }); test('Handle undefined causes', () => { + assert.deepStrictEqual(new Error('a', { cause: undefined }), new Error('a', { cause: undefined })); + assert.notDeepStrictEqual(new Error('a', { cause: 'undefined' }), new Error('a', { cause: undefined })); assert.notDeepStrictEqual(new Error('a', { cause: undefined }), new Error('a')); assert.notDeepStrictEqual(new Error('a'), new Error('a', { cause: undefined })); From ec38506a23650f5e709c026a309aa3ce315866ec Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Wed, 6 Nov 2024 10:53:18 +0100 Subject: [PATCH 3/3] fixup! assert: differentiate cases where `cause` is `undefined` or missing --- test/parallel/test-assert-deep-with-error.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-assert-deep-with-error.js b/test/parallel/test-assert-deep-with-error.js index 3c53066d6f9719..f6bc5c6359cfe8 100644 --- a/test/parallel/test-assert-deep-with-error.js +++ b/test/parallel/test-assert-deep-with-error.js @@ -9,7 +9,10 @@ const defaultStartMessage = 'Expected values to be strictly deep-equal:\n' + test('Handle error causes', () => { assert.deepStrictEqual(new Error('a', { cause: new Error('x') }), new Error('a', { cause: new Error('x') })); - assert.deepStrictEqual(new Error('a', { cause: new RangeError('x') }), new Error('a', { cause: new RangeError('x') })); + assert.deepStrictEqual( + new Error('a', { cause: new RangeError('x') }), + new Error('a', { cause: new RangeError('x') }), + ); assert.throws(() => { assert.deepStrictEqual(new Error('a', { cause: new Error('x') }), new Error('a', { cause: new Error('y') }));