refactor(fase2a): konsolider fire skriptede klienter til én kanonisk (S2.5)
This commit is contained in:
parent
7978bd5f49
commit
620d5cfb83
3 changed files with 136 additions and 108 deletions
60
tests/test_scripted_client_consolidation.py
Normal file
60
tests/test_scripted_client_consolidation.py
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
"""S2.5 (Step 9) consolidation guard (T-2.5e): the four scripted ``_inner_get_response`` bodies
|
||||
collapsed to ONE canonical client (``simulation.ScriptedChatClient``); conftest's three test doubles
|
||||
now SUBCLASS it. These grep-guards lock that in — they go RED if a divergent ``_inner_get_response``
|
||||
is re-added, if a ``src``→``tests`` import creeps in, or if a double stops subclassing the canonical.
|
||||
|
||||
The guard is a regression lock over an already-verified consolidation: before the collapse there were
|
||||
five ``def _inner_get_response`` sites (four scripted + test_step5's own-lineage double); after, two.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
_ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def _py_files(base: str) -> list[Path]:
|
||||
return sorted((_ROOT / base).rglob("*.py"))
|
||||
|
||||
|
||||
def test_inner_get_response_collapsed_to_two_sites() -> None:
|
||||
"""The four scripted clients collapse to ONE canonical ``_inner_get_response`` (simulation.py);
|
||||
test_step5's own-lineage double is the only other def. So exactly 2 def-sites remain — NOT 5."""
|
||||
sites = [
|
||||
p.relative_to(_ROOT).as_posix()
|
||||
for base in ("src", "tests")
|
||||
for p in _py_files(base)
|
||||
if p.name != Path(__file__).name # this guard file references the pattern in prose
|
||||
and "def _inner_get_response" in p.read_text(encoding="utf-8")
|
||||
]
|
||||
assert sorted(sites) == [
|
||||
"src/portfolio_optimiser/simulation.py",
|
||||
"tests/test_step5_refine_loadbearing.py",
|
||||
], f"expected the four scripted bodies collapsed to one canonical + test_step5's, got: {sites}"
|
||||
|
||||
|
||||
def test_no_src_imports_tests() -> None:
|
||||
"""No ``src`` module imports from ``tests`` — the canonical lives in ``src/simulation.py`` so
|
||||
``conftest`` imports ``src``, never the reverse (the forbidden src→tests direction)."""
|
||||
offenders = [
|
||||
p.relative_to(_ROOT).as_posix()
|
||||
for p in _py_files("src")
|
||||
if ("from tests" in (text := p.read_text(encoding="utf-8")) or "import tests" in text)
|
||||
]
|
||||
assert offenders == [], f"src must not import tests: {offenders}"
|
||||
|
||||
|
||||
def test_conftest_doubles_subclass_canonical() -> None:
|
||||
"""conftest's three test doubles genuinely SUBCLASS the canonical ``ScriptedChatClient``
|
||||
(delegating the shared body) — so the consolidation is real, not cosmetic."""
|
||||
from conftest import (
|
||||
ScriptedChatClient,
|
||||
SyntheticUsageChatClient,
|
||||
_ProjectAwareUsageChatClient,
|
||||
_RecordingChatClient,
|
||||
)
|
||||
|
||||
assert issubclass(SyntheticUsageChatClient, ScriptedChatClient)
|
||||
assert issubclass(_ProjectAwareUsageChatClient, ScriptedChatClient)
|
||||
assert issubclass(_RecordingChatClient, ScriptedChatClient)
|
||||
Loading…
Add table
Add a link
Reference in a new issue