mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
193 lines
5 KiB
Python
193 lines
5 KiB
Python
import pytest
|
||
|
||
from recommendations.optimiser.funding_optimiser import (
|
||
build_heat_pump_paths,
|
||
run_optimizer,
|
||
)
|
||
|
||
|
||
# ---------------------------------------------------------------------
|
||
# Heat pump path tests (unchanged – these are fine)
|
||
# ---------------------------------------------------------------------
|
||
|
||
def test_build_heat_pump_paths():
|
||
eg1 = build_heat_pump_paths([], ["loft_insulation"])
|
||
assert eg1 == [{'AND': ['loft_insulation', 'air_source_heat_pump']}]
|
||
|
||
eg2 = build_heat_pump_paths(
|
||
["internal_wall_insulation", "external_wall_insulation"],
|
||
["loft_insulation"],
|
||
)
|
||
|
||
assert eg2 == [
|
||
{'AND': ['internal_wall_insulation', 'loft_insulation', 'air_source_heat_pump']},
|
||
{'AND': ['external_wall_insulation', 'loft_insulation', 'air_source_heat_pump']},
|
||
]
|
||
|
||
|
||
# ---------------------------------------------------------------------
|
||
# run_optimizer tests
|
||
# ---------------------------------------------------------------------
|
||
|
||
def test_run_optimizer_empty_input():
|
||
solution, cost, gain = run_optimizer([])
|
||
assert solution is None
|
||
assert cost == 0.0
|
||
assert gain == 0.0
|
||
|
||
|
||
# ---------------------------------------------------------------------
|
||
# StrategicOptimiser mocking boundary
|
||
# ---------------------------------------------------------------------
|
||
|
||
def test_budget_and_target_are_passed_correctly(monkeypatch):
|
||
captured = {}
|
||
|
||
class FakeStrategicOptimiser:
|
||
def __init__(
|
||
self,
|
||
components,
|
||
budget=None,
|
||
target_gain=None,
|
||
allow_slack=False,
|
||
verbose=False,
|
||
):
|
||
captured["components"] = components
|
||
captured["budget"] = budget
|
||
captured["target_gain"] = target_gain
|
||
captured["allow_slack"] = allow_slack
|
||
|
||
self.solution = [{"cost": 100, "gain": 5}]
|
||
self.solution_cost = 100
|
||
self.solution_gain = 5
|
||
|
||
def solve(self):
|
||
pass
|
||
|
||
monkeypatch.setattr(
|
||
"recommendations.optimiser.funding_optimiser.StrategicOptimiser",
|
||
FakeStrategicOptimiser,
|
||
)
|
||
|
||
solution, cost, gain = run_optimizer(
|
||
[[{"cost": 100, "gain": 5}]],
|
||
budget=500,
|
||
sub_target_gain=10,
|
||
allow_slack=True,
|
||
)
|
||
|
||
assert captured["budget"] == 500
|
||
assert captured["target_gain"] == 10
|
||
assert captured["allow_slack"] is True
|
||
|
||
assert cost == 100
|
||
assert gain == 5
|
||
assert solution == [{"cost": 100, "gain": 5}]
|
||
|
||
|
||
def test_sub_target_gain_zero_is_passed_as_zero(monkeypatch):
|
||
captured = {}
|
||
|
||
class FakeStrategicOptimiser:
|
||
def __init__(
|
||
self,
|
||
components,
|
||
budget=None,
|
||
target_gain=None,
|
||
allow_slack=False,
|
||
verbose=False,
|
||
):
|
||
captured["target_gain"] = target_gain
|
||
self.solution = []
|
||
self.solution_cost = 0.0
|
||
self.solution_gain = 0.0
|
||
|
||
def solve(self):
|
||
pass
|
||
|
||
monkeypatch.setattr(
|
||
"recommendations.optimiser.funding_optimiser.StrategicOptimiser",
|
||
FakeStrategicOptimiser,
|
||
)
|
||
|
||
run_optimizer(
|
||
[[{"cost": 100, "gain": 5}]],
|
||
budget=500,
|
||
sub_target_gain=0,
|
||
)
|
||
|
||
assert captured["target_gain"] == 0
|
||
|
||
|
||
def test_sub_target_gain_none_becomes_infinity(monkeypatch):
|
||
captured = {}
|
||
|
||
class FakeStrategicOptimiser:
|
||
def __init__(
|
||
self,
|
||
components,
|
||
budget=None,
|
||
target_gain=None,
|
||
allow_slack=False,
|
||
verbose=False,
|
||
):
|
||
captured["target_gain"] = target_gain
|
||
self.solution = []
|
||
self.solution_cost = 0.0
|
||
self.solution_gain = 0.0
|
||
|
||
def solve(self):
|
||
pass
|
||
|
||
monkeypatch.setattr(
|
||
"recommendations.optimiser.funding_optimiser.StrategicOptimiser",
|
||
FakeStrategicOptimiser,
|
||
)
|
||
|
||
run_optimizer(
|
||
[[{"cost": 100, "gain": 5}]],
|
||
budget=500,
|
||
sub_target_gain=None,
|
||
)
|
||
|
||
assert captured["target_gain"] == None
|
||
|
||
|
||
def test_target_only_case(monkeypatch):
|
||
captured = {}
|
||
|
||
class FakeStrategicOptimiser:
|
||
def __init__(
|
||
self,
|
||
components,
|
||
budget=None,
|
||
target_gain=None,
|
||
allow_slack=False,
|
||
verbose=False,
|
||
):
|
||
captured["budget"] = budget
|
||
captured["target_gain"] = target_gain
|
||
|
||
self.solution = [{"cost": 50, "gain": 10}]
|
||
self.solution_cost = 50
|
||
self.solution_gain = 10
|
||
|
||
def solve(self):
|
||
pass
|
||
|
||
monkeypatch.setattr(
|
||
"recommendations.optimiser.funding_optimiser.StrategicOptimiser",
|
||
FakeStrategicOptimiser,
|
||
)
|
||
|
||
solution, cost, gain = run_optimizer(
|
||
[[{"cost": 50, "gain": 10}]],
|
||
sub_target_gain=10,
|
||
)
|
||
|
||
assert captured["budget"] is None
|
||
assert captured["target_gain"] == 10
|
||
|
||
assert cost == 50
|
||
assert gain == 10
|
||
assert solution == [{"cost": 50, "gain": 10}]
|