Skip to content

Commit ba42051

Browse files
committed
test(process): use FakeProcessUnit test double
1 parent 1f418ef commit ba42051

1 file changed

Lines changed: 33 additions & 28 deletions

File tree

tests/libecalc/process/process_solver/solvers/test_speed_solver.py

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from collections.abc import Callable
12
from typing import Final
23

34
import pytest
@@ -92,41 +93,43 @@ def speed_func(configuration: SpeedConfiguration):
9293
assert outlet_stream.pressure_bara == expected_pressure
9394

9495

95-
class FluidNotAchievableProcessUnit(ProcessUnit):
96-
"""Process unit that raises OutletFluidNotAchievableError based on speed.
97-
98-
Behaves like SpeedProcessUnit (pressure = inlet_pressure + speed) except when
99-
the speed matches the failure condition. Supports two modes:
100-
- fails_at_or_above: raises when speed >= threshold (for max-speed failure tests)
101-
- fails_at_or_below: raises when speed <= threshold (for min-speed failure tests)
102-
"""
96+
class FakeProcessUnit(ProcessUnit):
97+
"""Test double whose propagate_stream is supplied as a callable."""
10398

10499
def __init__(
105100
self,
106-
shaft: Shaft,
107-
fluid_service: FluidService,
108-
*,
109-
fails_at_or_above: float | None = None,
110-
fails_at_or_below: float | None = None,
101+
propagate_stream: Callable[[FluidStream], FluidStream],
111102
process_unit_id: ProcessUnitId | None = None,
112103
):
113104
self._id: Final[ProcessUnitId] = process_unit_id or ProcessUnit._create_id()
114-
self._shaft = shaft
115-
self._fluid_service = fluid_service
116-
self._fails_at_or_above = fails_at_or_above
117-
self._fails_at_or_below = fails_at_or_below
105+
self._propagate_stream = propagate_stream
118106

119107
def get_id(self) -> ProcessUnitId:
120108
return self._id
121109

122110
def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream:
123-
speed = self._shaft.get_speed()
124-
should_fail = (self._fails_at_or_above is not None and speed >= self._fails_at_or_above) or (
125-
self._fails_at_or_below is not None and speed <= self._fails_at_or_below
111+
return self._propagate_stream(inlet_stream)
112+
113+
114+
def _failing_speed_unit(
115+
shaft: Shaft,
116+
fluid_service: FluidService,
117+
*,
118+
fails_at_or_above: float | None = None,
119+
fails_at_or_below: float | None = None,
120+
) -> FakeProcessUnit:
121+
"""Build a FakeProcessUnit that mirrors `pressure = inlet + speed` but raises
122+
OutletFluidNotAchievableError when the shaft speed crosses the given threshold."""
123+
unit_id = ProcessUnit._create_id()
124+
125+
def _propagate(inlet_stream: FluidStream) -> FluidStream:
126+
speed = shaft.get_speed()
127+
should_fail = (fails_at_or_above is not None and speed >= fails_at_or_above) or (
128+
fails_at_or_below is not None and speed <= fails_at_or_below
126129
)
127130
if should_fail:
128131
raise OutletFluidNotAchievableError(
129-
process_unit_id=self._id,
132+
process_unit_id=unit_id,
130133
unachievable_operating_point=CompressorOperatingPoint(
131134
inlet_pressure_bara=inlet_stream.pressure_bara,
132135
inlet_temperature_kelvin=inlet_stream.temperature_kelvin,
@@ -136,13 +139,15 @@ def propagate_stream(self, inlet_stream: FluidStream) -> FluidStream:
136139
speed=speed,
137140
),
138141
)
139-
return self._fluid_service.create_stream_from_standard_rate(
142+
return fluid_service.create_stream_from_standard_rate(
140143
fluid_model=inlet_stream.fluid_model,
141144
pressure_bara=inlet_stream.pressure_bara + speed,
142145
standard_rate_m3_per_day=inlet_stream.standard_rate_sm3_per_day,
143146
temperature_kelvin=inlet_stream.temperature_kelvin,
144147
)
145148

149+
return FakeProcessUnit(propagate_stream=_propagate, process_unit_id=unit_id)
150+
146151

147152
def test_min_speed_fluid_not_achievable_target_achievable(
148153
search_strategy_factory,
@@ -152,7 +157,7 @@ def test_min_speed_fluid_not_achievable_target_achievable(
152157
fluid_service,
153158
):
154159
"""OutletFluidNotAchievableError at min speed: binary search finds higher effective min; target still reachable."""
155-
unit = FluidNotAchievableProcessUnit(shaft=shaft, fluid_service=fluid_service, fails_at_or_below=300)
160+
unit = _failing_speed_unit(shaft=shaft, fluid_service=fluid_service, fails_at_or_below=300)
156161
speed_solver = SpeedSolver(
157162
search_strategy=search_strategy_factory(),
158163
root_finding_strategy=root_finding_strategy,
@@ -179,7 +184,7 @@ def test_min_speed_fluid_not_achievable_target_not_achievable(
179184
fluid_service,
180185
):
181186
"""OutletFluidNotAchievableError at min speed: effective min too high → target below minimum achievable."""
182-
unit = FluidNotAchievableProcessUnit(shaft=shaft, fluid_service=fluid_service, fails_at_or_below=400)
187+
unit = _failing_speed_unit(shaft=shaft, fluid_service=fluid_service, fails_at_or_below=400)
183188
speed_solver = SpeedSolver(
184189
search_strategy=search_strategy_factory(),
185190
root_finding_strategy=root_finding_strategy,
@@ -209,7 +214,7 @@ def test_max_speed_fluid_not_achievable_target_achievable(
209214
fluid_service,
210215
):
211216
"""OutletFluidNotAchievableError at max speed: binary search finds lower effective max; target still reachable."""
212-
unit = FluidNotAchievableProcessUnit(shaft=shaft, fluid_service=fluid_service, fails_at_or_above=500)
217+
unit = _failing_speed_unit(shaft=shaft, fluid_service=fluid_service, fails_at_or_above=500)
213218
speed_solver = SpeedSolver(
214219
search_strategy=search_strategy_factory(),
215220
root_finding_strategy=root_finding_strategy,
@@ -236,7 +241,7 @@ def test_max_speed_fluid_not_achievable_target_not_achievable(
236241
fluid_service,
237242
):
238243
"""OutletFluidNotAchievableError at max speed: binary search finds lower effective max; target not reachable."""
239-
unit = FluidNotAchievableProcessUnit(shaft=shaft, fluid_service=fluid_service, fails_at_or_above=300)
244+
unit = _failing_speed_unit(shaft=shaft, fluid_service=fluid_service, fails_at_or_above=300)
240245
speed_solver = SpeedSolver(
241246
search_strategy=search_strategy_factory(),
242247
root_finding_strategy=root_finding_strategy,
@@ -266,7 +271,7 @@ def test_all_speeds_fluid_not_achievable_from_max(
266271
fluid_service,
267272
):
268273
"""All speeds fail EOS when searching from max: pre-check at boundary.min catches it immediately."""
269-
unit = FluidNotAchievableProcessUnit(shaft=shaft, fluid_service=fluid_service, fails_at_or_above=0)
274+
unit = _failing_speed_unit(shaft=shaft, fluid_service=fluid_service, fails_at_or_above=0)
270275
speed_solver = SpeedSolver(
271276
search_strategy=search_strategy_factory(),
272277
root_finding_strategy=root_finding_strategy,
@@ -293,7 +298,7 @@ def test_all_speeds_fluid_not_achievable_from_min(
293298
fluid_service,
294299
):
295300
"""All speeds fail EOS when searching from min: pre-check at boundary.max catches it immediately."""
296-
unit = FluidNotAchievableProcessUnit(shaft=shaft, fluid_service=fluid_service, fails_at_or_below=600)
301+
unit = _failing_speed_unit(shaft=shaft, fluid_service=fluid_service, fails_at_or_below=600)
297302
speed_solver = SpeedSolver(
298303
search_strategy=search_strategy_factory(),
299304
root_finding_strategy=root_finding_strategy,

0 commit comments

Comments
 (0)