from __future__ import annotations import json import tempfile import unittest from pathlib import Path from tools.check_documentation import ( DocumentationPolicy, check_documentation, ) class DocumentationCheckTests(unittest.TestCase): def repository(self, parent: Path) -> Path: root = parent / "repository" (root / "docs").mkdir(parents=True) (root / "schemas").mkdir() (root / "schemas" / "reference-adapter.schema.json").write_text( json.dumps( { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "additionalProperties": False, "required": [ "schema_version", "project_id", "title", "language", "source_roots", ], "properties": { "schema_version": {"const": 1}, "project_id": {"type": "string"}, "title": {"type": "string"}, "language": {"enum": ["python", "javascript", "typescript", "cpp"]}, "source_roots": { "type": "array", "minItems": 1, "items": {"type": "string"}, }, "compilation_database": {"type": "string"}, }, } ), encoding="utf-8", ) return root def test_linked_pages_h1_anchors_and_reference_example_pass(self) -> None: with tempfile.TemporaryDirectory() as directory: root = self.repository(Path(directory)) (root / "README.md").write_text( "# Project\n\n[Guide](docs/GUIDE.md#reference-adapter-configuration)\n", encoding="utf-8", ) (root / "docs" / "GUIDE.md").write_text( "\n".join( ( "# Guide", "", "## Reference adapter configuration", "", "`.docforge/reference-adapter.toml`:", "", "```toml", "schema_version = 1", 'project_id = "fixture"', 'title = "Fixture"', 'language = "python"', 'source_roots = ["src"]', "```", "", ) ), encoding="utf-8", ) report = check_documentation( root, policy=DocumentationPolicy( required_pages=(Path("README.md"), Path("docs/GUIDE.md")), pending_inventory=None, ), ) self.assertTrue(report.ok, [item.render() for item in report.diagnostics]) self.assertEqual(2, report.markdown_pages) self.assertEqual(1, report.reference_adapter_examples) def test_missing_anchor_orphan_and_duplicate_h1_fail_deterministically(self) -> None: with tempfile.TemporaryDirectory() as directory: root = self.repository(Path(directory)) (root / "README.md").write_text( "# Project\n\n[Broken](docs/GUIDE.md#missing)\n", encoding="utf-8", ) (root / "docs" / "GUIDE.md").write_text( "# Guide\n\n# Duplicate\n", encoding="utf-8", ) (root / "docs" / "ORPHAN.md").write_text("# Orphan\n", encoding="utf-8") report = check_documentation( root, policy=DocumentationPolicy( required_pages=(Path("README.md"), Path("docs/GUIDE.md")), pending_inventory=None, ), ) self.assertFalse(report.ok) codes = [item.code for item in report.diagnostics] self.assertEqual(["DOC016", "DOC017", "DOC023"], sorted(codes)) def test_pending_inventory_allows_absence_but_rejects_existing_page(self) -> None: with tempfile.TemporaryDirectory() as directory: root = self.repository(Path(directory)) (root / "README.md").write_text("# Project\n", encoding="utf-8") pending_path = root / "pending.txt" pending_path.write_text("docs/FUTURE.md\n", encoding="utf-8") policy = DocumentationPolicy( required_pages=(Path("README.md"), Path("docs/FUTURE.md")), pending_inventory=Path("pending.txt"), ) missing = check_documentation(root, policy=policy) self.assertTrue(missing.ok) self.assertEqual(1, missing.pending_pages) (root / "docs" / "FUTURE.md").write_text("# Future\n", encoding="utf-8") stale = check_documentation(root, policy=policy) self.assertEqual(["DOC014", "DOC023"], [item.code for item in stale.diagnostics]) def test_invalid_reference_example_reports_schema_path(self) -> None: with tempfile.TemporaryDirectory() as directory: root = self.repository(Path(directory)) (root / "README.md").write_text( "# Project\n\n[Guide](docs/GUIDE.md)\n", encoding="utf-8", ) (root / "docs" / "GUIDE.md").write_text( "\n".join( ( "# Guide", "", "Reference adapter configuration:", "", "```toml", 'language = "python"', 'source_roots = ["src"]', "```", "", ) ), encoding="utf-8", ) report = check_documentation( root, policy=DocumentationPolicy( required_pages=(Path("README.md"), Path("docs/GUIDE.md")), pending_inventory=None, ), ) schema_errors = [item for item in report.diagnostics if item.code == "DOC026"] self.assertEqual(3, len(schema_errors)) messages = " ".join(item.message for item in schema_errors) self.assertIn("schema_version", messages) self.assertIn("project_id", messages) self.assertIn("title", messages) if __name__ == "__main__": unittest.main()