fix(coverage): expand multi-line statements to all lines#154
fix(coverage): expand multi-line statements to all lines#154sohil-kshirsagar merged 3 commits intomainfrom
Conversation
V8 coverage uses byte offsets which ast-v8-to-istanbul converts to
Istanbul's statementMap with start/end line numbers. Previously we only
recorded the start line of each statement, so multi-line statements like
res.json({...}) spanning lines 14-20 only showed line 14 as covered.
Now we expand each statement to all lines in its range. Statements are
processed largest-first so inner (more specific) statements override
outer ones — e.g. a try-catch block (covered) contains a catch body
(uncovered), and the catch body correctly stays uncovered.
Extract extractLineCoverage() as a standalone testable function with
4 unit tests covering: multi-line expansion, single-line statements,
overlapping statement override, and empty input.
Before: 81.2% (52/64 lines) on example-express-server
After: 87.8% (144/164 lines) — correct count with full line tracking
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3c9d9ac. Configure here.
There was a problem hiding this comment.
1 issue found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/core/coverageProcessor.ts">
<violation number="1" location="src/core/coverageProcessor.ts:89">
P1: Unconditional overwrite of per-line counts can mark covered lines as uncovered when multiple statements map to the same line.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
Review bots correctly identified that unconditional last-write-wins could mark covered lines as uncovered when two same-size statements map to the same line (e.g. if(x) foo(); else bar();). Now track the statement size per line: strictly smaller (inner) statements override, same-size statements use Math.max so covered wins. Add test for same-size overlap case.
|
Tip New to Tusk? Learn more here. Unit TestsGenerated 4 tests - 4 passedTest Summary
ResultsTusk's tests all pass. The test suite validates the core logic of Code ReviewTusk Review: No issues foundView check history
Was Tusk helpful? Give feedback by reacting with 👍 or 👎 |



Multi-line JavaScript statements (like
res.json({...})spanning lines 14-20) only showed coverage on their first line. The rest appeared as gaps in the coverage UI — neither covered nor uncovered.Root cause
coverageProcessor.tsextracts line coverage from Istanbul'sstatementMap, which hasstartandendline/column pairs for each statement. The code only readstmtMap.start.line, ignoringstmtMap.end.line:Fix
Expand each statement to all lines in its range, and process statements largest-first so inner (more specific) statements override outer ones. This handles the key edge case: a try-catch block (covered, count=1) contains a catch body (uncovered, count=0) — the catch body must stay uncovered even though it's inside a covered range.
Extracted the logic into a standalone
extractLineCoverage()function for testability.Impact on coverage numbers
Tested on
example-express-server:The total coverable lines increased from 64 to 164 because continuation lines of multi-line statements are now counted. The percentage changed because both covered and coverable increased proportionally.
Review notes
coverage.pyreports individual lines natively