fix: 完善 UT 覆盖,统一 pytest 测试发现 - Closes #2
CI / test (pull_request) Successful in 9s

- 新建 pytest.ini 统一 test discovery(tests/ + skills/ir_generation_skill/tests/)
- test_step1~3 转换为 pytest 兼容格式,无输出文件时自动 skip
- 新增 tests/test_detect_conflicts.py(18 个纯函数单测)
- 新增 tests/test_config.py(7 个配置模块单测)
- CI 改为 pytest -v 使用 pytest.ini testpaths
- DEV_AGENT.md 新增 PR 提交规范

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-31 00:07:07 +08:00
parent 618364e744
commit 682dedb4b4
11 changed files with 619 additions and 32 deletions
@@ -365,6 +365,97 @@ def run_all_tests():
return total_failures == 0
# ═══════════════════════════════════════════════════════════════════════════════
# pytest discovery support — skips gracefully when output files are absent
# ═══════════════════════════════════════════════════════════════════════════════
import pytest # noqa: E402
def _load_si_and_doc():
"""Try to load semantic_index.json and the input document. Returns (si, doc) or (None, None)."""
try:
si = config.load_json(config.SEMANTIC_INDEX_JSON)
doc = config.load_input_document()
return si, doc
except FileNotFoundError:
return None, None
def test_step1_unit_ids():
"""pytest: verify all function_units have valid unit_id and name."""
si, doc = _load_si_and_doc()
if si is None:
pytest.skip("semantic_index.json not found — run step1_semantic_index.py first")
units = si.get("function_units", [])
errors = check_unit_ids(units)
assert not errors, f"unit_id/name errors: {errors}"
def test_step1_path_fields():
"""pytest: verify all function_units have non-empty path arrays."""
si, doc = _load_si_and_doc()
if si is None:
pytest.skip("semantic_index.json not found")
units = si.get("function_units", [])
errors = check_unit_paths(units)
assert not errors, f"path field errors: {errors}"
def test_step1_concept_parents():
"""pytest: verify concept parent references are valid."""
si, doc = _load_si_and_doc()
if si is None:
pytest.skip("semantic_index.json not found")
concepts = si.get("concepts", [])
errors = check_concept_parents(concepts)
assert not errors, f"concept parent errors: {errors}"
def test_step1_sources_exist():
"""pytest: verify all source references point to real content."""
si, doc = _load_si_and_doc()
if si is None:
pytest.skip("semantic_index.json not found")
units = si.get("function_units", [])
image_index = build_image_index(doc)
node_index = build_logic_tree_node_index(doc)
errors = check_sources_exist(units, image_index, node_index)
assert not errors, f"source reference errors: {errors}"
def test_step1_logic_tree_coverage():
"""pytest: verify decision/action nodes in logic trees are covered (warnings only)."""
si, doc = _load_si_and_doc()
if si is None:
pytest.skip("semantic_index.json not found")
units = si.get("function_units", [])
node_index = build_logic_tree_node_index(doc)
warnings = check_logic_tree_coverage(units, node_index)
# Warnings are informational, not failures — but report them
if warnings:
print(f"\n[WARN] Logic tree coverage warnings: {warnings}")
def test_step1_ensemble_confidence():
"""pytest: verify function_units have confidence/ensemble_support/source_versions."""
si, doc = _load_si_and_doc()
if si is None:
pytest.skip("semantic_index.json not found")
units = si.get("function_units", [])
errors = check_ensemble_confidence(units)
assert not errors, f"ensemble confidence errors: {errors}"
def test_step1_confidence_summary():
"""pytest: verify confidence_summary counts match actual unit/concept counts."""
si, doc = _load_si_and_doc()
if si is None:
pytest.skip("semantic_index.json not found")
errors = check_confidence_summary(si)
assert not errors, f"confidence_summary errors: {errors}"
if __name__ == "__main__":
success = run_all_tests()
sys.exit(0 if success else 1)