-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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 single assert first line #21626
Conversation
Just so people know in what way this could fail: 'use strict'; const assert = require('assert'); assert('');
// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(false); This fails with: |
I won't push hard for it, but my thinking is that you might as well write a test because if you don't, that line will show up as uncovered in our coverage report and someone will write a test for it but they may not know what to test for. Since you have all the context, might as well write the test. Sets a good example for others too, I suppose. Easiest way to make it work might be to put your test code above in a fixture and invoke the fixture using the child_process module. Fixtures don't get linted so there won't be any lint problems to overcome. |
3e2b925
to
83e32f6
Compare
There is actually a simple solution to properly fix the issue, so I went for that and added a test case as well. CI https://ci.nodejs.org/job/node-test-pull-request/15722/ PTAL |
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.
Test + fixture LGTM.
0a721e4
to
93a1fbf
Compare
I pushed another commit that should be squashed later on. The former algorithm did not work for the first line and it was not working well with very long lines (this could be the case for e.g. minified code. This addresses that by now only getting exactly what is necessary to produce the correct output. This reduces the number of reads and allocations in multiple cases. |
I looked at the test and fixture, but the actual code change needs careful review from someone...
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.
TEST+Fixture LGTM.
Can you add some more comments in the algorithm? it's not really readable atm. A description on what's getBuffer
does would also be very helpful.
I just added a couple of comments to clarify the algorithm. I hope that makes it clearer what is actually going on. |
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.
LGTM
Would be good to get another review on this from someone. @nodejs/testing |
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.
just a couple questions for you -- if it is possible to check line # in the assertion this would be nice, but sounds like it's a hassle?
() => require(path('assert-first-line')), | ||
{ | ||
name: 'AssertionError [ERR_ASSERTION]', | ||
message: "The expression evaluated to a falsy value:\n\n assert.ok('')\n" |
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.
could we assert that line 1
shows up somewhere in the stack trace, I imagine you already thought of this and it's too much of a hassle?
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 am not sure if I understand exactly what you request. The stack trace is not impacted by the code that is read here.
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.
Since this bug was only manifesting itself if an exception happened on the first line of the application, I was wondering if it's worthwhile asserting that this was the line in the stack trace that caused the error.
This is probably overkill, since the fixture name assert-first-line
is pretty clear about what's being tested. No blockers from me.
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.
Since the fixture itself can only throw on line 1, I think it is fine to keep it as is :)
lib/assert.js
Outdated
const buffers = []; | ||
do { | ||
const buffer = Buffer.allocUnsafe(bytesPerRead); | ||
let bytesPerRead = line === 0 ? column + 1000 : 8192; |
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.
purely out of curiosity, why switch to reading 1000 bytes at a time rather than 8192? I'm guessing both values are somewhat arbitrary?
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 does not read 1000 bytes at a time but the exact number of bytes necessary. So we either safe reading to many bytes (the necessary bytes could be smaller than 8kb) or we safe extra read calls (we know that the necessary bytes are more than 8kb). So it just optimizes for these two cases and in all other cases it will still read exactly 8kb on each read.
536a0e7
to
d1638f4
Compare
1) If simple assert is called in the very first line of a file and it causes an error, it used to report the wrong code. The reason is that the column that is reported is faulty. This is fixed by subtracting the offset from now on in such cases. 2) The actual code read is now limited to the part that is actually required to visualize the call site. All other code in e.g. minified files will not cause a significant overhead anymore. 3) The number of allocations is now significantly lower than it used to be. The buffer is reused until the correct line in the code is found. In general the algorithm tries to safe operations where possible. 4) The indentation is now corrected depending on where the statement actually beginns. 5) It is now possible to handle `.call()` and `.apply()` properly. 6) The user defined function name will now always be used instead of only choosing either `assert.ok()` or `assert()`.
d1638f4
to
b8fb486
Compare
@bcoe @mcollina @Trott PTAL. I had to do further adjustments as my former algorithm struggled with multi byte characters. So took a step back and rewrote the algorithm from scratch. All the changes are listed in the commit message. Now it contains more changes than just fixing the first line as it also improves the output, the indentation, the performance and it is able to handle more input properly. In the end I still believe that this is a patch though as it just fixes things in a way as they should have been before. It will also not impact most use cases. |
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.
LGTM
It seems some CI is failing, can you click “resume build” |
All checks passed :) |
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.
LGTM
1) If simple assert is called in the very first line of a file and it causes an error, it used to report the wrong code. The reason is that the column that is reported is faulty. This is fixed by subtracting the offset from now on in such cases. 2) The actual code read is now limited to the part that is actually required to visualize the call site. All other code in e.g. minified files will not cause a significant overhead anymore. 3) The number of allocations is now significantly lower than it used to be. The buffer is reused until the correct line in the code is found. In general the algorithm tries to safe operations where possible. 4) The indentation is now corrected depending on where the statement actually beginns. 5) It is now possible to handle `.call()` and `.apply()` properly. 6) The user defined function name will now always be used instead of only choosing either `assert.ok()` or `assert()`. PR-URL: nodejs#21626 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ben Coe <bencoe@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Landed in 43ee4d6 🎉 |
1) If simple assert is called in the very first line of a file and it causes an error, it used to report the wrong code. The reason is that the column that is reported is faulty. This is fixed by subtracting the offset from now on in such cases. 2) The actual code read is now limited to the part that is actually required to visualize the call site. All other code in e.g. minified files will not cause a significant overhead anymore. 3) The number of allocations is now significantly lower than it used to be. The buffer is reused until the correct line in the code is found. In general the algorithm tries to safe operations where possible. 4) The indentation is now corrected depending on where the statement actually beginns. 5) It is now possible to handle `.call()` and `.apply()` properly. 6) The user defined function name will now always be used instead of only choosing either `assert.ok()` or `assert()`. PR-URL: #21626 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ben Coe <bencoe@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
If simple assert is called in the very first line of a file and it
causes an error, it will report the wrong code. The reason is that
the column that is reported is faulty.
I tested this locally as it is not as nice to write a proper test for this and I am uncertain if it is worth it adding one. I feel it should be fine to land this without a test if no one disagrees.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes