Source file src/cmd/internal/script/scripttest/conditions.go

     1  // Copyright 2024 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 scripttest
     6  
     7  import (
     8  	"cmd/internal/script"
     9  	"fmt"
    10  	"internal/buildcfg"
    11  	"internal/platform"
    12  	"internal/testenv"
    13  	"runtime"
    14  	"strings"
    15  	"testing"
    16  )
    17  
    18  // AddToolChainScriptConditions accepts a [script.Cond] map and adds into it a
    19  // set of commonly used conditions for doing toolchains testing,
    20  // including whether the platform supports cgo, a buildmode condition,
    21  // support for GOEXPERIMENT testing, etc. Callers must also pass in
    22  // current GOHOSTOOS/GOHOSTARCH settings, since some of the conditions
    23  // introduced can be influenced by them.
    24  func AddToolChainScriptConditions(t *testing.T, conds map[string]script.Cond, goHostOS, goHostArch string) {
    25  	add := func(name string, cond script.Cond) {
    26  		if _, ok := conds[name]; ok {
    27  			t.Fatalf("condition %q is already registered", name)
    28  		}
    29  		conds[name] = cond
    30  	}
    31  
    32  	lazyBool := func(summary string, f func() bool) script.Cond {
    33  		return script.OnceCondition(summary, func() (bool, error) { return f(), nil })
    34  	}
    35  
    36  	add("asan", sysCondition("-asan", platform.ASanSupported, true, goHostOS, goHostArch))
    37  	add("buildmode", script.PrefixCondition("go supports -buildmode=<suffix>", hasBuildmode))
    38  	add("cgo", script.BoolCondition("host CGO_ENABLED", testenv.HasCGO()))
    39  	add("cgolinkext", script.Condition("platform requires external linking for cgo", cgoLinkExt))
    40  	add("cross", script.BoolCondition("cmd/go GOOS/GOARCH != GOHOSTOS/GOHOSTARCH", goHostOS != runtime.GOOS || goHostArch != runtime.GOARCH))
    41  	add("fuzz", sysCondition("-fuzz", platform.FuzzSupported, false, goHostOS, goHostArch))
    42  	add("fuzz-instrumented", sysCondition("-fuzz with instrumentation", platform.FuzzInstrumented, false, goHostOS, goHostArch))
    43  	add("GODEBUG", script.PrefixCondition("GODEBUG contains <suffix>", hasGodebug))
    44  	add("GOEXPERIMENT", script.PrefixCondition("GOEXPERIMENT <suffix> is enabled", hasGoexperiment))
    45  	add("go-builder", script.BoolCondition("GO_BUILDER_NAME is non-empty", testenv.Builder() != ""))
    46  	add("link", lazyBool("testenv.HasLink()", testenv.HasLink))
    47  	add("msan", sysCondition("-msan", platform.MSanSupported, true, goHostOS, goHostArch))
    48  	add("mustlinkext", script.Condition("platform always requires external linking", mustLinkExt))
    49  	add("pielinkext", script.Condition("platform requires external linking for PIE", pieLinkExt))
    50  	add("race", sysCondition("-race", platform.RaceDetectorSupported, true, goHostOS, goHostArch))
    51  	add("symlink", lazyBool("testenv.HasSymlink()", testenv.HasSymlink))
    52  }
    53  
    54  func sysCondition(flag string, f func(goos, goarch string) bool, needsCgo bool, goHostOS, goHostArch string) script.Cond {
    55  	return script.Condition(
    56  		"GOOS/GOARCH supports "+flag,
    57  		func(s *script.State) (bool, error) {
    58  			GOOS, _ := s.LookupEnv("GOOS")
    59  			GOARCH, _ := s.LookupEnv("GOARCH")
    60  			cross := goHostOS != GOOS || goHostArch != GOARCH
    61  			return (!needsCgo || (testenv.HasCGO() && !cross)) && f(GOOS, GOARCH), nil
    62  		})
    63  }
    64  
    65  func hasBuildmode(s *script.State, mode string) (bool, error) {
    66  	GOOS, _ := s.LookupEnv("GOOS")
    67  	GOARCH, _ := s.LookupEnv("GOARCH")
    68  	return platform.BuildModeSupported(runtime.Compiler, mode, GOOS, GOARCH), nil
    69  }
    70  
    71  func cgoLinkExt(s *script.State) (bool, error) {
    72  	GOOS, _ := s.LookupEnv("GOOS")
    73  	GOARCH, _ := s.LookupEnv("GOARCH")
    74  	return platform.MustLinkExternal(GOOS, GOARCH, true), nil
    75  }
    76  
    77  func mustLinkExt(s *script.State) (bool, error) {
    78  	GOOS, _ := s.LookupEnv("GOOS")
    79  	GOARCH, _ := s.LookupEnv("GOARCH")
    80  	return platform.MustLinkExternal(GOOS, GOARCH, false), nil
    81  }
    82  
    83  func pieLinkExt(s *script.State) (bool, error) {
    84  	GOOS, _ := s.LookupEnv("GOOS")
    85  	GOARCH, _ := s.LookupEnv("GOARCH")
    86  	return !platform.InternalLinkPIESupported(GOOS, GOARCH), nil
    87  }
    88  
    89  func hasGodebug(s *script.State, value string) (bool, error) {
    90  	godebug, _ := s.LookupEnv("GODEBUG")
    91  	for _, p := range strings.Split(godebug, ",") {
    92  		if strings.TrimSpace(p) == value {
    93  			return true, nil
    94  		}
    95  	}
    96  	return false, nil
    97  }
    98  
    99  func hasGoexperiment(s *script.State, value string) (bool, error) {
   100  	GOOS, _ := s.LookupEnv("GOOS")
   101  	GOARCH, _ := s.LookupEnv("GOARCH")
   102  	goexp, _ := s.LookupEnv("GOEXPERIMENT")
   103  	flags, err := buildcfg.ParseGOEXPERIMENT(GOOS, GOARCH, goexp)
   104  	if err != nil {
   105  		return false, err
   106  	}
   107  	for _, exp := range flags.All() {
   108  		if value == exp {
   109  			return true, nil
   110  		}
   111  		if strings.TrimPrefix(value, "no") == strings.TrimPrefix(exp, "no") {
   112  			return false, nil
   113  		}
   114  	}
   115  	return false, fmt.Errorf("unrecognized GOEXPERIMENT %q", value)
   116  }
   117  

View as plain text