Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions lib/internal/util/comparisons.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -837,10 +839,13 @@ function mapObjectEquiv(array, a, b, mode, memo) {
let start = 0;
let end = array.length - 1;
const comparator = mode !== kLoose ? objectComparisonStart : innerDeepEqual;
const extraChecks = mode === kLoose || array.length !== a.size;

for (const { 0: key1, 1: item1 } of a) {
if (extraChecks && (typeof key1 !== 'object' || key1 === null)) {
// Primitive and null keys can never match through the object comparator, so
// resolve them directly. This must happen for every such key (not only when
// the map sizes differ), otherwise a null/primitive key reaches
// objectComparisonStart and throws on `key.constructor`.
if (typeof key1 !== 'object' || key1 === null) {
if (b.has(key1)) {
if (mode !== kLoose || innerDeepEqual(item1, b.get(key1), mode, memo)) {
continue;
Expand Down
15 changes: 15 additions & 0 deletions test/parallel/test-assert-deep.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,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 ];
Expand All @@ -299,6 +303,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(), []);
Expand Down
Loading