-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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
assert: add support for Set and Map #2315
Conversation
|
||
function compareSetItems(a, b, strict) { | ||
for (let item of a) { | ||
if (!b.has(item)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should check the same index for sets, not sure about maps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Index? You mean the order?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strictly speaking sets are unordered, should we really worry about it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I agree with @Fishrock123 here. Order should probably be checked as well IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, sets do seem to be kind of unordered, you can't just "get" an index: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strictly speaking sets are unordered
Strictly correct, but note that unlike ES5 Objects where iteration is in "whatever, probably insertion" order, iteration over Sets and Maps is defined in ES2015 to occur in "insertion order". Despite this ordered iteration, one could consider the underlying data represented by the Set/Map datastructure to be unordered though.
While verifying order may be more strictly "equal", I disagree that this is very useful in practice though. Ignoring the spec, consider whether deepEqual would be more or less useful if it also verified the key order for objects. IMO, for common use cases, verification of the iteration order is not important. If you do want to additionally verify the ordering, it's trivial enough to do: convert the Set/Map.keys() to arrays and deepEqual the arrays.
Consider then if deepEqual does check order and one wants to ignore the iteration order one will need to create an array of the keys/values, sort it somehow (depends on data), then use this to create a new Map/Set. Checking iteration order would make the IMO common usecase more verbose.
It should check the same index for sets, not sure about maps.
deepEqual over Sets and Maps should exhibit the same behaviour with regard to order.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me.
if (!compareMapKeys(a, b, strict)) | ||
return false; | ||
|
||
return compareMapKeys(b, a, strict); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Knowing that we check size equality before, do we need to iterate on each Map ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point.
Comments have been addressed and additional tests have been added to verify that order does not matter. |
LGTM |
In addition to |
|
@thefourtheye good catch. Removed |
PS. I am in a forest with a bad internet connection. Sorry for leaving comments with a lot of delay :'( |
Can we use |
If we are comparing strictly, it is equivalent to using |
Updated to use |
Exactly. It doesn't matter if we are strict or not in this case, right? |
Yes, it will be "strict" in the sense that it checks strict equality regardless |
Unless, we were to use Edit: which may be necessary. Ex:
|
Yes. Okay, if that comment is clear to others, I am okay. One minor nit, you can even ignore it, I feel that |
Nah, I don't think deepEqual is necessary as of now. What would be interesting is, when the custom comparison feature lands in the language. |
Previously, assert.deepEqual used on maps and sets was not functioning correctly. This change adds support for correctly comparing Maps and Sets. For Maps, comparison is done by iterating over each item in the first Map and verifying that the key exists and the value is the same (depending on whether strict is applied). For Sets, each item is iterated over in the first Set and checked if it exists in the other Set. For both Maps and Sets, the size of both being compared is checked as well.
Now that I think about it though, should strict for sets not compare each item of sets using Edit: I guess that would go back to ordering being strict, so nevermind |
CI looks happy. |
Then we will be contradicting the result of |
Is it semver-minor ? |
Honestly, I would think this would be considered a bug fix? |
+1 for semver-minor |
One could also say it is semver-major because the behaviour changes for: var a = new Set([1, 2, 3]);
a.x = 1;
var b = {x: 1};
assert.deepEqual(a, b); I also see it as a bug fix btw. |
I need to check a few things, but bug fix sounds good as targos points out. We should also note that it is not a backward compatible change. Ah its confusing me. Sorry, I am not sure :-( |
return false; | ||
|
||
// iterate over all keys and check if they exist in the other | ||
for (let kvs of a) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let
is not faster than var
, if this code is hotcode, we would be better to use var
instead of let
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I wouldn't consider this to be hot code, but probably should stick with var for now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is not faster, but performs equally in this kind of situation: http://jsperf.com/let-vs-var-iteration
I believe the optimization arrived with V8 4.4.
I don't think we should do this (or anything else in #2309). Assert should remain used only for testing io.js itself, and not try to be a good general assertion library. If io.js tests need this ability enough times that we need to factor it out, we should, but until then, just adding it because it'd be nice isn't a good idea IMO. |
@domenic fair enough. This could be done in user-land fairly easy |
I went ahead and published an |
Now that maps and sets are in v8, its possible for node itself to start using them internally, in which case assert's deepEqual won't work for node itself. I guess we could wait until this actually happens, and some node contributor gets terribly confused, or fix it now. |
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
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]>
Previously,
assert.deepEqual
used on maps and sets was not functioningcorrectly.
This change adds support for correctly comparing Maps and Sets.
For Maps, comparison is done by iterating over each item in both Maps
and verifying that the key exists and the value is the same (depending
on whether strict is applied).
For Sets, each item is iterated in each Set and checked if it exists in
the other Set.
For both Maps and Sets, the size of both being compared is checked as
well.
Related: #2309