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

@@ -0,0 +1,88 @@
package presentation
import (
"testing"
"git.stormux.org/storm/cthulhu/internal/atspi"
)
func TestDocumentLineText(t *testing.T) {
line := atspi.DocumentLine{Contents: []atspi.DocumentContent{
{Snapshot: atspi.Snapshot{BusName: ":1.42", Path: "/text", Role: "static"}, Text: "Read "},
{Snapshot: atspi.Snapshot{BusName: ":1.42", Path: "/link", Role: "link"}, Text: "the link"},
{Snapshot: atspi.Snapshot{BusName: ":1.42", Path: "/heading", Role: "heading", HeadingLevel: 2}, Text: ""},
}}
if got := DocumentLineText(line); got != "Read, the link, link, heading level 2" {
t.Fatalf("DocumentLineText() = %q", got)
}
line.Contents = line.Contents[:2]
line.Contents[1].Snapshot.Visited = true
if got := DocumentLineText(line); got != "Read, the link, visited link" {
t.Fatalf("visited line = %q", got)
}
blank := atspi.DocumentLine{Contents: []atspi.DocumentContent{{
Snapshot: atspi.Snapshot{BusName: ":1.42", Path: "/blank", Role: "static"}, Text: "\n",
}}}
if got := DocumentLineText(blank); got != "blank" {
t.Fatalf("blank line = %q", got)
}
withoutBlank := DefaultOptions()
withoutBlank.SpeakBlankLines = false
if got := DocumentLineTextWithOptions(blank, withoutBlank); got != "" {
t.Fatalf("disabled blank line = %q", got)
}
listLine := atspi.DocumentLine{Contents: []atspi.DocumentContent{{
Snapshot: atspi.Snapshot{BusName: ":1.42", Path: "/item", Role: "list item"}, Text: "List text",
}}}
if got := DocumentLineText(listLine); got != "List text" {
t.Fatalf("list item role = %q", got)
}
controls := atspi.DocumentLine{Contents: []atspi.DocumentContent{
{Snapshot: atspi.Snapshot{BusName: ":1.42", Path: "/save", Role: "push button"}, Text: "Save"},
{Snapshot: atspi.Snapshot{BusName: ":1.42", Path: "/updates", Role: "check box", Checked: true}, Text: "Updates"},
}}
if got := DocumentLineText(controls); got != "Save, push button, Updates, check box, checked" {
t.Fatalf("control line = %q", got)
}
repeated := atspi.DocumentLine{Contents: []atspi.DocumentContent{
{Snapshot: atspi.Snapshot{BusName: ":1.1", Path: "/one", Role: "static"}, Text: "the"},
{Snapshot: atspi.Snapshot{BusName: ":1.1", Path: "/two", Role: "static"}, Text: "the"},
}}
if got := DocumentLineText(repeated); got != "the, the" {
t.Fatalf("repeated line content = %q", got)
}
}
func TestDocumentLineSoundPolicy(t *testing.T) {
link := atspi.Snapshot{BusName: ":1.42", Path: "/link", Role: "link", Visited: true}
line := atspi.DocumentLine{Contents: []atspi.DocumentContent{
{Snapshot: link, Text: "Read"}, {Snapshot: link, Text: "more"},
{Snapshot: atspi.Snapshot{BusName: ":1.42", Path: "/check", Role: "check box", Checked: true}, Text: "Updates"},
}}
options := DefaultOptions()
options.EnableSound, options.PlaySoundForRole, options.PlaySoundForState = true, true, true
options.RoleSoundPresentation = "sound_only"
cues := DocumentLineSoundCues(line, options)
if len(cues) != 2 || cues[0].Name != "link_visited" || cues[1].Name != "checkbox_checked" {
t.Fatalf("line cues = %#v", cues)
}
if got := DocumentLineTextWithOptions(line, options); got != "Read, more, Updates" {
t.Fatalf("sound-only text = %q", got)
}
options.PlaySoundForRole = false
if got := DocumentLineSoundCues(line, options); len(got) != 1 || got[0].Name != "checkbox_checked" {
t.Fatalf("state-only cues = %#v", got)
}
options.RoleSoundPresentation = "speech_only"
if got := DocumentLineSoundCues(line, options); len(got) != 0 {
t.Fatalf("speech-only cues = %#v", got)
}
if got := DocumentLineTextWithOptions(line, options); got != "Read, visited link, more, Updates, check box, checked" {
t.Fatalf("speech-only text = %q", got)
}
}