Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

testscript: add Go compiler and version conditions #154

Merged
merged 4 commits into from Mar 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 1 addition & 23 deletions gotooltest/setup.go
Expand Up @@ -10,7 +10,6 @@ import (
"bytes"
"encoding/json"
"fmt"
"go/build"
"os/exec"
"path/filepath"
"regexp"
Expand All @@ -22,7 +21,7 @@ import (
)

var (
goVersionRegex = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
goVersionRegex = regexp.MustCompile(`^go([1-9][0-9]*)\.([1-9][0-9]*)$`)

goEnv struct {
GOROOT string
Expand Down Expand Up @@ -104,27 +103,6 @@ func Setup(p *testscript.Params) error {
p.Cmds = make(map[string]func(ts *testscript.TestScript, neg bool, args []string))
}
p.Cmds["go"] = cmdGo
origCondition := p.Condition
p.Condition = func(cond string) (bool, error) {
if cond == "gc" || cond == "gccgo" {
// TODO this reflects the compiler that the current
// binary was built with but not necessarily the compiler
// that will be used.
return cond == runtime.Compiler, nil
}
if goVersionRegex.MatchString(cond) {
for _, v := range build.Default.ReleaseTags {
if cond == v {
return true, nil
}
}
return false, nil
}
if origCondition == nil {
return false, fmt.Errorf("unknown condition %q", cond)
}
return origCondition(cond)
}
return nil
}

Expand Down
3 changes: 3 additions & 0 deletions testscript/doc.go
Expand Up @@ -105,6 +105,9 @@ should only run when the condition is satisfied. The predefined conditions are:
- [link] for whether the OS has hard link support
- [symlink] for whether the OS has symbolic link support
- [exec:prog] for whether prog is available for execution (found by exec.LookPath)
- [gc] for whether Go was built with gc
- [gccgo] for whether Go was built with gccgo
- [go1.x] for whether the Go version is 1.x or later

A condition can be negated: [!short] means to run the rest of the line
when testing.Short() is false.
Expand Down
11 changes: 11 additions & 0 deletions testscript/testdata/cond.txt
@@ -0,0 +1,11 @@
[!exec:sh] skip 'sh not found in $PATH'

# test that exactly one of gc and gccgo is set
[gc] exec sh -c 'echo gc >> go-compiler'
[gccgo] exec sh -c 'echo gccgo >> go-compiler'
grep '\A(gc|gccgo)\n\z' go-compiler

# test that go version build tags are set
[go1.1] exec sh -c 'echo go1.1 >> go-version'
[go2.1] exec sh -c 'echo go2.1 >> go-version'
grep '\Ago1\.1\n\z' go-version
54 changes: 33 additions & 21 deletions testscript/testscript.go
Expand Up @@ -12,6 +12,7 @@ import (
"context"
"flag"
"fmt"
"go/build"
"io/ioutil"
"os"
"os/exec"
Expand All @@ -30,6 +31,8 @@ import (
"github.com/rogpeppe/go-internal/txtar"
)

var goVersionRegex = regexp.MustCompile(`^go([1-9][0-9]*)\.([1-9][0-9]*)$`)

var execCache par.Cache

// If -testwork is specified, the test prints the name of the temp directory
Expand Down Expand Up @@ -572,32 +575,41 @@ func (ts *TestScript) applyScriptUpdates() {

// condition reports whether the given condition is satisfied.
func (ts *TestScript) condition(cond string) (bool, error) {
switch cond {
case "short":
switch {
case cond == "short":
return testing.Short(), nil
case "net":
case cond == "net":
return testenv.HasExternalNetwork(), nil
case "link":
case cond == "link":
return testenv.HasLink(), nil
case "symlink":
case cond == "symlink":
return testenv.HasSymlink(), nil
case runtime.GOOS, runtime.GOARCH:
return true, nil
default:
if imports.KnownArch[cond] || imports.KnownOS[cond] {
return false, nil
}
if strings.HasPrefix(cond, "exec:") {
prog := cond[len("exec:"):]
ok := execCache.Do(prog, func() interface{} {
_, err := execpath.Look(prog, ts.Getenv)
return err == nil
}).(bool)
return ok, nil
}
if ts.params.Condition != nil {
return ts.params.Condition(cond)
case imports.KnownOS[cond]:
return cond == runtime.GOOS, nil
case imports.KnownArch[cond]:
return cond == runtime.GOARCH, nil
case strings.HasPrefix(cond, "exec:"):
prog := cond[len("exec:"):]
ok := execCache.Do(prog, func() interface{} {
_, err := execpath.Look(prog, ts.Getenv)
return err == nil
}).(bool)
return ok, nil
case cond == "gc" || cond == "gccgo":
// TODO this reflects the compiler that the current
// binary was built with but not necessarily the compiler
// that will be used.
return cond == runtime.Compiler, nil
case goVersionRegex.MatchString(cond):
for _, v := range build.Default.ReleaseTags {
if cond == v {
return true, nil
}
}
return false, nil
case ts.params.Condition != nil:
return ts.params.Condition(cond)
default:
ts.Fatalf("unknown condition %q", cond)
panic("unreachable")
}
Expand Down