summaryrefslogtreecommitdiff
path: root/internal/config/settings_test.go
blob: e46c8809936c6ec2b3e78e9143b7bc3d01375550 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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)
		}
	}
}