Files
2026Technology-Competition/tests/test_docx_injector.py
T
lhl e3c714d5d9 feat(writer): docx 注入原型提前(T17 架构审查整改,OV8)
- T17 (OV8, P1): 新建 src/genesis/writer/ 包
  - docx_injector.py: DocxInjector 用原生 python-docx 实现 §6.6 占位符注入
    - 章节级 {{section:id}} → 内容块 docx 元素序列(heading/paragraph/table)
    - 行内 {{meta}} → 元信息填充
    - 残留检查: 未替换 {{...}} 抛 DocxInjectError
    - 格式精度: 注入 heading 继承模板 Heading 样式,原内容不被破坏
  - 新增 test_docx_injector.py(5 用例)
  - 同步 design.md §6.7 渲染链路 T17 原型说明
- TDD: RED(模块缺失)→ GREEN(聚焦 5 passed)→ 全量 245 passed / 100.00%(1361 stmts/340 br)
2026-08-12 22:47:43 +08:00

90 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""docx 注入原型测试(T17OV8)。
OV8 裁定:最难成功标准(格式精度)排关键路径末尾 → docx 注入原型提前验证。
本文件测试 DocxInjector:模板占位符替换(章节级/行内)、残留检查、格式精度
(注入 heading 继承模板 Heading 样式,原有内容样式不被破坏)。
"""
from __future__ import annotations
import pytest
from docx import Document
from genesis.writer.docx_injector import (
Block,
DocxInjectError,
DocxInjector,
)
def _make_template(tmp_path, body: str) -> str:
doc = Document()
doc.add_paragraph("{{doc_title}}") # 行内占位符
doc.add_paragraph(body) # 章节占位符所在段落
doc.add_paragraph("尾部固定内容")
path = tmp_path / "template.docx"
doc.save(str(path))
return str(path)
def _section_blocks() -> list[Block]:
return [
Block(kind="heading", text="3.1 テーブル一覧", level=2),
Block(kind="paragraph", text="以下がDB表定义です。"),
Block(kind="table", rows=[["テーブル", "説明"], ["TB001", "社員"]]),
]
# ---------- 章节级占位符替换 ----------
def test_section_placeholder_replaced(tmp_path):
tpl = _make_template(tmp_path, "{{section:db_design}}")
inj = DocxInjector(tpl)
out = inj.inject({"db_design": _section_blocks()}, {"doc_title": "概要設計書"})
full_text = "\n".join(p.text for p in out.paragraphs)
assert "{{section:db_design}}" not in full_text
assert "3.1 テーブル一覧" in full_text
assert "以下がDB表定义です。" in full_text
# ---------- 行内占位符替换 ----------
def test_inline_meta_replaced(tmp_path):
tpl = _make_template(tmp_path, "{{section:db_design}}")
inj = DocxInjector(tpl)
out = inj.inject({"db_design": []}, {"doc_title": "概要設計書"})
assert "{{doc_title}}" not in "\n".join(p.text for p in out.paragraphs)
assert "概要設計書" in "\n".join(p.text for p in out.paragraphs)
# ---------- 占位符残留检查 ----------
def test_residue_detection_raises(tmp_path):
tpl = _make_template(tmp_path, "{{section:unknown_chapter}}")
inj = DocxInjector(tpl)
with pytest.raises(DocxInjectError, match="残留"):
inj.inject({}, {"doc_title": "X"})
# ---------- 格式精度:heading 继承模板样式 ----------
def test_heading_inherits_template_style(tmp_path):
tpl = _make_template(tmp_path, "{{section:db_design}}")
inj = DocxInjector(tpl)
out = inj.inject({"db_design": _section_blocks()}, {"doc_title": "T"})
# 注入的 heading blocklevel=2)应渲染为模板中存在的 Heading 2 样式段落
heading_paras = [p for p in out.paragraphs if p.style.name == "Heading 2"]
assert any("3.1 テーブル一覧" in p.text for p in heading_paras)
def test_original_content_style_preserved(tmp_path):
tpl = _make_template(tmp_path, "{{section:db_design}}")
inj = DocxInjector(tpl)
out = inj.inject({"db_design": []}, {"doc_title": "T"})
# 模板原有段落(尾部固定内容)在注入后仍存在且未被破坏
assert any("尾部固定内容" in p.text for p in out.paragraphs)