1
1
package cliui_test
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
6
+ "io"
5
7
"os"
6
8
"os/exec"
7
9
"testing"
@@ -24,7 +26,7 @@ func TestPrompt(t *testing.T) {
24
26
go func () {
25
27
resp ,err := newPrompt (ptty , cliui.PromptOptions {
26
28
Text :"Example" ,
27
- })
29
+ }, nil )
28
30
require .NoError (t ,err )
29
31
msgChan <- resp
30
32
}()
@@ -41,7 +43,7 @@ func TestPrompt(t *testing.T) {
41
43
resp ,err := newPrompt (ptty , cliui.PromptOptions {
42
44
Text :"Example" ,
43
45
IsConfirm :true ,
44
- })
46
+ }, nil )
45
47
require .NoError (t ,err )
46
48
doneChan <- resp
47
49
}()
@@ -50,14 +52,55 @@ func TestPrompt(t *testing.T) {
50
52
require .Equal (t ,"yes" ,<- doneChan )
51
53
})
52
54
55
+ t .Run ("Skip" ,func (t * testing.T ) {
56
+ t .Parallel ()
57
+ ptty := ptytest .New (t )
58
+ var buf bytes.Buffer
59
+
60
+ // Copy all data written out to a buffer. When we close the ptty, we can
61
+ // no longer read from the ptty.Output(), but we can read what was
62
+ // written to the buffer.
63
+ dataRead ,doneReading := context .WithTimeout (context .Background (),time .Second * 2 )
64
+ go func () {
65
+ // This will throw an error sometimes. The underlying ptty
66
+ // has its own cleanup routines in t.Cleanup. Instead of
67
+ // trying to control the close perfectly, just let the ptty
68
+ // double close. This error isn't important, we just
69
+ // want to know the ptty is done sending output.
70
+ _ ,_ = io .Copy (& buf ,ptty .Output ())
71
+ doneReading ()
72
+ }()
73
+
74
+ doneChan := make (chan string )
75
+ go func () {
76
+ resp ,err := newPrompt (ptty , cliui.PromptOptions {
77
+ Text :"ShouldNotSeeThis" ,
78
+ IsConfirm :true ,
79
+ },func (cmd * cobra.Command ) {
80
+ cliui .AllowSkipPrompt (cmd )
81
+ cmd .SetArgs ([]string {"-y" })
82
+ })
83
+ require .NoError (t ,err )
84
+ doneChan <- resp
85
+ }()
86
+
87
+ require .Equal (t ,"yes" ,<- doneChan )
88
+ // Close the reader to end the io.Copy
89
+ require .NoError (t ,ptty .Close (),"close eof reader" )
90
+ // Wait for the IO copy to finish
91
+ <- dataRead .Done ()
92
+ // Timeout error means the output was hanging
93
+ require .ErrorIs (t ,dataRead .Err (),context .Canceled ,"should be canceled" )
94
+ require .Len (t ,buf .Bytes (),0 ,"expect no output" )
95
+ })
53
96
t .Run ("JSON" ,func (t * testing.T ) {
54
97
t .Parallel ()
55
98
ptty := ptytest .New (t )
56
99
doneChan := make (chan string )
57
100
go func () {
58
101
resp ,err := newPrompt (ptty , cliui.PromptOptions {
59
102
Text :"Example" ,
60
- })
103
+ }, nil )
61
104
require .NoError (t ,err )
62
105
doneChan <- resp
63
106
}()
@@ -73,7 +116,7 @@ func TestPrompt(t *testing.T) {
73
116
go func () {
74
117
resp ,err := newPrompt (ptty , cliui.PromptOptions {
75
118
Text :"Example" ,
76
- })
119
+ }, nil )
77
120
require .NoError (t ,err )
78
121
doneChan <- resp
79
122
}()
@@ -89,7 +132,7 @@ func TestPrompt(t *testing.T) {
89
132
go func () {
90
133
resp ,err := newPrompt (ptty , cliui.PromptOptions {
91
134
Text :"Example" ,
92
- })
135
+ }, nil )
93
136
require .NoError (t ,err )
94
137
doneChan <- resp
95
138
}()
@@ -101,7 +144,7 @@ func TestPrompt(t *testing.T) {
101
144
})
102
145
}
103
146
104
- func newPrompt (ptty * ptytest.PTY ,opts cliui.PromptOptions ) (string ,error ) {
147
+ func newPrompt (ptty * ptytest.PTY ,opts cliui.PromptOptions , cmdOpt func ( cmd * cobra. Command ) ) (string ,error ) {
105
148
value := ""
106
149
cmd := & cobra.Command {
107
150
RunE :func (cmd * cobra.Command ,args []string )error {
@@ -110,7 +153,12 @@ func newPrompt(ptty *ptytest.PTY, opts cliui.PromptOptions) (string, error) {
110
153
return err
111
154
},
112
155
}
113
- cmd .SetOutput (ptty .Output ())
156
+ // Optionally modify the cmd
157
+ if cmdOpt != nil {
158
+ cmdOpt (cmd )
159
+ }
160
+ cmd .SetOut (ptty .Output ())
161
+ cmd .SetErr (ptty .Output ())
114
162
cmd .SetIn (ptty .Input ())
115
163
return value ,cmd .ExecuteContext (context .Background ())
116
164
}