import os import sys import tempfile import unittest from pathlib import Path ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) sys.path.insert(0, ROOT) from generate_handbook import generate_markdown_handbook def write_text(path: Path, content: str) -> None: path.parent.mkdir(parents=True, exist_ok=True) path.write_text(content, encoding="utf-8") class GenerateHandbookTest(unittest.TestCase): def test_generates_markdown_without_removing_images(self): with tempfile.TemporaryDirectory() as temp_dir: root = Path(temp_dir) src_root = root / "components" docs_root = root / "docs" / "source" / "mxpic" / "components" write_text( src_root / "primitives" / "pic" / "device.py", ''' class ExistingImage: """A class with a matching generated picture.""" class MissingImage: """A class without a picture.""" class ExistingImage: """A duplicate class name that should be documented once.""" def public_function(): """A public function.""" def public_function(): """A duplicate function name that should be documented once.""" def _hidden_function(): """A private function.""" ''', ) write_text(src_root / "basic.py", "CONSTANT = 1\n") write_text(src_root / "primitives" / "__init__.py", "") image_path = docs_root / "primitives" / "pic" / "ExistingImage.png" image_path.parent.mkdir(parents=True, exist_ok=True) image_path.write_bytes(b"fake png") write_text(docs_root / "old" / "stale.md", "# Stale\n") modules = generate_markdown_handbook( src_root=src_root, docs_root=docs_root, package_root="fake.components", ) self.assertEqual(len(modules), 2) self.assertTrue(image_path.exists()) self.assertFalse((docs_root / "old" / "stale.md").exists()) device_page = (docs_root / "primitives" / "pic" / "device.md").read_text( encoding="utf-8" ) self.assertIn("# fake.components.primitives.pic.device", device_page) self.assertIn(".. autoclass:: fake.components.primitives.pic.device.ExistingImage", device_page) self.assertEqual( device_page.count(".. autoclass:: fake.components.primitives.pic.device.ExistingImage"), 1, ) self.assertIn(".. image:: ExistingImage.png", device_page) self.assertIn(".. autoclass:: fake.components.primitives.pic.device.MissingImage", device_page) self.assertNotIn(".. image:: MissingImage.png", device_page) self.assertIn(".. autofunction:: fake.components.primitives.pic.device.public_function", device_page) self.assertEqual( device_page.count(".. autofunction:: fake.components.primitives.pic.device.public_function"), 1, ) self.assertNotIn("_hidden_function", device_page) basic_page = (docs_root / "basic.md").read_text(encoding="utf-8") self.assertIn(".. automodule:: fake.components.basic", basic_page) def test_recursive_indexes_point_to_existing_generated_pages(self): with tempfile.TemporaryDirectory() as temp_dir: root = Path(temp_dir) src_root = root / "components" docs_root = root / "docs" / "source" / "mxpic" / "components" write_text(src_root / "basic.py", "def make_basic():\n return None\n") write_text(src_root / "primitives" / "pic" / "device.py", "class Device:\n pass\n") generate_markdown_handbook( src_root=src_root, docs_root=docs_root, package_root="fake.components", ) root_index = (docs_root / "index.md").read_text(encoding="utf-8") primitives_index = (docs_root / "primitives" / "index.md").read_text( encoding="utf-8" ) pic_index = (docs_root / "primitives" / "pic" / "index.md").read_text( encoding="utf-8" ) self.assertIn("basic", root_index) self.assertIn("primitives/index", root_index) self.assertIn("pic/index", primitives_index) self.assertIn("device", pic_index) self.assert_toctree_entries_exist(docs_root) def assert_toctree_entries_exist(self, docs_root: Path) -> None: for index_path in docs_root.rglob("index.md"): for line in index_path.read_text(encoding="utf-8").splitlines(): entry = line.strip() if not entry or entry.startswith(("#", ":", "```")): continue target = index_path.parent / f"{entry}.md" self.assertTrue(target.exists(), f"{index_path} points to missing {target}") if __name__ == "__main__": unittest.main()