Files
md2gost/tests/test_render.py
T

234 lines
8.1 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.
import pytest
from md2gost.latex.titlepages import TITLEPAGES
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 render_fm(extra: str, body: str = "Текст.\n") -> str:
head = f"---\nназвание: Тестовая работа\nтип: Отчёт\n{extra}---\n\n"
parser = Parser(head + body)
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}[H]" 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}[H]" 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]
TABLE_MD = (
"Таблица 1 —— Сравнение скорости\n\n"
"| № Запуска | Python (сек) | C++ (сек) |\n"
"| :--- | :---: | ---: |\n"
"| **1** | 0.027852 | 0.000285 |\n"
)
def test_table_with_caption() -> None:
tex = render(TABLE_MD)
assert "\\begin{table}[H]" in tex
assert "\\caption{Сравнение скорости}" in tex
assert "\\begin{tabular}{|l|c|r|}" in tex
assert "\\textbf{1} & 0.027852 & 0.000285 \\\\" in tex
def test_table_caption_number_is_discarded() -> None:
tex = render(TABLE_MD)
block = _table_block(tex)
assert "Таблица 1" not in block
def test_table_without_caption_stays_bare() -> None:
tex = render("| a | b |\n| --- | --- |\n| 1 | 2 |\n")
assert "\\begin{table}" not in tex
assert "\\begin{tabular}{|l|l|}" in tex
def test_table_caption_paragraph_is_not_duplicated() -> None:
tex = render(TABLE_MD)
assert tex.count("Сравнение скорости") == 1
def _table_block(tex: str) -> str:
start = tex.index("\\begin{table}")
end = tex.index("\\end{table}") + len("\\end{table}")
return tex[start:end]
def test_titlepage_default_is_used_when_field_absent() -> None:
tex = render("Текст.\n")
assert "\\begin{titlepage}" in tex
assert "ОТЧЁТ ПО УЧЕБНОЙ ПРАКТИКЕ" not in tex
def test_titlepage_registry_lists_three_layouts() -> None:
assert set(TITLEPAGES) == {"default", "ptp-report", "ptp-task"}
def test_titlepage_unknown_name_raises() -> None:
with pytest.raises(ValueError, match="ptp-report"):
render_fm("титульник: несуществующий\n")
PTP_REPORT_FM = (
"титульник: ptp-report\n"
"факультет: Информатика и системы управления (ИУ)\n"
"кафедра: Теоретическая информатика и компьютерные технологии (ИУ9)\n"
"студент: И. И. Камалетдинов\n"
"студент_полностью: Камалетдинов Ильяс Илнарович\n"
"группа: ИУ9-22Б\n"
"тип_практики: проектно-технологическая практика\n"
"предприятие: МГТУ имени Н. Э. Баумана\n"
"команда: Система мониторинга радиоэфира\n"
"хранилище: https://monitor.yss.su/IU9/radio-serv\n"
"руководитель: Д. П. Посевин\n"
"год: 2026\n"
)
def test_ptp_report_has_blank_headings() -> None:
tex = render_fm(PTP_REPORT_FM)
for heading in (
"ОТЧЁТ ПО УЧЕБНОЙ ПРАКТИКЕ",
"Тип практики",
"Название предприятия",
"Команда",
"Оценка",
"Руководитель практики",
):
assert heading in tex
def test_ptp_report_fills_all_fields() -> None:
tex = render_fm(PTP_REPORT_FM)
for value in (
"Камалетдинов Ильяс Илнарович",
"И. И. Камалетдинов",
"ИУ9-22Б",
"проектно-технологическая практика",
"МГТУ имени Н. Э. Баумана",
"Д. П. Посевин",
"2026",
):
assert value in tex
def test_ptp_report_team_line_includes_repository() -> None:
tex = render_fm(PTP_REPORT_FM)
assert "Система мониторинга радиоэфира (хранилище" in tex
assert "monitor.yss.su/IU9/radio-serv" in tex
def test_ptp_report_team_line_without_repository() -> None:
fm = PTP_REPORT_FM.replace(
"хранилище: https://monitor.yss.su/IU9/radio-serv\n", ""
)
tex = render_fm(fm)
assert "хранилище" not in tex
def test_ptp_report_has_no_hardcoded_names() -> None:
"""Имена, группы и предприятия приходят только из front matter."""
import inspect
from md2gost.latex.titlepages import ptp_report
source = inspect.getsource(ptp_report)
for forbidden in ("Посевин", "Коновалов", "Камалетдинов", "ИУ9-2"):
assert forbidden not in source