.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.1.1 / internal / testenv / testenv.go
1 // Copyright 2019 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 testenv contains helper functions for skipping tests
6 // based on which tools are present in the environment.
7 package testenv
8
9 import (
10         "fmt"
11         "io/ioutil"
12         "os"
13         "os/exec"
14         "runtime"
15         "strings"
16         "sync"
17 )
18
19 // Testing is an abstraction of a *testing.T.
20 type Testing interface {
21         Skipf(format string, args ...interface{})
22         Fatalf(format string, args ...interface{})
23 }
24
25 type helperer interface {
26         Helper()
27 }
28
29 // packageMainIsDevel reports whether the module containing package main
30 // is a development version (if module information is available).
31 //
32 // Builds in GOPATH mode and builds that lack module information are assumed to
33 // be development versions.
34 var packageMainIsDevel = func() bool { return true }
35
36 var checkGoGoroot struct {
37         once sync.Once
38         err  error
39 }
40
41 func hasTool(tool string) error {
42         _, err := exec.LookPath(tool)
43         if err != nil {
44                 return err
45         }
46
47         switch tool {
48         case "patch":
49                 // check that the patch tools supports the -o argument
50                 temp, err := ioutil.TempFile("", "patch-test")
51                 if err != nil {
52                         return err
53                 }
54                 temp.Close()
55                 defer os.Remove(temp.Name())
56                 cmd := exec.Command(tool, "-o", temp.Name())
57                 if err := cmd.Run(); err != nil {
58                         return err
59                 }
60
61         case "go":
62                 checkGoGoroot.once.Do(func() {
63                         // Ensure that the 'go' command found by exec.LookPath is from the correct
64                         // GOROOT. Otherwise, 'some/path/go test ./...' will test against some
65                         // version of the 'go' binary other than 'some/path/go', which is almost
66                         // certainly not what the user intended.
67                         out, err := exec.Command(tool, "env", "GOROOT").CombinedOutput()
68                         if err != nil {
69                                 checkGoGoroot.err = err
70                                 return
71                         }
72                         GOROOT := strings.TrimSpace(string(out))
73                         if GOROOT != runtime.GOROOT() {
74                                 checkGoGoroot.err = fmt.Errorf("'go env GOROOT' does not match runtime.GOROOT:\n\tgo env: %s\n\tGOROOT: %s", GOROOT, runtime.GOROOT())
75                         }
76                 })
77                 if checkGoGoroot.err != nil {
78                         return checkGoGoroot.err
79                 }
80         }
81
82         return nil
83 }
84
85 func allowMissingTool(tool string) bool {
86         if runtime.GOOS == "android" {
87                 // Android builds generally run tests on a separate machine from the build,
88                 // so don't expect any external tools to be available.
89                 return true
90         }
91
92         switch tool {
93         case "go":
94                 if os.Getenv("GO_BUILDER_NAME") == "illumos-amd64-joyent" {
95                         // Work around a misconfigured builder (see https://golang.org/issue/33950).
96                         return true
97                 }
98         case "diff":
99                 if os.Getenv("GO_BUILDER_NAME") != "" {
100                         return true
101                 }
102         case "patch":
103                 if os.Getenv("GO_BUILDER_NAME") != "" {
104                         return true
105                 }
106         }
107
108         // If a developer is actively working on this test, we expect them to have all
109         // of its dependencies installed. However, if it's just a dependency of some
110         // other module (for example, being run via 'go test all'), we should be more
111         // tolerant of unusual environments.
112         return !packageMainIsDevel()
113 }
114
115 // NeedsTool skips t if the named tool is not present in the path.
116 func NeedsTool(t Testing, tool string) {
117         if t, ok := t.(helperer); ok {
118                 t.Helper()
119         }
120         err := hasTool(tool)
121         if err == nil {
122                 return
123         }
124         if allowMissingTool(tool) {
125                 t.Skipf("skipping because %s tool not available: %v", tool, err)
126         } else {
127                 t.Fatalf("%s tool not available: %v", tool, err)
128         }
129 }
130
131 // NeedsGoPackages skips t if the go/packages driver (or 'go' tool) implied by
132 // the current process environment is not present in the path.
133 func NeedsGoPackages(t Testing) {
134         if t, ok := t.(helperer); ok {
135                 t.Helper()
136         }
137
138         tool := os.Getenv("GOPACKAGESDRIVER")
139         switch tool {
140         case "off":
141                 // "off" forces go/packages to use the go command.
142                 tool = "go"
143         case "":
144                 if _, err := exec.LookPath("gopackagesdriver"); err == nil {
145                         tool = "gopackagesdriver"
146                 } else {
147                         tool = "go"
148                 }
149         }
150
151         NeedsTool(t, tool)
152 }
153
154 // NeedsGoPackagesEnv skips t if the go/packages driver (or 'go' tool) implied
155 // by env is not present in the path.
156 func NeedsGoPackagesEnv(t Testing, env []string) {
157         if t, ok := t.(helperer); ok {
158                 t.Helper()
159         }
160
161         for _, v := range env {
162                 if strings.HasPrefix(v, "GOPACKAGESDRIVER=") {
163                         tool := strings.TrimPrefix(v, "GOPACKAGESDRIVER=")
164                         if tool == "off" {
165                                 NeedsTool(t, "go")
166                         } else {
167                                 NeedsTool(t, tool)
168                         }
169                         return
170                 }
171         }
172
173         NeedsGoPackages(t)
174 }
175
176 // ExitIfSmallMachine emits a helpful diagnostic and calls os.Exit(0) if the
177 // current machine is a builder known to have scarce resources.
178 //
179 // It should be called from within a TestMain function.
180 func ExitIfSmallMachine() {
181         if os.Getenv("GO_BUILDER_NAME") == "linux-arm" {
182                 fmt.Fprintln(os.Stderr, "skipping test: linux-arm builder lacks sufficient memory (https://golang.org/issue/32834)")
183                 os.Exit(0)
184         }
185 }