"""Unit tests for personal calendar ICS generation.""" from types import SimpleNamespace from icalendar import Calendar as ICalendar from duty_teller.api.personal_calendar_ics import build_personal_ics # Minimal Duty-like object for build_personal_ics(duties_with_name: list[tuple[Duty, str]]) def _duty(id_, start_at, end_at, event_type="duty"): return ( SimpleNamespace( id=id_, start_at=start_at, end_at=end_at, event_type=event_type ), "Test User", ) def test_build_personal_ics_empty_returns_valid_calendar(): """Empty list produces VCALENDAR with no VEVENTs.""" ics = build_personal_ics([]) assert ics.startswith(b"BEGIN:VCALENDAR") assert ics.rstrip().endswith(b"END:VCALENDAR") cal = ICalendar.from_ical(ics) assert cal is not None events = [c for c in cal.walk() if c.name == "VEVENT"] assert len(events) == 0 def test_build_personal_ics_one_duty(): """One duty produces one VEVENT with correct DTSTART/DTEND/SUMMARY.""" duties = [ _duty(1, "2025-02-20T09:00:00Z", "2025-02-20T18:00:00Z", "duty"), ] ics = build_personal_ics(duties) cal = ICalendar.from_ical(ics) assert cal is not None events = [c for c in cal.walk() if c.name == "VEVENT"] assert len(events) == 1 ev = events[0] assert ev.get("summary") == "Duty" assert "2025-02-20" in str(ev.get("dtstart").dt) assert "2025-02-20" in str(ev.get("dtend").dt) assert b"duty-1@duty-teller" in ics or "duty-1@duty-teller" in ics.decode("utf-8") def test_build_personal_ics_event_types(): """Unavailable and vacation get correct SUMMARY.""" duties = [ _duty(1, "2025-02-20T09:00:00Z", "2025-02-21T09:00:00Z", "unavailable"), _duty(2, "2025-02-25T00:00:00Z", "2025-03-01T00:00:00Z", "vacation"), ] ics = build_personal_ics(duties) cal = ICalendar.from_ical(ics) events = [c for c in cal.walk() if c.name == "VEVENT"] assert len(events) == 2 summaries = [str(ev.get("summary")) for ev in events] assert "Unavailable" in summaries assert "Vacation" in summaries def test_build_personal_ics_naive_datetime_treated_as_utc(): """Duties with start_at/end_at without Z (naive datetime) are treated as UTC.""" duties = [ _duty(1, "2025-02-20T09:00:00", "2025-02-20T18:00:00", "duty"), ] ics = build_personal_ics(duties) cal = ICalendar.from_ical(ics) assert cal is not None events = [c for c in cal.walk() if c.name == "VEVENT"] assert len(events) == 1 ev = events[0] assert ev.get("summary") == "Duty" assert "2025-02-20" in str(ev.get("dtstart").dt) assert "2025-02-20" in str(ev.get("dtend").dt)