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