Files
temp/features/steps/acms_service_coverage_r3_steps.py
freemo 31472b5413 test(coverage): add Behave scenarios for 39 under-covered modules
Add Behave feature/step pairs that exercise uncovered branches across handlers, LSP, CLI, and service layers to reach the coverage gate.

ISSUES CLOSED: #1232
2026-03-31 21:47:12 +00:00

377 lines
14 KiB
Python

"""Step definitions for features/acms_service_coverage_r3.feature.
Targets uncovered lines in src/cleveragents/application/services/acms_service.py:
- Lines 34-35: TYPE_CHECKING imports (Settings, UnitOfWork) — validated via DI
- Line 112: ContextStrategy.can_handle protocol default body (Ellipsis)
- Line 120: ContextStrategy.assemble protocol default body (Ellipsis)
- Line 124: ContextStrategy.explain protocol default body (Ellipsis)
- Line 275: StrategySelector.select protocol default body (Ellipsis)
- Line 292: BudgetAllocator.allocate protocol default body (Ellipsis)
- Line 309: StrategyExecutor.execute protocol default body (Ellipsis)
- Line 396: SkeletonCompressor.compress protocol default body (Ellipsis)
- Line 577: DefaultBudgetPacker.pack returns fragments unchanged
"""
from __future__ import annotations
from unittest.mock import MagicMock
from behave import given, then, when
from behave.runner import Context
from cleveragents.application.services.acms_service import (
ACMSPipeline,
BudgetAllocator,
ContextStrategy,
DefaultBudgetPacker,
SkeletonCompressor,
StrategyCapabilities,
StrategyExecutor,
StrategySelector,
)
from cleveragents.domain.models.core.context_fragment import (
ContextBudget,
ContextFragment,
FragmentProvenance,
)
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
_DEFAULT_PROVENANCE = FragmentProvenance(resource_uri="test://coverage-r3")
def _make_frag(
uko_node: str = "test://r3",
content: str = "r3 content",
token_count: int = 10,
relevance_score: float = 0.5,
) -> ContextFragment:
return ContextFragment(
uko_node=uko_node,
content=content,
token_count=token_count,
relevance_score=relevance_score,
provenance=_DEFAULT_PROVENANCE,
)
# ---------------------------------------------------------------------------
# Bare Protocol subclasses — inherit default method bodies (the `...` stubs)
# without overriding them, so calling the methods executes the Ellipsis lines.
# ---------------------------------------------------------------------------
class _BareContextStrategy(ContextStrategy):
"""Inherits ContextStrategy Protocol defaults for can_handle/assemble/explain."""
@property
def name(self) -> str:
return "bare_test"
@property
def capabilities(self) -> StrategyCapabilities:
return StrategyCapabilities()
class _BareStrategySelector(StrategySelector):
"""Inherits StrategySelector Protocol default for select."""
class _BareBudgetAllocator(BudgetAllocator):
"""Inherits BudgetAllocator Protocol default for allocate."""
class _BareStrategyExecutor(StrategyExecutor):
"""Inherits StrategyExecutor Protocol default for execute."""
class _BareSkeletonCompressor(SkeletonCompressor):
"""Inherits SkeletonCompressor Protocol default for compress."""
# ---------------------------------------------------------------------------
# Lines 34-35: TYPE_CHECKING imports — DI validation
# ---------------------------------------------------------------------------
@given("ascov3 I have mock Settings and UnitOfWork objects")
def step_given_mock_settings_uow(context: Context) -> None:
context.ascov3_mock_settings = MagicMock(name="MockSettings")
context.ascov3_mock_uow = MagicMock(name="MockUnitOfWork")
@when("ascov3 I create a pipeline with settings and unit_of_work injected")
def step_when_create_pipeline_with_di(context: Context) -> None:
context.ascov3_error = None
try:
context.ascov3_pipeline = ACMSPipeline(
settings=context.ascov3_mock_settings,
unit_of_work=context.ascov3_mock_uow,
)
except Exception as exc:
context.ascov3_error = exc
@then("ascov3 the pipeline should store the injected dependencies")
def step_then_pipeline_stores_deps(context: Context) -> None:
assert context.ascov3_error is None, (
f"Pipeline creation failed: {context.ascov3_error}"
)
pipeline = context.ascov3_pipeline
assert pipeline._settings is context.ascov3_mock_settings, (
"Pipeline did not store the injected settings"
)
assert pipeline._unit_of_work is context.ascov3_mock_uow, (
"Pipeline did not store the injected unit_of_work"
)
# ---------------------------------------------------------------------------
# Line 112: ContextStrategy.can_handle default body
# ---------------------------------------------------------------------------
@given("ascov3 I have a bare ContextStrategy subclass")
def step_given_bare_context_strategy(context: Context) -> None:
context.ascov3_bare_strategy = _BareContextStrategy()
@when("ascov3 I call can_handle on the bare strategy with an empty request")
def step_when_call_can_handle(context: Context) -> None:
context.ascov3_error = None
try:
context.ascov3_can_handle_result = context.ascov3_bare_strategy.can_handle({})
except Exception as exc:
context.ascov3_error = exc
@then("ascov3 the can_handle result should be None")
def step_then_can_handle_none(context: Context) -> None:
assert context.ascov3_error is None, f"can_handle raised: {context.ascov3_error}"
assert context.ascov3_can_handle_result is None, (
f"Expected None, got {context.ascov3_can_handle_result!r}"
)
# ---------------------------------------------------------------------------
# Line 120: ContextStrategy.assemble default body
# ---------------------------------------------------------------------------
@when("ascov3 I call assemble on the bare strategy with empty fragments and a budget")
def step_when_call_assemble(context: Context) -> None:
context.ascov3_error = None
try:
budget = ContextBudget(max_tokens=100, reserved_tokens=0)
context.ascov3_assemble_result = context.ascov3_bare_strategy.assemble(
[], budget
)
except Exception as exc:
context.ascov3_error = exc
@then("ascov3 the assemble result should be None")
def step_then_assemble_none(context: Context) -> None:
assert context.ascov3_error is None, f"assemble raised: {context.ascov3_error}"
assert context.ascov3_assemble_result is None, (
f"Expected None, got {context.ascov3_assemble_result!r}"
)
# ---------------------------------------------------------------------------
# Line 124: ContextStrategy.explain default body
# ---------------------------------------------------------------------------
@when("ascov3 I call explain on the bare strategy")
def step_when_call_explain(context: Context) -> None:
context.ascov3_error = None
try:
context.ascov3_explain_result = context.ascov3_bare_strategy.explain()
except Exception as exc:
context.ascov3_error = exc
@then("ascov3 the explain result should be None")
def step_then_explain_none(context: Context) -> None:
assert context.ascov3_error is None, f"explain raised: {context.ascov3_error}"
assert context.ascov3_explain_result is None, (
f"Expected None, got {context.ascov3_explain_result!r}"
)
# ---------------------------------------------------------------------------
# Line 275: StrategySelector.select default body
# ---------------------------------------------------------------------------
@given("ascov3 I have a bare StrategySelector subclass")
def step_given_bare_selector(context: Context) -> None:
context.ascov3_bare_selector = _BareStrategySelector()
@when("ascov3 I call select on the bare selector with empty strategies")
def step_when_call_select(context: Context) -> None:
context.ascov3_error = None
try:
context.ascov3_select_result = context.ascov3_bare_selector.select([], {})
except Exception as exc:
context.ascov3_error = exc
@then("ascov3 the select result should be None")
def step_then_select_none(context: Context) -> None:
assert context.ascov3_error is None, f"select raised: {context.ascov3_error}"
assert context.ascov3_select_result is None, (
f"Expected None, got {context.ascov3_select_result!r}"
)
# ---------------------------------------------------------------------------
# Line 292: BudgetAllocator.allocate default body
# ---------------------------------------------------------------------------
@given("ascov3 I have a bare BudgetAllocator subclass")
def step_given_bare_allocator(context: Context) -> None:
context.ascov3_bare_allocator = _BareBudgetAllocator()
@when("ascov3 I call allocate on the bare allocator with empty candidates")
def step_when_call_allocate(context: Context) -> None:
context.ascov3_error = None
try:
context.ascov3_allocate_result = context.ascov3_bare_allocator.allocate([], 100)
except Exception as exc:
context.ascov3_error = exc
@then("ascov3 the allocate result should be None")
def step_then_allocate_none(context: Context) -> None:
assert context.ascov3_error is None, f"allocate raised: {context.ascov3_error}"
assert context.ascov3_allocate_result is None, (
f"Expected None, got {context.ascov3_allocate_result!r}"
)
# ---------------------------------------------------------------------------
# Line 309: StrategyExecutor.execute default body
# ---------------------------------------------------------------------------
@given("ascov3 I have a bare StrategyExecutor subclass")
def step_given_bare_executor(context: Context) -> None:
context.ascov3_bare_executor = _BareStrategyExecutor()
@when("ascov3 I call execute on the bare executor with empty allocations")
def step_when_call_execute(context: Context) -> None:
context.ascov3_error = None
try:
budget = ContextBudget(max_tokens=100, reserved_tokens=0)
context.ascov3_execute_result = context.ascov3_bare_executor.execute(
[], [], budget
)
except Exception as exc:
context.ascov3_error = exc
@then("ascov3 the execute result should be None")
def step_then_execute_none(context: Context) -> None:
assert context.ascov3_error is None, f"execute raised: {context.ascov3_error}"
assert context.ascov3_execute_result is None, (
f"Expected None, got {context.ascov3_execute_result!r}"
)
# ---------------------------------------------------------------------------
# Line 396: SkeletonCompressor.compress default body
# ---------------------------------------------------------------------------
@given("ascov3 I have a bare SkeletonCompressor subclass")
def step_given_bare_compressor(context: Context) -> None:
context.ascov3_bare_compressor = _BareSkeletonCompressor()
@when("ascov3 I call compress on the bare compressor with empty fragments")
def step_when_call_compress(context: Context) -> None:
context.ascov3_error = None
try:
context.ascov3_compress_result = context.ascov3_bare_compressor.compress(
(), 100
)
except Exception as exc:
context.ascov3_error = exc
@then("ascov3 the compress result should be None")
def step_then_compress_none(context: Context) -> None:
assert context.ascov3_error is None, f"compress raised: {context.ascov3_error}"
assert context.ascov3_compress_result is None, (
f"Expected None, got {context.ascov3_compress_result!r}"
)
# ---------------------------------------------------------------------------
# Line 577: DefaultBudgetPacker.pack
# ---------------------------------------------------------------------------
@given("ascov3 I have a DefaultBudgetPacker instance")
def step_given_default_packer(context: Context) -> None:
context.ascov3_packer = DefaultBudgetPacker()
@given("ascov3 I have a list of test fragments")
def step_given_test_fragments(context: Context) -> None:
context.ascov3_fragments = [
_make_frag(uko_node="test://r3-a", content="alpha", token_count=10),
_make_frag(uko_node="test://r3-b", content="beta", token_count=20),
]
@when("ascov3 I call pack on the packer with those fragments and a budget")
def step_when_call_pack_with_fragments(context: Context) -> None:
context.ascov3_error = None
try:
budget = ContextBudget(max_tokens=200, reserved_tokens=0)
context.ascov3_pack_result = context.ascov3_packer.pack(
context.ascov3_fragments, budget
)
except Exception as exc:
context.ascov3_error = exc
@when("ascov3 I call pack on the packer with empty fragments and a budget")
def step_when_call_pack_empty(context: Context) -> None:
context.ascov3_error = None
try:
budget = ContextBudget(max_tokens=200, reserved_tokens=0)
context.ascov3_pack_result = context.ascov3_packer.pack([], budget)
except Exception as exc:
context.ascov3_error = exc
@then("ascov3 the pack result should be the same fragments unchanged")
def step_then_pack_result_unchanged(context: Context) -> None:
assert context.ascov3_error is None, f"pack raised: {context.ascov3_error}"
result = list(context.ascov3_pack_result)
expected = context.ascov3_fragments
assert len(result) == len(expected), (
f"Expected {len(expected)} fragments, got {len(result)}"
)
for i, (r, e) in enumerate(zip(result, expected, strict=True)):
assert r.fragment_id == e.fragment_id, (
f"Fragment {i}: expected id {e.fragment_id}, got {r.fragment_id}"
)
@then("ascov3 the pack result should be an empty sequence")
def step_then_pack_result_empty(context: Context) -> None:
assert context.ascov3_error is None, f"pack raised: {context.ascov3_error}"
result = list(context.ascov3_pack_result)
assert result == [], f"Expected empty list, got {result}"