aboutsummaryrefslogtreecommitdiff
path: root/cmd/krino/sort_test.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-09-13 02:31:32 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-09-13 02:31:32 +0200
commit26c94eb3db62ec6eebbf8d22c11afe691d9520c4 (patch)
tree165e5bf69234b4f96c9b74deb4898d7143ddf120 /cmd/krino/sort_test.go
parenta6e442a645902011b2081c216daaec052cdc6ce6 (diff)
downloadkrino-26c94eb3db62ec6eebbf8d22c11afe691d9520c4.tar.gz
krino-26c94eb3db62ec6eebbf8d22c11afe691d9520c4.zip
krino: release 0.0.1 — man pages, install, examples, cross and release, README, changelogv0.0.1
Also: undo removes the directories its run created; a hardlink is never a duplicate of its own other name; a flag written before "undo" is honoured; --version prints no leading v. Duplicate conditions with different scopes not sharing an original is documented as a known limitation.
Diffstat (limited to 'cmd/krino/sort_test.go')
-rw-r--r--cmd/krino/sort_test.go63
1 files changed, 63 insertions, 0 deletions
diff --git a/cmd/krino/sort_test.go b/cmd/krino/sort_test.go
index e482f44..fa9a7ca 100644
--- a/cmd/krino/sort_test.go
+++ b/cmd/krino/sort_test.go
@@ -110,3 +110,66 @@ func TestAllSkippedDirectoryReportsZeroAndLogsNothing(t *testing.T) {
t.Errorf("journal gained entries for a directory with nothing to act on:\n%s", data)
}
}
+
+// TestPermanentDeleteOfDuplicatesUnderOverlappingDirKeepsACopy drives the
+// whole run end to end on the shape where a (duplicate "DIR") overlaps the
+// scanned tree: a recursive root holding Archive/x.pdf and a loose, older
+// x-copy.pdf with the same bytes, and a rule that permanently deletes
+// duplicates of anything under Archive. Whatever the verdicts, applying
+// the plan must leave the content on disk; the expected outcome is that
+// the archived copy stays and only the loose one goes.
+func TestPermanentDeleteOfDuplicatesUnderOverlappingDirKeepsACopy(t *testing.T) {
+ h := home(t)
+ dl := filepath.Join(h, "dl")
+ content := []byte("%PDF acme statement")
+ archived := filepath.Join(dl, "Archive", "x.pdf")
+ loose := filepath.Join(dl, "x-copy.pdf")
+ old := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
+ for p, mt := range map[string]time.Time{archived: old.Add(time.Hour), loose: old} {
+ if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(p, content, 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)
+ }
+ rules := "(path \"~/dl\")\n(recursive yes)\n(min-age 0s)\n" +
+ "(rule \"dups\" (when (duplicate \"Archive\")) (delete permanent))\n"
+ if err := os.WriteFile(filepath.Join(h, ".config", "krino", "dirs", "dl.conf"), []byte(rules), 0o644); err != nil {
+ t.Fatal(err)
+ }
+
+ code, out, errOut := runCLI(t, "-y")
+
+ var copies []string
+ err := filepath.WalkDir(dl, func(p string, d os.DirEntry, err error) error {
+ if err != nil || !d.Type().IsRegular() {
+ return err
+ }
+ if b, err := os.ReadFile(p); err == nil && string(b) == string(content) {
+ copies = append(copies, p)
+ }
+ return nil
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(copies) == 0 {
+ t.Fatalf("every copy was deleted (exit %d)\nstdout:\n%s\nstderr:\n%s", code, out, errOut)
+ }
+ if code != 0 {
+ t.Fatalf("run: %d %s", code, errOut)
+ }
+ if len(copies) != 1 || copies[0] != archived {
+ t.Errorf("copies left = %v, want only %s", copies, archived)
+ }
+}