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.public_export import ( ManifestSource, build_public_catalog, catalog_matches_sources, documentation_coverage_markdown, write_public_catalog, ) class PublicDocumentationExportTests(unittest.TestCase): 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"}, translations={ "de": { "title": "Beispiel verwenden", "summary": "Den Beispielablauf durchführen.", "body": "Öffnen und abschließen.", } }, ), ), ) 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({}, topic["content"]) 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"]) if __name__ == "__main__": unittest.main()