Files
patterm/internal/app/keymatch_test.go
2026-05-15 00:28:06 +01:00

83 lines
2.6 KiB
Go

package app
import "testing"
func TestMatchCtrlK(t *testing.T) {
cases := []struct {
name string
chunk string
offset int
wantMatch bool
wantAdvance int
}{
{"legacy lone byte", "\x0b", 0, true, 1},
{"legacy followed by text", "\x0bx", 0, true, 1},
{"kitty plain Ctrl-K", "\x1b[107;5u", 0, true, 8},
{"kitty with press event", "\x1b[107;5:1u", 0, true, 10},
{"kitty with key release", "\x1b[107;5:3u", 0, false, 0},
{"kitty with extra shift", "\x1b[107;6u", 0, false, 0},
{"kitty no modifier", "\x1b[107u", 0, false, 0},
{"kitty wrong key", "\x1b[108;5u", 0, false, 0},
{"kitty with associated text trailing group", "\x1b[107;5;107u", 0, true, 12},
{"modifyOtherKeys Ctrl-K", "\x1b[27;5;107~", 0, true, 11},
{"modifyOtherKeys wrong mods", "\x1b[27;6;107~", 0, false, 0},
{"unrelated CSI", "\x1b[A", 0, false, 0},
{"plain ascii", "k", 0, false, 0},
{"empty", "", 0, false, 0},
{"incomplete CSI", "\x1b[107;5", 0, false, 0},
{"offset past legacy", "x\x0b", 1, true, 1},
{"offset past kitty prefix", "x\x1b[107;5u", 1, true, 8},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got, adv := matchCtrlK([]byte(tc.chunk), tc.offset)
if got != tc.wantMatch || adv != tc.wantAdvance {
t.Fatalf("matchCtrlK(%q, %d) = (%v, %d); want (%v, %d)",
tc.chunk, tc.offset, got, adv, tc.wantMatch, tc.wantAdvance)
}
})
}
}
func TestParseSGRMouseWheel(t *testing.T) {
cases := []struct {
params string
want int
ok bool
}{
{"64;1;1", -3, true}, // wheel up
{"65;1;1", 3, true}, // wheel down
{"68;1;1", -3, true}, // shift+wheel up
{"69;1;1", 3, true}, // shift+wheel down
{"80;1;1", -3, true}, // ctrl+wheel up
{"81;1;1", 3, true}, // ctrl+wheel down
{"0;5;7", 0, false}, // left press
{"2;5;7", 0, false}, // right press
{"32;5;7", 0, false}, // drag
{"", 0, false}, // empty
{"abc;1;1", 0, false}, // garbage button
}
for _, c := range cases {
got, ok := parseSGRMouseWheel([]byte(c.params))
if ok != c.ok || got != c.want {
t.Errorf("parseSGRMouseWheel(%q) = (%d,%v), want (%d,%v)", c.params, got, ok, c.want, c.ok)
}
}
}
func TestMatchCtrlKConsecutive(t *testing.T) {
// Two kitty Ctrl-K sequences back to back, the chord case.
chunk := []byte("\x1b[107;5u\x1b[107;5u")
hit, adv := matchCtrlK(chunk, 0)
if !hit || adv != 8 {
t.Fatalf("first: hit=%v adv=%d", hit, adv)
}
hit2, adv2 := matchCtrlK(chunk, adv)
if !hit2 || adv2 != 8 {
t.Fatalf("second: hit=%v adv=%d", hit2, adv2)
}
if adv+adv2 != len(chunk) {
t.Fatalf("expected to cover the whole chunk, got %d/%d", adv+adv2, len(chunk))
}
}