diff options
author | James Wright <james@jamesswright.co.uk> | 2019-11-04 15:21:43 +0000 |
---|---|---|
committer | Ry Dahl <ry@tinyclouds.org> | 2019-11-04 10:21:42 -0500 |
commit | 429439d1983269ba40141a1b42f6ac809d1e8c86 (patch) | |
tree | 6956fb7bf619dff51aa3eb12cde8c8309b96a4b3 | |
parent | 86b3ac5108e2893091475a0318fcba6c14e19140 (diff) |
Consolidates asserts#equal branches for keyed collections (Map/Set) and supports deep equality of Map keys (#3258)
-rw-r--r-- | std/testing/asserts.ts | 50 | ||||
-rw-r--r-- | std/testing/asserts_test.ts | 11 |
2 files changed, 37 insertions, 24 deletions
diff --git a/std/testing/asserts.ts b/std/testing/asserts.ts index b242184b3..ceac52dbd 100644 --- a/std/testing/asserts.ts +++ b/std/testing/asserts.ts @@ -67,33 +67,13 @@ function buildMessage(diffResult: ReadonlyArray<DiffResult<string>>): string[] { return messages; } +function isKeyedCollection(x: unknown): x is Set<unknown> { + return [Symbol.iterator, "size"].every(k => k in (x as Set<unknown>)); +} + export function equal(c: unknown, d: unknown): boolean { const seen = new Map(); return (function compare(a: unknown, b: unknown): boolean { - if (a && a instanceof Set && b && b instanceof Set) { - if (a.size !== b.size) { - return false; - } - for (const item of b) { - if (!a.has(item)) { - return false; - } - } - return true; - } - if (a && b && a instanceof Map && b instanceof Map) { - if (a.size !== b.size) { - return false; - } - - for (const [key, value] of a) { - if (!compare(value, b.get(key))) { - return false; - } - } - - return true; - } // Have to render RegExp & Date for string comparison // unless it's mistreated as object if ( @@ -114,6 +94,28 @@ export function equal(c: unknown, d: unknown): boolean { if (Object.keys(a || {}).length !== Object.keys(b || {}).length) { return false; } + if (isKeyedCollection(a) && isKeyedCollection(b)) { + if (a.size !== b.size) { + return false; + } + + let unmatchedEntries = a.size; + + for (const [aKey, aValue] of a.entries()) { + for (const [bKey, bValue] of b.entries()) { + /* Given that Map keys can be references, we need + * to ensure that they are also deeply equal */ + if ( + (aKey === aValue && bKey === bValue && compare(aKey, bKey)) || + (compare(aKey, bKey) && compare(aValue, bValue)) + ) { + unmatchedEntries--; + } + } + } + + return unmatchedEntries === 0; + } const merged = { ...a, ...b }; for (const key in merged) { type Key = keyof typeof merged; diff --git a/std/testing/asserts_test.ts b/std/testing/asserts_test.ts index 062fac8cc..956d66e3e 100644 --- a/std/testing/asserts_test.ts +++ b/std/testing/asserts_test.ts @@ -44,6 +44,7 @@ test(function testingEqual(): void { assert(equal(new Set([1]), new Set([1]))); assert(!equal(new Set([1]), new Set([2]))); assert(equal(new Set([1, 2, 3]), new Set([3, 2, 1]))); + assert(equal(new Set([1, new Set([2, 3])]), new Set([new Set([3, 2]), 1]))); assert(!equal(new Set([1, 2]), new Set([3, 2, 1]))); assert(!equal(new Set([1, 2, 3]), new Set([4, 5, 6]))); assert(equal(new Set("denosaurus"), new Set("denosaurussss"))); @@ -83,6 +84,16 @@ test(function testingEqual(): void { new Map([["foo", new Map([["bar", "qux"]])]]) ) ); + assert(equal(new Map([[{ x: 1 }, true]]), new Map([[{ x: 1 }, true]]))); + assert(!equal(new Map([[{ x: 1 }, true]]), new Map([[{ x: 1 }, false]]))); + assert(!equal(new Map([[{ x: 1 }, true]]), new Map([[{ x: 2 }, true]]))); + assert(equal([1, 2, 3], [1, 2, 3])); + assert(equal([1, [2, 3]], [1, [2, 3]])); + assert(!equal([1, 2, 3, 4], [1, 2, 3])); + assert(!equal([1, 2, 3, 4], [1, 2, 3])); + assert(!equal([1, 2, 3, 4], [1, 4, 2, 3])); + assert(equal(new Uint8Array([1, 2, 3, 4]), new Uint8Array([1, 2, 3, 4]))); + assert(!equal(new Uint8Array([1, 2, 3, 4]), new Uint8Array([2, 1, 4, 3]))); }); test(function testingNotEquals(): void { |