Files
marki-docx/tests/test_level3_plumbing.py
Bernd Worsch ac442ea41f feat: WP-0003 complete — LEVEL3 advanced features + error framework
Implements full LEVEL3 feature set: cross-references (xref.py), numbered
figures (figures.py), auto-diagrams (diagrams.py), bibliography/citations
(bibliography.py), LEVEL3 capability detection (level3.py), and structured
error/warning records (errors.py). Builder, importer, and differ updated for
LEVEL3 round-trip support. REST and MCP interfaces updated with structured
warning records. 259 tests passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 10:51:38 +00:00

272 lines
9.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Tests for LEVEL3 plumbing — feature-level gating & disclosure (FR-537539)."""
from __future__ import annotations
import textwrap
from pathlib import Path
from markidocx.level3 import (
Level3Support,
ProcessorDependency,
capabilities_entry,
check_level3_support,
)
from markidocx.manifest import FeatureLevel, load_manifest
# ---------------------------------------------------------------------------
# Level3 support detection (FR-537, FR-538)
# ---------------------------------------------------------------------------
class TestCheckLevel3Support:
def test_returns_level3_support(self) -> None:
support = check_level3_support()
assert isinstance(support, Level3Support)
def test_always_available(self) -> None:
support = check_level3_support()
assert support.available is True
def test_dependencies_are_processor_dependency_instances(self) -> None:
support = check_level3_support()
for dep in support.dependencies:
assert isinstance(dep, ProcessorDependency)
assert dep.name in ("mmdc", "dot", "plantuml")
assert isinstance(dep.available, bool)
assert dep.description
def test_partial_when_no_diagram_tools(self, monkeypatch) -> None:
"""When no diagram tool is found, partial=True and missing_coverage is populated."""
import shutil
monkeypatch.setattr(shutil, "which", lambda _cmd: None)
support = check_level3_support()
assert support.partial is True
assert len(support.missing_coverage) > 0
assert any("diagram" in m for m in support.missing_coverage)
def test_not_partial_when_diagram_tool_present(self, monkeypatch) -> None:
"""When at least one diagram tool is found, partial=False."""
import shutil
def fake_which(cmd: str) -> str | None:
return "/usr/bin/mmdc" if cmd == "mmdc" else None
monkeypatch.setattr(shutil, "which", fake_which)
support = check_level3_support()
assert support.partial is False
assert support.missing_coverage == []
# ---------------------------------------------------------------------------
# capabilities_entry (FR-537)
# ---------------------------------------------------------------------------
class TestCapabilitiesEntry:
def test_returns_dict_with_level(self) -> None:
entry = capabilities_entry()
assert entry["level"] == "level3"
def test_available_is_true(self) -> None:
entry = capabilities_entry()
assert entry["available"] is True
def test_has_dependencies_list(self) -> None:
entry = capabilities_entry()
assert isinstance(entry["dependencies"], list)
for dep in entry["dependencies"]:
assert "name" in dep
assert "available" in dep
assert "description" in dep
def test_has_partial_and_missing_coverage(self) -> None:
entry = capabilities_entry()
assert "partial" in entry
assert "missing_coverage" in entry
# ---------------------------------------------------------------------------
# Manifest accepts feature_level: level3 (FR-537)
# ---------------------------------------------------------------------------
class TestManifestLevel3:
def test_level3_accepted(self, tmp_path: Path) -> None:
(tmp_path / "doc.md").write_text("# Hello", encoding="utf-8")
(tmp_path / "manifest.yaml").write_text(
textwrap.dedent("""\
project:
name: test
feature_level: level3
family: article
sources:
- path: doc.md
output:
dir: ./dist
"""),
encoding="utf-8",
)
m = load_manifest(tmp_path / "manifest.yaml")
assert m.project.feature_level == FeatureLevel.LEVEL3
def test_level3_routes_to_level3_processing(self, tmp_path: Path) -> None:
"""Building with feature_level: level3 succeeds (processing path reached)."""
from markidocx.builder import build_document
(tmp_path / "doc.md").write_text("# Hello\n\nContent.", encoding="utf-8")
(tmp_path / "manifest.yaml").write_text(
textwrap.dedent("""\
project:
name: test-l3
feature_level: level3
family: article
sources:
- path: doc.md
output:
dir: ./dist
"""),
encoding="utf-8",
)
m = load_manifest(tmp_path / "manifest.yaml")
result = build_document(m)
assert result.success
assert result.feature_level == "level3"
# ---------------------------------------------------------------------------
# partial_level3 flag and processor-dependency disclosure (FR-538, FR-539)
# ---------------------------------------------------------------------------
class TestPartialLevel3Flag:
def test_partial_level3_set_when_no_diagram_tools(
self, tmp_path: Path, monkeypatch
) -> None:
import shutil
from markidocx.builder import build_document
monkeypatch.setattr(shutil, "which", lambda _cmd: None)
(tmp_path / "doc.md").write_text("# Hello\n\nContent.", encoding="utf-8")
(tmp_path / "manifest.yaml").write_text(
textwrap.dedent("""\
project:
name: test-partial
feature_level: level3
family: article
sources:
- path: doc.md
output:
dir: ./dist
"""),
encoding="utf-8",
)
m = load_manifest(tmp_path / "manifest.yaml")
result = build_document(m)
assert result.success
assert result.partial_level3 is True
assert len(result.missing_coverage) > 0
def test_partial_level3_false_for_level1(self, tmp_path: Path) -> None:
from markidocx.builder import build_document
(tmp_path / "doc.md").write_text("# Hello\n\nContent.", encoding="utf-8")
(tmp_path / "manifest.yaml").write_text(
textwrap.dedent("""\
project:
name: test-l1
feature_level: level1
family: article
sources:
- path: doc.md
output:
dir: ./dist
"""),
encoding="utf-8",
)
m = load_manifest(tmp_path / "manifest.yaml")
result = build_document(m)
assert result.partial_level3 is False
assert result.missing_coverage == []
def test_dependency_warning_emitted_for_unavailable_tool(
self, tmp_path: Path, monkeypatch
) -> None:
import shutil
from markidocx.builder import build_document
from markidocx.errors import Severity
monkeypatch.setattr(shutil, "which", lambda _cmd: None)
(tmp_path / "doc.md").write_text("# Hello", encoding="utf-8")
(tmp_path / "manifest.yaml").write_text(
textwrap.dedent("""\
project:
name: t
feature_level: level3
family: article
sources:
- path: doc.md
output:
dir: ./dist
"""),
encoding="utf-8",
)
m = load_manifest(tmp_path / "manifest.yaml")
result = build_document(m)
dep_warnings = [
w for w in result.warning_records
if w.reason == "processor-dependency-unavailable"
]
assert dep_warnings, "Expected processor-dependency-unavailable warning"
assert all(w.severity == Severity.WARNING for w in dep_warnings)
# ---------------------------------------------------------------------------
# REST capabilities includes level3 (FR-537)
# ---------------------------------------------------------------------------
class TestRestCapabilitiesLevel3:
def test_capabilities_includes_level3(self) -> None:
from fastapi.testclient import TestClient
from markidocx.rest import create_app
client = TestClient(create_app())
resp = client.get("/capabilities")
assert resp.status_code == 200
body = resp.json()
outputs = body["outputs"]
assert "level3" in outputs
assert outputs["level3"]["level"] == "level3"
assert outputs["level3"]["available"] is True
assert "dependencies" in outputs["level3"]
# ---------------------------------------------------------------------------
# MCP validate_project includes level3 in context (FR-537)
# ---------------------------------------------------------------------------
class TestMcpLevel3:
def test_validate_project_includes_level3(self) -> None:
from markidocx.mcp_server import validate_project
manifest_yaml = textwrap.dedent("""\
project:
name: test
feature_level: level3
family: article
sources:
- path: doc.md
output:
dir: ./dist
""")
result = validate_project(manifest_yaml)
assert result["status"] == "ok"
assert result["feature_level"] == "level3"
assert "level3" in result["context"]
assert result["context"]["level3"]["available"] is True