69 lines
2.7 KiB
Python
69 lines
2.7 KiB
Python
|
|
"""`evolve._preflight` — the advisory pre-run feasibility warnings.
|
||
|
|
|
||
|
|
DESIGN.md §39.11 shipped two checks (does the demand fit the plot; is there
|
||
|
|
enough daylit wall for it). §39.17 adds the third, and the reason it is a
|
||
|
|
separate check is the whole point: check 2 divides demand evenly across
|
||
|
|
storeys, but a programme pins rooms to level 0 and the ground floor is the one
|
||
|
|
storey that cannot set itself back to buy more perimeter. Averaging hides a
|
||
|
|
ground floor that is short.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from homemaker_layout import evolve
|
||
|
|
|
||
|
|
EXAMPLES = Path(__file__).resolve().parent.parent / "examples"
|
||
|
|
pytestmark = pytest.mark.skipif(not (EXAMPLES / "harbor-house").is_dir(),
|
||
|
|
reason="examples absent")
|
||
|
|
|
||
|
|
|
||
|
|
def _warnings(progdir, capsys) -> list[str]:
|
||
|
|
evolve._preflight(str(progdir))
|
||
|
|
return [ln for ln in capsys.readouterr().err.splitlines() if ln.startswith("WARNING")]
|
||
|
|
|
||
|
|
|
||
|
|
def _ground(lines):
|
||
|
|
return [ln for ln in lines if "pinned to level 0" in ln]
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize("name", ["harbor-house", "maple-court"])
|
||
|
|
def test_ground_floor_shortfall_is_reported(name, capsys):
|
||
|
|
"""Both plateau programmes pass the averaged check and fail the ground-floor
|
||
|
|
one -- which is the case §39.17 exists to catch."""
|
||
|
|
ground = _ground(_warnings(EXAMPLES / name, capsys))
|
||
|
|
assert len(ground) == 1, f"{name} should warn about its pinned ground floor"
|
||
|
|
assert "courtyard" in ground[0]
|
||
|
|
assert "§39.17" in ground[0]
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize("name", ["health-centre", "programme-house"])
|
||
|
|
def test_programmes_with_a_slack_ground_floor_stay_quiet(name, capsys):
|
||
|
|
"""The two programmes that reach near-zero fails have ground-floor frontage
|
||
|
|
to spare, and must not be warned about it."""
|
||
|
|
assert _ground(_warnings(EXAMPLES / name, capsys)) == []
|
||
|
|
|
||
|
|
|
||
|
|
def test_the_ground_floor_check_is_stricter_than_the_averaged_one(capsys):
|
||
|
|
"""maple-court is the case that shows why averaging is not enough: the
|
||
|
|
per-storey average asks for a far smaller courtyard than the ground floor
|
||
|
|
actually needs. If these ever agree, one of the two checks is redundant."""
|
||
|
|
lines = _warnings(EXAMPLES / "maple-court", capsys)
|
||
|
|
averaged = [ln for ln in lines if "per storey needs" in ln]
|
||
|
|
assert averaged and _ground(lines)
|
||
|
|
|
||
|
|
def m2(line, after):
|
||
|
|
tail = line.split(after, 1)[1]
|
||
|
|
return float("".join(c for c in tail.split("m2")[0] if c.isdigit() or c == "."))
|
||
|
|
|
||
|
|
assert m2(_ground(lines)[0], "roughly") > m2(averaged[0], "Roughly")
|
||
|
|
|
||
|
|
|
||
|
|
def test_preflight_never_raises_on_a_directory_it_cannot_read(tmp_path, capsys):
|
||
|
|
"""Advisory only: it must never be able to stop a run."""
|
||
|
|
evolve._preflight(str(tmp_path))
|
||
|
|
assert _warnings(tmp_path, capsys) == []
|