Spaces:
Sleeping
Sleeping
| """ | |
| 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" | |
| 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 | |