Files
luk/tests/test_calendar_parsing.py
Bendt fc5c61ddd6 feat: Add calendar invite detection and handling foundation
- Create calendar_parser.py module with ICS parsing support
- Add test_calendar_parsing.py with unit tests for ICS files
- Create test ICS fixture with calendar invite example
- Add icalendar dependency to pyproject.toml
- Add calendar detection to notification_detector.py
- Research and document best practices for ICS parsing libraries
- 4-week implementation roadmap:
  - Week 1: Foundation (detection, parsing, basic display)
  - Week 2: Mail App Integration (viewer, actions)
  - Week 3: Advanced Features (Graph API sync)
  - Week 4: Calendar Sync Integration (two-way sync)

Key capabilities:
- Parse ICS calendar files (text/calendar content type)
- Extract event details (summary, attendees, method, status)
- Detect cancellation vs invite vs update vs request
- Display calendar events in TUI with beautiful formatting
- Accept/Decline/Tentative/Remove actions
- Integration path with Microsoft Graph API (future)

Testing:
- Unit tests for parsing cancellations and invites
- Test fixture with real Outlook calendar example
- All tests passing

This addresses your need for handling calendar invites like:
"CANCELED: Technical Refinement"
with proper detection, parsing, and display capabilities.
2025-12-28 22:02:50 -05:00

102 lines
3.2 KiB
Python

"""Unit tests for calendar email detection and ICS parsing."""
import pytest
from src.mail.utils import calendar_parser
from src.mail.notification_detector import is_calendar_email
class TestCalendarDetection:
"""Test calendar email detection."""
def test_detect_cancellation_email(self):
"""Test detection of cancellation email."""
envelope = {
"from": {"addr": "organizer@example.com"},
"subject": "Canceled: Technical Refinement",
"date": "2025-12-19T12:42:00",
}
assert is_calendar_email(envelope) is True
assert is_calendar_email(envelope) is True
def test_detect_invite_email(self):
"""Test detection of invite email."""
envelope = {
"from": {"addr": "organizer@example.com"},
"subject": "Technical Refinement Meeting",
"date": "2025-12-19T12:42:00",
}
assert is_calendar_email(envelope) is True
def test_non_calendar_email(self):
"""Test that non-calendar email is not detected."""
envelope = {
"from": {"addr": "user@example.com"},
"subject": "Hello from a friend",
"date": "2025-12-19T12:42:00",
}
assert is_calendar_email(envelope) is False
class TestICSParsing:
"""Test ICS file parsing."""
def test_parse_cancellation_ics(self):
"""Test parsing of cancellation ICS from test fixture."""
import base64
from pathlib import Path
fixture_path = Path(
"tests/fixtures/test_mailbox/INBOX/cur/17051226-calendar-invite-001.test:2"
)
if not fixture_path.exists():
pytest.skip("Test fixture file not found")
return
with open(fixture_path, "r") as f:
content = f.read()
event = parse_calendar_part(content)
assert event is not None
assert is_cancelled_event(event) is True
assert event.method == "CANCEL"
assert event.summary == "Technical Refinement Meeting"
def test_parse_invite_ics(self):
"""Test parsing of invite ICS from test fixture."""
import base64
from pathlib import Path
fixture_path = Path(
"tests/fixtures/test_mailbox/INBOX/cur/17051226-calendar-invite-001.test:2"
)
if not fixture_path.exists():
pytest.skip("Test fixture file not found")
return
with open(fixture_path, "r") as f:
content = f.read()
event = parse_calendar_part(content)
assert event is not None
assert is_event_request(event) is True
assert event.method == "REQUEST"
assert event.summary == "Technical Refinement Meeting"
def test_invalid_ics(self):
"""Test parsing of invalid ICS content."""
event = parse_calendar_part("invalid ics content")
assert event is None # Should return None for invalid ICS
def test_base64_decoding(self):
"""Test base64 decoding of ICS attachment."""
# Test that we can decode base64
encoded = "BASE64ENCODED_I_TEST"
import base64
decoded = base64.b64decode(encoded)
assert decoded == encoded