126 lines
3.9 KiB
Go
126 lines
3.9 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package atspi
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestNativeSpeechMetadata(t *testing.T) {
|
|
if os.Getenv("CTHULHU_SPEECH_METADATA") != "1" {
|
|
t.Skip("requires private GTK speech fixture")
|
|
}
|
|
ctx, cancel := context.WithTimeout(context.Background(), 12*time.Second)
|
|
defer cancel()
|
|
adapter := New()
|
|
adapter.SetCaptureTextAttributes(true)
|
|
if err := adapter.Start(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() {
|
|
stopCtx, stopCancel := context.WithTimeout(context.Background(), 3*time.Second)
|
|
defer stopCancel()
|
|
if err := adapter.Stop(stopCtx); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}()
|
|
for _, probe := range []struct{ key, name string }{{"F9", "Mnemonic probe"}, {"F10", "Indentation probe"}} {
|
|
pressTreeProbeKey(t, probe.key)
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
t.Fatal("missing speech metadata focus event", probe.name)
|
|
case event := <-adapter.Events():
|
|
if !((event.Type == FocusEvent || event.Type == FocusedStateEvent) && event.Source.Name == probe.name) {
|
|
continue
|
|
}
|
|
windowContext := false
|
|
for _, ancestor := range event.Source.BrailleContext {
|
|
if ancestor.Role == "frame" && ancestor.Name != "" {
|
|
windowContext = true
|
|
}
|
|
}
|
|
if !windowContext {
|
|
t.Fatalf("missing native braille window context: %+v", event.Source.BrailleContext)
|
|
}
|
|
if probe.key == "F9" {
|
|
if !strings.Contains(strings.ToLower(event.Source.Mnemonic), "a") {
|
|
t.Fatalf("missing native mnemonic: %q", event.Source.Mnemonic)
|
|
}
|
|
} else {
|
|
if event.Source.BrailleLine != "\t Indented É" {
|
|
t.Fatalf("raw indentation lost: %q", event.Source.BrailleLine)
|
|
}
|
|
found := false
|
|
for _, ancestor := range event.Source.SpeechContext {
|
|
if (ancestor.Role == "list" || ancestor.Role == "list box") && ancestor.Name == "Dynamic controls" {
|
|
if !ancestor.ChildCountKnown || ancestor.ChildCount != 10 {
|
|
t.Fatalf("native list count unavailable: %+v", ancestor)
|
|
}
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatalf("missing native list context: %+v", event.Source.SpeechContext)
|
|
}
|
|
}
|
|
goto nextProbe
|
|
}
|
|
}
|
|
nextProbe:
|
|
}
|
|
pressTreeProbeKey(t, "F11")
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
t.Fatal("missing color attribute focus event")
|
|
case event := <-adapter.Events():
|
|
if (event.Type != FocusEvent && event.Type != FocusedStateEvent) || event.Source.Name != "Color attribute probe" {
|
|
continue
|
|
}
|
|
if len(event.Source.TextAttributeRuns) == 0 || event.Source.TextAttributeRuns[0].Values["fg-color"] == "" {
|
|
t.Fatalf("native braille attribute runs missing: %+v", event.Source.TextAttributeRuns)
|
|
}
|
|
if !event.Source.Misspelled || !TextAttributesMisspelled(event.Source.TextAttributeRuns[0].Values) {
|
|
t.Fatalf("native error underline lost its spelling indicator: %+v", event.Source.TextAttributeRuns)
|
|
}
|
|
attributes, err := adapter.ReadCharacterAttributes(ctx, event.Source.ID())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !TextAttributesMisspelled(attributes.Values) {
|
|
t.Fatalf("character attributes lost spelling indicator: %+v", attributes.Values)
|
|
}
|
|
if color := attributes.Values["fg-color"]; color == "" {
|
|
t.Fatalf("native foreground color missing: %+v", attributes.Values)
|
|
} else {
|
|
t.Logf("native foreground color: %q", color)
|
|
}
|
|
goto protectedProbe
|
|
}
|
|
}
|
|
protectedProbe:
|
|
pressTreeProbeKey(t, "F7")
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
t.Fatal("missing protected text focus event")
|
|
case event := <-adapter.Events():
|
|
if (event.Type != FocusEvent && event.Type != FocusedStateEvent) || event.Source.Name != "Protected text probe" {
|
|
continue
|
|
}
|
|
attributes, err := adapter.ReadCharacterAttributes(ctx, event.Source.ID())
|
|
if err != nil || len(attributes.Values) != 0 {
|
|
t.Fatalf("password attributes: %+v, %v", attributes.Values, err)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}
|