92 lines
3.8 KiB
Python
92 lines
3.8 KiB
Python
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
|