200 lines
6.9 KiB
Python
200 lines
6.9 KiB
Python
import pytest
|
|
from git import Repo
|
|
from git.exc import InvalidGitRepositoryError
|
|
|
|
from ra_aid.tools import fuzzy_find_project_files
|
|
|
|
|
|
@pytest.fixture
|
|
def git_repo(tmp_path):
|
|
"""Create a temporary git repository with some test files"""
|
|
repo = Repo.init(tmp_path)
|
|
|
|
# Create some files
|
|
(tmp_path / "main.py").write_text("print('hello')")
|
|
(tmp_path / "test_main.py").write_text("def test_main(): pass")
|
|
(tmp_path / "lib").mkdir()
|
|
(tmp_path / "lib/utils.py").write_text("def util(): pass")
|
|
(tmp_path / "lib/__pycache__").mkdir()
|
|
(tmp_path / "lib/__pycache__/utils.cpython-39.pyc").write_text("cache")
|
|
|
|
# Create some untracked files
|
|
(tmp_path / "untracked.txt").write_text("untracked content")
|
|
(tmp_path / "draft.py").write_text("# draft code")
|
|
|
|
# Add and commit only some files
|
|
repo.index.add(["main.py", "lib/utils.py"])
|
|
repo.index.commit("Initial commit")
|
|
|
|
return tmp_path
|
|
|
|
|
|
@pytest.fixture
|
|
def non_git_repo(tmp_path):
|
|
"""Create a temporary directory with some test files but not a git repository"""
|
|
# Create some files
|
|
(tmp_path / "main.py").write_text("print('hello')")
|
|
(tmp_path / "test_main.py").write_text("def test_main(): pass")
|
|
(tmp_path / "lib").mkdir()
|
|
(tmp_path / "lib/utils.py").write_text("def util(): pass")
|
|
(tmp_path / "lib/__pycache__").mkdir()
|
|
(tmp_path / "lib/__pycache__/utils.cpython-39.pyc").write_text("cache")
|
|
|
|
# Create some additional files
|
|
(tmp_path / "data.txt").write_text("some data")
|
|
(tmp_path / "config.py").write_text("CONFIG = {'key': 'value'}")
|
|
|
|
# Create hidden files/directories that should be excluded by default
|
|
(tmp_path / ".venv").mkdir()
|
|
(tmp_path / ".venv/lib").mkdir()
|
|
(tmp_path / ".venv/lib/python3.9").mkdir()
|
|
(tmp_path / ".hidden_file.txt").write_text("hidden content")
|
|
|
|
return tmp_path
|
|
|
|
|
|
def test_basic_fuzzy_search(git_repo):
|
|
"""Test basic fuzzy matching functionality"""
|
|
results = fuzzy_find_project_files.invoke(
|
|
{"search_term": "utils", "repo_path": str(git_repo)}
|
|
)
|
|
|
|
assert len(results) >= 1
|
|
assert any("lib/utils.py" in match[0] for match in results)
|
|
assert all(isinstance(match[1], int) for match in results)
|
|
|
|
|
|
def test_threshold_filtering(git_repo):
|
|
"""Test threshold parameter behavior"""
|
|
# Should match with high threshold
|
|
results_high = fuzzy_find_project_files.invoke(
|
|
{"search_term": "main", "threshold": 80, "repo_path": str(git_repo)}
|
|
)
|
|
assert len(results_high) >= 1
|
|
assert any("main.py" in match[0] for match in results_high)
|
|
|
|
# Should not match with very high threshold
|
|
results_very_high = fuzzy_find_project_files.invoke(
|
|
{"search_term": "mian", "threshold": 99, "repo_path": str(git_repo)}
|
|
)
|
|
assert len(results_very_high) == 0
|
|
|
|
|
|
def test_max_results_limit(git_repo):
|
|
"""Test max_results parameter"""
|
|
max_results = 1
|
|
results = fuzzy_find_project_files.invoke(
|
|
{"search_term": "py", "max_results": max_results, "repo_path": str(git_repo)}
|
|
)
|
|
assert len(results) <= max_results
|
|
|
|
|
|
def test_include_paths_filter(git_repo):
|
|
"""Test include_paths filtering"""
|
|
results = fuzzy_find_project_files.invoke(
|
|
{"search_term": "py", "include_paths": ["lib/*"], "repo_path": str(git_repo)}
|
|
)
|
|
assert all("lib/" in match[0] for match in results)
|
|
|
|
|
|
def test_exclude_patterns_filter(git_repo):
|
|
"""Test exclude_patterns filtering"""
|
|
results = fuzzy_find_project_files.invoke(
|
|
{
|
|
"search_term": "py",
|
|
"exclude_patterns": ["*test*"],
|
|
"repo_path": str(git_repo),
|
|
}
|
|
)
|
|
assert not any("test" in match[0] for match in results)
|
|
|
|
|
|
def test_invalid_threshold():
|
|
"""Test error handling for invalid threshold"""
|
|
with pytest.raises(ValueError):
|
|
fuzzy_find_project_files.invoke({"search_term": "test", "threshold": 101})
|
|
|
|
|
|
def test_non_git_repo(non_git_repo):
|
|
"""Test fuzzy find works in non-git directories"""
|
|
# Now the function should work with non-git repositories
|
|
results = fuzzy_find_project_files.invoke(
|
|
{"search_term": "main", "repo_path": str(non_git_repo)}
|
|
)
|
|
assert len(results) >= 1
|
|
assert any("main.py" in match[0] for match in results)
|
|
|
|
|
|
def test_hidden_files_inclusion(non_git_repo):
|
|
"""Test include_hidden parameter works correctly"""
|
|
# Without include_hidden parameter (default False)
|
|
results_without_hidden = fuzzy_find_project_files.invoke(
|
|
{"search_term": "hidden", "repo_path": str(non_git_repo)}
|
|
)
|
|
assert len(results_without_hidden) == 0
|
|
|
|
# With include_hidden=True
|
|
results_with_hidden = fuzzy_find_project_files.invoke(
|
|
{"search_term": "hidden", "repo_path": str(non_git_repo), "include_hidden": True}
|
|
)
|
|
assert len(results_with_hidden) >= 1
|
|
assert any(".hidden_file.txt" in match[0] for match in results_with_hidden)
|
|
|
|
|
|
def test_exact_match(git_repo):
|
|
"""Test exact matching returns 100% score"""
|
|
results = fuzzy_find_project_files.invoke(
|
|
{"search_term": "main.py", "repo_path": str(git_repo)}
|
|
)
|
|
assert len(results) >= 1
|
|
assert any(match[1] == 100 for match in results)
|
|
|
|
|
|
def test_empty_search_term(git_repo):
|
|
"""Test behavior with empty search term"""
|
|
results = fuzzy_find_project_files.invoke(
|
|
{"search_term": "", "repo_path": str(git_repo)}
|
|
)
|
|
assert len(results) == 0
|
|
|
|
|
|
def test_untracked_files(git_repo):
|
|
"""Test that untracked files are included in search results"""
|
|
results = fuzzy_find_project_files.invoke(
|
|
{"search_term": "untracked", "repo_path": str(git_repo)}
|
|
)
|
|
assert len(results) >= 1
|
|
assert any("untracked.txt" in match[0] for match in results)
|
|
|
|
|
|
def test_no_matches(git_repo):
|
|
"""Test behavior when no files match the search term"""
|
|
results = fuzzy_find_project_files.invoke(
|
|
{"search_term": "nonexistentfile", "threshold": 80, "repo_path": str(git_repo)}
|
|
)
|
|
assert len(results) == 0
|
|
|
|
|
|
def test_excluding_system_dirs(non_git_repo):
|
|
"""Test that system directories are excluded by default"""
|
|
# Create files in directories that should be excluded by default
|
|
(non_git_repo / "__pycache__").mkdir(exist_ok=True)
|
|
(non_git_repo / "__pycache__/module.cpython-39.pyc").write_text("cache data")
|
|
(non_git_repo / ".ra-aid").mkdir(exist_ok=True)
|
|
(non_git_repo / ".ra-aid/config.json").write_text('{"setting": "value"}')
|
|
|
|
# Run search for files that should be excluded
|
|
results = fuzzy_find_project_files.invoke(
|
|
{"search_term": "config", "repo_path": str(non_git_repo)}
|
|
)
|
|
|
|
# Should find config.py but not .ra-aid/config.json
|
|
assert any("config.py" in match[0] for match in results)
|
|
assert not any(".ra-aid/config.json" in match[0] for match in results)
|
|
|
|
# Similarly for __pycache__
|
|
results_cache = fuzzy_find_project_files.invoke(
|
|
{"search_term": "module", "repo_path": str(non_git_repo)}
|
|
)
|
|
assert len(results_cache) == 0 # Should not find __pycache__ files
|