From 7daec9717d748ba0eff2087c4a3710259ec5b676 Mon Sep 17 00:00:00 2001 From: Coding On Star <447357187@qq.com> Date: Mon, 16 Mar 2026 15:09:46 +0800 Subject: [PATCH] feat(diff-coverage): enhance coverage reporting for multi-line statements and branches (#33516) Co-authored-by: CodingOnStar --- .../check-components-diff-coverage.test.ts | 47 +++++++++++++++++++ .../check-components-diff-coverage-lib.mjs | 19 +++++++- .../check-components-diff-coverage.mjs | 4 +- 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/web/__tests__/check-components-diff-coverage.test.ts b/web/__tests__/check-components-diff-coverage.test.ts index 690c7a512b..9ce8b30ceb 100644 --- a/web/__tests__/check-components-diff-coverage.test.ts +++ b/web/__tests__/check-components-diff-coverage.test.ts @@ -79,6 +79,23 @@ describe('check-components-diff-coverage helpers', () => { }) }) + it('should report the first changed line inside a multi-line uncovered statement', () => { + const entry = { + s: { 0: 0 }, + statementMap: { + 0: { start: { line: 10 }, end: { line: 14 } }, + }, + } + + const coverage = getChangedStatementCoverage(entry, new Set([13, 14])) + + expect(coverage).toEqual({ + covered: 0, + total: 1, + uncoveredLines: [13], + }) + }) + it('should fail changed lines when a source file has no coverage entry', () => { const coverage = getChangedStatementCoverage(undefined, new Set([42, 43])) @@ -118,6 +135,36 @@ describe('check-components-diff-coverage helpers', () => { }) }) + it('should report the first changed line inside a multi-line uncovered branch arm', () => { + const entry = { + b: { + 0: [0, 0], + }, + branchMap: { + 0: { + line: 30, + loc: { start: { line: 30 }, end: { line: 35 } }, + locations: [ + { start: { line: 31 }, end: { line: 34 } }, + { start: { line: 35 }, end: { line: 38 } }, + ], + type: 'if', + }, + }, + } + + const coverage = getChangedBranchCoverage(entry, new Set([33])) + + expect(coverage).toEqual({ + covered: 0, + total: 2, + uncoveredBranches: [ + { armIndex: 0, line: 33 }, + { armIndex: 1, line: 35 }, + ], + }) + }) + it('should ignore changed lines with valid pragma reasons and report invalid pragmas', () => { const sourceCode = [ 'const a = 1', diff --git a/web/scripts/check-components-diff-coverage-lib.mjs b/web/scripts/check-components-diff-coverage-lib.mjs index 2b158fd8ce..56318f38a2 100644 --- a/web/scripts/check-components-diff-coverage-lib.mjs +++ b/web/scripts/check-components-diff-coverage-lib.mjs @@ -100,7 +100,7 @@ export function getChangedStatementCoverage(entry, changedLines) { continue } - uncoveredLines.push(statement.start.line) + uncoveredLines.push(getFirstChangedLineInRange(statement, normalizedChangedLines)) } return { @@ -111,6 +111,7 @@ export function getChangedStatementCoverage(entry, changedLines) { } export function getChangedBranchCoverage(entry, changedLines) { + const normalizedChangedLines = [...(changedLines ?? [])].sort((a, b) => a - b) if (!entry) { return { covered: 0, @@ -141,7 +142,7 @@ export function getChangedBranchCoverage(entry, changedLines) { const location = locations[armIndex] ?? branch.loc ?? branch uncoveredBranches.push({ armIndex, - line: getLocationStartLine(location) ?? branch.line ?? 1, + line: getFirstChangedLineInRange(location, normalizedChangedLines, branch.line ?? 1), }) } } @@ -247,6 +248,20 @@ function rangeIntersectsChangedLines(location, changedLines) { return false } +function getFirstChangedLineInRange(location, changedLines, fallbackLine = 1) { + const startLine = getLocationStartLine(location) + const endLine = getLocationEndLine(location) ?? startLine + if (!startLine || !endLine) + return startLine ?? fallbackLine + + for (const lineNumber of changedLines) { + if (lineNumber >= startLine && lineNumber <= endLine) + return lineNumber + } + + return startLine ?? fallbackLine +} + function getLocationStartLine(location) { return location?.start?.line ?? location?.line ?? null } diff --git a/web/scripts/check-components-diff-coverage.mjs b/web/scripts/check-components-diff-coverage.mjs index 301f07309b..6a861c4f52 100644 --- a/web/scripts/check-components-diff-coverage.mjs +++ b/web/scripts/check-components-diff-coverage.mjs @@ -338,8 +338,8 @@ function buildSummary({ } lines.push(`Changed source files checked: ${changedSourceFiles.length}`) - lines.push(`Changed statement coverage: ${percentage(diffTotals.statements.covered, diffTotals.statements.total).toFixed(2)}%`) - lines.push(`Changed branch coverage: ${percentage(diffTotals.branches.covered, diffTotals.branches.total).toFixed(2)}%`) + lines.push(`Changed statement coverage: ${formatDiffPercent(diffTotals.statements)}`) + lines.push(`Changed branch coverage: ${formatDiffPercent(diffTotals.branches)}`) return lines }