182 lines
7 KiB
Python
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)]
|