// Copyright (c) 2026 Storm Dragon // SPDX-License-Identifier: GPL-3.0-or-later package app import ( "context" "errors" "reflect" "strings" "testing" "git.stormux.org/storm/fenrir/internal/config" "git.stormux.org/storm/fenrir/internal/screen" ) func TestSavedModifiersWaitForMenuCloseAndIdleKeys(t *testing.T) { base := config.Defaults() base.Keyboard.FenrirKeys = []string{"KEY_INSERT"} source := &fakeSource{snapshot: screen.Snapshot{Terminal: 1, Active: true}} voice := &fakeVoice{} calls := 0 idle := false keys := &fakeKeys{updateModifiers: func(reader, script []string) (bool, error) { calls++ if !reflect.DeepEqual(reader, []string{"KEY_CAPSLOCK"}) || !reflect.DeepEqual(script, []string{"KEY_META"}) { t.Fatal(reader, script) } return idle, nil }} a, err := new_application(context.Background(), source, keys, voice, RunOptions{Settings: base}) if err != nil { t.Fatal(err) } saved := base saved.Keyboard.FenrirKeys = []string{"KEY_CAPSLOCK"} saved.General.ScriptKeys = []string{"KEY_META"} a.ui.active = true a.apply_saved_settings(saved, false) a.apply_pending_modifiers() if calls != 0 || a.settings.pendingModifiers == nil { t.Fatal("changed during modal capture") } a.ui.active = false a.apply_pending_modifiers() if calls != 1 || !reflect.DeepEqual(a.settings.live.Keyboard.FenrirKeys, base.Keyboard.FenrirKeys) || !reflect.DeepEqual(a.settings.live.General.ScriptKeys, base.General.ScriptKeys) { t.Fatal("changed while held", a.settings.live) } idle = true a.apply_pending_modifiers() if calls != 2 || a.settings.pendingModifiers != nil || !reflect.DeepEqual(a.settings.live.Keyboard.FenrirKeys, saved.Keyboard.FenrirKeys) || !reflect.DeepEqual(a.settings.live.General.ScriptKeys, saved.General.ScriptKeys) { t.Fatal("new keys not applied", a.settings.live) } a.apply_pending_modifiers() if calls != 2 { t.Fatal("update repeated after success") } } func TestModifierApplyFailureKeepsPreviousRuntimeAndAllowsRetry(t *testing.T) { base := config.Defaults() base.Keyboard.FenrirKeys = []string{"KEY_INSERT"} source := &fakeSource{snapshot: screen.Snapshot{Terminal: 1, Active: true}} voice := &fakeVoice{} keys := &fakeKeys{updateModifiers: func([]string, []string) (bool, error) { return false, errors.New("fixture grab conflict") }} a, err := new_application(context.Background(), source, keys, voice, RunOptions{Settings: base}) if err != nil { t.Fatal(err) } saved := base saved.Keyboard.FenrirKeys = []string{"KEY_META"} a.apply_saved_settings(saved, false) a.apply_pending_modifiers() if a.settings.pendingModifiers != nil || !reflect.DeepEqual(a.settings.live.Keyboard.FenrirKeys, base.Keyboard.FenrirKeys) || !reflect.DeepEqual(a.settings.saveDraft.Keyboard.FenrirKeys, saved.Keyboard.FenrirKeys) { t.Fatal(a.settings) } if len(voice.messages) != 1 || !strings.Contains(voice.messages[0], "Previous keys remain active") { t.Fatal(voice.messages) } keys.updateModifiers = func([]string, []string) (bool, error) { return true, nil } a.apply_saved_settings(saved, false) a.apply_pending_modifiers() if !reflect.DeepEqual(a.settings.live.Keyboard.FenrirKeys, saved.Keyboard.FenrirKeys) { t.Fatal("retry failed") } }