@@ -34,6 +34,7 @@ import (
34
34
"github.com/rogpeppe/go-internal/internal/os/execpath"
35
35
"github.com/rogpeppe/go-internal/par"
36
36
"github.com/rogpeppe/go-internal/testenv"
37
+ "github.com/rogpeppe/go-internal/testscript/internal/pty"
37
38
"github.com/rogpeppe/go-internal/txtar"
38
39
)
39
40
@@ -100,6 +101,13 @@ func (e *Env) Getenv(key string) string {
100
101
return ""
101
102
}
102
103
104
+ func envvarname (k string ) string {
105
+ if runtime .GOOS == "windows" {
106
+ return strings .ToLower (k )
107
+ }
108
+ return k
109
+ }
110
+
103
111
// Setenv sets the value of the environment variable named by the key. It
104
112
// panics if key is invalid.
105
113
func (e * Env ) Setenv (key , value string ) {
@@ -357,6 +365,9 @@ type TestScript struct {
357
365
stdin string // standard input to next 'go' command; set by 'stdin' command.
358
366
stdout string // standard output from last 'go' command; for 'stdout' command
359
367
stderr string // standard error from last 'go' command; for 'stderr' command
368
+ ttyin string // terminal input; set by 'ttyin' command
369
+ stdinPty bool // connect pty to standard input; set by 'ttyin -stdin' command
370
+ ttyout string // terminal output; for 'ttyout' command
360
371
stopped bool // test wants to stop early
361
372
start time.Time // time phase started
362
373
background []backgroundCmd // backgrounded 'exec' and 'go' commands
@@ -940,16 +951,49 @@ func (ts *TestScript) exec(command string, args ...string) (stdout, stderr strin
940
951
var stdoutBuf , stderrBuf strings.Builder
941
952
cmd .Stdout = & stdoutBuf
942
953
cmd .Stderr = & stderrBuf
954
+ if ts .ttyin != "" {
955
+ ctrl , tty , err := pty .Open ()
956
+ if err != nil {
957
+ return "" , "" , err
958
+ }
959
+ doneR , doneW := make (chan struct {}), make (chan struct {})
960
+ var ptyBuf strings.Builder
961
+ go func () {
962
+ io .Copy (ctrl , strings .NewReader (ts .ttyin ))
963
+ ctrl .Write ([]byte {4 /* EOT */ })
964
+ close (doneW )
965
+ }()
966
+ go func () {
967
+ io .Copy (& ptyBuf , ctrl )
968
+ close (doneR )
969
+ }()
970
+ defer func () {
971
+ tty .Close ()
972
+ ctrl .Close ()
973
+ <- doneR
974
+ <- doneW
975
+ ts .ttyin = ""
976
+ ts .ttyout = ptyBuf .String ()
977
+ }()
978
+ pty .SetCtty (cmd , tty )
979
+ if ts .stdinPty {
980
+ cmd .Stdin = tty
981
+ }
982
+ }
943
983
if err = cmd .Start (); err == nil {
944
984
err = waitOrStop (ts .ctxt , cmd , ts .gracePeriod )
945
985
}
946
986
ts .stdin = ""
987
+ ts .stdinPty = false
947
988
return stdoutBuf .String (), stderrBuf .String (), err
948
989
}
949
990
950
991
// execBackground starts the given command line (an actual subprocess, not simulated)
951
992
// in ts.cd with environment ts.env.
952
993
func (ts * TestScript ) execBackground (command string , args ... string ) (* exec.Cmd , error ) {
994
+ if ts .ttyin != "" {
995
+ return nil , errors .New ("ttyin is not supported by background commands" )
996
+ }
953
997
cmd , err := ts .buildExecCmd (command , args ... )
954
998
if err != nil {
955
999
return nil , err
@@ -1126,6 +1170,8 @@ func (ts *TestScript) ReadFile(file string) string {
1126
1170
return ts .stdout
1127
1171
case "stderr" :
1128
1172
return ts .stderr
1173
+ case "ttyout" :
1174
+ return ts .ttyout
1129
1175
default :
1130
1176
file = ts .MkAbs (file )
1131
1177
data , err := ioutil .ReadFile (file )
0 commit comments