diff options
Diffstat (limited to 'tests/test-validate-el-hook.bats')
| -rw-r--r-- | tests/test-validate-el-hook.bats | 86 |
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 ] } |
