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,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))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user