// 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 . package tabbed 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) } } }