diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-17 00:23:51 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-17 00:23:51 +0200 |
| commit | 04b4243ad31d144c4caf9be4c5096a0f27a2648e (patch) | |
| tree | 056515d145ba8e4fba29a2150b2c58199133b0c1 /gui/internal/model/mainconf_test.go | |
| parent | 9db67b201b80e9b7f824989df8517cefc587036d (diff) | |
| download | krino-04b4243ad31d144c4caf9be4c5096a0f27a2648e.tar.gz krino-04b4243ad31d144c4caf9be4c5096a0f27a2648e.zip | |
gui: syntax colours, a file preview, and a settings window
Diffstat (limited to 'gui/internal/model/mainconf_test.go')
| -rw-r--r-- | gui/internal/model/mainconf_test.go | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/gui/internal/model/mainconf_test.go b/gui/internal/model/mainconf_test.go new file mode 100644 index 0000000..bae739a --- /dev/null +++ b/gui/internal/model/mainconf_test.go @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package model + +import ( + "errors" + "os" + "path/filepath" + "strings" + "testing" + + "krino/internal/engine" +) + +// mainConf opens krino.conf over a sandbox whose main file holds text. +func mainConf(t *testing.T, main string) (*MainConf, *engine.Engine, string) { + t.Helper() + e, h := sandboxDir(t, "(path \"~/dl\")\n(rule \"all\" (move \"Out\"))\n", + map[string]string{"a.pdf": "one"}) + if main != "" { + if err := os.WriteFile(e.MainFile, []byte(main), 0o644); err != nil { + t.Fatal(err) + } + reloaded, diags := engine.Load(e.MainFile) + if len(diags) > 0 { + t.Fatalf("the fixture does not load: %v", diags) + } + e = reloaded + } + m, err := OpenMain(e) + if err != nil { + t.Fatal(err) + } + return m, e, h +} + +// TestMainSettingsReadAndWrite: a default is read as written, changed in +// place, and taken out again, with everything else in the file untouched. +func TestMainSettingsReadAndWrite(t *testing.T) { + main := ";; the main file\n(include \"dl\")\n\n(defaults\n (min-age 2m) ; leave fresh files\n (on-conflict suffix))\n" + m, _, _ := mainConf(t, main) + + if args, set, err := m.Setting("min-age"); err != nil || !set || args != "2m" { + t.Errorf("min-age = %q, %v, %v", args, set, err) + } + if _, set, _ := m.Setting("fold"); set { + t.Error("fold reads as set") + } + if err := m.SetSetting("min-age", "1d"); err != nil { + t.Fatal(err) + } + if !strings.Contains(m.Text, "(min-age 1d)") || strings.Contains(m.Text, "(min-age 2m)") { + t.Errorf("min-age not rewritten:\n%s", m.Text) + } + for _, keep := range []string{";; the main file", "(include \"dl\")", "; leave fresh files", + "(on-conflict suffix)"} { + if !strings.Contains(m.Text, keep) { + t.Errorf("writing one setting lost %q:\n%s", keep, m.Text) + } + } + // A setting the file does not have goes inside (defaults ...). + if err := m.SetSetting("fold", "no"); err != nil { + t.Fatal(err) + } + if !strings.Contains(m.Text, "(fold no)") { + t.Errorf("fold not written:\n%s", m.Text) + } + if strings.Index(m.Text, "(fold no)") < strings.Index(m.Text, "(defaults") { + t.Errorf("fold landed outside the defaults:\n%s", m.Text) + } + if diags := m.Check(); len(diags) > 0 { + t.Fatalf("the file no longer loads: %v", diags) + } + // And out again. + if err := m.SetSetting("min-age", ""); err != nil { + t.Fatal(err) + } + if strings.Contains(m.Text, "min-age") { + t.Errorf("min-age still there:\n%s", m.Text) + } + if diags := m.Check(); len(diags) > 0 { + t.Errorf("the file no longer loads: %v", diags) + } +} + +// TestMainSettingsWithoutADefaultsForm: a file with no (defaults ...) gets +// one, and it loads. +func TestMainSettingsWithoutADefaultsForm(t *testing.T) { + m, _, _ := mainConf(t, "(include \"dl\")\n") + if err := m.SetSetting("recursive", "yes"); err != nil { + t.Fatal(err) + } + if !strings.Contains(m.Text, "(defaults") || !strings.Contains(m.Text, "(recursive yes)") { + t.Errorf("no defaults form was written:\n%s", m.Text) + } + if diags := m.Check(); len(diags) > 0 { + t.Errorf("the file no longer loads: %v", diags) + } +} + +// TestMainLogIsTopLevel: the log path is not a default; it is written at +// the top level, where krino.conf(5) puts it. +func TestMainLogIsTopLevel(t *testing.T) { + m, _, h := mainConf(t, "(include \"dl\")\n") + if err := m.SetSetting("log", "\"~/tmp/krino.log\""); err != nil { + t.Fatal(err) + } + if strings.Contains(m.Text, "(defaults") { + t.Errorf("the log went into the defaults:\n%s", m.Text) + } + if diags := m.Check(); len(diags) > 0 { + t.Fatalf("the file no longer loads: %v", diags) + } + if err := m.Save(); err != nil { + t.Fatal(err) + } + e, diags := engine.Load(filepath.Join(h, ".config", "krino", "krino.conf")) + if len(diags) > 0 { + t.Fatal(diags) + } + if !strings.HasSuffix(e.Config.LogFile(), "tmp/krino.log") { + t.Errorf("the saved log path is not in effect: %s", e.Config.LogFile()) + } +} + +// TestMainSaveGuards: krino.conf is saved by the same rules as a directory +// file - never broken, never over someone else's edit, and the previous +// text is kept. +func TestMainSaveGuards(t *testing.T) { + main := "(include \"dl\")\n" + m, _, _ := mainConf(t, main) + + m.Text = "(include \"dl\")\n(defaults (min-age nonsense))\n" + if err := m.Save(); err == nil { + t.Error("a file that will not load was saved") + } + if on, _ := os.ReadFile(m.File); string(on) != main { + t.Errorf("the refused save wrote anyway: %q", on) + } + + m.Text = "(include \"dl\")\n(defaults (min-age 1d))\n" + if err := m.Save(); err != nil { + t.Fatal(err) + } + if on, _ := os.ReadFile(m.File + ".bak"); string(on) != main { + t.Errorf("backup = %q, want the previous text", on) + } + + // Someone else edits it, and the next save refuses. + if err := os.WriteFile(m.File, []byte("(include \"dl\")\n;; theirs\n"), 0o644); err != nil { + t.Fatal(err) + } + m.Text = "(include \"dl\")\n;; mine\n" + if err := m.Save(); !errors.Is(err, ErrChangedOnDisk) { + t.Errorf("Save = %v, want ErrChangedOnDisk", err) + } +} + +// TestMainSettingRefusesAnUnknownHead: only the settings krino.conf(5) +// documents can be written this way. +func TestMainSettingRefusesAnUnknownHead(t *testing.T) { + m, _, _ := mainConf(t, "(include \"dl\")\n") + if err := m.SetSetting("nonsense", "1"); err == nil { + t.Error("an unknown setting was accepted") + } + if _, _, err := m.Setting("nonsense"); err == nil { + t.Error("an unknown setting was read") + } +} |
