1
0
mirror of https://github.com/golang/go synced 2024-11-17 16:24:42 -07:00

cmd/go: add a "don't care about success" operator to script_test

Use that operator to make test_race_install_cgo agnostic to whether GOROOT/pkg is writable.

Updates #37573
Updates #30316

Change-Id: I018c63b3c369209345069f917bbb3a52179e2b58
Reviewed-on: https://go-review.googlesource.com/c/go/+/223746
Reviewed-by: Jay Conrod <jayconrod@google.com>
This commit is contained in:
Bryan C. Mills 2020-03-17 13:08:22 -04:00
parent 0c0e8f224d
commit 42dfac6708
3 changed files with 117 additions and 90 deletions

View File

@ -82,9 +82,17 @@ type testScript struct {
type backgroundCmd struct { type backgroundCmd struct {
cmd *exec.Cmd cmd *exec.Cmd
wait <-chan struct{} wait <-chan struct{}
neg bool // if true, cmd should fail want simpleStatus
} }
type simpleStatus string
const (
success simpleStatus = ""
failure simpleStatus = "!"
successOrFailure simpleStatus = "?"
)
var extraEnvKeys = []string{ var extraEnvKeys = []string{
"SYSTEMROOT", // must be preserved on Windows to find DLLs; golang.org/issue/25210 "SYSTEMROOT", // must be preserved on Windows to find DLLs; golang.org/issue/25210
"WINDIR", // must be preserved on Windows to be able to run PowerShell command; golang.org/issue/30711 "WINDIR", // must be preserved on Windows to be able to run PowerShell command; golang.org/issue/30711
@ -206,7 +214,7 @@ func (ts *testScript) run() {
// With -v or -testwork, start log with full environment. // With -v or -testwork, start log with full environment.
if *testWork || testing.Verbose() { if *testWork || testing.Verbose() {
// Display environment. // Display environment.
ts.cmdEnv(false, nil) ts.cmdEnv(success, nil)
fmt.Fprintf(&ts.log, "\n") fmt.Fprintf(&ts.log, "\n")
ts.mark = ts.log.Len() ts.mark = ts.log.Len()
} }
@ -246,7 +254,7 @@ Script:
// Parse input line. Ignore blanks entirely. // Parse input line. Ignore blanks entirely.
parsed := ts.parse(line) parsed := ts.parse(line)
if parsed.name == "" { if parsed.name == "" {
if parsed.neg || len(parsed.conds) > 0 { if parsed.want != "" || len(parsed.conds) > 0 {
ts.fatalf("missing command") ts.fatalf("missing command")
} }
continue continue
@ -325,7 +333,7 @@ Script:
if cmd == nil { if cmd == nil {
ts.fatalf("unknown command %q", parsed.name) ts.fatalf("unknown command %q", parsed.name)
} }
cmd(ts, parsed.neg, parsed.args) cmd(ts, parsed.want, parsed.args)
// Command can ask script to stop early. // Command can ask script to stop early.
if ts.stopped { if ts.stopped {
@ -338,7 +346,7 @@ Script:
for _, bg := range ts.background { for _, bg := range ts.background {
interruptProcess(bg.cmd.Process) interruptProcess(bg.cmd.Process)
} }
ts.cmdWait(false, nil) ts.cmdWait(success, nil)
// Final phase ended. // Final phase ended.
rewind() rewind()
@ -353,7 +361,7 @@ Script:
// //
// NOTE: If you make changes here, update testdata/script/README too! // NOTE: If you make changes here, update testdata/script/README too!
// //
var scriptCmds = map[string]func(*testScript, bool, []string){ var scriptCmds = map[string]func(*testScript, simpleStatus, []string){
"addcrlf": (*testScript).cmdAddcrlf, "addcrlf": (*testScript).cmdAddcrlf,
"cc": (*testScript).cmdCc, "cc": (*testScript).cmdCc,
"cd": (*testScript).cmdCd, "cd": (*testScript).cmdCd,
@ -386,7 +394,7 @@ var regexpCmd = map[string]bool{
} }
// addcrlf adds CRLF line endings to the named files. // addcrlf adds CRLF line endings to the named files.
func (ts *testScript) cmdAddcrlf(neg bool, args []string) { func (ts *testScript) cmdAddcrlf(want simpleStatus, args []string) {
if len(args) == 0 { if len(args) == 0 {
ts.fatalf("usage: addcrlf file...") ts.fatalf("usage: addcrlf file...")
} }
@ -400,21 +408,21 @@ func (ts *testScript) cmdAddcrlf(neg bool, args []string) {
} }
// cc runs the C compiler along with platform specific options. // cc runs the C compiler along with platform specific options.
func (ts *testScript) cmdCc(neg bool, args []string) { func (ts *testScript) cmdCc(want simpleStatus, args []string) {
if len(args) < 1 || (len(args) == 1 && args[0] == "&") { if len(args) < 1 || (len(args) == 1 && args[0] == "&") {
ts.fatalf("usage: cc args... [&]") ts.fatalf("usage: cc args... [&]")
} }
var b work.Builder var b work.Builder
b.Init() b.Init()
ts.cmdExec(neg, append(b.GccCmd(".", ""), args...)) ts.cmdExec(want, append(b.GccCmd(".", ""), args...))
robustio.RemoveAll(b.WorkDir) robustio.RemoveAll(b.WorkDir)
} }
// cd changes to a different directory. // cd changes to a different directory.
func (ts *testScript) cmdCd(neg bool, args []string) { func (ts *testScript) cmdCd(want simpleStatus, args []string) {
if neg { if want != success {
ts.fatalf("unsupported: ! cd") ts.fatalf("unsupported: %v cd", want)
} }
if len(args) != 1 { if len(args) != 1 {
ts.fatalf("usage: cd dir") ts.fatalf("usage: cd dir")
@ -438,9 +446,9 @@ func (ts *testScript) cmdCd(neg bool, args []string) {
} }
// chmod changes permissions for a file or directory. // chmod changes permissions for a file or directory.
func (ts *testScript) cmdChmod(neg bool, args []string) { func (ts *testScript) cmdChmod(want simpleStatus, args []string) {
if neg { if want != success {
ts.fatalf("unsupported: ! chmod") ts.fatalf("unsupported: %v chmod", want)
} }
if len(args) < 2 { if len(args) < 2 {
ts.fatalf("usage: chmod perm paths...") ts.fatalf("usage: chmod perm paths...")
@ -460,10 +468,10 @@ func (ts *testScript) cmdChmod(neg bool, args []string) {
} }
// cmp compares two files. // cmp compares two files.
func (ts *testScript) cmdCmp(neg bool, args []string) { func (ts *testScript) cmdCmp(want simpleStatus, args []string) {
if neg { if want != success {
// It would be strange to say "this file can have any content except this precise byte sequence". // It would be strange to say "this file can have any content except this precise byte sequence".
ts.fatalf("unsupported: ! cmp") ts.fatalf("unsupported: %v cmp", want)
} }
quiet := false quiet := false
if len(args) > 0 && args[0] == "-q" { if len(args) > 0 && args[0] == "-q" {
@ -477,9 +485,9 @@ func (ts *testScript) cmdCmp(neg bool, args []string) {
} }
// cmpenv compares two files with environment variable substitution. // cmpenv compares two files with environment variable substitution.
func (ts *testScript) cmdCmpenv(neg bool, args []string) { func (ts *testScript) cmdCmpenv(want simpleStatus, args []string) {
if neg { if want != success {
ts.fatalf("unsupported: ! cmpenv") ts.fatalf("unsupported: %v cmpenv", want)
} }
quiet := false quiet := false
if len(args) > 0 && args[0] == "-q" { if len(args) > 0 && args[0] == "-q" {
@ -525,7 +533,7 @@ func (ts *testScript) doCmdCmp(args []string, env, quiet bool) {
} }
// cp copies files, maybe eventually directories. // cp copies files, maybe eventually directories.
func (ts *testScript) cmdCp(neg bool, args []string) { func (ts *testScript) cmdCp(want simpleStatus, args []string) {
if len(args) < 2 { if len(args) < 2 {
ts.fatalf("usage: cp src... dst") ts.fatalf("usage: cp src... dst")
} }
@ -565,20 +573,21 @@ func (ts *testScript) cmdCp(neg bool, args []string) {
targ = filepath.Join(dst, filepath.Base(src)) targ = filepath.Join(dst, filepath.Base(src))
} }
err := ioutil.WriteFile(targ, data, mode) err := ioutil.WriteFile(targ, data, mode)
if neg { switch want {
case failure:
if err == nil { if err == nil {
ts.fatalf("unexpected command success") ts.fatalf("unexpected command success")
} }
} else { case success:
ts.check(err) ts.check(err)
} }
} }
} }
// env displays or adds to the environment. // env displays or adds to the environment.
func (ts *testScript) cmdEnv(neg bool, args []string) { func (ts *testScript) cmdEnv(want simpleStatus, args []string) {
if neg { if want != success {
ts.fatalf("unsupported: ! env") ts.fatalf("unsupported: %v env", want)
} }
conv := func(s string) string { return s } conv := func(s string) string { return s }
@ -616,7 +625,7 @@ func (ts *testScript) cmdEnv(neg bool, args []string) {
} }
// exec runs the given command. // exec runs the given command.
func (ts *testScript) cmdExec(neg bool, args []string) { func (ts *testScript) cmdExec(want simpleStatus, args []string) {
if len(args) < 1 || (len(args) == 1 && args[0] == "&") { if len(args) < 1 || (len(args) == 1 && args[0] == "&") {
ts.fatalf("usage: exec program [args...] [&]") ts.fatalf("usage: exec program [args...] [&]")
} }
@ -631,7 +640,7 @@ func (ts *testScript) cmdExec(neg bool, args []string) {
ctxWait(testCtx, cmd) ctxWait(testCtx, cmd)
close(wait) close(wait)
}() }()
ts.background = append(ts.background, backgroundCmd{cmd, wait, neg}) ts.background = append(ts.background, backgroundCmd{cmd, wait, want})
} }
ts.stdout, ts.stderr = "", "" ts.stdout, ts.stderr = "", ""
} else { } else {
@ -642,7 +651,7 @@ func (ts *testScript) cmdExec(neg bool, args []string) {
if ts.stderr != "" { if ts.stderr != "" {
fmt.Fprintf(&ts.log, "[stderr]\n%s", ts.stderr) fmt.Fprintf(&ts.log, "[stderr]\n%s", ts.stderr)
} }
if err == nil && neg { if err == nil && want == failure {
ts.fatalf("unexpected command success") ts.fatalf("unexpected command success")
} }
} }
@ -651,14 +660,17 @@ func (ts *testScript) cmdExec(neg bool, args []string) {
fmt.Fprintf(&ts.log, "[%v]\n", err) fmt.Fprintf(&ts.log, "[%v]\n", err)
if testCtx.Err() != nil { if testCtx.Err() != nil {
ts.fatalf("test timed out while running command") ts.fatalf("test timed out while running command")
} else if !neg { } else if want == success {
ts.fatalf("unexpected command failure") ts.fatalf("unexpected command failure")
} }
} }
} }
// exists checks that the list of files exists. // exists checks that the list of files exists.
func (ts *testScript) cmdExists(neg bool, args []string) { func (ts *testScript) cmdExists(want simpleStatus, args []string) {
if want == successOrFailure {
ts.fatalf("unsupported: %v exists", want)
}
var readonly, exec bool var readonly, exec bool
loop: loop:
for len(args) > 0 { for len(args) > 0 {
@ -680,34 +692,34 @@ loop:
for _, file := range args { for _, file := range args {
file = ts.mkabs(file) file = ts.mkabs(file)
info, err := os.Stat(file) info, err := os.Stat(file)
if err == nil && neg { if err == nil && want == failure {
what := "file" what := "file"
if info.IsDir() { if info.IsDir() {
what = "directory" what = "directory"
} }
ts.fatalf("%s %s unexpectedly exists", what, file) ts.fatalf("%s %s unexpectedly exists", what, file)
} }
if err != nil && !neg { if err != nil && want == success {
ts.fatalf("%s does not exist", file) ts.fatalf("%s does not exist", file)
} }
if err == nil && !neg && readonly && info.Mode()&0222 != 0 { if err == nil && want == success && readonly && info.Mode()&0222 != 0 {
ts.fatalf("%s exists but is writable", file) ts.fatalf("%s exists but is writable", file)
} }
if err == nil && !neg && exec && runtime.GOOS != "windows" && info.Mode()&0111 == 0 { if err == nil && want == success && exec && runtime.GOOS != "windows" && info.Mode()&0111 == 0 {
ts.fatalf("%s exists but is not executable", file) ts.fatalf("%s exists but is not executable", file)
} }
} }
} }
// go runs the go command. // go runs the go command.
func (ts *testScript) cmdGo(neg bool, args []string) { func (ts *testScript) cmdGo(want simpleStatus, args []string) {
ts.cmdExec(neg, append([]string{testGo}, args...)) ts.cmdExec(want, append([]string{testGo}, args...))
} }
// mkdir creates directories. // mkdir creates directories.
func (ts *testScript) cmdMkdir(neg bool, args []string) { func (ts *testScript) cmdMkdir(want simpleStatus, args []string) {
if neg { if want != success {
ts.fatalf("unsupported: ! mkdir") ts.fatalf("unsupported: %v mkdir", want)
} }
if len(args) < 1 { if len(args) < 1 {
ts.fatalf("usage: mkdir dir...") ts.fatalf("usage: mkdir dir...")
@ -718,9 +730,9 @@ func (ts *testScript) cmdMkdir(neg bool, args []string) {
} }
// rm removes files or directories. // rm removes files or directories.
func (ts *testScript) cmdRm(neg bool, args []string) { func (ts *testScript) cmdRm(want simpleStatus, args []string) {
if neg { if want != success {
ts.fatalf("unsupported: ! rm") ts.fatalf("unsupported: %v rm", want)
} }
if len(args) < 1 { if len(args) < 1 {
ts.fatalf("usage: rm file...") ts.fatalf("usage: rm file...")
@ -733,12 +745,12 @@ func (ts *testScript) cmdRm(neg bool, args []string) {
} }
// skip marks the test skipped. // skip marks the test skipped.
func (ts *testScript) cmdSkip(neg bool, args []string) { func (ts *testScript) cmdSkip(want simpleStatus, args []string) {
if len(args) > 1 { if len(args) > 1 {
ts.fatalf("usage: skip [msg]") ts.fatalf("usage: skip [msg]")
} }
if neg { if want != success {
ts.fatalf("unsupported: ! skip") ts.fatalf("unsupported: %v skip", want)
} }
// Before we mark the test as skipped, shut down any background processes and // Before we mark the test as skipped, shut down any background processes and
@ -746,7 +758,7 @@ func (ts *testScript) cmdSkip(neg bool, args []string) {
for _, bg := range ts.background { for _, bg := range ts.background {
interruptProcess(bg.cmd.Process) interruptProcess(bg.cmd.Process)
} }
ts.cmdWait(false, nil) ts.cmdWait(success, nil)
if len(args) == 1 { if len(args) == 1 {
ts.t.Skip(args[0]) ts.t.Skip(args[0])
@ -755,15 +767,18 @@ func (ts *testScript) cmdSkip(neg bool, args []string) {
} }
// stale checks that the named build targets are stale. // stale checks that the named build targets are stale.
func (ts *testScript) cmdStale(neg bool, args []string) { func (ts *testScript) cmdStale(want simpleStatus, args []string) {
if len(args) == 0 { if len(args) == 0 {
ts.fatalf("usage: stale target...") ts.fatalf("usage: stale target...")
} }
tmpl := "{{if .Error}}{{.ImportPath}}: {{.Error.Err}}{{else}}" tmpl := "{{if .Error}}{{.ImportPath}}: {{.Error.Err}}{{else}}"
if neg { switch want {
case failure:
tmpl += "{{if .Stale}}{{.ImportPath}} is unexpectedly stale{{end}}" tmpl += "{{if .Stale}}{{.ImportPath}} is unexpectedly stale{{end}}"
} else { case success:
tmpl += "{{if not .Stale}}{{.ImportPath}} is unexpectedly NOT stale{{end}}" tmpl += "{{if not .Stale}}{{.ImportPath}} is unexpectedly NOT stale{{end}}"
default:
ts.fatalf("unsupported: %v stale", want)
} }
tmpl += "{{end}}" tmpl += "{{end}}"
goArgs := append([]string{"list", "-e", "-f=" + tmpl}, args...) goArgs := append([]string{"list", "-e", "-f=" + tmpl}, args...)
@ -777,26 +792,30 @@ func (ts *testScript) cmdStale(neg bool, args []string) {
} }
// stdout checks that the last go command standard output matches a regexp. // stdout checks that the last go command standard output matches a regexp.
func (ts *testScript) cmdStdout(neg bool, args []string) { func (ts *testScript) cmdStdout(want simpleStatus, args []string) {
scriptMatch(ts, neg, args, ts.stdout, "stdout") scriptMatch(ts, want, args, ts.stdout, "stdout")
} }
// stderr checks that the last go command standard output matches a regexp. // stderr checks that the last go command standard output matches a regexp.
func (ts *testScript) cmdStderr(neg bool, args []string) { func (ts *testScript) cmdStderr(want simpleStatus, args []string) {
scriptMatch(ts, neg, args, ts.stderr, "stderr") scriptMatch(ts, want, args, ts.stderr, "stderr")
} }
// grep checks that file content matches a regexp. // grep checks that file content matches a regexp.
// Like stdout/stderr and unlike Unix grep, it accepts Go regexp syntax. // Like stdout/stderr and unlike Unix grep, it accepts Go regexp syntax.
func (ts *testScript) cmdGrep(neg bool, args []string) { func (ts *testScript) cmdGrep(want simpleStatus, args []string) {
scriptMatch(ts, neg, args, "", "grep") scriptMatch(ts, want, args, "", "grep")
} }
// scriptMatch implements both stdout and stderr. // scriptMatch implements both stdout and stderr.
func scriptMatch(ts *testScript, neg bool, args []string, text, name string) { func scriptMatch(ts *testScript, want simpleStatus, args []string, text, name string) {
if want == successOrFailure {
ts.fatalf("unsupported: %v %s", want, name)
}
n := 0 n := 0
if len(args) >= 1 && strings.HasPrefix(args[0], "-count=") { if len(args) >= 1 && strings.HasPrefix(args[0], "-count=") {
if neg { if want == failure {
ts.fatalf("cannot use -count= with negated match") ts.fatalf("cannot use -count= with negated match")
} }
var err error var err error
@ -816,12 +835,12 @@ func scriptMatch(ts *testScript, neg bool, args []string, text, name string) {
} }
extraUsage := "" extraUsage := ""
want := 1 wantArgs := 1
if name == "grep" { if name == "grep" {
extraUsage = " file" extraUsage = " file"
want = 2 wantArgs = 2
} }
if len(args) != want { if len(args) != wantArgs {
ts.fatalf("usage: %s [-count=N] 'pattern'%s", name, extraUsage) ts.fatalf("usage: %s [-count=N] 'pattern'%s", name, extraUsage)
} }
@ -842,14 +861,16 @@ func scriptMatch(ts *testScript, neg bool, args []string, text, name string) {
// Matching against workdir would be misleading. // Matching against workdir would be misleading.
text = strings.ReplaceAll(text, ts.workdir, "$WORK") text = strings.ReplaceAll(text, ts.workdir, "$WORK")
if neg { switch want {
case failure:
if re.MatchString(text) { if re.MatchString(text) {
if isGrep && !quiet { if isGrep && !quiet {
fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text) fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text)
} }
ts.fatalf("unexpected match for %#q found in %s: %s", pattern, name, re.FindString(text)) ts.fatalf("unexpected match for %#q found in %s: %s", pattern, name, re.FindString(text))
} }
} else {
case success:
if !re.MatchString(text) { if !re.MatchString(text) {
if isGrep && !quiet { if isGrep && !quiet {
fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text) fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text)
@ -869,9 +890,9 @@ func scriptMatch(ts *testScript, neg bool, args []string, text, name string) {
} }
// stop stops execution of the test (marking it passed). // stop stops execution of the test (marking it passed).
func (ts *testScript) cmdStop(neg bool, args []string) { func (ts *testScript) cmdStop(want simpleStatus, args []string) {
if neg { if want != success {
ts.fatalf("unsupported: ! stop") ts.fatalf("unsupported: %v stop", want)
} }
if len(args) > 1 { if len(args) > 1 {
ts.fatalf("usage: stop [msg]") ts.fatalf("usage: stop [msg]")
@ -885,9 +906,9 @@ func (ts *testScript) cmdStop(neg bool, args []string) {
} }
// symlink creates a symbolic link. // symlink creates a symbolic link.
func (ts *testScript) cmdSymlink(neg bool, args []string) { func (ts *testScript) cmdSymlink(want simpleStatus, args []string) {
if neg { if want != success {
ts.fatalf("unsupported: ! symlink") ts.fatalf("unsupported: %v symlink", want)
} }
if len(args) != 3 || args[1] != "->" { if len(args) != 3 || args[1] != "->" {
ts.fatalf("usage: symlink file -> target") ts.fatalf("usage: symlink file -> target")
@ -898,9 +919,9 @@ func (ts *testScript) cmdSymlink(neg bool, args []string) {
} }
// wait waits for background commands to exit, setting stderr and stdout to their result. // wait waits for background commands to exit, setting stderr and stdout to their result.
func (ts *testScript) cmdWait(neg bool, args []string) { func (ts *testScript) cmdWait(want simpleStatus, args []string) {
if neg { if want != success {
ts.fatalf("unsupported: ! wait") ts.fatalf("unsupported: %v wait", want)
} }
if len(args) > 0 { if len(args) > 0 {
ts.fatalf("usage: wait") ts.fatalf("usage: wait")
@ -926,13 +947,13 @@ func (ts *testScript) cmdWait(neg bool, args []string) {
} }
if bg.cmd.ProcessState.Success() { if bg.cmd.ProcessState.Success() {
if bg.neg { if bg.want == failure {
ts.fatalf("unexpected command success") ts.fatalf("unexpected command success")
} }
} else { } else {
if testCtx.Err() != nil { if testCtx.Err() != nil {
ts.fatalf("test timed out while running command") ts.fatalf("test timed out while running command")
} else if !bg.neg { } else if bg.want == success {
ts.fatalf("unexpected command failure") ts.fatalf("unexpected command failure")
} }
} }
@ -1057,7 +1078,7 @@ type condition struct {
// A command is a complete command parsed from a script. // A command is a complete command parsed from a script.
type command struct { type command struct {
neg bool // if true, expect the command to fail want simpleStatus
conds []condition // all must be satisfied conds []condition // all must be satisfied
name string // the name of the command; must be non-empty name string // the name of the command; must be non-empty
args []string // shell-expanded arguments following name args []string // shell-expanded arguments following name
@ -1092,11 +1113,13 @@ func (ts *testScript) parse(line string) command {
// Command prefix ! means negate the expectations about this command: // Command prefix ! means negate the expectations about this command:
// go command should fail, match should not be found, etc. // go command should fail, match should not be found, etc.
if arg == "!" { // Prefix ? means allow either success or failure.
if cmd.neg { switch want := simpleStatus(arg); want {
ts.fatalf("duplicated '!' token") case failure, successOrFailure:
if cmd.want != "" {
ts.fatalf("duplicated '!' or '?' token")
} }
cmd.neg = true cmd.want = want
return return
} }

View File

@ -66,6 +66,10 @@ The command prefix ! indicates that the command on the rest of the line
(typically go or a matching predicate) must fail, not succeed. Only certain (typically go or a matching predicate) must fail, not succeed. Only certain
commands support this prefix. They are indicated below by [!] in the synopsis. commands support this prefix. They are indicated below by [!] in the synopsis.
The command prefix ? indicates that the command on the rest of the line
may or may not succeed, but the test should continue regardless.
Commands that support this prefix are indicated by [?].
The command prefix [cond] indicates that the command on the rest of the line The command prefix [cond] indicates that the command on the rest of the line
should only run when the condition is satisfied. The available conditions are: should only run when the condition is satisfied. The available conditions are:
@ -89,7 +93,7 @@ are satisfied.
The commands are: The commands are:
- [!] cc args... [&] - [! | ?] cc args... [&]
Run the C compiler, the platform specific flags (i.e. `go env GOGCCFLAGS`) will be Run the C compiler, the platform specific flags (i.e. `go env GOGCCFLAGS`) will be
added automatically before args. added automatically before args.
@ -111,7 +115,7 @@ The commands are:
Like cmp, but environment variables are substituted in the file contents Like cmp, but environment variables are substituted in the file contents
before the comparison. For example, $GOOS is replaced by the target GOOS. before the comparison. For example, $GOOS is replaced by the target GOOS.
- [!] cp src... dst - [! | ?] cp src... dst
Copy the listed files to the target file or existing directory. Copy the listed files to the target file or existing directory.
src can include "stdout" or "stderr" to use the standard output or standard error src can include "stdout" or "stderr" to use the standard output or standard error
from the most recent exec or go command. from the most recent exec or go command.
@ -123,7 +127,7 @@ The commands are:
The -r flag causes the values to be escaped using regexp.QuoteMeta The -r flag causes the values to be escaped using regexp.QuoteMeta
before being recorded. before being recorded.
- [!] exec program [args...] [&] - [! | ?] exec program [args...] [&]
Run the given executable program with the arguments. Run the given executable program with the arguments.
It must (or must not) succeed. It must (or must not) succeed.
Note that 'exec' does not terminate the script (unlike in Unix shells). Note that 'exec' does not terminate the script (unlike in Unix shells).
@ -140,7 +144,7 @@ The commands are:
If -readonly is given, the files or directories must be unwritable. If -readonly is given, the files or directories must be unwritable.
If -exec is given, the files or directories must be executable. If -exec is given, the files or directories must be executable.
- [!] go args... [&] - [! | ?] go args... [&]
Run the (test copy of the) go command with the given arguments. Run the (test copy of the) go command with the given arguments.
It must (or must not) succeed. It must (or must not) succeed.

View File

@ -2,6 +2,8 @@
[!race] skip [!race] skip
! stale cmd/cgo
env GOBIN=$WORK/bin env GOBIN=$WORK/bin
go install mtime sametime go install mtime sametime
@ -11,11 +13,9 @@ exec $GOBIN/mtime cgopath.txt # get the mtime of the file whose name is in cgopa
cp stdout cgotime_before.txt cp stdout cgotime_before.txt
# For this test, we don't actually care whether 'go test -race -i' succeeds. # For this test, we don't actually care whether 'go test -race -i' succeeds.
# It may fail, for example, if GOROOT was installed from source as root and # It may fail if GOROOT is read-only (perhaps it was installed as root).
# is now read-only. # We only care that it does not overwrite cmd/cgo regardless.
# We only care that — regardless of whether it succeeds — it does not ? go test -race -i runtime/race
# overwrite cmd/cgo.
go test -race -i runtime/race
exec $GOBIN/mtime cgopath.txt # get the mtime of the file whose name is in cgopath.txt exec $GOBIN/mtime cgopath.txt # get the mtime of the file whose name is in cgopath.txt
cp stdout cgotime_after.txt cp stdout cgotime_after.txt
@ -88,4 +88,4 @@ func main() {
fmt.Fprintf(os.Stderr, "time in %v (%v) is not the same as time in %v (%v)", os.Args[1], t1, os.Args[2], t2) fmt.Fprintf(os.Stderr, "time in %v (%v) is not the same as time in %v (%v)", os.Args[1], t1, os.Args[2], t2)
os.Exit(1) os.Exit(1)
} }
} }