Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for comparing ES2015 Maps and Sets #342

Closed
js-choi opened this issue Jan 23, 2017 · 15 comments
Closed

Support for comparing ES2015 Maps and Sets #342

js-choi opened this issue Jan 23, 2017 · 15 comments
Assignees

Comments

@js-choi
Copy link

js-choi commented Jan 23, 2017

As noted in inspect-js/node-deep-equal#28, Node’s deepEqual algorithm does not support comparing ES2015/ES6 Maps and Sets, and, as noted in nodejs/node#2309 and nodejs/node#2315, there is no intent by Node’s staff to support them. According to @domenic and @Trott, the Node standard assert module is intended for only testing Node itself, and assertions in user land should be addressed by user-land assertion libraries. For this same reason (mjackson/expect#47), along with circular references (mjackson/expect#50), the expect library has switched from node-deep-equal to is-equal (mjackson/expect@32e2169).

Given all this, it would make sense for Tape to add another recursive comparison function – alternative to t.deepEqual, t.deepLooseEqual, etc. – that would support Maps and Sets. This function too might use is-equal, which also supports comparing Dates and RegExps, and which might be called something like t.jsEquiv, since it would test whether two objects represent the same JavaScript-standard-library data.

Alternatively, it may be simpler and more generally useful to support Maps and Sets by simply comparing their iterators’ items. Shallow and deep versions might be called t.iterEquiv and t.deepIterEquiv (alternative names include t.itemsEqual, t.iterEqual, and so on). For instance, t.deepIterEquiv(new Map([ [ 3, 2 ], [ 5, 4 ] ]), [ [ 3, 2 ], [ 5, 4 ] ] would test as true, because the map and the array’s iterators both yield the same entries in the same order, and their entries’ iterators also yield the same integers in the same order.

In this case, t.iterEquiv and t.deepIterEquiv might also allow additional optional arguments that let the user customize what predicates are used to compare items. t.iterEquiv would take one optional predicate, for comparing items shallowly. t.deepIterEquiv would take two optional predicates: one for comparing leaf-node items and the other for comparing branch-node items without regard to the branches’ children.

These two options for comparing Maps and Sets – t.jsEquiv versus t.iterEquiv / t.deepIterEquiv – are not mutually exclusive, of course. Both are useful, and neither should also be difficult to implement; I might be open to doing the work myself. The question here is more about whether @substack thinks either or both of them would fit with his vision for Tape.

@ljharb
Copy link
Collaborator

ljharb commented Jan 24, 2017

I think these things could indeed be useful, but the goal of tape is generally to mirror the small API of assert. I'll wait to see what other collabs think.

In the meantime, something like this should work just fine:

var test = require('tape');
var isEqual = require('is-equal');

test('something', function (t) {
  t.ok(isEqual(a, b), 'a and b are equal');
  t.end();
});

@Trott
Copy link

Trott commented Jan 24, 2017

there is no intent by Node’s staff to support them.

Unfortunately, you are correct about the current official position of the project.

However, as a potential ray of hope: My view on assert has evolved since nodejs/node#2309. nodejs/node#10282 and one or two other current PRs may force the issue a bit. (See my only-mildly-incoherent comment at nodejs/node#10282 (comment).)

But yeah, there's no guarantees on any of that stuff and a change in the situation may take a while.

On the upside, the Node.js Core Technical Committee is scheduled to discuss this issue at this week's meeting. See nodejs/CTC#63 for info if interested.

@js-choi
Copy link
Author

js-choi commented Feb 5, 2017

@Trott Thanks; good to know. It’ll be slow but interesting for the whole Node ecosystem to see what ends up happening.

@ljharb In lieu of a change, it may be most efficient to put a note in the readme and whatever other documentation, saying that the intent of the tape API is to mirror node's assert, and that users should generally use other libraries such as is-equal or write their own comparator functions if they wish to compare items deeply. It would be usefully clarifying and might save the time of new users.

@ljharb
Copy link
Collaborator

ljharb commented Feb 5, 2017

@js-choi thanks, that's a great idea. PRs are appreciated, especially for docs improvements.

@Trott
Copy link

Trott commented Feb 6, 2017

At the last CTC meeting, it was agreed that the Locked API status for assert should not be used as a reason to decline to fix bugs. We also agreed to remove the doc material that says assert is intended for Node.js internal use only.

Based on the conversation, I believe we would now accept a PR to (for example) fix deepEqual() to work as expected with Maps and Sets. In fact, I believe there already may be a PR to do that (but I could be wrong about that).

The API is still Locked, which means no new features. But adjusting the API to work with Maps, Sets, Symbols, etc. should be allowable. (There's a chance people will argue that such changes should only be released in a major version, which goes out every six months. We'll see.)

Hope this helps.

@ljharb
Copy link
Collaborator

ljharb commented Feb 6, 2017

@Trott awesome - if you could link me to that PR, i'd be very interested in ensuring it behaves properly.

@Trott
Copy link

Trott commented Feb 6, 2017

@ljharb Found the PR. It's from 1.5 years ago and is closed. nodejs/node#2315 I'll update my comment above to strike out the part where I say that I think there's already a PR open for it.

@Trott
Copy link

Trott commented Feb 6, 2017

@ljharb Other open PRs on assert that might be worth your time reviewing:

@ghost
Copy link

ghost commented Feb 16, 2017

Once this is merged into core I will release a new major version of deep-equal based on the new algorithm that tape can be updated to support.

josephg added a commit to josephg/node that referenced this issue Mar 31, 2017
assert.deepEqual and assert.deepStrictEqual currently return true for
any pair of Maps and Sets regardless of content. This patch adds
support in deepEqual and deepStrictEqual to verify the contents of Maps
and Sets.

Unfortunately because there's no way to pairwise fetch set values or map
values which are equivalent but not reference-equal, this change
currently only supports reference equality checking in set values and
map key values. Equivalence checking could be done, but it would be an
O(n^2) operation, and worse, it would get slower exponentially if maps
and sets were nested.

Note that this change breaks compatibility with previous versions of
deepEqual and deepStrictEqual if consumers were depending on all maps
and sets to be seen as equivalent. The old behaviour was never
documented, but nevertheless there are certainly some tests out there
which depend on it.

Support has stalled because the assert API was frozen, but was recently
unfrozen in CTC#63

Fixes: nodejs#2309
Refs: tape-testing/tape#342
Refs: nodejs#2315
Refs: nodejs/CTC#63
addaleax pushed a commit to nodejs/node that referenced this issue Apr 3, 2017
assert.deepEqual and assert.deepStrictEqual currently return true for
any pair of Maps and Sets regardless of content. This patch adds
support in deepEqual and deepStrictEqual to verify the contents of Maps
and Sets.

Deeo equivalence checking is currently an
O(n^2) operation, and worse, it gets slower exponentially if maps
and sets were nested.

Note that this change breaks compatibility with previous versions of
deepEqual and deepStrictEqual if consumers were depending on all maps
and sets to be seen as equivalent. The old behaviour was never
documented, but nevertheless there are certainly some tests out there
which depend on it.

Support has stalled because the assert API was frozen, but was recently
unfrozen in CTC#63.

---

Later squashed in:

This change updates the checks for deep equality checking on Map and Set
to check all set values / all map keys to see if any of them match the
expected result.

This change is much slower, but based on the conversation in the pull
request its probably the right approach.

Fixes: #2309
Refs: tape-testing/tape#342
Refs: #2315
Refs: nodejs/CTC#63
PR-URL: #12142
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Rich Trott <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Joyee Cheung <[email protected]>
@Sawtaytoes
Copy link

As listed in inspect-js/node-deep-equal#54, it looks like support was added to Node.js in v8. Is there an ETA for this change coming to tape?

@Raynos Raynos removed their assignment Mar 1, 2019
@kumavis
Copy link

kumavis commented Aug 30, 2019

+1 to this

@lfurzewaddock
Copy link

Borrow solution from node-tap? tapjs/tapjs#372

@ljharb
Copy link
Collaborator

ljharb commented Oct 21, 2019

@lfurzewaddock that doesn't match node's assert module, and is both not robust and has a bug.

@lfurzewaddock
Copy link

Thanks @ljharb, I can confirm t.deepEqual for an object containing Maps with cyclical references worked successfully.

@ljharb
Copy link
Collaborator

ljharb commented Dec 23, 2019

This should be resolved in the v5.0.0-next.0 prerelease of tape, via deep-equal v2.

@ljharb ljharb closed this as completed Dec 23, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants