113 lines
3.6 KiB
Go
113 lines
3.6 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package app
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.stormux.org/storm/fenrir/internal/command"
|
|
"git.stormux.org/storm/fenrir/internal/config"
|
|
"git.stormux.org/storm/fenrir/internal/datetime"
|
|
"git.stormux.org/storm/fenrir/internal/input"
|
|
"git.stormux.org/storm/fenrir/internal/interaction"
|
|
"git.stormux.org/storm/fenrir/internal/screen"
|
|
)
|
|
|
|
func TestTimeDateMenuAppliesOnlyAfterSave(t *testing.T) {
|
|
for _, action := range []string{"save", "cancel", "failed save"} {
|
|
t.Run(action, func(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "settings.toml")
|
|
// Put this group first to exercise its controls directly.
|
|
original := "version=3\n[presentation.time_and_date]\ntime_format='24-hour-seconds'\ndate_format='numbers-ymd'\n"
|
|
if err := os.WriteFile(path, []byte(original), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
settings, err := config.Decode([]byte(original))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
source := &fakeSource{snapshot: screen.Snapshot{Terminal: 1, Active: true}}
|
|
keys, voice := &fakeKeys{events: make(chan error, 4)}, &fakeVoice{}
|
|
keys.onCapture = func(enabled bool) {
|
|
if !enabled {
|
|
keys.events <- nil
|
|
}
|
|
}
|
|
voice.onSay = func(text string) {
|
|
if strings.HasPrefix(text, "Fenrir Menu.") || strings.HasPrefix(text, "Could not save settings:") {
|
|
keys.events <- nil
|
|
}
|
|
}
|
|
step := 0
|
|
keys.poll = func(_ bool, handle func(input.Decision)) error {
|
|
step++
|
|
key := func(name string, shift bool) { handle(input.Decision{UI: &interaction.Key{Name: name, Shift: shift}}) }
|
|
switch step {
|
|
case 1:
|
|
handle(input.Decision{Command: command.FenrirMenu})
|
|
case 2:
|
|
key("tab", false)
|
|
key("down", false) // 24-hour-seconds -> 24-hour-seconds-words.
|
|
key("tab", false)
|
|
key("down", false) // numbers-ymd -> full-dm.
|
|
if action == "cancel" {
|
|
key("escape", false)
|
|
break
|
|
}
|
|
if action == "failed save" {
|
|
if err := os.WriteFile(path, []byte(original+"# external edit\n"), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
for range 4 {
|
|
key("tab", true)
|
|
}
|
|
key("enter", false)
|
|
case 3:
|
|
if action == "failed save" {
|
|
key("escape", false)
|
|
}
|
|
formats := settings.Presentation.DateTime
|
|
if action == "save" {
|
|
formats.TimeFormat, formats.DateFormat = "24-hour-seconds-words", "full-dm"
|
|
}
|
|
for _, id := range []command.ID{command.Time, command.Date} {
|
|
format, value := datetime.Format_time, formats.TimeFormat
|
|
if id == command.Date {
|
|
format, value = datetime.Format_date, formats.DateFormat
|
|
}
|
|
before, _ := format(value, time.Now())
|
|
handle(input.Decision{Command: id, Interrupt: true})
|
|
after, _ := format(value, time.Now())
|
|
got := voice.messages[len(voice.messages)-1]
|
|
if got != before && got != after {
|
|
t.Fatal("running format", id, got, before, after)
|
|
}
|
|
}
|
|
handle(input.Decision{Command: command.Quit})
|
|
}
|
|
return nil
|
|
}
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
defer cancel()
|
|
if err := run(ctx, source, keys, voice, nil, RunOptions{Settings: settings, ConfigPath: path}); err != nil || step != 3 {
|
|
t.Fatal(err, step, voice.messages)
|
|
}
|
|
loaded, _, err := config.Load(path, nil)
|
|
want := settings.Presentation.DateTime
|
|
if action == "save" {
|
|
want.TimeFormat, want.DateFormat = "24-hour-seconds-words", "full-dm"
|
|
}
|
|
if err != nil || loaded.Presentation.DateTime != want {
|
|
t.Fatal("saved formats", loaded.Presentation.DateTime, err)
|
|
}
|
|
})
|
|
}
|
|
}
|