ghost-shopper-api / python /tests /test_pdf_service.py
azzaraqi
Deploy FastAPI backend with Supabase pooler support
b84ea83
Raw
History Blame Contribute Delete
4.18 kB
"""
Unit Tests — PDFService
Tests:
- Returns None for a visit that doesn't exist
- Returns bytes for a valid visit
- Output starts with PDF magic bytes (%PDF)
- PDF size is reasonable (>1KB)
- Works correctly with no checklists / no photos
- Works with checklists and photos present
"""
import pytest
from sqlalchemy.ext.asyncio import AsyncSession
from models.visit_model import Visit
from models.checklist_model import Checklist
from models.photo_model import Photo
from services.pdf_service import PDFService
PDF_MAGIC = b"%PDF"
@pytest.mark.asyncio
class TestPDFService:
async def test_returns_none_for_missing_visit(
self, async_session: AsyncSession
):
import uuid
svc = PDFService()
result = await svc.generate_visit_report(async_session, uuid.uuid4())
assert result is None
async def test_returns_bytes_for_valid_visit(
self, async_session: AsyncSession, sample_visit: Visit
):
svc = PDFService()
result = await svc.generate_visit_report(async_session, sample_visit.id)
assert result is not None
assert isinstance(result, bytes)
async def test_output_is_valid_pdf(
self, async_session: AsyncSession, sample_visit: Visit
):
"""PDF must start with the %PDF magic header."""
svc = PDFService()
result = await svc.generate_visit_report(async_session, sample_visit.id)
assert result is not None
assert result[:4] == PDF_MAGIC
async def test_pdf_has_reasonable_size(
self, async_session: AsyncSession, sample_visit: Visit
):
"""PDF should be at least 1KB (basic structure is there)."""
svc = PDFService()
result = await svc.generate_visit_report(async_session, sample_visit.id)
assert result is not None
assert len(result) > 1024 # > 1 KB
async def test_pdf_with_no_checklists_no_photos(
self, async_session: AsyncSession, sample_visit: Visit
):
"""Visit with no related data should still produce a valid PDF."""
svc = PDFService()
result = await svc.generate_visit_report(async_session, sample_visit.id)
assert result is not None
assert result[:4] == PDF_MAGIC
async def test_pdf_with_checklists(
self,
async_session: AsyncSession,
sample_visit: Visit,
sample_checklist: Checklist,
):
"""Checklist data should be included — PDF size increases."""
svc = PDFService()
result = await svc.generate_visit_report(async_session, sample_visit.id)
assert result is not None
assert len(result) > 1024
async def test_pdf_with_photos(
self,
async_session: AsyncSession,
sample_visit: Visit,
sample_photo: Photo,
):
"""Photo metadata table should be included — PDF still valid."""
svc = PDFService()
result = await svc.generate_visit_report(async_session, sample_visit.id)
assert result is not None
assert result[:4] == PDF_MAGIC
async def test_pdf_with_all_data(
self,
async_session: AsyncSession,
sample_visit: Visit,
):
"""Full visit with multiple checklists and photos."""
# Add 3 checklists
for i, checked in enumerate([True, False, True]):
async_session.add(Checklist(
visit_id=sample_visit.id,
item_name=f"Step {i+1}",
is_checked=checked,
notes=f"Note for step {i+1}" if checked else None,
))
# Add 2 photos
for j in range(2):
async_session.add(Photo(
visit_id=sample_visit.id,
file_path=f"/uploads/photo_{j}.jpg",
file_name=f"photo_{j}.jpg",
file_size=51200,
mime_type="image/jpeg",
))
await async_session.flush()
svc = PDFService()
result = await svc.generate_visit_report(async_session, sample_visit.id)
assert result is not None
assert result[:4] == PDF_MAGIC
assert len(result) > 2048 # Richer content = larger PDF