+151
-53
@@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import json
|
||||
import pytest
|
||||
|
||||
from md2gost.diagram_includes import (
|
||||
@@ -25,8 +26,12 @@ from md2gost.diagram_renderer import (
|
||||
from md2gost.diagram_schemes import (
|
||||
DiagramScheme,
|
||||
apply_scheme,
|
||||
bundled_schemes_path,
|
||||
claim_user_scheme_if_diverged,
|
||||
configure_schemes,
|
||||
ensure_user_schemes,
|
||||
load_schemes_from_path,
|
||||
migrate_user_schemes,
|
||||
prepare_with_schemes,
|
||||
scheme_id_from_lang,
|
||||
user_schemes_path,
|
||||
@@ -83,35 +88,21 @@ def test_unknown_scheme_raises(tmp_path, monkeypatch):
|
||||
prepare_with_schemes("uml-nosuch", "A -> B", base=tmp_path)
|
||||
|
||||
|
||||
def test_bpmn_scheme_prepare(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
ensure_user_schemes(tmp_path)
|
||||
configure_schemes(base=tmp_path)
|
||||
assert is_diagram_lang("bpmn")
|
||||
assert is_diagram_lang("uml-bpmn")
|
||||
src, dtype = prepare_with_schemes("bpmn", "Start(s)\nEnd(e)\nFlow(s, e)", base=tmp_path)
|
||||
assert dtype == "plantuml"
|
||||
assert "Start(s)" in src
|
||||
assert "!include" in src
|
||||
assert "BPMN.puml" in src.replace("\\", "/")
|
||||
assert src.lower().count("@startuml") == 1
|
||||
|
||||
|
||||
def test_bundled_bpmn_survives_user_file_without_it(tmp_path, monkeypatch):
|
||||
def test_bundled_c4_survives_user_file_without_it(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
path = ensure_user_schemes(tmp_path)
|
||||
path.write_text('{"mine":{"title":"x","prefix":"","postfix":""}}\n', encoding="utf-8")
|
||||
configure_schemes(base=tmp_path)
|
||||
assert is_diagram_lang("mine")
|
||||
assert is_diagram_lang("bpmn")
|
||||
assert is_diagram_lang("c4")
|
||||
|
||||
|
||||
def test_scheme_id_from_lang():
|
||||
assert scheme_id_from_lang("uml") is None
|
||||
assert scheme_id_from_lang("uml-c4") == "c4"
|
||||
assert scheme_id_from_lang("c4") == "c4"
|
||||
assert scheme_id_from_lang("bpmn") == "bpmn"
|
||||
assert scheme_id_from_lang("uml-bpmn") == "bpmn"
|
||||
assert scheme_id_from_lang("usecase") == "usecase"
|
||||
assert scheme_id_from_lang("uml-usecase") == "usecase"
|
||||
|
||||
|
||||
def test_ensure_user_schemes_once(tmp_path):
|
||||
@@ -121,10 +112,129 @@ def test_ensure_user_schemes_once(tmp_path):
|
||||
path.write_text('{"mine":{"title":"x","prefix":"","postfix":""}}\n', encoding="utf-8")
|
||||
again = ensure_user_schemes(tmp_path)
|
||||
assert again == path
|
||||
assert "mine" in path.read_text(encoding="utf-8")
|
||||
text = path.read_text(encoding="utf-8")
|
||||
assert "mine" in text
|
||||
assert "c4" in text # migration re-adds bundled ids
|
||||
assert path == user_schemes_path(tmp_path)
|
||||
|
||||
|
||||
def test_migrate_removes_orphaned_builtin_and_adds_missing(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
path = user_schemes_path(tmp_path)
|
||||
path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"bpmn": {
|
||||
"title": "BPMN 2.0",
|
||||
"author": "md2gost",
|
||||
"prefix": "@startuml\n",
|
||||
"postfix": "\n@enduml",
|
||||
"includes": ["BPMN.puml"],
|
||||
},
|
||||
"mine": {"title": "x", "author": "", "prefix": "", "postfix": ""},
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
+ "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
result = migrate_user_schemes(tmp_path)
|
||||
assert result.written
|
||||
assert "bpmn" in result.removed
|
||||
assert "c4" in result.added
|
||||
schemes = load_schemes_from_path(path)
|
||||
assert "bpmn" not in schemes
|
||||
assert "mine" in schemes
|
||||
assert schemes["mine"].title == "x"
|
||||
bundled = load_schemes_from_path(bundled_schemes_path())
|
||||
for sid in bundled:
|
||||
assert sid in schemes
|
||||
|
||||
|
||||
def test_migrate_preserves_user_override_of_builtin(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
path = user_schemes_path(tmp_path)
|
||||
path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"c4": {
|
||||
"title": "My C4",
|
||||
"author": "",
|
||||
"docs": "custom docs",
|
||||
"prefix": "@startuml\n",
|
||||
"postfix": "\n@enduml",
|
||||
"includes": [],
|
||||
}
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
+ "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
result = migrate_user_schemes(tmp_path)
|
||||
schemes = load_schemes_from_path(path)
|
||||
assert schemes["c4"].docs == "custom docs"
|
||||
assert schemes["c4"].author == ""
|
||||
assert "c4" not in result.updated
|
||||
assert "usecase" in schemes # other bundled ids still added
|
||||
|
||||
|
||||
def test_migrate_updates_app_owned_builtin(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
path = user_schemes_path(tmp_path)
|
||||
path.write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"c4": {
|
||||
"title": "Old C4",
|
||||
"author": "md2gost",
|
||||
"version": "0.0.1",
|
||||
"docs": "stale",
|
||||
"prefix": "@startuml\n",
|
||||
"postfix": "\n@enduml",
|
||||
"includes": [],
|
||||
}
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
+ "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
result = migrate_user_schemes(tmp_path)
|
||||
assert "c4" in result.updated
|
||||
schemes = load_schemes_from_path(path)
|
||||
bundled = load_schemes_from_path(bundled_schemes_path())
|
||||
assert schemes["c4"].to_dict() == bundled["c4"].to_dict()
|
||||
|
||||
|
||||
def test_migrate_idempotent(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
ensure_user_schemes(tmp_path)
|
||||
path = user_schemes_path(tmp_path)
|
||||
before = path.read_text(encoding="utf-8")
|
||||
mtime1 = path.stat().st_mtime_ns
|
||||
result = migrate_user_schemes(tmp_path)
|
||||
assert not result.written
|
||||
assert not result.changed
|
||||
assert path.read_text(encoding="utf-8") == before
|
||||
assert path.stat().st_mtime_ns == mtime1
|
||||
|
||||
|
||||
def test_claim_user_scheme_if_diverged():
|
||||
bundled = load_schemes_from_path(bundled_schemes_path())
|
||||
stock = bundled["c4"]
|
||||
same = DiagramScheme.from_dict("c4", stock.to_dict())
|
||||
claimed_same = claim_user_scheme_if_diverged(same, bundled=bundled)
|
||||
assert claimed_same.author == "md2gost"
|
||||
edited = DiagramScheme.from_dict(
|
||||
"c4",
|
||||
{**stock.to_dict(), "docs": "my docs"},
|
||||
)
|
||||
claimed = claim_user_scheme_if_diverged(edited, bundled=bundled)
|
||||
assert claimed.author == ""
|
||||
assert claimed.docs == "my docs"
|
||||
|
||||
|
||||
def test_apply_scheme_no_double_start():
|
||||
scheme = DiagramScheme(
|
||||
id="t",
|
||||
@@ -137,6 +247,18 @@ def test_apply_scheme_no_double_start():
|
||||
assert "skinparam monochrome true" in out
|
||||
|
||||
|
||||
def test_archimate_scheme_includes_stdlib():
|
||||
bundled = load_schemes_from_path(bundled_schemes_path())
|
||||
scheme = bundled["archimate"]
|
||||
assert scheme.title == "ArchiMate 3.2"
|
||||
out = apply_scheme(scheme, 'Business_Actor(a, "X")\n')
|
||||
assert "!include <archimate/Archimate>" in out
|
||||
assert "Business_Actor(a, \"X\")" in out
|
||||
assert out.strip().lower().startswith("@startuml")
|
||||
assert "@enduml" in out.lower()
|
||||
assert out.lower().count("@startuml") == 1
|
||||
|
||||
|
||||
def test_include_cache_index_no_overwrite(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
calls = []
|
||||
@@ -455,39 +577,15 @@ def test_diagram_engine_status_mentions_java_or_kroki():
|
||||
def test_diagram_langs():
|
||||
assert "uml" in DIAGRAM_LANGS
|
||||
assert "c4" in DIAGRAM_LANGS
|
||||
assert "bpmn" in DIAGRAM_LANGS
|
||||
assert "usecase" in DIAGRAM_LANGS
|
||||
assert "idef0" in DIAGRAM_LANGS
|
||||
assert "dfd" in DIAGRAM_LANGS
|
||||
assert is_diagram_lang("uml")
|
||||
assert is_diagram_lang("uml-c4")
|
||||
assert is_diagram_lang("uml-bpmn")
|
||||
|
||||
|
||||
def test_render_bpmn_with_jar(tmp_path, monkeypatch):
|
||||
import shutil
|
||||
|
||||
monkeypatch.chdir(tmp_path)
|
||||
ensure_user_schemes(tmp_path)
|
||||
configure_schemes(base=tmp_path)
|
||||
jar = resolve_plantuml_jar(download=False)
|
||||
if not shutil.which("java") or not jar:
|
||||
pytest.skip("нужны Java и plantuml.jar")
|
||||
configure_diagrams(fallback="off", cache_dir=str(tmp_path), plantuml_jar=jar)
|
||||
body = "\n".join(
|
||||
[
|
||||
"Start(s)",
|
||||
"StartMessage(sm, \"msg\")",
|
||||
"UserTask(t, \"Шаг\")",
|
||||
"XOR(gw)",
|
||||
"AND(p)",
|
||||
"OR(o)",
|
||||
"End(e)",
|
||||
"EndTerminate(et)",
|
||||
"Flow(s, t)",
|
||||
"Flow(t, gw)",
|
||||
"CondFlow(gw, e, \"да\")",
|
||||
"DefaultFlow(gw, et)",
|
||||
]
|
||||
)
|
||||
result = render_diagram("bpmn", body, cache_dir=str(tmp_path), fallback="off")
|
||||
data = Path(result.png_path).read_bytes()
|
||||
assert data.startswith(b"\x89PNG")
|
||||
assert len(data) > 500
|
||||
assert is_diagram_lang("uml-usecase")
|
||||
assert is_diagram_lang("idef0")
|
||||
assert is_diagram_lang("uml-idef0")
|
||||
assert is_diagram_lang("dfd")
|
||||
assert is_diagram_lang("uml-dfd")
|
||||
assert is_diagram_lang("data-flow-diagram")
|
||||
assert is_diagram_lang("yourdon")
|
||||
|
||||
Reference in New Issue
Block a user