package scheduler import ( "testing" "time" ) func TestParseCron(t *testing.T) { tests := []struct { expr string wantErr bool }{ {"* * * * *", false}, {"0 * * * *", false}, {"*/5 * * * *", false}, {"0,30 * * * *", false}, {"0-30 * * * *", false}, {"*/15 9-17 * * *", false}, {"0 0 1 * *", false}, {"0 0 * * 0", false}, {"0 0 1,15 * *", false}, {"invalid", true}, {"* * * *", true}, {"60 * * * *", true}, {"* 24 * * *", true}, } for _, tt := range tests { _, err := ParseCron(tt.expr) if (err != nil) != tt.wantErr { t.Errorf("ParseCron(%q) error = %v, wantErr %v", tt.expr, err, tt.wantErr) } } } func TestCronMatches(t *testing.T) { expr, err := ParseCron("*/5 * * * *") if err != nil { t.Fatal(err) } tests := []struct { minute int want bool }{ {0, true}, {5, true}, {10, true}, {15, true}, {1, false}, {2, false}, {7, false}, } now := time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC) for _, tt := range tests { tm := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), tt.minute, 0, 0, time.UTC) if got := expr.Matches(tm); got != tt.want { t.Errorf("Matches(minute=%d) = %v, want %v", tt.minute, got, tt.want) } } } func TestCronMatchesSpecific(t *testing.T) { expr, err := ParseCron("30 9 15 * *") if err != nil { t.Fatal(err) } matches := time.Date(2024, 6, 15, 9, 30, 0, 0, time.UTC) if !expr.Matches(matches) { t.Error("should match 9:30 on 15th of month") } notMatch := time.Date(2024, 6, 16, 9, 30, 0, 0, time.UTC) if expr.Matches(notMatch) { t.Error("should not match 9:30 on 16th of month") } } func TestNextRun(t *testing.T) { expr, err := ParseCron("*/5 * * * *") if err != nil { t.Fatal(err) } from := time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC) next := NextRun(expr, from) if next.Minute() != 5 || next.Hour() != 12 { t.Errorf("NextRun = %v, want 12:05", next) } if !next.After(from) { t.Error("NextRun should be after from time") } }