Files
md2gost/tests/test_render.py
T
Arseny 8a921e2337 [ADD] поддержка изображений и рефакторинг диспетчера токенов
- registry.py: реестры BLOCK/PATTERNS/INLINE с декораторами @block/@pattern/@inline
- render.py: единый диспетчер, слой паттернов, проверка контракта pos (RuntimeError),
  pending_toc вместо current_heading для единственной вставки СОДЕРЖАНИЯ
- handlers/image.py: вики-ссылки ![[путь|ширина]], подпись Рисунок N —— ... ,
  figure-окружение, авто-нумерация, копирование файлов в tmpdir
- handlers/inline.py: табличная диспетчеризация вместо if/elif
- Все block-обработчики подписаны @block, корректно продвигают pos
- parser.py: препроцессинг ![[...]] → ![](path), iter_image_sources()
- main.py: _copy_assets (emblem+картинки в tmpdir), фикс лога (имя .tex),
  cwd=tmpdir для xelatex, цикл вместо дублирования, force-include emblem
- tests/test_render.py: pytest (10 тестов), pyproject dev-dep, make test
- preamble.py: name=Рисунок для figure-caption (было Рис. от babel)
- Исправлены баги: мёртвый обработчик, emblem не копировалась,
  множественный TOC, захардкожен report.log, маскировка pos
- README/AGENTS.md обновлены
2026-08-25 13:58:01 +03:00

103 lines
3.5 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.
from md2gost.parser import Parser
from md2gost.render import Renderer
FRONT_MATTER = "---\nназвание: Тестовая работа\nтип: Отчёт\n---\n\n"
def render(md: str) -> str:
parser = Parser(FRONT_MATTER + md)
return Renderer(parser.tokens, parser.front_matter).render()
def test_heading_numbering() -> None:
tex = render("# Исследовательская часть\n\n## Обзор\n")
assert "\\section{Исследовательская часть}" in tex
assert "\\subsection{Обзор}" in tex
def test_unnumbered_heading() -> None:
tex = render("# ВВЕДЕНИЕ\n\nТекст.\n")
assert "\\section{" not in tex
assert "\\clearpage" in tex
assert "ВВЕДЕНИЕ" in tex
def test_list_punctuation() -> None:
tex = render("- один\n- два\n- три\n")
assert " \\item один;" in tex
assert " \\item три." in tex
def test_figure_with_caption(tmp_path) -> None:
tex = render(
"![[images/antenna.png]]\n\nРисунок 1 — Антенна\n\n"
"Данная антенна используется для ...\n"
)
assert "\\begin{figure}[ht]" in tex
assert "\\centering" in tex
assert (
"\\includegraphics[width=0.8\\textwidth]{\\detokenize{images/antenna.png}}"
in tex
)
assert "\\caption{Антенна}" in tex
assert "Данная антенна используется для ..." in tex
def test_figure_without_caption() -> None:
tex = render("![[images/photo.png]]\n\nОбычный абзац после картинки.\n")
assert "\\begin{figure}[ht]" in tex
assert "\\caption{" not in tex
assert "Обычный абзац после картинки." in tex
def test_figure_custom_width() -> None:
tex = render("![[images/scheme.png|50]]\n\nРисунок 2 —— Схема\n")
assert (
"\\includegraphics[width=0.5\\textwidth]{\\detokenize{images/scheme.png}}"
in tex
)
def test_caption_number_is_discarded() -> None:
tex = render("![[images/a.png]]\n\nРисунок 7 —— Что-то\n")
assert "7" not in _figure_block(tex)
def test_inline_image_skipped_with_warning(capsys) -> None:
tex = render("Текст с ![alt](img.png) внутри.\n")
assert "предупреждение: картинка внутри текста пропущена" in capsys.readouterr().err
assert "\\begin{figure}" not in tex
assert "img.png" not in tex
def test_toc_inserted_once() -> None:
tex = render("# СОДЕРЖАНИЕ\n\n# ВВЕДЕНИЕ\n\nТекст.\n\n# ЗАКЛЮЧЕНИЕ\n\nВыводы.\n")
assert tex.count("\\tableofcontents") == 1
def test_handler_must_advance_pos() -> None:
from markdown_it import MarkdownIt
tokens = MarkdownIt().parse(FRONT_MATTER + "# Заголовок\n")
renderer = Renderer(tokens, {"название": "Т", "тип": "Отчёт"})
renderer.render()
broken = Renderer(tokens, {"название": "Т", "тип": "Отчёт"})
from md2gost.registry import BLOCK
original = BLOCK["heading_open"]
BLOCK["heading_open"] = lambda r, tok: ""
try:
try:
broken.render()
raise AssertionError("ожидался RuntimeError")
except RuntimeError as e:
assert "heading_open" in str(e)
finally:
BLOCK["heading_open"] = original
def _figure_block(tex: str) -> str:
start = tex.index("\\begin{figure}")
end = tex.index("\\end{figure}") + len("\\end{figure}")
return tex[start:end]