#!/usr/bin/env python3 """章后抽取的机械绑定测试,不连接数据库、不调用模型。""" import pathlib import sys PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SCRIPT_DIR = PROJECT_ROOT / ".claude" / "skills" / "extract-chapter-knowledge" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from extract_knowledge import ExtractionContractError, normalize_extraction, salvage_extraction # noqa: E402 BODY = "林深走进舰桥,何岚把黑色钥匙交给他。" def test_normalize_binds_evidence_and_aliases(): result = normalize_extraction({ "entities": [{"type": "人物", "name": "林深", "brief": "机师", "fields": {}, "evidence": "林深走进舰桥"}], "relations": [], "state": {"handoff": "继续调查"}, }, BODY) assert result["entities"][0]["type"] == "character" assert result["entities"][0]["evidence"] in BODY def test_normalize_rejects_fabricated_evidence(): try: normalize_extraction({ "entities": [{"type": "item", "name": "黑钥匙", "brief": "钥匙", "fields": {}, "evidence": "正文没有这句"}], "relations": [], "state": {}, }, BODY) except ExtractionContractError as exc: assert "证据不在正文" in str(exc) else: raise AssertionError("编造证据必须失败关闭") def test_salvage_drops_unbound_relation_and_keeps_exact_name_evidence(): result = salvage_extraction({ "entities": [ {"type": "item", "name": "黑色钥匙", "brief": "钥匙", "fields": {}, "evidence": "模型编造"}, {"type": "item", "name": "不存在的物件", "brief": "?", "fields": {}, "evidence": "模型编造"}, ], "relations": [{"source": "林深", "target": "何岚", "type": "伙伴", "description": "?", "evidence": "模型编造"}], "state": {}, }, "林深走进舰桥,何岚把黑色钥匙交给他。") assert [item["name"] for item in result["entities"]] == ["黑色钥匙"] assert result["entities"][0]["evidence"] == "黑色钥匙" assert result["relations"] == [] assert result["mechanicalDrops"] == {"entities": 1, "relations": 1} def main(): test_normalize_binds_evidence_and_aliases() test_normalize_rejects_fabricated_evidence() test_salvage_drops_unbound_relation_and_keeps_exact_name_evidence() print("全部通过") if __name__ == "__main__": main()