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

assert: fix deepEqual always return true on URL #50853

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

meixg
Copy link
Member

@meixg meixg commented Nov 22, 2023

Fixes: #50836

@nodejs-github-bot nodejs-github-bot added needs-ci PRs that need a full CI run. util Issues and PRs related to the built-in util module. labels Nov 22, 2023
@tniessen tniessen added assert Issues and PRs related to the assert subsystem. whatwg-url Issues and PRs related to the WHATWG URL implementation. labels Nov 22, 2023
Copy link
Member

@anonrig anonrig left a comment

Choose a reason for hiding this comment

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

LGTM

@aduh95
Copy link
Contributor

aduh95 commented Nov 22, 2023

Related test failure:

=== release test-whatwg-url-custom-inspect ===
Path: parallel/test-whatwg-url-custom-inspect
Error: --- stderr ---
node:assert:126
  throw new AssertionError(obj);
  ^

AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+ actual - expected

+ '{ a: ***host.name:8080/path/name/?que=ry#hash }'
- '{ a: URL {} }'
    at Object.<anonymous> (/home/runner/work/node/node/test/parallel/test-whatwg-url-custom-inspect.js:65:8)
    at Module._compile (node:internal/modules/cjs/loader:1375:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1434:10)
    at Module.load (node:internal/modules/cjs/loader:1206:32)
    at Module._load (node:internal/modules/cjs/loader:1022:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:142:12)
    at node:internal/main/run_main_module:28:49 {
  generatedMessage: true,
  code: 'ERR_ASSERTION',
  actual: '{ a: ***host.name:8080/path/name/?que=ry#hash }',
  expected: '{ a: URL {} }',
  operator: 'strictEqual'
}

@meixg
Copy link
Member Author

meixg commented Nov 23, 2023

Related test failure:

=== release test-whatwg-url-custom-inspect ===
Path: parallel/test-whatwg-url-custom-inspect
Error: --- stderr ---
node:assert:126
  throw new AssertionError(obj);
  ^

AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
+ actual - expected

+ '{ a: ***host.name:8080/path/name/?que=ry#hash }'
- '{ a: URL {} }'
    at Object.<anonymous> (/home/runner/work/node/node/test/parallel/test-whatwg-url-custom-inspect.js:65:8)
    at Module._compile (node:internal/modules/cjs/loader:1375:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1434:10)
    at Module.load (node:internal/modules/cjs/loader:1206:32)
    at Module._load (node:internal/modules/cjs/loader:1022:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:142:12)
    at node:internal/main/run_main_module:28:49 {
  generatedMessage: true,
  code: 'ERR_ASSERTION',
  actual: '{ a: ***host.name:8080/path/name/?que=ry#hash }',
  expected: '{ a: URL {} }',
  operator: 'strictEqual'
}

fixed

@meixg meixg added the request-ci Add this label to start a Jenkins CI on a PR. label Nov 23, 2023
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Nov 23, 2023
@nodejs-github-bot
Copy link
Collaborator

@nodejs-github-bot
Copy link
Collaborator

Copy link
Member

@BridgeAR BridgeAR left a comment

Choose a reason for hiding this comment

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

The detection is not checking for an actual instance of URL and it's just a heuristic which can trigger for lots of other objects as well. Assert has to be very strict about knowing what to check for. We would need a proper check for being an URL object and that's something we can not easily do.

Update: The check is actually just additive, so it should be ok in assert. I would still like to see if we can just rely upon changing URL instead of assert and util.

} else if (isURL(value) && !(recurseTimes > ctx.depth && ctx.depth !== null)) {
base = value.href;
if (keys.length === 0 && protoProps === undefined) {
return base;
Copy link
Member

Choose a reason for hiding this comment

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

I think it would be valuable to see the object structure as before. With this change, it almost looks like a string without providing the information about being an URL object.
Overall, I am not fond of special handling URL during inspection, especially as our detection is only a heuristic that can definitely trigger for lots of other objects (Boolean(self?.href && self.protocol && self.auth === undefined && self.path === undefined)). We could see if we want to change the implementation in URL itself that no special handling would be needed.

Copy link
Contributor

@MCprotein MCprotein Jul 23, 2024

Choose a reason for hiding this comment

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

@BridgeAR Hi.
I thought it would be a simple solution to using instanceof, but I found that Using a symbol or instanceof would not be able to recognize URL objects coming from other implementations (e.g. in Electron) in the annotation

Could you tell me in what direction you think the implementation of the URL object should be changed?

Copy link
Member

Choose a reason for hiding this comment

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

That is the reason why we use the heuristic. Let's imagine a user handles websites and has a structure like: { href: 'string', protocol: 'ftp', country: 'GER' }. It would now be detected as URL. Our detection is only working in URL itself, by expecting objects of a specific shape. It does not work for a general input case like inspect. It is fine in assert, due to just parsing a few properties multiple times. The effective difference is triggering the getter for href.

I understand that it would be good to detect changes between input in case an assertion fails, I am just not sure how to ideally indicate that difference. We could consider activating custom inspection. It was turned off by default while using assertions as it is likely that it would show better debugging information in most cases. This just prevents getters from being accessed.

@theoludwig
Copy link
Contributor

What is the status of this PR? Is there any way, can anyone help to move this forward? 😄

@MCprotein
Copy link
Contributor

@meixg hi, What is the current status of this PR?

@RedYetiDev RedYetiDev added the stalled Issues and PRs that are stalled. label Aug 9, 2024
Copy link
Contributor

github-actions bot commented Aug 9, 2024

This issue/PR was marked as stalled, it will be automatically closed in 30 days. If it should remain open, please leave a comment explaining why it should remain open.

@RedYetiDev
Copy link
Member

Hi! People appear to have been requesting updates since March. For that reason, I've marked this PR as stalled. When action is taken, I'll be happy to un-mark it :-).

} else if (isURL(value) && !(recurseTimes > ctx.depth && ctx.depth !== null)) {
base = value.href;
if (keys.length === 0 && protoProps === undefined) {
return base;
Copy link
Member

Choose a reason for hiding this comment

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

That is the reason why we use the heuristic. Let's imagine a user handles websites and has a structure like: { href: 'string', protocol: 'ftp', country: 'GER' }. It would now be detected as URL. Our detection is only working in URL itself, by expecting objects of a specific shape. It does not work for a general input case like inspect. It is fine in assert, due to just parsing a few properties multiple times. The effective difference is triggering the getter for href.

I understand that it would be good to detect changes between input in case an assertion fails, I am just not sure how to ideally indicate that difference. We could consider activating custom inspection. It was turned off by default while using assertions as it is likely that it would show better debugging information in most cases. This just prevents getters from being accessed.

const a = new URL('http://foo');
const b = new URL('http://bar');

assertNotDeepOrStrict(a, b);
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we want a test for the error message, due to this being blocked for exactly that reason.

@RedYetiDev RedYetiDev removed the stalled Issues and PRs that are stalled. label Oct 1, 2024
@meixg meixg added the request-ci Add this label to start a Jenkins CI on a PR. label Oct 5, 2024
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Oct 5, 2024
@nodejs-github-bot
Copy link
Collaborator

Copy link

codecov bot commented Oct 5, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 88.41%. Comparing base (98788da) to head (ea84315).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #50853      +/-   ##
==========================================
+ Coverage   87.89%   88.41%   +0.52%     
==========================================
  Files         652      652              
  Lines      186589   186604      +15     
  Branches    35750    36062     +312     
==========================================
+ Hits       163999   164988     +989     
+ Misses      15816    14889     -927     
+ Partials     6774     6727      -47     
Files with missing lines Coverage Δ
lib/internal/util/comparisons.js 100.00% <100.00%> (ø)
lib/internal/util/inspect.js 99.95% <100.00%> (-0.05%) ⬇️

... and 92 files with indirect coverage changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assert Issues and PRs related to the assert subsystem. needs-ci PRs that need a full CI run. util Issues and PRs related to the built-in util module. whatwg-url Issues and PRs related to the WHATWG URL implementation.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Node v20] assert.deepEqual doesn't detect two different URLs
10 participants