Spaces:
Sleeping
Sleeping
| """ | |
| Unit Tests β Pydantic Visit/Checklist/Photo Schemas | |
| Tests: | |
| - VisitCreate: required fields, validation rules, defaults | |
| - VisitUpdate: all-optional, partial updates | |
| - VisitResponse: from_attributes (ORM β Pydantic) | |
| - ChecklistCreate / ChecklistUpdate | |
| - PhotoModel schema | |
| """ | |
| from datetime import datetime, timezone | |
| import pytest | |
| from pydantic import ValidationError | |
| from models.visit_model import Visit, VisitCreate, VisitUpdate, VisitResponse | |
| from models.checklist_model import Checklist, ChecklistCreate, ChecklistUpdate | |
| # βββββββββββββββββββββββββββββββββββββββββββ | |
| # VisitCreate | |
| # βββββββββββββββββββββββββββββββββββββββββββ | |
| class TestVisitCreate: | |
| def _valid(self, **overrides): | |
| return { | |
| "title": "Site Inspection", | |
| "visit_date": datetime(2026, 5, 1, 9, 0, tzinfo=timezone.utc), | |
| **overrides, | |
| } | |
| def test_valid_minimal(self): | |
| v = VisitCreate(**self._valid()) | |
| assert v.title == "Site Inspection" | |
| assert v.status == "pending" # default | |
| assert v.description is None | |
| assert v.location is None | |
| def test_valid_full(self): | |
| v = VisitCreate(**self._valid( | |
| description="Monthly check", | |
| location="Gedung A", | |
| status="in_progress", | |
| )) | |
| assert v.location == "Gedung A" | |
| assert v.status == "in_progress" | |
| def test_title_required(self): | |
| with pytest.raises(ValidationError) as exc_info: | |
| VisitCreate(visit_date=datetime(2026, 5, 1, 9, 0)) | |
| errors = exc_info.value.errors() | |
| assert any(e["loc"] == ("title",) for e in errors) | |
| def test_title_empty_string_invalid(self): | |
| with pytest.raises(ValidationError): | |
| VisitCreate(**self._valid(title="")) | |
| def test_title_too_long(self): | |
| with pytest.raises(ValidationError): | |
| VisitCreate(**self._valid(title="x" * 256)) | |
| def test_visit_date_required(self): | |
| with pytest.raises(ValidationError): | |
| VisitCreate(title="Test") | |
| def test_location_max_length(self): | |
| with pytest.raises(ValidationError): | |
| VisitCreate(**self._valid(location="L" * 256)) | |
| # βββββββββββββββββββββββββββββββββββββββββββ | |
| # VisitUpdate | |
| # βββββββββββββββββββββββββββββββββββββββββββ | |
| class TestVisitUpdate: | |
| def test_all_optional_empty(self): | |
| u = VisitUpdate() | |
| assert u.title is None | |
| assert u.status is None | |
| def test_partial_update(self): | |
| u = VisitUpdate(status="completed") | |
| assert u.status == "completed" | |
| assert u.title is None | |
| def test_title_empty_invalid(self): | |
| with pytest.raises(ValidationError): | |
| VisitUpdate(title="") | |
| # βββββββββββββββββββββββββββββββββββββββββββ | |
| # VisitResponse β ORM round-trip | |
| # βββββββββββββββββββββββββββββββββββββββββββ | |
| class TestVisitResponse: | |
| def test_from_orm(self, sample_visit: Visit): | |
| """VisitResponse must serialize from an ORM object (from_attributes).""" | |
| resp = VisitResponse.model_validate(sample_visit) | |
| assert str(resp.id) == str(sample_visit.id) | |
| assert resp.title == sample_visit.title | |
| assert resp.status == sample_visit.status | |
| # Mark as async because sample_visit is an async fixture | |
| async def test_from_orm_async(self, sample_visit): | |
| resp = VisitResponse.model_validate(sample_visit) | |
| assert resp.title == "Test Site Inspection" | |
| assert resp.location == "Gedung A" | |
| # βββββββββββββββββββββββββββββββββββββββββββ | |
| # ChecklistCreate / ChecklistUpdate | |
| # βββββββββββββββββββββββββββββββββββββββββββ | |
| class TestChecklistSchemas: | |
| def test_create_minimal(self): | |
| c = ChecklistCreate(item_name="Panel check") | |
| assert c.item_name == "Panel check" | |
| assert c.is_checked is False # default | |
| assert c.notes is None | |
| def test_create_with_notes(self): | |
| c = ChecklistCreate(item_name="Grounding", is_checked=True, notes="OK") | |
| assert c.is_checked is True | |
| assert c.notes == "OK" | |
| def test_create_empty_name_invalid(self): | |
| with pytest.raises(ValidationError): | |
| ChecklistCreate(item_name="") | |
| def test_update_all_optional(self): | |
| u = ChecklistUpdate() | |
| assert u.is_checked is None | |
| assert u.item_name is None | |
| def test_update_toggle(self): | |
| u = ChecklistUpdate(is_checked=True) | |
| assert u.is_checked is True | |