diff --git a/lib/internal/util/comparisons.js b/lib/internal/util/comparisons.js index 2582217febc6..2e412835940f 100644 --- a/lib/internal/util/comparisons.js +++ b/lib/internal/util/comparisons.js @@ -686,16 +686,18 @@ function setObjectEquiv(array, a, b, mode, memo) { const comparator = mode !== kLoose ? objectComparisonStart : innerDeepEqual; const extraChecks = mode === kLoose || array.length !== a.size; for (const val1 of a) { - if (extraChecks) { - if (typeof val1 === 'object') { - if (b.has(val1)) { - continue; - } - } else if (b.has(val1)) { + // Primitive and null members can only match by identity, and must never + // reach objectComparisonStart (which throws on `val.constructor` for + // null/undefined). Resolve them directly for every such member. + if (typeof val1 !== 'object' || val1 === null) { + if (b.has(val1)) { continue; - } else if (mode !== kLoose) { + } + if (mode !== kLoose) { return false; } + } else if (extraChecks && b.has(val1)) { + continue; } let innerStart = start; diff --git a/test/parallel/test-assert-deep.js b/test/parallel/test-assert-deep.js index f7aded0d9aca..91faa7839854 100644 --- a/test/parallel/test-assert-deep.js +++ b/test/parallel/test-assert-deep.js @@ -278,6 +278,10 @@ test('es6 Maps and Sets', () => { assertDeepAndStrictEqual(new Set([[1, 2], [3, 4]]), new Set([[3, 4], [1, 2]])); assertNotDeepOrStrict(new Set([{ a: 0 }]), new Set([{ a: 1 }])); assertNotDeepOrStrict(new Set([Symbol()]), new Set([Symbol()])); + // A null/primitive member lined up against object-only members in the other + // set must report inequality, not throw on `member.constructor`. + assertNotDeepOrStrict(new Set([null, {}, {}]), new Set([{}, {}, {}])); + assertNotDeepOrStrict(new Set([undefined, {}, {}]), new Set([{}, {}, {}])); { const a = [ 1, 2 ]; @@ -298,6 +302,17 @@ test('es6 Maps and Sets', () => { new Map([[[1], 1], [{}, 2]]), new Map([[[1], 2], [{}, 1]]) ); + // A null/primitive key that lines up with object-only keys in the other map + // must report inequality, not throw on `key.constructor`. Refs: object keys + // of `b` equal in count to `a.size` used to skip the primitive-key handling. + assertNotDeepOrStrict( + new Map([[null, 1], [{}, 2]]), + new Map([[{}, 9], [{}, 9]]) + ); + assertNotDeepOrStrict( + new Map([[undefined, 1], [{}, 2]]), + new Map([[{}, 9], [{}, 9]]) + ); assertNotDeepOrStrict(new Set([1]), [1]); assertNotDeepOrStrict(new Set(), []);