"""Every renderer that produces a device-facing frame must return exactly EPD_WIDTH*EPD_HEIGHT/2 bytes (the panel's packed 2px/byte format) -- firmware writes this straight to the display with no length checking of its own, so a renderer that's off by even one byte is a silent on-device corruption bug, not a clean error. This is a cheap, high-value regression guard: pure PIL rendering, no DB/HTTP/Node.""" from __future__ import annotations import pytest from app.calendar_render import CALENDAR_VIEWS, render_calendar from app.image_pipeline import EPD_HEIGHT, EPD_WIDTH, render_placeholder EXPECTED_BYTES = EPD_WIDTH * EPD_HEIGHT // 2 ORIENTATIONS = ["landscape", "landscape_flipped", "portrait", "portrait_flipped"] _SAMPLE_EVENTS = [ { "summary": "Dentist", "start": "2026-08-01T14:00:00+00:00", "end": "2026-08-01T15:00:00+00:00", "all_day": False, "sources": [{"owner_display_name": "Alice", "color_index": None}], }, { "summary": "Team Offsite", "start": "2026-08-03T00:00:00", "end": "2026-08-04T00:00:00", "all_day": True, "sources": [{"owner_display_name": "Bob", "color_index": 2}], }, ] @pytest.mark.parametrize("orientation", ORIENTATIONS) def test_placeholder_render_size(orientation): data = render_placeholder(["Not configured yet"], orientation=orientation) assert len(data) == EXPECTED_BYTES @pytest.mark.parametrize("view", CALENDAR_VIEWS) def test_calendar_render_size_across_views(view): data = render_calendar(_SAMPLE_EVENTS, view, browse_offset=0, orientation="landscape", palette_rgb=None, timezone="UTC") assert len(data) == EXPECTED_BYTES @pytest.mark.parametrize("orientation", ORIENTATIONS) def test_calendar_render_size_across_orientations(orientation): data = render_calendar(_SAMPLE_EVENTS, "agenda", browse_offset=0, orientation=orientation, palette_rgb=None, timezone="UTC") assert len(data) == EXPECTED_BYTES def test_calendar_render_size_empty_events(): data = render_calendar([], "week", browse_offset=0, orientation="landscape", palette_rgb=None, timezone="UTC") assert len(data) == EXPECTED_BYTES def test_calendar_render_size_with_fetch_summary_and_tasks(): tasks = [{"summary": "Buy milk", "completed": False}, {"summary": "Walk the dog", "completed": True}] data = render_calendar(_SAMPLE_EVENTS, "week", browse_offset=0, orientation="landscape", palette_rgb=None, timezone="UTC", fetch_summary="1 of 2 calendars unavailable", week_days=5, week_layout="vertical", tasks=tasks) assert len(data) == EXPECTED_BYTES def test_calendar_render_size_with_week_start_offset(): data = render_calendar(_SAMPLE_EVENTS, "week", browse_offset=0, orientation="landscape", palette_rgb=None, timezone="UTC", week_days=3, week_start_offset=2) assert len(data) == EXPECTED_BYTES