mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
test(fixtures): build_epc() deep-copies its windows so callers can't leak state
The worksheet build_epc() fixtures wrapped a module-level SECTION_6_VERTICAL_ WINDOWS tuple in list(), so every call returned the SAME SapWindow objects. A test that mutated a returned window (the glazing slices flip glazing_type to single) leaked that change into every later build_epc() -- which surfaced as double_glazing-product failures in the first-run integration tests only when test_console ran first in the same process. Deep-copy the windows per call in all six fixtures (000474/477/480/487/490/516) so each EpcPropertyData owns an independent window graph, and drop the now-redundant defensive copy at the glazing test's call site. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
456a81df0a
commit
4783ff9dfd
7 changed files with 33 additions and 12 deletions
|
|
@ -19,6 +19,7 @@ Distinct features vs prior fixtures:
|
||||||
first 5.27) — the upper storey is smaller than the ground
|
first 5.27) — the upper storey is smaller than the ground
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import copy
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from datatypes.epc.domain.epc_property_data import (
|
from datatypes.epc.domain.epc_property_data import (
|
||||||
|
|
@ -164,7 +165,10 @@ def build_epc() -> EpcPropertyData:
|
||||||
heated_rooms_count=3,
|
heated_rooms_count=3,
|
||||||
door_count=2,
|
door_count=2,
|
||||||
low_energy_fixed_lighting_bulbs_count=8,
|
low_energy_fixed_lighting_bulbs_count=8,
|
||||||
sap_windows=list(SECTION_6_VERTICAL_WINDOWS),
|
# Deep-copy so each build_epc() owns its windows (the module-level
|
||||||
|
# SECTION_6_VERTICAL_WINDOWS tuple holds shared SapWindow objects; a
|
||||||
|
# caller mutating a returned window would otherwise leak across calls).
|
||||||
|
sap_windows=[copy.deepcopy(window) for window in SECTION_6_VERTICAL_WINDOWS],
|
||||||
percent_draughtproofed=78,
|
percent_draughtproofed=78,
|
||||||
extensions_count=2,
|
extensions_count=2,
|
||||||
blocked_chimneys_count=0,
|
blocked_chimneys_count=0,
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ Distinct features vs prior fixtures:
|
||||||
flat ceiling — just stud walls (1.5/1.3 height) + slopes
|
flat ceiling — just stud walls (1.5/1.3 height) + slopes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import copy
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from datatypes.epc.domain.epc_property_data import (
|
from datatypes.epc.domain.epc_property_data import (
|
||||||
|
|
@ -137,7 +138,10 @@ def build_epc() -> EpcPropertyData:
|
||||||
door_count=2,
|
door_count=2,
|
||||||
percent_draughtproofed=100,
|
percent_draughtproofed=100,
|
||||||
low_energy_fixed_lighting_bulbs_count=SECTION_5_BULB_COUNT_LEL,
|
low_energy_fixed_lighting_bulbs_count=SECTION_5_BULB_COUNT_LEL,
|
||||||
sap_windows=list(SECTION_6_VERTICAL_WINDOWS),
|
# Deep-copy so each build_epc() owns its windows (the module-level
|
||||||
|
# SECTION_6_VERTICAL_WINDOWS tuple holds shared SapWindow objects; a
|
||||||
|
# caller mutating a returned window would otherwise leak across calls).
|
||||||
|
sap_windows=[copy.deepcopy(window) for window in SECTION_6_VERTICAL_WINDOWS],
|
||||||
blocked_chimneys_count=0,
|
blocked_chimneys_count=0,
|
||||||
dwelling_type="Mid-Terrace house",
|
dwelling_type="Mid-Terrace house",
|
||||||
built_form="Mid-Terrace",
|
built_form="Mid-Terrace",
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ Differs from 000487 along several useful axes:
|
||||||
- No alternative wall (vs 1 timber-frame alt wall on the extension)
|
- No alternative wall (vs 1 timber-frame alt wall on the extension)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import copy
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from datatypes.epc.domain.epc_property_data import (
|
from datatypes.epc.domain.epc_property_data import (
|
||||||
|
|
@ -180,7 +181,10 @@ def build_epc() -> EpcPropertyData:
|
||||||
door_count=2, # cert lodges 2 doors total
|
door_count=2, # cert lodges 2 doors total
|
||||||
percent_draughtproofed=100,
|
percent_draughtproofed=100,
|
||||||
low_energy_fixed_lighting_bulbs_count=SECTION_5_BULB_COUNT_LEL,
|
low_energy_fixed_lighting_bulbs_count=SECTION_5_BULB_COUNT_LEL,
|
||||||
sap_windows=list(SECTION_6_VERTICAL_WINDOWS),
|
# Deep-copy so each build_epc() owns its windows (the module-level
|
||||||
|
# SECTION_6_VERTICAL_WINDOWS tuple holds shared SapWindow objects; a
|
||||||
|
# caller mutating a returned window would otherwise leak across calls).
|
||||||
|
sap_windows=[copy.deepcopy(window) for window in SECTION_6_VERTICAL_WINDOWS],
|
||||||
extensions_count=1,
|
extensions_count=1,
|
||||||
blocked_chimneys_count=0,
|
blocked_chimneys_count=0,
|
||||||
dwelling_type="Mid-Terrace house",
|
dwelling_type="Mid-Terrace house",
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ values captured below. Treat the LINE_X constants as authoritative; if
|
||||||
they diverge from our code, the bug is on our side.
|
they diverge from our code, the bug is on our side.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import copy
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from datatypes.epc.domain.epc_property_data import (
|
from datatypes.epc.domain.epc_property_data import (
|
||||||
|
|
@ -190,7 +191,10 @@ def build_epc() -> EpcPropertyData:
|
||||||
door_count=1,
|
door_count=1,
|
||||||
percent_draughtproofed=100,
|
percent_draughtproofed=100,
|
||||||
low_energy_fixed_lighting_bulbs_count=SECTION_5_BULB_COUNT_LEL,
|
low_energy_fixed_lighting_bulbs_count=SECTION_5_BULB_COUNT_LEL,
|
||||||
sap_windows=list(SECTION_6_VERTICAL_WINDOWS),
|
# Deep-copy so each build_epc() owns its windows (the module-level
|
||||||
|
# SECTION_6_VERTICAL_WINDOWS tuple holds shared SapWindow objects; a
|
||||||
|
# caller mutating a returned window would otherwise leak across calls).
|
||||||
|
sap_windows=[copy.deepcopy(window) for window in SECTION_6_VERTICAL_WINDOWS],
|
||||||
extensions_count=1,
|
extensions_count=1,
|
||||||
blocked_chimneys_count=0,
|
blocked_chimneys_count=0,
|
||||||
dwelling_type="Enclosed Mid-Terrace house",
|
dwelling_type="Enclosed Mid-Terrace house",
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ Distinct features vs prior fixtures:
|
||||||
- DP = 100%, so (15) = 0.05 (lowest window-infiltration component)
|
- DP = 100%, so (15) = 0.05 (lowest window-infiltration component)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import copy
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from datatypes.epc.domain.epc_property_data import (
|
from datatypes.epc.domain.epc_property_data import (
|
||||||
|
|
@ -146,7 +147,11 @@ def build_epc() -> EpcPropertyData:
|
||||||
heated_rooms_count=4,
|
heated_rooms_count=4,
|
||||||
door_count=2,
|
door_count=2,
|
||||||
low_energy_fixed_lighting_bulbs_count=8,
|
low_energy_fixed_lighting_bulbs_count=8,
|
||||||
sap_windows=list(SECTION_6_VERTICAL_WINDOWS),
|
# Deep-copy so each build_epc() owns its windows: SECTION_6_VERTICAL_
|
||||||
|
# WINDOWS is a module-level tuple of shared SapWindow objects, and a
|
||||||
|
# caller that mutates a returned window (e.g. flipping glazing_type to
|
||||||
|
# test a glazing measure) would otherwise leak into every later call.
|
||||||
|
sap_windows=[copy.deepcopy(window) for window in SECTION_6_VERTICAL_WINDOWS],
|
||||||
percent_draughtproofed=100,
|
percent_draughtproofed=100,
|
||||||
extensions_count=1,
|
extensions_count=1,
|
||||||
blocked_chimneys_count=0,
|
blocked_chimneys_count=0,
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ Distinct features vs prior fixtures:
|
||||||
as 000480 but on a single-part dwelling
|
as 000480 but on a single-part dwelling
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import copy
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from datatypes.epc.domain.epc_property_data import (
|
from datatypes.epc.domain.epc_property_data import (
|
||||||
|
|
@ -175,7 +176,10 @@ def build_epc() -> EpcPropertyData:
|
||||||
],
|
],
|
||||||
percent_draughtproofed=75,
|
percent_draughtproofed=75,
|
||||||
low_energy_fixed_lighting_bulbs_count=SECTION_5_BULB_COUNT_LEL,
|
low_energy_fixed_lighting_bulbs_count=SECTION_5_BULB_COUNT_LEL,
|
||||||
sap_windows=list(SECTION_6_VERTICAL_WINDOWS),
|
# Deep-copy so each build_epc() owns its windows (the module-level
|
||||||
|
# SECTION_6_VERTICAL_WINDOWS tuple holds shared SapWindow objects; a
|
||||||
|
# caller mutating a returned window would otherwise leak across calls).
|
||||||
|
sap_windows=[copy.deepcopy(window) for window in SECTION_6_VERTICAL_WINDOWS],
|
||||||
blocked_chimneys_count=0,
|
blocked_chimneys_count=0,
|
||||||
dwelling_type="Mid-Terrace house",
|
dwelling_type="Mid-Terrace house",
|
||||||
built_form="Mid-Terrace",
|
built_form="Mid-Terrace",
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import copy
|
|
||||||
import dataclasses
|
import dataclasses
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
@ -117,11 +116,8 @@ def test_run_modelling_listed_building_yields_no_wall_insulation() -> None:
|
||||||
|
|
||||||
def _single_glazed_epc() -> EpcPropertyData:
|
def _single_glazed_epc() -> EpcPropertyData:
|
||||||
"""The cavity/floor dwelling with all windows single-glazed — the glazing
|
"""The cavity/floor dwelling with all windows single-glazed — the glazing
|
||||||
generator's trigger, sized so the upgrade reaches the optimised package.
|
generator's trigger, sized so the upgrade reaches the optimised package."""
|
||||||
|
epc: EpcPropertyData = _build_uninsulated_cavity_and_floor_epc()
|
||||||
`build_epc()` shares its window objects across calls, so deep-copy before
|
|
||||||
mutating to avoid leaking single-glazing into other tests' baselines."""
|
|
||||||
epc: EpcPropertyData = copy.deepcopy(_build_uninsulated_cavity_and_floor_epc())
|
|
||||||
for window in epc.sap_windows:
|
for window in epc.sap_windows:
|
||||||
window.glazing_type = 1 # SAP10.2 Table U2 code 1 = single.
|
window.glazing_type = 1 # SAP10.2 Table U2 code 1 = single.
|
||||||
return epc
|
return epc
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue