mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
223 lines
6 KiB
Python
223 lines
6 KiB
Python
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
import domain.magicplan.api.response as api
|
|
from domain.magicplan.api.response import MagicPlanPlan, Symbol, Vec3, WallItem
|
|
from domain.magicplan.mapper import (
|
|
_map_window, # pyright: ignore[reportPrivateUsage]
|
|
map_address,
|
|
map_plan,
|
|
)
|
|
from domain.magicplan.models import Plan
|
|
|
|
FIXTURE_DIR = Path(__file__).parents[3] / "tests" / "magic_plan"
|
|
PLAN_ID = "72efd2e0-b2b9-48cd-b82e-41f5b3166c9a"
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def raw_data() -> dict[str, Any]:
|
|
payload = json.loads(
|
|
(FIXTURE_DIR / "magicplan_api_plan_response.json").read_text()
|
|
)
|
|
return payload["data"]
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def mp(raw_data: dict[str, Any]) -> MagicPlanPlan:
|
|
return MagicPlanPlan.model_validate(raw_data)
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def plan(mp: MagicPlanPlan) -> Plan:
|
|
return map_plan(mp)
|
|
|
|
|
|
# --- Plan-level ---
|
|
|
|
|
|
def test_plan_uid(plan: Plan) -> None:
|
|
assert plan.uid == PLAN_ID
|
|
|
|
|
|
def test_plan_postcode(plan: Plan) -> None:
|
|
assert plan.postcode == "BR2 8DU"
|
|
|
|
|
|
def test_plan_address(plan: Plan) -> None:
|
|
assert plan.address == "20 Larch Way, Bromley, GB"
|
|
|
|
|
|
def test_floor_count(plan: Plan) -> None:
|
|
assert len(plan.floors) == 2
|
|
|
|
|
|
# --- Room dimensions ---
|
|
|
|
|
|
def test_first_room_name(plan: Plan) -> None:
|
|
assert plan.floors[0].rooms[0].name == "Kitchen"
|
|
|
|
|
|
def test_room_dimensions_are_floats(plan: Plan) -> None:
|
|
room = plan.floors[0].rooms[0]
|
|
assert isinstance(room.width_m, float)
|
|
assert isinstance(room.length_m, float)
|
|
assert isinstance(room.area_m2, float)
|
|
|
|
|
|
def test_room_area_rounded_to_2dp(plan: Plan) -> None:
|
|
room = plan.floors[0].rooms[0]
|
|
assert room.area_m2 == 9.39
|
|
|
|
|
|
def test_room_dimensions_parsed_from_string(plan: Plan) -> None:
|
|
room = plan.floors[0].rooms[0]
|
|
assert room.width_m == 3.19
|
|
assert room.length_m == 2.94
|
|
|
|
|
|
# --- Windows ---
|
|
|
|
|
|
def test_kitchen_has_windows(plan: Plan) -> None:
|
|
assert len(plan.floors[0].rooms[0].windows) >= 1
|
|
|
|
|
|
def test_window_fields_are_floats(plan: Plan) -> None:
|
|
window = plan.floors[0].rooms[0].windows[0]
|
|
assert isinstance(window.width_m, float)
|
|
assert isinstance(window.height_m, float)
|
|
assert isinstance(window.area_m2, float)
|
|
|
|
|
|
def test_window_opening_type_prefix_stripped(plan: Plan) -> None:
|
|
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) -> None:
|
|
window = plan.floors[0].rooms[0].windows[0]
|
|
assert window.area_m2 == round(window.width_m * window.height_m, 2)
|
|
|
|
|
|
def test_window_dimensions_rounded_to_2dp(plan: Plan) -> None:
|
|
window = plan.floors[0].rooms[0].windows[0]
|
|
assert window.width_m == 0.90
|
|
assert window.height_m == 1.00
|
|
assert window.area_m2 == 0.90
|
|
|
|
|
|
def test_hallway_has_no_windows(plan: Plan) -> None:
|
|
hallway = plan.floors[0].rooms[3]
|
|
assert hallway.name == "Hallway"
|
|
assert hallway.windows == []
|
|
|
|
|
|
def test_floor1_window_opening_type_awning(plan: Plan) -> None:
|
|
bedroom1 = plan.floors[1].rooms[0]
|
|
assert bedroom1.name == "Bedroom 1"
|
|
assert bedroom1.windows[0].opening_type == "awning"
|
|
|
|
|
|
# --- Doors ---
|
|
|
|
|
|
def test_kitchen_has_doors(plan: Plan) -> None:
|
|
assert len(plan.floors[0].rooms[0].doors) >= 1
|
|
|
|
|
|
def test_door_width_is_float(plan: Plan) -> None:
|
|
door = plan.floors[0].rooms[0].doors[0]
|
|
assert isinstance(door.width_mm, float)
|
|
|
|
|
|
def test_door_width_rounded_to_2dp(plan: Plan) -> None:
|
|
door = plan.floors[0].rooms[0].doors[0]
|
|
assert door.width_mm == 800.0
|
|
|
|
|
|
def test_door_height_is_correct(plan: Plan) -> None:
|
|
# Kitchen doorhinged has size.z = 2.04 m = 2040 mm
|
|
door = plan.floors[0].rooms[0].doors[0]
|
|
assert door.height_mm == 2040.0
|
|
|
|
|
|
# --- Ventilation ---
|
|
|
|
|
|
def test_window_with_no_custom_fields_has_no_ventilation() -> None:
|
|
wi = WallItem(
|
|
uid="test",
|
|
symbol=Symbol(id="windowcasement", name="Casement Window", valid=True),
|
|
size=Vec3(x=1.0, y=0.0, z=1.2),
|
|
position=Vec3(x=0.0, y=0.0, z=0.0),
|
|
rotation=Vec3(x=0.0, y=0.0, z=0.0),
|
|
)
|
|
|
|
window = _map_window(wi)
|
|
|
|
assert window.ventilation is None
|
|
|
|
|
|
def test_kitchen_window_has_ventilation(plan: Plan) -> None:
|
|
window = plan.floors[0].rooms[0].windows[0]
|
|
|
|
assert window.ventilation is not None
|
|
assert window.ventilation.trickle_vent_area_mm2 == 1700
|
|
|
|
|
|
def test_toilet_door_has_ventilation_undercut(plan: Plan) -> None:
|
|
toilet_doors = plan.floors[0].rooms[2].doors
|
|
hinged = next(d for d in toilet_doors if d.ventilation is not None)
|
|
|
|
assert hinged.ventilation is not None
|
|
assert hinged.ventilation.undercut_mm == 70.0
|
|
|
|
|
|
def test_doorglass_is_classified_as_window(plan: Plan) -> None:
|
|
room = plan.floors[0].rooms[1]
|
|
|
|
assert "doorglass" in [w.opening_type for w in room.windows]
|
|
|
|
|
|
def test_glass_door_ventilation_opening_type(plan: Plan) -> None:
|
|
room = plan.floors[0].rooms[1]
|
|
glass = next(w for w in room.windows if w.opening_type == "doorglass")
|
|
|
|
assert glass.ventilation is not None
|
|
assert glass.ventilation.opening_type == "External.Door"
|
|
|
|
|
|
# --- Address unit tests ---
|
|
|
|
|
|
def test_map_address_with_street_and_number() -> None:
|
|
addr = api.Address(street_number="2", street="Laburnum Way", city="Bromley", country="GB")
|
|
|
|
assert map_address(addr) == "2 Laburnum Way, Bromley, GB"
|
|
|
|
|
|
def test_map_address_with_street_number_only() -> None:
|
|
addr = api.Address(street_number="2", city="Bromley", country="GB")
|
|
|
|
assert map_address(addr) == "2, Bromley, GB"
|
|
|
|
|
|
def test_map_address_with_street_only() -> None:
|
|
addr = api.Address(street="Laburnum Way", city="Bromley", country="GB")
|
|
|
|
assert map_address(addr) == "Laburnum Way, Bromley, GB"
|
|
|
|
|
|
def test_map_address_city_absent_is_omitted() -> None:
|
|
addr = api.Address(street_number="2", street="Laburnum Way", country="GB")
|
|
|
|
assert map_address(addr) == "2 Laburnum Way, GB"
|
|
|
|
|
|
def test_map_address_none_returns_none() -> None:
|
|
assert map_address(None) is None
|