1package config
2
3import (
4 "testing"
5
6 "github.com/stretchr/testify/assert"
7 "github.com/stretchr/testify/require"
8)
9
10func TestTransformLegacyActions_SliceFormat(t *testing.T) {
11 transformer := NewLegacyConfigTransformer()
12
13 rawConfig := map[string]any{
14 "workspace": map[string]any{
15 "pane_mode": map[string]any{
16 "actions": map[string]any{
17 "focus-left": []any{"h", "arrowleft"},
18 },
19 },
20 },
21 }
22
23 transformer.TransformLegacyActions(rawConfig)
24
25 actions := rawConfig["workspace"].(map[string]any)["pane_mode"].(map[string]any)["actions"].(map[string]any)
26 binding, ok := actions["focus-left"].(map[string]any)
27 require.True(t, ok, "should be converted to map")
28
29 keys, ok := binding["keys"].([]string)
30 require.True(t, ok, "keys should be []string")
31 assert.Equal(t, []string{"h", "arrowleft"}, keys)
32 assert.NotEmpty(t, binding["desc"], "should have description from defaults")
33}
34
35func TestTransformLegacyActions_AllModes(t *testing.T) {
36 transformer := NewLegacyConfigTransformer()
37
38 rawConfig := map[string]any{
39 "workspace": map[string]any{
40 "pane_mode": map[string]any{
41 "actions": map[string]any{
42 "focus-left": []any{"h"},
43 },
44 },
45 "tab_mode": map[string]any{
46 "actions": map[string]any{
47 "next-tab": []any{"l"},
48 },
49 },
50 "resize_mode": map[string]any{
51 "actions": map[string]any{
52 "resize-increase": []any{"+"},
53 },
54 },
55 "shortcuts": map[string]any{
56 "actions": map[string]any{
57 "close_pane": []any{"ctrl+w"},
58 },
59 },
60 },
61 "session": map[string]any{
62 "session_mode": map[string]any{
63 "actions": map[string]any{
64 "session-manager": []any{"m"},
65 },
66 },
67 },
68 }
69
70 transformer.TransformLegacyActions(rawConfig)
71
72 // Check pane mode
73 paneActions := rawConfig["workspace"].(map[string]any)["pane_mode"].(map[string]any)["actions"].(map[string]any)
74 paneFocus, ok := paneActions["focus-left"].(map[string]any)
75 require.True(t, ok)
76 assert.Equal(t, []string{"h"}, paneFocus["keys"])
77
78 // Check tab mode
79 tabActions := rawConfig["workspace"].(map[string]any)["tab_mode"].(map[string]any)["actions"].(map[string]any)
80 tabNext, ok := tabActions["next-tab"].(map[string]any)
81 require.True(t, ok)
82 assert.Equal(t, []string{"l"}, tabNext["keys"])
83
84 // Check resize mode
85 resizeActions := rawConfig["workspace"].(map[string]any)["resize_mode"].(map[string]any)["actions"].(map[string]any)
86 resizeInc, ok := resizeActions["resize-increase"].(map[string]any)
87 require.True(t, ok)
88 assert.Equal(t, []string{"+"}, resizeInc["keys"])
89
90 // Check shortcuts
91 shortcutActions := rawConfig["workspace"].(map[string]any)["shortcuts"].(map[string]any)["actions"].(map[string]any)
92 closePane, ok := shortcutActions["close-pane"].(map[string]any)
93 require.True(t, ok, "underscore action names are renamed to the hyphen form")
94 assert.NotContains(t, shortcutActions, "close_pane")
95 assert.Equal(t, []string{"ctrl+w"}, closePane["keys"])
96
97 // Check session mode
98 sessionActions := rawConfig["session"].(map[string]any)["session_mode"].(map[string]any)["actions"].(map[string]any)
99 sessionMgr, ok := sessionActions["session-manager"].(map[string]any)
100 require.True(t, ok)
101 assert.Equal(t, []string{"m"}, sessionMgr["keys"])
102}
103
104func TestTransformLegacyActions_AlreadyNewFormat(t *testing.T) {
105 transformer := NewLegacyConfigTransformer()
106
107 rawConfig := map[string]any{
108 "workspace": map[string]any{
109 "pane_mode": map[string]any{
110 "actions": map[string]any{
111 "focus-left": map[string]any{
112 "keys": []string{"h"},
113 "desc": "Custom description",
114 },
115 },
116 },
117 },
118 }
119
120 transformer.TransformLegacyActions(rawConfig)
121
122 actions := rawConfig["workspace"].(map[string]any)["pane_mode"].(map[string]any)["actions"].(map[string]any)
123 binding := actions["focus-left"].(map[string]any)
124
125 // Should remain unchanged
126 assert.Equal(t, "Custom description", binding["desc"])
127}
128
129func TestTransformLegacyActions_MissingSection(t *testing.T) {
130 transformer := NewLegacyConfigTransformer()
131
132 rawConfig := map[string]any{
133 "appearance": map[string]any{
134 "theme": "dark",
135 },
136 }
137
138 // Should not panic
139 transformer.TransformLegacyActions(rawConfig)
140
141 // Config should be unchanged
142 assert.Equal(t, "dark", rawConfig["appearance"].(map[string]any)["theme"])
143}
144
145func TestTransformLegacyActions_EmptyConfig(t *testing.T) {
146 transformer := NewLegacyConfigTransformer()
147
148 rawConfig := map[string]any{}
149
150 // Should not panic
151 transformer.TransformLegacyActions(rawConfig)
152
153 assert.Empty(t, rawConfig)
154}
155
156func TestTransformLegacyActions_PartialPath(t *testing.T) {
157 transformer := NewLegacyConfigTransformer()
158
159 rawConfig := map[string]any{
160 "workspace": map[string]any{
161 "pane_mode": map[string]any{
162 // actions section missing
163 },
164 },
165 }
166
167 // Should not panic
168 transformer.TransformLegacyActions(rawConfig)
169
170 // Verify config is unchanged
171 require.NotNil(t, rawConfig["workspace"])
172}
173
174func TestTransformLegacyEngineConfig_RemovesDeprecatedContextMenuHandler(t *testing.T) {
175 transformer := NewLegacyConfigTransformer()
176
177 rawConfig := map[string]any{
178 "engine": map[string]any{
179 "cef": map[string]any{
180 "enable_context_menu_handler": true,
181 },
182 },
183 }
184
185 transformer.TransformLegacyEngineConfig(rawConfig)
186
187 cef := rawConfig["engine"].(map[string]any)["cef"].(map[string]any)
188 _, exists := cef["enable_context_menu_handler"]
189 assert.False(t, exists)
190}
191
192func TestTransformLegacyEngineConfig_MigratesLegacyCEFWindowlessFrameRateDefault(t *testing.T) {
193 transformer := NewLegacyConfigTransformer()
194 rawConfig := map[string]any{
195 "engine": map[string]any{
196 "cef": map[string]any{
197 "windowless_frame_rate": 60,
198 },
199 },
200 }
201
202 transformer.TransformLegacyEngineConfig(rawConfig)
203
204 cef := rawConfig["engine"].(map[string]any)["cef"].(map[string]any)
205 assert.Equal(t, true, cef["adaptive_windowless_frame_rate"])
206 assert.Equal(t, 0, cef["windowless_frame_rate"])
207 assert.Equal(t, defaultCEFWindowlessFrameRateMax, cef["windowless_frame_rate_max"])
208}
209
210func TestTransformLegacyEngineConfig_UpgradesObsoletePreciseScrollDefault(t *testing.T) {
211 transformer := NewLegacyConfigTransformer()
212 rawConfig := map[string]any{
213 "engine": map[string]any{
214 "cef": map[string]any{
215 "input": map[string]any{
216 "scroll_precise_multiplier": 0.35,
217 },
218 },
219 },
220 }
221
222 transformer.TransformLegacyEngineConfig(rawConfig)
223
224 input := rawConfig["engine"].(map[string]any)["cef"].(map[string]any)["input"].(map[string]any)
225 assert.InDelta(t, defaultCEFScrollPreciseMultiplier, input["scroll_precise_multiplier"], 0.001)
226}
227
228func TestTransformLegacyEngineConfig_MigratesLegacyTouchpadScrollKey(t *testing.T) {
229 transformer := NewLegacyConfigTransformer()
230 rawConfig := map[string]any{
231 "engine": map[string]any{
232 "cef": map[string]any{
233 "input": map[string]any{
234 "scroll_touchpad_multiplier": 0.35,
235 },
236 },
237 },
238 }
239
240 transformer.TransformLegacyEngineConfig(rawConfig)
241
242 input := rawConfig["engine"].(map[string]any)["cef"].(map[string]any)["input"].(map[string]any)
243 assert.InDelta(t, defaultCEFScrollPreciseMultiplier, input["scroll_precise_multiplier"], 0.001)
244 assert.NotContains(t, input, "scroll_touchpad_multiplier")
245}
246
247func TestTransformLegacyEngineConfig_PreservesCustomPreciseScrollMultiplier(t *testing.T) {
248 transformer := NewLegacyConfigTransformer()
249 rawConfig := map[string]any{
250 "engine": map[string]any{
251 "cef": map[string]any{
252 "input": map[string]any{
253 "scroll_precise_multiplier": 4.0,
254 },
255 },
256 },
257 }
258
259 transformer.TransformLegacyEngineConfig(rawConfig)
260
261 input := rawConfig["engine"].(map[string]any)["cef"].(map[string]any)["input"].(map[string]any)
262 assert.InDelta(t, 4.0, input["scroll_precise_multiplier"], 0.001)
263}
264
265func TestTransformLegacyEngineConfig_PreservesCustomLegacyTouchpadScrollMultiplier(t *testing.T) {
266 transformer := NewLegacyConfigTransformer()
267 rawConfig := map[string]any{
268 "engine": map[string]any{
269 "cef": map[string]any{
270 "input": map[string]any{
271 "scroll_touchpad_multiplier": 4.0,
272 },
273 },
274 },
275 }
276
277 transformer.TransformLegacyEngineConfig(rawConfig)
278
279 input := rawConfig["engine"].(map[string]any)["cef"].(map[string]any)["input"].(map[string]any)
280 assert.InDelta(t, 4.0, input["scroll_precise_multiplier"], 0.001)
281 assert.NotContains(t, input, "scroll_touchpad_multiplier")
282}
283
284func TestTransformLegacyEngineConfig_PrefersCustomLegacyTouchpadOverGeneratedPreciseDefault(t *testing.T) {
285 transformer := NewLegacyConfigTransformer()
286 rawConfig := map[string]any{
287 "engine": map[string]any{
288 "cef": map[string]any{
289 "input": map[string]any{
290 "scroll_touchpad_multiplier": 4.0,
291 "scroll_precise_multiplier": 0.35,
292 },
293 },
294 },
295 }
296
297 transformer.TransformLegacyEngineConfig(rawConfig)
298
299 input := rawConfig["engine"].(map[string]any)["cef"].(map[string]any)["input"].(map[string]any)
300 assert.InDelta(t, 4.0, input["scroll_precise_multiplier"], 0.001)
301 assert.NotContains(t, input, "scroll_touchpad_multiplier")
302}
303
304func TestTransformLegacyEngineConfig_PreservesExplicitCEFWindowlessFrameRate(t *testing.T) {
305 transformer := NewLegacyConfigTransformer()
306 rawConfig := map[string]any{
307 "engine": map[string]any{
308 "cef": map[string]any{
309 "adaptive_windowless_frame_rate": false,
310 "windowless_frame_rate": 60,
311 },
312 },
313 }
314
315 transformer.TransformLegacyEngineConfig(rawConfig)
316
317 cef := rawConfig["engine"].(map[string]any)["cef"].(map[string]any)
318 assert.Equal(t, false, cef["adaptive_windowless_frame_rate"])
319 assert.Equal(t, 60, cef["windowless_frame_rate"])
320 _, hasMax := cef["windowless_frame_rate_max"]
321 assert.False(t, hasMax)
322}
323
324func TestTransformLegacyEngineConfig_PreservesNonDefaultCEFWindowlessFrameRate(t *testing.T) {
325 transformer := NewLegacyConfigTransformer()
326 rawConfig := map[string]any{
327 "engine": map[string]any{
328 "cef": map[string]any{
329 "windowless_frame_rate": 144,
330 },
331 },
332 }
333
334 transformer.TransformLegacyEngineConfig(rawConfig)
335
336 cef := rawConfig["engine"].(map[string]any)["cef"].(map[string]any)
337 _, hasAdaptive := cef["adaptive_windowless_frame_rate"]
338 assert.False(t, hasAdaptive)
339 assert.Equal(t, 144, cef["windowless_frame_rate"])
340}
341
342func TestTransformLegacyEngineConfig_MissingCefSection(t *testing.T) {
343 transformer := NewLegacyConfigTransformer()
344 rawConfig := map[string]any{
345 "engine": map[string]any{
346 "webkit": map[string]any{"enabled": true},
347 },
348 }
349
350 transformer.TransformLegacyEngineConfig(rawConfig)
351
352 engine, ok := rawConfig["engine"].(map[string]any)
353 require.True(t, ok)
354 assert.NotNil(t, engine)
355 assert.Equal(t, true, engine["webkit"].(map[string]any)["enabled"])
356}
357
358func TestTransformLegacyEngineConfig_MissingContextMenuHandlerKey(t *testing.T) {
359 transformer := NewLegacyConfigTransformer()
360 rawConfig := map[string]any{
361 "engine": map[string]any{
362 "cef": map[string]any{
363 "other_setting": true,
364 },
365 },
366 }
367
368 transformer.TransformLegacyEngineConfig(rawConfig)
369
370 cef := rawConfig["engine"].(map[string]any)["cef"].(map[string]any)
371 assert.True(t, cef["other_setting"].(bool))
372 _, exists := cef["enable_context_menu_handler"]
373 assert.False(t, exists)
374}
375
376func TestTransformLegacyEngineConfig_NonMapEngineSection(t *testing.T) {
377 transformer := NewLegacyConfigTransformer()
378 rawConfig := map[string]any{
379 "engine": "invalid",
380 }
381
382 transformer.TransformLegacyEngineConfig(rawConfig)
383
384 assert.Equal(t, "invalid", rawConfig["engine"])
385}
386
387func TestTransformLegacyActions_UnknownAction(t *testing.T) {
388 transformer := NewLegacyConfigTransformer()
389
390 rawConfig := map[string]any{
391 "workspace": map[string]any{
392 "pane_mode": map[string]any{
393 "actions": map[string]any{
394 "unknown-action": []any{"x"},
395 },
396 },
397 },
398 }
399
400 transformer.TransformLegacyActions(rawConfig)
401
402 actions := rawConfig["workspace"].(map[string]any)["pane_mode"].(map[string]any)["actions"].(map[string]any)
403 binding, ok := actions["unknown-action"].(map[string]any)
404 require.True(t, ok)
405 assert.Equal(t, []string{"x"}, binding["keys"])
406 assert.Empty(t, binding["desc"], "unknown action should have empty description")
407}
408
409func TestTransformLegacyActions_RenamesUnderscoreNamesInEveryActionMap(t *testing.T) {
410 raw := map[string]any{
411 "workspace": map[string]any{
412 "shortcuts": map[string]any{"actions": map[string]any{"toggle_floating_pane": map[string]any{"keys": []any{"alt+g"}}}},
413 "prefix_mode": map[string]any{"actions": map[string]any{"enter_resize_mode": map[string]any{"keys": []any{"z"}}}},
414 "pane_mode": map[string]any{"actions": map[string]any{"focus_left": map[string]any{"keys": []any{"z"}}}},
415 "tab_mode": map[string]any{"actions": map[string]any{"new_tab": map[string]any{"keys": []any{"z"}}}},
416 "resize_mode": map[string]any{"actions": map[string]any{"resize_increase_left": map[string]any{"keys": []any{"z"}}}},
417 "vim_mode": map[string]any{"actions": map[string]any{"vim_scroll_left": map[string]any{"keys": []any{"z"}}}},
418 },
419 "session": map[string]any{
420 "session_mode": map[string]any{"actions": map[string]any{"session_manager": map[string]any{"keys": []any{"z"}}}},
421 },
422 }
423
424 NewLegacyConfigTransformer().TransformLegacyActions(raw)
425
426 want := map[string]string{
427 "shortcuts": "toggle-floating-pane",
428 "prefix_mode": "enter-resize-mode",
429 "pane_mode": "focus-left",
430 "tab_mode": "new-tab",
431 "resize_mode": "resize-increase-left",
432 "vim_mode": "vim-scroll-left",
433 }
434 workspace := raw["workspace"].(map[string]any)
435 for section, name := range want {
436 actions := workspace[section].(map[string]any)["actions"].(map[string]any)
437 assert.Len(t, actions, 1, section)
438 assert.Contains(t, actions, name, section)
439 }
440 sessionActions := raw["session"].(map[string]any)["session_mode"].(map[string]any)["actions"].(map[string]any)
441 assert.Len(t, sessionActions, 1)
442 assert.Contains(t, sessionActions, "session-manager")
443}
444
445func TestTransformLegacyActions_HyphenSpellingWinsOverUnderscore(t *testing.T) {
446 raw := map[string]any{
447 "workspace": map[string]any{
448 "pane_mode": map[string]any{"actions": map[string]any{
449 "stack_pane": map[string]any{"keys": []any{"q"}},
450 "stack-pane": map[string]any{"keys": []any{"w"}},
451 }},
452 },
453 }
454
455 NewLegacyConfigTransformer().TransformLegacyActions(raw)
456
457 actions := raw["workspace"].(map[string]any)["pane_mode"].(map[string]any)["actions"].(map[string]any)
458 require.Len(t, actions, 1)
459 assert.Equal(t, []any{"w"}, actions["stack-pane"].(map[string]any)["keys"])
460}
461
462func TestTransformLegacyActions_RenamesUnderscoreNamesInSliceFormat(t *testing.T) {
463 raw := map[string]any{
464 "workspace": map[string]any{
465 "pane_mode": map[string]any{"actions": map[string]any{"stack_pane": []any{"q"}}},
466 },
467 }
468
469 NewLegacyConfigTransformer().TransformLegacyActions(raw)
470
471 actions := raw["workspace"].(map[string]any)["pane_mode"].(map[string]any)["actions"].(map[string]any)
472 binding, ok := actions["stack-pane"].(map[string]any)
473 require.True(t, ok)
474 assert.Equal(t, []string{"q"}, binding["keys"])
475 assert.Equal(t, DefaultConfig().Workspace.PaneMode.Actions["stack-pane"].Desc, binding["desc"])
476}