fix(coverage): compare overall on shared files and cover compact edges

Deleting 100%-covered packages such as recovery falsely regressed overall
percent against merge-base. Baseline overall now uses only files still
present in the candidate profile, with a 0.1pp CI tolerance. Also exercise
stripSchemaValueCompact nested map/slice branches.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
玉澜
2026-08-06 13:06:52 +08:00
co-authored by Cursor
parent 9266632694
commit fd3c82aa91
4 changed files with 81 additions and 5 deletions
+27 -1
View File
@@ -132,7 +132,10 @@ func run(
fmt.Fprintln(stderr, baselineErr)
return 2
}
baselineOverall = coveragePercent(baseline)
// Compare overall non-regression on the shared file set only.
// Deleted packages (for example a retired 100%-covered helper tree)
// must not create a false overall regression against merge-base.
baselineOverall = coveragePercent(filterBlocksByFiles(baseline, profileFiles(overall)))
}
}
diff, err := readProfiles(diffPaths, modulePath)
@@ -483,6 +486,29 @@ func coveragePercent(blocks []coverageBlock) float64 {
return float64(covered) * 100 / float64(total)
}
func profileFiles(blocks []coverageBlock) map[string]bool {
files := map[string]bool{}
for _, block := range blocks {
if block.File != "" {
files[block.File] = true
}
}
return files
}
func filterBlocksByFiles(blocks []coverageBlock, allowed map[string]bool) []coverageBlock {
if len(allowed) == 0 {
return nil
}
filtered := make([]coverageBlock, 0, len(blocks))
for _, block := range blocks {
if allowed[block.File] {
filtered = append(filtered, block)
}
}
return filtered
}
// mergeCoverageBlocks unions duplicate blocks emitted by cross-package
// coverage. A block is covered when any instrumented test binary executed it;
// counting the same source block once per binary would both dilute the overall
+29 -3
View File
@@ -92,7 +92,7 @@ func TestRunDefaultsToFullChangedCodeCoverage(t *testing.T) {
}
}
func TestRunEvaluatesBaselineProfileWithCandidateCoverageModel(t *testing.T) {
func TestCrossPlatformCoverageRunEvaluatesBaselineProfileWithCandidateCoverageModel(t *testing.T) {
profile := filepath.Join(t.TempDir(), "coverage.out")
body := "mode: atomic\n" +
"example.com/project/internal/a.go:10.1,12.2 5 0\n" +
@@ -101,9 +101,14 @@ func TestRunEvaluatesBaselineProfileWithCandidateCoverageModel(t *testing.T) {
if err := os.WriteFile(profile, []byte(body), 0o600); err != nil {
t.Fatal(err)
}
baseline := filepath.Join(t.TempDir(), "baseline.out")
baselineBody := body + "example.com/project/internal/deleted.go:1.1,2.2 100 1\n"
if err := os.WriteFile(baseline, []byte(baselineBody), 0o600); err != nil {
t.Fatal(err)
}
args := []string{
"--overall-profile", profile,
"--baseline-profile", profile,
"--baseline-profile", baseline,
"--diff-profile", profile,
"--base-ref", "base",
"--module", "example.com/project",
@@ -115,8 +120,10 @@ func TestRunEvaluatesBaselineProfileWithCandidateCoverageModel(t *testing.T) {
if code := run(args, &stdout, &stderr, loader, nil); code != 0 {
t.Fatalf("run code=%d stderr=%s", code, stderr.String())
}
// Candidate overall stays 50%; merge-base ignores the deleted 100%-covered
// package so non-regression compares the shared file set only.
if !strings.Contains(stdout.String(), "overall coverage: 50.0000% (merge-base 50.0000%") {
t.Fatalf("baseline and candidate did not share one coverage model: %q", stdout.String())
t.Fatalf("shared-file baseline comparison failed: %q", stdout.String())
}
}
@@ -436,6 +443,25 @@ func TestEvaluateAllowsMeasurementTolerance(t *testing.T) {
}
}
func TestCrossPlatformCoverageFilterBlocksByFilesDropsDeletedPackages(t *testing.T) {
baseline := []coverageBlock{
{File: "internal/keep.go", StartLine: 1, EndLine: 10, Statements: 50, Count: 1},
{File: "internal/keep.go", StartLine: 11, EndLine: 20, Statements: 50, Count: 0},
{File: "internal/deleted.go", StartLine: 1, EndLine: 40, Statements: 100, Count: 1},
}
currentFiles := profileFiles([]coverageBlock{
{File: "internal/keep.go", StartLine: 1, EndLine: 8, Statements: 40, Count: 1},
})
filtered := filterBlocksByFiles(baseline, currentFiles)
got := coveragePercent(filtered)
if got != 50 {
t.Fatalf("shared-file baseline = %.4f%%, want 50%% (deleted 100%%-covered package excluded)", got)
}
if len(profileFiles(filtered)) != 1 || !profileFiles(filtered)["internal/keep.go"] {
t.Fatalf("filtered files = %#v, want only keep.go", profileFiles(filtered))
}
}
func TestEvaluateDefaultsToZeroOverallTolerance(t *testing.T) {
result := evaluate(gateInput{
Overall: []coverageBlock{{Statements: 403, Count: 1}, {Statements: 597, Count: 0}},