aboutsummaryrefslogtreecommitdiff
path: root/tests/test-validate-el-hook.bats
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-validate-el-hook.bats')
-rw-r--r--tests/test-validate-el-hook.bats86
1 files changed, 55 insertions, 31 deletions
diff --git a/tests/test-validate-el-hook.bats b/tests/test-validate-el-hook.bats
index 2dbcae79..43c3569c 100644
--- a/tests/test-validate-el-hook.bats
+++ b/tests/test-validate-el-hook.bats
@@ -1,19 +1,21 @@
#!/usr/bin/env bats
-# Tests for .claude/hooks/validate-el.sh — specifically the auto-test cap.
+# Tests for .claude/hooks/validate-el.sh — the auto-test runner.
#
-# The hook runs the tests matching an edited file, but only when the match
-# count is between 1 and MAX_AUTO_TEST_FILES. Above the cap the whole block
-# was skipped with no else branch: nothing printed, exit 0, indistinguishable
-# from a passing run. That is live for the three largest families here
-# (calendar-sync 63 test files, music 45, ai-term 35), so every edit to those
-# modules ran parens and byte-compile and zero tests, silently.
+# The runner used to skip entirely above MAX_AUTO_TEST_FILES=20, with no else
+# branch: nothing printed, exit 0, indistinguishable from a passing run. That
+# was live for the three largest families here (calendar-sync 63 test files,
+# music 45, ai-term 35), so every edit to those ran parens and byte-compile and
+# zero tests, silently.
#
-# The cap itself is fine — running 63 files per keystroke is not wanted. The
-# defect is the silence, so these tests assert the skip announces itself and
-# names what to run.
+# The cap was removed rather than made loud, because its premise did not hold.
+# Measured on this machine, running a whole family takes about a second:
+# ai-term 208 tests in 1.0s, music 403 in 1.7s, calendar-sync 633 in 0.9s. It
+# was also concealing a real cross-test pollution bug in calendar-sync that
+# only appears when that family runs in one process.
#
-# Each test builds a synthetic project in BATS_TEST_TMPDIR and points
-# CLAUDE_PROJECT_DIR at it, so nothing runs against the real tree.
+# These tests pin that no file count is skipped. Each builds a synthetic
+# project in BATS_TEST_TMPDIR and points CLAUDE_PROJECT_DIR at it, so nothing
+# runs against the real tree.
setup() {
HOOK="${BATS_TEST_DIRNAME}/../.claude/hooks/validate-el.sh"
@@ -23,8 +25,7 @@ setup() {
printf '(provide (quote widget))\n' > "$PROJ/modules/widget.el"
}
-# Create N test files matching the widget stem. Each is trivially green so a
-# run below the cap succeeds and the only variable is the count.
+# N green test files matching the widget stem.
make_tests() {
local n="$1" i
for ((i = 1; i <= n; i++)); do
@@ -33,41 +34,64 @@ make_tests() {
done
}
+# One failing test file, to prove the run is real rather than merely quiet.
+make_failing_test() {
+ printf '(require (quote ert))\n(ert-deftest test-widget-bad () (should nil))\n' \
+ > "$PROJ/tests/test-widget-bad.el"
+}
+
hook_input() {
printf '{"tool_input":{"file_path":"%s"}}' "$PROJ/modules/widget.el"
}
+run_hook() {
+ run bash -c "$(printf '%q' "$HOOK") <<< '$(hook_input)'"
+}
+
# ------------------------------- Normal cases -------------------------------
-@test "under the cap: runs the tests and stays quiet on success" {
+@test "a small family runs and passes quietly" {
make_tests 3
- run bash -c "$(printf '%q' "$HOOK") <<< '$(hook_input)'"
+ run_hook
[ "$status" -eq 0 ]
- [[ "${output,,}" != *"skipped"* ]]
+}
+
+@test "a failing test blocks, so a quiet pass means the tests really ran" {
+ make_tests 3
+ make_failing_test
+ run_hook
+ [ "$status" -eq 2 ]
+ [[ "$output" == *"TESTS FAILED"* ]]
}
# ------------------------------ Boundary cases ------------------------------
-@test "exactly at the cap: still runs the tests" {
+@test "at the old cap of 20 files: runs" {
make_tests 20
- run bash -c "$(printf '%q' "$HOOK") <<< '$(hook_input)'"
+ run_hook
[ "$status" -eq 0 ]
- [[ "${output,,}" != *"skipped"* ]]
}
-# -------------------------------- Error cases -------------------------------
-
-@test "over the cap: says it skipped rather than exiting silently" {
+@test "past the old cap: still runs, no longer skipped" {
make_tests 21
- run bash -c "$(printf '%q' "$HOOK") <<< '$(hook_input)'"
- # Must not fail the edit — the cap is deliberate, the silence is not.
+ run_hook
[ "$status" -eq 0 ]
- [[ "${output,,}" == *"skipped"* ]]
+ [[ "${output,,}" != *"skipped"* ]]
}
-@test "over the cap: names the count and how to run them" {
- make_tests 21
- run bash -c "$(printf '%q' "$HOOK") <<< '$(hook_input)'"
- [[ "$output" == *"21"* ]]
- [[ "$output" == *"make test-file"* ]]
+@test "well past the old cap: a failure in file 63 is still caught" {
+ # The regression this guards: at 63 files the runner used to skip, so a red
+ # test in a big family reported clean. calendar-sync is exactly this size.
+ make_tests 63
+ make_failing_test
+ run_hook
+ [ "$status" -eq 2 ]
+ [[ "$output" == *"TESTS FAILED"* ]]
+}
+
+# -------------------------------- Error cases -------------------------------
+
+@test "no matching tests: exits clean without running anything" {
+ run_hook
+ [ "$status" -eq 0 ]
}