# -*- coding: utf-8 -*- from docx import Document from docx.oxml.ns import qn from zipfile import ZipFile from pathlib import Path p = Path("在线考试系统实现方案(优化定稿版).docx") doc = Document(p) parts = [x.text for x in doc.paragraphs] for table in doc.tables: for row in table.rows: for cell in row.cells: parts.append(cell.text) text = chr(10).join(parts) headings = [(x.style.name, x.text) for x in doc.paragraphs if x.style.name.startswith("Heading")] required = [ "方案 B + 评审整改 + 协议补强", "P0", "P1", "P2", "R1", "R10", "answer_item(session_id, question_id)", "answer_operation", "opId", "payloadHash", "base_version", "server_seq", "STALE_VERSION", "SUBMIT_UNKNOWN", "UNIQUE submission(session_id)", "requestHash", "C10", "13 周", "2026-11-10", "不能直接复用", "不能证明其已经实现", "R8 未关闭", "先证明“不会错”,再测量“跑多快”" ] for s in required: assert s in text, s for bad in ["TODO", "待补充", "待填写"]: assert bad not in text, bad assert len(doc.tables) == 21, len(doc.tables) assert "DUPLICATE_CONTENT" not in text assert "CONTENT_ALREADY_EQUAL" in text assert "会话语义正确率 = 故障结束后" in text assert "status、next_seq、version" not in text assert "状态迁移用会话行锁,不另设version" in text for status in ["APPLIED", "DUPLICATE", "STALE_VERSION", "SESSION_CLOSED", "REJECTED"]: assert status in text from optimized_plan_content import EXAM_ANSWER, PROCTOR_EVENT, PROCTOR_SESSION for link in [EXAM_ANSWER, PROCTOR_EVENT, PROCTOR_SESSION]: assert "/blob/master/" in link and "/domain/entity/" not in link and "/blob/main/" not in link with ZipFile(p) as z: xml = z.read("word/document.xml").decode("utf-8") assert "TOC " in xml and "1-2" in xml assert xml.count("= 9 settings = z.read("word/settings.xml").decode("utf-8") assert "updateFields" in settings print("path:", p.resolve()) print("bytes:", p.stat().st_size, "paragraphs:", len(doc.paragraphs), "tables:", len(doc.tables), "headings:", len(headings)) print("hyperlinks:", xml.count("