import { assertEquals } from "./assert_equals.ts";
export function assertObjectMatch( actual: Record<PropertyKey, any>, expected: Record<PropertyKey, unknown>, msg?: string,): void { type loose = Record<PropertyKey, unknown>;
function filter(a: loose, b: loose) { const seen = new WeakMap(); return fn(a, b);
function fn(a: loose, b: loose): loose { if ((seen.has(a)) && (seen.get(a) === b)) { return a; } try { seen.set(a, b); } catch (err) { if (err instanceof TypeError) { throw new TypeError( `Cannot assertObjectMatch ${ a === null ? null : `type ${typeof a}` }`, ); } else throw err; } const filtered = {} as loose; const entries = [ ...Object.getOwnPropertyNames(a), ...Object.getOwnPropertySymbols(a), ] .filter((key) => key in b) .map((key) => [key, a[key as string]]) as Array<[string, unknown]>; for (const [key, value] of entries) { if (Array.isArray(value)) { const subset = (b as loose)[key]; if (Array.isArray(subset)) { filtered[key] = fn({ ...value }, { ...subset }); continue; } } else if (value instanceof RegExp) { filtered[key] = value; continue; } else if (typeof value === "object" && value !== null) { const subset = (b as loose)[key]; if ((typeof subset === "object") && subset) { if ((value instanceof Map) && (subset instanceof Map)) { filtered[key] = new Map( [...value].filter(([k]) => subset.has(k)).map(( [k, v], ) => [k, typeof v === "object" ? fn(v, subset.get(k)) : v]), ); continue; } if ((value instanceof Set) && (subset instanceof Set)) { filtered[key] = new Set([...value].filter((v) => subset.has(v))); continue; } filtered[key] = fn(value as loose, subset as loose); continue; } } filtered[key] = value; } return filtered; } } return assertEquals( filter(actual, expected), filter(expected, expected), msg, );}