package app import ( "context" "log/slog" "strings" "testing" "git.stormux.org/storm/cthulhu/internal/config" "git.stormux.org/storm/cthulhu/internal/input" ) type learnSpeechRecorder struct { texts []string interrupts int } func (recorder *learnSpeechRecorder) Enqueue(request speechRequest) { recorder.texts = append(recorder.texts, request.Text) } func (recorder *learnSpeechRecorder) Interrupt() { recorder.interrupts++ } type learnBrailleRecorder struct{ texts []string } func (recorder *learnBrailleRecorder) EnqueueMessage(text string) bool { recorder.texts = append(recorder.texts, text) return true } func TestLearnModePresentsKeyCommandsWithoutExecutingThem(t *testing.T) { live := &liveSettings{} live.Store(config.DefaultSettings()) speech := &learnSpeechRecorder{} braille := &learnBrailleRecorder{} presenter := &learnModePresenter{ctx: context.Background(), logger: slog.New(slog.DiscardHandler), speech: speech, braille: braille, live: live} presenter.handle(input.CommandEvent{Command: input.ToggleLearnMode, LearnModeStarted: true}) if !presenter.active || len(speech.texts) != 2 || !strings.Contains(speech.texts[1], "Cthulhu F1") || len(braille.texts) != 1 { t.Fatalf("start speech=%q braille=%q", speech.texts, braille.texts) } presenter.handle(input.CommandEvent{Command: input.LearnKey, Chord: input.CommandChord{Symbol: 'q', CthulhuModifier: true}, KeyName: "q", Timestamp: 100}) if got := speech.texts[len(speech.texts)-1]; got != "Quit Cthulhu." { t.Fatalf("command description = %q", got) } if got := braille.texts[len(braille.texts)-1]; got != "Quit Cthulhu." { t.Fatalf("braille description = %q", got) } presenter.handle(input.CommandEvent{Command: input.LearnKey, Chord: input.CommandChord{Symbol: 'z'}, KeyName: "z", Timestamp: 1000}) presenter.handle(input.CommandEvent{Command: input.LearnKey, Chord: input.CommandChord{Symbol: 'z'}, KeyName: "z", Timestamp: 1200}) if got := speech.texts[len(speech.texts)-1]; got != "zulu" { t.Fatalf("phonetic double press = %q", got) } presenter.handle(input.CommandEvent{Command: input.ToggleLearnMode, Chord: input.CommandChord{Symbol: 'h', CthulhuModifier: true}, KeyName: "h"}) if presenter.active || speech.texts[len(speech.texts)-1] != "Exiting learn mode." || speech.interrupts < 4 { t.Fatalf("exit speech=%q interrupts=%d", speech.texts, speech.interrupts) } } func TestLearnShortcutListUsesActiveBindings(t *testing.T) { settings := config.DefaultSettings() settings.KeyBindings = []input.BindingOverride{{Layout: input.DesktopKeyboardLayout, Scope: "global", Command: input.Preferences, Keys: []string{"Cthulhu+Ctrl+F8"}}} list := makeShortcutList(settings) if len(list.Rows) == 0 || !strings.Contains(list.Title, "shortcuts found") { t.Fatalf("empty shortcut list: %+v", list) } foundLearn := false foundPreferences := false for _, row := range list.Rows { if row.Label == "Enter or exit learn mode." { foundLearn = strings.Contains(row.Keys, "Cthulhu+h") && strings.Contains(row.Keys, "Cthulhu+F1") } if row.Label == "Open Cthulhu preferences." { foundPreferences = true if row.Keys != "Cthulhu+Ctrl+F8" { t.Fatalf("preferences keys = %q", row.Keys) } } } if !foundLearn || !foundPreferences { t.Fatalf("learn and preferences shortcuts missing from list: learn=%t preferences=%t", foundLearn, foundPreferences) } }