github.com/deis/deis@v1.13.5-0.20170519182049-1d9e59fbdbfc/Godeps/_workspace/src/golang.org/x/crypto/ssh/terminal/terminal_test.go (about) 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 "io" 9 "testing" 10 ) 11 12 type MockTerminal struct { 13 toSend []byte 14 bytesPerRead int 15 received []byte 16 } 17 18 func (c *MockTerminal) Read(data []byte) (n int, err error) { 19 n = len(data) 20 if n == 0 { 21 return 22 } 23 if n > len(c.toSend) { 24 n = len(c.toSend) 25 } 26 if n == 0 { 27 return 0, io.EOF 28 } 29 if c.bytesPerRead > 0 && n > c.bytesPerRead { 30 n = c.bytesPerRead 31 } 32 copy(data, c.toSend[:n]) 33 c.toSend = c.toSend[n:] 34 return 35 } 36 37 func (c *MockTerminal) Write(data []byte) (n int, err error) { 38 c.received = append(c.received, data...) 39 return len(data), nil 40 } 41 42 func TestClose(t *testing.T) { 43 c := &MockTerminal{} 44 ss := NewTerminal(c, "> ") 45 line, err := ss.ReadLine() 46 if line != "" { 47 t.Errorf("Expected empty line but got: %s", line) 48 } 49 if err != io.EOF { 50 t.Errorf("Error should have been EOF but got: %s", err) 51 } 52 } 53 54 var keyPressTests = []struct { 55 in string 56 line string 57 err error 58 throwAwayLines int 59 }{ 60 { 61 err: io.EOF, 62 }, 63 { 64 in: "\r", 65 line: "", 66 }, 67 { 68 in: "foo\r", 69 line: "foo", 70 }, 71 { 72 in: "a\x1b[Cb\r", // right 73 line: "ab", 74 }, 75 { 76 in: "a\x1b[Db\r", // left 77 line: "ba", 78 }, 79 { 80 in: "a\177b\r", // backspace 81 line: "b", 82 }, 83 { 84 in: "\x1b[A\r", // up 85 }, 86 { 87 in: "\x1b[B\r", // down 88 }, 89 { 90 in: "line\x1b[A\x1b[B\r", // up then down 91 line: "line", 92 }, 93 { 94 in: "line1\rline2\x1b[A\r", // recall previous line. 95 line: "line1", 96 throwAwayLines: 1, 97 }, 98 { 99 // recall two previous lines and append. 100 in: "line1\rline2\rline3\x1b[A\x1b[Axxx\r", 101 line: "line1xxx", 102 throwAwayLines: 2, 103 }, 104 { 105 // Ctrl-A to move to beginning of line followed by ^K to kill 106 // line. 107 in: "a b \001\013\r", 108 line: "", 109 }, 110 { 111 // Ctrl-A to move to beginning of line, Ctrl-E to move to end, 112 // finally ^K to kill nothing. 113 in: "a b \001\005\013\r", 114 line: "a b ", 115 }, 116 { 117 in: "\027\r", 118 line: "", 119 }, 120 { 121 in: "a\027\r", 122 line: "", 123 }, 124 { 125 in: "a \027\r", 126 line: "", 127 }, 128 { 129 in: "a b\027\r", 130 line: "a ", 131 }, 132 { 133 in: "a b \027\r", 134 line: "a ", 135 }, 136 { 137 in: "one two thr\x1b[D\027\r", 138 line: "one two r", 139 }, 140 { 141 in: "\013\r", 142 line: "", 143 }, 144 { 145 in: "a\013\r", 146 line: "a", 147 }, 148 { 149 in: "ab\x1b[D\013\r", 150 line: "a", 151 }, 152 { 153 in: "Ξεσκεπάζω\r", 154 line: "Ξεσκεπάζω", 155 }, 156 { 157 in: "£\r\x1b[A\177\r", // non-ASCII char, enter, up, backspace. 158 line: "", 159 throwAwayLines: 1, 160 }, 161 { 162 in: "£\r££\x1b[A\x1b[B\177\r", // non-ASCII char, enter, 2x non-ASCII, up, down, backspace, enter. 163 line: "£", 164 throwAwayLines: 1, 165 }, 166 { 167 // Ctrl-D at the end of the line should be ignored. 168 in: "a\004\r", 169 line: "a", 170 }, 171 { 172 // a, b, left, Ctrl-D should erase the b. 173 in: "ab\x1b[D\004\r", 174 line: "a", 175 }, 176 { 177 // a, b, c, d, left, left, ^U should erase to the beginning of 178 // the line. 179 in: "abcd\x1b[D\x1b[D\025\r", 180 line: "cd", 181 }, 182 { 183 // Bracketed paste mode: control sequences should be returned 184 // verbatim in paste mode. 185 in: "abc\x1b[200~de\177f\x1b[201~\177\r", 186 line: "abcde\177", 187 }, 188 { 189 // Enter in bracketed paste mode should still work. 190 in: "abc\x1b[200~d\refg\x1b[201~h\r", 191 line: "efgh", 192 throwAwayLines: 1, 193 }, 194 { 195 // Lines consisting entirely of pasted data should be indicated as such. 196 in: "\x1b[200~a\r", 197 line: "a", 198 err: ErrPasteIndicator, 199 }, 200 } 201 202 func TestKeyPresses(t *testing.T) { 203 for i, test := range keyPressTests { 204 for j := 1; j < len(test.in); j++ { 205 c := &MockTerminal{ 206 toSend: []byte(test.in), 207 bytesPerRead: j, 208 } 209 ss := NewTerminal(c, "> ") 210 for k := 0; k < test.throwAwayLines; k++ { 211 _, err := ss.ReadLine() 212 if err != nil { 213 t.Errorf("Throwaway line %d from test %d resulted in error: %s", k, i, err) 214 } 215 } 216 line, err := ss.ReadLine() 217 if line != test.line { 218 t.Errorf("Line resulting from test %d (%d bytes per read) was '%s', expected '%s'", i, j, line, test.line) 219 break 220 } 221 if err != test.err { 222 t.Errorf("Error resulting from test %d (%d bytes per read) was '%v', expected '%v'", i, j, err, test.err) 223 break 224 } 225 } 226 } 227 } 228 229 func TestPasswordNotSaved(t *testing.T) { 230 c := &MockTerminal{ 231 toSend: []byte("password\r\x1b[A\r"), 232 bytesPerRead: 1, 233 } 234 ss := NewTerminal(c, "> ") 235 pw, _ := ss.ReadPassword("> ") 236 if pw != "password" { 237 t.Fatalf("failed to read password, got %s", pw) 238 } 239 line, _ := ss.ReadLine() 240 if len(line) > 0 { 241 t.Fatalf("password was saved in history") 242 } 243 } 244 245 var setSizeTests = []struct { 246 width, height int 247 }{ 248 {40, 13}, 249 {80, 24}, 250 {132, 43}, 251 } 252 253 func TestTerminalSetSize(t *testing.T) { 254 for _, setSize := range setSizeTests { 255 c := &MockTerminal{ 256 toSend: []byte("password\r\x1b[A\r"), 257 bytesPerRead: 1, 258 } 259 ss := NewTerminal(c, "> ") 260 ss.SetSize(setSize.width, setSize.height) 261 pw, _ := ss.ReadPassword("Password: ") 262 if pw != "password" { 263 t.Fatalf("failed to read password, got %s", pw) 264 } 265 if string(c.received) != "Password: \r\n" { 266 t.Errorf("failed to set the temporary prompt expected %q, got %q", "Password: ", c.received) 267 } 268 } 269 }