Skip to content

assert: fix deepEqual similar sets and maps bug - #13426

Closed
josephg wants to merge 4 commits into
nodejs:masterfrom
josephg:deepequal-bug
Closed

assert: fix deepEqual similar sets and maps bug#13426
josephg wants to merge 4 commits into
nodejs:masterfrom
josephg:deepequal-bug

Conversation

@josephg

Copy link
Copy Markdown
Contributor

This fixes a bug where deepEqual and deepStrictEqual would have
incorrect behaviour in sets and maps containing multiple equivalent
keys.

Fixes: #13347
Refs: #12142

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • commit message follows commit guidelines
Affected core subsystem(s)

assert

This fixes a bug where deepEqual and deepStrictEqual would have
incorrect behaviour in sets and maps containing multiple equivalent
keys.
Fixes: nodejs#13347
Refs: nodejs#12142
@nodejs-github-botnodejs-github-bot added the assert Issues and PRs related to the assert subsystem. label Jun 3, 2017

@refackrefack left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM % nits & CI

Comment threadtest/parallel/test-assert-deep.js Outdated

assertDeepAndStrictEqual(new Set([{}]), new Set([{}]));

// Discussion of these test cases here - https://github.com/nodejs/node/issues/13347

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: just put Ref: https://github.com/nodejs/node/issues/13347

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment threadlib/assert.js Outdated
// This is a set of the entries in b which have been consumed in our pairwise
// comparison. Initialized lazily so sets which only have value types can
// skip an extra allocation.
let bEntriesUsed = null;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd rather you name it something like usedEntries, since bEntriesUsed sounds like a boolean predicating a need to use .entries()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you choose to accept this nit, rename everywhere else as well...

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure - I don't have a strong opinion so I've renamed it.

My concern with usedEntries is that it doesn't make it clear that we're marking entries in set b.

@refack

Copy link
Copy Markdown
Contributor

Comment threadlib/assert.js Outdated
// slower if large, very similar sets / maps are nested inside.
// Unfortunately there's no real way around this.
if (!setHasSimilarElement(b, val1, strict, memo)) {
if (bEntriesUsed == null && typeof val1 === 'object')

@rmdmrmdmJun 3, 2017

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it important that a current val1 is an object? And why it should prevent initializing bEntriesUsed "for now" if it is not?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bug doesn't affect value types because its impossible for two strings, numbers, bools, etc to be deepEqual to one another without being reference-equal. So in the case where the set or map only contains value typed entries, there's no need to allocate an extra set for bEntriesUsed.

Lazily allocating the set when needed is a microoptimization.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then maybe it worth to continue that optimization and checking type of val2 before adding it to set of usedEntries? Because presence of even single object in a set with large number of typed entries would lead to adding them to usedEntries without any need.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe.. but in practice its very rare to mix types in set / map keys. And it still won't matter in strict mode because there's an early return for value types anyway.

Uhhhh but not in non-strict mode. Huh - looks like this also doesn't throw:

assert.deepEqual(newSet([3,'3']),newSet([3,4]));

fixes

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... Fixed. PR updated so this behaves correctly too.

@refackrefack left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

@refack

Copy link
Copy Markdown
Contributor

@refack

Copy link
Copy Markdown
Contributor

Lint errors:

not ok 27 - /usr/home/iojs/build/workspace/node-test-linter/test/parallel/test-assert-deep.js
---
message: Missing space before value for key 'a'.
severity: error
data:
line: 208
column: 15
ruleId: key-spacing
messages:
- message: Missing space before value for key 'a'.
severity: error
data:
line: 208
column: 22
ruleId: key-spacing
- message: Missing space before value for key 'a'.
severity: error
data:
line: 208
column: 29
ruleId: key-spacing
- message: Missing space before value for key 'a'.
severity: error
data:
line: 209
column: 15
ruleId: key-spacing
- message: Missing space before value for key 'a'.
severity: error
data:
line: 209
column: 22
ruleId: key-spacing
- message: Missing space before value for key 'a'.
severity: error
data:
line: 209
column: 29
ruleId: key-spacing
...

@josephg

Copy link
Copy Markdown
ContributorAuthor

Oops! Sorry about that. Fixed!

$ make lint
Running JS linter...
./node tools/eslint/bin/eslint.js --cache --rulesdir=tools/eslint-rules --ext=.js,.md \
benchmark doc lib test tools
Running C++ linter...
Total errors found: 0

@refack

Copy link
Copy Markdown
Contributor

@refack

Copy link
Copy Markdown
Contributor

Linux CI fail was infrastructure related, but still rerunning: https://ci.nodejs.org/job/node-test-commit-linux/10349/

@josephg

Copy link
Copy Markdown
ContributorAuthor

Unless there's any more comments, I think this is ready to merge 👓

@refackrefack self-assigned this Jun 5, 2017
@refack

Copy link
Copy Markdown
Contributor

I'll land this later today (let PDT people a last chance to chime in)
/cc @nodejs/testing

refack pushed a commit to refack/node that referenced this pull request Jun 5, 2017
This fixes a bug where deepEqual and deepStrictEqual would have
incorrect behaviour in sets and maps containing multiple equivalent
keys.
PR-URL: nodejs#13426Fixes: nodejs#13347
Refs: nodejs#12142
Reviewed-By: Refael Ackermann <refack@gmail.com>
@refack

Copy link
Copy Markdown
Contributor

landed in 7cddcc9

@refackrefack closed this Jun 5, 2017
@refack

Copy link
Copy Markdown
Contributor

Extra quick sanity of master: https://ci.nodejs.org/job/node-test-commit-linuxone/6404/

@josephg
josephg deleted the deepequal-bug branch June 5, 2017 22:40
jasnell pushed a commit that referenced this pull request Jun 7, 2017
This fixes a bug where deepEqual and deepStrictEqual would have
incorrect behaviour in sets and maps containing multiple equivalent
keys.
PR-URL: #13426Fixes: #13347
Refs: #12142
Reviewed-By: Refael Ackermann <refack@gmail.com>
@gibfahngibfahn mentioned this pull request Jun 15, 2017
3 tasks
@refackrefack removed their assignment Oct 20, 2018
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

assertIssues and PRs related to the assert subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

assert: deepEqual of two Sets with different content passes

5 participants

@josephg@refack@rmdm@MylesBorins@nodejs-github-bot