mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
fix(assert): partialDeepStrictEqual now correctly handles Map subset checking (#26257)
## Summary - Fixed `assert.partialDeepStrictEqual` to correctly handle Map subset checking - Previously, Map comparison used `Bun.deepEquals` which required exact equality - Now properly checks that all entries in the expected Map exist in the actual Map with matching values Fixes #24338 ## Test plan - Added comprehensive test suite in `test/regression/issue/24338.test.ts` covering: - Basic subset checking (key2 in Map with key1 and key2) - Exact match cases - Empty expected Map - Multiple matching entries - Nested objects as values - Failure cases when expected has more keys - Failure cases when key is missing in actual - Failure cases when values differ - Nested Map values - Non-string keys 🤖 Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: Claude Bot <claude-bot@bun.sh> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -377,6 +377,9 @@ function isSpecial(obj) {
|
||||
|
||||
const typesToCallDeepStrictEqualWith = [isKeyObject, isWeakSet, isWeakMap, Buffer.isBuffer];
|
||||
const SafeSetPrototypeIterator = SafeSet.prototype[SymbolIterator];
|
||||
const SafeMapPrototypeIterator = SafeMap.prototype[SymbolIterator];
|
||||
const SafeMapPrototypeHas = SafeMap.prototype.has;
|
||||
const SafeMapPrototypeGet = SafeMap.prototype.get;
|
||||
|
||||
/**
|
||||
* Compares two objects or values recursively to check if they are equal.
|
||||
@@ -388,9 +391,33 @@ const SafeSetPrototypeIterator = SafeSet.prototype[SymbolIterator];
|
||||
* compareBranch({a: 1, b: 2, c: 3}, {a: 1, b: 2}); // true
|
||||
*/
|
||||
function compareBranch(actual, expected, comparedObjects?) {
|
||||
// Check for Map object equality
|
||||
// Check for Map object equality (subset check for partialDeepStrictEqual)
|
||||
if (isMap(actual) && isMap(expected)) {
|
||||
return Bun.deepEquals(actual, expected, true);
|
||||
if (expected.size > actual.size) {
|
||||
return false; // `expected` can't be a subset if it has more elements
|
||||
}
|
||||
|
||||
comparedObjects ??= new SafeWeakSet();
|
||||
|
||||
// Handle circular references
|
||||
if (comparedObjects.has(actual)) {
|
||||
return true;
|
||||
}
|
||||
comparedObjects.add(actual);
|
||||
|
||||
const expectedIterator = SafeMapPrototypeIterator.$call(expected);
|
||||
|
||||
for (const { 0: key, 1: expectedValue } of expectedIterator) {
|
||||
if (!SafeMapPrototypeHas.$call(actual, key)) {
|
||||
return false;
|
||||
}
|
||||
const actualValue = SafeMapPrototypeGet.$call(actual, key);
|
||||
if (!compareBranch(actualValue, expectedValue, comparedObjects)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for ArrayBuffer object equality
|
||||
|
||||
115
test/regression/issue/24338.test.ts
Normal file
115
test/regression/issue/24338.test.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import assert from "node:assert";
|
||||
import { test } from "node:test";
|
||||
|
||||
// https://github.com/oven-sh/bun/issues/24338
|
||||
// assert.partialDeepStrictEqual should support Map subset checking
|
||||
|
||||
test("partialDeepStrictEqual with Map subset - basic case", () => {
|
||||
// The expected Map is a subset of actual Map
|
||||
assert.partialDeepStrictEqual(
|
||||
new Map([
|
||||
["key1", "value1"],
|
||||
["key2", "value2"],
|
||||
]),
|
||||
new Map([["key2", "value2"]]),
|
||||
);
|
||||
});
|
||||
|
||||
test("partialDeepStrictEqual with Map - exact match", () => {
|
||||
assert.partialDeepStrictEqual(new Map([["key1", "value1"]]), new Map([["key1", "value1"]]));
|
||||
});
|
||||
|
||||
test("partialDeepStrictEqual with Map - empty expected", () => {
|
||||
assert.partialDeepStrictEqual(new Map([["key1", "value1"]]), new Map());
|
||||
});
|
||||
|
||||
test("partialDeepStrictEqual with Map - multiple matching entries", () => {
|
||||
assert.partialDeepStrictEqual(
|
||||
new Map([
|
||||
["a", 1],
|
||||
["b", 2],
|
||||
["c", 3],
|
||||
]),
|
||||
new Map([
|
||||
["a", 1],
|
||||
["c", 3],
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
test("partialDeepStrictEqual with Map - nested objects as values", () => {
|
||||
assert.partialDeepStrictEqual(
|
||||
new Map([
|
||||
["config", { debug: true, verbose: false }],
|
||||
["data", { items: [1, 2, 3] }],
|
||||
]),
|
||||
new Map([["config", { debug: true }]]),
|
||||
);
|
||||
});
|
||||
|
||||
test("partialDeepStrictEqual with Map - should fail when expected has more keys", () => {
|
||||
assert.throws(
|
||||
() =>
|
||||
assert.partialDeepStrictEqual(
|
||||
new Map([["key1", "value1"]]),
|
||||
new Map([
|
||||
["key1", "value1"],
|
||||
["key2", "value2"],
|
||||
]),
|
||||
),
|
||||
assert.AssertionError,
|
||||
);
|
||||
});
|
||||
|
||||
test("partialDeepStrictEqual with Map - should fail when key missing in actual", () => {
|
||||
assert.throws(
|
||||
() => assert.partialDeepStrictEqual(new Map([["key1", "value1"]]), new Map([["key2", "value2"]])),
|
||||
assert.AssertionError,
|
||||
);
|
||||
});
|
||||
|
||||
test("partialDeepStrictEqual with Map - should fail when value differs", () => {
|
||||
assert.throws(
|
||||
() => assert.partialDeepStrictEqual(new Map([["key1", "value1"]]), new Map([["key1", "different"]])),
|
||||
assert.AssertionError,
|
||||
);
|
||||
});
|
||||
|
||||
test("partialDeepStrictEqual with Map - nested Map values", () => {
|
||||
assert.partialDeepStrictEqual(
|
||||
new Map([
|
||||
[
|
||||
"outer",
|
||||
new Map([
|
||||
["inner1", 1],
|
||||
["inner2", 2],
|
||||
]),
|
||||
],
|
||||
]),
|
||||
new Map([["outer", new Map([["inner1", 1]])]]),
|
||||
);
|
||||
});
|
||||
|
||||
test("partialDeepStrictEqual with Map - non-string keys", () => {
|
||||
const objKey = { id: 1 };
|
||||
assert.partialDeepStrictEqual(
|
||||
new Map([
|
||||
[1, "one"],
|
||||
[objKey, "object"],
|
||||
[true, "boolean"],
|
||||
]),
|
||||
new Map([[1, "one"]]),
|
||||
);
|
||||
});
|
||||
|
||||
test("partialDeepStrictEqual with Map - circular reference", () => {
|
||||
const actualMap = new Map<string, unknown>();
|
||||
actualMap.set("self", actualMap);
|
||||
actualMap.set("other", "value");
|
||||
|
||||
const expectedMap = new Map<string, unknown>();
|
||||
expectedMap.set("self", expectedMap);
|
||||
|
||||
// Should not hang due to circular reference
|
||||
assert.partialDeepStrictEqual(actualMap, expectedMap);
|
||||
});
|
||||
Reference in New Issue
Block a user