Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / go / ssa / testmain.go
1 // Copyright 2013 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 package ssa
6
7 // CreateTestMainPackage synthesizes a main package that runs all the
8 // tests of the supplied packages.
9 // It is closely coupled to $GOROOT/src/cmd/go/test.go and $GOROOT/src/testing.
10 //
11 // TODO(adonovan): throws this all away now that x/tools/go/packages
12 // provides access to the actual synthetic test main files.
13
14 import (
15         "bytes"
16         "fmt"
17         "go/ast"
18         "go/parser"
19         "go/types"
20         "log"
21         "os"
22         "strings"
23         "text/template"
24 )
25
26 // FindTests returns the Test, Benchmark, and Example functions
27 // (as defined by "go test") defined in the specified package,
28 // and its TestMain function, if any.
29 //
30 // Deprecated: Use golang.org/x/tools/go/packages to access synthetic
31 // testmain packages.
32 func FindTests(pkg *Package) (tests, benchmarks, examples []*Function, main *Function) {
33         prog := pkg.Prog
34
35         // The first two of these may be nil: if the program doesn't import "testing",
36         // it can't contain any tests, but it may yet contain Examples.
37         var testSig *types.Signature                              // func(*testing.T)
38         var benchmarkSig *types.Signature                         // func(*testing.B)
39         var exampleSig = types.NewSignature(nil, nil, nil, false) // func()
40
41         // Obtain the types from the parameters of testing.MainStart.
42         if testingPkg := prog.ImportedPackage("testing"); testingPkg != nil {
43                 mainStart := testingPkg.Func("MainStart")
44                 params := mainStart.Signature.Params()
45                 testSig = funcField(params.At(1).Type())
46                 benchmarkSig = funcField(params.At(2).Type())
47
48                 // Does the package define this function?
49                 //   func TestMain(*testing.M)
50                 if f := pkg.Func("TestMain"); f != nil {
51                         sig := f.Type().(*types.Signature)
52                         starM := mainStart.Signature.Results().At(0).Type() // *testing.M
53                         if sig.Results().Len() == 0 &&
54                                 sig.Params().Len() == 1 &&
55                                 types.Identical(sig.Params().At(0).Type(), starM) {
56                                 main = f
57                         }
58                 }
59         }
60
61         // TODO(adonovan): use a stable order, e.g. lexical.
62         for _, mem := range pkg.Members {
63                 if f, ok := mem.(*Function); ok &&
64                         ast.IsExported(f.Name()) &&
65                         strings.HasSuffix(prog.Fset.Position(f.Pos()).Filename, "_test.go") {
66
67                         switch {
68                         case testSig != nil && isTestSig(f, "Test", testSig):
69                                 tests = append(tests, f)
70                         case benchmarkSig != nil && isTestSig(f, "Benchmark", benchmarkSig):
71                                 benchmarks = append(benchmarks, f)
72                         case isTestSig(f, "Example", exampleSig):
73                                 examples = append(examples, f)
74                         default:
75                                 continue
76                         }
77                 }
78         }
79         return
80 }
81
82 // Like isTest, but checks the signature too.
83 func isTestSig(f *Function, prefix string, sig *types.Signature) bool {
84         return isTest(f.Name(), prefix) && types.Identical(f.Signature, sig)
85 }
86
87 // Given the type of one of the three slice parameters of testing.Main,
88 // returns the function type.
89 func funcField(slice types.Type) *types.Signature {
90         return slice.(*types.Slice).Elem().Underlying().(*types.Struct).Field(1).Type().(*types.Signature)
91 }
92
93 // isTest tells whether name looks like a test (or benchmark, according to prefix).
94 // It is a Test (say) if there is a character after Test that is not a lower-case letter.
95 // We don't want TesticularCancer.
96 // Plundered from $GOROOT/src/cmd/go/test.go
97 func isTest(name, prefix string) bool {
98         if !strings.HasPrefix(name, prefix) {
99                 return false
100         }
101         if len(name) == len(prefix) { // "Test" is ok
102                 return true
103         }
104         return ast.IsExported(name[len(prefix):])
105 }
106
107 // CreateTestMainPackage creates and returns a synthetic "testmain"
108 // package for the specified package if it defines tests, benchmarks or
109 // executable examples, or nil otherwise.  The new package is named
110 // "main" and provides a function named "main" that runs the tests,
111 // similar to the one that would be created by the 'go test' tool.
112 //
113 // Subsequent calls to prog.AllPackages include the new package.
114 // The package pkg must belong to the program prog.
115 //
116 // Deprecated: Use golang.org/x/tools/go/packages to access synthetic
117 // testmain packages.
118 func (prog *Program) CreateTestMainPackage(pkg *Package) *Package {
119         if pkg.Prog != prog {
120                 log.Fatal("Package does not belong to Program")
121         }
122
123         // Template data
124         var data struct {
125                 Pkg                         *Package
126                 Tests, Benchmarks, Examples []*Function
127                 Main                        *Function
128                 Go18                        bool
129         }
130         data.Pkg = pkg
131
132         // Enumerate tests.
133         data.Tests, data.Benchmarks, data.Examples, data.Main = FindTests(pkg)
134         if data.Main == nil &&
135                 data.Tests == nil && data.Benchmarks == nil && data.Examples == nil {
136                 return nil
137         }
138
139         // Synthesize source for testmain package.
140         path := pkg.Pkg.Path() + "$testmain"
141         tmpl := testmainTmpl
142         if testingPkg := prog.ImportedPackage("testing"); testingPkg != nil {
143                 // In Go 1.8, testing.MainStart's first argument is an interface, not a func.
144                 data.Go18 = types.IsInterface(testingPkg.Func("MainStart").Signature.Params().At(0).Type())
145         } else {
146                 // The program does not import "testing", but FindTests
147                 // returned non-nil, which must mean there were Examples
148                 // but no Test, Benchmark, or TestMain functions.
149
150                 // We'll simply call them from testmain.main; this will
151                 // ensure they don't panic, but will not check any
152                 // "Output:" comments.
153                 // (We should not execute an Example that has no
154                 // "Output:" comment, but it's impossible to tell here.)
155                 tmpl = examplesOnlyTmpl
156         }
157         var buf bytes.Buffer
158         if err := tmpl.Execute(&buf, data); err != nil {
159                 log.Fatalf("internal error expanding template for %s: %v", path, err)
160         }
161         if false { // debugging
162                 fmt.Fprintln(os.Stderr, buf.String())
163         }
164
165         // Parse and type-check the testmain package.
166         f, err := parser.ParseFile(prog.Fset, path+".go", &buf, parser.Mode(0))
167         if err != nil {
168                 log.Fatalf("internal error parsing %s: %v", path, err)
169         }
170         conf := types.Config{
171                 DisableUnusedImportCheck: true,
172                 Importer:                 importer{pkg},
173         }
174         files := []*ast.File{f}
175         info := &types.Info{
176                 Types:      make(map[ast.Expr]types.TypeAndValue),
177                 Defs:       make(map[*ast.Ident]types.Object),
178                 Uses:       make(map[*ast.Ident]types.Object),
179                 Implicits:  make(map[ast.Node]types.Object),
180                 Scopes:     make(map[ast.Node]*types.Scope),
181                 Selections: make(map[*ast.SelectorExpr]*types.Selection),
182         }
183         testmainPkg, err := conf.Check(path, prog.Fset, files, info)
184         if err != nil {
185                 log.Fatalf("internal error type-checking %s: %v", path, err)
186         }
187
188         // Create and build SSA code.
189         testmain := prog.CreatePackage(testmainPkg, files, info, false)
190         testmain.SetDebugMode(false)
191         testmain.Build()
192         testmain.Func("main").Synthetic = "test main function"
193         testmain.Func("init").Synthetic = "package initializer"
194         return testmain
195 }
196
197 // An implementation of types.Importer for an already loaded SSA program.
198 type importer struct {
199         pkg *Package // package under test; may be non-importable
200 }
201
202 func (imp importer) Import(path string) (*types.Package, error) {
203         if p := imp.pkg.Prog.ImportedPackage(path); p != nil {
204                 return p.Pkg, nil
205         }
206         if path == imp.pkg.Pkg.Path() {
207                 return imp.pkg.Pkg, nil
208         }
209         return nil, fmt.Errorf("not found") // can't happen
210 }
211
212 var testmainTmpl = template.Must(template.New("testmain").Parse(`
213 package main
214
215 import "io"
216 import "os"
217 import "testing"
218 import p {{printf "%q" .Pkg.Pkg.Path}}
219
220 {{if .Go18}}
221 type deps struct{}
222
223 func (deps) ImportPath() string { return "" }
224 func (deps) MatchString(pat, str string) (bool, error) { return true, nil }
225 func (deps) SetPanicOnExit0(bool) {}
226 func (deps) StartCPUProfile(io.Writer) error { return nil }
227 func (deps) StartTestLog(io.Writer) {}
228 func (deps) StopCPUProfile() {}
229 func (deps) StopTestLog() error { return nil }
230 func (deps) WriteHeapProfile(io.Writer) error { return nil }
231 func (deps) WriteProfileTo(string, io.Writer, int) error { return nil }
232
233 var match deps
234 {{else}}
235 func match(_, _ string) (bool, error) { return true, nil }
236 {{end}}
237
238 func main() {
239         tests := []testing.InternalTest{
240 {{range .Tests}}
241                 { {{printf "%q" .Name}}, p.{{.Name}} },
242 {{end}}
243         }
244         benchmarks := []testing.InternalBenchmark{
245 {{range .Benchmarks}}
246                 { {{printf "%q" .Name}}, p.{{.Name}} },
247 {{end}}
248         }
249         examples := []testing.InternalExample{
250 {{range .Examples}}
251                 {Name: {{printf "%q" .Name}}, F: p.{{.Name}}},
252 {{end}}
253         }
254         m := testing.MainStart(match, tests, benchmarks, examples)
255 {{with .Main}}
256         p.{{.Name}}(m)
257 {{else}}
258         os.Exit(m.Run())
259 {{end}}
260 }
261
262 `))
263
264 var examplesOnlyTmpl = template.Must(template.New("examples").Parse(`
265 package main
266
267 import p {{printf "%q" .Pkg.Pkg.Path}}
268
269 func main() {
270 {{range .Examples}}
271         p.{{.Name}}()
272 {{end}}
273 }
274 `))