from pathlib import Path from docx import Document from app.review_filler import ( build_review_decisions, extract_review_tables, fill_review_docx_from_analysis, parse_analysis_markdown, select_review_table, validate_review_results, ) ROOT_DIR = Path(__file__).resolve().parent.parent ANALYSIS_MD = ROOT_DIR / "test" / "中央处理机正常模式软件任务书V1_00_094006f6_analysis.md" REVIEW_DOCX = ROOT_DIR / "test" / "附录A文档审查.docx" def test_parse_analysis_markdown_extracts_evidence_sections() -> None: analysis = parse_analysis_markdown(ANALYSIS_MD) sections = {item.section for item in analysis.evidences} polarities = {item.polarity for item in analysis.evidences} assert analysis.source_filename == "中央处理机正常模式软件任务书V1.00.docx" assert "符合项" in sections assert "不符合项" in sections assert "缺失章节或缺失证据" in sections assert {"positive", "negative", "manual"}.issubset(polarities) assert any("合格性规定" in item.text for item in analysis.evidences) def test_extract_review_tables_skips_qitao_and_selects_a2_for_requirements_analysis() -> None: analysis = parse_analysis_markdown(ANALYSIS_MD) tables = extract_review_tables(REVIEW_DOCX) selected = select_review_table(analysis, tables) assert [table.heading for table in tables] == [ "A.2软件需求规格说明审查单", "A.3软件设计文档审查单", "A.4用户手册审查单", ] assert selected.heading == "A.2软件需求规格说明审查单" assert len(selected.criteria) == 24 assert selected.criteria[0].sequence == "1" assert selected.criteria[0].category == "完整性" def test_build_review_decisions_uses_negative_evidence_for_missing_sections() -> None: analysis = parse_analysis_markdown(ANALYSIS_MD) table = select_review_table(analysis, extract_review_tables(REVIEW_DOCX)) decisions = build_review_decisions(analysis, table) assert len(decisions) == 24 assert {decision.result for decision in decisions}.issubset({"通过", "未通过", "不适用"}) assert decisions[0].criterion.sequence == "1" assert decisions[0].result == "未通过" assert any("缩略名" in evidence.text or "版本号" in evidence.text for evidence in decisions[0].evidence) missing_qualification = [ decision for decision in decisions if "合格性规定" in decision.criterion.content or "合格性" in decision.reason ] assert missing_qualification assert all(decision.result == "未通过" for decision in missing_qualification) def test_fill_review_docx_from_analysis_writes_mutually_exclusive_results(tmp_path: Path) -> None: output_docx = tmp_path / "review-filled.docx" result = fill_review_docx_from_analysis(ANALYSIS_MD, REVIEW_DOCX, output_docx) assert result.target_heading == "A.2软件需求规格说明审查单; A.3软件设计文档审查单; A.4用户手册审查单" assert len(result.decisions) == 70 assert output_docx.exists() assert validate_review_results(output_docx, "A.2") == [] assert validate_review_results(output_docx, "A.3") == [] assert validate_review_results(output_docx, "A.4") == [] document = Document(output_docx) expected_rows = {1: 24, 2: 18, 3: 28} for table_index, expected_count in expected_rows.items(): marked_rows = 0 for row in document.tables[table_index].rows[3:]: sequence = row.cells[0].text.strip() if not sequence.isdigit(): continue marks = [row.cells[index].text.strip() for index in (3, 4, 5)] assert sum(1 for value in marks if value == "✔") == 1 marked_rows += 1 assert marked_rows == expected_count