// Copyright (c) 2026 Storm Dragon // SPDX-License-Identifier: GPL-3.0-or-later package preferences import ( "testing" "git.stormux.org/storm/fenrir/internal/config" "git.stormux.org/storm/fenrir/internal/interaction" ) func focus_setting(t *testing.T, session *interaction.Session, id string) { t.Helper() for range 100 { if control, ok := session.Focused_control(); ok && control.ID == id { return } session.Handle(interaction.Key{Name: "tab"}) } t.Fatal("control not reachable", id) } func TestHardwareControlsUpdateImmediatelyAndKeepDraftEdits(t *testing.T) { base := config.Defaults() session, err := New_session(base, nil) if err != nil { t.Fatal(err) } previous := base discovery := Discovery{Driver: "speech-dispatcher"} for _, path := range []string{"presentation.speech.hardware_device", "presentation.speech.hardware_baud_rate", "presentation.speech.test"} { if !session.Values()[path].Hidden { t.Fatal("hardware control initially visible", path) } } focus_setting(t, session, "speech.driver") session.Handle(interaction.Key{Name: "down"}) if !discovery.Refresh_speech(session, &previous) { t.Fatal("driver change not detected") } if control, _ := session.Focused_control(); control.ID != "speech.driver" { t.Fatal("driver change moved focus", control) } focus_setting(t, session, "speech.hardware_device") session.Handle(interaction.Key{Text: "/dev/fixture-synth"}) focus_setting(t, session, "speech.hardware_baud_rate") session.Handle(interaction.Key{Name: "end"}) draft, err := Settings(session, base) if err != nil || draft.Presentation.Speech.HardwareDevice != "/dev/fixture-synth" || draft.Presentation.Speech.HardwareBaudRate != 115200 { t.Fatal(draft, err) } focus_setting(t, session, "speech.driver") session.Handle(interaction.Key{Name: "down"}) discovery.Refresh_speech(session, &previous) for _, path := range []string{"presentation.speech.hardware_device", "presentation.speech.hardware_baud_rate", "presentation.speech.module", "presentation.speech.language", "presentation.speech.voice"} { if !session.Values()[path].Hidden { t.Fatal("irrelevant USB control visible", path) } } if session.Values()["presentation.speech.test"].Hidden { t.Fatal("USB test button hidden") } session.Handle(interaction.Key{Name: "up"}) discovery.Refresh_speech(session, &previous) draft, err = Settings(session, base) if err != nil || draft.Presentation.Speech.HardwareDevice != "/dev/fixture-synth" || draft.Presentation.Speech.HardwareBaudRate != 115200 { t.Fatal("driver round trip lost edits", draft, err) } session.Handle(interaction.Key{Name: "home"}) discovery.Refresh_speech(session, &previous) if !session.Values()["presentation.speech.test"].Hidden || session.Values()["presentation.speech.module"].Hidden { t.Fatal("Speech Dispatcher controls not restored") } } func TestEveryHardwareFormCanSavePortAndTypedBaud(t *testing.T) { for _, driver := range []string{"dectalk", "dectalk-usb", "litetalk", "doubletalk", "tripletalk"} { base := config.Defaults() base.Presentation.Speech.Driver = driver base.Presentation.Speech.HardwareDevice = "/dev/fixture-original" session, err := New_session(base, nil) if err != nil { t.Fatal(err) } if driver != "dectalk-usb" { focus_setting(t, session, "speech.hardware_device") session.Handle(interaction.Key{Ctrl: true, Text: "a"}) session.Handle(interaction.Key{Text: "/dev/fixture-updated"}) focus_setting(t, session, "speech.hardware_baud_rate") session.Handle(interaction.Key{Name: "home"}) session.Handle(interaction.Key{Name: "down"}) } draft, err := Settings(session, base) if err != nil { t.Fatal(driver, err) } if driver != "dectalk-usb" && (draft.Presentation.Speech.HardwareDevice != "/dev/fixture-updated" || draft.Presentation.Speech.HardwareBaudRate != 1200) { t.Fatal(draft) } if !session.Values()["presentation.speech.module"].Hidden { t.Fatal("dispatcher control exposed", driver) } if base.Presentation.Speech.HardwareDevice != "/dev/fixture-original" { t.Fatal("base mutated") } } }