terminal_test.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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. package terminal
  5. import (
  6. "io"
  7. "testing"
  8. )
  9. type MockTerminal struct {
  10. toSend []byte
  11. bytesPerRead int
  12. received []byte
  13. }
  14. func (c *MockTerminal) Read(data []byte) (n int, err error) {
  15. n = len(data)
  16. if n == 0 {
  17. return
  18. }
  19. if n > len(c.toSend) {
  20. n = len(c.toSend)
  21. }
  22. if n == 0 {
  23. return 0, io.EOF
  24. }
  25. if c.bytesPerRead > 0 && n > c.bytesPerRead {
  26. n = c.bytesPerRead
  27. }
  28. copy(data, c.toSend[:n])
  29. c.toSend = c.toSend[n:]
  30. return
  31. }
  32. func (c *MockTerminal) Write(data []byte) (n int, err error) {
  33. c.received = append(c.received, data...)
  34. return len(data), nil
  35. }
  36. func TestClose(t *testing.T) {
  37. c := &MockTerminal{}
  38. ss := NewTerminal(c, "> ")
  39. line, err := ss.ReadLine()
  40. if line != "" {
  41. t.Errorf("Expected empty line but got: %s", line)
  42. }
  43. if err != io.EOF {
  44. t.Errorf("Error should have been EOF but got: %s", err)
  45. }
  46. }
  47. var keyPressTests = []struct {
  48. in string
  49. line string
  50. err error
  51. throwAwayLines int
  52. }{
  53. {
  54. err: io.EOF,
  55. },
  56. {
  57. in: "\r",
  58. line: "",
  59. },
  60. {
  61. in: "foo\r",
  62. line: "foo",
  63. },
  64. {
  65. in: "a\x1b[Cb\r", // right
  66. line: "ab",
  67. },
  68. {
  69. in: "a\x1b[Db\r", // left
  70. line: "ba",
  71. },
  72. {
  73. in: "a\177b\r", // backspace
  74. line: "b",
  75. },
  76. {
  77. in: "\x1b[A\r", // up
  78. },
  79. {
  80. in: "\x1b[B\r", // down
  81. },
  82. {
  83. in: "line\x1b[A\x1b[B\r", // up then down
  84. line: "line",
  85. },
  86. {
  87. in: "line1\rline2\x1b[A\r", // recall previous line.
  88. line: "line1",
  89. throwAwayLines: 1,
  90. },
  91. {
  92. // recall two previous lines and append.
  93. in: "line1\rline2\rline3\x1b[A\x1b[Axxx\r",
  94. line: "line1xxx",
  95. throwAwayLines: 2,
  96. },
  97. {
  98. // Ctrl-A to move to beginning of line followed by ^K to kill
  99. // line.
  100. in: "a b \001\013\r",
  101. line: "",
  102. },
  103. {
  104. // Ctrl-A to move to beginning of line, Ctrl-E to move to end,
  105. // finally ^K to kill nothing.
  106. in: "a b \001\005\013\r",
  107. line: "a b ",
  108. },
  109. {
  110. in: "\027\r",
  111. line: "",
  112. },
  113. {
  114. in: "a\027\r",
  115. line: "",
  116. },
  117. {
  118. in: "a \027\r",
  119. line: "",
  120. },
  121. {
  122. in: "a b\027\r",
  123. line: "a ",
  124. },
  125. {
  126. in: "a b \027\r",
  127. line: "a ",
  128. },
  129. {
  130. in: "one two thr\x1b[D\027\r",
  131. line: "one two r",
  132. },
  133. {
  134. in: "\013\r",
  135. line: "",
  136. },
  137. {
  138. in: "a\013\r",
  139. line: "a",
  140. },
  141. {
  142. in: "ab\x1b[D\013\r",
  143. line: "a",
  144. },
  145. {
  146. in: "Ξεσκεπάζω\r",
  147. line: "Ξεσκεπάζω",
  148. },
  149. {
  150. in: "£\r\x1b[A\177\r", // non-ASCII char, enter, up, backspace.
  151. line: "",
  152. throwAwayLines: 1,
  153. },
  154. {
  155. in: "£\r££\x1b[A\x1b[B\177\r", // non-ASCII char, enter, 2x non-ASCII, up, down, backspace, enter.
  156. line: "£",
  157. throwAwayLines: 1,
  158. },
  159. }
  160. func TestKeyPresses(t *testing.T) {
  161. for i, test := range keyPressTests {
  162. for j := 1; j < len(test.in); j++ {
  163. c := &MockTerminal{
  164. toSend: []byte(test.in),
  165. bytesPerRead: j,
  166. }
  167. ss := NewTerminal(c, "> ")
  168. for k := 0; k < test.throwAwayLines; k++ {
  169. _, err := ss.ReadLine()
  170. if err != nil {
  171. t.Errorf("Throwaway line %d from test %d resulted in error: %s", k, i, err)
  172. }
  173. }
  174. line, err := ss.ReadLine()
  175. if line != test.line {
  176. t.Errorf("Line resulting from test %d (%d bytes per read) was '%s', expected '%s'", i, j, line, test.line)
  177. break
  178. }
  179. if err != test.err {
  180. t.Errorf("Error resulting from test %d (%d bytes per read) was '%v', expected '%v'", i, j, err, test.err)
  181. break
  182. }
  183. }
  184. }
  185. }
  186. func TestPasswordNotSaved(t *testing.T) {
  187. c := &MockTerminal{
  188. toSend: []byte("password\r\x1b[A\r"),
  189. bytesPerRead: 1,
  190. }
  191. ss := NewTerminal(c, "> ")
  192. pw, _ := ss.ReadPassword("> ")
  193. if pw != "password" {
  194. t.Fatalf("failed to read password, got %s", pw)
  195. }
  196. line, _ := ss.ReadLine()
  197. if len(line) > 0 {
  198. t.Fatalf("password was saved in history")
  199. }
  200. }