band-aider-pub/tests/band_aider/test_lexical_anchor_check.py
2026-10-17 11:57:37 -07:00

182 lines
7 KiB
Python

# SPDX-FileCopyrightText: 2026 Art Sea LLC
#
# SPDX-License-Identifier: AGPL-3.0-only
from __future__ import annotations
from band_aider.judgement.lexical_anchor_check import (
LEXICAL_MAX_COMPARISON_LENGTH,
LEXICAL_MAX_EDIT_DISTANCE,
LEXICAL_MAX_WINDOW_WORDS,
LEXICAL_MIN_COMPARISON_LENGTH,
LexicalAnchorCheck,
)
def _check(anchors, beats) -> LexicalAnchorCheck:
"""Return one lexical check for test inputs."""
return LexicalAnchorCheck(changes=[], anchors=anchors, candidate_beats=beats)
def test_lexical_anchor_check_constants_are_explicit() -> None:
"""Verify lexical constants match the prefilter policy."""
assert LEXICAL_MAX_EDIT_DISTANCE == 2
assert LEXICAL_MAX_COMPARISON_LENGTH == 128
assert LEXICAL_MAX_WINDOW_WORDS == 3
assert LEXICAL_MIN_COMPARISON_LENGTH == 3
def test_lexical_anchor_check_matches_filename_stem_path_and_component() -> None:
"""Verify filename, stem, full path, basename, and component forms match."""
assert _check(["cli.py"], ["band_aider/cli.py"])() is True
assert _check(["cli"], ["band_aider/cli.py"])() is True
assert _check(["band_aider/cli.py"], ["band_aider/cli.py"])() is True
assert _check(["cli.py"], ["/tmp/repo/band_aider/cli.py"])() is True
assert _check(["band_aider"], ["band_aider/cli.py"])() is True
def test_lexical_anchor_check_matches_identifier_styles() -> None:
"""Verify CamelCase, snake_case, kebab-case, flags, env vars, and dotted names match."""
assert _check(["BroadOrNarrowCheck"], ["BroadOrNarrowCheck"])() is True
assert _check(["broad_or_narrow_check"], ["BroadOrNarrowCheck"])() is True
assert _check(["broad-or-narrow-check"], ["BroadOrNarrowCheck"])() is True
assert _check(["BroadOrNarrowCheck.create"], ["BroadOrNarrowCheck.create"])() is True
assert _check(["--terminal-ui"], ["terminal-ui"])() is True
assert _check(["BAND_AIDER_DEBUG"], ["BAND_AIDER_DEBUG=true"])() is True
assert _check(["pydevd_pycharm.settrace"], ["pydevd_pycharm.settrace"])() is True
def test_lexical_anchor_check_matches_one_two_and_three_token_windows() -> None:
"""Verify contiguous one-, two-, and three-token windows are searchable."""
assert _check(["alpha"], ["alpha beta gamma delta"])() is True
assert _check(["beta gamma"], ["alpha beta gamma delta"])() is True
assert _check(["beta gamma delta"], ["alpha beta gamma delta"])() is True
assert _check(["alpha beta gamma delta"], ["prefix alpha beta gamma delta suffix"])() is False
assert _check(["alpha beta gamma delta"], ["alpha beta gamma delta"])() is True
def test_lexical_anchor_check_recombines_candidate_path_parts() -> None:
"""Verify candidate path parts use bounded sliding recombination without extension tokens."""
candidate = "band_aider/ai_client/completion_client.py"
assert _check(["ai-client"], [candidate])() is True
assert _check(["aider-ai-client"], [candidate])() is True
assert _check(["band-aider-ai-client-completion"], [candidate])() is False
assert _check(["client-py"], [candidate])() is False
def test_lexical_anchor_check_applies_length_sensitive_edit_distance() -> None:
"""Verify exact, distance-one, distance-two, and short-string matching rules."""
exact = _check(["widget"], ["widget"])
medium = _check(["widget"], ["widgit"])
long = _check(["prefiltering"], ["prefilterring"])
short = _check(["cli"], ["clx"])
assert exact() is True
assert exact.edit_distance == 0
assert medium() is True
assert medium.edit_distance == 1
assert long() is True
assert long.edit_distance == 1
assert short() is False
def test_lexical_anchor_check_length_difference_rejects_without_distance_work() -> None:
"""Verify comparisons impossible by length are skipped before Levenshtein work."""
check = _check(["abcde"], ["abcdefghij"])
assert check() is False
assert check.comparison_count == 0
def test_lexical_anchor_check_rejects_oversized_values_without_truncation() -> None:
"""Verify oversized anchors and candidates are treated as non-matches."""
oversized = "x" * (LEXICAL_MAX_COMPARISON_LENGTH + 1)
assert _check([oversized], ["x"])() is False
assert _check(["x"], [oversized])() is False
def test_lexical_anchor_check_empty_and_unrelated_inputs_return_false() -> None:
"""Verify empty and unrelated lexical inputs fail closed."""
assert _check([], ["cli.py"])() is False
assert _check(["cli.py"], [])() is False
assert _check([""], [" "])() is False
assert _check(["cli.py"], ["README.md"])() is False
def test_lexical_anchor_check_does_not_match_filename_extension_only() -> None:
"""Verify file anchors do not match unrelated files through a shared extension token."""
assert _check(["cli.py"], ["band_aider/__init__.py"])() is False
assert _check(["cli.py"], ["band_aider/ai_client/completion_client.py"])() is False
assert _check(["band_aider/cli.py"], ["band_aider/ai_client/cycle_jacker.py"])() is False
assert _check(["cli.py"], ["band_aider/cli.py"])() is True
def test_lexical_anchor_check_rejects_forms_shorter_than_three_characters() -> None:
"""Verify short anchors and short windows do not match."""
assert _check(["ui"], ["ui"])() is False
assert _check(["py"], ["py"])() is False
assert _check(["cli"], ["cli"])() is True
assert _check(["--ui"], ["--ui"])() is False
assert _check(["--dev"], ["--dev"])() is True
def test_lexical_anchor_check_does_not_break_anchors_into_windows() -> None:
"""Verify multi-token anchors do not match partial candidate windows."""
assert _check(["terminal-ui"], ["terminal"])() is False
assert _check(["terminal-ui"], ["terminal-ui"])() is True
assert _check(["terminal-ui"], ["enable terminal ui mode"])() is True
assert _check(["pydevd_pycharm.settrace"], ["pydevd_pycharm"])() is False
assert _check(["pydevd"], ["pydevd_pycharm.settrace"])() is True
def test_lexical_anchor_check_keeps_file_anchors_whole() -> None:
"""Verify filename anchors do not become filename-stem anchors."""
check = _check(
["cli.py"],
[
"/repo/band_aider/ai_client/llm_logging.py",
"Initialize repo-rooted hierarchical logging once from the CLI.",
],
)
assert check() is False
assert check.best_anchor == ""
def test_lexical_anchor_check_errors_log_and_record_false(caplog) -> None:
"""Verify malformed lexical inputs fail closed, log, and append changes."""
check = _check([object()], ["cli.py"])
assert check() is False
assert check.changes == [(check, False)]
assert check.error.startswith("TypeError:")
assert "LexicalAnchorCheck failed closed" in caplog.text
def test_lexical_anchor_check_changes_records_true_and_false() -> None:
"""Verify lexical checks append final decisions to changes."""
true_check = _check(["cli.py"], ["cli.py"])
false_check = _check(["cli.py"], ["README.md"])
assert true_check() is True
assert false_check() is False
assert true_check.changes == [(true_check, True)]
assert false_check.changes == [(false_check, False)]