Files
md_to_gost/tests/test_pipeline.py
Igor20264 510f7e7adf
Python application / build (push) Waiting to run
v0.5.2
Что то сделал
2026-09-08 19:37:54 +03:00

248 lines
8.2 KiB
Python

"""CLI/GUI shared pipeline helpers."""
import os
import sys
from md2gost.dnd import first_markdown, normalize_drop_paths, parse_tkdnd_files
from md2gost.pipeline import (
ConvertRequest,
convert,
default_output_path,
should_launch_gui,
timestamped_output_path,
)
from md2gost.__main__ import build_parser, request_from_args
def test_should_launch_gui():
assert should_launch_gui(None, False) is True
assert should_launch_gui("", False) is True
assert should_launch_gui("a.md", True) is True
assert should_launch_gui("a.md", False) is False
def test_default_output_path():
path = default_output_path(r"C:\docs\report.md")
assert path.endswith("report.docx")
def test_timestamped_output_path(tmp_path):
import re
src = tmp_path / "ПР1.docx"
src.write_bytes(b"x")
out = timestamped_output_path(str(src))
name = os.path.basename(out)
assert re.fullmatch(r"ПР1_\d{4}-\d{2}-\d{2}-\d{2}-\d{2}\.docx", name)
assert not os.path.exists(out)
# collision → seconds (or seconds_2)
open(out, "wb").close()
out2 = timestamped_output_path(str(src))
assert out2 != out
assert os.path.basename(out2).startswith("ПР1_")
assert out2.endswith(".docx")
def test_parse_tkdnd_files():
raw = r"{C:\My Files\a.md} C:\tmp\b.md"
assert parse_tkdnd_files(raw) == [r"C:\My Files\a.md", r"C:\tmp\b.md"]
def test_normalize_and_first_markdown(tmp_path):
md = tmp_path / "note.md"
png = tmp_path / "pic.png"
md.write_text("# hi\n", encoding="utf-8")
png.write_text("x", encoding="utf-8")
paths = normalize_drop_paths([str(png), str(md)])
assert first_markdown(paths) == os.path.normpath(str(md))
def test_convert_rejects_non_md(tmp_path):
txt = tmp_path / "file.txt"
txt.write_text("nope", encoding="utf-8")
result = convert(ConvertRequest(filename=str(txt)))
assert result.ok is False
assert result.exit_code == 1
def test_convert_missing_file():
result = convert(ConvertRequest(filename="definitely-missing.md"))
assert result.ok is False
assert result.exit_code == 2
def test_parser_gui_and_optional_file():
parser = build_parser()
args = parser.parse_args(["--gui", "report.md", "--type", "PIS_custom"])
assert args.gui is True
assert args.filename == "report.md"
req = request_from_args(args)
assert req.doc_type == "PIS_custom"
assert req.filename == "report.md"
def test_win32_drop_api_pointer_width():
if sys.platform != "win32":
return
import ctypes
from md2gost.dnd import _win32_drop_api
api = _win32_drop_api()
assert api.CallWindowProc.argtypes[0] is ctypes.c_void_p
huge = (1 << 40) | 0x1234
api.CallWindowProc.argtypes[0](huge) # must not OverflowError
def test_win32_drop_hook_survives_window_messages():
if sys.platform != "win32":
return
import tkinter as tk
from md2gost.dnd import enable_file_drop
root = tk.Tk()
try:
root.geometry("240x160+40+40")
root.update()
kind = enable_file_drop(root, lambda _paths: None)
root.update()
root.event_generate("<Motion>", x=12, y=12)
root.update()
assert kind in {"win32", "tkdnd", "none"}
finally:
root.destroy()
def test_argv_needs_console():
from md2gost.__main__ import _argv_needs_console
assert _argv_needs_console(["md2gost"]) is False
assert _argv_needs_console(["md2gost", "--gui"]) is False
assert _argv_needs_console(["md2gost", "--help"]) is True
assert _argv_needs_console(["md2gost", "report.md"]) is True
assert _argv_needs_console(["md2gost", "--gui", "report.md"]) is False
def test_gui_module_imports():
from md2gost import gui
assert hasattr(gui, "run_gui")
assert hasattr(gui, "main")
def test_hr_pagebreak_becomes_page_break():
import os
import docx
from md2gost import package_dir
from md2gost.parser_ import Parser
from md2gost.renderable.page_break import PageBreak
doc = docx.Document(os.path.join(package_dir(), "Template.docx"))
doc._body.clear_content()
text = "До разрыва.\n\n---\n\nПосле разрыва.\n"
items = list(Parser(doc, text, hr_pagebreak=True).parse())
assert any(isinstance(x, PageBreak) for x in items)
doc2 = docx.Document(os.path.join(package_dir(), "Template.docx"))
doc2._body.clear_content()
items_off = list(Parser(doc2, text, hr_pagebreak=False).parse())
assert not any(isinstance(x, PageBreak) for x in items_off)
texts = []
for item in items_off:
para = getattr(item, "_docx_paragraph", None)
if para is not None:
texts.append(para.text)
assert not any("ThematicBreak" in t for t in texts)
def test_prompt_catalog_loads():
from md2gost.help_content import load_prompt_catalog
catalog = load_prompt_catalog()
names = {name for name, _title, text in catalog}
assert "generate-md.md" in names
assert "generate-mirea-report.md" in names
assert "generate-pis-custom-report.md" in names
assert "emulate-student.md" in names
assert all(text.strip() for _n, _t, text in catalog)
def test_compose_prompt_with_schemes():
from md2gost.diagram_schemes import DiagramScheme
from md2gost.help_content import compose_prompt, scheme_prompt_block
scheme = DiagramScheme(
id="c4",
title="C4 Container",
docs='Person(alias, "Label")',
ai_prompt="Рисуй C4. Блок ```uml-c4 без @startuml.",
)
block = scheme_prompt_block(scheme)
assert "uml-c4" in block
assert "```c4" in block or "```uml-c4" in block
assert "Рисуй C4" in block
assert "Person(alias" in block
base = "Базовый промпт про markdown.\n"
out = compose_prompt(base, [scheme])
assert out.startswith("Базовый промпт")
assert "Дополнение: выбранные схемы" in out
assert "uml-c4" in out
assert compose_prompt(base, []).strip() == base.strip()
assert compose_prompt(base, None).strip() == base.strip()
def test_docs_catalog_loads():
from md2gost.help_content import load_docs_catalog
catalog = load_docs_catalog()
assert catalog, "docs/ catalog should not be empty"
names = {name for name, _title, _text in catalog}
assert "README.md" in names
assert "markdown.md" in names
assert catalog[0][0].lower() == "readme.md"
assert "Документация" in catalog[0][1]
assert all(text.strip() for _n, _t, text in catalog)
def test_listing_continuation_mode():
import os
import docx
from md2gost import package_dir
from md2gost.profiles import DEFAULT_LISTING_CONTINUATION
from md2gost.renderable.caption import CaptionInfo
from md2gost.renderable.listing import Listing
doc = docx.Document(os.path.join(package_dir(), "Template.docx"))
doc._body.clear_content()
listing = Listing(doc._body, "python", CaptionInfo("c1", "Код"))
listing.set_text("print(1)\n")
assert listing._continuation_mode == DEFAULT_LISTING_CONTINUATION
listing.set_continuation_mode("caption")
assert listing._continuation_mode == "caption"
try:
listing.set_continuation_mode("nope")
raise AssertionError("expected ValueError")
except ValueError:
pass
def test_parser_listing_continuation_flag():
parser = build_parser()
args = parser.parse_args(["report.md", "--listing-continuation", "legacy"])
req = request_from_args(args)
assert req.listing_continuation == "legacy"
args2 = parser.parse_args(["report.md"])
assert request_from_args(args2).listing_continuation == "word"
def test_parser_hr_pagebreak_flag():
parser = build_parser()
args = parser.parse_args(["report.md", "--no-hr-pagebreak"])
req = request_from_args(args)
assert req.hr_pagebreak is False
args2 = parser.parse_args(["report.md"])
assert request_from_args(args2).hr_pagebreak is False
assert request_from_args(args2).doc_type == "practice"
args3 = parser.parse_args(["report.md", "--hr-pagebreak"])
assert request_from_args(args3).hr_pagebreak is True
def test_parser_no_file_is_ok():
parser = build_parser()
args = parser.parse_args([])
assert args.filename is None
assert args.gui is False