"""Tests for RRULE recurrence expansion (U1).""" from __future__ import annotations from agentkit.calendar.recurrence import expand_rrule def test_expand_rrule_weekly_count() -> None: """FREQ=WEEKLY;BYDAY=MO;COUNT=4 from Monday → 4 occurrences.""" result = expand_rrule( "FREQ=WEEKLY;BYDAY=MO;COUNT=4", "2026-07-06T10:00:00+00:00", # Monday ) assert len(result) == 4 # All should be Mondays for occ in result: # 2026-07-06 is Monday, 07-13, 07-20, 07-27 assert "T10:00:00+00:00" in occ def test_expand_rrule_daily_range_filter() -> None: """FREQ=DAILY starting Jan 1, range Jan 3–Jan 5 → 3 occurrences.""" result = expand_rrule( "FREQ=DAILY", "2026-01-01T00:00:00+00:00", range_start="2026-01-03T00:00:00+00:00", range_end="2026-01-06T00:00:00+00:00", ) assert len(result) == 3 # Jan 3, 4, 5 def test_expand_rrule_until_clause() -> None: """FREQ=DAILY;UNTIL=20260131 → occurrences stop at Jan 31.""" result = expand_rrule( "FREQ=DAILY;UNTIL=20260131T235959Z", "2026-01-29T00:00:00+00:00", ) assert len(result) == 3 # Jan 29, 30, 31 def test_expand_rrule_no_rrule_returns_single() -> None: """rrule=None → returns [start_time] only.""" result = expand_rrule(None, "2026-07-01T10:00:00+00:00") assert result == ["2026-07-01T10:00:00+00:00"] result = expand_rrule("", "2026-07-01T10:00:00+00:00") assert result == ["2026-07-01T10:00:00+00:00"] def test_expand_rrule_all_day_event() -> None: """All-day event with RRULE, verify date expansion (no time component issues).""" result = expand_rrule( "FREQ=DAILY;COUNT=3", "2026-07-01T00:00:00+00:00", ) assert len(result) == 3 assert result[0].startswith("2026-07-01") assert result[1].startswith("2026-07-02") assert result[2].startswith("2026-07-03") def test_expand_rrule_dst_boundary() -> None: """Event crossing DST transition, verify UTC consistency. March 8, 2026 is US DST spring-forward. A daily event starting March 7 should produce correct UTC occurrences across the boundary. """ result = expand_rrule( "FREQ=DAILY;COUNT=3", "2026-03-07T10:00:00+00:00", ) assert len(result) == 3 # All should be at 10:00 UTC regardless of DST for occ in result: assert "T10:00:00+00:00" in occ