diff --git a/datatypes/magicplan/domain/mapper.py b/datatypes/magicplan/domain/mapper.py index 00efba3d..c841a963 100644 --- a/datatypes/magicplan/domain/mapper.py +++ b/datatypes/magicplan/domain/mapper.py @@ -24,7 +24,7 @@ def _map_room(r) -> Room: name=r.name, width=width, length=length, - area=r.area, + area=round(r.area, 2), windows=[_map_window(wi) for wi in r.wall_items if wi.symbol.id.startswith("window")], doors=[_map_door(wi) for wi in r.wall_items if wi.symbol.id.startswith("door")], ) @@ -34,19 +34,19 @@ def _parse_dimensions(dimensions: str | None) -> tuple[float, float]: if not dimensions: return 0.0, 0.0 parts = dimensions.split(" x ") - width = float(parts[0].split(" m")[0]) - length = float(parts[1].split(" m")[0]) + width = round(float(parts[0].split(" m")[0]), 2) + length = round(float(parts[1].split(" m")[0]), 2) return width, length def _map_window(wi) -> Window: return Window( - width=wi.size.x, - height=wi.size.z, - area=wi.size.x * wi.size.z, + width=round(wi.size.x, 2), + height=round(wi.size.z, 2), + area=round(wi.size.x * wi.size.z, 2), opening_type=wi.symbol.id.removeprefix("window"), ) def _map_door(wi) -> Door: - return Door(width=wi.size.x) + return Door(width=round(wi.size.x, 2)) diff --git a/datatypes/magicplan/domain/tests/test_mapper.py b/datatypes/magicplan/domain/tests/test_mapper.py new file mode 100644 index 00000000..6fc80262 --- /dev/null +++ b/datatypes/magicplan/domain/tests/test_mapper.py @@ -0,0 +1,106 @@ +import json +from pathlib import Path +from typing import Any + +import pytest +from pytest import approx + +from datatypes.magicplan.api.response import MagicPlan +from datatypes.magicplan.domain.mapper import map_plan +from datatypes.magicplan.domain.models import Plan + +FIXTURE_DIR = Path(__file__).parents[4] / "backend" / "magic_plan" +PLAN_ID = "a7285ed1-878d-47eb-8aa6-85ef9e187516" + + +@pytest.fixture(scope="module") +def raw_data() -> dict[str, Any]: + payload = json.loads( + (FIXTURE_DIR / "magicplan_api_plan_response_example.json").read_text() + ) + return payload["data"] + + +@pytest.fixture(scope="module") +def mp(raw_data: dict[str, Any]) -> MagicPlan: + return MagicPlan.model_validate(raw_data) + + +@pytest.fixture(scope="module") +def plan(mp: MagicPlan) -> Plan: + return map_plan(mp) + + +def test_plan_uid(plan: Plan): + assert plan.uid == PLAN_ID + + +def test_floor_count(plan: Plan): + assert len(plan.floors) == 2 + + +def test_first_room_name(plan: Plan): + assert plan.floors[0].rooms[0].name == "Kitchen" + + +def test_room_dimensions_are_floats(plan: Plan): + room = plan.floors[0].rooms[0] + assert isinstance(room.width, float) + assert isinstance(room.length, float) + assert isinstance(room.area, float) + + +def test_room_area_rounded_to_2dp(plan: Plan): + room = plan.floors[0].rooms[0] + assert room.area == 7.95 + + +def test_room_dimensions_parsed_from_string(plan: Plan): + room = plan.floors[0].rooms[0] + assert room.width == pytest.approx(2.67) + assert room.length == pytest.approx(2.98) + + +def test_kitchen_has_windows(plan: Plan): + room = plan.floors[0].rooms[0] + assert len(room.windows) >= 1 + + +def test_window_fields_are_floats(plan: Plan): + window = plan.floors[0].rooms[0].windows[0] + assert isinstance(window.width, float) + assert isinstance(window.height, float) + assert isinstance(window.area, float) + + +def test_window_opening_type_prefix_stripped(plan: Plan): + window = plan.floors[0].rooms[0].windows[0] + assert not window.opening_type.startswith("window") + assert window.opening_type == "casement" + + +def test_window_area_is_width_times_height(plan: Plan): + window = plan.floors[0].rooms[0].windows[0] + assert window.area == pytest.approx(window.width * window.height, rel=1e-2) + + +def test_window_dimensions_rounded_to_2dp(plan: Plan): + window = plan.floors[0].rooms[0].windows[0] + assert window.width == 1.40 + assert window.height == 1.20 + assert window.area == 1.68 + + +def test_door_width_rounded_to_2dp(plan: Plan): + door = plan.floors[0].rooms[0].doors[0] + assert door.width == 0.79 + + +def test_kitchen_has_doors(plan: Plan): + room = plan.floors[0].rooms[0] + assert len(room.doors) >= 1 + + +def test_door_width_is_float(plan: Plan): + door = plan.floors[0].rooms[0].doors[0] + assert isinstance(door.width, float)