package terminal import ( "testing" "github.com/gdamore/tcell/v2" ) func TestEncodePrintableCharacters(t *testing.T) { tests := []struct { name string rune rune mods tcell.ModMask want string }{ {"a letter", 'a', tcell.ModNone, "a"}, {"a space", ' ', tcell.ModNone, " "}, {"an accented letter is UTF-8", 'é', tcell.ModNone, "é"}, {"Alt prefixes an escape", 'b', tcell.ModAlt, "\x1bb"}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { got := Encode(tcell.NewEventKey(tcell.KeyRune, tc.rune, tc.mods), false) if string(got) != tc.want { t.Errorf("Encode() = %q, want %q", got, tc.want) } }) } } func TestEncodeNamedKeys(t *testing.T) { tests := []struct { key tcell.Key want string }{ {tcell.KeyEnter, "\r"}, {tcell.KeyTab, "\t"}, {tcell.KeyEscape, "\x1b"}, {tcell.KeyBacktab, "\x1b[Z"}, {tcell.KeyDelete, "\x1b[3~"}, {tcell.KeyInsert, "\x1b[2~"}, {tcell.KeyPgUp, "\x1b[5~"}, {tcell.KeyPgDn, "\x1b[6~"}, {tcell.KeyF1, "\x1bOP"}, {tcell.KeyF5, "\x1b[15~"}, {tcell.KeyF12, "\x1b[24~"}, } for _, tc := range tests { got := Encode(tcell.NewEventKey(tc.key, 0, tcell.ModNone), false) if string(got) != tc.want { t.Errorf("Encode(%v) = %q, want %q", tc.key, got, tc.want) } } } func TestEncodeCursorKeysFollowTheModeTheProgramAskedFor(t *testing.T) { // This is the most visible thing an emulator can get wrong: the arrow keys // inside vim or at a readline prompt. tests := []struct { key tcell.Key normal, appMod string }{ {tcell.KeyUp, "\x1b[A", "\x1bOA"}, {tcell.KeyDown, "\x1b[B", "\x1bOB"}, {tcell.KeyRight, "\x1b[C", "\x1bOC"}, {tcell.KeyLeft, "\x1b[D", "\x1bOD"}, {tcell.KeyHome, "\x1b[H", "\x1bOH"}, {tcell.KeyEnd, "\x1b[F", "\x1bOF"}, } for _, tc := range tests { if got := Encode(tcell.NewEventKey(tc.key, 0, tcell.ModNone), false); string(got) != tc.normal { t.Errorf("Encode(%v) = %q, want %q", tc.key, got, tc.normal) } if got := Encode(tcell.NewEventKey(tc.key, 0, tcell.ModNone), true); string(got) != tc.appMod { t.Errorf("Encode(%v) in application mode = %q, want %q", tc.key, got, tc.appMod) } } } func TestEncodeControlKeys(t *testing.T) { // tcell's value for a control key *is* the byte a terminal expects. tests := []struct { name string key tcell.Key want byte }{ {"Ctrl-A", tcell.KeyCtrlA, 0x01}, {"Ctrl-C interrupts", tcell.KeyCtrlC, 0x03}, {"Ctrl-D ends the input", tcell.KeyCtrlD, 0x04}, {"Ctrl-Z suspends", tcell.KeyCtrlZ, 0x1a}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { got := Encode(tcell.NewEventKey(tc.key, 0, tcell.ModCtrl), false) if len(got) != 1 || got[0] != tc.want { t.Errorf("Encode() = %q, want the single byte %#02x", got, tc.want) } }) } } func TestBackspaceSendsDelete(t *testing.T) { // tcell posts both 0x08 and 0x7f as KeyBackspace, so Ctrl-H and the // backspace key cannot be told apart here. DEL is what a modern terminal // sends for the key people actually press. for _, key := range []tcell.Key{tcell.KeyBackspace, tcell.KeyBackspace2} { if got := Encode(tcell.NewEventKey(key, 0, tcell.ModNone), false); string(got) != "\x7f" { t.Errorf("Encode(%v) = %q, want DEL", key, got) } } } func TestControlKeysUseTcellsOwnOffset(t *testing.T) { // A real terminal byte of 0x03 reaches tcell as KeyCtrlSpace+3. Encoding // from the raw value instead would send nothing at all for every Ctrl-key, // silently. if got := int(tcell.KeyCtrlSpace); got != 64 { t.Fatalf("tcell.KeyCtrlSpace = %d, want 64 — this test's premise has changed", got) } for control := byte(0); control < 32; control++ { key := tcell.KeyCtrlSpace + tcell.Key(control) if _, named := namedKeys[key]; named { continue } got := Encode(tcell.NewEventKey(key, 0, tcell.ModCtrl), false) if len(got) != 1 || got[0] != control { t.Errorf("Encode(%v) = %q, want the single byte %#02x", key, got, control) } } } func TestAltWithAControlKeyPrefixesAnEscape(t *testing.T) { got := Encode(tcell.NewEventKey(tcell.KeyCtrlC, 0, tcell.ModCtrl|tcell.ModAlt), false) if string(got) != "\x1b\x03" { t.Errorf("Encode() = %q, want an escape then the control byte", got) } } func TestAKeyWithNoTerminalMeaningEncodesToNothing(t *testing.T) { if got := Encode(tcell.NewEventKey(tcell.KeyF64, 0, tcell.ModNone), false); len(got) != 0 { t.Errorf("Encode() = %q, want nothing to send", got) } }