"""Tests for the bundled ``bug`` extension. Validates: - Bundled layout (manifest, README, three command files) - Catalog registration - Wheel/source-checkout resolution via ``_locate_bundled_extension`` - Install via ``ExtensionManager.install_from_directory`` copies the three command files and records them in the installed manifest (command registration with AI agents is exercised separately and not asserted here) """ from __future__ import annotations import json from pathlib import Path import yaml from specify_cli import _locate_bundled_extension PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent.parent EXT_DIR = PROJECT_ROOT / "extensions" / "bug" EXPECTED_COMMANDS = { "speckit.bug.assess", "speckit.bug.fix", "speckit.bug.test", } # ── Bundled extension layout ───────────────────────────────────────────────── class TestExtensionLayout: def test_extension_yml_exists(self): assert (EXT_DIR / "extension.yml").is_file() def test_extension_yml_has_required_fields(self): manifest = yaml.safe_load( (EXT_DIR / "extension.yml").read_text(encoding="utf-8") ) assert manifest["extension"]["id"] == "bug" assert manifest["extension"]["name"] == "Bug Triage Workflow" assert manifest["extension"]["author"] == "spec-kit-core" commands = {c["name"] for c in manifest["provides"]["commands"]} assert commands == EXPECTED_COMMANDS def test_readme_exists(self): readme = EXT_DIR / "README.md" assert readme.is_file() text = readme.read_text(encoding="utf-8") assert "Bug Triage Workflow Extension" in text def test_command_files_exist(self): for name in EXPECTED_COMMANDS: cmd = EXT_DIR / "commands" / f"{name}.md" assert cmd.is_file(), f"Missing command file: {cmd}" # ── Catalog registration ───────────────────────────────────────────────────── class TestCatalogEntry: def test_catalog_lists_bug_as_bundled(self): catalog = json.loads( (PROJECT_ROOT / "extensions" / "catalog.json").read_text(encoding="utf-8") ) entry = catalog["extensions"]["bug"] assert entry["bundled"] is True assert entry["id"] == "bug" assert entry["author"] == "spec-kit-core" # ── Bundle resolution ──────────────────────────────────────────────────────── class TestBundleResolution: def test_locate_bundled_extension_finds_bug(self): located = _locate_bundled_extension("bug") assert located is not None assert (located / "extension.yml").is_file() # ── Install ────────────────────────────────────────────────────────────────── class TestExtensionInstall: def test_install_from_directory(self, tmp_path: Path): from specify_cli.extensions import ExtensionManager (tmp_path / ".specify").mkdir() manager = ExtensionManager(tmp_path) manifest = manager.install_from_directory(EXT_DIR, "0.9.0", register_commands=False) assert manifest.id == "bug" assert manager.registry.is_installed("bug") # All three command files are copied into the installed extension dir installed = tmp_path / ".specify" / "extensions" / "bug" for name in EXPECTED_COMMANDS: assert (installed / "commands" / f"{name}.md").is_file() def test_install_command_names(self, tmp_path: Path): """The installed manifest exposes the expected command names.""" from specify_cli.extensions import ExtensionManager (tmp_path / ".specify").mkdir() manager = ExtensionManager(tmp_path) manifest = manager.install_from_directory(EXT_DIR, "0.9.0", register_commands=False) names = {c["name"] for c in manifest.commands} assert names == EXPECTED_COMMANDS