90 lines
3.5 KiB
Go
90 lines
3.5 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"testing"
|
|
|
|
"git.stormux.org/storm/cthulhu/internal/config"
|
|
"git.stormux.org/storm/cthulhu/internal/input"
|
|
)
|
|
|
|
func TestProcessInputEventsUsesLiveInterruptionSettings(t *testing.T) {
|
|
live := &liveSettings{}
|
|
settings := config.DefaultSettings()
|
|
settings.EnableKeyEcho = true
|
|
settings.EnableActionKeys = true
|
|
for _, mode := range []string{input.InterruptAllKeys, input.InterruptCommonKeys, input.InterruptCustomKeys} {
|
|
settings.SpeechInterruption = input.InterruptionSettings{Mode: mode, Keys: []string{"Tab"}}
|
|
live.Store(settings)
|
|
speech := &fakeSpeechQueue{spoken: make(chan string, 10), interrupt: make(chan struct{}, 10)}
|
|
listener := &fakeInputListener{events: make(chan input.Event, 8)}
|
|
for _, name := range []string{"a", "Tab", "Control_L", "Return"} {
|
|
listener.events <- input.NewKeyEvent(42, true, name)
|
|
listener.events <- input.NewKeyEvent(42, false, name)
|
|
}
|
|
close(listener.events)
|
|
processInputEvents(context.Background(), slog.New(slog.DiscardHandler), speech, listener, input.EchoSettings{}, live, nil)
|
|
want := map[string]int{input.InterruptAllKeys: 4, input.InterruptCommonKeys: 2, input.InterruptCustomKeys: 1}[mode]
|
|
if len(speech.interrupt) != want {
|
|
t.Fatalf("mode %s interrupted %d times, want %d", mode, len(speech.interrupt), want)
|
|
}
|
|
// Selecting interruption keys must not suppress ordinary key echo.
|
|
if len(speech.spoken) < 2 {
|
|
t.Fatalf("mode %s suppressed Tab/Enter echo", mode)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAppliedInterruptionKeysPreserveQueuedSpeechAndSayAll(t *testing.T) {
|
|
logger := slog.New(slog.DiscardHandler)
|
|
speech := newSpeechWorker(logger, nil)
|
|
speech.running = true
|
|
live := &liveSettings{}
|
|
settings := config.DefaultSettings()
|
|
settings.EnableKeyEcho = false
|
|
live.Store(settings)
|
|
preferences := &preferencesWorker{settings: settings, live: live, speechWorker: speech}
|
|
settings.SpeechInterruption.Mode = input.InterruptCommonKeys
|
|
if err := preferences.applyRuntime(context.Background(), settings); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
deliver := func(name string) {
|
|
listener := &fakeInputListener{events: make(chan input.Event, 1)}
|
|
listener.events <- input.NewKeyEvent(42, true, name)
|
|
close(listener.events)
|
|
processInputEvents(context.Background(), logger, speech, listener, input.EchoSettings{}, live, nil)
|
|
}
|
|
readContext := speech.BeginReadAll(context.Background(), 0)
|
|
speech.Enqueue(speechRequest{Text: "First announcement"})
|
|
speech.Enqueue(speechRequest{Text: "Second announcement"})
|
|
generation := speech.generation
|
|
deliver("Up")
|
|
deliver("a")
|
|
if readContext.Err() != nil || len(speech.pending) != 2 || speech.generation != generation {
|
|
t.Fatal("unselected keys cancelled Say All or dropped queued speech")
|
|
}
|
|
deliver("Control_R")
|
|
if readContext.Err() != context.Canceled || len(speech.pending) != 0 {
|
|
t.Fatal("common interruption key did not cancel Say All and pending output")
|
|
}
|
|
settings.SpeechInterruption = input.InterruptionSettings{Mode: input.InterruptCustomKeys, Keys: []string{"F8"}}
|
|
if err := preferences.applyRuntime(context.Background(), settings); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
speech.Enqueue(speechRequest{Text: "Custom mode announcement"})
|
|
deliver("Control_R")
|
|
if len(speech.pending) != 1 {
|
|
t.Fatal("previous interruption mode remained active after Apply")
|
|
}
|
|
deliver("F8")
|
|
if len(speech.pending) != 0 {
|
|
t.Fatal("custom interruption key did not cancel queued output")
|
|
}
|
|
speech.Enqueue(speechRequest{Text: "Old output"})
|
|
speech.ProtectCommand(100)
|
|
if len(speech.pending) != 0 {
|
|
t.Fatal("reader command failed to cancel old output in custom mode")
|
|
}
|
|
}
|