"""Tests for `muse hooks install/uninstall/status` — musehub#192 Phase 2. Phase 1's `muse hooks list` is covered separately in tests/test_cmd_hooks.py. """ from __future__ import annotations import json import pathlib from tests.cli_test_helper import CliRunner runner = CliRunner() def _invoke(path: pathlib.Path, args: list[str]): import os saved = os.getcwd() try: os.chdir(path) return runner.invoke(None, args) finally: os.chdir(saved) def _init_repo(path: pathlib.Path, domain: str = "code") -> None: r = _invoke(path, ["init", "--domain", domain]) assert r.exit_code == 0, r.output def _write_hooks(path: pathlib.Path, content: str) -> None: (path / ".musehooks.toml").write_text(content, encoding="utf-8") class TestHooksInstall: def test_install_exits_0_and_marks_installed(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) _write_hooks(tmp_path, '[pre-commit]\ncommands = ["echo hi"]\n') r = _invoke(tmp_path, ["hooks", "install", "--json"]) assert r.exit_code == 0, r.output data = json.loads(r.output) assert data["installed"] is True status_r = _invoke(tmp_path, ["hooks", "status", "--json"]) assert json.loads(status_r.output)["state"] == "installed" def test_install_twice_is_still_success(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) _write_hooks(tmp_path, '[pre-commit]\ncommands = ["echo hi"]\n') assert _invoke(tmp_path, ["hooks", "install"]).exit_code == 0 assert _invoke(tmp_path, ["hooks", "install"]).exit_code == 0 def test_install_not_a_repo_exits_2(self, tmp_path: pathlib.Path) -> None: r = _invoke(tmp_path, ["hooks", "install", "--json"]) assert r.exit_code == 2 class TestHooksUninstall: def test_uninstall_exits_0_and_clears_state(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) _write_hooks(tmp_path, '[pre-commit]\ncommands = ["echo hi"]\n') _invoke(tmp_path, ["hooks", "install"]) r = _invoke(tmp_path, ["hooks", "uninstall", "--json"]) assert r.exit_code == 0, r.output data = json.loads(r.output) assert data["installed"] is False status_r = _invoke(tmp_path, ["hooks", "status", "--json"]) assert json.loads(status_r.output)["state"] == "defined_not_installed" def test_uninstall_when_never_installed_is_still_success(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) r = _invoke(tmp_path, ["hooks", "uninstall", "--json"]) assert r.exit_code == 0, r.output class TestHooksStatus: def test_not_defined_state(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) r = _invoke(tmp_path, ["hooks", "status", "--json"]) assert r.exit_code == 0, r.output assert json.loads(r.output)["state"] == "not_defined" def test_defined_not_installed_state(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) _write_hooks(tmp_path, '[pre-commit]\ncommands = ["echo hi"]\n') r = _invoke(tmp_path, ["hooks", "status", "--json"]) assert json.loads(r.output)["state"] == "defined_not_installed" def test_text_mode_mentions_install_command_when_not_installed(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) _write_hooks(tmp_path, '[pre-commit]\ncommands = ["echo hi"]\n') r = _invoke(tmp_path, ["hooks", "status"]) assert r.exit_code == 0, r.output assert "muse hooks install" in r.output def test_malformed_toml_exits_1(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) _write_hooks(tmp_path, "[pre-commit\ncommands = [") r = _invoke(tmp_path, ["hooks", "status", "--json"]) assert r.exit_code == 1 def test_status_not_a_repo_exits_2(self, tmp_path: pathlib.Path) -> None: r = _invoke(tmp_path, ["hooks", "status", "--json"]) assert r.exit_code == 2