diff --git a/pkg/testcoverage/check.go b/pkg/testcoverage/check.go index af37dab6..d9e357ce 100644 --- a/pkg/testcoverage/check.go +++ b/pkg/testcoverage/check.go @@ -35,7 +35,7 @@ func Check(w io.Writer, cfg Config) bool { } } - err = generateAndSaveBadge(w, cfg, result.TotalCoverage) + err = generateAndSaveBadge(w, cfg, result.TotalStats.CoveredPercentage()) if err != nil { fmt.Fprintf(w, "failed to generate and save badge: %v\n", err) return false @@ -58,23 +58,14 @@ func reportForHuman(w io.Writer, result AnalyzeResult) string { func Analyze(cfg Config, coverageStats []coverage.Stats) AnalyzeResult { thr := cfg.Threshold - overrideRules := compileOverridePathRules(cfg) - filesBelowThreshold := checkCoverageStatsBelowThreshold(coverageStats, thr.File, overrideRules) - - packagesBelowThreshold := checkCoverageStatsBelowThreshold( - makePackageStats(coverageStats), thr.Package, overrideRules, - ) - - totalStats := coverage.CalcTotalStats(coverageStats) - meetsTotalCoverage := len(coverageStats) == 0 || totalStats.CoveredPercentage() >= thr.Total - return AnalyzeResult{ - Threshold: thr, - FilesBelowThreshold: filesBelowThreshold, - PackagesBelowThreshold: packagesBelowThreshold, - MeetsTotalCoverage: meetsTotalCoverage, - TotalCoverage: totalStats.CoveredPercentage(), + Threshold: thr, + FilesBelowThreshold: checkCoverageStatsBelowThreshold(coverageStats, thr.File, overrideRules), + PackagesBelowThreshold: checkCoverageStatsBelowThreshold( + makePackageStats(coverageStats), thr.Package, overrideRules, + ), + TotalStats: coverage.CalcTotalStats(coverageStats), } } diff --git a/pkg/testcoverage/check_test.go b/pkg/testcoverage/check_test.go index 5a093c7f..e2d60716 100644 --- a/pkg/testcoverage/check_test.go +++ b/pkg/testcoverage/check_test.go @@ -201,7 +201,7 @@ func Test_Analyze(t *testing.T) { result := Analyze(Config{}, nil) assert.Empty(t, result.FilesBelowThreshold) assert.Empty(t, result.PackagesBelowThreshold) - assert.Equal(t, 0, result.TotalCoverage) + assert.Equal(t, 0, result.TotalStats.CoveredPercentage()) }) t.Run("total coverage above threshold", func(t *testing.T) { diff --git a/pkg/testcoverage/coverage/types.go b/pkg/testcoverage/coverage/types.go index 9c9ea882..a851a41c 100644 --- a/pkg/testcoverage/coverage/types.go +++ b/pkg/testcoverage/coverage/types.go @@ -1,6 +1,7 @@ package coverage import ( + "fmt" "regexp" "strings" ) @@ -17,7 +18,24 @@ func (s Stats) CoveredPercentage() int { } //nolint:mnd // relax +func (s Stats) Str() string { + c := s.CoveredPercentage() + + if c == 100 { // precision not needed + return fmt.Sprintf("%d%% (%d/%d)", c, s.Covered, s.Total) + } else if c < 10 { // adds space for singe digit number + return fmt.Sprintf(" %.1f%% (%d/%d)", coveredPercentageF(s.Total, s.Covered), s.Covered, s.Total) + } + + return fmt.Sprintf("%.1f%% (%d/%d)", coveredPercentageF(s.Total, s.Covered), s.Covered, s.Total) +} + func CoveredPercentage(total, covered int64) int { + return int(coveredPercentageF(total, covered)) +} + +//nolint:mnd // relax +func coveredPercentageF(total, covered int64) float64 { if total == 0 { return 0 } @@ -26,7 +44,7 @@ func CoveredPercentage(total, covered int64) int { return 100 } - return int(float64(covered*100) / float64(total)) + return float64(covered*100) / float64(total) } func stripPrefix(name, prefix string) string { diff --git a/pkg/testcoverage/coverage/types_test.go b/pkg/testcoverage/coverage/types_test.go index 71c373c8..99b60776 100644 --- a/pkg/testcoverage/coverage/types_test.go +++ b/pkg/testcoverage/coverage/types_test.go @@ -28,3 +28,12 @@ func TestCoveredPercentage(t *testing.T) { assert.Equal(t, tc.percentage, CoveredPercentage(tc.total, tc.covered)) } } + +func TestStatStr(t *testing.T) { + t.Parallel() + + assert.Equal(t, " 0.0% (0/0)", Stats{}.Str()) + assert.Equal(t, " 9.1% (1/11)", Stats{Covered: 1, Total: 11}.Str()) + assert.Equal(t, "22.2% (2/9)", Stats{Covered: 2, Total: 9}.Str()) + assert.Equal(t, "100% (10/10)", Stats{Covered: 10, Total: 10}.Str()) +} diff --git a/pkg/testcoverage/report.go b/pkg/testcoverage/report.go index 79d97ebd..7efd8444 100644 --- a/pkg/testcoverage/report.go +++ b/pkg/testcoverage/report.go @@ -47,11 +47,11 @@ func ReportForHuman(w io.Writer, result AnalyzeResult) { if thr.Total > 0 { // Total threshold report fmt.Fprintf(tabber, "Total coverage threshold (%d%%) satisfied:\t", thr.Total) - fmt.Fprint(tabber, statusStr(result.MeetsTotalCoverage)) + fmt.Fprint(tabber, statusStr(result.MeetsTotalCoverage())) fmt.Fprint(tabber, "\n") } - fmt.Fprintf(tabber, "Total test coverage: %d%%\n", result.TotalCoverage) + fmt.Fprintf(tabber, "Total test coverage: %s\n", result.TotalStats.Str()) } func reportIssuesForHuman(w io.Writer, coverageStats []coverage.Stats) { @@ -62,7 +62,7 @@ func reportIssuesForHuman(w io.Writer, coverageStats []coverage.Stats) { fmt.Fprintf(w, "\n below threshold:\tcoverage:\tthreshold:") for _, stats := range coverageStats { - fmt.Fprintf(w, "\n %s\t%d%%\t%d%%", stats.Name, stats.CoveredPercentage(), stats.Threshold) + fmt.Fprintf(w, "\n %s\t%s\t%d%%", stats.Name, stats.Str(), stats.Threshold) } fmt.Fprintf(w, "\n") @@ -82,8 +82,8 @@ func ReportForGithubAction(w io.Writer, result AnalyzeResult) { for _, stats := range result.FilesBelowThreshold { title := "File test coverage below threshold" msg := fmt.Sprintf( - "%s: coverage: %d%%; threshold: %d%%", - title, stats.CoveredPercentage(), stats.Threshold, + "%s: coverage: %s; threshold: %d%%", + title, stats.Str(), stats.Threshold, ) reportLineError(stats.Name, title, msg) } @@ -91,17 +91,17 @@ func ReportForGithubAction(w io.Writer, result AnalyzeResult) { for _, stats := range result.PackagesBelowThreshold { title := "Package test coverage below threshold" msg := fmt.Sprintf( - "%s: package: %s; coverage: %d%%; threshold: %d%%", - title, stats.Name, stats.CoveredPercentage(), stats.Threshold, + "%s: package: %s; coverage: %s; threshold: %d%%", + title, stats.Name, stats.Str(), stats.Threshold, ) reportError(title, msg) } - if !result.MeetsTotalCoverage { + if !result.MeetsTotalCoverage() { title := "Total test coverage below threshold" msg := fmt.Sprintf( - "%s: coverage: %d%%; threshold: %d%%", - title, result.TotalCoverage, result.Threshold.Total, + "%s: coverage: %s; threshold: %d%%", + title, result.TotalStats.Str(), result.Threshold.Total, ) reportError(title, msg) } @@ -121,11 +121,11 @@ func SetGithubActionOutput(result AnalyzeResult, report string) error { return fmt.Errorf("could not open GitHub output file: %w", err) } - totalStr := strconv.Itoa(result.TotalCoverage) + totalStr := strconv.Itoa(result.TotalStats.CoveredPercentage()) return errors.Join( setOutputValue(file, gaOutputTotalCoverage, totalStr), - setOutputValue(file, gaOutputBadgeColor, badge.Color(result.TotalCoverage)), + setOutputValue(file, gaOutputBadgeColor, badge.Color(result.TotalStats.CoveredPercentage())), setOutputValue(file, gaOutputBadgeText, totalStr+"%"), setOutputValue(file, gaOutputReport, multiline(report)), file.Close(), diff --git a/pkg/testcoverage/report_test.go b/pkg/testcoverage/report_test.go index c9bdbb54..9edf956d 100644 --- a/pkg/testcoverage/report_test.go +++ b/pkg/testcoverage/report_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/assert" . "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage" + "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage/coverage" ) func Test_ReportForHuman(t *testing.T) { @@ -22,7 +23,7 @@ func Test_ReportForHuman(t *testing.T) { t.Parallel() buf := &bytes.Buffer{} - ReportForHuman(buf, AnalyzeResult{Threshold: thr, MeetsTotalCoverage: true}) + ReportForHuman(buf, AnalyzeResult{Threshold: thr, TotalStats: coverage.Stats{}}) assertHumanReport(t, buf.String(), 3, 0) }) @@ -30,7 +31,7 @@ func Test_ReportForHuman(t *testing.T) { t.Parallel() buf := &bytes.Buffer{} - ReportForHuman(buf, AnalyzeResult{Threshold: thr, MeetsTotalCoverage: false}) + ReportForHuman(buf, AnalyzeResult{Threshold: thr, TotalStats: coverage.Stats{Total: 1}}) assertHumanReport(t, buf.String(), 2, 1) }) diff --git a/pkg/testcoverage/types.go b/pkg/testcoverage/types.go index 9efcaa9e..6e7e9825 100644 --- a/pkg/testcoverage/types.go +++ b/pkg/testcoverage/types.go @@ -12,16 +12,19 @@ type AnalyzeResult struct { Threshold Threshold FilesBelowThreshold []coverage.Stats PackagesBelowThreshold []coverage.Stats - MeetsTotalCoverage bool - TotalCoverage int + TotalStats coverage.Stats } func (r *AnalyzeResult) Pass() bool { - return r.MeetsTotalCoverage && + return r.MeetsTotalCoverage() && len(r.FilesBelowThreshold) == 0 && len(r.PackagesBelowThreshold) == 0 } +func (r *AnalyzeResult) MeetsTotalCoverage() bool { + return r.TotalStats.Total == 0 || r.TotalStats.CoveredPercentage() >= r.Threshold.Total +} + func packageForFile(filename string) string { i := strings.LastIndex(filename, "/") if i == -1 {