Cthulhu is no longer a fork. Now it is a screen reader written in Golang.

This commit is contained in:
Storm Dragon committed 2026-10-14 00:16:34 -04:00
1 parent a998fe67de
commit 069fc674dc
708 files changed
+112482 -532

No files matched your search

+87
View File
@@ -0,0 +1,87 @@
// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
package app
import (
"bufio"
"context"
"encoding/json"
"log/slog"
"os"
"os/exec"
"testing"
"time"
"git.stormux.org/storm/cthulhu/internal/atspi"
)
func TestNativeAutomaticTitleDispatchLatency(t *testing.T) {
if os.Getenv("CTHULHU_NATIVE_WINDOW_TITLES") != "1" {
t.Skip("private Xvfb and D-Bus fixture only")
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
fixture := exec.CommandContext(ctx, "python3", "-u", "../../tests/window_title_fixture.py")
stdin, err := fixture.StdinPipe()
if err != nil {
t.Fatal(err)
}
stdout, err := fixture.StdoutPipe()
if err != nil {
t.Fatal(err)
}
fixture.Stderr = os.Stderr
if err = fixture.Start(); err != nil {
t.Fatal(err)
}
defer func() { stdin.Close(); fixture.Wait() }()
scanner := bufio.NewScanner(stdout)
if !scanner.Scan() {
t.Fatal("fixture did not start")
}
adapter := atspi.New()
if err = adapter.Start(ctx); err != nil {
t.Fatal(err)
}
defer adapter.Stop(context.Background())
queue := &fakeSpeechQueue{spoken: make(chan string, 8)}
completed := make(chan error, 1)
go func() { completed <- processEvents(ctx, slog.New(slog.DiscardHandler), queue, adapter, 0) }()
defer func() {
cancel()
if err := <-completed; err != nil {
t.Error(err)
}
}()
wait := func(want string, deadline <-chan time.Time) {
t.Helper()
for {
select {
case got := <-queue.spoken:
if got == want {
return
}
case <-deadline:
t.Fatalf("title %q was not queued promptly", want)
case <-ctx.Done():
t.Fatal(ctx.Err())
}
}
}
wait("Example title", time.After(2*time.Second))
for _, title := range []string{"Status one", "Status two", "Status three"} {
data, _ := json.Marshal(map[string]string{"action": "title", "window": "normal", "title": title})
began := time.Now()
deadline := time.After(200 * time.Millisecond)
if _, err = stdin.Write(append(data, '\n')); err != nil {
t.Fatal(err)
}
if !scanner.Scan() || scanner.Text() != "ready" {
t.Fatal("fixture command failed")
}
wait(title, deadline)
t.Logf("X11 title update to speech queue: %s", time.Since(began))
}
}