github.com/bir3/gocompiler@v0.9.2202/src/cmd/gocmd/internal/script/scripttest/scripttest.go (about) 1 // Copyright 2022 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 adapts the script engine for use in tests. 6 package scripttest 7 8 import ( 9 "bufio" 10 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/cfg" 11 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/script" 12 "errors" 13 "io" 14 "strings" 15 "testing" 16 ) 17 18 // DefaultCmds returns a set of broadly useful script commands. 19 // 20 // This set includes all of the commands in script.DefaultCmds, 21 // as well as a "skip" command that halts the script and causes the 22 // testing.TB passed to Run to be skipped. 23 func DefaultCmds() map[string]script.Cmd { 24 cmds := script.DefaultCmds() 25 cmds["skip"] = Skip() 26 return cmds 27 } 28 29 // DefaultConds returns a set of broadly useful script conditions. 30 // 31 // This set includes all of the conditions in script.DefaultConds, 32 // as well as: 33 // 34 // - Conditions of the form "exec:foo" are active when the executable "foo" is 35 // found in the test process's PATH, and inactive when the executable is 36 // not found. 37 // 38 // - "short" is active when testing.Short() is true. 39 // 40 // - "verbose" is active when testing.Verbose() is true. 41 func DefaultConds() map[string]script.Cond { 42 conds := script.DefaultConds() 43 conds["exec"] = CachedExec() 44 conds["short"] = script.BoolCondition("testing.Short()", testing.Short()) 45 conds["verbose"] = script.BoolCondition("testing.Verbose()", testing.Verbose()) 46 return conds 47 } 48 49 // Run runs the script from the given filename starting at the given initial state. 50 // When the script completes, Run closes the state. 51 func Run(t testing.TB, e *script.Engine, s *script.State, filename string, testScript io.Reader) { 52 t.Helper() 53 err := func() (err error) { 54 log := new(strings.Builder) 55 log.WriteString("\n") // Start output on a new line for consistent indentation. 56 57 // Defer writing to the test log in case the script engine panics during execution, 58 // but write the log before we write the final "skip" or "FAIL" line. 59 t.Helper() 60 defer func() { 61 t.Helper() 62 63 if closeErr := s.CloseAndWait(log); err == nil { 64 err = closeErr 65 } 66 67 if log.Len() > 0 { 68 t.Log(strings.TrimSuffix(log.String(), "\n")) 69 } 70 }() 71 72 if testing.Verbose() { 73 // Add the environment to the start of the script log. 74 wait, err := script.Env().Run(s) 75 if err != nil { 76 t.Fatal(err) 77 } 78 if wait != nil { 79 stdout, stderr, err := wait(s) 80 if err != nil { 81 t.Fatalf("env: %v\n%s", err, stderr) 82 } 83 if len(stdout) > 0 { 84 s.Logf("%s\n", stdout) 85 } 86 } 87 } 88 89 return e.Execute(s, filename, bufio.NewReader(testScript), log) 90 }() 91 92 if skip := (skipError{}); errors.As(err, &skip) { 93 if skip.msg == "" { 94 t.Skip("SKIP") 95 } else { 96 t.Skipf("SKIP: %v", skip.msg) 97 } 98 } 99 if err != nil { 100 t.Errorf("FAIL: %v", err) 101 } 102 } 103 104 // Skip returns a sentinel error that causes Run to mark the test as skipped. 105 func Skip() script.Cmd { 106 return script.Command( 107 script.CmdUsage{ 108 Summary: "skip the current test", 109 Args: "[msg]", 110 }, 111 func(_ *script.State, args ...string) (script.WaitFunc, error) { 112 if len(args) > 1 { 113 return nil, script.ErrUsage 114 } 115 if len(args) == 0 { 116 return nil, skipError{""} 117 } 118 return nil, skipError{args[0]} 119 }) 120 } 121 122 type skipError struct { 123 msg string 124 } 125 126 func (s skipError) Error() string { 127 if s.msg == "" { 128 return "skip" 129 } 130 return s.msg 131 } 132 133 // CachedExec returns a Condition that reports whether the PATH of the test 134 // binary itself (not the script's current environment) contains the named 135 // executable. 136 func CachedExec() script.Cond { 137 return script.CachedCondition( 138 "<suffix> names an executable in the test binary's PATH", 139 func(name string) (bool, error) { 140 _, err := cfg.LookPath(name) 141 return err == nil, nil 142 }) 143 }