feat: add repeated dual-QR A4 resource headers

This commit is contained in:
user
2026-07-15 21:31:34 +02:00
parent da1e37eea9
commit 01a5f18414
7 changed files with 1601 additions and 114 deletions
+161 -2
View File
@@ -2,9 +2,12 @@
from __future__ import annotations
import json
import base64
import os
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
@@ -86,18 +89,174 @@ def check_render() -> None:
raise AssertionError(f"TeX nie zawiera znacznika {marker!r}")
if marker not in html:
raise AssertionError(f"HTML nie zawiera znacznika {marker!r}")
if r"\qrcode[height=" not in tex:
if "\x00" in html:
raise AssertionError("HTML zawiera bajt NUL po rozwinięciu placeholderów")
if not any(r"\qrcode[" in line and "height=" in line for line in tex.splitlines()):
raise AssertionError("TeX nie zawiera kodu QR z tabliczki")
for expected_url in (
"https://demo.example.edu/cards/demo-01",
"https://gitea.example.edu/edu/cards/demo-01",
):
if expected_url not in tex or expected_url not in html:
raise AssertionError(f"brak adresu nagłówka {expected_url!r}")
if tex.count(r"\qrcode[level=L,height=22mm]") < 2:
raise AssertionError("TeX nie zawiera obu kodów QR nagłówka")
for marker in ("resource-qr-repository", "resource-qr-page"):
if marker not in html:
raise AssertionError(f"HTML nie zawiera komórki {marker!r}")
for marker in ('class="title-qr"', 'class="code-subblock"'):
if marker not in html:
raise AssertionError(f"HTML nie zawiera znacznika {marker!r}")
def check_section_assets() -> None:
with tempfile.TemporaryDirectory(prefix="card-layouts-assets-") as temp_dir:
card_root = Path(temp_dir) / "card"
shutil.copytree(EXAMPLE_CARD, card_root, ignore=shutil.ignore_patterns("build"))
source_path = card_root / "json" / "card_source.json"
source = load_json(source_path)
source["template"] = str(ROOT / "templates" / "karta-klasyczna.json")
source["generated"] = {
"tex": "build/tex/main.tex",
"html": "build/html/index.html",
"html_css": "build/html/style.css",
}
source["sections"][0]["content_tex"] += (
r" \textbf{Widok \texttt{GDB}.}"
"\\begin{verbatim}stemctl test demo\\end{verbatim}"
)
source["sections"][0]["assets"] = [
{
"path": "assets/debug-screen.png",
"caption": "Kontrolny zrzut debuggera.",
"label": "fig:debug-screen",
"alt": "Zrzut debuggera",
"kind": "screenshot",
"width": 0.96,
}
]
source["sections"][0]["steps"][0]["figure_refs"] = ["fig:debug-screen"]
source_path.write_text(json.dumps(source, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
asset_path = card_root / "doc" / "assets" / "debug-screen.png"
asset_path.parent.mkdir(parents=True, exist_ok=True)
asset_path.write_bytes(
base64.b64decode(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII="
)
)
subprocess.run(
[sys.executable, str(ROOT / "tools" / "render_card.py"), str(card_root)],
cwd=ROOT,
check=True,
stdout=subprocess.DEVNULL,
)
tex = (card_root / "build" / "tex" / "main.tex").read_text(encoding="utf-8")
html = (card_root / "build" / "html" / "index.html").read_text(encoding="utf-8")
copied_asset = card_root / "build" / "html" / "figures" / "debug-screen.png"
for marker in ("fig:debug-screen", "debug-screen.png", "Kontrolny zrzut debuggera"):
if marker not in tex:
raise AssertionError(f"TeX assetu nie zawiera znacznika {marker!r}")
if marker not in html:
raise AssertionError(f"HTML assetu nie zawiera znacznika {marker!r}")
if "\x00" in html:
raise AssertionError("HTML assetu zawiera bajt NUL")
if r"\begin{verbatim}" in html or r"\end{verbatim}" in html:
raise AssertionError("HTML zawiera surowe środowisko verbatim")
if "<pre><code>stemctl test demo</code></pre>" not in html:
raise AssertionError("HTML nie zawiera wyrenderowanego bloku verbatim")
if not copied_asset.is_file():
raise AssertionError(f"asset nie został skopiowany: {copied_asset}")
def check_external_references() -> None:
with tempfile.TemporaryDirectory(prefix="card-layouts-references-") as temp_dir:
root = Path(temp_dir)
card_root = root / "card"
registry_root = root / "registry"
shutil.copytree(EXAMPLE_CARD, card_root, ignore=shutil.ignore_patterns("build"))
(registry_root / "json").mkdir(parents=True)
(registry_root / "docs").mkdir()
registry_uuid = "03403a8a-e20d-5b17-9004-26d9fe6c3003"
strategy_uuid = "1ecfc474-4fbd-5a56-8ef1-80ae557761d0"
card_uuid = "4abec2d9-79e9-5dca-9040-c60669f51ff8"
registry = {
"schema": "esc-reference-registry.v1",
"uuid": registry_uuid,
"name": "test-registry",
"title": "Rejestr testowy",
"root_path": "..",
"base_url": "https://example.test/materials/",
"entries": [
{
"uuid": strategy_uuid,
"kind": "strategy",
"code": "M02",
"title": "Breakpointy",
"path": "docs/M02.md",
},
{
"uuid": card_uuid,
"kind": "card",
"title": "Wskaźniki i tablice",
"path": "docs/card.md",
},
],
}
registry_path = registry_root / "json" / "reference_registry.json"
registry_path.write_text(
json.dumps(registry, ensure_ascii=False, indent=2) + "\n",
encoding="utf-8",
)
(registry_root / "docs" / "M02.md").write_text("# M02\n", encoding="utf-8")
(registry_root / "docs" / "card.md").write_text("# Karta\n", encoding="utf-8")
source_path = card_root / "json" / "card_source.json"
source = load_json(source_path)
source["template"] = str(ROOT / "templates" / "karta-klasyczna.json")
source["reference_registries"] = [
{"uuid": registry_uuid, "source": str(registry_path)}
]
source["sections"][0]["steps"][0]["references"] = [
{"kind": "strategy", "registry_uuid": registry_uuid, "uuid": strategy_uuid},
{"kind": "card", "registry_uuid": registry_uuid, "uuid": card_uuid},
]
source_path.write_text(
json.dumps(source, ensure_ascii=False, indent=2) + "\n",
encoding="utf-8",
)
subprocess.run(
[sys.executable, str(ROOT / "tools" / "render_card.py"), str(card_root)],
cwd=ROOT,
check=True,
stdout=subprocess.DEVNULL,
)
tex = (card_root / "build" / "tex" / "main.tex").read_text(encoding="utf-8")
html = (card_root / "build" / "html" / "index.html").read_text(encoding="utf-8")
expected = (
"https://example.test/materials/docs/M02.md",
"https://example.test/materials/docs/card.md",
"M02",
"Wskaźniki i tablice",
)
for marker in expected:
if marker not in tex:
raise AssertionError(f"TeX referencji nie zawiera {marker!r}")
if marker not in html:
raise AssertionError(f"HTML referencji nie zawiera {marker!r}")
if f'data-reference-uuid="{strategy_uuid}"' not in html:
raise AssertionError("HTML nie zachowuje UUID rozwiązanej strategii")
if "<code>M02</code>" not in html:
raise AssertionError("HTML nie pokazuje kodu strategii jako etykiety")
def main() -> int:
check_json_files()
check_optional_json_schema()
check_render()
check_section_assets()
check_external_references()
print("PASS: schematy, layouty, przykład serii oraz render TeX/HTML są spójne.")
return 0