Files
govoplan-docs/tests/test_public_export.py
T

241 lines
9.3 KiB
Python

from __future__ import annotations
import json
import tempfile
import unittest
from pathlib import Path
from govoplan_core.core.modules import DocumentationTopic, ModuleManifest
from govoplan_docs.backend.manifest import get_manifest as get_docs_manifest
from govoplan_docs.public_export import (
ManifestSource,
build_public_catalog,
catalog_matches_sources,
coverage_baseline,
coverage_regression_issues,
documentation_coverage_markdown,
write_public_catalog,
)
class PublicDocumentationExportTests(unittest.TestCase):
def test_docs_manifest_has_complete_german_public_coverage(self) -> None:
module = build_public_catalog(
(ManifestSource(get_docs_manifest()),)
)["modules"][0]
self.assertEqual(9, module["coverage"]["topic_count"])
self.assertEqual(0, module["coverage"]["missing_german_topic_count"])
self.assertEqual([], module["coverage"]["missing_german_topic_ids"])
self.assertEqual(2, module["coverage"]["structured_localizable_topic_count"])
self.assertEqual(
2, module["coverage"]["german_structured_complete_topic_count"]
)
self.assertEqual(
[], module["coverage"]["missing_german_structured_topic_ids"]
)
self.assertEqual([], module["coverage"]["missing"])
def test_catalog_projects_localized_manifest_topics_and_gaps(self) -> None:
manifest = ModuleManifest(
id="example",
name="Example",
version="1.2.3",
documentation=(
DocumentationTopic(
id="example.workflow",
title="Use example",
summary="Perform the example workflow.",
body="Open and finish it.",
documentation_types=("user", "admin"),
metadata={
"kind": "workflow",
"steps": ["Review", "Execute"],
"verification": "Confirm completion.",
},
translations={
"de": {
"title": "Beispiel verwenden",
"summary": "Den Beispielablauf durchführen.",
"body": "Öffnen und abschließen.",
}
},
structured_translation_version="1",
structured_translations={
"de": {
"steps": ["Prüfen", "Ausführen"],
"verification": "Den Abschluss bestätigen.",
}
},
),
),
)
catalog = build_public_catalog(
(ManifestSource(manifest, "https://example.invalid/repository"),)
)
topic = catalog["modules"][0]["topics"][0]
self.assertEqual("Beispiel verwenden", topic["localizations"]["de"]["title"])
self.assertTrue(topic["localizations"]["de"]["complete"])
self.assertEqual("workflow", topic["kind"])
self.assertEqual(["Review", "Execute"], topic["content"]["steps"])
self.assertEqual(
["Prüfen", "Ausführen"],
topic["content_localizations"]["de"]["content"]["steps"],
)
self.assertTrue(topic["content_localizations"]["de"]["complete"])
self.assertIn(
"field/consequence reference",
catalog["modules"][0]["coverage"]["missing"],
)
def test_digest_check_ignores_generation_timestamp(self) -> None:
source = ManifestSource(
ModuleManifest(
id="example",
name="Example",
version="1.0.0",
documentation=(
DocumentationTopic(
id="example.reference",
title="Reference",
summary="Reference summary",
metadata={"kind": "reference"},
),
),
)
)
first = build_public_catalog((source,))
second = build_public_catalog((source,))
with tempfile.TemporaryDirectory() as directory:
output = Path(directory) / "catalog.json"
write_public_catalog(output, first)
self.assertTrue(catalog_matches_sources(output, second))
parsed = json.loads(output.read_text(encoding="utf-8"))
parsed["source_digest"] = "stale"
output.write_text(json.dumps(parsed), encoding="utf-8")
self.assertFalse(catalog_matches_sources(output, second))
def test_coverage_report_identifies_generated_source(self) -> None:
catalog = build_public_catalog(
(
ManifestSource(
ModuleManifest(
id="example",
name="Example",
version="1.0.0",
documentation=(),
)
),
)
)
report = documentation_coverage_markdown(catalog)
self.assertIn("Public documentation coverage", report)
self.assertIn("`example`", report)
self.assertIn("Edit module manifests", report)
def test_catalog_preserves_structured_static_documentation(self) -> None:
manifest = ModuleManifest(
id="example",
name="Example",
version="1.0.0",
documentation=(
DocumentationTopic(
id="example.workflow",
title="Run example",
summary="Run it safely.",
metadata={
"kind": "workflow",
"prerequisites": ["Approved input"],
"steps": ["Review", "Execute"],
"fields": [
{
"label": "Mode",
"user_description": "Selected behavior.",
}
],
},
),
),
)
topic = build_public_catalog((ManifestSource(manifest),))["modules"][0]["topics"][0]
self.assertEqual(["Review", "Execute"], topic["content"]["steps"])
self.assertEqual("Mode", topic["content"]["fields"][0]["label"])
def test_catalog_preserves_specialized_documentation_kinds(self) -> None:
manifest = ModuleManifest(
id="example",
name="Example",
version="1.0.0",
documentation=(
DocumentationTopic(
id="example.runbook",
title="Recover example",
summary="Restore the example safely.",
metadata={"kind": "operator_workflow"},
),
),
)
topic = build_public_catalog((ManifestSource(manifest),))["modules"][0]["topics"][0]
self.assertEqual("operator-workflow", topic["kind"])
def test_coverage_baseline_rejects_text_and_structured_regressions(self) -> None:
healthy = build_public_catalog(
(
ManifestSource(
ModuleManifest(
id="example",
name="Example",
version="1.0.0",
documentation=(
DocumentationTopic(
id="example.reference",
title="Reference",
summary="Reference summary.",
body="Reference body.",
translations={
"de": {
"title": "Referenz",
"summary": "Referenzzusammenfassung.",
"body": "Referenzinhalt.",
}
},
metadata={
"kind": "reference",
"limitations": ["Source limitation."],
},
structured_translation_version="1",
structured_translations={
"de": {
"limitations": [
"Einschränkung der Quelle."
]
}
},
),
),
)
),
)
)
baseline = coverage_baseline(healthy)
self.assertEqual((), coverage_regression_issues(healthy, baseline))
regressed = json.loads(json.dumps(healthy))
regressed["summary"]["german_complete_topic_count"] = 0
regressed["summary"]["german_structured_complete_topic_count"] = 0
issues = coverage_regression_issues(regressed, baseline)
self.assertTrue(any("german_complete_topic_count" in issue for issue in issues))
self.assertTrue(
any("german_structured_complete_topic_count" in issue for issue in issues)
)
if __name__ == "__main__":
unittest.main()