""" Unit Tests — Assessment & Outlet Pydantic Schemas Tests: - AssessmentCreate: required fields, validation (score range, category) - AssessmentResponse: ORM → Pydantic round-trip - OutletCreate: required fields, validation - OutletResponse: ORM → Pydantic round-trip """ from datetime import datetime, timezone import pytest from pydantic import ValidationError from models.assessment_model import Assessment, AssessmentCreate, AssessmentResponse from models.outlet_model import Outlet, OutletCreate, OutletResponse # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # AssessmentCreate # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class TestAssessmentCreate: def _valid(self, **overrides): return { "category": "A", "item_no": 1, "criteria": "Welcoming Kasir", "score": 4.0, "raw_value": "4", **overrides, } def test_valid_minimal(self): a = AssessmentCreate(**self._valid()) assert a.category == "A" assert a.item_no == 1 assert a.score == 4.0 assert a.notes is None def test_valid_with_notes(self): a = AssessmentCreate(**self._valid(notes="Sangat baik", description="Kasir ramah")) assert a.notes == "Sangat baik" assert a.description == "Kasir ramah" def test_category_required(self): data = self._valid() del data["category"] with pytest.raises(ValidationError) as exc_info: AssessmentCreate(**data) assert any(e["loc"] == ("category",) for e in exc_info.value.errors()) def test_category_max_length_1(self): with pytest.raises(ValidationError): AssessmentCreate(**self._valid(category="AB")) def test_category_empty_string_invalid(self): with pytest.raises(ValidationError): AssessmentCreate(**self._valid(category="")) def test_score_below_minimum(self): with pytest.raises(ValidationError): AssessmentCreate(**self._valid(score=0.5)) def test_score_above_maximum(self): with pytest.raises(ValidationError): AssessmentCreate(**self._valid(score=5.5)) def test_score_boundary_min(self): a = AssessmentCreate(**self._valid(score=1.0)) assert a.score == 1.0 def test_score_boundary_max(self): a = AssessmentCreate(**self._valid(score=5.0)) assert a.score == 5.0 def test_item_no_below_minimum(self): with pytest.raises(ValidationError): AssessmentCreate(**self._valid(item_no=0)) def test_item_no_above_maximum(self): with pytest.raises(ValidationError): AssessmentCreate(**self._valid(item_no=11)) def test_criteria_required(self): data = self._valid() del data["criteria"] with pytest.raises(ValidationError): AssessmentCreate(**data) def test_criteria_empty_invalid(self): with pytest.raises(ValidationError): AssessmentCreate(**self._valid(criteria="")) def test_criteria_max_length(self): with pytest.raises(ValidationError): AssessmentCreate(**self._valid(criteria="x" * 501)) # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # AssessmentResponse — ORM round-trip # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class TestAssessmentResponse: @pytest.mark.asyncio async def test_from_orm(self, sample_assessment: Assessment): resp = AssessmentResponse.model_validate(sample_assessment) assert str(resp.id) == str(sample_assessment.id) assert resp.category == "A" assert resp.item_no == 1 assert resp.score == 4.0 assert resp.raw_value == "4" assert resp.notes == "Baik" # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # OutletCreate # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class TestOutletCreate: def test_valid_minimal(self): o = OutletCreate(name="Outlet A") assert o.name == "Outlet A" assert o.location is None assert o.description is None def test_valid_full(self): o = OutletCreate( name="Outlet B", location="Jl. Merdeka", description="Outlet cabang", ) assert o.location == "Jl. Merdeka" def test_name_required(self): with pytest.raises(ValidationError) as exc_info: OutletCreate() assert any(e["loc"] == ("name",) for e in exc_info.value.errors()) def test_name_empty_invalid(self): with pytest.raises(ValidationError): OutletCreate(name="") def test_name_max_length(self): with pytest.raises(ValidationError): OutletCreate(name="x" * 256) def test_location_max_length(self): with pytest.raises(ValidationError): OutletCreate(name="OK", location="L" * 256) # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # OutletResponse — ORM round-trip # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class TestOutletResponse: @pytest.mark.asyncio async def test_from_orm(self, sample_outlet: Outlet): resp = OutletResponse.model_validate(sample_outlet) assert str(resp.id) == str(sample_outlet.id) assert resp.name == "Outlet Gedung A" assert resp.location == "Jl. Sudirman No. 1"