github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/analysis/unitchecker/unitchecker_test.go (about) 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 unitchecker_test 9 10 // This test depends on features such as 11 // go vet's support for vetx files (1.11) and 12 // the (*os.ProcessState).ExitCode method (1.12). 13 14 import ( 15 "flag" 16 "os" 17 "os/exec" 18 "regexp" 19 "runtime" 20 "strings" 21 "testing" 22 23 "github.com/powerman/golang-tools/go/analysis/passes/findcall" 24 "github.com/powerman/golang-tools/go/analysis/passes/printf" 25 "github.com/powerman/golang-tools/go/analysis/unitchecker" 26 "github.com/powerman/golang-tools/go/packages/packagestest" 27 ) 28 29 func TestMain(m *testing.M) { 30 if os.Getenv("UNITCHECKER_CHILD") == "1" { 31 // child process 32 main() 33 panic("unreachable") 34 } 35 36 flag.Parse() 37 os.Exit(m.Run()) 38 } 39 40 func main() { 41 unitchecker.Main( 42 findcall.Analyzer, 43 printf.Analyzer, 44 ) 45 } 46 47 // This is a very basic integration test of modular 48 // analysis with facts using unitchecker under "go vet". 49 // It fork/execs the main function above. 50 func TestIntegration(t *testing.T) { packagestest.TestAll(t, testIntegration) } 51 func testIntegration(t *testing.T, exporter packagestest.Exporter) { 52 if runtime.GOOS != "linux" && runtime.GOOS != "darwin" { 53 t.Skipf("skipping fork/exec test on this platform") 54 } 55 56 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 57 Name: "golang.org/fake", 58 Files: map[string]interface{}{ 59 "a/a.go": `package a 60 61 func _() { 62 MyFunc123() 63 } 64 65 func MyFunc123() {} 66 `, 67 "b/b.go": `package b 68 69 import "golang.org/fake/a" 70 71 func _() { 72 a.MyFunc123() 73 MyFunc123() 74 } 75 76 func MyFunc123() {} 77 `, 78 }}}) 79 defer exported.Cleanup() 80 81 const wantA = `# golang.org/fake/a 82 ([/._\-a-zA-Z0-9]+[\\/]fake[\\/])?a/a.go:4:11: call of MyFunc123\(...\) 83 ` 84 const wantB = `# golang.org/fake/b 85 ([/._\-a-zA-Z0-9]+[\\/]fake[\\/])?b/b.go:6:13: call of MyFunc123\(...\) 86 ([/._\-a-zA-Z0-9]+[\\/]fake[\\/])?b/b.go:7:11: call of MyFunc123\(...\) 87 ` 88 const wantAJSON = `# golang.org/fake/a 89 \{ 90 "golang.org/fake/a": \{ 91 "findcall": \[ 92 \{ 93 "posn": "([/._\-a-zA-Z0-9]+[\\/]fake[\\/])?a/a.go:4:11", 94 "message": "call of MyFunc123\(...\)" 95 \} 96 \] 97 \} 98 \} 99 ` 100 101 for _, test := range []struct { 102 args string 103 wantOut string 104 wantExit int 105 }{ 106 {args: "golang.org/fake/a", wantOut: wantA, wantExit: 2}, 107 {args: "golang.org/fake/b", wantOut: wantB, wantExit: 2}, 108 {args: "golang.org/fake/a golang.org/fake/b", wantOut: wantA + wantB, wantExit: 2}, 109 {args: "-json golang.org/fake/a", wantOut: wantAJSON, wantExit: 0}, 110 {args: "-c=0 golang.org/fake/a", wantOut: wantA + "4 MyFunc123\\(\\)\n", wantExit: 2}, 111 } { 112 cmd := exec.Command("go", "vet", "-vettool="+os.Args[0], "-findcall.name=MyFunc123") 113 cmd.Args = append(cmd.Args, strings.Fields(test.args)...) 114 cmd.Env = append(exported.Config.Env, "UNITCHECKER_CHILD=1") 115 cmd.Dir = exported.Config.Dir 116 117 out, err := cmd.CombinedOutput() 118 exitcode := 0 119 if exitErr, ok := err.(*exec.ExitError); ok { 120 exitcode = exitErr.ExitCode() 121 } 122 if exitcode != test.wantExit { 123 t.Errorf("%s: got exit code %d, want %d", test.args, exitcode, test.wantExit) 124 } 125 126 matched, err := regexp.Match(test.wantOut, out) 127 if err != nil { 128 t.Fatal(err) 129 } 130 if !matched { 131 t.Errorf("%s: got <<%s>>, want match of regexp <<%s>>", test.args, out, test.wantOut) 132 } 133 } 134 }