shad-go/tools/testtool/commands/coverage.go

97 lines
2.1 KiB
Go
Raw Normal View History

2020-03-18 22:29:11 +00:00
package commands
import (
"fmt"
"go/parser"
"go/token"
"strconv"
"strings"
"golang.org/x/tools/cover"
)
// coverageCommentPrefix is a prefix of coverage comment.
//
// Coverage comment has the following form:
//
// // min coverage: 80.5%
const coverageCommentPrefix = "min coverage: "
type CoverageRequirements struct {
Enabled bool
Percent float64
}
// getCoverageRequirements searches for comment in test files
// that specifies test coverage requirements.
//
// Stops on first matching comment.
func getCoverageRequirements(rootPackage string) *CoverageRequirements {
files := listTestFiles(rootPackage)
for _, f := range files {
if r, _ := searchCoverageComment(f); r.Enabled {
2020-03-18 22:29:11 +00:00
return r
}
}
return &CoverageRequirements{}
2020-03-18 22:29:11 +00:00
}
// searchCoverageComment searches for the first occurrence of the comment of the form
//
// // min coverage: 80.5%
//
// Stops on the first matching comment.
func searchCoverageComment(fname string) (*CoverageRequirements, error) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, fname, nil, parser.ParseComments)
if err != nil {
return nil, err
}
for _, c := range f.Comments {
t := c.Text()
if !strings.HasPrefix(t, coverageCommentPrefix) || !strings.HasSuffix(t, "%\n") {
continue
}
t = strings.TrimPrefix(t, coverageCommentPrefix)
t = strings.TrimSuffix(t, "%\n")
percent, err := strconv.ParseFloat(t, 64)
if err != nil {
continue
}
if percent < 0 || percent > 100.0 {
continue
}
return &CoverageRequirements{Enabled: true, Percent: percent}, nil
}
return &CoverageRequirements{}, nil
}
// calCoverage calculates coverage percent for given coverage profile.
func calCoverage(profile string) (float64, error) {
profiles, err := cover.ParseProfiles(profile)
if err != nil {
return 0.0, fmt.Errorf("cannot parse coverage profile file %s: %w", profile, err)
}
var total, covered int
for _, p := range profiles {
for _, block := range p.Blocks {
total += block.NumStmt
if block.Count > 0 {
covered += block.NumStmt
}
}
}
if total == 0 {
return 0.0, nil
}
return float64(covered) / float64(total) * 100, nil
}