"""DOCX core properties: resolve, apply, persist in user profile.""" from __future__ import annotations from datetime import datetime from pathlib import Path from docx import Document from md2gost.doc_metadata import ( CORE_PROP_MAX, DEFAULT_AUTHOR_SOURCE, DEFAULT_DOC_COMMENTS, DocumentMetadata, apply_document_metadata, clip_core, resolve_document_metadata, ) from md2gost.pipeline import ConvertRequest, convert from md2gost.user_profile import UserProfile, load_user_profile, save_user_profile from md2gost.__main__ import build_parser, request_from_args def test_clip_core_limit(): assert clip_core("ab") == "ab" assert len(clip_core("x" * (CORE_PROP_MAX + 10))) == CORE_PROP_MAX def test_metadata_from_dict_defaults_and_empty_comments(): blank = DocumentMetadata.from_dict(None) assert blank.author_source == DEFAULT_AUTHOR_SOURCE assert blank.comments == DEFAULT_DOC_COMMENTS empty = DocumentMetadata.from_dict({"comments": "", "author_source": "nope"}) assert empty.comments == "" assert empty.author_source == DEFAULT_AUTHOR_SOURCE custom = DocumentMetadata.from_dict({"author_source": "student", "title": " Отчёт "}) assert custom.author_source == "student" assert custom.title == "Отчёт" def test_resolve_author_sources(monkeypatch): monkeypatch.setattr("md2gost.doc_metadata.os_user", lambda: "win-user") stored = DocumentMetadata(author_source="custom", author="Кастом К. К.") os_meta = resolve_document_metadata(stored=DocumentMetadata(author_source="os")) assert os_meta.author == "win-user" assert os_meta.last_modified_by == "win-user" assert os_meta.comments == DEFAULT_DOC_COMMENTS student_meta = resolve_document_metadata( stored=DocumentMetadata(author_source="student"), student="Студентов С. С.", ) assert student_meta.author == "Студентов С. С." custom_meta = resolve_document_metadata(stored=stored) assert custom_meta.author == "Кастом К. К." override = resolve_document_metadata( stored=stored, author="С CLI", comments="", title="Тема работы", last_modified_by="Редактор", ) assert override.author == "С CLI" assert override.comments == "" assert override.title == "Тема работы" assert override.last_modified_by == "Редактор" empty_custom = resolve_document_metadata( stored=DocumentMetadata(author_source="custom", author=""), ) assert empty_custom.author == "win-user" def test_apply_document_metadata_writes_core_props(tmp_path: Path): from md2gost import package_dir doc = Document(str(Path(package_dir()) / "Template.docx")) stamp = datetime(2026, 9, 8, 12, 0, 0) apply_document_metadata( doc, DocumentMetadata( author="Автор А. А.", last_modified_by="Автор А. А.", title="Название", subject="Тема", keywords="гост, отчёт", comments="", category="учебный", ), now=stamp, ) out = tmp_path / "meta.docx" doc.save(str(out)) loaded = Document(str(out)) cp = loaded.core_properties assert cp.author == "Автор А. А." assert cp.last_modified_by == "Автор А. А." assert cp.title == "Название" assert cp.subject == "Тема" assert cp.keywords == "гост, отчёт" assert cp.comments == "" assert cp.category == "учебный" assert cp.revision == 1 assert cp.created.replace(tzinfo=None) == stamp assert cp.modified.replace(tzinfo=None) == stamp def test_user_profile_preserves_metadata_when_saving_student(tmp_path: Path): save_user_profile( UserProfile( student="А А А", group="ГР-1", metadata=DocumentMetadata( author_source="student", title="Отчёт", comments="", ), ), base=tmp_path, ) loaded = load_user_profile(base=tmp_path) assert loaded.student == "А А А" assert loaded.metadata.author_source == "student" assert loaded.metadata.title == "Отчёт" assert loaded.metadata.comments == "" loaded.student = "Б Б Б" save_user_profile(loaded, base=tmp_path) again = load_user_profile(base=tmp_path) assert again.student == "Б Б Б" assert again.group == "ГР-1" assert again.metadata.title == "Отчёт" assert again.metadata.comments == "" def test_old_user_json_without_metadata_block(tmp_path: Path): path = tmp_path / "md2gost.user.json" path.write_text('{"student": "Иванов", "group": "ИНБО-01-00"}\n', encoding="utf-8") loaded = load_user_profile(base=tmp_path) assert loaded.student == "Иванов" assert loaded.metadata.comments == DEFAULT_DOC_COMMENTS assert loaded.metadata.author_source == DEFAULT_AUTHOR_SOURCE def test_parser_doc_metadata_flags(): parser = build_parser() args = parser.parse_args( [ "report.md", "--doc-author-from", "student", "--doc-author", "Петров П. П.", "--doc-title", "Курсовая", "--doc-comments", "", "--doc-keywords", "гост", ] ) req = request_from_args(args) assert req.doc_author_source == "student" assert req.doc_author == "Петров П. П." assert req.doc_title == "Курсовая" assert req.doc_comments == "" assert req.doc_keywords == "гост" default = request_from_args(parser.parse_args(["report.md"])) assert default.doc_author is None assert default.doc_comments is None def test_pipeline_applies_profile_and_cli_metadata(tmp_path: Path, monkeypatch): from md2gost import user_profile as up monkeypatch.setattr(up, "app_dir", lambda: tmp_path) save_user_profile( UserProfile( student="Конвейев К. К.", group="ИНБО-00-00", metadata=DocumentMetadata( author_source="student", title="Из профиля", subject="Тема профиля", comments="штамп", ), ), base=tmp_path, ) md = tmp_path / "report.md" md.write_text("# *ВВЕДЕНИЕ\n\nТекст.\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 cp = Document(str(out)).core_properties assert cp.author == "Конвейев К. К." assert cp.last_modified_by == "Конвейев К. К." assert cp.title == "Из профиля" assert cp.subject == "Тема профиля" assert cp.comments == "штамп" assert cp.revision == 1 out2 = tmp_path / "report2.docx" result2 = convert( ConvertRequest( filename=str(md), output=str(out2), table_continuation="off", listing_continuation="off", open_when_done=False, doc_author="С CLI", doc_comments="", doc_title="С CLI название", ), log=lambda _m: None, ) assert result2.ok, result2.message cp2 = Document(str(out2)).core_properties assert cp2.author == "С CLI" assert cp2.comments == "" assert cp2.title == "С CLI название" assert cp2.subject == "Тема профиля"