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
86
87
88
89
90
91
92
93
94
95
|
// SPDX-License-Identifier: GPL-3.0-or-later
package model
import (
"os"
"path/filepath"
"testing"
"time"
)
// names is the rows an order leaves, for the assertions below.
func names(t *PlanTab, shown []int) []string {
var out []string
for _, i := range shown {
out = append(out, t.Rows[i].Rel)
}
return out
}
func same(a []string, b ...string) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
// TestSorted: each order reads the way its label says, and the default
// leaves the plan as krino made it.
func TestSorted(t *testing.T) {
conf := "(path \"~/dl\")\n" +
"(rule \"pdfs\" (when (type pdf)) (move \"Docs\") (stop))\n" +
"(rule \"rest\" (move \"Other\"))\n"
e, h := sandboxDir(t, conf, map[string]string{
"big.pdf": "0123456789abcdef", "small.txt": "x", "middle.pdf": "0123456789",
})
// Distinct times, so age has something to order by.
now := time.Now()
for name, ago := range map[string]time.Duration{
"big.pdf": 3 * time.Hour, "small.txt": 90 * 24 * time.Hour, "middle.pdf": 24 * time.Hour,
} {
p := filepath.Join(h, "dl", name)
when := now.Add(-ago)
if err := os.Chtimes(p, when, when); err != nil {
t.Fatal(err)
}
}
tab := planTab(t, e)
all := tab.Matching("")
if got := names(tab, tab.Sorted(all, SortDefault)); len(got) != 3 {
t.Fatalf("default = %v", got)
}
if got := names(tab, tab.Sorted(all, SortName)); !same(got, "big.pdf", "middle.pdf", "small.txt") {
t.Errorf("by name = %v", got)
}
if got := names(tab, tab.Sorted(all, SortSize)); !same(got, "big.pdf", "middle.pdf", "small.txt") {
t.Errorf("by size = %v", got)
}
if got := names(tab, tab.Sorted(all, SortAge)); !same(got, "small.txt", "middle.pdf", "big.pdf") {
t.Errorf("by age = %v, want the oldest first", got)
}
if got := names(tab, tab.Sorted(all, SortRule)); !same(got, "big.pdf", "middle.pdf", "small.txt") {
t.Errorf("by rule = %v, want pdfs before rest", got)
}
// An order krino does not know leaves the plan alone rather than
// guessing at one.
if got := names(tab, tab.Sorted(all, "nonsense")); !same(got, names(tab, all)...) {
t.Errorf("an unknown order changed the list: %v", got)
}
// Sorting never changes the plan itself.
if len(tab.Rows) != 3 || tab.Rows[0].Rel != names(tab, all)[0] {
t.Error("the plan's own order changed")
}
}
// TestSortedIsStable: files that compare the same keep the plan's order, so
// the list does not shuffle under the eye.
func TestSortedIsStable(t *testing.T) {
conf := "(path \"~/dl\")\n(rule \"all\" (move \"Out\"))\n"
e, _ := sandboxDir(t, conf, map[string]string{"a.txt": "x", "b.txt": "x", "c.txt": "x"})
tab := planTab(t, e)
all := tab.Matching("")
first := names(tab, tab.Sorted(all, SortSize))
for i := 0; i < 5; i++ {
if got := names(tab, tab.Sorted(all, SortSize)); !same(got, first...) {
t.Fatalf("run %d = %v, want %v", i, got, first)
}
}
}
|