...
1# Test for bug where cached coverage profiles with -coverpkg can contain
2# outdated line references when source files are modified.
3# This reproduces the issue where coverage data from cache may reference
4# lines that no longer exist in the updated source files.
5
6[short] skip
7[GODEBUG:gocacheverify=1] skip
8
9# We're testing cache behavior, so start with a clean GOCACHE.
10env GOCACHE=$WORK/cache
11
12# Create a project structure with multiple packages
13# proj/
14# some_func.go
15# some_func_test.go
16# sub/
17# sub.go
18# sub_test.go
19# sum/
20# sum.go
21
22# Switch to the proj directory
23cd proj
24
25# Run tests with -coverpkg to collect coverage for all packages
26go test -coverpkg=proj/... -coverprofile=cover1.out ./...
27stdout 'coverage:'
28
29# Verify the first coverage profile exists and has expected content
30exists cover1.out
31grep -q 'proj/sub/sub.go:' cover1.out
32
33# Run again to ensure caching works
34go test -coverpkg=proj/... -coverprofile=cover1_cached.out ./...
35stdout '\(cached\)'
36stdout 'coverage:'
37
38# Note: Due to the bug, cached coverage profiles may have duplicate entries.
39# The duplicate entries are the entries for the previous file structure and the new file structure.
40
41# Now modify sub.go to change line structure - this will invalidate
42# the cache for the sub package but not for the proj package.
43cp ../sub_modified.go sub/sub.go
44
45# After modifying sub.go, we should not have both old and new line references.
46go test -coverpkg=proj/... -coverprofile=cover2.out ./...
47stdout 'coverage:'
48
49# With the bug present, we would see duplicate entries for the same lines.
50# With the bug fixed, there should be no duplicate or stale entries in the coverage profile.
51grep 'proj/sub/sub.go:' cover2.out
52# The fix should ensure that only the new line format exists, not the old one
53grep 'proj/sub/sub.go:3.24,4.35' cover2.out
54# This should fail if the stale coverage line exists (the bug is present)
55! grep 'proj/sub/sub.go:3.24,4.22' cover2.out
56
57-- proj/go.mod --
58module proj
59
60go 1.21
61
62-- proj/some_func.go --
63package proj
64
65import "proj/sum"
66
67func SomeFunc(a, b int) int {
68 if a == 0 && b == 0 {
69 return 0
70 }
71 return sum.Sum(a, b)
72}
73
74-- proj/some_func_test.go --
75package proj
76
77import (
78 "testing"
79)
80
81func Test_SomeFunc(t *testing.T) {
82 t.Run("test1", func(t *testing.T) {
83 result := SomeFunc(1, 1)
84 if result != 2 {
85 t.Errorf("Expected 2, got %d", result)
86 }
87 })
88}
89
90-- proj/sub/sub.go --
91package sub
92
93func Sub(a, b int) int {
94 if a == 0 && b == 0 {
95 return 0
96 }
97 return a - b
98}
99
100-- proj/sub/sub_test.go --
101package sub
102
103import (
104 "testing"
105)
106
107func Test_Sub(t *testing.T) {
108 t.Run("test_sub1", func(t *testing.T) {
109 result := Sub(1, 1)
110 if result != 0 {
111 t.Errorf("Expected 0, got %d", result)
112 }
113 })
114}
115
116-- proj/sum/sum.go --
117package sum
118
119func Sum(a, b int) int {
120 if a == 0 {
121 return b
122 }
123 return a + b
124}
125
126-- sub_modified.go --
127package sub
128
129func Sub(a, b int) int {
130 if a == 0 && b == 0 || a == -100 {
131 return 0
132 }
133 return a - b
134}
View as plain text