summaryrefslogtreecommitdiff
path: root/internal/engine/undo_identity_test.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-09-14 23:07:57 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-09-14 23:07:57 +0200
commitc66a842ce4679a3ffa5504dad39b1402bea75e9f (patch)
tree9e9db5e569b9f16a4ca4e66d0a5b0f456a186ece /internal/engine/undo_identity_test.go
parentb013e5fb87580e4cab0d85a0d2c8bb402c610413 (diff)
downloadkrino-0.0.7.tar.gz
krino-0.0.7.zip
plan 10 re-check: cut run column, damaged undo run, emptied directory cleanup, text turning binary, explain flags, interrupt docsv0.0.7
Diffstat (limited to 'internal/engine/undo_identity_test.go')
-rw-r--r--internal/engine/undo_identity_test.go80
1 files changed, 80 insertions, 0 deletions
diff --git a/internal/engine/undo_identity_test.go b/internal/engine/undo_identity_test.go
index f9d6307..f42c5da 100644
--- a/internal/engine/undo_identity_test.go
+++ b/internal/engine/undo_identity_test.go
@@ -492,3 +492,83 @@ func TestUndoRefusesATrashEntryRecordedForAnotherPath(t *testing.T) {
t.Errorf("Refused = %q; want the trash entry named as another file's", f.Refused)
}
}
+
+// TestFinishedUndoRemovesADirectoryLeftEmpty: a directory made by one file's
+// chain and still holding another file is not offered on its own, but once
+// that other file's reversal empties it, the undo removes it (plan 10
+// re-check R1).
+func TestFinishedUndoRemovesADirectoryLeftEmpty(t *testing.T) {
+ e, run, h, logPath := appliedRun(t, map[string]map[string]string{"dl": {"a.pdf": "one", "b.pdf": "two"}},
+ map[string]string{"dl": "(path \"~/dl\")\n(rule \"r\" (move \"Out\"))\n"})
+ out := filepath.Join(h, "dl", "Out")
+ undo := func(decline string) {
+ t.Helper()
+ up, err := e.PlanUndo(run)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for i := range up.Files {
+ up.Files[i].Declined = up.Files[i].File == decline
+ }
+ j, err := journal.Open(logPath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer j.Close()
+ if _, err := e.ApplyUndo(context.Background(), up, j, journal.NewRunID(time.Now())); err != nil {
+ t.Fatal(err)
+ }
+ }
+ up, err := e.PlanUndo(run)
+ if err != nil {
+ t.Fatal(err)
+ }
+ other := ""
+ for _, f := range up.Files {
+ made := false
+ for _, s := range f.Steps {
+ made = made || s.Action == "undo-mkdir"
+ }
+ if !made {
+ other = f.File
+ }
+ }
+ undo(other) // the file that made Out goes back; the other still holds Out
+ if _, err := os.Stat(out); err != nil {
+ t.Fatalf("Out went while %s still held it: %v", other, err)
+ }
+ undo("") // the other goes back, leaving Out empty
+ if _, err := os.Lstat(out); !os.IsNotExist(err) {
+ t.Errorf("Out is still there after the undo finished: %v", err)
+ }
+}
+
+// TestUndoRunWithADamagedLineIsStillAnUndo: a damaged line in an undo run's
+// log does not make that run look like an ordinary one that can be undone
+// (plan 10 re-check R3).
+func TestUndoRunWithADamagedLineIsStillAnUndo(t *testing.T) {
+ e, run, _, logPath := appliedRun(t, map[string]map[string]string{"dl": {"a.pdf": "one"}},
+ map[string]string{"dl": "(path \"~/dl\")\n(rule \"r\" (rename \"r-{name}\") (move \"Out\"))\n"})
+ up, err := e.PlanUndo(run)
+ if err != nil {
+ t.Fatal(err)
+ }
+ j, err := journal.Open(logPath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ undoRun := journal.NewRunID(time.Now().Add(time.Second))
+ if _, err := e.ApplyUndo(context.Background(), up, j, undoRun); err != nil {
+ t.Fatal(err)
+ }
+ j.Close()
+ f, err := os.OpenFile(logPath, os.O_APPEND|os.O_WRONLY, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ f.WriteString(time.Now().UTC().Format(time.RFC3339) + "\t" + undoRun + "\tdl\ta.pdf\t9\tundo-mo\n")
+ f.Close()
+ if _, err := e.PlanUndo(undoRun); err == nil || !strings.Contains(err.Error(), "itself an undo") {
+ t.Errorf("PlanUndo(undo run with a damaged line) = %v; want refused as an undo", err)
+ }
+}