[ADD] тест вёрстки: эталонный документ собирается без выходов за поле
This commit is contained in:
@@ -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. – С. 324–328.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
Reference in New Issue
Block a user