After commit c018f5fd29 Fenrir is being switched over to go. If you do not want to be part of the testing process, please switch to master.
This commit is contained in:
1 parent
c018f5fd29
commit
0e50de4c76
1047 files changed
+58364
-63747
No files matched your search
@@ -0,0 +1,176 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"git.stormux.org/storm/fenrir/internal/config"
|
||||
"git.stormux.org/storm/fenrir/internal/control"
|
||||
"git.stormux.org/storm/fenrir/internal/presentation"
|
||||
)
|
||||
|
||||
func runtime_request(a *application, text string) string {
|
||||
reply := make(chan string, 1)
|
||||
a.remote_request(control.Request{UID: os.Geteuid(), Text: text, Reply: reply})
|
||||
return <-reply
|
||||
}
|
||||
|
||||
func TestRemoteTrackingSelectionAndAtomicFlags(t *testing.T) {
|
||||
for _, baseMode := range []string{"cursor", "table", "highlight"} {
|
||||
base := config.Defaults()
|
||||
base.Reading.Mode = baseMode
|
||||
for _, trial := range []struct{ text, mode string }{
|
||||
{"reading#mode=cursor", "cursor"},
|
||||
{"reading#mode=table", "table"},
|
||||
{"reading#mode=highlight", "highlight"},
|
||||
{"focus#cursor=False;focus#highlight=True", "highlight"},
|
||||
{"focus#highlight=True;focus#cursor=False", "highlight"},
|
||||
{"focus#highlight=False,focus#cursor=True", "cursor"},
|
||||
{"focus#cursor=False;focus#highlight=False", "table"},
|
||||
} {
|
||||
updated, err := remote_settings(base, "SET "+trial.text)
|
||||
if err != nil || updated.Reading.Mode != trial.mode {
|
||||
t.Fatal(baseMode, trial, updated.Reading.Mode, err)
|
||||
}
|
||||
}
|
||||
for _, invalid := range []string{
|
||||
"reading#mode=", "reading#mode=invalid", "reading#mode=CURSOR",
|
||||
"focus#cursor=invalid", "focus#cursor=True;focus#highlight=True",
|
||||
"reading#mode=cursor;focus#highlight=False",
|
||||
} {
|
||||
updated, err := remote_settings(base, "SET speech#enabled=False;"+invalid)
|
||||
if err == nil || !reflect.DeepEqual(updated, base) {
|
||||
t.Fatal("invalid selection partially applied", baseMode, invalid, updated, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoteTrackingLiveSaveResetAndGates(t *testing.T) {
|
||||
for _, terminalMode := range []bool{false, true} {
|
||||
a, _ := persistence_application(t, terminalMode)
|
||||
// A Python flag update must use the current mode for both live and
|
||||
// saved state, even when a menu draft chose a different startup mode.
|
||||
a.settings.saveDraft.Reading.Mode = "highlight"
|
||||
for _, text := range []string{"SETTING SET focus#cursor=False;focus#highlight=True", "SETTING SET reading#mode=highlight"} {
|
||||
a.settings.live.Remote.EnableSettingsRemote = false
|
||||
if runtime_request(a, text) == "" || a.engine.Tracking_mode() != "cursor" {
|
||||
t.Fatal("disabled remote changed mode")
|
||||
}
|
||||
a.settings.live.Remote.EnableSettingsRemote = true
|
||||
reply := make(chan string, 1)
|
||||
a.remote_request(control.Request{UID: os.Geteuid() + 1, Text: text, Reply: reply})
|
||||
if <-reply == "" || a.engine.Tracking_mode() != "cursor" {
|
||||
t.Fatal("unauthorized caller changed mode")
|
||||
}
|
||||
if response := runtime_request(a, text); response != "" || a.engine.Tracking_mode() != "highlight" || a.settings.saveDraft.Reading.Mode != "highlight" {
|
||||
t.Fatal("tracking not applied to live/draft", response)
|
||||
}
|
||||
if response := runtime_request(a, "SETTING RESET"); response != "" || a.engine.Tracking_mode() != "cursor" || a.settings.saveDraft.Reading.Mode != "cursor" {
|
||||
t.Fatal("reset did not restore tracking", response)
|
||||
}
|
||||
}
|
||||
a.settings.saveDraft.Reading.Mode = "highlight"
|
||||
if response := runtime_request(a, "SETTING SET focus#cursor=False"); response != "" || a.engine.Tracking_mode() != "table" || a.settings.saveDraft.Reading.Mode != "table" {
|
||||
t.Fatal("partial flag update used a stale saved mode", response)
|
||||
}
|
||||
reply := persistence_request(a, "SAVE")
|
||||
finish_persistence(t, a, false)
|
||||
persistence_reply(t, reply, false)
|
||||
saved, _, err := config.Load(a.options.ConfigPath, nil)
|
||||
if err != nil || saved.Reading.Mode != "table" {
|
||||
t.Fatal("remote tracking not saved", saved.Reading.Mode, err)
|
||||
}
|
||||
if response := runtime_request(a, "SETTING SET reading#mode=highlight"); response != "" {
|
||||
t.Fatal(response)
|
||||
}
|
||||
if response := runtime_request(a, "SETTING RESET"); response != "" || a.engine.Tracking_mode() != "table" {
|
||||
t.Fatal("reset lost saved tracking baseline", response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoteSpeechRestorationFeedbackAndAdmission(t *testing.T) {
|
||||
for _, terminalMode := range []bool{false, true} {
|
||||
for _, soundMode := range []string{"enabled", "disabled", "missing", "unavailable"} {
|
||||
a, voice := persistence_application(t, terminalMode)
|
||||
sounds := a.cues.(*fakeSounds)
|
||||
a.settings.live.Presentation.Sound.Enabled = soundMode != "disabled"
|
||||
if soundMode == "missing" {
|
||||
sounds.missing = map[presentation.Cue]bool{presentation.SpeechOn: true, presentation.SpeechOff: true}
|
||||
} else if soundMode == "unavailable" {
|
||||
a.cues = nil
|
||||
}
|
||||
voice.messages, sounds.cues = nil, nil
|
||||
for _, text := range []string{"SETTING SET speech#enabled=False", "COMMAND SAY discarded", "SETTING SET speech#enabled=True"} {
|
||||
if response := runtime_request(a, text); response != "" {
|
||||
t.Fatal(response)
|
||||
}
|
||||
}
|
||||
if a.muted || voice.muted || slices.Contains(voice.messages, "discarded") {
|
||||
t.Fatal("remote mute/restoration or discard failed", voice.messages)
|
||||
}
|
||||
if soundMode == "enabled" {
|
||||
if !reflect.DeepEqual(sounds.cues, []presentation.Cue{presentation.SpeechOff, presentation.SpeechOn}) || len(voice.messages) != 0 {
|
||||
t.Fatal("missing or duplicated mute feedback", sounds.cues, voice.messages)
|
||||
}
|
||||
} else if !reflect.DeepEqual(voice.messages, []string{"speech enabled"}) {
|
||||
t.Fatal("missing restoration speech fallback", soundMode, voice.messages)
|
||||
}
|
||||
voice.messages, sounds.cues = nil, nil
|
||||
if response := runtime_request(a, "SETTING SET speech#enabled=True"); response != "" || len(voice.messages)+len(sounds.cues) != 0 {
|
||||
t.Fatal("identical enable repeated feedback", response)
|
||||
}
|
||||
if response := runtime_request(a, "COMMAND TEMPDISABLESPEECH"); response != "" || !a.temporarySilence {
|
||||
t.Fatal("remote keypad action did not silence", response)
|
||||
}
|
||||
voice.messages, sounds.cues = nil, nil
|
||||
before := a.settings.saveDraft
|
||||
reply := make(chan string, 1)
|
||||
a.remote_request(control.Request{UID: os.Geteuid() + 1, Text: "SETTING SET speech#enabled=True", Reply: reply})
|
||||
if <-reply == "" || !a.temporarySilence {
|
||||
t.Fatal("unauthorized enable restored temporary silence")
|
||||
}
|
||||
a.settings.live.Remote.EnableSettingsRemote = false
|
||||
if response := runtime_request(a, "SETTING SET speech#enabled=True"); response == "" || !a.temporarySilence {
|
||||
t.Fatal("disabled remote enable restored temporary silence", response)
|
||||
}
|
||||
a.settings.live.Remote.EnableSettingsRemote = true
|
||||
for _, text := range []string{"SETTING SET speech#enabled=True;reading#mode=bad", "COMMAND TEMPDISABLESPEECH extra"} {
|
||||
if response := runtime_request(a, text); response == "" || !a.temporarySilence || !reflect.DeepEqual(a.settings.saveDraft, before) || len(voice.messages)+len(sounds.cues) != 0 {
|
||||
t.Fatal("invalid request restored speech or changed state", text, response)
|
||||
}
|
||||
}
|
||||
for _, text := range []string{"COMMAND SAY discarded", "SETTING SET reading#mode=highlight"} {
|
||||
if response := runtime_request(a, text); response != "" || !a.temporarySilence || len(voice.messages) != 0 {
|
||||
t.Fatal("unrelated request cleared temporary silence", text, response)
|
||||
}
|
||||
}
|
||||
if response := runtime_request(a, "SETTING SET speech#enabled=True"); response != "" || a.temporarySilence || a.muted {
|
||||
t.Fatal("explicit enable failed to restore temporary silence", response)
|
||||
}
|
||||
if soundMode == "enabled" {
|
||||
if !reflect.DeepEqual(sounds.cues, []presentation.Cue{presentation.SpeechOn}) || len(voice.messages) != 0 {
|
||||
t.Fatal("temporary restoration feedback", sounds.cues, voice.messages)
|
||||
}
|
||||
} else if !reflect.DeepEqual(voice.messages, []string{"speech enabled"}) {
|
||||
t.Fatal("temporary restoration fallback", soundMode, voice.messages)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoteNoArgumentCommandsRejectExtraParameters(t *testing.T) {
|
||||
a, voice := persistence_application(t, true)
|
||||
for _, verb := range []string{"INTERRUPT", "TEMPDISABLESPEECH", "QUITAPPLICATION", "EXPORTCLIPBOARD"} {
|
||||
before := voice.interrupts
|
||||
if response := runtime_request(a, "COMMAND "+verb+" extra"); response == "" || a.quitting || a.temporarySilence || voice.interrupts != before {
|
||||
t.Fatal("malformed command had side effects", verb, response)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user