summaryrefslogtreecommitdiff
path: root/internal/models/recurrence_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/models/recurrence_test.go')
-rw-r--r--internal/models/recurrence_test.go40
1 files changed, 40 insertions, 0 deletions
diff --git a/internal/models/recurrence_test.go b/internal/models/recurrence_test.go
index 8d18996..affba56 100644
--- a/internal/models/recurrence_test.go
+++ b/internal/models/recurrence_test.go
@@ -49,3 +49,43 @@ func TestComputeNextOccurrence(t *testing.T) {
})
}
}
+
+func TestCollapseRecurringSeries_KeepsOnlyEarliestOpenInstance(t *testing.T) {
+ sep1 := time.Date(2026, 9, 1, 0, 0, 0, 0, time.UTC)
+ oct1 := time.Date(2026, 10, 1, 0, 0, 0, 0, time.UTC)
+
+ tasks := []Task{
+ {ID: "bills-sep", Content: "Bills", DueDate: &sep1, RecurrenceSeriesID: "bills"},
+ {ID: "bills-oct", Content: "Bills", DueDate: &oct1, RecurrenceSeriesID: "bills"},
+ {ID: "one-off", Content: "Fix curtain holder"},
+ }
+
+ got := CollapseRecurringSeries(tasks)
+
+ var ids []string
+ for _, task := range got {
+ ids = append(ids, task.ID)
+ }
+ if len(got) != 2 {
+ t.Fatalf("got %d tasks (%v), want 2: one row per recurring series plus the one-off", len(got), ids)
+ }
+ if got[0].ID != "bills-sep" {
+ t.Errorf("kept %q for the Bills series, want bills-sep (the earliest open instance is the one you actually owe)", got[0].ID)
+ }
+ if got[1].ID != "one-off" {
+ t.Errorf("non-recurring task was dropped or reordered: got %q", got[1].ID)
+ }
+}
+
+func TestCollapseRecurringSeries_UndatedAndDistinctSeriesUntouched(t *testing.T) {
+ due := time.Date(2026, 9, 1, 0, 0, 0, 0, time.UTC)
+ tasks := []Task{
+ {ID: "a", RecurrenceSeriesID: "series-a", DueDate: &due},
+ {ID: "b", RecurrenceSeriesID: "series-b", DueDate: &due},
+ {ID: "c", RecurrenceSeriesID: "series-c"}, // recurring but undated
+ }
+
+ if got := CollapseRecurringSeries(tasks); len(got) != 3 {
+ t.Errorf("len = %d, want 3 -- distinct series must not collapse into each other", len(got))
+ }
+}