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  }