aboutsummaryrefslogtreecommitdiff
path: root/cmd/krino/exclude_test.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-09-14 14:08:36 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-09-14 14:08:36 +0200
commit1d3f2d1e4c59867024470d3444e12698b7ebb22e (patch)
tree4fa14f455c72f9b206a680dcc1b0f4c1f3708158 /cmd/krino/exclude_test.go
parent07c24054cab965800983ef40f53a05c2db131ede (diff)
downloadkrino-1d3f2d1e4c59867024470d3444e12698b7ebb22e.tar.gz
krino-1d3f2d1e4c59867024470d3444e12698b7ebb22e.zip
0.0.4: max-size, exclude forms, --min-agev0.0.4
Diffstat (limited to 'cmd/krino/exclude_test.go')
-rw-r--r--cmd/krino/exclude_test.go136
1 files changed, 136 insertions, 0 deletions
diff --git a/cmd/krino/exclude_test.go b/cmd/krino/exclude_test.go
new file mode 100644
index 0000000..2e9ff2a
--- /dev/null
+++ b/cmd/krino/exclude_test.go
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package main
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+ "time"
+
+ "krino/internal/engine"
+ "krino/internal/scan"
+)
+
+// excludeFixture makes ~/dl with an old a.iso, an old keep.txt and a fresh
+// new.txt, a krino.conf excluding iso files everywhere, and dl's own rules:
+// exclude names starting with "draft", move everything else to Out.
+func excludeFixture(t *testing.T) string {
+ t.Helper()
+ h := home(t)
+ dl := filepath.Join(h, "dl")
+ old := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
+ for name, mt := range map[string]time.Time{"a.iso": old, "keep.txt": old, "draft.txt": old, "new.txt": time.Now()} {
+ p := filepath.Join(dl, name)
+ if err := os.MkdirAll(dl, 0o755); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(p, []byte("x"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.Chtimes(p, mt, mt); err != nil {
+ t.Fatal(err)
+ }
+ }
+ if code, _, errOut := runCLI(t, "init"); code != 0 {
+ t.Fatal(errOut)
+ }
+ if code, _, errOut := runCLI(t, "new", "dl", dl); code != 0 {
+ t.Fatal(errOut)
+ }
+ cfg := filepath.Join(h, ".config", "krino")
+ mainConf, err := os.ReadFile(filepath.Join(cfg, "krino.conf"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(cfg, "krino.conf"), append(mainConf, []byte("\n(exclude (type iso))\n")...), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ rules := "(path \"~/dl\")\n(exclude (name \"^draft\"))\n(rule \"all\" (move \"Out\"))\n"
+ if err := os.WriteFile(filepath.Join(cfg, "dirs", "dl.conf"), []byte(rules), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ return h
+}
+
+// TestMinAgeFlagOverridesTheSetting: --min-age changes "too new" for one
+// run, in either position, and a bad value is a usage error before anything
+// is read.
+func TestMinAgeFlagOverridesTheSetting(t *testing.T) {
+ excludeFixture(t)
+ _, out, _ := runCLI(t, "-n")
+ if strings.Contains(out, "new.txt") || !strings.Contains(out, "1 too new") {
+ t.Errorf("without the flag new.txt should be too new:\n%s", out)
+ }
+ for _, args := range [][]string{{"--min-age", "0", "-n"}, {"-n", "--min-age", "0s"}} {
+ code, out, errOut := runCLI(t, args...)
+ if code != 0 || !strings.Contains(out, " new.txt\n") || strings.Contains(out, "too new") {
+ t.Errorf("%v: exit %d, new.txt should be planned:\n%s\n%s", args, code, out, errOut)
+ }
+ }
+ code, _, errOut := runCLI(t, "--min-age", "soon", "-n")
+ if code != 2 || !strings.Contains(errOut, "--min-age") {
+ t.Errorf("--min-age soon: exit %d, stderr %q; want 2 naming --min-age", code, errOut)
+ }
+}
+
+// TestVerboseListsExcludedFiles: with -v, the plan lists each excluded file
+// with the exclude that set it aside; the counts line counts them.
+func TestVerboseListsExcludedFiles(t *testing.T) {
+ excludeFixture(t)
+ code, out, errOut := runCLI(t, "-n", "-v")
+ if code != 0 {
+ t.Fatalf("exit %d: %s", code, errOut)
+ }
+ for _, want := range []string{
+ "2 excluded",
+ "\nexcluded\n a.iso (exclude (type iso))\n draft.txt (exclude (name \"^draft\"))\n",
+ } {
+ if !strings.Contains(out, want) {
+ t.Errorf("output lacks %q:\n%s", want, out)
+ }
+ }
+}
+
+// TestCheckListsExclusions: check shows each directory's exclusions, the
+// krino.conf ones first, before its rules.
+func TestCheckListsExclusions(t *testing.T) {
+ excludeFixture(t)
+ code, out, errOut := runCLI(t, "check")
+ if code != 0 {
+ t.Fatalf("exit %d: %s", code, errOut)
+ }
+ want := " (exclude (type iso))\n (exclude (name \"^draft\"))\n 1 all"
+ if !strings.Contains(out, want) {
+ t.Errorf("check output lacks %q:\n%s", want, out)
+ }
+}
+
+// TestExplainShowsExclusion: explain says which exclude sets the file
+// aside and traces every exclude.
+func TestExplainShowsExclusion(t *testing.T) {
+ h := excludeFixture(t)
+ code, out, errOut := runCLI(t, "explain", filepath.Join(h, "dl", "a.iso"))
+ if code != 0 {
+ t.Fatalf("exit %d: %s", code, errOut)
+ }
+ for _, want := range []string{
+ "krino would set this file aside: (exclude (type iso))\n",
+ "(exclude (type iso)): MATCH\n",
+ "(exclude (name \"^draft\")): no\n",
+ } {
+ if !strings.Contains(out, want) {
+ t.Errorf("explain output lacks %q:\n%s", want, out)
+ }
+ }
+}
+
+// TestSkipSummaryCountsTooBig: a file skipped for max-size is counted as
+// too big in the "not acted on" line.
+func TestSkipSummaryCountsTooBig(t *testing.T) {
+ r := &engine.Result{Skipped: []scan.Skipped{{Rel: "big.iso", Reason: scan.TooBig}}}
+ if got := skipSummaryLine(r, nil, false); !strings.Contains(got, "1 too big") {
+ t.Errorf("line = %q, want 1 too big", got)
+ }
+}