summaryrefslogtreecommitdiff
path: root/internal/models/recurrence_test.go
blob: 8d18996c9bb1d77ae132802d066773f535ceaf72 (plain)
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
package models

import (
	"testing"
	"time"
)

func TestComputeNextOccurrence(t *testing.T) {
	mustParse := func(t *testing.T, s string) time.Time {
		t.Helper()
		d, err := time.Parse("2006-01-02", s)
		if err != nil {
			t.Fatalf("bad fixture date %q: %v", s, err)
		}
		return d
	}

	tests := []struct {
		name     string
		due      string
		freq     string
		interval int
		weekdays []int
		want     string
	}{
		{"daily interval 1", "2026-07-13", "daily", 1, nil, "2026-07-14"},
		{"daily interval 3", "2026-07-13", "daily", 3, nil, "2026-07-16"},
		{"weekly no weekdays interval 1", "2026-07-13", "weekly", 1, nil, "2026-07-20"},
		{"weekly no weekdays interval 2", "2026-07-13", "weekly", 2, nil, "2026-07-27"},
		// 2026-07-13 is a Monday (weekday=1).
		{"weekly with weekdays same week", "2026-07-13", "weekly", 1, []int{1, 3, 5}, "2026-07-15"},
		{"weekly with weekdays wraps to next week", "2026-07-17", "weekly", 1, []int{1, 3, 5}, "2026-07-20"}, // due=Fri(5), wraps to Mon
		{"weekly with weekdays interval 2 wraps", "2026-07-13", "weekly", 2, []int{1}, "2026-07-27"},          // due=Mon, only Mon active, skip a week
		{"monthly interval 1", "2026-06-13", "monthly", 1, nil, "2026-07-13"},
		{"monthly rollover", "2026-01-31", "monthly", 1, nil, "2026-03-03"},
		{"monthly rollover locks in on the drifted day", "2026-03-03", "monthly", 1, nil, "2026-04-03"},
		{"yearly interval 1", "2026-07-13", "yearly", 1, nil, "2027-07-13"},
		{"unknown freq returns due unchanged", "2026-07-13", "bogus", 1, nil, "2026-07-13"},
		{"interval below 1 is treated as 1", "2026-07-13", "daily", 0, nil, "2026-07-14"},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			got := ComputeNextOccurrence(mustParse(t, tc.due), tc.freq, tc.interval, tc.weekdays)
			want := mustParse(t, tc.want)
			if !got.Equal(want) {
				t.Errorf("ComputeNextOccurrence(%s, %s, %d, %v) = %s, want %s", tc.due, tc.freq, tc.interval, tc.weekdays, got.Format("2006-01-02"), tc.want)
			}
		})
	}
}