from datetime import UTC, datetime import pytest from pigway_frame_flow.errors import FlowError from pigway_frame_flow.providers.ical import calendar_events def feed(properties): return ( "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\n" + properties + "\r\nEND:VEVENT\r\nEND:VCALENDAR" ).encode() def test_recurring_event_exclusions_and_folded_title(): result = calendar_events( feed( "UID:one\r\nDTSTART:20261008T080000Z\r\nRRULE:FREQ=DAILY;COUNT=3\r\nEXDATE:20261009T080000Z\r\nSUMMARY:Family\r\n time" ), datetime(2026, 10, 8, tzinfo=UTC), ) assert len(result["events"]) == 2 assert result["events"][0]["title"] == "Family time" assert result["events"][1]["start"].startswith("2026-10-10") def test_cancelled_event_ignored(): assert ( calendar_events( feed("DTSTART:20261008T080000Z\r\nSTATUS:CANCELLED\r\nSUMMARY:Cancelled"), datetime(2026, 10, 8, tzinfo=UTC), )["events"] == [] ) def test_high_frequency_rejected(): with pytest.raises(FlowError): calendar_events( feed("DTSTART:20261008T080000Z\r\nRRULE:FREQ=SECONDLY\r\nSUMMARY:Bad"), datetime(2026, 10, 8, tzinfo=UTC), ) def test_timezone_and_past_filter(): events = calendar_events( feed("DTSTART;TZID=Asia/Shanghai:20261008T090000\r\nSUMMARY:Meeting"), datetime(2026, 10, 8, tzinfo=UTC), )["events"] assert len(events) == 1 assert events[0]["start"].endswith("+08:00") assert ( calendar_events( feed("DTSTART:20260101T090000Z\r\nSUMMARY:Past"), datetime(2026, 10, 8, tzinfo=UTC), )["events"] == [] )