1package input
2
3import (
4 "testing"
5
6 "github.com/bnema/dumber/internal/domain/vimkeys"
7 "github.com/bnema/puregotk/v4/gdk"
8)
9
10func TestKeyvalToVimKey(t *testing.T) {
11 tests := []struct {
12 name string
13 keyval uint
14 state gdk.ModifierType
15 want vimkeys.Key
16 wantOk bool
17 }{
18 {
19 name: "braceright with shift encodes glyph without shift mod",
20 keyval: uint(gdk.KEY_braceright),
21 state: gdk.ShiftMaskValue,
22 want: vimkeys.Key{Sym: "}"},
23 wantOk: true,
24 },
25 {
26 name: "uppercase J with shift keeps letter and shift",
27 keyval: uint(gdk.KEY_J),
28 state: gdk.ShiftMaskValue,
29 want: vimkeys.Key{Sym: "j", Mods: vimkeys.ModShift},
30 wantOk: true,
31 },
32 {
33 name: "lowercase j without mods",
34 keyval: uint(gdk.KEY_j),
35 state: gdk.NoModifierMaskValue,
36 want: vimkeys.Key{Sym: "j"},
37 wantOk: true,
38 },
39 {
40 name: "named Escape keeps ctrl modifier",
41 keyval: uint(gdk.KEY_Escape),
42 state: gdk.ControlMaskValue,
43 want: vimkeys.Key{Sym: "Esc", Mods: vimkeys.ModCtrl},
44 wantOk: true,
45 },
46 {
47 name: "named Return keeps shift modifier",
48 keyval: uint(gdk.KEY_Return),
49 state: gdk.ShiftMaskValue,
50 want: vimkeys.Key{Sym: "CR", Mods: vimkeys.ModShift},
51 wantOk: true,
52 },
53 {
54 name: "named KP_Enter maps to CR",
55 keyval: uint(gdk.KEY_KP_Enter),
56 state: gdk.NoModifierMaskValue,
57 want: vimkeys.Key{Sym: "CR"},
58 wantOk: true,
59 },
60 {
61 name: "named Space keeps alt modifier",
62 keyval: uint(gdk.KEY_space),
63 state: gdk.AltMaskValue,
64 want: vimkeys.Key{Sym: "Space", Mods: vimkeys.ModAlt},
65 wantOk: true,
66 },
67 {
68 name: "named Tab maps to Tab",
69 keyval: uint(gdk.KEY_Tab),
70 state: gdk.NoModifierMaskValue,
71 want: vimkeys.Key{Sym: "Tab"},
72 wantOk: true,
73 },
74 {
75 name: "named ISO_Left_Tab maps to Tab",
76 keyval: uint(gdk.KEY_ISO_Left_Tab),
77 state: gdk.ShiftMaskValue,
78 want: vimkeys.Key{Sym: "Tab", Mods: vimkeys.ModShift},
79 wantOk: true,
80 },
81 {
82 name: "named BackSpace is BackSpace not BS",
83 keyval: uint(gdk.KEY_BackSpace),
84 state: gdk.NoModifierMaskValue,
85 want: vimkeys.Key{Sym: "BackSpace"},
86 wantOk: true,
87 },
88 {
89 name: "named Delete is Delete not Del",
90 keyval: uint(gdk.KEY_Delete),
91 state: gdk.ControlMaskValue,
92 want: vimkeys.Key{Sym: "Delete", Mods: vimkeys.ModCtrl},
93 wantOk: true,
94 },
95 {
96 name: "named Left keeps ctrl",
97 keyval: uint(gdk.KEY_Left),
98 state: gdk.ControlMaskValue,
99 want: vimkeys.Key{Sym: "Left", Mods: vimkeys.ModCtrl},
100 wantOk: true,
101 },
102 {
103 name: "named Right",
104 keyval: uint(gdk.KEY_Right),
105 state: gdk.NoModifierMaskValue,
106 want: vimkeys.Key{Sym: "Right"},
107 wantOk: true,
108 },
109 {
110 name: "named Up",
111 keyval: uint(gdk.KEY_Up),
112 state: gdk.NoModifierMaskValue,
113 want: vimkeys.Key{Sym: "Up"},
114 wantOk: true,
115 },
116 {
117 name: "named Down",
118 keyval: uint(gdk.KEY_Down),
119 state: gdk.NoModifierMaskValue,
120 want: vimkeys.Key{Sym: "Down"},
121 wantOk: true,
122 },
123 {
124 name: "named Home",
125 keyval: uint(gdk.KEY_Home),
126 state: gdk.NoModifierMaskValue,
127 want: vimkeys.Key{Sym: "Home"},
128 wantOk: true,
129 },
130 {
131 name: "named End",
132 keyval: uint(gdk.KEY_End),
133 state: gdk.NoModifierMaskValue,
134 want: vimkeys.Key{Sym: "End"},
135 wantOk: true,
136 },
137 {
138 name: "named PageUp",
139 keyval: uint(gdk.KEY_Page_Up),
140 state: gdk.NoModifierMaskValue,
141 want: vimkeys.Key{Sym: "PageUp"},
142 wantOk: true,
143 },
144 {
145 name: "named PageDown",
146 keyval: uint(gdk.KEY_Page_Down),
147 state: gdk.AltMaskValue,
148 want: vimkeys.Key{Sym: "PageDown", Mods: vimkeys.ModAlt},
149 wantOk: true,
150 },
151 {
152 name: "ctrl+d printable letter keeps ctrl",
153 keyval: uint(gdk.KEY_d),
154 state: gdk.ControlMaskValue,
155 want: vimkeys.Key{Sym: "d", Mods: vimkeys.ModCtrl},
156 wantOk: true,
157 },
158 {
159 name: "ctrl+eacute Latin-1 keyval round-trips through parser",
160 keyval: uint(gdk.KEY_eacute),
161 state: gdk.ControlMaskValue,
162 want: vimkeys.Key{Sym: "é", Mods: vimkeys.ModCtrl},
163 wantOk: true,
164 },
165 {
166 name: "non-printable rejected",
167 keyval: 0,
168 state: gdk.NoModifierMaskValue,
169 wantOk: false,
170 },
171 }
172
173 for _, tt := range tests {
174 t.Run(tt.name+"_roundtrip_string", func(t *testing.T) {
175 if !tt.wantOk {
176 return
177 }
178 got, ok := KeyvalToVimKey(tt.keyval, tt.state)
179 if !ok {
180 t.Fatalf("KeyvalToVimKey() ok = false")
181 }
182 canonical := got.String()
183 parsed, err := vimkeys.ParseBinding(canonical)
184 if err != nil {
185 t.Fatalf("ParseBinding(%q) error = %v", canonical, err)
186 }
187 if !parsed.Equal(vimkeys.Sequence{got}) {
188 t.Fatalf("round-trip %q -> %v, want %v", canonical, parsed, vimkeys.Sequence{got})
189 }
190 })
191 }
192
193 for _, tt := range tests {
194 t.Run(tt.name, func(t *testing.T) {
195 got, ok := KeyvalToVimKey(tt.keyval, tt.state)
196 if ok != tt.wantOk {
197 t.Fatalf("KeyvalToVimKey() ok = %v, want %v", ok, tt.wantOk)
198 }
199 if !tt.wantOk {
200 return
201 }
202 if got != tt.want {
203 t.Fatalf("KeyvalToVimKey() = %#v, want %#v", got, tt.want)
204 }
205 })
206 }
207}