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,174 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
package wine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.stormux.org/storm/cthulhu/internal/atspi"
|
||||
"github.com/godbus/dbus/v5"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestReviewRegistryRetiresInactiveWindowTrees(t *testing.T) {
|
||||
r := readyReviewRegistry(t)
|
||||
n := registerNotice(t, r, ":1.2")
|
||||
r.captureCall = func(_ context.Context, _ string, _ dbus.ObjectPath, notice ReviewFocusNotice) (map[string]dbus.Variant, error) {
|
||||
f := reviewWire()
|
||||
f["window"] = dbus.MakeVariant(notice.Window)
|
||||
f["revision"] = dbus.MakeVariant(notice.Revision)
|
||||
nodes := f["nodes"].Value().([]map[string]dbus.Variant)
|
||||
nodes[0]["id"] = dbus.MakeVariant(notice.Window)
|
||||
for _, node := range nodes[1:] {
|
||||
if node["parent"].Value() == "window" {
|
||||
node["parent"] = dbus.MakeVariant(notice.Window)
|
||||
}
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
for i := 1; i <= 32; i++ {
|
||||
n.Window = fmt.Sprintf("window%d", i)
|
||||
n.Revision = uint64(i)
|
||||
if !r.PresentFocus(n.Sender, n) {
|
||||
t.Fatal("focus rejected")
|
||||
}
|
||||
one, err := r.Capture(context.Background(), n.ID())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
two, err := r.Capture(context.Background(), n.ID())
|
||||
if err != nil || one != two {
|
||||
t.Fatal("active window tree is not stable")
|
||||
}
|
||||
if len(r.providers[n.Sender].trees) != 1 {
|
||||
t.Fatalf("retained %d inactive trees", len(r.providers[n.Sender].trees)-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func registryNotice(sender string) ReviewFocusNotice {
|
||||
return ReviewFocusNotice{Sender: sender, Path: ReviewObjectPath, Instance: "helper-instance", Window: "window", Focus: "input", Revision: 1, Title: "same title", Role: "window", Bounds: atspi.Rectangle{X: 10, Y: 20, Width: 400, Height: 300}}
|
||||
}
|
||||
func readyReviewRegistry(t *testing.T) *ReviewRegistry {
|
||||
t.Helper()
|
||||
registry := NewReviewRegistry(nil)
|
||||
// Unit tests substitute transport only; registration still requires lifecycle.
|
||||
registry.ctx, registry.cancel = context.WithCancel(context.Background())
|
||||
t.Cleanup(func() { registry.Stop(context.Background()) })
|
||||
return registry
|
||||
}
|
||||
func registerNotice(t *testing.T, r *ReviewRegistry, sender string) ReviewFocusNotice {
|
||||
t.Helper()
|
||||
notice := registryNotice(sender)
|
||||
if !r.RegisterProvider(sender, ReviewObjectPath, 1) || !r.PresentFocus(sender, notice) {
|
||||
t.Fatal("registration rejected")
|
||||
}
|
||||
return notice
|
||||
}
|
||||
func TestReviewRegistryTwoProviders(t *testing.T) {
|
||||
r := readyReviewRegistry(t)
|
||||
one := registerNotice(t, r, ":1.2")
|
||||
two := registerNotice(t, r, ":1.3")
|
||||
if one.ID() == two.ID() || len(r.Focuses()) != 2 || !r.Current(one.ID()) || !r.Current(two.ID()) {
|
||||
t.Fatal("providers collided")
|
||||
}
|
||||
if len(r.changes) != 1 {
|
||||
t.Fatal("notifications are not coalesced")
|
||||
}
|
||||
if !r.RegisterProvider(one.Sender, ReviewObjectPath, 1) || r.Current(one.ID()) || len(r.Focuses()) != 1 {
|
||||
t.Fatal("registration retained old lifetime")
|
||||
}
|
||||
}
|
||||
func TestReviewRegistrySenderAssociation(t *testing.T) {
|
||||
r := readyReviewRegistry(t)
|
||||
n := registryNotice(":1.2")
|
||||
if r.PresentFocus(n.Sender, n) || r.RegisterProvider("well.known", ReviewObjectPath, 1) || r.RegisterProvider(n.Sender, ReviewObjectPath, 2) || r.RegisterProvider(n.Sender, "/wrong", 1) {
|
||||
t.Fatal("invalid provider accepted")
|
||||
}
|
||||
registerNotice(t, r, n.Sender)
|
||||
n.Sender = ":1.99"
|
||||
n.Path = "/forged"
|
||||
if !r.PresentFocus(":1.2", n) {
|
||||
t.Fatal("actual sender rejected")
|
||||
}
|
||||
got := r.Focuses()[0]
|
||||
if got.Sender != ":1.2" || got.Path != ReviewObjectPath {
|
||||
t.Fatal("payload forged destination")
|
||||
}
|
||||
n.Revision = 0
|
||||
if r.PresentFocus(":1.2", n) {
|
||||
t.Fatal("invalid focus accepted")
|
||||
}
|
||||
}
|
||||
func TestReviewRegistryProviderDisappears(t *testing.T) {
|
||||
r := readyReviewRegistry(t)
|
||||
n := registerNotice(t, r, ":1.2")
|
||||
r.disappeared(n.Sender)
|
||||
if r.Current(n.ID()) || len(r.Focuses()) != 0 {
|
||||
t.Fatal("dead provider retained")
|
||||
}
|
||||
if _, err := r.Capture(context.Background(), n.ID()); !errors.Is(err, ErrReviewUnavailable) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
func TestReviewCaptureDeadlineAndStaleReply(t *testing.T) {
|
||||
r := readyReviewRegistry(t)
|
||||
n := registerNotice(t, r, ":1.2")
|
||||
calls := 0
|
||||
r.captureCall = func(ctx context.Context, sender string, path dbus.ObjectPath, notice ReviewFocusNotice) (map[string]dbus.Variant, error) {
|
||||
calls++
|
||||
fields := reviewWire()
|
||||
if calls == 1 {
|
||||
fields["status"] = dbus.MakeVariant("stale")
|
||||
fields["nodes"] = dbus.MakeVariant([]map[string]dbus.Variant{})
|
||||
}
|
||||
return fields, nil
|
||||
}
|
||||
tree, err := r.Capture(context.Background(), n.ID())
|
||||
if err != nil || tree == nil || calls != 2 {
|
||||
t.Fatalf("stale retry: %v calls=%d", err, calls)
|
||||
}
|
||||
again, err := r.Capture(context.Background(), n.ID())
|
||||
if err != nil || again != tree {
|
||||
t.Fatal("capture replaced live tree")
|
||||
}
|
||||
r.captureCall = func(ctx context.Context, _ string, _ dbus.ObjectPath, _ ReviewFocusNotice) (map[string]dbus.Variant, error) {
|
||||
<-ctx.Done()
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
started := time.Now()
|
||||
if _, err = r.Capture(context.Background(), n.ID()); err == nil || time.Since(started) > 750*time.Millisecond {
|
||||
t.Fatalf("deadline: %v", err)
|
||||
}
|
||||
r.captureCall = func(context.Context, string, dbus.ObjectPath, ReviewFocusNotice) (map[string]dbus.Variant, error) {
|
||||
f := reviewWire()
|
||||
f["revision"] = dbus.MakeVariant(uint64(2))
|
||||
return f, nil
|
||||
}
|
||||
if _, err = r.Capture(context.Background(), n.ID()); !errors.Is(err, ErrReviewStale) {
|
||||
t.Fatalf("wrong source: %v", err)
|
||||
}
|
||||
}
|
||||
func TestReviewCaptureStopCancels(t *testing.T) {
|
||||
r := readyReviewRegistry(t)
|
||||
n := registerNotice(t, r, ":1.2")
|
||||
entered := make(chan struct{})
|
||||
done := make(chan error, 1)
|
||||
r.captureCall = func(ctx context.Context, _ string, _ dbus.ObjectPath, _ ReviewFocusNotice) (map[string]dbus.Variant, error) {
|
||||
close(entered)
|
||||
<-ctx.Done()
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
go func() { _, err := r.Capture(context.Background(), n.ID()); done <- err }()
|
||||
<-entered
|
||||
r.Stop(context.Background())
|
||||
select {
|
||||
case err := <-done:
|
||||
if err == nil {
|
||||
t.Fatal("cancelled capture accepted")
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("stop blocked")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user