"""Unit tests for src/shared/shared/pdf.py (weekly summary PDF generator).""" import pytest from fpdf import FPDF as _RealFPDF from shared.pdf import build_weekly_summary_pdf class _NoCompressFPDF(_RealFPDF): """FPDF subclass with stream compression off, so the content stream holds readable text we can assert against without a PDF parser.""" last_pages_count = 0 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.set_compression(False) def output(self, *args, **kwargs): _NoCompressFPDF.last_pages_count = self.pages_count return super().output(*args, **kwargs) @pytest.fixture() def readable_pdf(monkeypatch): """Patch the generator to emit uncompressed (searchable) PDFs.""" monkeypatch.setattr("shared.pdf.FPDF", _NoCompressFPDF) def _orders(): return [ { "employee_name": "Bob Jones", "employee_email": "bob@seahavenind.com", "items": [ {"name": "Chicken Parm", "quantity": 2}, {"name": "Caesar Salad", "quantity": 1}, ], }, { "employee_name": "Alice Smith", "employee_email": "alice@seahavenind.com", "items": [{"name": "Veggie Bowl", "quantity": 3}], }, ] def _build(orders, **overrides): kwargs = { "week": "2026-W19", "generated_at": "2026-05-22T16:35:40-04:00", "total_employees": len(orders), "total_meals": sum(i["quantity"] for o in orders for i in o["items"]), } kwargs.update(overrides) return build_weekly_summary_pdf(orders, **kwargs) def _volume_orders(count, items_per_employee=2): """Synthetic orders for layout/page-count checks.""" return [ { "employee_name": f"Employee {i:02d}", "employee_email": f"emp{i:02d}@seahavenind.com", "items": [ {"name": f"Meal {j}", "quantity": 1} for j in range(items_per_employee) ], } for i in range(count) ] class TestPdfStructure: def test_returns_pdf_bytes(self): pdf = _build(_orders()) assert isinstance(pdf, bytes) assert pdf[:5] == b"%PDF-", "Output should be a valid PDF" assert len(pdf) > 0 def test_empty_orders_still_valid_pdf(self): pdf = _build([], total_employees=0, total_meals=0) assert pdf[:5] == b"%PDF-" class TestPdfContent: def test_header_shows_week_and_counts(self, readable_pdf): pdf = _build(_orders()) text = pdf.decode("latin-1") assert "Weekly Meal Order Summary - 2026-W19" in text assert "2 employees" in text assert "6 meals" in text def test_each_employee_and_item_present(self, readable_pdf): orders = _orders() pdf = _build(orders) text = pdf.decode("latin-1") for order in orders: assert order["employee_name"] in text, f"missing {order['employee_name']}" assert order["employee_email"] in text for item in order["items"]: assert item["name"] in text, f"missing item {item['name']}" def test_no_prices_anywhere(self, readable_pdf): """Per issue #16: strictly employee, item, qty — never a price.""" orders = _orders() # Even if price fields are present on the items, they must not be rendered. for o in orders: for i in o["items"]: i["price"] = 12.50 i["subtotal"] = 99.99 pdf = _build(orders) text = pdf.decode("latin-1") assert "$" not in text, "PDF must contain no currency symbol" assert "12.50" not in text and "99.99" not in text, "PDF must not render prices" def test_non_latin1_chars_do_not_crash(self): orders = [ { "employee_name": "José 🍜 Ramírez", "employee_email": "jose@seahavenind.com", "items": [{"name": "Phở Bowl", "quantity": 1}], } ] pdf = _build(orders) assert pdf[:5] == b"%PDF-" class TestPdfLayout: def test_typical_week_fits_on_one_page(self, readable_pdf): """12 employees with 2 items each overflowed the pre-DEV-210 layout.""" pdf = _build(_volume_orders(12)) assert pdf[:5] == b"%PDF-" assert _NoCompressFPDF.last_pages_count == 1 def test_high_volume_still_paginates(self, readable_pdf): pdf = _build(_volume_orders(40)) assert pdf[:5] == b"%PDF-" assert _NoCompressFPDF.last_pages_count >= 2