Skip to content

Commit 49b340b

Browse files
committed
go/analysis: update tests for different go list error behavior
golang.org/cl/437298 updates go list to not exit with a non-zero error code in some cases and instead place the error on the Package struct. Also, as a cleanup, some places where exit status 2 was returned will return exit status 1 (bringing it in line with other errors returned by the go command). TestEncodeDecode in facts_test.go has been updated to fix a missing function body that is not relevant to the test, but that was causing an error because the Package struct now has an error on it. TestRunDespiteErrors in checker_test.go has been updated to reflect that in some cases an analysis with RunDespiteErrors will fail to run because a build error returned by go list when it's run to get export data is not recognized as being a parse/typechecker error (the kind of error allowed by TestRunDespiteError). TestIntegration in unitchecker_test.go has been updated to reflect that go vet running unitchecker will now fail with exit status 1 instead of 2 (so it just checks for a zero or non-zero status). For golang/go#25842 Change-Id: Idbbd19b5de661e6e5f49e0475c5bc918d8e33803 Reviewed-on: https://go-review.googlesource.com/c/tools/+/441879 Reviewed-by: Alan Donovan <[email protected]> Reviewed-by: Michael Matloob <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Michael Matloob <[email protected]> gopls-CI: kokoro <[email protected]>
1 parent cd0288f commit 49b340b

File tree

3 files changed

+47
-14
lines changed

3 files changed

+47
-14
lines changed

go/analysis/internal/checker/checker_test.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,18 @@ func Foo(s string) int {
128128
RunDespiteErrors: true,
129129
}
130130

131+
// A no-op analyzer that should finish regardless of
132+
// parse or type errors in the code.
133+
noopWithFact := &analysis.Analyzer{
134+
Name: "noopfact",
135+
Requires: []*analysis.Analyzer{inspect.Analyzer},
136+
Run: func(pass *analysis.Pass) (interface{}, error) {
137+
return nil, nil
138+
},
139+
RunDespiteErrors: true,
140+
FactTypes: []analysis.Fact{&EmptyFact{}},
141+
}
142+
131143
for _, test := range []struct {
132144
name string
133145
pattern []string
@@ -136,7 +148,17 @@ func Foo(s string) int {
136148
}{
137149
// parse/type errors
138150
{name: "skip-error", pattern: []string{"file=" + path}, analyzers: []*analysis.Analyzer{analyzer}, code: 1},
139-
{name: "despite-error", pattern: []string{"file=" + path}, analyzers: []*analysis.Analyzer{noop}, code: 0},
151+
// RunDespiteErrors allows a driver to run an Analyzer even after parse/type errors.
152+
//
153+
// The noop analyzer doesn't use facts, so the driver loads only the root
154+
// package from source. For the rest, it asks 'go list' for export data,
155+
// which fails because the compiler encounters the type error. Since the
156+
// errors come from 'go list', the driver doesn't run the analyzer.
157+
{name: "despite-error", pattern: []string{"file=" + path}, analyzers: []*analysis.Analyzer{noop}, code: 1},
158+
// The noopfact analyzer does use facts, so the driver loads source for
159+
// all dependencies, does type checking itself, recognizes the error as a
160+
// type error, and runs the analyzer.
161+
{name: "despite-error-fact", pattern: []string{"file=" + path}, analyzers: []*analysis.Analyzer{noopWithFact}, code: 0},
140162
// combination of parse/type errors and no errors
141163
{name: "despite-error-and-no-error", pattern: []string{"file=" + path, "sort"}, analyzers: []*analysis.Analyzer{analyzer, noop}, code: 1},
142164
// non-existing package error
@@ -150,10 +172,17 @@ func Foo(s string) int {
150172
// no errors
151173
{name: "no-errors", pattern: []string{"sort"}, analyzers: []*analysis.Analyzer{analyzer, noop}, code: 0},
152174
} {
175+
if test.name == "despite-error" { // TODO(matloob): once CL 437298 is submitted, add the condition testenv.Go1Point() < 20
176+
continue
177+
}
153178
if got := checker.Run(test.pattern, test.analyzers); got != test.code {
154179
t.Errorf("got incorrect exit code %d for test %s; want %d", got, test.name, test.code)
155180
}
156181
}
157182

158183
defer cleanup()
159184
}
185+
186+
type EmptyFact struct{}
187+
188+
func (f *EmptyFact) AFact() {}

go/analysis/internal/facts/facts_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func TestEncodeDecode(t *testing.T) {
148148
type N4[T a.T4|int8] func() T
149149
type N5[T interface{Bar() a.T5} ] func() T
150150
151-
type t5 struct{}; func (t5) Bar() a.T5
151+
type t5 struct{}; func (t5) Bar() a.T5 { return 0 }
152152
153153
var G1 N1[a.T1]
154154
var G2 func() N2[a.T2]

go/analysis/unitchecker/unitchecker_test.go

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -148,17 +148,17 @@ func _() {
148148
\}
149149
`
150150
for _, test := range []struct {
151-
args string
152-
wantOut string
153-
wantExit int
151+
args string
152+
wantOut string
153+
wantExitError bool
154154
}{
155-
{args: "golang.org/fake/a", wantOut: wantA, wantExit: 2},
156-
{args: "golang.org/fake/b", wantOut: wantB, wantExit: 2},
157-
{args: "golang.org/fake/c", wantOut: wantC, wantExit: 2},
158-
{args: "golang.org/fake/a golang.org/fake/b", wantOut: wantA + wantB, wantExit: 2},
159-
{args: "-json golang.org/fake/a", wantOut: wantAJSON, wantExit: 0},
160-
{args: "-json golang.org/fake/c", wantOut: wantCJSON, wantExit: 0},
161-
{args: "-c=0 golang.org/fake/a", wantOut: wantA + "4 MyFunc123\\(\\)\n", wantExit: 2},
155+
{args: "golang.org/fake/a", wantOut: wantA, wantExitError: true},
156+
{args: "golang.org/fake/b", wantOut: wantB, wantExitError: true},
157+
{args: "golang.org/fake/c", wantOut: wantC, wantExitError: true},
158+
{args: "golang.org/fake/a golang.org/fake/b", wantOut: wantA + wantB, wantExitError: true},
159+
{args: "-json golang.org/fake/a", wantOut: wantAJSON, wantExitError: false},
160+
{args: "-json golang.org/fake/c", wantOut: wantCJSON, wantExitError: false},
161+
{args: "-c=0 golang.org/fake/a", wantOut: wantA + "4 MyFunc123\\(\\)\n", wantExitError: true},
162162
} {
163163
cmd := exec.Command("go", "vet", "-vettool="+os.Args[0], "-findcall.name=MyFunc123")
164164
cmd.Args = append(cmd.Args, strings.Fields(test.args)...)
@@ -170,8 +170,12 @@ func _() {
170170
if exitErr, ok := err.(*exec.ExitError); ok {
171171
exitcode = exitErr.ExitCode()
172172
}
173-
if exitcode != test.wantExit {
174-
t.Errorf("%s: got exit code %d, want %d", test.args, exitcode, test.wantExit)
173+
if (exitcode != 0) != test.wantExitError {
174+
want := "zero"
175+
if test.wantExitError {
176+
want = "nonzero"
177+
}
178+
t.Errorf("%s: got exit code %d, want %s", test.args, exitcode, want)
175179
}
176180

177181
matched, err := regexp.Match(test.wantOut, out)

0 commit comments

Comments
 (0)