test(acms): add direct _read_file and add_command traversal coverage
Adds a focused feature file that directly exercises the diff-coverage gaps reported by the coverage gate across 13 prior attempts: acms/index.py lines 597-612 (_read_file: stat + size-check + read_text) context.py lines 111-112 (add_command: traverser invocation) Three scenarios, each targeting specific line ranges: 1. _read_file with default traverser covers lines 597-598, 611-612 2. _read_file with max_file_size=1 covers lines 602-607 3. add_command with real ChunkedFileTraverser covers lines 111-112 (also transitively covers 597-612 via _read_file) ISSUES CLOSED: #9982
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
Feature: ChunkedFileTraverser _read_file and add_command traversal coverage
|
||||
Direct coverage for diff lines that the parallel test runner may not
|
||||
reach via the acms_context_add.feature scenarios:
|
||||
acms/index.py lines 597-612 (_read_file stat + size-check + read_text)
|
||||
context.py lines 111-112 (add_command traverser invocation)
|
||||
|
||||
Background:
|
||||
Given a temp file exists for read file coverage
|
||||
|
||||
Scenario: _read_file returns AcmsIndexEntry for a normal readable file
|
||||
When I directly call _read_file with default traverser
|
||||
Then the direct read file result should be an AcmsIndexEntry
|
||||
|
||||
Scenario: _read_file returns None when file exceeds max_file_size
|
||||
When I directly call _read_file with max_file_size 1
|
||||
Then the direct read file result should be None
|
||||
|
||||
Scenario: add_command invokes the real traverser for an existing path
|
||||
When I call add_command with the real traverser and a mocked container
|
||||
Then the mocked add_to_context should have been called
|
||||
@@ -0,0 +1,84 @@
|
||||
"""Step definitions for direct _read_file and add_command traversal coverage.
|
||||
|
||||
Targets diff-coverage gaps:
|
||||
acms/index.py lines 597-612 (_read_file stat/size-check/read_text paths)
|
||||
context.py lines 111-112 (add_command traverser invocation)
|
||||
|
||||
Step names are prefixed with ``rf_`` / ``ac_`` context attributes and use
|
||||
unique step text to avoid AmbiguousStep conflicts with existing steps.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from behave import given, then, when
|
||||
from behave.runner import Context
|
||||
|
||||
from cleveragents.acms.index import AcmsIndexEntry, ChunkedFileTraverser
|
||||
|
||||
|
||||
@given("a temp file exists for read file coverage")
|
||||
def step_rf_temp_file(context: Context) -> None:
|
||||
"""Create a small temp file used by all scenarios in this feature."""
|
||||
context.rf_tmpdir = tempfile.mkdtemp()
|
||||
path = Path(context.rf_tmpdir) / "sample.py"
|
||||
path.write_text("# sample content\n", encoding="utf-8")
|
||||
context.rf_path = path
|
||||
|
||||
|
||||
@when("I directly call _read_file with default traverser")
|
||||
def step_rf_direct_default(context: Context) -> None:
|
||||
"""Call _read_file directly — exercises lines 597-598 and 611-612."""
|
||||
traverser = ChunkedFileTraverser()
|
||||
context.rf_result = traverser._read_file(context.rf_path)
|
||||
|
||||
|
||||
@when("I directly call _read_file with max_file_size 1")
|
||||
def step_rf_direct_max_size(context: Context) -> None:
|
||||
"""Call _read_file with max_file_size=1 — exercises lines 602-607."""
|
||||
traverser = ChunkedFileTraverser(max_file_size=1)
|
||||
context.rf_result = traverser._read_file(context.rf_path)
|
||||
|
||||
|
||||
@then("the direct read file result should be an AcmsIndexEntry")
|
||||
def step_rf_result_is_entry(context: Context) -> None:
|
||||
assert isinstance(context.rf_result, AcmsIndexEntry), (
|
||||
f"Expected AcmsIndexEntry, got {type(context.rf_result)!r}"
|
||||
)
|
||||
|
||||
|
||||
@then("the direct read file result should be None")
|
||||
def step_rf_result_is_none(context: Context) -> None:
|
||||
assert context.rf_result is None, (
|
||||
f"Expected None from _read_file, got {context.rf_result!r}"
|
||||
)
|
||||
|
||||
|
||||
@when("I call add_command with the real traverser and a mocked container")
|
||||
def step_ac_call_add_command_real_traverser(context: Context) -> None:
|
||||
"""Call add_command with the REAL ChunkedFileTraverser — exercises lines 111-112."""
|
||||
from cleveragents.cli.commands.context import add_command
|
||||
|
||||
container = MagicMock()
|
||||
context_service = MagicMock()
|
||||
context_service.add_to_context.return_value = ([context.rf_path], [])
|
||||
container.context_service.return_value = context_service
|
||||
project_service = MagicMock()
|
||||
project_service.get_current_project.return_value = MagicMock()
|
||||
container.project_service.return_value = project_service
|
||||
|
||||
with patch(
|
||||
"cleveragents.application.container.get_container",
|
||||
return_value=container,
|
||||
):
|
||||
add_command([str(context.rf_path)])
|
||||
|
||||
context.ac_context_service = context_service
|
||||
|
||||
|
||||
@then("the mocked add_to_context should have been called")
|
||||
def step_ac_add_to_context_called(context: Context) -> None:
|
||||
context.ac_context_service.add_to_context.assert_called_once()
|
||||
Reference in New Issue
Block a user