1
2
3
4
5 package unitchecker_test
6
7 import (
8 "flag"
9 "os"
10 "os/exec"
11 "regexp"
12 "runtime"
13 "strings"
14 "testing"
15
16 "golang.org/x/tools/go/analysis/passes/assign"
17 "golang.org/x/tools/go/analysis/passes/findcall"
18 "golang.org/x/tools/go/analysis/passes/printf"
19 "golang.org/x/tools/go/analysis/unitchecker"
20 "golang.org/x/tools/go/packages/packagestest"
21 )
22
23 func TestMain(m *testing.M) {
24
25 switch os.Getenv("ENTRYPOINT") {
26 case "vet":
27 vet()
28 panic("unreachable")
29 case "minivet":
30 minivet()
31 panic("unreachable")
32 case "worker":
33 worker()
34 panic("unreachable")
35 }
36
37
38 flag.Parse()
39 os.Exit(m.Run())
40 }
41
42
43 func minivet() {
44 unitchecker.Main(
45 findcall.Analyzer,
46 printf.Analyzer,
47 assign.Analyzer,
48 )
49 }
50
51
52
53
54 func TestIntegration(t *testing.T) { packagestest.TestAll(t, testIntegration) }
55 func testIntegration(t *testing.T, exporter packagestest.Exporter) {
56 if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
57 t.Skipf("skipping fork/exec test on this platform")
58 }
59
60 exported := packagestest.Export(t, exporter, []packagestest.Module{{
61 Name: "golang.org/fake",
62 Files: map[string]interface{}{
63 "a/a.go": `package a
64
65 func _() {
66 MyFunc123()
67 }
68
69 func MyFunc123() {}
70 `,
71 "b/b.go": `package b
72
73 import "golang.org/fake/a"
74
75 func _() {
76 a.MyFunc123()
77 MyFunc123()
78 }
79
80 func MyFunc123() {}
81 `,
82 "c/c.go": `package c
83
84 func _() {
85 i := 5
86 i = i
87 }
88 `,
89 }}})
90 defer exported.Cleanup()
91
92 const wantA = `# golang.org/fake/a
93 ([/._\-a-zA-Z0-9]+[\\/]fake[\\/])?a/a.go:4:11: call of MyFunc123\(...\)
94 `
95 const wantB = `# golang.org/fake/b
96 ([/._\-a-zA-Z0-9]+[\\/]fake[\\/])?b/b.go:6:13: call of MyFunc123\(...\)
97 ([/._\-a-zA-Z0-9]+[\\/]fake[\\/])?b/b.go:7:11: call of MyFunc123\(...\)
98 `
99 const wantC = `# golang.org/fake/c
100 ([/._\-a-zA-Z0-9]+[\\/]fake[\\/])?c/c.go:5:5: self-assignment of i to i
101 `
102 const wantAJSON = `# golang.org/fake/a
103 \{
104 "golang.org/fake/a": \{
105 "findcall": \[
106 \{
107 "posn": "([/._\-a-zA-Z0-9]+[\\/]fake[\\/])?a/a.go:4:11",
108 "message": "call of MyFunc123\(...\)",
109 "suggested_fixes": \[
110 \{
111 "message": "Add '_TEST_'",
112 "edits": \[
113 \{
114 "filename": "([/._\-a-zA-Z0-9]+[\\/]fake[\\/])?a/a.go",
115 "start": 32,
116 "end": 32,
117 "new": "_TEST_"
118 \}
119 \]
120 \}
121 \]
122 \}
123 \]
124 \}
125 \}
126 `
127 const wantCJSON = `# golang.org/fake/c
128 \{
129 "golang.org/fake/c": \{
130 "assign": \[
131 \{
132 "posn": "([/._\-a-zA-Z0-9]+[\\/]fake[\\/])?c/c.go:5:5",
133 "message": "self-assignment of i to i",
134 "suggested_fixes": \[
135 \{
136 "message": "Remove",
137 "edits": \[
138 \{
139 "filename": "([/._\-a-zA-Z0-9]+[\\/]fake[\\/])?c/c.go",
140 "start": 37,
141 "end": 42,
142 "new": ""
143 \}
144 \]
145 \}
146 \]
147 \}
148 \]
149 \}
150 \}
151 `
152 for _, test := range []struct {
153 args string
154 wantOut string
155 wantExitError bool
156 }{
157 {args: "golang.org/fake/a", wantOut: wantA, wantExitError: true},
158 {args: "golang.org/fake/b", wantOut: wantB, wantExitError: true},
159 {args: "golang.org/fake/c", wantOut: wantC, wantExitError: true},
160 {args: "golang.org/fake/a golang.org/fake/b", wantOut: wantA + wantB, wantExitError: true},
161 {args: "-json golang.org/fake/a", wantOut: wantAJSON, wantExitError: false},
162 {args: "-json golang.org/fake/c", wantOut: wantCJSON, wantExitError: false},
163 {args: "-c=0 golang.org/fake/a", wantOut: wantA + "4 MyFunc123\\(\\)\n", wantExitError: true},
164 } {
165 cmd := exec.Command("go", "vet", "-vettool="+os.Args[0], "-findcall.name=MyFunc123")
166 cmd.Args = append(cmd.Args, strings.Fields(test.args)...)
167 cmd.Env = append(exported.Config.Env, "ENTRYPOINT=minivet")
168 cmd.Dir = exported.Config.Dir
169
170
171
172
173
174
175
176
177 out, err := cmd.CombinedOutput()
178 exitcode := 0
179 if exitErr, ok := err.(*exec.ExitError); ok {
180 exitcode = exitErr.ExitCode()
181 }
182 if (exitcode != 0) != test.wantExitError {
183 want := "zero"
184 if test.wantExitError {
185 want = "nonzero"
186 }
187 t.Errorf("%s: got exit code %d, want %s", test.args, exitcode, want)
188 }
189
190 matched, err := regexp.Match(test.wantOut, out)
191 if err != nil {
192 t.Fatalf("regexp.Match(<<%s>>): %v", test.wantOut, err)
193 }
194 if !matched {
195 t.Errorf("%s: got <<%s>>, want match of regexp <<%s>>", test.args, out, test.wantOut)
196 }
197 }
198 }
199
View as plain text