test_core_hooks_run.py
python
sha256:5f7b38765462d4b092afecab903684171b41c9e7aabc0f6515088d43c5e2cb4f
feat(#192): Phase 3 — muse commit runs installed pre-commit hooks
Sonnet 5
patch
3 days ago
| 1 | """Tests for muse/core/hooks.py::run_hook_point — musehub#192 Phase 3 core layer. |
| 2 | |
| 3 | Covers command execution semantics only. CLI-level `muse commit` integration |
| 4 | (--no-verify, warnings, exit codes) is covered in tests/test_cmd_commit_hooks.py. |
| 5 | """ |
| 6 | |
| 7 | import pathlib |
| 8 | |
| 9 | from muse.core.hooks import install_hooks, run_hook_point |
| 10 | |
| 11 | |
| 12 | def _write_hooks(tmp_path: pathlib.Path, content: str) -> None: |
| 13 | (tmp_path / ".musehooks.toml").write_text(content, encoding="utf-8") |
| 14 | |
| 15 | |
| 16 | class TestRunHookPointNotInstalled: |
| 17 | def test_not_installed_does_not_execute_anything(self, tmp_path: pathlib.Path) -> None: |
| 18 | _write_hooks( |
| 19 | tmp_path, |
| 20 | '[pre-commit]\ncommands = ["touch should-not-exist.txt"]\n', |
| 21 | ) |
| 22 | result = run_hook_point(tmp_path, "pre-commit") |
| 23 | assert result.executed is False |
| 24 | assert result.passed is True |
| 25 | assert not (tmp_path / "should-not-exist.txt").exists() |
| 26 | |
| 27 | def test_no_hooks_defined_at_all_is_a_pass(self, tmp_path: pathlib.Path) -> None: |
| 28 | install_hooks(tmp_path) # installed, but nothing declared |
| 29 | result = run_hook_point(tmp_path, "pre-commit") |
| 30 | assert result.executed is False |
| 31 | assert result.passed is True |
| 32 | |
| 33 | |
| 34 | class TestRunHookPointInstalled: |
| 35 | def test_passing_command_executes_and_passes(self, tmp_path: pathlib.Path) -> None: |
| 36 | _write_hooks( |
| 37 | tmp_path, |
| 38 | '[pre-commit]\ncommands = ["touch ran.txt"]\n', |
| 39 | ) |
| 40 | install_hooks(tmp_path) |
| 41 | result = run_hook_point(tmp_path, "pre-commit") |
| 42 | assert result.executed is True |
| 43 | assert result.passed is True |
| 44 | assert (tmp_path / "ran.txt").exists() |
| 45 | |
| 46 | def test_failing_command_stops_and_reports_it(self, tmp_path: pathlib.Path) -> None: |
| 47 | _write_hooks( |
| 48 | tmp_path, |
| 49 | '[pre-commit]\ncommands = ["exit 1"]\n', |
| 50 | ) |
| 51 | install_hooks(tmp_path) |
| 52 | result = run_hook_point(tmp_path, "pre-commit") |
| 53 | assert result.executed is True |
| 54 | assert result.passed is False |
| 55 | assert result.failed_command == "exit 1" |
| 56 | |
| 57 | def test_first_failure_stops_subsequent_commands(self, tmp_path: pathlib.Path) -> None: |
| 58 | _write_hooks( |
| 59 | tmp_path, |
| 60 | '[pre-commit]\ncommands = ["exit 1", "touch should-not-run.txt"]\n', |
| 61 | ) |
| 62 | install_hooks(tmp_path) |
| 63 | result = run_hook_point(tmp_path, "pre-commit") |
| 64 | assert result.passed is False |
| 65 | assert not (tmp_path / "should-not-run.txt").exists() |
| 66 | |
| 67 | def test_multiple_passing_commands_all_run_in_order(self, tmp_path: pathlib.Path) -> None: |
| 68 | _write_hooks( |
| 69 | tmp_path, |
| 70 | '[pre-commit]\ncommands = ["touch first.txt", "touch second.txt"]\n', |
| 71 | ) |
| 72 | install_hooks(tmp_path) |
| 73 | result = run_hook_point(tmp_path, "pre-commit") |
| 74 | assert result.passed is True |
| 75 | assert (tmp_path / "first.txt").exists() |
| 76 | assert (tmp_path / "second.txt").exists() |
| 77 | |
| 78 | def test_stderr_captured_on_failure(self, tmp_path: pathlib.Path) -> None: |
| 79 | _write_hooks( |
| 80 | tmp_path, |
| 81 | '[pre-commit]\ncommands = ["echo boom-message 1>&2; exit 1"]\n', |
| 82 | ) |
| 83 | install_hooks(tmp_path) |
| 84 | result = run_hook_point(tmp_path, "pre-commit") |
| 85 | assert result.passed is False |
| 86 | assert "boom-message" in result.output |
| 87 | |
| 88 | def test_runs_relative_to_repo_root(self, tmp_path: pathlib.Path) -> None: |
| 89 | _write_hooks( |
| 90 | tmp_path, |
| 91 | '[pre-commit]\ncommands = ["touch here.txt"]\n', |
| 92 | ) |
| 93 | install_hooks(tmp_path) |
| 94 | # Run from a subdirectory-equivalent scenario by passing tmp_path as |
| 95 | # root explicitly — command must execute with cwd=root regardless of |
| 96 | # the caller's actual process cwd. |
| 97 | run_hook_point(tmp_path, "pre-commit") |
| 98 | assert (tmp_path / "here.txt").exists() |
File History
1 commit
sha256:5f7b38765462d4b092afecab903684171b41c9e7aabc0f6515088d43c5e2cb4f
feat(#192): Phase 3 — muse commit runs installed pre-commit hooks
Sonnet 5
patch
3 days ago