Files
duty-teller/tests/test_personal_calendar_ics.py
Nikolay Tatarinov 35946a5812
All checks were successful
CI / lint-and-test (push) Successful in 23s
feat: add tests for admin checks and error handling
- Introduced new tests for the `is_admin_async` function to verify correct behavior based on user roles.
- Added tests for error handling in the `error_handler` to ensure exceptions are logged and do not propagate.
- Enhanced test coverage for configuration settings by adding a test for parsing admin phone numbers from environment variables.
- Updated the `.cursorrules` file to include the use of a virtual environment for better dependency management.
2026-02-21 00:50:29 +03:00

77 lines
2.6 KiB
Python

"""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)