"""The one-property console entrypoint for interactive sense-checking.""" from __future__ import annotations import dataclasses import pytest from datatypes.epc.domain.epc import Epc from datatypes.epc.domain.epc_property_data import EpcPropertyData from harness.console import DEFAULT_CATALOGUE, run_modelling, run_one from repositories.product.product_json_repository import ProductJsonRepository from tests.domain.sap10_calculator.worksheet._elmhurst_worksheet_000490 import ( build_epc as _build_uninsulated_cavity_and_floor_epc, ) # Every Measure Type the four fabric generators can emit; the harness catalogue # must price all of them or an offline run raises mid-pipeline. _GENERATOR_MEASURE_TYPES = ( "cavity_wall_insulation", "loft_insulation", "suspended_floor_insulation", "solid_floor_insulation", "mechanical_ventilation", ) def _uninsulated_lodged_epc() -> EpcPropertyData: epc = _build_uninsulated_cavity_and_floor_epc() return dataclasses.replace( epc, energy_rating_current=57, current_energy_efficiency_band=Epc.D, co2_emissions_current=3.0, energy_consumption_current=300, ) def test_run_one_returns_a_plan_and_prints_the_table( capsys: pytest.CaptureFixture[str], ) -> None: # Arrange epc: EpcPropertyData = _uninsulated_lodged_epc() # Act — run one property end-to-end with no database, against the default # sample catalogue. plan = run_one(epc, goal_band="C") # Assert — a multi-measure Plan came back, and its sense-check table printed. assert len(plan.measures) >= 1 printed: str = capsys.readouterr().out assert "Plan SAP" in printed assert "cavity_wall_insulation" in printed def test_run_modelling_inspects_a_plan_without_baseline_or_lodged_performance() -> None: # Arrange — the RAW 000490 fixture, with NO lodged recorded-performance, so # the Baseline stage could not run on it. Modelling re-scores the EPC itself. epc: EpcPropertyData = _build_uninsulated_cavity_and_floor_epc() # Act — Modelling only, no Ingestion / Baseline, no database. plan = run_modelling(epc, goal_band="C", print_table=False) # Assert — a multi-measure Plan came straight out of Modelling. assert len(plan.measures) >= 1 def test_sample_catalogue_prices_every_generator_measure_type() -> None: # Arrange — the default offline catalogue. products: ProductJsonRepository = ProductJsonRepository(DEFAULT_CATALOGUE) # Act / Assert — get() raises if a Measure Type is unpriced, so an offline # run over arbitrary EPCs never dies on a missing catalogue entry. for measure_type in _GENERATOR_MEASURE_TYPES: products.get(measure_type) def test_run_one_threads_a_current_market_value_onto_the_plan() -> None: # Arrange epc: EpcPropertyData = _uninsulated_lodged_epc() # Act — supply a Property Valuation so the Plan can value the uplift. plan = run_one( epc, goal_band="C", current_market_value=250_000.0, print_table=False ) # Assert — the value reached the Plan, which derives its Valuation Uplift # from it (the £ amount is 0 here as 000490 stays within band D). assert plan.current_market_value == 250_000.0 assert plan.valuation.average_value is not None