Skip to content

Commit 93f0ae5

Browse files
committed
chore_: bring in gocovmerge util
1 parent 8f83d66 commit 93f0ae5

File tree

6 files changed

+380
-3
lines changed

6 files changed

+380
-3
lines changed

Makefile

-1
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,6 @@ test-unit: export UNIT_TEST_PACKAGES_NOT_PARALLELIZABLE ?= \
367367
test-unit: export UNIT_TEST_PACKAGES_WITH_EXTENDED_TIMEOUT ?= \
368368
github.com/status-im/status-go/protocol
369369
test-unit: ##@tests Run unit and integration tests
370-
go install github.com/wadey/gocovmerge@latest
371370
./_assets/scripts/run_unit_tests.sh
372371

373372
test-unit-race: export GOTEST_EXTRAFLAGS=-race

_assets/scripts/run_unit_tests.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ run_test_for_package() {
9292
redirect_stdout "${output_file}"
9393

9494
# Merge package coverage results
95-
gocovmerge ${package_dir}/coverage.out.rerun.* > ${coverage_file}
95+
go run ./cmd/test-coverage-utils/gocovmerge.go ${package_dir}/coverage.out.rerun.* > ${coverage_file}
9696

9797
# Cleanup coverage reports
9898
rm -f ${package_dir}/coverage.out.rerun.*

cmd/test-coverage-utils/gocovmerge.go

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// gocovmerge takes the results from multiple `go test -coverprofile` runs and
2+
// merges them into one profile
3+
package main
4+
5+
import (
6+
"flag"
7+
"fmt"
8+
"io"
9+
"log"
10+
"os"
11+
"sort"
12+
13+
"golang.org/x/tools/cover"
14+
)
15+
16+
func mergeProfiles(p *cover.Profile, merge *cover.Profile) {
17+
if p.Mode != merge.Mode {
18+
log.Fatalf("cannot merge profiles with different modes")
19+
}
20+
// Since the blocks are sorted, we can keep track of where the last block
21+
// was inserted and only look at the blocks after that as targets for merge
22+
startIndex := 0
23+
for _, b := range merge.Blocks {
24+
startIndex = mergeProfileBlock(p, b, startIndex)
25+
}
26+
}
27+
28+
func mergeProfileBlock(p *cover.Profile, pb cover.ProfileBlock, startIndex int) int {
29+
sortFunc := func(i int) bool {
30+
pi := p.Blocks[i+startIndex]
31+
return pi.StartLine >= pb.StartLine && (pi.StartLine != pb.StartLine || pi.StartCol >= pb.StartCol)
32+
}
33+
34+
i := 0
35+
if sortFunc(i) != true {
36+
i = sort.Search(len(p.Blocks)-startIndex, sortFunc)
37+
}
38+
i += startIndex
39+
if i < len(p.Blocks) && p.Blocks[i].StartLine == pb.StartLine && p.Blocks[i].StartCol == pb.StartCol {
40+
if p.Blocks[i].EndLine != pb.EndLine || p.Blocks[i].EndCol != pb.EndCol {
41+
log.Fatalf("OVERLAP MERGE: %v %v %v", p.FileName, p.Blocks[i], pb)
42+
}
43+
switch p.Mode {
44+
case "set":
45+
p.Blocks[i].Count |= pb.Count
46+
case "count", "atomic":
47+
p.Blocks[i].Count += pb.Count
48+
default:
49+
log.Fatalf("unsupported covermode: '%s'", p.Mode)
50+
}
51+
} else {
52+
if i > 0 {
53+
pa := p.Blocks[i-1]
54+
if pa.EndLine >= pb.EndLine && (pa.EndLine != pb.EndLine || pa.EndCol > pb.EndCol) {
55+
log.Fatalf("OVERLAP BEFORE: %v %v %v", p.FileName, pa, pb)
56+
}
57+
}
58+
if i < len(p.Blocks)-1 {
59+
pa := p.Blocks[i+1]
60+
if pa.StartLine <= pb.StartLine && (pa.StartLine != pb.StartLine || pa.StartCol < pb.StartCol) {
61+
log.Fatalf("OVERLAP AFTER: %v %v %v", p.FileName, pa, pb)
62+
}
63+
}
64+
p.Blocks = append(p.Blocks, cover.ProfileBlock{})
65+
copy(p.Blocks[i+1:], p.Blocks[i:])
66+
p.Blocks[i] = pb
67+
}
68+
return i + 1
69+
}
70+
71+
func addProfile(profiles []*cover.Profile, p *cover.Profile) []*cover.Profile {
72+
i := sort.Search(len(profiles), func(i int) bool { return profiles[i].FileName >= p.FileName })
73+
if i < len(profiles) && profiles[i].FileName == p.FileName {
74+
mergeProfiles(profiles[i], p)
75+
} else {
76+
profiles = append(profiles, nil)
77+
copy(profiles[i+1:], profiles[i:])
78+
profiles[i] = p
79+
}
80+
return profiles
81+
}
82+
83+
func dumpProfiles(profiles []*cover.Profile, out io.Writer) {
84+
if len(profiles) == 0 {
85+
return
86+
}
87+
fmt.Fprintf(out, "mode: %s\n", profiles[0].Mode)
88+
for _, p := range profiles {
89+
for _, b := range p.Blocks {
90+
fmt.Fprintf(out, "%s:%d.%d,%d.%d %d %d\n", p.FileName, b.StartLine, b.StartCol, b.EndLine, b.EndCol, b.NumStmt, b.Count)
91+
}
92+
}
93+
}
94+
95+
func main() {
96+
flag.Parse()
97+
98+
var merged []*cover.Profile
99+
100+
for _, file := range flag.Args() {
101+
profiles, err := cover.ParseProfiles(file)
102+
if err != nil {
103+
log.Fatalf("failed to parse profiles: %v", err)
104+
}
105+
for _, p := range profiles {
106+
merged = addProfile(merged, p)
107+
}
108+
}
109+
110+
dumpProfiles(merged, os.Stdout)
111+
}

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ require (
102102
golang.org/x/net v0.25.0
103103
golang.org/x/text v0.15.0
104104
golang.org/x/time v0.5.0
105+
golang.org/x/tools v0.21.0
105106
)
106107

107108
require (
@@ -279,7 +280,6 @@ require (
279280
golang.org/x/sync v0.7.0 // indirect
280281
golang.org/x/sys v0.20.0 // indirect
281282
golang.org/x/term v0.20.0 // indirect
282-
golang.org/x/tools v0.21.0 // indirect
283283
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
284284
gopkg.in/yaml.v3 v3.0.1 // indirect
285285
lukechampine.com/blake3 v1.2.1 // indirect

0 commit comments

Comments
 (0)