[ADD] тест вёрстки: эталонный документ собирается без выходов за поле

This commit is contained in:
Arseny
2026-09-02 13:12:36 +03:00
parent 82cde7b94b
commit d5b6f4b89e
+122
View File
@@ -0,0 +1,122 @@
"""Сквозная проверка вёрстки: документ должен собираться без дефектов.
Отдельные обработчики проверяются модульными тестами, но выход текста за поле
проявляется только после сборки: он зависит от шрифта, ширины колонок и
взаимодействия пакетов. Этот тест ловит регресс, который иначе видно лишь
глазами в готовом PDF.
"""
from __future__ import annotations
import shutil
import subprocess
import tempfile
from pathlib import Path
import pytest
import md2gost
from md2gost.latex.log import parse_log
from md2gost.parser import Parser
from md2gost.render import Renderer
pytestmark = pytest.mark.skipif(
shutil.which("xelatex") is None, reason="xelatex не установлен"
)
# Документ собран из конструкций, на которых вёрстка ломалась:
# длинный токен в узкой колонке, подглава с двузначным номером в оглавлении,
# перечень сокращений, листинг с подписью и длинными строками.
FRONT_MATTER = """---
титульник: ptp-report
факультет: Информатика и системы управления (ИУ)
кафедра: Теоретическая информатика и компьютерные технологии (ИУ9)
тип: Отчёт
название: Проверка вёрстки
студент: Иванов И. И.
студент_полностью: Иванов Иван Иванович
группа: ИУ9-22Б
тип_практики: проектно-технологическая практика
предприятие: МГТУ имени Н. Э. Баумана
команда: Проверка вёрстки
хранилище: https://example.invalid/very/long/repository/path
руководитель: Петров П. П.
год: 2026
---
"""
SUBSECTIONS = "\n".join(
f"## Подглава номер {i}\n\nТекст подглавы номер {i}.\n" for i in range(1, 12)
)
BODY = f"""
# АННОТАЦИЯ
Проверка вёрстки.
# СОДЕРЖАНИЕ
# ПЕРЕЧЕНЬ ПРИНЯТЫХ СОКРАЩЕНИЙ
SDR — Software-Defined Radio — программно-определяемая радиосистема
PSO — Particle Swarm Optimisation — метод роевой оптимизации
# ВВЕДЕНИЕ
Введение.
# Раздел
{SUBSECTIONS}
Таблица 1 —— Таблица с длинным токеном
| Направление | Формат | Назначение |
| :--- | :--- | :--- |
| сервер | HackRFTestingServer:идентификатор | Приветствие, подтверждает подключение |
Листинг 1 —— Листинг с длинными строками
```cpp
template <typename Rep, typename Period>
std::vector<T> drain_with_timeout(const std::atomic<bool>& running,
const std::chrono::duration<Rep, Period>& timeout);
```
# ЗАКЛЮЧЕНИЕ
Заключение.
# СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ
1. Гилев, И. В. Использование технологии SDR / И. В. Гилев. – Воронеж, 2025. С. 324328.
"""
def _build(md_text: str) -> str:
"""Собрать документ и вернуть журнал xelatex."""
parser = Parser(md_text)
# Картинок в эталонном документе нет — копировать нужно только эмблему.
latex = Renderer(parser.tokens, parser.front_matter).render()
emblem = Path(md2gost.__file__).parent.parent / "emblem.png"
with tempfile.TemporaryDirectory(prefix="md2gost-layout-") as cache:
cache_dir = Path(cache)
tex = cache_dir / "doc.tex"
tex.write_text(latex, encoding="utf-8")
if emblem.is_file():
shutil.copy2(emblem, cache_dir / "emblem.png")
for _ in range(2):
subprocess.run(
["xelatex", "-interaction=nonstopmode", str(tex)],
cwd=cache_dir,
capture_output=True,
)
assert (cache_dir / "doc.pdf").is_file(), "xelatex не собрал PDF"
return (cache_dir / "doc.log").read_text(errors="replace")
def test_reference_document_has_no_layout_defects() -> None:
diags = parse_log(_build(FRONT_MATTER + BODY))
defects = [d for d in diags if d.kind in ("error", "overfull")]
assert not defects, "\n".join(f"{d.kind}: {d.message}" for d in defects)