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:
Storm Dragon committed 2026-10-27 20:30:55 -04:00
1 parent c018f5fd29
commit 0e50de4c76
1047 files changed
+58364 -63747

No files matched your search

+119
View File
@@ -0,0 +1,119 @@
// Copyright (c) 2026 Storm Dragon
// SPDX-License-Identifier: GPL-3.0-or-later
package app
import (
"context"
"path/filepath"
"slices"
"strings"
"testing"
"time"
"git.stormux.org/storm/fenrir/internal/command"
"git.stormux.org/storm/fenrir/internal/config"
"git.stormux.org/storm/fenrir/internal/control"
"git.stormux.org/storm/fenrir/internal/input"
"git.stormux.org/storm/fenrir/internal/screen"
)
func TestMenuRemoteAndQuickSavePreserveNextLaunchChoices(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
path := filepath.Join(t.TempDir(), "settings.toml")
base := config.Defaults()
source := &fakeSource{snapshot: screen.Snapshot{Terminal: 1, Active: true, Rows: 1, Cols: 5, Cells: []rune("alpha")}}
voice := &fakeVoice{}
keys := &fakeKeys{poll: func(bool, func(input.Decision)) error { return nil }}
a, err := new_application(ctx, source, keys, voice, RunOptions{Settings: base, ConfigPath: path})
if err != nil {
t.Fatal(err)
}
defer a.ui.close()
// Exercise the successful menu-save callback with both live and next-launch
// choices, then interleave session commands, remote changes and a quick save.
menuSaved := base
menuSaved.Keyboard.Layout = "laptop"
menuSaved.Presentation.Speech.Module = "next-module"
menuSaved.Presentation.Speech.Rate = 60
menuSaved.Review.LineBreak = false
menuSaved.Presentation.Sound.Driver = "alsa"
menuSaved.Presentation.Sound.Theme = "fixture-pack"
menuSaved.Presentation.Sound.Device = "null"
if err := config.Save(path, menuSaved); err != nil {
t.Fatal(err)
}
a.apply_saved_settings(menuSaved, false)
if a.settings.live.Keyboard.Layout != base.Keyboard.Layout || a.settings.live.Presentation.Speech.Module != base.Presentation.Speech.Module || a.settings.live.Review != base.Review || a.settings.live.Presentation.Sound != base.Presentation.Sound {
t.Fatal("next-launch choices changed the running configuration")
}
if len(voice.parameters) == 0 || voice.parameters[len(voice.parameters)-1].Rate != 60 {
t.Fatal("menu speech adjustment did not apply live", voice.parameters)
}
for _, id := range []command.ID{command.Mute, command.AutoRead, command.ToggleAttributes} {
a.handle_input(input.Decision{Command: id})
}
for _, request := range []struct {
text string
want string
}{
{"SETTING SET speech#enabled=True;unknown#setting=True", "Unsupported remote setting"},
{"SETTING SET keyboard#word_echo=True", ""},
} {
replies := make(chan string, 1)
a.remote_request(control.Request{UID: 0, Text: request.text, Reply: replies})
if reply := <-replies; !strings.HasPrefix(reply, request.want) || request.want == "" && reply != "" {
t.Fatal("unexpected remote response", reply)
}
if !voice.muted || a.engine.Automatic_reading() {
t.Fatal("remote assignment changed unrelated session state")
}
}
for _, id := range []command.ID{command.NextQuickValue, command.SaveSettings, command.Quit} {
a.handle_input(input.Decision{Command: id})
}
if err := a.loop(nil); err != nil || ctx.Err() != nil {
t.Fatal("save and quit failed", err, ctx.Err())
}
saved, _, err := config.Load(path, nil)
if err != nil {
t.Fatal(err)
}
want := menuSaved
want.Keyboard.WordEcho = true
want.Presentation.Speech.Rate = 70
if saved.Keyboard.Layout != want.Keyboard.Layout || saved.Presentation.Speech.Module != want.Presentation.Speech.Module || saved.Review != want.Review || saved.Presentation.Speech.Rate != want.Presentation.Speech.Rate || !saved.Keyboard.WordEcho || saved.Presentation.Sound != want.Presentation.Sound {
t.Fatal("mixed settings paths lost saved choices", saved)
}
if !saved.Presentation.Speech.Enabled || !saved.Reading.Automatic || saved.Reading.Attributes != base.Reading.Attributes {
t.Fatal("session overrides leaked into the save", saved)
}
freshVoice := &fakeVoice{}
fresh, err := new_application(ctx, source, &fakeKeys{}, freshVoice, RunOptions{Settings: saved})
if err != nil {
t.Fatal(err)
}
defer fresh.ui.close()
if err := fresh.read_screen(); err != nil || !slices.Contains(freshVoice.messages, "alpha") {
t.Fatal("saved defaults did not restore startup reading", err, freshVoice.messages)
}
}
func TestRemoteCannotEnableSpeechWithoutStartupConnection(t *testing.T) {
base := config.Defaults()
base.Presentation.Speech.Enabled = false
a, err := new_application(context.Background(), &fakeSource{}, &fakeKeys{}, disabledVoice{}, RunOptions{Settings: base})
if err != nil {
t.Fatal(err)
}
defer a.ui.close()
response := a.apply_remote_settings("SET speech#enabled=True;keyboard#word_echo=True")
if response != "Speech was disabled at startup; enable it in settings and relaunch" {
t.Fatal(response)
}
if !a.muted || a.settings.live.Presentation.Speech.Enabled || a.settings.live.Keyboard.WordEcho || a.settings.saveDraft.Presentation.Speech.Enabled || a.settings.saveDraft.Keyboard.WordEcho {
t.Fatal("rejected request partially changed live or saved settings")
}
}