81 lines
3.0 KiB
Go
81 lines
3.0 KiB
Go
// 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)
|
|
}
|
|
}
|