Files

121 lines
4.8 KiB
Go

// Fenrir console screen reader.
// Copyright (c) 2026 Storm Dragon
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <https://www.gnu.org/licenses/gpl-3.0.html>.
package interaction
import (
"strings"
"testing"
)
func TestGroupedChoicesTraversalIsolationAndSelection(t *testing.T) {
form := Form{Type: TabForm, Title: "Settings", Tabs: []Tab{{ID: "presentation", Label: "Presentation", Controls: []Control{
{ID: "speech.driver", Label: "Driver", Group: "Speech", Kind: ComboBox, Choices: []Choice{{ID: "first", Label: "First"}, {ID: "second", Label: "Second", Unavailable: "fixture dependency missing"}}},
{ID: "speech.enabled", Label: "Speech enabled", Group: "Speech", Kind: CheckBox},
{ID: "sound.enabled", Label: "Sound enabled", Group: "Sound", Kind: CheckBox},
{ID: "ok", Label: "OK", Kind: Button, Action: "save"},
}}}}
session, err := New_session(form)
if err != nil {
t.Fatal(err)
}
if got := session.Handle(Key{Name: "tab"}).Speech; got != "Speech. Driver combo box First" {
t.Fatal(got)
}
for _, key := range []Key{{Text: "invented"}, {Name: "enter"}, {Name: "space"}, {Ctrl: true, Text: "a"}} {
if result := session.Handle(key); result.Action != "" || result.Cancelled {
t.Fatal(result)
}
}
if got := session.Values()["presentation.speech.driver"].Choices[0].ID; got != "first" {
t.Fatal(got)
}
if got := session.Handle(Key{Name: "down"}).Speech; got != "Second. unavailable: fixture dependency missing" {
t.Fatal(got)
}
session.Handle(Key{Name: "down"})
if got := session.Values()["presentation.speech.driver"].Selected; got != 1 {
t.Fatal("combo wrapped", got)
}
values := session.Values()
values["presentation.speech.driver"].Choices[1].Label = "altered"
if strings.Contains(session.Describe(), "altered") || form.Tabs[0].Controls[0].Selected != 0 {
t.Fatal("aliased choice state")
}
session.Handle(Key{Name: "home"})
if got := session.Values()["presentation.speech.driver"].Selected; got != 0 {
t.Fatal(got)
}
if got := session.Handle(Key{Name: "tab"}).Speech; got != "Speech enabled unchecked" {
t.Fatal("repeated group", got)
}
if got := session.Handle(Key{Name: "tab"}).Speech; got != "Sound. Sound enabled unchecked" {
t.Fatal(got)
}
if got := session.Handle(Key{Name: "tab", Shift: true}).Speech; got != "Speech. Speech enabled unchecked" {
t.Fatal(got)
}
if !session.Handle(Key{Name: "escape"}).Cancelled {
t.Fatal("escape trapped")
}
}
func TestComboChangesSpeakOnlyValueAndFocusRepeatsLabel(t *testing.T) {
form := Form{Type: TabForm, Title: "Settings", Tabs: []Tab{{ID: "settings", Label: "Settings", Controls: []Control{
{ID: "format", Label: "Format", Kind: ComboBox, Choices: []Choice{{ID: "one", Label: "First"}, {ID: "two", Label: "Second"}, {ID: "three", Label: "Third"}}},
{ID: "ok", Label: "OK", Kind: Button, Action: "save"},
}}}}
session, err := New_session(form)
if err != nil {
t.Fatal(err)
}
if got := session.Handle(Key{Name: "tab"}).Speech; got != "Format combo box First" {
t.Fatal(got)
}
for _, testCase := range []struct{ key, want string }{
{"down", "Second"}, {"right", "Third"}, {"up", "Second"},
{"left", "First"}, {"end", "Third"}, {"home", "First"},
} {
if got := session.Handle(Key{Name: testCase.key}).Speech; got != testCase.want {
t.Fatal(testCase.key, got, testCase.want)
}
}
session.Handle(Key{Name: "tab"})
if got := session.Handle(Key{Name: "tab", Shift: true}).Speech; got != "Format combo box First" {
t.Fatal("reverse focus omitted label", got)
}
session.Handle(Key{Name: "tab", Shift: true})
if got := session.Handle(Key{Name: "tab"}).Speech; got != "Format combo box First" {
t.Fatal("forward focus omitted label", got)
}
}
func TestChoiceDefinitionsRejectMissingAndDuplicateSelections(t *testing.T) {
for _, control := range []Control{
{Choices: nil},
{Choices: []Choice{{ID: "one", Label: "One"}}, Selected: 1},
{Choices: []Choice{{ID: "one", Label: "One"}, {ID: "one", Label: "Duplicate"}}},
{Choices: []Choice{{ID: "one"}}},
} {
control.ID, control.Label, control.Kind = "driver", "Driver", ComboBox
form := Form{Type: TabForm, Title: "Settings", Tabs: []Tab{{ID: "presentation", Label: "Presentation", Controls: []Control{control}}}}
if _, err := New_session(form); err == nil {
t.Fatal("invalid combo accepted", control)
}
}
}