| package pty |
| |
| import ( |
| "bytes" |
| "io" |
| "os" |
| "testing" |
| ) |
| |
| // Will fill p from reader r |
| func readBytes(r io.Reader, p []byte) error { |
| bytesRead := 0 |
| for bytesRead < len(p) { |
| n, err := r.Read(p[bytesRead:]) |
| if err != nil { |
| return err |
| } |
| bytesRead = bytesRead + n |
| } |
| return nil |
| } |
| |
| func TestOpen(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty, err := Open() |
| if err != nil { |
| t.Errorf("Unexpected error from Open: %s", err) |
| } |
| |
| err = tty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from tty Close: %s", err) |
| } |
| |
| err = pty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from pty Close: %s", err) |
| } |
| } |
| |
| func TestName(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty, err := Open() |
| if err != nil { |
| t.Errorf("Unexpected error from Open: %s", err) |
| } |
| |
| // Check name isn't empty. There's variation on what exactly the OS calls these files. |
| if pty.Name() == "" { |
| t.Error("pty name was empty") |
| } |
| if tty.Name() == "" { |
| t.Error("tty name was empty") |
| } |
| |
| err = tty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from tty Close: %s", err) |
| } |
| |
| err = pty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from pty Close: %s", err) |
| } |
| } |
| |
| // TestOpenByName ensures that the name associated with the tty is valid |
| // and can be opened and used if passed by file name (rather than passing |
| // the existing open file descriptor). |
| func TestOpenByName(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty, err := Open() |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer pty.Close() |
| defer tty.Close() |
| |
| ttyFile, err := os.OpenFile(tty.Name(), os.O_RDWR, 0600) |
| if err != nil { |
| t.Fatalf("Failed to open tty file: %v", err) |
| } |
| defer ttyFile.Close() |
| |
| // Ensure we can write to the newly opened tty file and read on the pty. |
| text := []byte("ping") |
| n, err := ttyFile.Write(text) |
| if err != nil { |
| t.Errorf("Unexpected error from Write: %s", err) |
| } |
| if n != len(text) { |
| t.Errorf("Unexpected count returned from Write, got %d expected %d", n, len(text)) |
| } |
| |
| buffer := make([]byte, len(text)) |
| if err := readBytes(pty, buffer); err != nil { |
| t.Errorf("Unexpected error from readBytes: %s", err) |
| } |
| if !bytes.Equal(text, buffer) { |
| t.Errorf("Unexpected result returned from Read, got %v expected %v", buffer, text) |
| } |
| } |
| |
| func TestGetsize(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty, err := Open() |
| if err != nil { |
| t.Errorf("Unexpected error from Open: %s", err) |
| } |
| |
| prows, pcols, err := Getsize(pty) |
| if err != nil { |
| t.Errorf("Unexpected error from Getsize: %s", err) |
| } |
| |
| trows, tcols, err := Getsize(tty) |
| if err != nil { |
| t.Errorf("Unexpected error from Getsize: %s", err) |
| } |
| |
| if prows != trows { |
| t.Errorf("pty rows != tty rows: %d != %d", prows, trows) |
| } |
| if prows != trows { |
| t.Errorf("pty cols != tty cols: %d != %d", pcols, tcols) |
| } |
| |
| err = tty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from tty Close: %s", err) |
| } |
| |
| err = pty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from pty Close: %s", err) |
| } |
| } |
| |
| func TestGetsizefull(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty, err := Open() |
| if err != nil { |
| t.Errorf("Unexpected error from Open: %s", err) |
| } |
| |
| psize, err := GetsizeFull(pty) |
| if err != nil { |
| t.Errorf("Unexpected error from GetsizeFull: %s", err) |
| } |
| |
| tsize, err := GetsizeFull(tty) |
| if err != nil { |
| t.Errorf("Unexpected error from GetsizeFull: %s", err) |
| } |
| |
| if psize.X != tsize.X { |
| t.Errorf("pty x != tty x: %d != %d", psize.X, tsize.X) |
| } |
| if psize.Y != tsize.Y { |
| t.Errorf("pty y != tty y: %d != %d", psize.Y, tsize.Y) |
| } |
| if psize.Rows != tsize.Rows { |
| t.Errorf("pty rows != tty rows: %d != %d", psize.Rows, tsize.Rows) |
| } |
| if psize.Cols != tsize.Cols { |
| t.Errorf("pty cols != tty cols: %d != %d", psize.Cols, tsize.Cols) |
| } |
| |
| err = tty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from tty Close: %s", err) |
| } |
| |
| err = pty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from pty Close: %s", err) |
| } |
| } |
| |
| func TestSetsize(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty, err := Open() |
| if err != nil { |
| t.Errorf("Unexpected error from Open: %s", err) |
| } |
| |
| psize, err := GetsizeFull(pty) |
| if err != nil { |
| t.Errorf("Unexpected error from GetsizeFull: %s", err) |
| } |
| |
| psize.X = psize.X + 1 |
| psize.Y = psize.Y + 1 |
| psize.Rows = psize.Rows + 1 |
| psize.Cols = psize.Cols + 1 |
| |
| err = Setsize(tty, psize) |
| if err != nil { |
| t.Errorf("Unexpected error from Setsize: %s", err) |
| } |
| |
| tsize, err := GetsizeFull(tty) |
| if err != nil { |
| t.Errorf("Unexpected error from GetsizeFull: %s", err) |
| } |
| |
| if psize.X != tsize.X { |
| t.Errorf("pty x != tty x: %d != %d", psize.X, tsize.X) |
| } |
| if psize.Y != tsize.Y { |
| t.Errorf("pty y != tty y: %d != %d", psize.Y, tsize.Y) |
| } |
| if psize.Rows != tsize.Rows { |
| t.Errorf("pty rows != tty rows: %d != %d", psize.Rows, tsize.Rows) |
| } |
| if psize.Cols != tsize.Cols { |
| t.Errorf("pty cols != tty cols: %d != %d", psize.Cols, tsize.Cols) |
| } |
| |
| err = tty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from tty Close: %s", err) |
| } |
| |
| err = pty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from pty Close: %s", err) |
| } |
| } |
| |
| func TestReadWriteText(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty, err := Open() |
| if err != nil { |
| t.Errorf("Unexpected error from Open: %s", err) |
| } |
| |
| // Write to tty, read from pty |
| text := []byte("ping") |
| n, err := tty.Write(text) |
| if err != nil { |
| t.Errorf("Unexpected error from Write: %s", err) |
| } |
| if n != len(text) { |
| t.Errorf("Unexpected count returned from Write, got %d expected %d", n, len(text)) |
| } |
| |
| buffer := make([]byte, 4) |
| err = readBytes(pty, buffer) |
| if err != nil { |
| t.Errorf("Unexpected error from readBytes: %s", err) |
| } |
| if !bytes.Equal(text, buffer) { |
| t.Errorf("Unexpected result returned from Read, got %v expected %v", buffer, text) |
| } |
| |
| // Write to pty, read from tty. |
| // We need to send a \n otherwise this will block in the terminal driver. |
| text = []byte("pong\n") |
| n, err = pty.Write(text) |
| if err != nil { |
| t.Errorf("Unexpected error from Write: %s", err) |
| } |
| if n != len(text) { |
| t.Errorf("Unexpected count returned from Write, got %d expected %d", n, len(text)) |
| } |
| |
| buffer = make([]byte, 5) |
| err = readBytes(tty, buffer) |
| if err != nil { |
| t.Errorf("Unexpected error from readBytes: %s", err) |
| } |
| expect := []byte("pong\n") |
| if !bytes.Equal(expect, buffer) { |
| t.Errorf("Unexpected result returned from Read, got %v expected %v", buffer, expect) |
| } |
| |
| // Read the echo back from pty |
| buffer = make([]byte, 5) |
| err = readBytes(pty, buffer) |
| if err != nil { |
| t.Errorf("Unexpected error from readBytes: %s", err) |
| } |
| expect = []byte("pong\r") |
| if !bytes.Equal(expect, buffer) { |
| t.Errorf("Unexpected result returned from Read, got %v expected %v", buffer, expect) |
| } |
| |
| err = tty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from tty Close: %s", err) |
| } |
| |
| err = pty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from pty Close: %s", err) |
| } |
| } |
| |
| func TestReadWriteControls(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty, err := Open() |
| if err != nil { |
| t.Errorf("Unexpected error from Open: %s", err) |
| } |
| |
| // Write the start of a line to pty |
| text := []byte("pind") |
| n, err := pty.Write(text) |
| if err != nil { |
| t.Errorf("Unexpected error from Write: %s", err) |
| } |
| if n != len(text) { |
| t.Errorf("Unexpected count returned from Write, got %d expected %d", n, len(text)) |
| } |
| |
| // Backspace that last char |
| n, err = pty.Write([]byte("\b")) |
| if err != nil { |
| t.Errorf("Unexpected error from Write: %s", err) |
| } |
| if n != 1 { |
| t.Errorf("Unexpected count returned from Write, got %d expected %d", n, 1) |
| } |
| |
| // Write the correct char and a CR |
| n, err = pty.Write([]byte("g\n")) |
| if err != nil { |
| t.Errorf("Unexpected error from Write: %s", err) |
| } |
| if n != 2 { |
| t.Errorf("Unexpected count returned from Write, got %d expected %d", n, 2) |
| } |
| |
| // Read the line |
| buffer := make([]byte, 7) |
| err = readBytes(tty, buffer) |
| if err != nil { |
| t.Errorf("Unexpected error from readBytes: %s", err) |
| } |
| expect := []byte("pind\bg\n") |
| if !bytes.Equal(expect, buffer) { |
| t.Errorf("Unexpected result returned from Read, got %v expected %v", buffer, expect) |
| } |
| |
| // Read the echo back from pty |
| buffer = make([]byte, 7) |
| err = readBytes(pty, buffer) |
| if err != nil { |
| t.Errorf("Unexpected error from readBytes: %s", err) |
| } |
| expect = []byte("pind^Hg") |
| if !bytes.Equal(expect, buffer) { |
| t.Errorf("Unexpected result returned from Read, got %v expected %v", buffer, expect) |
| } |
| |
| err = tty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from tty Close: %s", err) |
| } |
| |
| err = pty.Close() |
| if err != nil { |
| t.Errorf("Unexpected error from pty Close: %s", err) |
| } |
| } |