Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

assert: make Maps be partially compared in partialDeepStrictEqual #56195

Merged
merged 1 commit into from
Dec 11, 2024
Merged
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
18 changes: 11 additions & 7 deletions lib/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,22 +385,26 @@ const typesToCallDeepStrictEqualWith = [
isKeyObject, isWeakSet, isWeakMap, Buffer.isBuffer, isSharedArrayBuffer,
];

function compareMaps(actual, expected, comparedObjects) {
if (MapPrototypeGetSize(actual) !== MapPrototypeGetSize(expected)) {
function partiallyCompareMaps(actual, expected, comparedObjects) {
if (MapPrototypeGetSize(expected) > MapPrototypeGetSize(actual)) {
return false;
}
const safeIterator = FunctionPrototypeCall(SafeMap.prototype[SymbolIterator], actual);

comparedObjects ??= new SafeWeakSet();
const expectedIterator = FunctionPrototypeCall(SafeMap.prototype[SymbolIterator], expected);

for (const { 0: key, 1: val } of safeIterator) {
if (!MapPrototypeHas(expected, key)) {
for (const { 0: key, 1: expectedValue } of expectedIterator) {
if (!MapPrototypeHas(actual, key)) {
return false;
}
if (!compareBranch(val, MapPrototypeGet(expected, key), comparedObjects)) {

const actualValue = MapPrototypeGet(actual, key);

if (!compareBranch(actualValue, expectedValue, comparedObjects)) {
return false;
}
}

return true;
}

Expand Down Expand Up @@ -553,7 +557,7 @@ function compareBranch(
) {
// Check for Map object equality
if (isMap(actual) && isMap(expected)) {
return compareMaps(actual, expected, comparedObjects);
return partiallyCompareMaps(actual, expected, comparedObjects);
}

if (
Expand Down
75 changes: 73 additions & 2 deletions test/parallel/test-assert-objects.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,26 @@ describe('Object Comparison Tests', () => {
},
{
description:
'throws when comparing two Map objects with different length',
'throws when the expected Map has more entries than the actual Map',
actual: new Map([
['key1', 'value1'],
['key2', 'value2'],
]),
expected: new Map([['key1', 'value1']]),
expected: new Map([
['key1', 'value1'],
['key2', 'value2'],
['key3', 'value3'],
]),
},
{
description: 'throws when the nested array in the Map is not a subset of the other nested array',
actual: new Map([
['key1', ['value1', 'value2']],
['key2', 'value2'],
]),
expected: new Map([
['key1', ['value3']],
]),
},
{
description:
Expand Down Expand Up @@ -564,6 +578,63 @@ describe('Object Comparison Tests', () => {
['key2', 'value2'],
]),
},
{
description:
'compares two Map objects where expected is a subset of actual',
actual: new Map([
['key1', 'value1'],
['key2', 'value2'],
]),
expected: new Map([['key1', 'value1']]),
},
{
description:
'compares two deeply nested Maps',
actual: {
a: {
b: {
c: new Map([
['key1', 'value1'],
['key2', 'value2'],
])
},
z: [1, 2, 3]
}
},
expected: {
a: {
z: [1, 2, 3],
b: {
c: new Map([['key1', 'value1']])
}
}
},
},
{
description: 'compares Maps nested into Maps',
actual: new Map([
['key1', new Map([
['nestedKey1', 'nestedValue1'],
['nestedKey2', 'nestedValue2'],
])],
['key2', 'value2'],
]),
expected: new Map([
['key1', new Map([
['nestedKey1', 'nestedValue1'],
])],
])
},
{
description: 'compares Maps with nested arrays inside',
actual: new Map([
['key1', ['value1', 'value2']],
['key2', 'value2'],
]),
expected: new Map([
['key1', ['value1', 'value2']],
]),
},
{
description:
'compares two objects with identical getter/setter properties',
Expand Down
Loading