Cthulhu is no longer a fork. Now it is a screen reader written in Golang.
This commit is contained in:
1 parent
a998fe67de
commit
069fc674dc
708 files changed
+112482
-532
No files matched your search
@@ -0,0 +1,97 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// Authors: Storm Dragon, Angus Kola
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.stormux.org/storm/cthulhu/internal/input"
|
||||
"git.stormux.org/storm/cthulhu/internal/review"
|
||||
)
|
||||
|
||||
func TestFlatReviewSpellingPresentation(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
command input.Command
|
||||
text string
|
||||
parts []string
|
||||
character bool
|
||||
}{
|
||||
{input.ReviewCurrentWord, "book", nil, false},
|
||||
{input.ReviewCurrentCharacter, "b", nil, true},
|
||||
{input.ReviewPhoneticCharacter, "B", []string{"bravo"}, false},
|
||||
{input.ReviewSpellWord, "Book", []string{"B", "o", "o", "k"}, true},
|
||||
{input.ReviewPhoneticWord, "Book", []string{"bravo", "oscar", "oscar", "kilo"}, false},
|
||||
{input.ReviewSpellWord, "猫1!", []string{"猫", "1", "!"}, true},
|
||||
{input.ReviewPhoneticWord, "猫1!", []string{"猫", "1", "!"}, false},
|
||||
{input.ReviewPhoneticCharacter, " ", nil, true},
|
||||
{input.ReviewPhoneticWord, "", nil, false},
|
||||
} {
|
||||
queue := &fakeSpeechQueue{requests: make(chan speechRequest, 1), spoken: make(chan string, 1)}
|
||||
unit, step := flatReviewCommand(tc.command)
|
||||
result := review.Result{FlatUnit: unit, FlatStep: step, FlatSpeech: flat_review_speech(tc.command), FlatPosition: review.FlatPosition{Text: tc.text}}
|
||||
presentFlatReviewResult(slog.New(slog.DiscardHandler), queue, result)
|
||||
request := <-queue.requests
|
||||
if !reflect.DeepEqual(request.Spelling, tc.parts) || request.Character != tc.character {
|
||||
t.Fatalf("%s %q request=%#v", tc.command, tc.text, request)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type spellingTestSpeaker struct {
|
||||
parts []string
|
||||
characters []string
|
||||
after func()
|
||||
}
|
||||
|
||||
func (*spellingTestSpeaker) Connect(context.Context) error { return nil }
|
||||
func (*spellingTestSpeaker) Close(context.Context) error { return nil }
|
||||
func (*spellingTestSpeaker) Cancel(context.Context) error { return nil }
|
||||
func (speaker *spellingTestSpeaker) Speak(_ context.Context, text string) error {
|
||||
speaker.parts = append(speaker.parts, text)
|
||||
if speaker.after != nil {
|
||||
speaker.after()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (speaker *spellingTestSpeaker) SpeakCharacter(ctx context.Context, text string) error {
|
||||
speaker.characters = append(speaker.characters, text)
|
||||
return speaker.Speak(ctx, text)
|
||||
}
|
||||
|
||||
func TestReviewSpellingDeliveryAndInterruption(t *testing.T) {
|
||||
for _, style := range []review.FlatSpeech{review.FlatSpell, review.FlatPhonetic} {
|
||||
speaker := &spellingTestSpeaker{}
|
||||
worker := newSpeechWorker(slog.New(slog.DiscardHandler), speaker)
|
||||
request := speechRequest{Text: "book", Cause: "flat-review"}
|
||||
set_review_spelling(&request, strings.Repeat("book", 20), style)
|
||||
if err := worker.deliver(context.Background(), request); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(speaker.parts) != 80 {
|
||||
t.Fatalf("long spelling lost letters: %d", len(speaker.parts))
|
||||
}
|
||||
wantCharacters := 0
|
||||
if style == review.FlatSpell {
|
||||
wantCharacters = 80
|
||||
}
|
||||
if len(speaker.characters) != wantCharacters {
|
||||
t.Fatalf("character-mode delivery=%d", len(speaker.characters))
|
||||
}
|
||||
worker.running = true // Exercise the real interruption generation barrier.
|
||||
speaker.parts = nil
|
||||
speaker.after = worker.InterruptForUser
|
||||
if err := worker.deliver(context.Background(), request); !errors.Is(err, context.Canceled) {
|
||||
t.Fatalf("interrupt=%v", err)
|
||||
}
|
||||
if len(speaker.parts) != 1 {
|
||||
t.Fatalf("spelling continued after input: %v", speaker.parts)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user