80 lines
3.0 KiB
Go
80 lines
3.0 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package app
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"testing"
|
|
|
|
"git.stormux.org/storm/cthulhu/internal/input"
|
|
)
|
|
|
|
func TestAutomaticTitleSurvivesMovementRepeatsBeforeAndAfterDelivery(t *testing.T) {
|
|
speaker := &fakeSpeaker{spoken: make(chan string, 1)}
|
|
worker := newSpeechWorker(slog.New(slog.DiscardHandler), speaker)
|
|
worker.running = true
|
|
worker.Enqueue(speechRequest{Text: "Game status", Cause: "window-title", Append: true})
|
|
repeat := input.Event{Name: "Up", Pressed: true, Repeat: true, Timestamp: 100}
|
|
if worker.InterruptForInput(repeat) || len(worker.pending) != 1 {
|
|
t.Fatal("repeat discarded queued title")
|
|
}
|
|
request, ok := worker.next()
|
|
if !ok {
|
|
t.Fatal("title missing from queue")
|
|
}
|
|
if err := worker.deliver(context.Background(), request); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if text := <-speaker.spoken; text != "Game status" {
|
|
t.Fatalf("speech = %q", text)
|
|
}
|
|
if worker.InterruptForInput(repeat) || worker.generation != 0 {
|
|
t.Fatal("repeat interrupted title after backend accepted it")
|
|
}
|
|
if !worker.InterruptForInput(input.Event{Name: "Up", Pressed: true, Timestamp: 200}) {
|
|
t.Fatal("fresh movement key did not interrupt")
|
|
}
|
|
}
|
|
|
|
func TestAutomaticTitleStillStopsForExplicitInput(t *testing.T) {
|
|
for _, event := range []input.Event{
|
|
{Name: "Left", Pressed: true},
|
|
{Name: "Control_L", Pressed: true, Repeat: true},
|
|
{Name: "Control_R", Pressed: true, Repeat: true},
|
|
{Name: "Escape", Pressed: true, Repeat: true},
|
|
} {
|
|
t.Run(event.Name, func(t *testing.T) {
|
|
worker := newSpeechWorker(slog.New(slog.DiscardHandler), nil)
|
|
worker.running = true
|
|
worker.Enqueue(speechRequest{Text: "Game status", Cause: "window-title", Append: true})
|
|
if !worker.InterruptForInput(event) || len(worker.pending) != 0 || worker.generation != 1 {
|
|
t.Fatal("explicit input did not stop title speech")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTitleProtectionDoesNotChangeOrdinaryReading(t *testing.T) {
|
|
for _, cause := range []string{"focus", "flat-review", "current-time", "key-echo", "read-all"} {
|
|
t.Run(cause, func(t *testing.T) {
|
|
worker := newSpeechWorker(slog.New(slog.DiscardHandler), nil)
|
|
worker.running = true
|
|
worker.Enqueue(speechRequest{Text: "Game status", Cause: "window-title", Append: true})
|
|
worker.Enqueue(speechRequest{Text: "Reading", Cause: cause})
|
|
if !worker.InterruptForInput(input.Event{Name: "Up", Pressed: true, Repeat: true}) || len(worker.pending) != 0 {
|
|
t.Fatal("title protection leaked into ordinary reading")
|
|
}
|
|
})
|
|
}
|
|
worker := newSpeechWorker(slog.New(slog.DiscardHandler), nil)
|
|
worker.running = true
|
|
ctx := worker.BeginReadAll(context.Background(), 100)
|
|
worker.Enqueue(speechRequest{Text: "Game status", Cause: "window-title", Append: true})
|
|
if !worker.InterruptForInput(input.Event{Name: "Up", Pressed: true, Repeat: true, Timestamp: 101}) || ctx.Err() != context.Canceled {
|
|
t.Fatal("appended title prevented held key from stopping Say All")
|
|
}
|
|
}
|