"""Tests for ``muse hooks`` CLI — musehub#192 Phase 1: HK_03 (`muse hooks list`). Phase 1 scope only: reads the tracked ``.musehooks.toml`` and prints its contents. No local activation state yet (Phase 2) and no ``muse commit`` integration yet (Phase 3). """ 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 TestHooksListNoFile: def test_no_musehooks_file_json_reports_empty(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) r = _invoke(tmp_path, ["hooks", "list", "--json"]) assert r.exit_code == 0, r.output data = json.loads(r.output) assert data["hooks"] == {} def test_no_musehooks_file_text_says_none_defined(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) r = _invoke(tmp_path, ["hooks", "list"]) assert r.exit_code == 0, r.output assert "no" in r.output.lower() or "none" in r.output.lower() class TestHooksListWithFile: def test_json_reports_pre_commit_commands(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) _write_hooks( tmp_path, '[pre-commit]\ncommands = ["muse agent-config status --json"]\n', ) r = _invoke(tmp_path, ["hooks", "list", "--json"]) assert r.exit_code == 0, r.output data = json.loads(r.output) assert data["hooks"]["pre-commit"] == ["muse agent-config status --json"] def test_text_mode_shows_hook_point_and_commands(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) _write_hooks( tmp_path, '[pre-commit]\ncommands = ["muse agent-config status --json"]\n', ) r = _invoke(tmp_path, ["hooks", "list"]) assert r.exit_code == 0, r.output assert "pre-commit" in r.output assert "muse agent-config status --json" in r.output class TestHooksListErrors: def test_malformed_toml_exits_1_with_clear_message(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) _write_hooks(tmp_path, "[pre-commit\ncommands = [") r = _invoke(tmp_path, ["hooks", "list", "--json"]) assert r.exit_code == 1 assert "parse error" in r.stderr.lower() def test_unknown_hook_point_exits_1_with_clear_message(self, tmp_path: pathlib.Path) -> None: _init_repo(tmp_path) _write_hooks(tmp_path, '[bogus-point]\ncommands = ["echo hi"]\n') r = _invoke(tmp_path, ["hooks", "list", "--json"]) assert r.exit_code == 1 assert "unknown hook point" in r.stderr.lower() def test_not_a_repo_exits_2(self, tmp_path: pathlib.Path) -> None: r = _invoke(tmp_path, ["hooks", "list", "--json"]) assert r.exit_code == 2