import importlib.util import sys import tempfile import unittest from pathlib import Path MODULE_PATH = ( Path(__file__).resolve().parents[1] / "src/simplecadapi/auto_tools/skill_pack.py" ) MODULE_SPEC = importlib.util.spec_from_file_location( "simplecadapi_skill_pack", MODULE_PATH, ) if MODULE_SPEC is None or MODULE_SPEC.loader is None: raise RuntimeError(f"Unable to load module spec for {MODULE_PATH}") skill_pack = importlib.util.module_from_spec(MODULE_SPEC) sys.modules[MODULE_SPEC.name] = skill_pack MODULE_SPEC.loader.exec_module(skill_pack) class TestSkillPackPathResolution(unittest.TestCase): def test_default_project_root_from_source_checkout(self): with tempfile.TemporaryDirectory() as tmp_dir: project_root = Path(tmp_dir) (project_root / "pyproject.toml").write_text( "[project]\nname = 'simplecadapi'\n", encoding="utf-8", ) package_root = project_root / "src/simplecadapi" module_file = package_root / "auto_tools/skill_pack.py" module_file.parent.mkdir(parents=True, exist_ok=True) module_file.write_text("", encoding="utf-8") resolved = skill_pack._default_project_root(module_file) self.assertEqual(resolved, project_root.resolve()) def test_default_project_root_from_site_packages_install(self): with tempfile.TemporaryDirectory() as tmp_dir: site_packages = Path(tmp_dir) / ".venv/lib/python3.12/site-packages" module_file = site_packages / "simplecadapi/auto_tools/skill_pack.py" module_file.parent.mkdir(parents=True, exist_ok=True) module_file.write_text("", encoding="utf-8") resolved = skill_pack._default_project_root(module_file) self.assertEqual(resolved, site_packages.resolve()) def test_default_output_root_from_source_checkout(self): with tempfile.TemporaryDirectory() as tmp_dir: project_root = Path(tmp_dir) (project_root / "pyproject.toml").write_text( "[project]\nname = 'simplecadapi'\n", encoding="utf-8", ) (project_root / "src/simplecadapi").mkdir(parents=True, exist_ok=True) resolved = skill_pack._default_output_root(project_root) self.assertEqual(resolved, (project_root / "skills").resolve()) def test_default_output_root_from_site_packages_install(self): with tempfile.TemporaryDirectory() as tmp_dir: tmp_path = Path(tmp_dir) site_packages = tmp_path / ".venv/lib/python3.12/site-packages" site_packages.mkdir(parents=True, exist_ok=True) workspace_root = tmp_path / "workspace" workspace_root.mkdir() resolved = skill_pack._default_output_root( site_packages, cwd=workspace_root, ) self.assertEqual(resolved, (workspace_root / "skills").resolve()) def test_build_from_site_packages_layout_uses_metadata_readme(self): with tempfile.TemporaryDirectory() as tmp_dir: tmp_path = Path(tmp_dir) site_packages = tmp_path / ".venv/lib/python3.12/site-packages" docs_api = site_packages / "docs/api" docs_core = site_packages / "docs/core" docs_stdlib = site_packages / "docs/stdlib" docs_api.mkdir(parents=True, exist_ok=True) docs_core.mkdir(parents=True, exist_ok=True) docs_stdlib.mkdir(parents=True, exist_ok=True) (docs_api / "README.md").write_text("# API Docs\n", encoding="utf-8") (docs_core / "README.md").write_text("# Core Docs\n", encoding="utf-8") (docs_stdlib / "README.md").write_text( "# Standard Library Docs\n", encoding="utf-8", ) dist_info = site_packages / "simplecadapi-2.0.2.dist-info" (dist_info / "licenses").mkdir(parents=True, exist_ok=True) (dist_info / "METADATA").write_text( "Metadata-Version: 2.1\n" "Name: simplecadapi\n" "Version: 2.0.2\n" "Summary: Demo package\n" "\n" "# Demo README\n" "\n" "Installed package readme body.\n", encoding="utf-8", ) (dist_info / "licenses/LICENSE").write_text( "MIT License\n", encoding="utf-8", ) output_root = tmp_path / "workspace/skills" packager = skill_pack.SkillPackager( project_root=site_packages, output_root=output_root, skill_name="simplecadapi", license_name="MIT", package_name="simplecadapi", package_version="2.0.2", refresh_docs=True, quiet=True, ) result = packager.build() self.assertTrue((result.skill_root / "SKILL.md").exists()) self.assertTrue( (result.skill_root / "references/docs/api/README.md").exists() ) self.assertTrue( (result.skill_root / "references/docs/stdlib/README.md").exists() ) package_summary = ( result.skill_root / "references/SDK_PACKAGE_SUMMARY.md" ).read_text(encoding="utf-8") self.assertIn("# SDK Package Summary", package_summary) self.assertIn("Installed package readme body.", package_summary) self.assertIn("references/docs/stdlib/README.md", package_summary) self.assertEqual( (result.skill_root / "references/LICENSE.txt").read_text( encoding="utf-8" ), "MIT License\n", ) self.assertFalse((result.skill_root / "scripts").exists()) def test_build_skill_markdown_mentions_graph_and_model_workflow(self): with tempfile.TemporaryDirectory() as tmp_dir: tmp_path = Path(tmp_dir) project_root = tmp_path / "project" docs_api = project_root / "docs/api" docs_core = project_root / "docs/core" docs_stdlib = project_root / "docs/stdlib" docs_api.mkdir(parents=True, exist_ok=True) docs_core.mkdir(parents=True, exist_ok=True) docs_stdlib.mkdir(parents=True, exist_ok=True) (docs_api / "README.md").write_text("# API Docs\n", encoding="utf-8") (docs_core / "README.md").write_text("# Core Docs\n", encoding="utf-8") (docs_stdlib / "README.md").write_text( "# Standard Library Docs\n", encoding="utf-8", ) (project_root / "README.md").write_text("# Demo\n", encoding="utf-8") (project_root / "LICENSE").write_text("MIT\n", encoding="utf-8") (project_root / "pyproject.toml").write_text( "[project]\nname = 'simplecadapi'\nversion = '2.0.9'\ndescription = 'Demo package'\n", encoding="utf-8", ) (project_root / "src/simplecadapi").mkdir(parents=True, exist_ok=True) packager = skill_pack.SkillPackager( project_root=project_root, output_root=tmp_path / "skills", skill_name="simplecadapi", license_name="MIT", quiet=True, ) content = packager._build_skill_markdown() self.assertIn("GraphSession", content) self.assertIn("export_model_json", content) self.assertIn("replay_model_json", content) self.assertIn("Use the graph/model JSON workflow", content) self.assertIn("use keyword arguments", content) self.assertIn("do not use positional arguments", content) self.assertIn("Standard Parts Library", content) self.assertIn("references/docs/stdlib/README.md", content) self.assertIn("scad.std.gear", content) self.assertIn("scad.std.bearing", content) self.assertIn("Modeling Mental Model", content) self.assertIn("current modeling workflows", content) self.assertIn("SDK_OVERVIEW.md", content) self.assertIn("SDK_SURFACES.md", content) self.assertIn("MODELING_WORKFLOWS.md", content) self.assertIn("SDK_PACKAGE_SUMMARY.md", content) self.assertNotIn("scripts/", content) self.assertNotIn("v1", content.lower()) self.assertNotIn("v2", content.lower()) if __name__ == "__main__": unittest.main()