| package pty |
| |
| import ( |
| "os" |
| "testing" |
| ) |
| |
| func TestOpen(t *testing.T) { |
| t.Parallel() |
| |
| openClose(t) |
| } |
| |
| func TestName(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty := openClose(t) |
| |
| // 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.") |
| } |
| } |
| |
| // 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 := openClose(t) // Get the pty/tty pair. |
| |
| // Manually open the tty from the exiting name. |
| ttyFile, err := os.OpenFile(tty.Name(), os.O_RDWR, 0o600) |
| noError(t, err, "Failed to open tty file") |
| defer func() { _ = 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) // Write the text to the manually open tty. |
| noError(t, err, "Unexpected error from Write") // Make sure it didn't fail. |
| assert(t, len(text), n, "Unexpected count returned from Write") // Assert the number of bytes written. |
| |
| buffer := readN(t, pty, len(text), "Unexpected error from pty Read") |
| assertBytes(t, text, buffer, "Unexpected result result returned from pty Read") |
| } |
| |
| func TestGetsize(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty := openClose(t) |
| |
| prows, pcols, err := Getsize(pty) |
| noError(t, err, "Unexpected error from pty Getsize") |
| |
| trows, tcols, err := Getsize(tty) |
| noError(t, err, "Unexpected error from tty Getsize") |
| |
| assert(t, prows, trows, "rows from Getsize on pty and tty should match") |
| assert(t, pcols, tcols, "cols from Getsize on pty and tty should match") |
| } |
| |
| func TestGetsizeFull(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty := openClose(t) |
| |
| psize, err := GetsizeFull(pty) |
| noError(t, err, "Unexpected error from pty GetsizeFull") |
| |
| tsize, err := GetsizeFull(tty) |
| noError(t, err, "Unexpected error from tty GetsizeFull") |
| |
| assert(t, psize.X, tsize.X, "X from GetsizeFull on pty and tty should match") |
| assert(t, psize.Y, tsize.Y, "Y from GetsizeFull on pty and tty should match") |
| assert(t, psize.Rows, tsize.Rows, "rows from GetsizeFull on pty and tty should match") |
| assert(t, psize.Cols, tsize.Cols, "cols from GetsizeFull on pty and tty should match") |
| } |
| |
| func TestSetsize(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty := openClose(t) |
| |
| psize, err := GetsizeFull(pty) |
| noError(t, err, "Unexpected error from pty GetsizeFull") |
| |
| psize.X++ |
| psize.Y++ |
| psize.Rows++ |
| psize.Cols++ |
| |
| noError(t, Setsize(tty, psize), "Unexpected error from Setsize") |
| |
| tsize, err := GetsizeFull(tty) |
| noError(t, err, "Unexpected error from tty GetsizeFull") |
| |
| assert(t, psize.X, tsize.X, "Unexpected Getsize X result after Setsize") |
| assert(t, psize.Y, tsize.Y, "Unexpected Getsize Y result after Setsize") |
| assert(t, psize.Rows, tsize.Rows, "Unexpected Getsize Rows result after Setsize") |
| assert(t, psize.Cols, tsize.Cols, "Unexpected Getsize Cols result after Setsize") |
| } |
| |
| func TestReadWriteText(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty := openClose(t) |
| |
| // Write to tty, read from pty. |
| { |
| text := []byte("ping") |
| |
| n, err := tty.Write(text) |
| noError(t, err, "Unexpected error from tty Write") |
| assert(t, n, len(text), "Unexpected count returned from tty Write") |
| |
| buffer := readN(t, pty, len(text), "Unexpected error from pty Read") |
| assertBytes(t, text, buffer, "Unexpected result returned from pty Read") |
| } |
| |
| // 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) |
| noError(t, err, "Unexpected error from pty Write") |
| assert(t, n, len(text), "Unexpected count returned from pty Write") |
| |
| // Expect the raw text back when reading from tty. |
| buffer := readN(t, tty, len(text), "Unexpected error from tty Read") |
| assertBytes(t, text, buffer, "Unexpected result returned from tty Read") |
| |
| // Read the echo back from pty. Expect LF to be CRLF. |
| expect := []byte("pong\r\n") |
| buffer = readN(t, pty, len(expect), "Unexpected error from pty Read") |
| assertBytes(t, expect, buffer, "Unexpected result returned from pty Read") |
| } |
| } |
| |
| func TestReadWriteControls(t *testing.T) { |
| t.Parallel() |
| |
| pty, tty := openClose(t) |
| |
| // Write the start of a line to pty. |
| n, err := pty.WriteString("pind") // Intentional typo. |
| noError(t, err, "Unexpected error from Write initial text") // Make sure it didn't fail. |
| assert(t, 4, n, "Unexpected count returned from Write initial text") // Assert the number of bytes written. |
| |
| // Backspace that last char. |
| n, err = pty.WriteString("\b") // "Remove" the typo. |
| noError(t, err, "Unexpected error from Write backspace") // Make sure it didn't fail. |
| assert(t, 1, n, "Unexpected count returned from Write backspace") // Assert the number of bytes written. |
| |
| // Write the correct char and a LF. |
| n, err = pty.WriteString("g\n") // Fix the typo. |
| noError(t, err, "Unexpected error from Write fixed text") // Make sure it didn't fail. |
| assert(t, 2, n, "Unexpected count returned from Write fixed text") // Assert the number of bytes written. |
| |
| // Read the line. |
| buffer := readN(t, tty, 7, "Unexpected error from tty Read") |
| assertBytes(t, []byte("pind\bg\n"), buffer, "Unexpected result returned from tty Read") |
| |
| // Read the echo back from pty. |
| buffer = readN(t, pty, 9, "Unexpected error from pty Read") |
| assertBytes(t, []byte("pind^Hg\r\n"), buffer, "Unexpected result returned from pty Read") |
| } |