fischer-agentkit/tests/documents/test_word_renderer.py

148 lines
4.5 KiB
Python

"""Tests for WordRenderer — Markdown → .docx mapping (U2)."""
from __future__ import annotations
from pathlib import Path
from docx import Document
from agentkit.documents.renderers.word_renderer import WordRenderer
def _render(markdown: str, tmp_path: Path) -> Path:
"""Render markdown to a temp .docx and return the path."""
out = tmp_path / "test.docx"
WordRenderer().render(markdown, out)
return out
def _read_paragraphs(path: Path) -> list[str]:
"""Return all paragraph texts from a .docx."""
doc = Document(str(path))
return [p.text for p in doc.paragraphs]
def test_heading_levels(tmp_path: Path) -> None:
"""# / ## / ### map to heading levels 1/2/3."""
md = "# Title\n## Subtitle\n### Section\n"
path = _render(md, tmp_path)
doc = Document(str(path))
headings = [(p.style.name, p.text) for p in doc.paragraphs if p.text]
assert ("Heading 1", "Title") in headings
assert ("Heading 2", "Subtitle") in headings
assert ("Heading 3", "Section") in headings
def test_paragraphs(tmp_path: Path) -> None:
"""Plain text lines become paragraphs."""
md = "First paragraph.\n\nSecond paragraph.\n"
path = _render(md, tmp_path)
texts = _read_paragraphs(path)
assert "First paragraph." in texts
assert "Second paragraph." in texts
def test_bullet_list(tmp_path: Path) -> None:
"""Bullet items use List Bullet style."""
md = "- Apple\n- Banana\n- Cherry\n"
path = _render(md, tmp_path)
doc = Document(str(path))
bullets = [p for p in doc.paragraphs if p.style.name == "List Bullet"]
assert len(bullets) == 3
assert bullets[0].text == "Apple"
assert bullets[1].text == "Banana"
assert bullets[2].text == "Cherry"
def test_numbered_list(tmp_path: Path) -> None:
"""Numbered items use List Number style."""
md = "1. First\n2. Second\n3. Third\n"
path = _render(md, tmp_path)
doc = Document(str(path))
numbers = [p for p in doc.paragraphs if p.style.name == "List Number"]
assert len(numbers) == 3
assert numbers[0].text == "First"
assert numbers[1].text == "Second"
def test_table(tmp_path: Path) -> None:
"""GFM table maps to a docx table with correct cells."""
md = "| Name | Age |\n| --- | --- |\n| Alice | 30 |\n| Bob | 25 |\n"
path = _render(md, tmp_path)
doc = Document(str(path))
assert len(doc.tables) == 1
table = doc.tables[0]
# 3 rows (header + 2 data), 2 cols
assert len(table.rows) == 3
assert len(table.columns) == 2
assert table.cell(0, 0).text == "Name"
assert table.cell(0, 1).text == "Age"
assert table.cell(1, 0).text == "Alice"
assert table.cell(2, 1).text == "25"
def test_bold_inline(tmp_path: Path) -> None:
"""**bold** produces a bold run."""
md = "This has **bold** text.\n"
path = _render(md, tmp_path)
doc = Document(str(path))
para = doc.paragraphs[0]
bold_runs = [r for r in para.runs if r.bold]
assert len(bold_runs) == 1
assert bold_runs[0].text == "bold"
def test_italic_inline(tmp_path: Path) -> None:
"""*italic* produces an italic run."""
md = "This has *italic* text.\n"
path = _render(md, tmp_path)
doc = Document(str(path))
para = doc.paragraphs[0]
italic_runs = [r for r in para.runs if r.italic]
assert len(italic_runs) == 1
assert italic_runs[0].text == "italic"
def test_empty_markdown(tmp_path: Path) -> None:
"""Empty Markdown produces a valid (empty) document."""
path = _render("", tmp_path)
assert path.exists()
doc = Document(str(path))
# No paragraphs with text
assert all(not p.text for p in doc.paragraphs)
def test_mixed_content(tmp_path: Path) -> None:
"""Heading + paragraph + list + table renders without error."""
md = """# Report
This is the intro.
- Point one
- Point two
| Col A | Col B |
| ----- | ----- |
| 1 | 2 |
Final paragraph.
"""
path = _render(md, tmp_path)
assert path.exists()
doc = Document(str(path))
# Should have at least one heading, one table, two bullet items
headings = [p for p in doc.paragraphs if p.style.name.startswith("Heading")]
assert len(headings) >= 1
assert len(doc.tables) == 1
bullets = [p for p in doc.paragraphs if p.style.name == "List Bullet"]
assert len(bullets) == 2
def test_chinese_text(tmp_path: Path) -> None:
"""Chinese characters render correctly in paragraphs and headings."""
md = "# 中文标题\n\n这是中文段落。\n"
path = _render(md, tmp_path)
texts = _read_paragraphs(path)
assert "中文标题" in texts
assert "这是中文段落。" in texts