aboutsummaryrefslogtreecommitdiffstats
path: root/test_cal_notif.py
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-27 19:53:54 +0200
committerDanilo M. <danix@danix.xyz>2026-09-27 19:53:54 +0200
commit608a449d5d98a3e8bba624f8e3546516b2a8f998 (patch)
tree807534678ac9fc13b0a4645cc4fe885a87851874 /test_cal_notif.py
parentdb9a7a2dc1e35991c6410a1cef1ddad1c0b3c155 (diff)
downloadcal-notif-608a449d5d98a3e8bba624f8e3546516b2a8f998.tar.gz
cal-notif-608a449d5d98a3e8bba624f8e3546516b2a8f998.zip
Expand calendar events: RRULE, EXDATE, RECURRENCE-ID, all-day, VALARM
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'test_cal_notif.py')
-rw-r--r--test_cal_notif.py67
1 files changed, 67 insertions, 0 deletions
diff --git a/test_cal_notif.py b/test_cal_notif.py
index 27f60ba..2237dae 100644
--- a/test_cal_notif.py
+++ b/test_cal_notif.py
@@ -79,6 +79,73 @@ def test_config():
pass
+def test_expand():
+ lo, hi = at(2026, 1, 1), at(2026, 2, 1)
+ # Weekly zoned event, two EXDATEs, one moved occurrence.
+ weekly = """UID:w@example.org
+DTSTART;TZID=Europe/Rome:20260105T090000
+DTEND;TZID=Europe/Rome:20260105T100000
+RRULE:FREQ=WEEKLY;UNTIL=20260131T000000Z
+EXDATE;TZID=Europe/Rome:20260112T090000,20260119T090000
+SUMMARY:standup"""
+ moved = """UID:w@example.org
+RECURRENCE-ID;TZID=Europe/Rome:20260126T090000
+DTSTART;TZID=Europe/Rome:20260126T150000
+DTEND;TZID=Europe/Rome:20260126T160000
+SUMMARY:standup moved"""
+ occ = cn.expand(ics(weekly, moved), "work", lo, hi)
+ got = sorted((o.start, o.summary) for o in occ)
+ assert got == [(at(2026, 1, 5, 9), "standup"), (at(2026, 1, 26, 15), "standup moved")], got
+
+ # All-day yearly with a UTC UNTIL (dateutil rejects the naive/aware mix
+ # unless normalised) and a relative VALARM 1 day before.
+ bday = """UID:b@example.org
+DTSTART;VALUE=DATE:19800112
+RRULE:FREQ=YEARLY;UNTIL=20300101T000000Z
+SUMMARY:birthday
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-P1D
+END:VALARM"""
+ (o,) = cn.expand(ics(bday), "bd", lo, hi)
+ assert o.allday and o.start == datetime(2026, 1, 12).astimezone()
+ assert o.valarms == (datetime(2026, 1, 11).astimezone(),)
+
+ # A week-ahead VALARM on an event past `hi` widens that event's window.
+ far = """UID:f@example.org
+DTSTART;TZID=Europe/Rome:20260205T090000
+SUMMARY:far
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER:-P7D
+END:VALARM"""
+ (o,) = cn.expand(ics(far), "c", lo, hi)
+ assert o.valarms == (at(2026, 1, 29, 9),)
+ assert cn.expand(ics(far.replace("-P7D", "-PT1H")), "c", lo, hi) == []
+
+ # RELATED=END trigger counts from DTEND.
+ end = """UID:e@example.org
+DTSTART;TZID=Europe/Rome:20260110T090000
+DTEND;TZID=Europe/Rome:20260110T110000
+BEGIN:VALARM
+ACTION:DISPLAY
+TRIGGER;RELATED=END:-PT15M
+END:VALARM"""
+ (o,) = cn.expand(ics(end), "c", lo, hi)
+ assert o.valarms == (at(2026, 1, 10, 10, 45),)
+
+
+def test_load_events():
+ with tempfile.TemporaryDirectory() as d:
+ cal = Path(d) / "123"
+ cal.mkdir()
+ (cal / "displayname").write_text("work\n")
+ (cal / "a.ics").write_bytes(ics("UID:a@example.org\nDTSTART;TZID=Europe/Rome:20260110T090000"))
+ (cal / "broken.ics").write_text("not a calendar")
+ (o,) = cn.load_events(d, at(2026, 1, 1), at(2026, 2, 1)) # broken one skipped
+ assert o.cal == "work" and o.uid == "a@example.org"
+
+
if __name__ == "__main__":
for name, fn in list(globals().items()):
if name.startswith("test_"):