140 lines
5.4 KiB
Go
140 lines
5.4 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package app
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"log/slog"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"git.stormux.org/storm/cthulhu/internal/config"
|
|
"git.stormux.org/storm/cthulhu/internal/input"
|
|
"git.stormux.org/storm/cthulhu/internal/preferences"
|
|
)
|
|
|
|
func TestLaptopLayoutSessionAndExplicitPreferences(t *testing.T) {
|
|
global := config.DefaultSettings()
|
|
global.Path = filepath.Join(t.TempDir(), "settings.toml")
|
|
store, err := config.NewStore(global.Path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := store.Save(global); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
app := global
|
|
app.CthulhuModifierKeys = []string{"Insert"}
|
|
app.TimeFormat = "24-hour"
|
|
for _, name := range []string{"Cached Application", "New Application"} {
|
|
if err := store.SaveForApplication(name, app); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
original, err := os.ReadFile(global.Path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
worker := newPreferencesWorker(slog.New(slog.DiscardHandler), global, acceptingRemoteSpeechSettings{})
|
|
worker.laptopLayout = true
|
|
worker.settings = worker.sessionKeyboard(global)
|
|
worker.live = &liveSettings{}
|
|
worker.live.Store(worker.settings)
|
|
recorder := &keyboardRecorder{}
|
|
worker.bindings = recorder
|
|
checkLaptop := func(settings config.Settings) {
|
|
t.Helper()
|
|
if settings.KeyboardLayout != int(input.LaptopKeyboardLayout) ||
|
|
!reflect.DeepEqual(settings.CthulhuModifierKeys, []string{"Caps_Lock"}) {
|
|
t.Fatalf("laptop keyboard lost: layout=%d keys=%v", settings.KeyboardLayout, settings.CthulhuModifierKeys)
|
|
}
|
|
}
|
|
checkLaptop(worker.settings)
|
|
worker.cycle_progress_output()
|
|
if worker.globalSettings.KeyboardLayout != global.KeyboardLayout || !reflect.DeepEqual(worker.globalSettings.CthulhuModifierKeys, global.CthulhuModifierKeys) {
|
|
t.Fatal("progress shortcut cached the startup keyboard in global settings")
|
|
}
|
|
for _, name := range []string{"Cached Application", "Other Application", "Cached Application", "New Application"} {
|
|
worker.switchApplication(t.Context(), name)
|
|
if worker.activeApp != name {
|
|
t.Fatal("application switch failed")
|
|
}
|
|
checkLaptop(worker.settings)
|
|
checkLaptop(worker.live.Load())
|
|
if name != "Other Application" && worker.settings.TimeFormat != "24-hour" {
|
|
t.Fatal("startup keyboard override discarded application preferences")
|
|
}
|
|
}
|
|
current, err := os.ReadFile(global.Path)
|
|
if err != nil || !bytes.Equal(current, original) {
|
|
t.Fatalf("switching applications saved the override: %v", err)
|
|
}
|
|
// A remote session change and the speech-save shortcut must not promote
|
|
// the startup keyboard override into global or cached profile settings.
|
|
next := worker.settings
|
|
next.EnableKeyEcho = true
|
|
if response := worker.applyNext(t.Context(), next, false, false); !response.Accepted {
|
|
t.Fatal(response.Message)
|
|
}
|
|
worker.cycle_progress_output()
|
|
cached := worker.appSettings[worker.activeApp]
|
|
if cached.KeyboardLayout != app.KeyboardLayout || !reflect.DeepEqual(cached.CthulhuModifierKeys, app.CthulhuModifierKeys) {
|
|
t.Fatal("session changes cached the startup keyboard in application settings")
|
|
}
|
|
worker.handleSpeechCommand(t.Context(), input.IncreaseSpeechSetting)
|
|
worker.handleSpeechCommand(t.Context(), input.SaveSpeechSettings)
|
|
loaded, err := store.Load()
|
|
if err != nil || loaded.KeyboardLayout != global.KeyboardLayout || !reflect.DeepEqual(loaded.CthulhuModifierKeys, global.CthulhuModifierKeys) {
|
|
t.Fatalf("speech save changed the saved keyboard: %v", err)
|
|
}
|
|
worker.switchApplication(t.Context(), "Other Application")
|
|
worker.switchApplication(t.Context(), "New Application")
|
|
checkLaptop(worker.settings)
|
|
if !worker.settings.EnableKeyEcho {
|
|
t.Fatal("remote application change was lost")
|
|
}
|
|
if !worker.beginEdit(t.Context(), "") {
|
|
t.Fatal("could not open global preferences")
|
|
}
|
|
checkLaptop(worker.editing)
|
|
values := preferences.FromSettings(worker.editing)
|
|
values.KeyboardLayout = global.KeyboardLayout
|
|
values.CthulhuModifierKeys = global.CthulhuModifierKeys
|
|
recorder.err = errors.New("grab conflict")
|
|
if response := worker.apply(t.Context(), preferences.Request{Values: values}); response.Accepted || !worker.laptopLayout {
|
|
t.Fatal("failed preferences apply discarded the startup override")
|
|
}
|
|
checkLaptop(worker.settings)
|
|
// Saving the displayed laptop choice explicitly makes it permanent.
|
|
recorder.err = nil
|
|
values = preferences.FromSettings(worker.editing)
|
|
if response := worker.apply(t.Context(), preferences.Request{Values: values, Save: true}); !response.Accepted || worker.laptopLayout {
|
|
t.Fatalf("explicit save did not replace the startup override: %+v", response)
|
|
}
|
|
loaded, err = store.Load()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
checkLaptop(loaded)
|
|
worker.editingActive = false
|
|
if !worker.beginEdit(t.Context(), "") {
|
|
t.Fatal("could not reopen preferences")
|
|
}
|
|
values = preferences.FromSettings(worker.editing)
|
|
values.KeyboardLayout = global.KeyboardLayout
|
|
values.CthulhuModifierKeys = global.CthulhuModifierKeys
|
|
if response := worker.apply(t.Context(), preferences.Request{Values: values}); !response.Accepted {
|
|
t.Fatal(response.Message)
|
|
}
|
|
worker.editingActive = false
|
|
worker.switchApplication(t.Context(), "Another Application")
|
|
if worker.settings.KeyboardLayout != global.KeyboardLayout || !reflect.DeepEqual(worker.settings.CthulhuModifierKeys, global.CthulhuModifierKeys) {
|
|
t.Fatal("preferences could not replace the laptop keyboard for the session")
|
|
}
|
|
}
|