Files
temp/features/steps/validation_cli_uncovered_branches_steps.py
T

124 lines
4.9 KiB
Python

"""Step definitions for validation CLI uncovered branches.
Covers two gaps in ``cleveragents.cli.commands.validation``:
1. ``_get_tool_registry_service()`` (lines 75-95) — the full construction path
that imports from the container, creates an engine/session-factory, builds
repositories, and returns a ``ToolRegistryService``.
2. ``detach`` command branch L356→360 — when the user confirms the detach
prompt but ``detach_validation`` returns ``False`` (attachment not found).
"""
from __future__ import annotations
from typing import Any
from unittest.mock import MagicMock, patch
from behave import given, then, when
from behave.runner import Context
from typer.testing import CliRunner
from cleveragents.cli.commands.validation import app as validation_app
_runner = CliRunner()
# ---------------------------------------------------------------------------
# Patch targets
# ---------------------------------------------------------------------------
# We patch get_container *inside* the validation module's lazy import so the
# real function body executes but uses our mock container.
_PATCH_GET_CONTAINER = "cleveragents.application.container.get_container"
# For the detach scenario we still patch the whole helper to isolate DB access.
_PATCH_VAL_SVC = "cleveragents.cli.commands.validation._get_tool_registry_service"
# ---------------------------------------------------------------------------
# Background
# ---------------------------------------------------------------------------
@given("a validation cli branch test runner with mocks")
def step_validation_cli_branch_background(context: Context) -> None:
context.vcb_runner = _runner
context.vcb_result = None
context.vcb_returned_service: Any = None
context.vcb_mock_service: MagicMock | None = None
# ---------------------------------------------------------------------------
# Scenario 1: _get_tool_registry_service construction path (L75-95)
# ---------------------------------------------------------------------------
@given("the validation cli branch DI container provides a database url")
def step_vcb_di_container(context: Context) -> None:
"""Set up a mock container whose ``database_url()`` returns an in-memory
SQLite URL so the real construction path executes end-to-end."""
mock_container = MagicMock()
mock_container.database_url.return_value = "sqlite:///:memory:"
context.vcb_mock_container = mock_container
@when("the validation cli branch _get_tool_registry_service is called")
def step_vcb_call_get_tool_registry_service(context: Context) -> None:
from cleveragents.cli.commands.validation import _get_tool_registry_service
with patch(_PATCH_GET_CONTAINER, return_value=context.vcb_mock_container):
context.vcb_returned_service = _get_tool_registry_service()
@then("the validation cli branch returned service should be a ToolRegistryService")
def step_vcb_verify_service_type(context: Context) -> None:
from cleveragents.application.services.tool_registry_service import (
ToolRegistryService,
)
assert context.vcb_returned_service is not None, (
"_get_tool_registry_service returned None"
)
assert isinstance(context.vcb_returned_service, ToolRegistryService), (
f"Expected ToolRegistryService, got {type(context.vcb_returned_service)}"
)
# ---------------------------------------------------------------------------
# Scenario 2: detach — user confirms but attachment not found (L356→360)
# ---------------------------------------------------------------------------
@given("the validation cli branch detach service returns false")
def step_vcb_detach_service_false(context: Context) -> None:
"""Prepare a mock service whose ``detach_validation`` returns ``False``."""
svc = MagicMock()
svc.detach_validation.return_value = False
context.vcb_mock_service = svc
@when('the validation cli branch detach is invoked with confirmation for "{att_id}"')
def step_vcb_detach_with_confirmation(context: Context, att_id: str) -> None:
"""Invoke the detach command *without* ``--yes`` and feed ``y`` to the
confirmation prompt so the code reaches ``service.detach_validation``
which returns ``False`` — covering L356→360."""
with patch(_PATCH_VAL_SVC, return_value=context.vcb_mock_service):
context.vcb_result = _runner.invoke(
validation_app,
["detach", att_id],
input="y\n",
)
@then("the validation cli branch detach result should abort with not found")
def step_vcb_detach_abort_not_found(context: Context) -> None:
result = context.vcb_result
assert result is not None, "No CLI result captured"
# The command should abort (non-zero exit)
assert result.exit_code != 0, (
f"Expected non-zero exit, got {result.exit_code}. Output: {result.output}"
)
assert "Attachment not found" in result.output, (
f"Expected 'Attachment not found' in output, got: {result.output}"
)