carlos / platform Public

schedule: pin the Vixie dom||dow OR-semantics branch in cron.go

Every existing Next test case left at least one of day-of-month or
day-of-week as "*", so dayMatches' default branch (both restricted →
match if either does) had no direct coverage. Add a test that pins
both halves of the OR: a dow-only match and a dom-only match.
Paul Campbell pushed by paul@keymail.dev 964f2a7cc66f5a59a5cb16f79fce12df3950bdaa parent c0aa3ac
1 file changed, +22 −0
  • internal/schedule/cron_test.go +22 −0
diff --git a/internal/schedule/cron_test.go b/internal/schedule/cron_test.go
index 561ad87f4..6400034b7 100644
--- a/internal/schedule/cron_test.go
+++ b/internal/schedule/cron_test.go
@@ -52,6 +52,28 @@ func TestCronNextIsStrictlyAfterAndUTC(t *testing.T) {
}
}
+// dayMatches applies Vixie cron's rule: when BOTH day-of-month and
+// day-of-week are restricted (neither is "*"), a day matches if EITHER
+// field matches — not both. This pins that OR branch, which nothing else
+// exercised (every other case above leaves at least one day field as "*").
+func TestCronBothDayFieldsRestrictedIsOR(t *testing.T) {
+ c, err := ParseCron("0 0 1 * 3") // day-of-month = 1, weekday = Wednesday
+ if err != nil {
+ t.Fatal(err)
+ }
+ // 2026-08-26 is a Wednesday but not the 1st of the month: only AND
+ // semantics would skip it (waiting for a 1st that falls on a
+ // Wednesday); OR semantics fire here because dow alone matches.
+ if got, want := c.Next(at("2026-08-23T00:00:00Z")), at("2026-08-26T00:00:00Z"); !got.Equal(want) {
+ t.Fatalf("dom=1 dow=Wed after a Sunday = %s, want %s (dow-only match, OR semantics)", got.Format(time.RFC3339), want.Format(time.RFC3339))
+ }
+ // 2026-09-01 is a Tuesday, not the Wednesday dow wants, but it is the
+ // 1st: dom alone matches, which is the other half of the OR.
+ if got, want := c.Next(at("2026-08-27T00:00:00Z")), at("2026-09-01T00:00:00Z"); !got.Equal(want) {
+ t.Fatalf("dom=1 dow=Wed after 2026-08-27 = %s, want %s (dom-only match, OR semantics)", got.Format(time.RFC3339), want.Format(time.RFC3339))
+ }
+}
+
func TestCronNextHonoursNonUTCInput(t *testing.T) {
expr, _ := ParseCron("0 8 * * *")
loc := time.FixedZone("plus2", 2*3600)