# Copyright (c) 2026 Patrick Motsch # All rights reserved. """A3: layout primitives (cover_page, image_grid). Covers the markdown authoring conventions (fenced ```cover_page / ```image_grid blocks) and the PDF/DOCX renderer handlers, using real reportlab / python-docx. """ import base64 import io from modules.serviceCenter.services.serviceGeneration.styleDefaults import resolveStyle from modules.serviceCenter.services.serviceGeneration.renderers.rendererPdf import RendererPdf from modules.serviceCenter.services.serviceGeneration.renderers.rendererDocx import RendererDocx from modules.serviceCenter.services.serviceGeneration.subDocumentUtility import markdownToDocumentJson from modules.datamodels.datamodelJson import supportedSectionTypes def _tinyPngB64() -> str: from PIL import Image as PILImage buf = io.BytesIO() PILImage.new("RGB", (8, 8), (30, 120, 200)).save(buf, format="PNG") return base64.b64encode(buf.getvalue()).decode("ascii") def _imgContent(): return {"base64Data": _tinyPngB64(), "altText": "Pic"} # ── datamodel ─────────────────────────────────────────────────────── def test_layout_types_are_registered(): assert "cover_page" in supportedSectionTypes assert "image_grid" in supportedSectionTypes # ── markdown authoring ────────────────────────────────────────────── def test_markdown_parses_cover_page_block(): md = ( "```cover_page\n" "title: Klageschrift\n" "subtitle: In Sachen A gegen B\n" "author: Dr. Muster\n" "date: 2026-06-02\n" "logo: file:logo-1\n" "```\n" ) doc = markdownToDocumentJson(md, "T") sections = doc["documents"][0]["sections"] assert len(sections) == 1 sec = sections[0] assert sec["content_type"] == "cover_page" content = sec["elements"][0]["content"] assert content["title"] == "Klageschrift" assert content["subtitle"] == "In Sachen A gegen B" assert content["author"] == "Dr. Muster" assert content["date"] == "2026-06-02" assert content["_fileRef"] == "logo-1" def test_markdown_parses_image_grid_block(): md = ( "```image_grid\n" "columns: 3\n" '![Foto1](file:img-1 "200pt")\n' "file:img-2\n" "https://example.com/x.png\n" "```\n" ) doc = markdownToDocumentJson(md, "T") sec = doc["documents"][0]["sections"][0] assert sec["content_type"] == "image_grid" content = sec["elements"][0]["content"] assert content["columns"] == 3 assert len(content["images"]) == 3 assert content["images"][0]["_fileRef"] == "img-1" assert content["images"][0]["widthPt"] == 200 assert content["images"][1]["_fileRef"] == "img-2" assert content["images"][2]["_srcUrl"] == "https://example.com/x.png" def test_markdown_plain_code_block_still_works(): md = "```python\nprint('x')\n```\n" doc = markdownToDocumentJson(md, "T") sec = doc["documents"][0]["sections"][0] assert sec["content_type"] == "code_block" assert sec["elements"][0]["content"]["language"] == "python" # ── PDF handlers ──────────────────────────────────────────────────── def test_pdf_cover_page_emits_page_break(): from reportlab.platypus import PageBreak r = RendererPdf() styles = r._convertUnifiedStyleToInternal(resolveStyle(None)) el = {"content": {"title": "Report", "subtitle": "2026", "author": "PM"}} flowables = r._renderCoverPage(el, styles) assert any(isinstance(f, PageBreak) for f in flowables) assert len(flowables) >= 2 def test_pdf_image_grid_builds_table(): from reportlab.platypus import Table r = RendererPdf() r._tempImageFiles = [] styles = r._convertUnifiedStyleToInternal(resolveStyle(None)) el = {"content": {"columns": 2, "images": [_imgContent(), _imgContent(), _imgContent()]}} flowables = r._renderImageGrid(el, styles) tables = [f for f in flowables if isinstance(f, Table)] assert len(tables) == 1 # 3 images, 2 columns -> 2 rows (last cell padded). assert len(tables[0]._cellvalues) == 2 r._cleanupTempImageFiles() # ── DOCX handlers ─────────────────────────────────────────────────── def test_docx_cover_page_renders_and_breaks(): from docx import Document r = RendererDocx() doc = Document() before = len(doc.paragraphs) r._renderCoverPage(doc, {"content": {"title": "Klageschrift", "author": "Dr. M"}}, {}) # New paragraphs were added (spacers + title + author) and a page break exists. assert len(doc.paragraphs) > before xml = doc.element.xml assert "w:br" in xml and 'type="page"' in xml def test_docx_image_grid_builds_table_with_pictures(): from docx import Document r = RendererDocx() doc = Document() r._renderImageGrid(doc, {"content": {"columns": 2, "images": [_imgContent(), _imgContent(), _imgContent()]}}, {}) assert len(doc.tables) == 1 table = doc.tables[0] assert len(table.columns) == 2 assert len(table.rows) == 2 assert len(doc.inline_shapes) == 3