Files
ipswap/internal/config/config_test.go
T
bsncubed d93ae63156 Default the update repo to the Gitea host
Settles the first open question in claude.md: the update endpoint is
gitea.apointless.space/bsncubed/ipswap. It was left empty — which disables the
checker — only because the host was unconfirmed.

Load unmarshals over the defaults, so an absent update_repo takes the new
default while an explicitly empty one stays empty. That distinction is the off
switch, and forks depend on it, so it is now pinned by a test.

Adds the config package's first tests while here: the defaulting rules above,
the repair path for a nonsensical mask style or poll interval, and the
guarantee that a corrupt config.json still yields usable defaults rather than
stopping the app from starting.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 13:37:38 +10:00

99 lines
2.6 KiB
Go

package config
import (
"os"
"path/filepath"
"testing"
)
func TestLoadMissingFileReturnsDefaults(t *testing.T) {
s, err := Load(filepath.Join(t.TempDir(), "config.json"))
if err != nil {
t.Fatalf("a missing config must not be an error: %v", err)
}
if s != Default() {
t.Errorf("expected defaults, got %+v", s)
}
if s.UpdateRepo != DefaultUpdateRepo {
t.Errorf("update repo default = %q, want %q", s.UpdateRepo, DefaultUpdateRepo)
}
}
// An absent field takes the default, but an explicitly empty one must stay
// empty — that is how the update check is turned off.
func TestExplicitEmptyUpdateRepoDisablesTheCheck(t *testing.T) {
path := filepath.Join(t.TempDir(), "config.json")
if err := os.WriteFile(path, []byte(`{"update_repo": ""}`), 0o644); err != nil {
t.Fatal(err)
}
s, err := Load(path)
if err != nil {
t.Fatal(err)
}
if s.UpdateRepo != "" {
t.Errorf("an explicit empty update_repo must be preserved, got %q", s.UpdateRepo)
}
// The rest of the file was absent, so it should still be defaulted.
if s.ActivePollSeconds != Default().ActivePollSeconds {
t.Errorf("unset fields should keep their defaults, got %+v", s)
}
}
func TestLoadRepairsNonsense(t *testing.T) {
path := filepath.Join(t.TempDir(), "config.json")
if err := os.WriteFile(path, []byte(`{"mask_style":"wat","active_poll_seconds":0}`), 0o644); err != nil {
t.Fatal(err)
}
s, err := Load(path)
if err != nil {
t.Fatal(err)
}
if s.MaskStyle != MaskPrefix {
t.Errorf("an unknown mask style should fall back to prefix, got %q", s.MaskStyle)
}
if s.ActivePollSeconds != 30 {
t.Errorf("a zero poll interval should be repaired, got %d", s.ActivePollSeconds)
}
}
// A corrupt config must not stop the app from starting.
func TestLoadCorruptFileReturnsDefaultsAndError(t *testing.T) {
path := filepath.Join(t.TempDir(), "config.json")
if err := os.WriteFile(path, []byte(`{not json`), 0o644); err != nil {
t.Fatal(err)
}
s, err := Load(path)
if err == nil {
t.Error("expected an error for a corrupt config")
}
if s != Default() {
t.Errorf("a corrupt config should still yield usable defaults, got %+v", s)
}
}
func TestSaveRoundTrip(t *testing.T) {
path := filepath.Join(t.TempDir(), "nested", "config.json")
want := Default()
want.MaskStyle = MaskDotted
want.StartWithWindows = true
want.UpdateRepo = "https://example.com/o/r"
if err := want.Save(path); err != nil {
t.Fatal(err)
}
got, err := Load(path)
if err != nil {
t.Fatal(err)
}
if got != want {
t.Errorf("round trip changed the settings:\n got %+v\nwant %+v", got, want)
}
if !got.DottedMasks() {
t.Error("DottedMasks should be true for MaskDotted")
}
}