diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-11 14:47:10 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-11 15:01:57 +0200 |
| commit | 42b02c47be9b285099203e44a2570636d4ca6f03 (patch) | |
| tree | 82bcb9e19bd886f36e1ca7b2d94a204c988f1fd1 /internal/config/settings_test.go | |
| download | krino-42b02c47be9b285099203e44a2570636d4ca6f03.tar.gz krino-42b02c47be9b285099203e44a2570636d4ca6f03.zip | |
krino: foundation — sexp reader, config language, init/new/check
Diffstat (limited to 'internal/config/settings_test.go')
| -rw-r--r-- | internal/config/settings_test.go | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/internal/config/settings_test.go b/internal/config/settings_test.go new file mode 100644 index 0000000..e46c880 --- /dev/null +++ b/internal/config/settings_test.go @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package config + +import ( + "reflect" + "testing" + "time" + + "krino/internal/sexp" +) + +func parseSettings(t *testing.T, src string) (Settings, []*Diag) { + t.Helper() + nodes, err := sexp.Parse("s.conf", []byte(src)) + if err != nil { + t.Fatal(err) + } + var s Settings + d := &diags{file: "s.conf"} + seen := map[string]*sexp.Node{} + for _, n := range nodes { + s.parse(n, d, seen) + } + return s, d.list +} + +func TestSettingsResolve(t *testing.T) { + s, errs := parseSettings(t, `(case strict) (fold no) (recursive yes) (max-depth 3) + (min-age 5m) (max-read 1G) (busy ".tmp") (on-conflict skip)`) + if len(errs) > 0 { + t.Fatal(errs) + } + want := Resolved{Case: CaseStrict, Fold: false, Recursive: true, MaxDepth: 3, + MinAge: 5 * time.Minute, MaxRead: 1 << 30, Busy: []string{".tmp"}, OnConflict: ConflictSkip} + if got := s.Over(Builtin()); !reflect.DeepEqual(got, want) { + t.Fatalf("got %+v\nwant %+v", got, want) + } +} + +func TestBuiltin(t *testing.T) { + want := Resolved{Case: CaseIgnore, Fold: true, MinAge: 2 * time.Minute, MaxRead: 50 << 20, + Busy: []string{".part", ".aria2", ".crdownload"}, OnConflict: ConflictSuffix} + if got := Builtin(); !reflect.DeepEqual(got, want) { + t.Fatalf("got %+v\nwant %+v", got, want) + } +} + +func TestSettingsLayering(t *testing.T) { + defaults, _ := parseSettings(t, `(min-age 5m) (fold no)`) + dir, _ := parseSettings(t, `(fold yes)`) + got := dir.Over(defaults.Over(Builtin())) + if got.MinAge != 5*time.Minute || !got.Fold || got.MaxRead != 50<<20 { + t.Fatalf("got %+v", got) + } +} + +func TestBusyEmptyDisables(t *testing.T) { + s, errs := parseSettings(t, `(busy)`) + if len(errs) > 0 || s.Busy == nil { + t.Fatalf("errs %v, busy %v", errs, s.Busy) + } + if got := s.Over(Builtin()).Busy; len(got) != 0 { + t.Fatalf("busy = %v, want none", got) + } +} + +func TestSettingErrors(t *testing.T) { + tests := []struct{ src, want string }{ + {`(case loud)`, `s.conf:1:7: case is ignore or strict, not loud`}, + {`(case "ignore")`, `s.conf:1:7: case values are bare words: write (case ignore)`}, + {`(fold)`, `s.conf:1:1: fold takes one value: (fold yes) or (fold no)`}, + {`(max-depth 0)`, `s.conf:1:12: max-depth is a whole number from 1, not 0`}, + {`(min-age soon)`, `s.conf:1:10: min-age: bad duration "soon": want a whole number followed by s, m, h, d or w, like 30d`}, + {`(max-read 5m)`, `s.conf:1:11: max-read: bad size "5m": want a whole number with an optional K, M, G or T, like 50M`}, + {`(busy part)`, `s.conf:1:7: busy takes strings, like ".part"; got part`}, + {`(fold yes) (fold no)`, `s.conf:1:12: fold set twice (first at line 1)`}, + } + for _, tt := range tests { + _, errs := parseSettings(t, tt.src) + if len(errs) != 1 || errs[0].Error() != tt.want { + t.Errorf("%s:\n got %v\n want %s", tt.src, errs, tt.want) + } + } +} |
