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