github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/tpl/internal/go_templates/testenv/testenv.go (about) 1 // Copyright 2015 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 provides information about what functionality 6 // is available in different testing environments run by the Go team. 7 // 8 // It is an internal package because these details are specific 9 // to the Go team's test setup (on build.golang.org) and not 10 // fundamental to tests in general. 11 package testenv 12 13 import ( 14 "bytes" 15 "errors" 16 "flag" 17 "fmt" 18 19 "github.com/gohugoio/hugo/tpl/internal/go_templates/cfg" 20 21 //"internal/platform" 22 "os" 23 "os/exec" 24 "path/filepath" 25 "runtime" 26 "strconv" 27 "strings" 28 "sync" 29 "testing" 30 ) 31 32 // Save the original environment during init for use in checks. A test 33 // binary may modify its environment before calling HasExec to change its 34 // behavior (such as mimicking a command-line tool), and that modified 35 // environment might cause environment checks to behave erratically. 36 var origEnv = os.Environ() 37 38 // Builder reports the name of the builder running this test 39 // (for example, "linux-amd64" or "windows-386-gce"). 40 // If the test is not running on the build infrastructure, 41 // Builder returns the empty string. 42 func Builder() string { 43 return os.Getenv("GO_BUILDER_NAME") 44 } 45 46 // HasGoBuild reports whether the current system can build programs with “go build” 47 // and then run them with os.StartProcess or exec.Command. 48 func HasGoBuild() bool { 49 // Modified by Hugo (not needed) 50 return false 51 } 52 53 var ( 54 goBuildOnce sync.Once 55 goBuildErr error 56 ) 57 58 // MustHaveGoBuild checks that the current system can build programs with “go build” 59 // and then run them with os.StartProcess or exec.Command. 60 // If not, MustHaveGoBuild calls t.Skip with an explanation. 61 func MustHaveGoBuild(t testing.TB) { 62 if os.Getenv("GO_GCFLAGS") != "" { 63 t.Helper() 64 t.Skipf("skipping test: 'go build' not compatible with setting $GO_GCFLAGS") 65 } 66 if !HasGoBuild() { 67 t.Helper() 68 t.Skipf("skipping test: 'go build' unavailable: %v", goBuildErr) 69 } 70 } 71 72 // HasGoRun reports whether the current system can run programs with “go run.” 73 func HasGoRun() bool { 74 // For now, having go run and having go build are the same. 75 return HasGoBuild() 76 } 77 78 // MustHaveGoRun checks that the current system can run programs with “go run.” 79 // If not, MustHaveGoRun calls t.Skip with an explanation. 80 func MustHaveGoRun(t testing.TB) { 81 if !HasGoRun() { 82 t.Skipf("skipping test: 'go run' not available on %s/%s", runtime.GOOS, runtime.GOARCH) 83 } 84 } 85 86 // HasParallelism reports whether the current system can execute multiple 87 // threads in parallel. 88 // There is a copy of this function in cmd/dist/test.go. 89 func HasParallelism() bool { 90 switch runtime.GOOS { 91 case "js", "wasip1": 92 return false 93 } 94 return true 95 } 96 97 // MustHaveParallelism checks that the current system can execute multiple 98 // threads in parallel. If not, MustHaveParallelism calls t.Skip with an explanation. 99 func MustHaveParallelism(t testing.TB) { 100 if !HasParallelism() { 101 t.Skipf("skipping test: no parallelism available on %s/%s", runtime.GOOS, runtime.GOARCH) 102 } 103 } 104 105 // GoToolPath reports the path to the Go tool. 106 // It is a convenience wrapper around GoTool. 107 // If the tool is unavailable GoToolPath calls t.Skip. 108 // If the tool should be available and isn't, GoToolPath calls t.Fatal. 109 func GoToolPath(t testing.TB) string { 110 MustHaveGoBuild(t) 111 path, err := GoTool() 112 if err != nil { 113 t.Fatal(err) 114 } 115 // Add all environment variables that affect the Go command to test metadata. 116 // Cached test results will be invalidate when these variables change. 117 // See golang.org/issue/32285. 118 for _, envVar := range strings.Fields(cfg.KnownEnv) { 119 os.Getenv(envVar) 120 } 121 return path 122 } 123 124 var ( 125 gorootOnce sync.Once 126 gorootPath string 127 gorootErr error 128 ) 129 130 func findGOROOT() (string, error) { 131 gorootOnce.Do(func() { 132 gorootPath = runtime.GOROOT() 133 if gorootPath != "" { 134 // If runtime.GOROOT() is non-empty, assume that it is valid. 135 // 136 // (It might not be: for example, the user may have explicitly set GOROOT 137 // to the wrong directory, or explicitly set GOROOT_FINAL but not GOROOT 138 // and hasn't moved the tree to GOROOT_FINAL yet. But those cases are 139 // rare, and if that happens the user can fix what they broke.) 140 return 141 } 142 143 // runtime.GOROOT doesn't know where GOROOT is (perhaps because the test 144 // binary was built with -trimpath, or perhaps because GOROOT_FINAL was set 145 // without GOROOT and the tree hasn't been moved there yet). 146 // 147 // Since this is internal/testenv, we can cheat and assume that the caller 148 // is a test of some package in a subdirectory of GOROOT/src. ('go test' 149 // runs the test in the directory containing the packaged under test.) That 150 // means that if we start walking up the tree, we should eventually find 151 // GOROOT/src/go.mod, and we can report the parent directory of that. 152 // 153 // Notably, this works even if we can't run 'go env GOROOT' as a 154 // subprocess. 155 156 cwd, err := os.Getwd() 157 if err != nil { 158 gorootErr = fmt.Errorf("finding GOROOT: %w", err) 159 return 160 } 161 162 dir := cwd 163 for { 164 parent := filepath.Dir(dir) 165 if parent == dir { 166 // dir is either "." or only a volume name. 167 gorootErr = fmt.Errorf("failed to locate GOROOT/src in any parent directory") 168 return 169 } 170 171 if base := filepath.Base(dir); base != "src" { 172 dir = parent 173 continue // dir cannot be GOROOT/src if it doesn't end in "src". 174 } 175 176 b, err := os.ReadFile(filepath.Join(dir, "go.mod")) 177 if err != nil { 178 if os.IsNotExist(err) { 179 dir = parent 180 continue 181 } 182 gorootErr = fmt.Errorf("finding GOROOT: %w", err) 183 return 184 } 185 goMod := string(b) 186 187 for goMod != "" { 188 var line string 189 line, goMod, _ = strings.Cut(goMod, "\n") 190 fields := strings.Fields(line) 191 if len(fields) >= 2 && fields[0] == "module" && fields[1] == "std" { 192 // Found "module std", which is the module declaration in GOROOT/src! 193 gorootPath = parent 194 return 195 } 196 } 197 } 198 }) 199 200 return gorootPath, gorootErr 201 } 202 203 // GOROOT reports the path to the directory containing the root of the Go 204 // project source tree. This is normally equivalent to runtime.GOROOT, but 205 // works even if the test binary was built with -trimpath and cannot exec 206 // 'go env GOROOT'. 207 // 208 // If GOROOT cannot be found, GOROOT skips t if t is non-nil, 209 // or panics otherwise. 210 func GOROOT(t testing.TB) string { 211 path, err := findGOROOT() 212 if err != nil { 213 if t == nil { 214 panic(err) 215 } 216 t.Helper() 217 t.Skip(err) 218 } 219 return path 220 } 221 222 // GoTool reports the path to the Go tool. 223 func GoTool() (string, error) { 224 if !HasGoBuild() { 225 return "", errors.New("platform cannot run go tool") 226 } 227 goToolOnce.Do(func() { 228 goToolPath, goToolErr = exec.LookPath("go") 229 }) 230 return goToolPath, goToolErr 231 } 232 233 var ( 234 goToolOnce sync.Once 235 goToolPath string 236 goToolErr error 237 ) 238 239 // HasSrc reports whether the entire source tree is available under GOROOT. 240 func HasSrc() bool { 241 switch runtime.GOOS { 242 case "ios": 243 return false 244 } 245 return true 246 } 247 248 // HasExternalNetwork reports whether the current system can use 249 // external (non-localhost) networks. 250 func HasExternalNetwork() bool { 251 return !testing.Short() && runtime.GOOS != "js" && runtime.GOOS != "wasip1" 252 } 253 254 // MustHaveExternalNetwork checks that the current system can use 255 // external (non-localhost) networks. 256 // If not, MustHaveExternalNetwork calls t.Skip with an explanation. 257 func MustHaveExternalNetwork(t testing.TB) { 258 if runtime.GOOS == "js" || runtime.GOOS == "wasip1" { 259 t.Helper() 260 t.Skipf("skipping test: no external network on %s", runtime.GOOS) 261 } 262 if testing.Short() { 263 t.Helper() 264 t.Skipf("skipping test: no external network in -short mode") 265 } 266 } 267 268 // HasCGO reports whether the current system can use cgo. 269 func HasCGO() bool { 270 hasCgoOnce.Do(func() { 271 goTool, err := GoTool() 272 if err != nil { 273 return 274 } 275 cmd := exec.Command(goTool, "env", "CGO_ENABLED") 276 cmd.Env = origEnv 277 out, err := cmd.Output() 278 if err != nil { 279 panic(fmt.Sprintf("%v: %v", cmd, out)) 280 } 281 hasCgo, err = strconv.ParseBool(string(bytes.TrimSpace(out))) 282 if err != nil { 283 panic(fmt.Sprintf("%v: non-boolean output %q", cmd, out)) 284 } 285 }) 286 return hasCgo 287 } 288 289 var ( 290 hasCgoOnce sync.Once 291 hasCgo bool 292 ) 293 294 // MustHaveCGO calls t.Skip if cgo is not available. 295 func MustHaveCGO(t testing.TB) { 296 if !HasCGO() { 297 t.Skipf("skipping test: no cgo") 298 } 299 } 300 301 // CanInternalLink reports whether the current system can link programs with 302 // internal linking. 303 func CanInternalLink(withCgo bool) bool { 304 // Modified by Hugo (not needed) 305 return false 306 } 307 308 // MustInternalLink checks that the current system can link programs with internal 309 // linking. 310 // If not, MustInternalLink calls t.Skip with an explanation. 311 func MustInternalLink(t testing.TB, withCgo bool) { 312 if !CanInternalLink(withCgo) { 313 if withCgo && CanInternalLink(false) { 314 t.Skipf("skipping test: internal linking on %s/%s is not supported with cgo", runtime.GOOS, runtime.GOARCH) 315 } 316 t.Skipf("skipping test: internal linking on %s/%s is not supported", runtime.GOOS, runtime.GOARCH) 317 } 318 } 319 320 // MustHaveBuildMode reports whether the current system can build programs in 321 // the given build mode. 322 // If not, MustHaveBuildMode calls t.Skip with an explanation. 323 func MustHaveBuildMode(t testing.TB, buildmode string) { 324 // Modified by Hugo (not needed) 325 } 326 327 // HasSymlink reports whether the current system can use os.Symlink. 328 func HasSymlink() bool { 329 ok, _ := hasSymlink() 330 return ok 331 } 332 333 // MustHaveSymlink reports whether the current system can use os.Symlink. 334 // If not, MustHaveSymlink calls t.Skip with an explanation. 335 func MustHaveSymlink(t testing.TB) { 336 ok, reason := hasSymlink() 337 if !ok { 338 t.Skipf("skipping test: cannot make symlinks on %s/%s: %s", runtime.GOOS, runtime.GOARCH, reason) 339 } 340 } 341 342 // HasLink reports whether the current system can use os.Link. 343 func HasLink() bool { 344 // From Android release M (Marshmallow), hard linking files is blocked 345 // and an attempt to call link() on a file will return EACCES. 346 // - https://code.google.com/p/android-developer-preview/issues/detail?id=3150 347 return runtime.GOOS != "plan9" && runtime.GOOS != "android" 348 } 349 350 // MustHaveLink reports whether the current system can use os.Link. 351 // If not, MustHaveLink calls t.Skip with an explanation. 352 func MustHaveLink(t testing.TB) { 353 if !HasLink() { 354 t.Skipf("skipping test: hardlinks are not supported on %s/%s", runtime.GOOS, runtime.GOARCH) 355 } 356 } 357 358 var flaky = flag.Bool("flaky", false, "run known-flaky tests too") 359 360 func SkipFlaky(t testing.TB, issue int) { 361 t.Helper() 362 if !*flaky { 363 t.Skipf("skipping known flaky test without the -flaky flag; see golang.org/issue/%d", issue) 364 } 365 } 366 367 func SkipFlakyNet(t testing.TB) { 368 t.Helper() 369 if v, _ := strconv.ParseBool(os.Getenv("GO_BUILDER_FLAKY_NET")); v { 370 t.Skip("skipping test on builder known to have frequent network failures") 371 } 372 } 373 374 // CPUIsSlow reports whether the CPU running the test is suspected to be slow. 375 func CPUIsSlow() bool { 376 switch runtime.GOARCH { 377 case "arm", "mips", "mipsle", "mips64", "mips64le", "wasm": 378 return true 379 } 380 return false 381 } 382 383 // SkipIfShortAndSlow skips t if -short is set and the CPU running the test is 384 // suspected to be slow. 385 // 386 // (This is useful for CPU-intensive tests that otherwise complete quickly.) 387 func SkipIfShortAndSlow(t testing.TB) { 388 if testing.Short() && CPUIsSlow() { 389 t.Helper() 390 t.Skipf("skipping test in -short mode on %s", runtime.GOARCH) 391 } 392 } 393 394 // SkipIfOptimizationOff skips t if optimization is disabled. 395 func SkipIfOptimizationOff(t testing.TB) { 396 if OptimizationOff() { 397 t.Helper() 398 t.Skip("skipping test with optimization disabled") 399 } 400 } 401 402 // WriteImportcfg writes an importcfg file used by the compiler or linker to 403 // dstPath containing entries for the file mappings in packageFiles, as well 404 // as for the packages transitively imported by the package(s) in pkgs. 405 // 406 // pkgs may include any package pattern that is valid to pass to 'go list', 407 // so it may also be a list of Go source files all in the same directory. 408 func WriteImportcfg(t testing.TB, dstPath string, packageFiles map[string]string, pkgs ...string) { 409 t.Helper() 410 411 icfg := new(bytes.Buffer) 412 icfg.WriteString("# import config\n") 413 for k, v := range packageFiles { 414 fmt.Fprintf(icfg, "packagefile %s=%s\n", k, v) 415 } 416 417 if len(pkgs) > 0 { 418 // Use 'go list' to resolve any missing packages and rewrite the import map. 419 cmd := Command(t, GoToolPath(t), "list", "-export", "-deps", "-f", `{{if ne .ImportPath "command-line-arguments"}}{{if .Export}}{{.ImportPath}}={{.Export}}{{end}}{{end}}`) 420 cmd.Args = append(cmd.Args, pkgs...) 421 cmd.Stderr = new(strings.Builder) 422 out, err := cmd.Output() 423 if err != nil { 424 t.Fatalf("%v: %v\n%s", cmd, err, cmd.Stderr) 425 } 426 427 for _, line := range strings.Split(string(out), "\n") { 428 if line == "" { 429 continue 430 } 431 importPath, export, ok := strings.Cut(line, "=") 432 if !ok { 433 t.Fatalf("invalid line in output from %v:\n%s", cmd, line) 434 } 435 if packageFiles[importPath] == "" { 436 fmt.Fprintf(icfg, "packagefile %s=%s\n", importPath, export) 437 } 438 } 439 } 440 441 if err := os.WriteFile(dstPath, icfg.Bytes(), 0666); err != nil { 442 t.Fatal(err) 443 } 444 } 445 446 // SyscallIsNotSupported reports whether err may indicate that a system call is 447 // not supported by the current platform or execution environment. 448 func SyscallIsNotSupported(err error) bool { 449 return syscallIsNotSupported(err) 450 }