From 93bdbff5ed7014d9ee3179ff4a5486d3251eadff Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 27 Oct 2026 11:53:46 +0100 Subject: [PATCH 1/3] remove redundant "else" in test-utils Signed-off-by: Sebastiaan van Stijn --- term_unix_test.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/term_unix_test.go b/term_unix_test.go index 01f30e0..5bfefde 100644 --- a/term_unix_test.go +++ b/term_unix_test.go @@ -15,12 +15,11 @@ func newTTYForTest(t *testing.T) *os.File { pty, tty, err := cpty.Open() if err != nil { t.Fatalf("error creating pty: %v", err) - } else { - t.Cleanup(func() { - _ = pty.Close() - _ = tty.Close() - }) } + t.Cleanup(func() { + _ = pty.Close() + _ = tty.Close() + }) return pty } @@ -30,9 +29,8 @@ func newTempFile(t *testing.T) *os.File { tmpFile, err := os.CreateTemp(t.TempDir(), "temp") if err != nil { t.Fatalf("error creating tempfile: %v", err) - } else { - t.Cleanup(func() { _ = tmpFile.Close() }) } + t.Cleanup(func() { _ = tmpFile.Close() }) return tmpFile } From 480be7e2d2aba5c6b8d99ec624c94bd7237d9523 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sat, 5 Nov 2022 16:50:59 +0100 Subject: [PATCH 2/3] switch to use blackbox testing Signed-off-by: Sebastiaan van Stijn --- ascii_test.go | 12 ++++--- proxy_test.go | 82 ++++++++++++++++++++++++----------------------- term_unix_test.go | 4 +-- 3 files changed, 51 insertions(+), 47 deletions(-) diff --git a/ascii_test.go b/ascii_test.go index 071fe72..592808d 100644 --- a/ascii_test.go +++ b/ascii_test.go @@ -1,12 +1,14 @@ -package term +package term_test import ( "bytes" "testing" + + "github.com/moby/term" ) func TestToBytes(t *testing.T) { - codes, err := ToBytes("ctrl-a,a") + codes, err := term.ToBytes("ctrl-a,a") if err != nil { t.Error(err) } @@ -15,12 +17,12 @@ func TestToBytes(t *testing.T) { t.Errorf("expected: %+v, got: %+v", expected, codes) } - _, err = ToBytes("shift-z") + _, err = term.ToBytes("shift-z") if err == nil { t.Error("expected and error") } - codes, err = ToBytes("ctrl-@,ctrl-[,~,ctrl-o") + codes, err = term.ToBytes("ctrl-@,ctrl-[,~,ctrl-o") if err != nil { t.Error(err) } @@ -29,7 +31,7 @@ func TestToBytes(t *testing.T) { t.Errorf("expected: %+v, got: %+v", expected, codes) } - codes, err = ToBytes("DEL,+") + codes, err = term.ToBytes("DEL,+") if err != nil { t.Error(err) } diff --git a/proxy_test.go b/proxy_test.go index 9adb91a..e0829b9 100644 --- a/proxy_test.go +++ b/proxy_test.go @@ -1,15 +1,17 @@ -package term +package term_test import ( "bytes" "testing" + + "github.com/moby/term" ) func TestEscapeProxyRead(t *testing.T) { t.Run("no escape keys, keys [a]", func(t *testing.T) { - escapeKeys, _ := ToBytes("") - keys, _ := ToBytes("a") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + escapeKeys, _ := term.ToBytes("") + keys, _ := term.ToBytes("a") + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) buf := make([]byte, len(keys)) nr, err := reader.Read(buf) @@ -25,9 +27,9 @@ func TestEscapeProxyRead(t *testing.T) { }) t.Run("no escape keys, keys [a,b,c]", func(t *testing.T) { - escapeKeys, _ := ToBytes("") - keys, _ := ToBytes("a,b,c") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + escapeKeys, _ := term.ToBytes("") + keys, _ := term.ToBytes("a,b,c") + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) buf := make([]byte, len(keys)) nr, err := reader.Read(buf) @@ -43,9 +45,9 @@ func TestEscapeProxyRead(t *testing.T) { }) t.Run("no escape keys, no keys", func(t *testing.T) { - escapeKeys, _ := ToBytes("") - keys, _ := ToBytes("") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + escapeKeys, _ := term.ToBytes("") + keys, _ := term.ToBytes("") + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) buf := make([]byte, len(keys)) nr, err := reader.Read(buf) @@ -64,9 +66,9 @@ func TestEscapeProxyRead(t *testing.T) { }) t.Run("DEL escape key, keys [a,b,c,+]", func(t *testing.T) { - escapeKeys, _ := ToBytes("DEL") - keys, _ := ToBytes("a,b,c,+") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + escapeKeys, _ := term.ToBytes("DEL") + keys, _ := term.ToBytes("a,b,c,+") + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) buf := make([]byte, len(keys)) nr, err := reader.Read(buf) @@ -82,9 +84,9 @@ func TestEscapeProxyRead(t *testing.T) { }) t.Run("DEL escape key, no keys", func(t *testing.T) { - escapeKeys, _ := ToBytes("DEL") - keys, _ := ToBytes("") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + escapeKeys, _ := term.ToBytes("DEL") + keys, _ := term.ToBytes("") + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) buf := make([]byte, len(keys)) nr, err := reader.Read(buf) @@ -103,9 +105,9 @@ func TestEscapeProxyRead(t *testing.T) { }) t.Run("ctrl-x,ctrl-@ escape key, keys [DEL]", func(t *testing.T) { - escapeKeys, _ := ToBytes("ctrl-x,ctrl-@") - keys, _ := ToBytes("DEL") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + escapeKeys, _ := term.ToBytes("ctrl-x,ctrl-@") + keys, _ := term.ToBytes("DEL") + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) buf := make([]byte, len(keys)) nr, err := reader.Read(buf) @@ -121,9 +123,9 @@ func TestEscapeProxyRead(t *testing.T) { }) t.Run("ctrl-c escape key, keys [ctrl-c]", func(t *testing.T) { - escapeKeys, _ := ToBytes("ctrl-c") - keys, _ := ToBytes("ctrl-c") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + escapeKeys, _ := term.ToBytes("ctrl-c") + keys, _ := term.ToBytes("ctrl-c") + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) buf := make([]byte, len(keys)) nr, err := reader.Read(buf) @@ -139,9 +141,9 @@ func TestEscapeProxyRead(t *testing.T) { }) t.Run("ctrl-c,ctrl-z escape key, keys [ctrl-c],[ctrl-z]", func(t *testing.T) { - escapeKeys, _ := ToBytes("ctrl-c,ctrl-z") - keys, _ := ToBytes("ctrl-c,ctrl-z") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + escapeKeys, _ := term.ToBytes("ctrl-c,ctrl-z") + keys, _ := term.ToBytes("ctrl-c,ctrl-z") + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) buf := make([]byte, 1) nr, err := reader.Read(buf) @@ -168,9 +170,9 @@ func TestEscapeProxyRead(t *testing.T) { }) t.Run("ctrl-c,ctrl-z escape key, keys [ctrl-c,ctrl-z]", func(t *testing.T) { - escapeKeys, _ := ToBytes("ctrl-c,ctrl-z") - keys, _ := ToBytes("ctrl-c,ctrl-z") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + escapeKeys, _ := term.ToBytes("ctrl-c,ctrl-z") + keys, _ := term.ToBytes("ctrl-c,ctrl-z") + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) buf := make([]byte, 2) nr, err := reader.Read(buf) @@ -186,9 +188,9 @@ func TestEscapeProxyRead(t *testing.T) { }) t.Run("ctrl-c,ctrl-z escape key, keys [ctrl-c],[DEL,+]", func(t *testing.T) { - escapeKeys, _ := ToBytes("ctrl-c,ctrl-z") - keys, _ := ToBytes("ctrl-c,DEL,+") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + escapeKeys, _ := term.ToBytes("ctrl-c,ctrl-z") + keys, _ := term.ToBytes("ctrl-c,DEL,+") + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) buf := make([]byte, 1) nr, err := reader.Read(buf) @@ -216,9 +218,9 @@ func TestEscapeProxyRead(t *testing.T) { }) t.Run("ctrl-c,ctrl-z escape key, keys [ctrl-c],[DEL]", func(t *testing.T) { - escapeKeys, _ := ToBytes("ctrl-c,ctrl-z") - keys, _ := ToBytes("ctrl-c,DEL") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + escapeKeys, _ := term.ToBytes("ctrl-c,ctrl-z") + keys, _ := term.ToBytes("ctrl-c,DEL") + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) buf := make([]byte, 1) nr, err := reader.Read(buf) @@ -246,9 +248,9 @@ func TestEscapeProxyRead(t *testing.T) { }) t.Run("a,b,c,d escape key, keys [a,b],[c,d]", func(t *testing.T) { - escapeKeys, _ := ToBytes("a,b,c,d") - keys, _ := ToBytes("a,b,c,d") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + escapeKeys, _ := term.ToBytes("a,b,c,d") + keys, _ := term.ToBytes("a,b,c,d") + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) buf := make([]byte, 2) nr, err := reader.Read(buf) @@ -276,9 +278,9 @@ func TestEscapeProxyRead(t *testing.T) { }) t.Run("ctrl-p,ctrl-q escape key, keys [ctrl-p],[a],[ctrl-p,ctrl-q]", func(t *testing.T) { - escapeKeys, _ := ToBytes("ctrl-p,ctrl-q") - keys, _ := ToBytes("ctrl-p,a,ctrl-p,ctrl-q") - reader := NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + escapeKeys, _ := term.ToBytes("ctrl-p,ctrl-q") + keys, _ := term.ToBytes("ctrl-p,a,ctrl-p,ctrl-q") + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) buf := make([]byte, 1) nr, err := reader.Read(buf) diff --git a/term_unix_test.go b/term_unix_test.go index 5bfefde..3b17812 100644 --- a/term_unix_test.go +++ b/term_unix_test.go @@ -44,7 +44,7 @@ func TestGetWinsize(t *testing.T) { t.Fatal("winSize is nil") } - newSize := Winsize{Width: 200, Height: 200, x: winSize.x, y: winSize.y} + newSize := Winsize{Width: 200, Height: 200} err = SetWinsize(tty.Fd(), &newSize) if err != nil { t.Fatal(err) @@ -67,7 +67,7 @@ func TestSetWinsize(t *testing.T) { if winSize == nil { t.Fatal("winSize is nil") } - newSize := Winsize{Width: 200, Height: 200, x: winSize.x, y: winSize.y} + newSize := Winsize{Width: 200, Height: 200} err = SetWinsize(tty.Fd(), &newSize) if err != nil { t.Fatal(err) From b41d1eeec37bfa613e7233d71af13129a8b730e5 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 27 Oct 2026 14:56:04 +0100 Subject: [PATCH 3/3] rewrite TestEscapeProxyRead to a table-test Signed-off-by: Sebastiaan van Stijn --- proxy_test.go | 474 +++++++++++++++++--------------------------------- 1 file changed, 158 insertions(+), 316 deletions(-) diff --git a/proxy_test.go b/proxy_test.go index e0829b9..8793855 100644 --- a/proxy_test.go +++ b/proxy_test.go @@ -2,326 +2,168 @@ package term_test import ( "bytes" + "errors" + "io" "testing" "github.com/moby/term" ) func TestEscapeProxyRead(t *testing.T) { - t.Run("no escape keys, keys [a]", func(t *testing.T) { - escapeKeys, _ := term.ToBytes("") - keys, _ := term.ToBytes("a") - reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - - buf := make([]byte, len(keys)) - nr, err := reader.Read(buf) - if err != nil { - t.Error(err) - } - if expected := len(keys); nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - }) - - t.Run("no escape keys, keys [a,b,c]", func(t *testing.T) { - escapeKeys, _ := term.ToBytes("") - keys, _ := term.ToBytes("a,b,c") - reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - - buf := make([]byte, len(keys)) - nr, err := reader.Read(buf) - if err != nil { - t.Error(err) - } - if expected := len(keys); nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - }) - - t.Run("no escape keys, no keys", func(t *testing.T) { - escapeKeys, _ := term.ToBytes("") - keys, _ := term.ToBytes("") - reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - - buf := make([]byte, len(keys)) - nr, err := reader.Read(buf) - if err == nil { - t.Error("expected an error when there are no keys are to read") - } - if expected := 0; len(keys) != expected { - t.Errorf("expected: %d, got: %d", expected, len(keys)) - } - if expected := len(keys); nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if expected := len(keys); len(buf) != expected { - t.Errorf("expected: %d, got: %d", expected, len(buf)) - } - }) - - t.Run("DEL escape key, keys [a,b,c,+]", func(t *testing.T) { - escapeKeys, _ := term.ToBytes("DEL") - keys, _ := term.ToBytes("a,b,c,+") - reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - - buf := make([]byte, len(keys)) - nr, err := reader.Read(buf) - if err != nil { - t.Error(err) - } - if expected := len(keys); nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - }) - - t.Run("DEL escape key, no keys", func(t *testing.T) { - escapeKeys, _ := term.ToBytes("DEL") - keys, _ := term.ToBytes("") - reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - - buf := make([]byte, len(keys)) - nr, err := reader.Read(buf) - if err == nil { - t.Error("expected an error when there are no keys are to read") - } - if expected := 0; len(keys) != expected { - t.Errorf("expected: %d, got: %d", expected, len(keys)) - } - if expected := len(keys); nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if expected := len(keys); len(buf) != expected { - t.Errorf("expected: %d, got: %d", expected, len(buf)) - } - }) - - t.Run("ctrl-x,ctrl-@ escape key, keys [DEL]", func(t *testing.T) { - escapeKeys, _ := term.ToBytes("ctrl-x,ctrl-@") - keys, _ := term.ToBytes("DEL") - reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - - buf := make([]byte, len(keys)) - nr, err := reader.Read(buf) - if err != nil { - t.Error(err) - } - if expected := 1; nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - }) - - t.Run("ctrl-c escape key, keys [ctrl-c]", func(t *testing.T) { - escapeKeys, _ := term.ToBytes("ctrl-c") - keys, _ := term.ToBytes("ctrl-c") - reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - - buf := make([]byte, len(keys)) - nr, err := reader.Read(buf) - if expected := "read escape sequence"; err == nil || err.Error() != expected { - t.Errorf("expected: %v, got: %v", expected, err) - } - if expected := 0; nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - }) - - t.Run("ctrl-c,ctrl-z escape key, keys [ctrl-c],[ctrl-z]", func(t *testing.T) { - escapeKeys, _ := term.ToBytes("ctrl-c,ctrl-z") - keys, _ := term.ToBytes("ctrl-c,ctrl-z") - reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - - buf := make([]byte, 1) - nr, err := reader.Read(buf) - if err != nil { - t.Error(err) - } - if expected := 0; nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys[0:1]) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - - nr, err = reader.Read(buf) - if expected := "read escape sequence"; err == nil || err.Error() != expected { - t.Errorf("expected: %v, got: %v", expected, err) - } - if expected := 0; nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys[1:]) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - }) - - t.Run("ctrl-c,ctrl-z escape key, keys [ctrl-c,ctrl-z]", func(t *testing.T) { - escapeKeys, _ := term.ToBytes("ctrl-c,ctrl-z") - keys, _ := term.ToBytes("ctrl-c,ctrl-z") - reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - - buf := make([]byte, 2) - nr, err := reader.Read(buf) - if expected := "read escape sequence"; err == nil || err.Error() != expected { - t.Errorf("expected: %v, got: %v", expected, err) - } - if expected := 0; nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - }) - - t.Run("ctrl-c,ctrl-z escape key, keys [ctrl-c],[DEL,+]", func(t *testing.T) { - escapeKeys, _ := term.ToBytes("ctrl-c,ctrl-z") - keys, _ := term.ToBytes("ctrl-c,DEL,+") - reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - - buf := make([]byte, 1) - nr, err := reader.Read(buf) - if err != nil { - t.Error(err) - } - if expected := 0; nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys[0:1]) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - - buf = make([]byte, len(keys)) - nr, err = reader.Read(buf) - if err != nil { - t.Error(err) - } - if expected := len(keys); nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - }) - - t.Run("ctrl-c,ctrl-z escape key, keys [ctrl-c],[DEL]", func(t *testing.T) { - escapeKeys, _ := term.ToBytes("ctrl-c,ctrl-z") - keys, _ := term.ToBytes("ctrl-c,DEL") - reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - - buf := make([]byte, 1) - nr, err := reader.Read(buf) - if err != nil { - t.Error(err) - } - if expected := 0; nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys[0:1]) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - - buf = make([]byte, len(keys)) - nr, err = reader.Read(buf) - if err != nil { - t.Error(err) - } - if expected := len(keys); nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - }) - - t.Run("a,b,c,d escape key, keys [a,b],[c,d]", func(t *testing.T) { - escapeKeys, _ := term.ToBytes("a,b,c,d") - keys, _ := term.ToBytes("a,b,c,d") - reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - - buf := make([]byte, 2) - nr, err := reader.Read(buf) - if err != nil { - t.Error(err) - } - if expected := 0; nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys[0:2]) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - - buf = make([]byte, 2) - nr, err = reader.Read(buf) - if expected := "read escape sequence"; err == nil || err.Error() != expected { - t.Errorf("expected: %v, got: %v", expected, err) - } - if expected := 0; nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys[2:4]) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - }) - - t.Run("ctrl-p,ctrl-q escape key, keys [ctrl-p],[a],[ctrl-p,ctrl-q]", func(t *testing.T) { - escapeKeys, _ := term.ToBytes("ctrl-p,ctrl-q") - keys, _ := term.ToBytes("ctrl-p,a,ctrl-p,ctrl-q") - reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) - - buf := make([]byte, 1) - nr, err := reader.Read(buf) - if err != nil { - t.Error(err) - } - if expected := 0; nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - - buf = make([]byte, 1) - nr, err = reader.Read(buf) - if err != nil { - t.Error(err) - } - if expected := 1; nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys[:1]) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - - buf = make([]byte, 2) - nr, err = reader.Read(buf) - if err != nil { - t.Error(err) - } - if expected := 1; nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - if !bytes.Equal(buf, keys[1:3]) { - t.Errorf("expected: %+v, got: %+v", keys, buf) - } - - buf = make([]byte, 2) - nr, err = reader.Read(buf) - if expected := "read escape sequence"; err == nil || err.Error() != expected { - t.Errorf("expected: %v, got: %v", expected, err) - } - if expected := 0; nr != expected { - t.Errorf("expected: %d, got: %d", expected, nr) - } - }) + type readStep struct { + size int + n int + expErr error + buf []byte + } + + tests := []struct { + name string + escapeKeys string + keys string + reads []readStep + }{ + { + name: "no escape keys, single key", + keys: "a", + reads: []readStep{ + {size: 1, n: 1, buf: []byte("a")}, + }, + }, + { + name: "no escape keys, multiple keys", + keys: "a,b,c", + reads: []readStep{ + {size: 3, n: 3, buf: []byte("abc")}, + }, + }, + { + name: "no escape keys, no input", + reads: []readStep{ + {size: 0, n: 0, expErr: io.EOF}, + }, + }, + { + name: "DEL escape key, unmatched input", + escapeKeys: "DEL", + keys: "a,b,c,+", + reads: []readStep{ + {size: 4, n: 4, buf: []byte("abc+")}, + }, + }, + { + name: "DEL escape key, no input", + escapeKeys: "DEL", + reads: []readStep{ + {size: 0, n: 0, expErr: io.EOF}, + }, + }, + { + name: "ctrl-x,ctrl-@ escape sequence, unmatched DEL", + escapeKeys: "ctrl-x,ctrl-@", + keys: "DEL", + reads: []readStep{ + {size: 1, n: 1, buf: []byte{'\x7f'}}, + }, + }, + { + name: "ctrl-c escape key, complete match", + escapeKeys: "ctrl-c", + keys: "ctrl-c", + reads: []readStep{ + {size: 1, n: 0, expErr: term.EscapeError{}, buf: []byte{'\x03'}}, + }, + }, + { + name: "ctrl-c,ctrl-z escape sequence, match across reads", + escapeKeys: "ctrl-c,ctrl-z", + keys: "ctrl-c,ctrl-z", + reads: []readStep{ + {size: 1, n: 0, buf: []byte{'\x03'}}, + {size: 1, n: 0, expErr: term.EscapeError{}, buf: []byte{'\x1a'}}, + }, + }, + { + name: "ctrl-c,ctrl-z escape sequence, match in one read", + escapeKeys: "ctrl-c,ctrl-z", + keys: "ctrl-c,ctrl-z", + reads: []readStep{ + {size: 2, n: 0, expErr: term.EscapeError{}, buf: []byte{'\x03', '\x1a'}}, + }, + }, + { + name: "ctrl-c,ctrl-z escape sequence, partial match followed by DEL and plus", + escapeKeys: "ctrl-c,ctrl-z", + keys: "ctrl-c,DEL,+", + reads: []readStep{ + {size: 1, n: 0, buf: []byte{'\x03'}}, + {size: 3, n: 3, buf: []byte{'\x03', '\x7f', '+'}}, + }, + }, + { + name: "ctrl-c,ctrl-z escape sequence, partial match followed by DEL", + escapeKeys: "ctrl-c,ctrl-z", + keys: "ctrl-c,DEL", + reads: []readStep{ + {size: 1, n: 0, buf: []byte{'\x03'}}, + {size: 2, n: 2, buf: []byte{'\x03', '\x7f'}}, + }, + }, + { + name: "four-key escape sequence, match across reads", + escapeKeys: "a,b,c,d", + keys: "a,b,c,d", + reads: []readStep{ + {size: 2, n: 0, buf: []byte("ab")}, + {size: 2, n: 0, expErr: term.EscapeError{}, buf: []byte("cd")}, + }, + }, + { + name: "ctrl-p,ctrl-q escape sequence, match after mismatch", + escapeKeys: "ctrl-p,ctrl-q", + keys: "ctrl-p,a,ctrl-p,ctrl-q", + reads: []readStep{ + {size: 1, n: 0}, + {size: 1, n: 1, buf: []byte{'\x10'}}, + {size: 2, n: 1, buf: []byte{'a', '\x10'}}, + {size: 2, n: 0, expErr: term.EscapeError{}}, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var escapeKeys []byte + var err error + if tc.escapeKeys != "" { + escapeKeys, err = term.ToBytes(tc.escapeKeys) + if err != nil { + t.Fatalf("parse escape keys: %v", err) + } + } + var keys []byte + if tc.keys != "" { + keys, err = term.ToBytes(tc.keys) + if err != nil { + t.Fatalf("parse input keys: %v", err) + } + } + + reader := term.NewEscapeProxy(bytes.NewReader(keys), escapeKeys) + for i, step := range tc.reads { + buf := make([]byte, step.size) + n, err := reader.Read(buf) + if !errors.Is(err, step.expErr) { + t.Errorf("read %d: expected error %v, got %v", i+1, step.expErr, err) + } + if n != step.n { + t.Errorf("read %d: expected %d bytes, got %d", i+1, step.n, n) + } + // Compare the entire buffer, including when Read returns n == 0. + if step.buf != nil && !bytes.Equal(buf, step.buf) { + t.Errorf("read %d: expected buffer %v, got %v", i+1, step.buf, buf) + } + } + }) + } }