assert.deepEqual(new Set([{a: 1}, {a: 1}]), new Set([{a: 1}, {a: 2}]))
assert.deepStrictEqual(new Set([{a: 1}, {a: 1}]), new Set([{a: 1}, {a: 2}]))
Both of these checks passes, while I would expect them to fail.
I can reproduce.
This fails:
assert.deepEqual(new Set([{a: 1}, {a: 1}]), new Set([{b: 1}, {b: 2}]));
assert.deepStrictEqual(new Set([{a: 1}, {a: 1}]), new Set([{b: 1}, {b: 2}]));
This also fails:
assert.deepEqual(new Set([{a: 1}]), new Set([{a: 2}]));
assert.deepStrictEqual(new Set([{a: 1}]), new Set([{a: 2}]));
褋褋 @nodejs/testing
Also cc @josephg due to https://github.com/nodejs/node/pull/12142
Errr, yep this is a bug.
assert.deepStrictEqual(new Set([{a: 1}, {a: 1}]), new Set([{a: 1}, {a: 2}]))
There's two semantics going on here:
{a:1} and {a:1} because they aren't references to the same object.deep[Strict]Equal, they are the same.So you've made a set with two different objects that are considered identical by deepEqual. As far as deepEqual should be concerned, is this equivalent to a set with only one {a:1} in it? Its sort of weird.
Anyway, after a long discussion deep equality comparison currently works by doing this:
The .size comparison uses the semantics of sets - that is, internal reference equality. The pairwise item comparisons uses the semantics of deepEqual / deepStrictEqual. And hence the bug.
~We could fix it by changing the code to do it both ways around:~ (Edit: This is also buggy - see my comment below)
(... although then step 1 isn't needed anymore, and might cause more bugs?)
Alternately, we could track which items of set 2 have already been consumed by the matching. So:
.. Which I think is correct.
And, maps have the equivalent logic & same bug:
assert.deepEqual(new Map([[{x:1}, 5], [{x:1}, 5]]), new Map([[{x:1}, 5], [{x:2}, 5]]))
assert.deepStrictEqual(new Map([[{x:1}, 5], [{x:1}, 5]]), new Map([[{x:1}, 5], [{x:2}, 5]]))
(... although then step 1 isn't needed anymore, and might cause more bugs?)
Is it still needed with this approach to prevent this from being equal?
assert.deepStrictEqual(new Set([{a: 1}, {a: 1}]), new Set([{a: 1}]))
.... Er, yeah, sure is @vsemozhetbyt :)
Actually the first method would consider these sets to be equal:
new Set([{a:1}, {a:1}, {a:2}])
new Set([{a:1}, {a:2}, {a:2}])
So we should fix this using the second method.
This also fails to throw, due to the same bug:
assert.deepEqual(new Set([3, '3']), new Set([3, 4]));
// and
assert.deepEqual(new Map([[3, 0], ['3', 0]]), new Map([[3, 0], [4, 0]]);
... and heads up by a bro from lodash.js
(version 6.11.4, Windows x64)
assert.deepEqual( new Map([['x', 'y']]),
new Map([['y', 'x']]) ); // Doesn't throw
I assert that this is fixed in v8.7.0.
Primitive support for map and set equality wasn't added until node 8. In node 6 all maps and all sets are considered equivalent. These also didn't throw in node 7 and below:
assert.deepEqual(new Map(), new Map())
assert.deepEqual(new Map(), new Set())