Skip to content

Commit d535388

Browse files
committed
moved to pkg. reading from stdin. upgraded treemap
1 parent 3b38b7e commit d535388

File tree

12 files changed

+398
-594
lines changed

12 files changed

+398
-594
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
docs:
22
-rm docs/*.svg
3+
cat testdata/treemap.cover | ./go-cover-treemap > docs/go-cover-treemap-stdin.svg
34
./go-cover-treemap -coverprofile testdata/treemap.cover > docs/go-cover-treemap.svg
45
./go-cover-treemap -coverprofile testdata/go-featureprocessing.cover > docs/go-featureprocessing.svg
56
./go-cover-treemap -coverprofile testdata/gin.cover > docs/gin.svg

covertreemap/covertreemap.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package covertreemap
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/nikolaydubina/treemap"
9+
"golang.org/x/tools/cover"
10+
)
11+
12+
// CoverageTreemapBuilder creates single treemap tree where each leaf is a file.
13+
// Heat is test coverage.
14+
// Size is number of lines.
15+
type CoverageTreemapBuilder struct {
16+
countStatements bool
17+
}
18+
19+
// NewCoverageTreemapBuilder is constructor.
20+
func NewCoverageTreemapBuilder(
21+
countStatements bool,
22+
) CoverageTreemapBuilder {
23+
return CoverageTreemapBuilder{
24+
countStatements: countStatements,
25+
}
26+
}
27+
28+
// CoverageTreemapFromProfiles from profiles.
29+
// Note, we should not normalize heat since go coverage already reports 0~100%.
30+
func (s CoverageTreemapBuilder) CoverageTreemapFromProfiles(profiles []*cover.Profile) (*treemap.Tree, error) {
31+
if len(profiles) == 0 {
32+
return nil, errors.New("no profiles passed")
33+
}
34+
tree := treemap.Tree{
35+
Nodes: map[string]treemap.Node{},
36+
To: map[string][]string{},
37+
}
38+
39+
// for finding roots
40+
hasParent := map[string]bool{}
41+
42+
for _, profile := range profiles {
43+
if profile == nil {
44+
return nil, fmt.Errorf("got nil profile")
45+
}
46+
47+
if _, ok := tree.Nodes[profile.FileName]; ok {
48+
return nil, fmt.Errorf("duplicate node(%s)", profile.FileName)
49+
}
50+
51+
var size int = 1
52+
if s.countStatements {
53+
size = numStatements(profile)
54+
if size == 0 {
55+
// fallback
56+
size = 1
57+
}
58+
}
59+
60+
parts := strings.Split(profile.FileName, "/")
61+
hasParent[parts[0]] = false
62+
63+
tree.Nodes[profile.FileName] = treemap.Node{
64+
Path: profile.FileName,
65+
Size: float64(size),
66+
Heat: percentCovered(profile),
67+
HasHeat: true,
68+
}
69+
70+
for parent, i := parts[0], 1; i < len(parts); i++ {
71+
child := parent + "/" + parts[i]
72+
73+
tree.Nodes[parent] = treemap.Node{
74+
Path: parent,
75+
}
76+
77+
tree.To[parent] = append(tree.To[parent], child)
78+
hasParent[child] = true
79+
80+
parent = child
81+
}
82+
}
83+
84+
for node, v := range tree.To {
85+
tree.To[node] = unique(v)
86+
}
87+
88+
var roots []string
89+
for node, has := range hasParent {
90+
if !has {
91+
roots = append(roots, node)
92+
}
93+
}
94+
95+
switch {
96+
case len(roots) == 0:
97+
return nil, errors.New("no roots, possible cycle in graph")
98+
case len(roots) > 1:
99+
tree.Root = "some-secret-string"
100+
tree.To[tree.Root] = roots
101+
default:
102+
tree.Root = roots[0]
103+
}
104+
105+
return &tree, nil
106+
}
107+
108+
func unique(a []string) []string {
109+
u := map[string]bool{}
110+
var b []string
111+
for _, q := range a {
112+
if _, ok := u[q]; !ok {
113+
u[q] = true
114+
b = append(b, q)
115+
}
116+
}
117+
return b
118+
}
119+
120+
// This is based on official go tool.
121+
// Returns value in range 0~1
122+
// Official reference: https://github.com/golang/go/blob/master/src/cmd/cover/html.go#L97
123+
func percentCovered(p *cover.Profile) float64 {
124+
var total, covered int64
125+
for _, b := range p.Blocks {
126+
total += int64(b.NumStmt)
127+
if b.Count > 0 {
128+
covered += int64(b.NumStmt)
129+
}
130+
}
131+
if total == 0 {
132+
return 0
133+
}
134+
return float64(covered) / float64(total)
135+
}
136+
137+
func numStatements(p *cover.Profile) int {
138+
var total int
139+
for _, b := range p.Blocks {
140+
total += b.NumStmt
141+
}
142+
return total
143+
}

docs/go-cover-treemap-stdin.svg

Lines changed: 125 additions & 0 deletions
Loading

docs/go-cover-treemap.svg

Lines changed: 2 additions & 28 deletions
Loading

0 commit comments

Comments
 (0)