fix(assert): test a RegExp matcher against String(thrown), and make it terminal - #9228
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
Included review availability: Your plan provides up to 8 included reviews per hour; 0 remain after this review. 📝 WalkthroughWalkthroughRegExp matchers in ChangesRegExp assertion matcher correction
Estimated code review effort: 2 (Simple) | ~15 minutes Merge Risk: ⚪ Minimal · up to The PR makes RegExp thrown-error matching terminal and aligns its input with the stringified error across the assertion APIs; no actionable merge-blocking risk remains beyond normal checks and review. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Linked Issues checkExplanation The implementation satisfies issue Full details: Docstring CoverageExplanation Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 2 files. (1 skipped: 1 unsupported.)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…t terminal
The previous commit on this branch added `return false` after the RegExp
block. That stopped the fallthrough into `instanceof`, but kept the line that
caused it: a retry of the pattern against `thrown.message`.
Node tests a RegExp matcher against `String(thrown)` and nothing else, and
treats RegExp as a terminal matcher category. The whole block collapses to one
statement, which fixes both halves at the single point `throws`,
`doesNotThrow`, `rejects`, and `doesNotReject` all route through:
- An anchored pattern matching the bare message but not the stringified error
was wrongly accepted. `assert.throws(() => { throw new Error("nope") },
/^nope/)` passed, where Node reports an AssertionError because `String(err)`
is "Error: nope". Same for a thrown non-error carrying a `message` property,
whose `String()` is "[object Object]".
- A pattern matching neither reached `js_instanceof_dynamic(thrown, regexp)`
and surfaced as a TypeError instead of an AssertionError, so throws/rejects
reported the wrong error class and doesNotThrow/doesNotReject failed to
rethrow the original error.
A RegExp value on a validator key (`{ message: /bad/ }`) is a different matcher
and is still tested against that property in `object_matcher_matches`.
The `thrown.message` retry dates to the original implementation in #1924 and
was never a workaround for anything else.
The pre-existing `assert/errors/strict-throws-validation.ts` could not catch
either bug: `/will-not-match/` matches neither input, so it cannot tell them
apart, and it prints only `name` and `code`. The new fixture covers both inputs
across all four entry points and matches Node 26.5.1 byte for byte. The unit
tests replace the setjmp-based one, which the previous fix also passed.
Fixes #9227
Refs #9202
Claude-Session: https://claude.ai/code/session_01QFubuLjMeJBhrHSfCuoPMp
79ff37b to
10977c0
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
|
Merged. Validated on a shared branch with #9228, #9257, #9263, #9271, #9272, #9274, #9277, #9279 and #9280 — one build, one validation pass, then split back out and merged individually. Results across the batch:
One probe ( |
Summary
The first commit on this branch added
return falseafter the RegExp block inexpected_error_matches. That stopped the fallthrough intoinstanceof, butkept the line that caused it — a retry of the pattern against
thrown.message— so a whole second bug survived.
Node tests a RegExp matcher against
String(thrown)and nothing else, andtreats RegExp as a terminal matcher category. The block collapses to one
statement:
That fixes both halves at the single point
throws,doesNotThrow,rejects,and
doesNotRejectall route through.The two bugs
Wrong input. An anchored pattern matching the bare message but not the
stringified error was wrongly accepted, because
String(new Error("nope"))is"Error: nope":Same for a thrown non-error carrying a
messageproperty, whoseString()is"[object Object]".Wrong control flow. A pattern matching neither input reached
js_instanceof_dynamic(thrown, regexp)and surfaced as aTypeErrorinstead ofan
AssertionError, sothrows/rejectsreported the wrong error class anddoesNotThrow/doesNotRejectfailed to rethrow the original error.A RegExp value on a validator key (
{ message: /bad/ }) is a differentmatcher and is still tested against that property in
object_matcher_matches.The
thrown.messageretry dates to the original implementation in #1924 and wasnever a workaround for anything else.
Why the existing fixture could not catch this
assert/errors/strict-throws-validation.tsuses/will-not-match/, a patternmatching neither the message nor the stringified error, so it cannot tell the
two inputs apart — and it prints only
nameandcode.assert/errors/throws-regexp-matcher-input.tscovers both inputs across allfour entry points and matches Node 26.5.1 byte for byte on 9 cases. The unit
tests replace the setjmp-based one, which the previous fix also passed:
Known remaining gap (not fixed here)
Node's generated message is
The input did not match the regular expression /x/. Input:\n\n'Error: nope'\n; Perry emits the genericThe thrown error did not match the expected matcher. That fallback is shared by every matchercategory, so patching only the regexp arm would leave the message layer
half-parity. Recorded in the changelog fragment as separate work.
Related issue
Fixes #9227
Refs #9202
Test plan
RUST_TEST_THREADS=1 cargo test -p perry-runtime regexp_matcher_tests— 3 passed./run_parity_tests.sh --suite node-suite --module assert— 71 PASS, 0 fail, 0 compile fail, 0 crash, 0 skip (100.0%), against the pinned Node 26.5.1cargo fmtclean;assert.rsis 1368 lines (under the 2000-line cap)changelog.d/9228-assert-regexp-matcher-input.md(thelintjob requires a fragment for anycrates/change)fix:formatNote on the oracle: run the suite with the pinned Node on PATH. With Node
v24 instead of 26.5.1,
assert/imports/calltracker-shapereports a falsemismatch —
assert.CallTrackerstill exists in v24 and was removed by v26, sothe oracle disagrees with itself, not with Perry. Same tree: 70/71 under v24,
71/71 under v26.5.1.
Summary by CodeRabbit
Bug Fixes
Tests