Files
factory/lib/interns-mcp/tests/test_grep_audit.py
vitya ca669d96e1 feat(lib): bundle MCP servers from .common/lib into factory/lib/
Copies source (no node_modules, dist, .tasks, .wiki, __pycache__) for:
- projects-meta-mcp v2.25.0 (TypeScript/Node)
- wiki-graph v0.3.1 (TypeScript/Node)
- interns-mcp v0.3.3 (Python/FastMCP)

.gitignore: exclude lib build artefacts (node_modules, dist, .venv, __pycache__, *.pyc)
bootstrap.ps1: add MCP build step — npm install+build for TS servers, venv+pip for Python

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 13:17:29 +03:00

238 lines
6.8 KiB
Python

"""Tests for grep_audit intern — deterministic, LLM-free."""
import json
from interns_mcp.interns.base import Intern, InternResponse
from interns_mcp.interns.grep_audit import GrepAudit
def test_substring_case_sensitive(tmp_path):
f = tmp_path / "claude.md"
f.write_text("follow project discipline\nuse superpowers\n", encoding="utf-8")
intern = GrepAudit()
result = intern.run(
paths=[str(f)],
patterns=["follow project discipline", "Follow Project Discipline"],
output="json",
)
assert isinstance(result, InternResponse)
data = json.loads(result.text)
matches = data["rows"][0]["matches"]
assert matches["follow project discipline"] is True
assert matches["Follow Project Discipline"] is False
def test_substring_case_insensitive(tmp_path):
f = tmp_path / "claude.md"
f.write_text("follow project discipline\n", encoding="utf-8")
intern = GrepAudit()
result = intern.run(
paths=[str(f)],
patterns=["FOLLOW PROJECT DISCIPLINE"],
output="json",
case_sensitive=False,
)
data = json.loads(result.text)
assert data["rows"][0]["matches"]["FOLLOW PROJECT DISCIPLINE"] is True
def test_regex_named(tmp_path):
f = tmp_path / "pyproject.toml"
f.write_text('version = "0.3.0"\n', encoding="utf-8")
intern = GrepAudit()
result = intern.run(
paths=[str(f)],
patterns=[{"pattern": r'version\s*=\s*"\d+\.\d+\.\d+"', "name": "version-line", "regex": True}],
output="json",
)
data = json.loads(result.text)
assert data["rows"][0]["matches"]["version-line"] is True
def test_dict_substring(tmp_path):
f = tmp_path / "skill.md"
f.write_text("trigger string here\n", encoding="utf-8")
intern = GrepAudit()
result = intern.run(
paths=[str(f)],
patterns=[{"pattern": "trigger string", "name": "trigger"}],
output="json",
)
data = json.loads(result.text)
assert data["rows"][0]["matches"]["trigger"] is True
def test_output_table(tmp_path):
f1 = tmp_path / "a.md"
f1.write_text("alpha beta\n", encoding="utf-8")
f2 = tmp_path / "b.md"
f2.write_text("gamma\n", encoding="utf-8")
intern = GrepAudit()
result = intern.run(
paths=[str(f1), str(f2)],
patterns=["alpha", "gamma"],
output="table",
)
text = result.text
assert text.splitlines()[0].startswith("| Path |")
assert "alpha" in text.splitlines()[0]
assert "gamma" in text.splitlines()[0]
# f1 has alpha but not gamma
f1_line = [l for l in text.splitlines() if str(f1) in l][0]
assert "" in f1_line
assert "" in f1_line
# f2 has gamma but not alpha
f2_line = [l for l in text.splitlines() if str(f2) in l][0]
assert "" in f2_line
assert "" in f2_line
def test_output_json(tmp_path):
f = tmp_path / "a.md"
f.write_text("alpha\n", encoding="utf-8")
intern = GrepAudit()
result = intern.run(
paths=[str(f)],
patterns=["alpha", "missing"],
output="json",
)
data = json.loads(result.text)
assert "rows" in data
assert len(data["rows"]) == 1
assert data["rows"][0]["path"] == str(f)
assert data["rows"][0]["matches"]["alpha"] is True
assert data["rows"][0]["matches"]["missing"] is False
def test_file_not_found_partial_result(tmp_path):
f_real = tmp_path / "exists.md"
f_real.write_text("hello\n", encoding="utf-8")
f_ghost = tmp_path / "ghost.md" # never created
intern = GrepAudit()
result = intern.run(
paths=[str(f_real), str(f_ghost)],
patterns=["hello"],
output="json",
)
data = json.loads(result.text)
assert len(data["rows"]) == 2 # partial result, no abort
rows_by_path = {r["path"]: r for r in data["rows"]}
assert rows_by_path[str(f_real)]["matches"]["hello"] is True
# Ghost row: match is None (unreadable cell), error field present
assert rows_by_path[str(f_ghost)]["matches"]["hello"] is None
assert "error" in rows_by_path[str(f_ghost)]
def test_file_not_found_table_renders_warning(tmp_path):
f_ghost = tmp_path / "ghost.md" # never created
intern = GrepAudit()
result = intern.run(
paths=[str(f_ghost)],
patterns=["x"],
output="table",
)
assert "⚠️" in result.text
def test_empty_paths():
intern = GrepAudit()
result = intern.run(paths=[], patterns=["x"], output="json")
data = json.loads(result.text)
assert data["rows"] == []
assert result.usage["files_scanned"] == 0
assert result.usage["matches_total"] == 0
def test_empty_patterns(tmp_path):
f = tmp_path / "a.md"
f.write_text("alpha\n", encoding="utf-8")
intern = GrepAudit()
result = intern.run(paths=[str(f)], patterns=[], output="json")
data = json.loads(result.text)
assert len(data["rows"]) == 1
assert data["rows"][0]["matches"] == {}
assert result.usage["patterns_evaluated"] == 0
def test_unicode_content_utf8(tmp_path):
f = tmp_path / "ru.md"
f.write_text("русский текст\n", encoding="utf-8")
intern = GrepAudit()
result = intern.run(
paths=[str(f)],
patterns=["русский"],
output="json",
)
data = json.loads(result.text)
assert data["rows"][0]["matches"]["русский"] is True
def test_unicode_content_binary_garbage_does_not_crash(tmp_path):
f = tmp_path / "binary.bin"
f.write_bytes(b"\xff\xfe\x00\x01\x02 hello \xff")
intern = GrepAudit()
# errors="replace" should let us still grep for "hello"
result = intern.run(
paths=[str(f)],
patterns=["hello"],
output="json",
)
data = json.loads(result.text)
assert data["rows"][0]["matches"]["hello"] is True
def test_usage_counts(tmp_path):
f1 = tmp_path / "a.md"
f1.write_text("alpha\n", encoding="utf-8")
f2 = tmp_path / "b.md"
f2.write_text("alpha beta\n", encoding="utf-8")
intern = GrepAudit()
result = intern.run(
paths=[str(f1), str(f2)],
patterns=["alpha", "beta"],
output="json",
)
assert result.usage["files_scanned"] == 2
assert result.usage["patterns_evaluated"] == 2
# f1: alpha ✓, beta ✗ → 1
# f2: alpha ✓, beta ✓ → 2
assert result.usage["matches_total"] == 3
def test_endpoint_null_no_client_no_crash():
"""LLM-free intern must not require client wiring."""
intern = GrepAudit(config={"endpoint": None})
assert intern.client is None
assert intern.endpoint is None
def test_base_intern_accepts_endpoint_null_config():
"""Base class survives config with explicit endpoint=null (no LLM init triggered)."""
intern = Intern(config={"endpoint": None, "model": None})
assert intern.endpoint is None
assert intern.model is None
assert intern.client is None