111 lines
2.9 KiB
Go
111 lines
2.9 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package app
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.stormux.org/storm/cthulhu/internal/input"
|
|
"git.stormux.org/storm/cthulhu/internal/ocr"
|
|
)
|
|
|
|
func TestCopyFeedbackRequiresClipboardChangeAndNewCopyKey(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
changes := make(chan struct{})
|
|
tracker := &input.IntentTracker{}
|
|
speech := &fakeSpeechQueue{spoken: make(chan string, 4), interrupt: make(chan struct{}, 4)}
|
|
done := runCopyFeedback(ctx, changes, tracker, speech, nil, nil)
|
|
checkSilent := func() {
|
|
t.Helper()
|
|
select {
|
|
case got := <-speech.spoken:
|
|
t.Fatalf("unexpected speech %q", got)
|
|
case <-time.After(30 * time.Millisecond):
|
|
}
|
|
}
|
|
change := func() { changes <- struct{}{} }
|
|
change()
|
|
checkSilent()
|
|
tracker.Observe(input.NewKeyEvent(0, true, "Control_L"))
|
|
tracker.Observe(input.NewKeyEvent(0, true, "c"))
|
|
checkSilent()
|
|
change()
|
|
select {
|
|
case got := <-speech.spoken:
|
|
if got != "copied to clipboard" {
|
|
t.Fatalf("copy speech = %q", got)
|
|
}
|
|
case <-time.After(time.Second):
|
|
t.Fatal("copy was not announced")
|
|
}
|
|
change()
|
|
checkSilent()
|
|
tracker.Observe(input.NewKeyEvent(0, true, "c"))
|
|
change()
|
|
select {
|
|
case got := <-speech.spoken:
|
|
if got != "copied to clipboard" {
|
|
t.Fatalf("second copy speech = %q", got)
|
|
}
|
|
case <-time.After(time.Second):
|
|
t.Fatal("second copy was not announced")
|
|
}
|
|
tracker.Observe(input.NewKeyEvent(0, true, "v"))
|
|
change()
|
|
checkSilent()
|
|
cancel()
|
|
select {
|
|
case <-done:
|
|
case <-time.After(time.Second):
|
|
t.Fatal("copy worker did not stop")
|
|
}
|
|
}
|
|
|
|
func TestCopyFeedbackDoesNotRepeatOCRCopy(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
changes := make(chan struct{})
|
|
tracker := &input.IntentTracker{}
|
|
speech := &fakeSpeechQueue{spoken: make(chan string, 2), interrupt: make(chan struct{}, 2)}
|
|
session := &ocrSession{cursor: ocr.NewCursor(ocr.Result{Text: "OCR"}), cancel: func() {}}
|
|
done := runCopyFeedback(ctx, changes, tracker, speech, nil, session)
|
|
tracker.Observe(input.NewKeyEvent(0, true, "Control_L"))
|
|
tracker.Observe(input.NewKeyEvent(0, true, "c"))
|
|
changes <- struct{}{}
|
|
select {
|
|
case got := <-speech.spoken:
|
|
t.Fatalf("duplicate OCR copy feedback %q", got)
|
|
case <-time.After(30 * time.Millisecond):
|
|
}
|
|
session.mu.Lock()
|
|
session.cursor, session.cancel = nil, nil
|
|
session.mu.Unlock()
|
|
changes <- struct{}{}
|
|
select {
|
|
case got := <-speech.spoken:
|
|
t.Fatalf("late duplicate OCR copy feedback %q", got)
|
|
case <-time.After(30 * time.Millisecond):
|
|
}
|
|
tracker.Observe(input.NewKeyEvent(0, true, "c"))
|
|
changes <- struct{}{}
|
|
select {
|
|
case got := <-speech.spoken:
|
|
if got != "copied to clipboard" {
|
|
t.Fatal(got)
|
|
}
|
|
case <-time.After(time.Second):
|
|
t.Fatal("ordinary copy feedback was suppressed")
|
|
}
|
|
cancel()
|
|
select {
|
|
case <-done:
|
|
case <-time.After(time.Second):
|
|
t.Fatal("copy worker did not stop")
|
|
}
|
|
}
|