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  }