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,80 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// Authors: Storm Dragon, Angus Kola
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package presentation
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.stormux.org/storm/cthulhu/internal/atspi"
|
||||
"git.stormux.org/storm/cthulhu/internal/sound"
|
||||
)
|
||||
|
||||
func TestPositionSoundPolicy(t *testing.T) {
|
||||
base := Options{EnableSound: true, PlaySoundForPositionInSet: true, RoleSoundPresentation: "sound_and_speech"}
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
position, size int
|
||||
want string
|
||||
}{
|
||||
{"first", 1, 3, sound.PositionCueName(0)},
|
||||
{"middle", 2, 3, sound.PositionCueName(0.5)},
|
||||
{"last", 3, 3, sound.PositionCueName(1)},
|
||||
{"virtual set", 501, 1001, sound.PositionCueName(0.5)},
|
||||
{"unknown", 0, 0, ""}, {"negative", -1, 3, ""},
|
||||
{"outside set", 4, 3, ""}, {"unknown size", 1, -1, ""},
|
||||
{"single item", 1, 1, ""},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
snapshot := atspi.Snapshot{Name: "Example", Role: "list item", PositionInSet: test.position, SetSize: test.size}
|
||||
cues := SoundCues(snapshot, base)
|
||||
if test.want == "" {
|
||||
if len(cues) != 0 {
|
||||
t.Fatalf("invalid set produced cues: %v", cues)
|
||||
}
|
||||
} else if len(cues) != 1 || cues[0].Name != test.want {
|
||||
t.Fatalf("position cues = %v, want %s", cues, test.want)
|
||||
}
|
||||
if got := FocusTextWithOptions(snapshot, base); got != "Example, list item" {
|
||||
t.Fatalf("position cue changed speech: %q", got)
|
||||
}
|
||||
})
|
||||
}
|
||||
snapshot := atspi.Snapshot{Role: "radio button", Checked: true, PositionInSet: 2, SetSize: 3}
|
||||
for _, gate := range []string{"disabled sounds", "disabled position", "speech only", "unavailable", "defunct"} {
|
||||
options, source := base, snapshot
|
||||
switch gate {
|
||||
case "disabled sounds":
|
||||
options.EnableSound = false
|
||||
case "disabled position":
|
||||
options.PlaySoundForPositionInSet = false
|
||||
case "speech only":
|
||||
options.RoleSoundPresentation = "speech_only"
|
||||
case "unavailable":
|
||||
options.SoundCueAvailable = func(string) bool { return false }
|
||||
case "defunct":
|
||||
source.Defunct = true
|
||||
}
|
||||
if got := SoundCues(source, options); len(got) != 0 {
|
||||
t.Errorf("%s cues: %v", gate, got)
|
||||
}
|
||||
}
|
||||
base.PlaySoundForState = true
|
||||
base.RoleSoundPresentation = "sound_only"
|
||||
if got := SoundCues(snapshot, base); len(got) != 2 || got[0].Name != "radiobutton_checked" || got[1].Name != sound.PositionCueName(0.5) {
|
||||
t.Fatalf("state/position order = %v", got)
|
||||
}
|
||||
if got := EventSoundCues(atspi.NewEvent("object:state-changed:checked", snapshot), base); len(got) != 1 || got[0].Name != "radiobutton_checked" {
|
||||
t.Fatalf("state change replayed position: %v", got)
|
||||
}
|
||||
for _, eventType := range []string{atspi.FocusEvent, atspi.FocusedStateEvent, atspi.ActiveDescendantEvent, atspi.SelectionChangedEvent} {
|
||||
if got := EventSoundCues(atspi.NewEvent(eventType, snapshot), base); len(got) != 2 {
|
||||
t.Errorf("%s cues: %v", eventType, got)
|
||||
}
|
||||
}
|
||||
line := atspi.DocumentLine{Contents: []atspi.DocumentContent{{Snapshot: snapshot}, {Snapshot: snapshot}}}
|
||||
if got := DocumentLineSoundCues(line, base); len(got) != 2 {
|
||||
t.Fatalf("line replayed position: %v", got)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user