Files
temp/features/steps/context_service_uncovered_lines_steps.py
T

166 lines
5.5 KiB
Python

"""Behave steps to cover uncovered branches in context_service."""
import os
import tempfile
from pathlib import Path
from behave import given, then, when
from cleveragents.application.services.context_service import ContextService
from cleveragents.application.services.plan_service import PlanService
from cleveragents.application.services.project_service import ProjectService
from cleveragents.config.settings import Settings
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
from features.mocks.mock_ai_provider import MockAIProvider
@given("a context service coverage workspace")
def step_context_service_workspace(context):
temp_dir = Path(tempfile.mkdtemp())
context.temp_dir = temp_dir
os.chdir(temp_dir)
(temp_dir / ".cleveragents").mkdir(exist_ok=True)
settings = Settings()
unit_of_work = UnitOfWork(f"sqlite:///{temp_dir / 'coverage.db'}")
unit_of_work.init_database()
project_service = ProjectService(settings, unit_of_work)
project = project_service.initialize_project(
name="coverage-project", path=temp_dir, force=True
)
plan_service = PlanService(settings, unit_of_work, ai_provider=MockAIProvider())
plan_service.create_plan(project=project, prompt="coverage plan")
context.settings = settings
context.unit_of_work = unit_of_work
context.project = project
context.context_service = ContextService(settings, unit_of_work)
@when("I try to add a default ignored file")
def step_add_default_ignored_file(context):
ignored_dir = context.temp_dir / "__pycache__"
ignored_dir.mkdir(exist_ok=True)
ignored_file = ignored_dir / "ignored.pyc"
ignored_file.write_text("ignored cache")
context.added_files, context.already_in_context = (
context.context_service.add_to_context(
project=context.project, path=ignored_file
)
)
@then("the file is skipped without context entries")
def step_verify_default_ignored_skip(context):
assert context.added_files == []
assert context.already_in_context == []
assert context.context_service.list_context(context.project) == []
@given("a .agentsignore file with directory and anchored rules")
def step_create_agentsignore(context):
ignore_file = context.temp_dir / ".agentsignore"
ignore_file.write_text("# comment line\nignored_dir/\n/anchored.txt\n")
@when("I check ignore status for matching files")
def step_check_agentsignore_matches(context):
dir_path = context.temp_dir / "ignored_dir"
dir_path.mkdir(exist_ok=True)
dir_file = dir_path / "nested.txt"
dir_file.write_text("nested")
anchored_file = context.temp_dir / "anchored.txt"
anchored_file.write_text("anchored")
context.dir_ignored = context.context_service._should_ignore(
context.project, dir_file
)
context.anchored_ignored = context.context_service._should_ignore(
context.project, anchored_file
)
@then("the directory rule and anchored rule are both applied")
def step_verify_agentsignore_rules(context):
assert context.dir_ignored is True
assert context.anchored_ignored is True
@given("project include paths are set to allow only matching files")
def step_set_include_paths(context):
context.project.settings.include_paths = ["allowed/**"]
@given("project exclude paths block temporary files")
def step_set_exclude_paths(context):
context.project.settings.exclude_paths = ["*.tmp"]
@when("I check ignore status for included and excluded files")
def step_check_include_exclude(context):
allowed_dir = context.temp_dir / "allowed"
allowed_dir.mkdir(exist_ok=True)
included_file = allowed_dir / "keep.py"
included_file.write_text("keep")
excluded_file = context.temp_dir / "notes.tmp"
excluded_file.write_text("skip")
outside_include = context.temp_dir / "other" / "skip.py"
outside_include.parent.mkdir(parents=True, exist_ok=True)
outside_include.write_text("skip")
context.included_ignored = context.context_service._should_ignore(
context.project, included_file
)
context.excluded_ignored = context.context_service._should_ignore(
context.project, excluded_file
)
context.outside_include_ignored = context.context_service._should_ignore(
context.project, outside_include
)
@then("excluded files are ignored and included files allowed")
def step_verify_include_exclude(context):
assert context.excluded_ignored is True
assert context.included_ignored is False
@then("files outside the include globs are ignored")
def step_verify_include_guardrail(context):
assert context.outside_include_ignored is True
@then("paths outside the project are treated as non matches")
def step_verify_project_path_mismatch(context):
external_path = context.temp_dir.parent / "external.txt"
external_path.write_text("outside")
assert (
context.context_service._project_path_matches(
context.project, external_path, "*.txt"
)
is False
)
@when("I run ignore matching against an unrelated base directory")
def step_non_relative_match(context):
unrelated_base = context.temp_dir / "unrelated"
unrelated_base.mkdir(exist_ok=True)
target_file = context.temp_dir / "nested" / "file.txt"
target_file.parent.mkdir(parents=True, exist_ok=True)
target_file.write_text("data")
context.non_relative_match = context.context_service._matches_ignore(
unrelated_base, "*.txt", target_file
)
@then("non-relative paths are treated as not ignored")
def step_verify_non_relative(context):
assert context.non_relative_match is False