OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / crypto / ssh / terminal / terminal_test.go
1 // Copyright 2011 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 terminal
6
7 import (
8         "bytes"
9         "io"
10         "os"
11         "testing"
12 )
13
14 type MockTerminal struct {
15         toSend       []byte
16         bytesPerRead int
17         received     []byte
18 }
19
20 func (c *MockTerminal) Read(data []byte) (n int, err error) {
21         n = len(data)
22         if n == 0 {
23                 return
24         }
25         if n > len(c.toSend) {
26                 n = len(c.toSend)
27         }
28         if n == 0 {
29                 return 0, io.EOF
30         }
31         if c.bytesPerRead > 0 && n > c.bytesPerRead {
32                 n = c.bytesPerRead
33         }
34         copy(data, c.toSend[:n])
35         c.toSend = c.toSend[n:]
36         return
37 }
38
39 func (c *MockTerminal) Write(data []byte) (n int, err error) {
40         c.received = append(c.received, data...)
41         return len(data), nil
42 }
43
44 func TestClose(t *testing.T) {
45         c := &MockTerminal{}
46         ss := NewTerminal(c, "> ")
47         line, err := ss.ReadLine()
48         if line != "" {
49                 t.Errorf("Expected empty line but got: %s", line)
50         }
51         if err != io.EOF {
52                 t.Errorf("Error should have been EOF but got: %s", err)
53         }
54 }
55
56 var keyPressTests = []struct {
57         in             string
58         line           string
59         err            error
60         throwAwayLines int
61 }{
62         {
63                 err: io.EOF,
64         },
65         {
66                 in:   "\r",
67                 line: "",
68         },
69         {
70                 in:   "foo\r",
71                 line: "foo",
72         },
73         {
74                 in:   "a\x1b[Cb\r", // right
75                 line: "ab",
76         },
77         {
78                 in:   "a\x1b[Db\r", // left
79                 line: "ba",
80         },
81         {
82                 in:   "a\177b\r", // backspace
83                 line: "b",
84         },
85         {
86                 in: "\x1b[A\r", // up
87         },
88         {
89                 in: "\x1b[B\r", // down
90         },
91         {
92                 in:   "line\x1b[A\x1b[B\r", // up then down
93                 line: "line",
94         },
95         {
96                 in:             "line1\rline2\x1b[A\r", // recall previous line.
97                 line:           "line1",
98                 throwAwayLines: 1,
99         },
100         {
101                 // recall two previous lines and append.
102                 in:             "line1\rline2\rline3\x1b[A\x1b[Axxx\r",
103                 line:           "line1xxx",
104                 throwAwayLines: 2,
105         },
106         {
107                 // Ctrl-A to move to beginning of line followed by ^K to kill
108                 // line.
109                 in:   "a b \001\013\r",
110                 line: "",
111         },
112         {
113                 // Ctrl-A to move to beginning of line, Ctrl-E to move to end,
114                 // finally ^K to kill nothing.
115                 in:   "a b \001\005\013\r",
116                 line: "a b ",
117         },
118         {
119                 in:   "\027\r",
120                 line: "",
121         },
122         {
123                 in:   "a\027\r",
124                 line: "",
125         },
126         {
127                 in:   "a \027\r",
128                 line: "",
129         },
130         {
131                 in:   "a b\027\r",
132                 line: "a ",
133         },
134         {
135                 in:   "a b \027\r",
136                 line: "a ",
137         },
138         {
139                 in:   "one two thr\x1b[D\027\r",
140                 line: "one two r",
141         },
142         {
143                 in:   "\013\r",
144                 line: "",
145         },
146         {
147                 in:   "a\013\r",
148                 line: "a",
149         },
150         {
151                 in:   "ab\x1b[D\013\r",
152                 line: "a",
153         },
154         {
155                 in:   "Ξεσκεπάζω\r",
156                 line: "Ξεσκεπάζω",
157         },
158         {
159                 in:             "£\r\x1b[A\177\r", // non-ASCII char, enter, up, backspace.
160                 line:           "",
161                 throwAwayLines: 1,
162         },
163         {
164                 in:             "£\r££\x1b[A\x1b[B\177\r", // non-ASCII char, enter, 2x non-ASCII, up, down, backspace, enter.
165                 line:           "£",
166                 throwAwayLines: 1,
167         },
168         {
169                 // Ctrl-D at the end of the line should be ignored.
170                 in:   "a\004\r",
171                 line: "a",
172         },
173         {
174                 // a, b, left, Ctrl-D should erase the b.
175                 in:   "ab\x1b[D\004\r",
176                 line: "a",
177         },
178         {
179                 // a, b, c, d, left, left, ^U should erase to the beginning of
180                 // the line.
181                 in:   "abcd\x1b[D\x1b[D\025\r",
182                 line: "cd",
183         },
184         {
185                 // Bracketed paste mode: control sequences should be returned
186                 // verbatim in paste mode.
187                 in:   "abc\x1b[200~de\177f\x1b[201~\177\r",
188                 line: "abcde\177",
189         },
190         {
191                 // Enter in bracketed paste mode should still work.
192                 in:             "abc\x1b[200~d\refg\x1b[201~h\r",
193                 line:           "efgh",
194                 throwAwayLines: 1,
195         },
196         {
197                 // Lines consisting entirely of pasted data should be indicated as such.
198                 in:   "\x1b[200~a\r",
199                 line: "a",
200                 err:  ErrPasteIndicator,
201         },
202 }
203
204 func TestKeyPresses(t *testing.T) {
205         for i, test := range keyPressTests {
206                 for j := 1; j < len(test.in); j++ {
207                         c := &MockTerminal{
208                                 toSend:       []byte(test.in),
209                                 bytesPerRead: j,
210                         }
211                         ss := NewTerminal(c, "> ")
212                         for k := 0; k < test.throwAwayLines; k++ {
213                                 _, err := ss.ReadLine()
214                                 if err != nil {
215                                         t.Errorf("Throwaway line %d from test %d resulted in error: %s", k, i, err)
216                                 }
217                         }
218                         line, err := ss.ReadLine()
219                         if line != test.line {
220                                 t.Errorf("Line resulting from test %d (%d bytes per read) was '%s', expected '%s'", i, j, line, test.line)
221                                 break
222                         }
223                         if err != test.err {
224                                 t.Errorf("Error resulting from test %d (%d bytes per read) was '%v', expected '%v'", i, j, err, test.err)
225                                 break
226                         }
227                 }
228         }
229 }
230
231 func TestPasswordNotSaved(t *testing.T) {
232         c := &MockTerminal{
233                 toSend:       []byte("password\r\x1b[A\r"),
234                 bytesPerRead: 1,
235         }
236         ss := NewTerminal(c, "> ")
237         pw, _ := ss.ReadPassword("> ")
238         if pw != "password" {
239                 t.Fatalf("failed to read password, got %s", pw)
240         }
241         line, _ := ss.ReadLine()
242         if len(line) > 0 {
243                 t.Fatalf("password was saved in history")
244         }
245 }
246
247 var setSizeTests = []struct {
248         width, height int
249 }{
250         {40, 13},
251         {80, 24},
252         {132, 43},
253 }
254
255 func TestTerminalSetSize(t *testing.T) {
256         for _, setSize := range setSizeTests {
257                 c := &MockTerminal{
258                         toSend:       []byte("password\r\x1b[A\r"),
259                         bytesPerRead: 1,
260                 }
261                 ss := NewTerminal(c, "> ")
262                 ss.SetSize(setSize.width, setSize.height)
263                 pw, _ := ss.ReadPassword("Password: ")
264                 if pw != "password" {
265                         t.Fatalf("failed to read password, got %s", pw)
266                 }
267                 if string(c.received) != "Password: \r\n" {
268                         t.Errorf("failed to set the temporary prompt expected %q, got %q", "Password: ", c.received)
269                 }
270         }
271 }
272
273 func TestReadPasswordLineEnd(t *testing.T) {
274         var tests = []struct {
275                 input string
276                 want  string
277         }{
278                 {"\n", ""},
279                 {"\r\n", ""},
280                 {"test\r\n", "test"},
281                 {"testtesttesttes\n", "testtesttesttes"},
282                 {"testtesttesttes\r\n", "testtesttesttes"},
283                 {"testtesttesttesttest\n", "testtesttesttesttest"},
284                 {"testtesttesttesttest\r\n", "testtesttesttesttest"},
285         }
286         for _, test := range tests {
287                 buf := new(bytes.Buffer)
288                 if _, err := buf.WriteString(test.input); err != nil {
289                         t.Fatal(err)
290                 }
291
292                 have, err := readPasswordLine(buf)
293                 if err != nil {
294                         t.Errorf("readPasswordLine(%q) failed: %v", test.input, err)
295                         continue
296                 }
297                 if string(have) != test.want {
298                         t.Errorf("readPasswordLine(%q) returns %q, but %q is expected", test.input, string(have), test.want)
299                         continue
300                 }
301
302                 if _, err = buf.WriteString(test.input); err != nil {
303                         t.Fatal(err)
304                 }
305                 have, err = readPasswordLine(buf)
306                 if err != nil {
307                         t.Errorf("readPasswordLine(%q) failed: %v", test.input, err)
308                         continue
309                 }
310                 if string(have) != test.want {
311                         t.Errorf("readPasswordLine(%q) returns %q, but %q is expected", test.input, string(have), test.want)
312                         continue
313                 }
314         }
315 }
316
317 func TestMakeRawState(t *testing.T) {
318         fd := int(os.Stdout.Fd())
319         if !IsTerminal(fd) {
320                 t.Skip("stdout is not a terminal; skipping test")
321         }
322
323         st, err := GetState(fd)
324         if err != nil {
325                 t.Fatalf("failed to get terminal state from GetState: %s", err)
326         }
327         defer Restore(fd, st)
328         raw, err := MakeRaw(fd)
329         if err != nil {
330                 t.Fatalf("failed to get terminal state from MakeRaw: %s", err)
331         }
332
333         if *st != *raw {
334                 t.Errorf("states do not match; was %v, expected %v", raw, st)
335         }
336 }
337
338 func TestOutputNewlines(t *testing.T) {
339         // \n should be changed to \r\n in terminal output.
340         buf := new(bytes.Buffer)
341         term := NewTerminal(buf, ">")
342
343         term.Write([]byte("1\n2\n"))
344         output := string(buf.Bytes())
345         const expected = "1\r\n2\r\n"
346
347         if output != expected {
348                 t.Errorf("incorrect output: was %q, expected %q", output, expected)
349         }
350 }