mirror of
https://github.com/denoland/std.git
synced 2024-11-21 20:50:22 +00:00
fix(assert): fix assertObjectMatch()
prints arrays as objects (#5503)
fix(assert): fix ssertObjectMatch prints arrays as objects
This commit is contained in:
parent
b6b0d68381
commit
5cff014b02
@ -49,7 +49,7 @@ function isObject(val: unknown): boolean {
|
|||||||
return typeof val === "object" && val !== null;
|
return typeof val === "object" && val !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function filter(a: loose, b: loose) {
|
function filter(a: loose, b: loose): loose {
|
||||||
const seen = new WeakMap();
|
const seen = new WeakMap();
|
||||||
return filterObject(a, b);
|
return filterObject(a, b);
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ function filter(a: loose, b: loose) {
|
|||||||
|
|
||||||
// On array references, build a filtered array and filter nested objects inside
|
// On array references, build a filtered array and filter nested objects inside
|
||||||
if (Array.isArray(value) && Array.isArray(subset)) {
|
if (Array.isArray(value) && Array.isArray(subset)) {
|
||||||
filtered[key] = filterObject({ ...value }, { ...subset });
|
filtered[key] = filterArray(value, subset);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,4 +135,66 @@ function filter(a: loose, b: loose) {
|
|||||||
|
|
||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function filterArray(a: unknown[], b: unknown[]): unknown[] {
|
||||||
|
// Prevent infinite loop with circular references with same filter
|
||||||
|
if (seen.has(a) && (seen.get(a) === b)) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
seen.set(a, b);
|
||||||
|
|
||||||
|
const filtered: unknown[] = [];
|
||||||
|
const count = Math.min(a.length, b.length);
|
||||||
|
|
||||||
|
for (let i = 0; i < count; ++i) {
|
||||||
|
const value = a[i];
|
||||||
|
const subset = b[i];
|
||||||
|
|
||||||
|
// On regexp references, keep value as it to avoid loosing pattern and flags
|
||||||
|
if (value instanceof RegExp) {
|
||||||
|
filtered.push(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On array references, build a filtered array and filter nested objects inside
|
||||||
|
if (Array.isArray(value) && Array.isArray(subset)) {
|
||||||
|
filtered.push(filterArray(value, subset));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On nested objects references, build a filtered object recursively
|
||||||
|
if (isObject(value) && isObject(subset)) {
|
||||||
|
// When both operands are maps, build a filtered map with common keys and filter nested objects inside
|
||||||
|
if ((value instanceof Map) && (subset instanceof Map)) {
|
||||||
|
const map = new Map(
|
||||||
|
[...value].filter(([k]) => subset.has(k))
|
||||||
|
.map(([k, v]) => {
|
||||||
|
const v2 = subset.get(k);
|
||||||
|
if (isObject(v) && isObject(v2)) {
|
||||||
|
return [k, filterObject(v as loose, v2 as loose)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [k, v];
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
filtered.push(map);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When both operands are set, build a filtered set with common values
|
||||||
|
if ((value instanceof Set) && (subset instanceof Set)) {
|
||||||
|
filtered.push(value.intersection(subset));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered.push(filterObject(value as loose, subset as loose));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
filtered.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,11 @@ const n = {
|
|||||||
["b", b],
|
["b", b],
|
||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
|
const o = { foo: [new Map([["bar", n.bar], ["baz", null]])] };
|
||||||
|
const p = { bar: [new Set([1, 2, 3])] };
|
||||||
|
const q = { foo: [1, 2] as unknown[] };
|
||||||
|
q.foo[2] = q.foo;
|
||||||
|
const r = { bar: [[1, [2, [q]]]] };
|
||||||
|
|
||||||
Deno.test("assertObjectMatch() matches simple subset", () => {
|
Deno.test("assertObjectMatch() matches simple subset", () => {
|
||||||
assertObjectMatch(a, {
|
assertObjectMatch(a, {
|
||||||
@ -79,6 +84,7 @@ Deno.test("assertObjectMatch() matches subset with circular reference", () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
assertObjectMatch(q, { foo: [1, 2, [1, 2, [1, 2, [1, 2]]]] });
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test("assertObjectMatch() matches subset with interface", () => {
|
Deno.test("assertObjectMatch() matches subset with interface", () => {
|
||||||
@ -105,6 +111,7 @@ Deno.test("assertObjectMatch() matches subset with nested array inside", () => {
|
|||||||
assertObjectMatch(j, { foo: [[1, 2, 3]] });
|
assertObjectMatch(j, { foo: [[1, 2, 3]] });
|
||||||
assertObjectMatch(k, { foo: [[1, [2, [3]]]] });
|
assertObjectMatch(k, { foo: [[1, [2, [3]]]] });
|
||||||
assertObjectMatch(l, { foo: [[1, [2, [a, e, j, k]]]] });
|
assertObjectMatch(l, { foo: [[1, [2, [a, e, j, k]]]] });
|
||||||
|
assertObjectMatch(r, { bar: [[1, [2, [q]]]] });
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test("assertObjectMatch() matches subset with regexp", () => {
|
Deno.test("assertObjectMatch() matches subset with regexp", () => {
|
||||||
@ -117,6 +124,9 @@ Deno.test("assertObjectMatch() matches subset with built-in data structures", ()
|
|||||||
assertObjectMatch(n, { bar: new Map([["bar", 2]]) });
|
assertObjectMatch(n, { bar: new Map([["bar", 2]]) });
|
||||||
assertObjectMatch(n, { baz: new Map([["b", b]]) });
|
assertObjectMatch(n, { baz: new Map([["b", b]]) });
|
||||||
assertObjectMatch(n, { baz: new Map([["b", { foo: true }]]) });
|
assertObjectMatch(n, { baz: new Map([["b", { foo: true }]]) });
|
||||||
|
assertObjectMatch(o, { foo: [new Map([["baz", null]])] });
|
||||||
|
assertObjectMatch(o, { foo: [new Map([["bar", n.bar]])] });
|
||||||
|
assertObjectMatch(p, { bar: [new Set([2, 3])] });
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test("assertObjectMatch() throws when a key is missing from subset", () => {
|
Deno.test("assertObjectMatch() throws when a key is missing from subset", () => {
|
||||||
@ -341,6 +351,10 @@ Deno.test("assertObjectMatch() prints inputs correctly", () => {
|
|||||||
description: "foo",
|
description: "foo",
|
||||||
},
|
},
|
||||||
name: "somegroup",
|
name: "somegroup",
|
||||||
|
nodes: [
|
||||||
|
"somenode",
|
||||||
|
"someothernode",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -356,9 +370,46 @@ Deno.test("assertObjectMatch() prints inputs correctly", () => {
|
|||||||
+ description: "foo",
|
+ description: "foo",
|
||||||
+ },
|
+ },
|
||||||
+ name: "somegroup",
|
+ name: "somegroup",
|
||||||
|
+ nodes: [
|
||||||
|
+ "somenode",
|
||||||
|
+ "someothernode",
|
||||||
|
+ ],
|
||||||
- message: "NodeNotFound",
|
- message: "NodeNotFound",
|
||||||
},
|
},
|
||||||
protocol: "graph",
|
protocol: "graph",
|
||||||
}`,
|
}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assertThrows(
|
||||||
|
() => assertObjectMatch({ foo: [] }, { foo: ["bar"] }),
|
||||||
|
AssertionError,
|
||||||
|
` {
|
||||||
|
+ foo: [
|
||||||
|
+ "bar",
|
||||||
|
+ ],
|
||||||
|
- foo: [],
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const a = {};
|
||||||
|
const b = {};
|
||||||
|
|
||||||
|
Object.defineProperty(a, "hello", {
|
||||||
|
value: "world",
|
||||||
|
enumerable: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(b, "foo", {
|
||||||
|
value: "bar",
|
||||||
|
enumerable: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
assertThrows(
|
||||||
|
() => assertObjectMatch(a, b),
|
||||||
|
AssertionError,
|
||||||
|
` {
|
||||||
|
- hello: "world",
|
||||||
|
+ foo: "bar",
|
||||||
|
}`,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user