Skip to content

Commit 7f581cf

Browse files
authored
Merge pull request #177 from shogo82148/improve-merging-profiles
improve merging profiles
2 parents 769aead + b063ca2 commit 7f581cf

File tree

4 files changed

+110
-52
lines changed

4 files changed

+110
-52
lines changed

gocover.go

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -32,52 +32,73 @@ func findFile(file string) (string, error) {
3232
// mergeProfs merges profiles for same target packages.
3333
// It assumes each profiles have same sorted FileName and Blocks.
3434
func mergeProfs(pfss [][]*cover.Profile) []*cover.Profile {
35-
// skip empty profiles ([no test files])
36-
for i := 0; i < len(pfss); i++ {
37-
if len(pfss[i]) > 0 {
38-
pfss = pfss[i:]
39-
break
40-
}
41-
}
4235
if len(pfss) == 0 {
4336
return nil
44-
} else if len(pfss) == 1 {
45-
return pfss[0]
4637
}
47-
head, rest := pfss[0], pfss[1:]
48-
ret := make([]*cover.Profile, 0, len(head))
49-
for i, profile := range head {
50-
for _, ps := range rest {
51-
// find profiles
52-
if len(ps) == 0 {
53-
continue
54-
} else if len(ps) < i+1 {
55-
continue
56-
} else if ps[i].FileName != profile.FileName {
57-
continue
38+
for len(pfss) > 1 {
39+
i := 0
40+
for ; 2*i+1 < len(pfss); i++ {
41+
pfss[i] = mergeTwoProfs(pfss[2*i], pfss[2*i+1])
42+
}
43+
if 2*i < len(pfss) {
44+
pfss[i] = pfss[2*i]
45+
i++
46+
}
47+
pfss = pfss[:i]
48+
}
49+
return pfss[0]
50+
}
51+
52+
func mergeTwoProfs(left, right []*cover.Profile) []*cover.Profile {
53+
ret := make([]*cover.Profile, 0, len(left)+len(right))
54+
for len(left) > 0 && len(right) > 0 {
55+
if left[0].FileName == right[0].FileName {
56+
profile := &cover.Profile{
57+
FileName: left[0].FileName,
58+
Mode: left[0].Mode,
59+
Blocks: mergeTwoProfBlock(left[0].Blocks, right[0].Blocks),
5860
}
59-
profile.Blocks = mergeProfBlocks(profile.Blocks, ps[i].Blocks)
61+
ret = append(ret, profile)
62+
left = left[1:]
63+
right = right[1:]
64+
} else if left[0].FileName < right[0].FileName {
65+
ret = append(ret, left[0])
66+
left = left[1:]
67+
} else {
68+
ret = append(ret, right[0])
69+
right = right[1:]
6070
}
61-
ret = append(ret, profile)
6271
}
72+
ret = append(ret, left...)
73+
ret = append(ret, right...)
6374
return ret
6475
}
6576

66-
func mergeProfBlocks(as, bs []cover.ProfileBlock) []cover.ProfileBlock {
67-
if len(as) != len(bs) {
68-
log.Fatal("Two block length should be same")
69-
}
70-
// cover.ProfileBlock generated by cover.ParseProfiles() is sorted by
71-
// StartLine and StartCol, so we can use index.
72-
ret := make([]cover.ProfileBlock, 0, len(as))
73-
for i, a := range as {
74-
b := bs[i]
75-
if a.StartLine != b.StartLine || a.StartCol != b.StartCol {
76-
log.Fatal("Blocks are not sorted")
77+
func mergeTwoProfBlock(left, right []cover.ProfileBlock) []cover.ProfileBlock {
78+
ret := make([]cover.ProfileBlock, 0, len(left)+len(right))
79+
for len(left) > 0 && len(right) > 0 {
80+
a, b := left[0], right[0]
81+
if a.StartLine == b.StartLine && a.StartCol == b.StartCol && a.EndLine == b.EndLine && a.EndCol == b.EndCol {
82+
ret = append(ret, cover.ProfileBlock{
83+
StartLine: a.StartLine,
84+
StartCol: a.StartCol,
85+
EndLine: a.EndLine,
86+
EndCol: a.EndCol,
87+
NumStmt: a.NumStmt,
88+
Count: a.Count + b.Count,
89+
})
90+
left = left[1:]
91+
right = right[1:]
92+
} else if a.StartLine < b.StartLine || (a.StartLine == b.StartLine && a.StartCol < b.StartCol) {
93+
ret = append(ret, a)
94+
left = left[1:]
95+
} else {
96+
ret = append(ret, b)
97+
right = right[1:]
7798
}
78-
a.Count += b.Count
79-
ret = append(ret, a)
8099
}
100+
ret = append(ret, left...)
101+
ret = append(ret, right...)
81102
return ret
82103
}
83104

goveralls_test.go

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ func fakeServer() *httptest.Server {
2424

2525
func fakeServerWithPayloadChannel(payload chan Job) *httptest.Server {
2626
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
27-
// this is a standard baked response
28-
fmt.Fprintln(w, `{"error":false,"message":"Fake message","URL":"http://fake.url"}`)
29-
3027
body, err := ioutil.ReadAll(r.Body)
3128
// query params are used for the body payload
3229
vals, err := url.ParseQuery(string(body))
@@ -44,23 +41,11 @@ func fakeServerWithPayloadChannel(payload chan Job) *httptest.Server {
4441
payload <- job
4542

4643
w.WriteHeader(http.StatusOK)
44+
// this is a standard baked response
45+
fmt.Fprintln(w, `{"error":false,"message":"Fake message","URL":"http://fake.url"}`)
4746
}))
4847
}
4948

50-
func TestUsage(t *testing.T) {
51-
tmp := prepareTest(t)
52-
defer os.RemoveAll(tmp)
53-
cmd := exec.Command("goveralls", "-h")
54-
b, err := cmd.CombinedOutput()
55-
if err == nil {
56-
t.Fatal("Expected exit code 1 bot 0")
57-
}
58-
s := strings.Split(string(b), "\n")[0]
59-
if !strings.HasPrefix(s, "Usage: goveralls ") {
60-
t.Fatalf("Expected %v, but %v", "Usage: ", s)
61-
}
62-
}
63-
6449
func TestCustomJobId(t *testing.T) {
6550
tmp := prepareTest(t)
6651
defer os.RemoveAll(tmp)

usage_ge1.15_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// +build go1.15
2+
3+
package main
4+
5+
import (
6+
"os"
7+
"os/exec"
8+
"runtime"
9+
"strings"
10+
"testing"
11+
)
12+
13+
func TestUsage(t *testing.T) {
14+
tmp := prepareTest(t)
15+
defer os.RemoveAll(tmp)
16+
cmd := exec.Command("goveralls", "-h")
17+
b, err := cmd.CombinedOutput()
18+
runtime.Version()
19+
if err != nil {
20+
t.Fatal(err)
21+
}
22+
s := strings.Split(string(b), "\n")[0]
23+
if !strings.HasPrefix(s, "Usage: goveralls ") {
24+
t.Fatalf("Expected %v, but %v", "Usage: ", s)
25+
}
26+
}

usage_lt1.15_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// +build !go1.15
2+
3+
package main
4+
5+
import (
6+
"os"
7+
"os/exec"
8+
"runtime"
9+
"strings"
10+
"testing"
11+
)
12+
13+
func TestUsage(t *testing.T) {
14+
tmp := prepareTest(t)
15+
defer os.RemoveAll(tmp)
16+
cmd := exec.Command("goveralls", "-h")
17+
b, err := cmd.CombinedOutput()
18+
runtime.Version()
19+
if err == nil {
20+
t.Fatal("Expected exit code 1 bot 0")
21+
}
22+
s := strings.Split(string(b), "\n")[0]
23+
if !strings.HasPrefix(s, "Usage: goveralls ") {
24+
t.Fatalf("Expected %v, but %v", "Usage: ", s)
25+
}
26+
}

0 commit comments

Comments
 (0)