292 lines
8.9 KiB
Python
292 lines
8.9 KiB
Python
"""Tests for title page generation (```title, info_conv.yaml, template fill)."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from pathlib import Path
|
||
|
||
from docx import Document
|
||
|
||
from md2gost.title_page import (
|
||
TitleMeta,
|
||
build_title_docx,
|
||
load_info_conv,
|
||
merge_title_meta,
|
||
parse_and_strip_title_fence,
|
||
parse_kv_text,
|
||
should_generate_title,
|
||
)
|
||
from md2gost.user_profile import UserProfile, load_user_profile, save_user_profile
|
||
|
||
|
||
def test_parse_title_fence_and_strip():
|
||
md = (
|
||
"```title\n"
|
||
"number: 3\n"
|
||
"year: 2025\n"
|
||
"discipline: Тестовая дисциплина\n"
|
||
"```\n"
|
||
"\n"
|
||
"# *ВВЕДЕНИЕ\n"
|
||
"\n"
|
||
"Text.\n"
|
||
)
|
||
fields, body = parse_and_strip_title_fence(md)
|
||
assert fields["number"] == "3"
|
||
assert fields["year"] == "2025"
|
||
assert fields["discipline"] == "Тестовая дисциплина"
|
||
assert "# *ВВЕДЕНИЕ" in body
|
||
assert "```title" not in body
|
||
|
||
|
||
def test_parse_kv_russian_aliases_and_typos():
|
||
raw = (
|
||
"Инститиут: ИИТ\n"
|
||
"Кафедра: ЦТ\n"
|
||
"Дисциплина: ПАЦО\n"
|
||
"Преподователь: Иванов И. И.\n"
|
||
"Должность: старший преподаватель\n"
|
||
)
|
||
y = parse_kv_text(raw)
|
||
assert y["institute"] == "ИИТ"
|
||
assert y["department"] == "ЦТ"
|
||
assert y["discipline"] == "ПАЦО"
|
||
assert y["teacher"] == "Иванов И. И."
|
||
assert y["teacher_position"] == "старший преподаватель"
|
||
|
||
|
||
def test_merge_fence_overrides_yaml():
|
||
yaml_f = {"institute": "ИИТ", "discipline": "Из yaml"}
|
||
fence = {"discipline": "Из fence", "number": "2"}
|
||
meta = merge_title_meta(
|
||
yaml_fields=yaml_f,
|
||
fence_fields=fence,
|
||
student="Петров П. П.",
|
||
group="ИНБО-01-20",
|
||
)
|
||
assert meta.institute == "ИИТ"
|
||
assert meta.discipline == "Из fence"
|
||
assert meta.number == "2"
|
||
assert meta.student == "Петров П. П."
|
||
assert meta.group == "ИНБО-01-20"
|
||
# student/group ignored from yaml/fence
|
||
meta2 = merge_title_meta(
|
||
yaml_fields={"student": "X", "group": "Y", "institute": "Z"},
|
||
student="A",
|
||
group="B",
|
||
)
|
||
assert meta2.student == "A" and meta2.group == "B"
|
||
assert meta2.institute == "Z"
|
||
|
||
|
||
def test_load_info_conv(tmp_path: Path):
|
||
p = tmp_path / "info_conv.yaml"
|
||
p.write_text(
|
||
"Институт: Институт информационных технологий (ИИТ)\n"
|
||
"Кафедра: Кафедра ЦТ\n"
|
||
"Преподаватель: Сидоров\n"
|
||
"Должность: ассистент\n",
|
||
encoding="utf-8",
|
||
)
|
||
data = load_info_conv(tmp_path)
|
||
assert "ИИТ" in data["institute"]
|
||
assert data["teacher"] == "Сидоров"
|
||
|
||
|
||
def test_should_generate_title(tmp_path: Path):
|
||
assert should_generate_title(
|
||
explicit_title="ready.docx",
|
||
fence_fields={"number": "1"},
|
||
md_dir=tmp_path,
|
||
enabled=True,
|
||
) is False
|
||
assert should_generate_title(
|
||
explicit_title=None,
|
||
fence_fields={"number": "1"},
|
||
md_dir=tmp_path,
|
||
enabled=False,
|
||
) is False
|
||
assert should_generate_title(
|
||
explicit_title=None,
|
||
fence_fields={"number": "1"},
|
||
md_dir=tmp_path,
|
||
enabled=True,
|
||
) is True
|
||
assert should_generate_title(
|
||
explicit_title=None,
|
||
fence_fields={},
|
||
md_dir=tmp_path,
|
||
enabled=True,
|
||
) is False
|
||
(tmp_path / "info_conv.yaml").write_text("Институт: X\n", encoding="utf-8")
|
||
assert should_generate_title(
|
||
explicit_title=None,
|
||
fence_fields={},
|
||
md_dir=tmp_path,
|
||
enabled=True,
|
||
) is True
|
||
assert should_generate_title(
|
||
explicit_title=None,
|
||
fence_fields={},
|
||
md_dir=tmp_path,
|
||
enabled=False,
|
||
) is False
|
||
|
||
|
||
def test_user_profile_roundtrip(tmp_path: Path):
|
||
save_user_profile(UserProfile(student="А А А", group="ГР-1"), base=tmp_path)
|
||
loaded = load_user_profile(base=tmp_path)
|
||
assert loaded.student == "А А А"
|
||
assert loaded.group == "ГР-1"
|
||
assert loaded.is_complete()
|
||
|
||
|
||
def test_build_title_docx_fills_red_slots(tmp_path: Path):
|
||
meta = TitleMeta(
|
||
institute="Институт ИИТ",
|
||
department="Кафедра ЦТ",
|
||
discipline="Дисциплина X",
|
||
number="7",
|
||
group="ИНБО-99-99",
|
||
student="Тестов Тест Тестович",
|
||
teacher_position="доцент, кафедра ЦТ",
|
||
teacher="Преподов П. П.",
|
||
year="2024",
|
||
)
|
||
out = tmp_path / "title.docx"
|
||
build_title_docx(meta, out)
|
||
doc = Document(str(out))
|
||
texts = [p.text for p in doc.paragraphs]
|
||
assert "Институт ИИТ" in texts[0]
|
||
assert "Кафедра ЦТ" in texts[1]
|
||
assert "Дисциплина X" in texts[5]
|
||
assert "7" in texts[8]
|
||
assert "ИНБО-99-99" in texts[13]
|
||
assert "Тестов Тест Тестович" in texts[15]
|
||
assert "доцент" in texts[19]
|
||
assert "Преподов" in texts[21]
|
||
assert "2024" in texts[28]
|
||
# prefixes kept
|
||
assert texts[13].startswith("студент группы")
|
||
assert "по дисциплине" in texts[5]
|
||
assert "Москва" in texts[28]
|
||
|
||
|
||
def test_pipeline_generates_title(tmp_path: Path, monkeypatch):
|
||
from md2gost.pipeline import ConvertRequest, convert
|
||
from md2gost import user_profile as up
|
||
|
||
monkeypatch.setattr(up, "app_dir", lambda: tmp_path)
|
||
save_user_profile(
|
||
UserProfile(student="Конвейев К. К.", group="ИНБО-00-00"),
|
||
base=tmp_path,
|
||
)
|
||
(tmp_path / "info_conv.yaml").write_text(
|
||
"Институт: ИИТ тест\n"
|
||
"Кафедра: Каф тест\n"
|
||
"Дисциплина: Дисц тест\n"
|
||
"Преподаватель: Преп П. П.\n"
|
||
"Должность: ст. преподаватель\n",
|
||
encoding="utf-8",
|
||
)
|
||
md = tmp_path / "report.md"
|
||
md.write_text(
|
||
"```title\n"
|
||
"number: 2\n"
|
||
"year: 2026\n"
|
||
"```\n"
|
||
"\n"
|
||
"# *СОДЕРЖАНИЕ\n"
|
||
"\n"
|
||
"[TOC]\n"
|
||
"\n"
|
||
"# *ВВЕДЕНИЕ\n"
|
||
"\n"
|
||
"Текст введения.\n"
|
||
"\n"
|
||
"# *ЗАКЛЮЧЕНИЕ\n"
|
||
"\n"
|
||
"Вывод.\n"
|
||
"\n"
|
||
"# *СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ\n"
|
||
"\n"
|
||
"[1]: Книга. — М., 2024.\n",
|
||
encoding="utf-8",
|
||
)
|
||
out = tmp_path / "report.docx"
|
||
result = convert(
|
||
ConvertRequest(
|
||
filename=str(md),
|
||
output=str(out),
|
||
table_continuation="off",
|
||
listing_continuation="off",
|
||
auto_title=True,
|
||
open_when_done=False,
|
||
),
|
||
log=lambda _m: None,
|
||
)
|
||
assert result.ok, result.message
|
||
assert out.is_file()
|
||
doc = Document(str(out))
|
||
blob = "\n".join(p.text for p in doc.paragraphs)
|
||
assert "Конвейев" in blob
|
||
assert "ИНБО-00-00" in blob
|
||
assert "ИИТ тест" in blob
|
||
assert "Дисц тест" in blob
|
||
assert "Преп П. П." in blob
|
||
|
||
|
||
def test_pipeline_skips_title_by_default(tmp_path: Path, monkeypatch):
|
||
from md2gost.pipeline import ConvertRequest, convert
|
||
from md2gost import user_profile as up
|
||
|
||
monkeypatch.setattr(up, "app_dir", lambda: tmp_path)
|
||
save_user_profile(
|
||
UserProfile(student="Конвейев К. К.", group="ИНБО-00-00"),
|
||
base=tmp_path,
|
||
)
|
||
(tmp_path / "info_conv.yaml").write_text(
|
||
"Институт: ИИТ тест\n"
|
||
"Кафедра: Каф тест\n"
|
||
"Дисциплина: Дисц тест\n"
|
||
"Преподаватель: Преп П. П.\n"
|
||
"Должность: ст. преподаватель\n",
|
||
encoding="utf-8",
|
||
)
|
||
md = tmp_path / "report.md"
|
||
md.write_text(
|
||
"```title\n"
|
||
"number: 2\n"
|
||
"year: 2026\n"
|
||
"```\n"
|
||
"\n"
|
||
"# *ВВЕДЕНИЕ\n"
|
||
"\n"
|
||
"Текст введения.\n"
|
||
"\n"
|
||
"# *ЗАКЛЮЧЕНИЕ\n"
|
||
"\n"
|
||
"Вывод.\n"
|
||
"\n"
|
||
"# *СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ\n"
|
||
"\n"
|
||
"[1]: Книга. — М., 2024.\n",
|
||
encoding="utf-8",
|
||
)
|
||
out = tmp_path / "report.docx"
|
||
result = convert(
|
||
ConvertRequest(
|
||
filename=str(md),
|
||
output=str(out),
|
||
table_continuation="off",
|
||
listing_continuation="off",
|
||
open_when_done=False,
|
||
),
|
||
log=lambda _m: None,
|
||
)
|
||
assert result.ok, result.message
|
||
doc = Document(str(out))
|
||
blob = "\n".join(p.text for p in doc.paragraphs)
|
||
assert "Конвейев" not in blob
|
||
assert "ИИТ тест" not in blob
|
||
assert "Текст введения" in blob
|