generated from coulomb/repo-seed
Milestone 2’s core deterministic scanner path
This commit is contained in:
@@ -96,3 +96,51 @@ def test_capability_must_belong_to_repository(tmp_path):
|
||||
assert "ability" in str(exc)
|
||||
else:
|
||||
raise AssertionError("expected a NotFoundError")
|
||||
|
||||
|
||||
def test_analyze_repository_records_snapshot_and_observed_facts(tmp_path):
|
||||
source = tmp_path / "repo"
|
||||
source.mkdir()
|
||||
(source / "README.md").write_text("# Example\n", encoding="utf-8")
|
||||
(source / "requirements.txt").write_text("fastapi\n", encoding="utf-8")
|
||||
(source / "app.py").write_text(
|
||||
"from fastapi import FastAPI\n"
|
||||
"app = FastAPI()\n"
|
||||
'@app.get("/health")\n'
|
||||
"def health():\n"
|
||||
" return {}\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
service = make_service(tmp_path)
|
||||
repository = service.register_repository(
|
||||
name="Example",
|
||||
url=str(source),
|
||||
description="A local fixture repository",
|
||||
)
|
||||
|
||||
summary = service.analyze_repository(repository.id)
|
||||
|
||||
assert summary.analysis_run.status == "completed"
|
||||
assert summary.snapshot is not None
|
||||
assert summary.snapshot.file_count == 3
|
||||
assert service.get_repository(repository.id).status == "analyzed"
|
||||
fact_names = {(fact.kind, fact.name, fact.path) for fact in summary.facts}
|
||||
assert ("documentation", "README", "README.md") in fact_names
|
||||
assert ("framework", "FastAPI", "requirements.txt") in fact_names
|
||||
assert ("interface", "python route decorator", "app.py") in fact_names
|
||||
|
||||
|
||||
def test_analyze_repository_failure_is_recorded(tmp_path):
|
||||
service = make_service(tmp_path)
|
||||
repository = service.register_repository(
|
||||
name="Missing",
|
||||
url=str(tmp_path / "does-not-exist"),
|
||||
)
|
||||
|
||||
summary = service.analyze_repository(repository.id)
|
||||
|
||||
assert summary.analysis_run.status == "failed"
|
||||
assert summary.snapshot is None
|
||||
assert "does not exist" in (summary.analysis_run.error_message or "")
|
||||
assert service.get_repository(repository.id).status == "analysis_failed"
|
||||
|
||||
36
tests/test_repository_scanner.py
Normal file
36
tests/test_repository_scanner.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from repo_registry.repo_scanning.scanner import DeterministicScanner
|
||||
|
||||
|
||||
def test_deterministic_scanner_extracts_structural_facts(tmp_path):
|
||||
repo = tmp_path / "sample"
|
||||
repo.mkdir()
|
||||
(repo / "README.md").write_text("# MailRouter\n", encoding="utf-8")
|
||||
(repo / "pyproject.toml").write_text(
|
||||
'[project]\ndependencies = ["fastapi", "pytest"]\n',
|
||||
encoding="utf-8",
|
||||
)
|
||||
(repo / "src").mkdir()
|
||||
(repo / "src" / "routes.py").write_text(
|
||||
"from fastapi import APIRouter\n"
|
||||
"router = APIRouter()\n"
|
||||
'@router.post("/classify-email")\n'
|
||||
"def classify_email():\n"
|
||||
" return {}\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(repo / "tests").mkdir()
|
||||
(repo / "tests" / "test_routes.py").write_text("def test_ok(): pass\n", encoding="utf-8")
|
||||
|
||||
result = DeterministicScanner().scan(repo)
|
||||
|
||||
facts = {(fact.kind, fact.name, fact.path) for fact in result.facts}
|
||||
assert result.file_count == 4
|
||||
assert ("documentation", "README", "README.md") in facts
|
||||
assert ("manifest", "pyproject.toml", "pyproject.toml") in facts
|
||||
assert ("test", "test_routes.py", "tests/test_routes.py") in facts
|
||||
assert ("framework", "FastAPI", "pyproject.toml") in facts
|
||||
assert ("framework", "pytest", "pyproject.toml") in facts
|
||||
assert ("interface", "python route decorator", "src/routes.py") in facts
|
||||
|
||||
languages = {fact.name: fact.metadata["file_count"] for fact in result.facts if fact.kind == "language"}
|
||||
assert languages == {"Python": 2}
|
||||
@@ -67,3 +67,43 @@ def test_api_manual_registry_loop(tmp_path):
|
||||
assert search_response.json()
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
|
||||
def test_api_analysis_run_loop(tmp_path):
|
||||
source = tmp_path / "repo"
|
||||
source.mkdir()
|
||||
(source / "README.md").write_text("# Searchable\n", encoding="utf-8")
|
||||
(source / "package.json").write_text(
|
||||
'{"dependencies":{"react":"latest","vite":"latest"}}',
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
def override_settings():
|
||||
return Settings(database_path=str(tmp_path / "api-analysis.sqlite3"))
|
||||
|
||||
app.dependency_overrides[get_settings] = override_settings
|
||||
client = TestClient(app)
|
||||
try:
|
||||
repository_response = client.post(
|
||||
"/repos",
|
||||
json={"name": "Frontend", "url": str(source)},
|
||||
)
|
||||
repository_id = repository_response.json()["id"]
|
||||
|
||||
run_response = client.post(f"/repos/{repository_id}/analysis-runs", json={})
|
||||
assert run_response.status_code == 201
|
||||
run = run_response.json()
|
||||
assert run["analysis_run"]["status"] == "completed"
|
||||
assert run["snapshot"]["file_count"] == 2
|
||||
|
||||
facts_response = client.get(f"/repos/{repository_id}/observed-facts")
|
||||
assert facts_response.status_code == 200
|
||||
fact_names = {
|
||||
(fact["kind"], fact["name"], fact["path"])
|
||||
for fact in facts_response.json()
|
||||
}
|
||||
assert ("documentation", "README", "README.md") in fact_names
|
||||
assert ("framework", "React", "package.json") in fact_names
|
||||
assert ("framework", "Vite", "package.json") in fact_names
|
||||
finally:
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
Reference in New Issue
Block a user