import json from pathlib import Path from unittest.mock import MagicMock, patch import pytest from datatypes.magicplan.api.response import MagicPlanPlan, PlanSummary from domain.magicplan.mapper import map_plan from domain.magicplan.models import Plan from backend.magic_plan.magic_plan_client import MagicPlanClient from backend.magic_plan.magic_plan_service import MagicPlanService FIXTURE_DIR = Path(__file__).parents[2] / "magic_plan" PLAN_ID = "a7285ed1-878d-47eb-8aa6-85ef9e187516" @pytest.fixture(scope="module") def domain_plan() -> Plan: data = json.loads( (FIXTURE_DIR / "magicplan_api_plan_response_example.json").read_text() ) return map_plan(MagicPlanPlan.model_validate(data["data"])) @pytest.fixture(scope="module") def api_magic_plan() -> MagicPlanPlan: data = json.loads( (FIXTURE_DIR / "magicplan_api_plan_response_example.json").read_text() ) return MagicPlanPlan.model_validate(data["data"]) @pytest.fixture(scope="module") def plan_summary() -> PlanSummary: data = json.loads( (FIXTURE_DIR / "magicplan_api_plan_response_example.json").read_text() ) return MagicPlanPlan.model_validate(data["data"]).plan @pytest.fixture() def mock_client() -> MagicMock: return MagicMock(spec=MagicPlanClient) def _make_service(mock_client: MagicMock) -> MagicPlanService: return MagicPlanService(client=mock_client) # --- no match --- def test_run_raises_when_no_plan_found(mock_client: MagicMock) -> None: # Arrange mock_client.get_plans.return_value.plans = [] service = _make_service(mock_client) # Act / Assert with pytest.raises(ValueError, match="No MagicPlan found"): service.run("99 Nowhere Road London SW1A 1AA") # --- match found --- def test_run_fetches_plan_with_matched_id( mock_client: MagicMock, api_magic_plan: MagicPlanPlan, plan_summary: PlanSummary, domain_plan: Plan, ) -> None: # Arrange mock_client.get_plans.return_value.plans = [plan_summary] mock_client.get_plan.return_value = api_magic_plan service = _make_service(mock_client) with patch( "backend.magic_plan.magic_plan_service.find_matching_plan", return_value=plan_summary, ), patch("backend.magic_plan.magic_plan_service.save_plan"), patch( "backend.magic_plan.magic_plan_service.db_session" ): service.run("2 Laburnum Way Bromley BR2 8BZ") # Assert mock_client.get_plan.assert_called_once_with(plan_summary.id) def test_run_returns_mapped_plan( mock_client: MagicMock, api_magic_plan: MagicPlanPlan, plan_summary: PlanSummary, domain_plan: Plan, ) -> None: # Arrange mock_client.get_plans.return_value.plans = [plan_summary] mock_client.get_plan.return_value = api_magic_plan service = _make_service(mock_client) with patch( "backend.magic_plan.magic_plan_service.find_matching_plan", return_value=plan_summary, ), patch("backend.magic_plan.magic_plan_service.save_plan"), patch( "backend.magic_plan.magic_plan_service.db_session" ): result = service.run("2 Laburnum Way Bromley BR2 8BZ") # Assert assert isinstance(result, Plan) assert result.uid == PLAN_ID def test_run_calls_save_plan_with_mapped_plan( mock_client: MagicMock, api_magic_plan: MagicPlanPlan, plan_summary: PlanSummary, ) -> None: # Arrange mock_client.get_plans.return_value.plans = [plan_summary] mock_client.get_plan.return_value = api_magic_plan service = _make_service(mock_client) with patch( "backend.magic_plan.magic_plan_service.find_matching_plan", return_value=plan_summary, ), patch("backend.magic_plan.magic_plan_service.save_plan") as mock_save, patch( "backend.magic_plan.magic_plan_service.db_session" ): service.run("2 Laburnum Way Bromley BR2 8BZ") # Assert — save_plan called with a Plan whose uid matches call_args = mock_save.call_args saved_plan: Plan = call_args[0][1] assert saved_plan.uid == PLAN_ID def test_run_accepts_uprn_without_error( mock_client: MagicMock, api_magic_plan: MagicPlanPlan, plan_summary: PlanSummary, ) -> None: # Arrange mock_client.get_plans.return_value.plans = [plan_summary] mock_client.get_plan.return_value = api_magic_plan service = _make_service(mock_client) with patch( "backend.magic_plan.magic_plan_service.find_matching_plan", return_value=plan_summary, ), patch("backend.magic_plan.magic_plan_service.save_plan"), patch( "backend.magic_plan.magic_plan_service.db_session" ): service.run("2 Laburnum Way Bromley BR2 8BZ", uprn="100023336956")