| 1 | // Copyright 2018 The Go Authors. All rights reserved. |
|---|---|
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | //go:build go1.12 |
| 6 | // +build go1.12 |
| 7 | |
| 8 | package multichecker_test |
| 9 | |
| 10 | import ( |
| 11 | "fmt" |
| 12 | "os" |
| 13 | "os/exec" |
| 14 | "runtime" |
| 15 | "testing" |
| 16 | |
| 17 | "golang.org/x/tools/go/analysis" |
| 18 | "golang.org/x/tools/go/analysis/multichecker" |
| 19 | "golang.org/x/tools/go/analysis/passes/findcall" |
| 20 | "golang.org/x/tools/internal/testenv" |
| 21 | ) |
| 22 | |
| 23 | func main() { |
| 24 | fail := &analysis.Analyzer{ |
| 25 | Name: "fail", |
| 26 | Doc: "always fail on a package 'sort'", |
| 27 | Run: func(pass *analysis.Pass) (interface{}, error) { |
| 28 | if pass.Pkg.Path() == "sort" { |
| 29 | return nil, fmt.Errorf("failed") |
| 30 | } |
| 31 | return nil, nil |
| 32 | }, |
| 33 | } |
| 34 | multichecker.Main(findcall.Analyzer, fail) |
| 35 | } |
| 36 | |
| 37 | // TestExitCode ensures that analysis failures are reported correctly. |
| 38 | // This test fork/execs the main function above. |
| 39 | func TestExitCode(t *testing.T) { |
| 40 | if runtime.GOOS != "linux" { |
| 41 | t.Skipf("skipping fork/exec test on this platform") |
| 42 | } |
| 43 | |
| 44 | if os.Getenv("MULTICHECKER_CHILD") == "1" { |
| 45 | // child process |
| 46 | |
| 47 | // replace [progname -test.run=TestExitCode -- ...] |
| 48 | // by [progname ...] |
| 49 | os.Args = os.Args[2:] |
| 50 | os.Args[0] = "vet" |
| 51 | main() |
| 52 | panic("unreachable") |
| 53 | } |
| 54 | |
| 55 | testenv.NeedsTool(t, "go") |
| 56 | |
| 57 | for _, test := range []struct { |
| 58 | args []string |
| 59 | want int |
| 60 | }{ |
| 61 | {[]string{"nosuchdir/..."}, 1}, // matched no packages |
| 62 | {[]string{"nosuchpkg"}, 1}, // matched no packages |
| 63 | {[]string{"-unknownflag"}, 2}, // flag error |
| 64 | {[]string{"-findcall.name=panic", "io"}, 3}, // finds diagnostics |
| 65 | {[]string{"-findcall=0", "io"}, 0}, // no checkers |
| 66 | {[]string{"-findcall.name=nosuchfunc", "io"}, 0}, // no diagnostics |
| 67 | {[]string{"-findcall.name=panic", "sort", "io"}, 1}, // 'fail' failed on 'sort' |
| 68 | |
| 69 | // -json: exits zero even in face of diagnostics or package errors. |
| 70 | {[]string{"-findcall.name=panic", "-json", "io"}, 0}, |
| 71 | {[]string{"-findcall.name=panic", "-json", "io"}, 0}, |
| 72 | {[]string{"-findcall.name=panic", "-json", "sort", "io"}, 0}, |
| 73 | } { |
| 74 | args := []string{"-test.run=TestExitCode", "--"} |
| 75 | args = append(args, test.args...) |
| 76 | cmd := exec.Command(os.Args[0], args...) |
| 77 | cmd.Env = append(os.Environ(), "MULTICHECKER_CHILD=1") |
| 78 | out, err := cmd.CombinedOutput() |
| 79 | if len(out) > 0 { |
| 80 | t.Logf("%s: out=<<%s>>", test.args, out) |
| 81 | } |
| 82 | var exitcode int |
| 83 | if err, ok := err.(*exec.ExitError); ok { |
| 84 | exitcode = err.ExitCode() // requires go1.12 |
| 85 | } |
| 86 | if exitcode != test.want { |
| 87 | t.Errorf("%s: exited %d, want %d", test.args, exitcode, test.want) |
| 88 | } |
| 89 | } |
| 90 | } |
| 91 |
Members