#!/usr/bin/env python3 """Generate Typst tables of unit tests for chapter 5.""" from __future__ import annotations import re from collections import defaultdict from pathlib import Path def typst_escape(s: str) -> str: return s.replace("\\", "\\\\").replace("`", "\\`") def emit_table( lines: list[str], caption: str, ncol: int, headers: list[str], data_rows: list[list[str]], label: str, ) -> None: lines.append("#pz-test-table(\n") lines.append(f" [{caption}],\n") lines.append(f" {ncol},\n") lines.append(" table.header(\n") for h in headers: lines.append(f" [{typst_escape(h)}],\n") lines.append(" ),\n") for row in data_rows: cells = ", ".join(f"[{typst_escape(c)}]" for c in row) lines.append(f" {cells},\n") lines.append(f") <{label}>\n\n") def main() -> None: root = Path(__file__).resolve().parents[2] out = Path(__file__).resolve().parents[1] / "includes" / "ch05-tests-generated.typ" rows: list[tuple[str, str, str, str]] = [] for p in sorted(root.rglob("*.kt")): if "/src/test/" not in p.as_posix(): continue text = p.read_text(encoding="utf-8", errors="replace") cls_m = re.search(r"class\s+(\w+)", text) if not cls_m: continue cls = cls_m.group(1) mod = p.parts[p.parts.index("src") - 1] rel = p.relative_to(root).as_posix() for m in re.finditer(r"@Test[\s\S]*?fun\s+(?:`([^`]+)`|(\w+))\s*\(", text): name = m.group(1) or m.group(2) rows.append((mod, cls, name, rel)) by_mod: dict[str, list] = defaultdict(list) for mod, cls, name, rel in rows: by_mod[mod].append((cls, name, rel)) lines = [ "// AUTO-GENERATED by gen_test_tables.py — include from ch05.typ\n", '#import "common.typ": pz-test-table\n\n', ] summary_rows = [] for mod in sorted(by_mod): for cls, name, rel in by_mod[mod]: short = rel.split("/")[-1] summary_rows.append([mod, cls, name, short]) emit_table( lines, "Сводка модульных unit-тестов (src/test)", 4, ["Модуль", "Класс", "Метод", "Файл"], summary_rows, "tbl-unit-all", ) for mod in sorted(by_mod): safe = mod.replace("-", "_") lines.append(f"=== Реестр тестов модуля :{mod}\n\n") mod_rows = [ [cls, name, rel.split("/")[-1]] for cls, name, rel in by_mod[mod] ] emit_table( lines, f"Unit-тесты модуля :{mod}", 3, ["Класс", "Метод", "Файл"], mod_rows, f"tbl-unit-{safe}", ) out.write_text("".join(lines), encoding="utf-8") print(f"Wrote {out} ({len(rows)} tests)", flush=True) if __name__ == "__main__": main()