test: knowledge gap identifier tests (#172)
This commit is contained in:
141
tests/test_knowledge_gap_identifier.py
Normal file
141
tests/test_knowledge_gap_identifier.py
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
"""Tests for knowledge_gap_identifier module."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'scripts'))
|
||||||
|
|
||||||
|
from knowledge_gap_identifier import KnowledgeGapIdentifier, GapType, GapSeverity
|
||||||
|
|
||||||
|
|
||||||
|
def _make_repo(tmpdir, structure):
|
||||||
|
"""Create a test repo from a dict of {path: content}."""
|
||||||
|
for rel_path, content in structure.items():
|
||||||
|
p = Path(tmpdir) / rel_path
|
||||||
|
p.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
p.write_text(content)
|
||||||
|
|
||||||
|
|
||||||
|
def test_undocumented_symbol():
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
_make_repo(tmpdir, {
|
||||||
|
"src/calculator.py": "def add(a, b):\n return a + b\n",
|
||||||
|
"README.md": "# Calculator\n",
|
||||||
|
})
|
||||||
|
report = KnowledgeGapIdentifier().analyze(tmpdir)
|
||||||
|
undocumented = [g for g in report.gaps if g.gap_type == GapType.UNDOCUMENTED]
|
||||||
|
assert any(g.name == "add" for g in undocumented), "add should be undocumented"
|
||||||
|
|
||||||
|
|
||||||
|
def test_documented_symbol_no_gap():
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
_make_repo(tmpdir, {
|
||||||
|
"src/calculator.py": "def add(a, b):\n return a + b\n",
|
||||||
|
"README.md": "# Calculator\nUse `add()` to add numbers.\n",
|
||||||
|
})
|
||||||
|
report = KnowledgeGapIdentifier().analyze(tmpdir)
|
||||||
|
undocumented = [g for g in report.gaps
|
||||||
|
if g.gap_type == GapType.UNDOCUMENTED and g.name == "add"]
|
||||||
|
assert len(undocumented) == 0, "add is documented, should not be flagged"
|
||||||
|
|
||||||
|
|
||||||
|
def test_untested_module():
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
_make_repo(tmpdir, {
|
||||||
|
"src/calculator.py": "def add(a, b):\n return a + b\n",
|
||||||
|
"src/helper.py": "def format(x):\n return str(x)\n",
|
||||||
|
"tests/test_calculator.py": "from src.calculator import add\nassert add(1,2) == 3\n",
|
||||||
|
})
|
||||||
|
report = KnowledgeGapIdentifier().analyze(tmpdir)
|
||||||
|
untested = [g for g in report.gaps if g.gap_type == GapType.UNTESTED]
|
||||||
|
assert any("helper" in g.name for g in untested), "helper should be untested"
|
||||||
|
|
||||||
|
|
||||||
|
def test_tested_module_no_gap():
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
_make_repo(tmpdir, {
|
||||||
|
"src/calculator.py": "def add(a, b):\n return a + b\n",
|
||||||
|
"tests/test_calculator.py": "def test_add():\n assert True\n",
|
||||||
|
})
|
||||||
|
report = KnowledgeGapIdentifier().analyze(tmpdir)
|
||||||
|
untested = [g for g in report.gaps
|
||||||
|
if g.gap_type == GapType.UNTESTED and "calculator" in g.name]
|
||||||
|
assert len(untested) == 0, "calculator has tests, should not be flagged"
|
||||||
|
|
||||||
|
|
||||||
|
def test_missing_implementation():
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
_make_repo(tmpdir, {
|
||||||
|
"src/app.py": "def run():\n pass\n",
|
||||||
|
"docs/api.md": "# API\nUse `NonExistentClass` to do things.\n",
|
||||||
|
})
|
||||||
|
report = KnowledgeGapIdentifier().analyze(tmpdir)
|
||||||
|
missing = [g for g in report.gaps if g.gap_type == GapType.MISSING_IMPLEMENTATION]
|
||||||
|
assert any(g.name == "NonExistentClass" for g in missing)
|
||||||
|
|
||||||
|
|
||||||
|
def test_private_symbols_skipped():
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
_make_repo(tmpdir, {
|
||||||
|
"src/app.py": "def _internal():\n pass\ndef public():\n pass\n",
|
||||||
|
"README.md": "# App\n",
|
||||||
|
})
|
||||||
|
report = KnowledgeGapIdentifier().analyze(tmpdir)
|
||||||
|
undocumented_names = [g.name for g in report.gaps if g.gap_type == GapType.UNDOCUMENTED]
|
||||||
|
assert "_internal" not in undocumented_names, "Private symbols should be skipped"
|
||||||
|
assert "public" in undocumented_names
|
||||||
|
|
||||||
|
|
||||||
|
def test_empty_repo():
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
report = KnowledgeGapIdentifier().analyze(tmpdir)
|
||||||
|
assert len(report.gaps) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_invalid_path():
|
||||||
|
report = KnowledgeGapIdentifier().analyze("/nonexistent/path/xyz")
|
||||||
|
assert len(report.gaps) == 1
|
||||||
|
assert report.gaps[0].severity == GapSeverity.ERROR
|
||||||
|
|
||||||
|
|
||||||
|
def test_report_summary():
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
_make_repo(tmpdir, {
|
||||||
|
"src/app.py": "class MyService:\n def handle(self):\n pass\n",
|
||||||
|
"README.md": "# App\n",
|
||||||
|
})
|
||||||
|
report = KnowledgeGapIdentifier().analyze(tmpdir)
|
||||||
|
summary = report.summary()
|
||||||
|
assert "UNDOCUMENTED" in summary
|
||||||
|
assert "MyService" in summary
|
||||||
|
|
||||||
|
|
||||||
|
def test_report_to_dict():
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
_make_repo(tmpdir, {
|
||||||
|
"src/app.py": "def hello():\n pass\n",
|
||||||
|
"README.md": "# App\n",
|
||||||
|
})
|
||||||
|
report = KnowledgeGapIdentifier().analyze(tmpdir)
|
||||||
|
d = report.to_dict()
|
||||||
|
assert "total_gaps" in d
|
||||||
|
assert "gaps" in d
|
||||||
|
assert isinstance(d["gaps"], list)
|
||||||
|
assert d["total_gaps"] > 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_undocumented_symbol()
|
||||||
|
test_documented_symbol_no_gap()
|
||||||
|
test_untested_module()
|
||||||
|
test_tested_module_no_gap()
|
||||||
|
test_missing_implementation()
|
||||||
|
test_private_symbols_skipped()
|
||||||
|
test_empty_repo()
|
||||||
|
test_invalid_path()
|
||||||
|
test_report_summary()
|
||||||
|
test_report_to_dict()
|
||||||
|
print("All 10 tests passed.")
|
||||||
Reference in New Issue
Block a user