229 lines
7.7 KiB
Python
229 lines
7.7 KiB
Python
"""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 == "Тема профиля"
|