From 98b3a6738f772b34fbf5f9023b7eb86e6cc09852 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Sat, 18 Apr 2026 11:51:09 +0200 Subject: [PATCH 1/2] fix(runner): stop on failure when test errors with runtime error Runtime errors (e.g. `command not found`, `illegal option`) now honour `--stop-on-failure` / `BASHUNIT_STOP_ON_FAILURE=true`, matching the behaviour for assertion failures. Closes #383 --- CHANGELOG.md | 1 + src/runner.sh | 8 ++++++++ tests/acceptance/bashunit_stop_on_failure_test.sh | 10 ++++++++++ .../test_bashunit_stop_on_failure_runtime_error.sh | 9 +++++++++ 4 files changed, 28 insertions(+) create mode 100644 tests/acceptance/fixtures/test_bashunit_stop_on_failure_runtime_error.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f4553b2..0db890c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Allow most assert functions to accept an optional trailing label parameter to override the failure message title (e.g. `assert_same "a" "$b" "checking user name"`) (#77) ### Fixed +- Fix `--stop-on-failure` not stopping when a test errors with a runtime error (e.g. `command not found`, `illegal option`) (#383) - Fix spying on `echo` or `printf` causing bashunit to hang due to infinite recursion (#607) - Fix invalid `.env.example` coverage threshold entry and copy `.env.example` to `.env` in CI test workflows so configuration parse errors are caught during automated test runs - Fix `clock::now` shell-time parsing when `EPOCHREALTIME` uses a comma decimal separator diff --git a/src/runner.sh b/src/runner.sh index 833c6f35..1feab35a 100755 --- a/src/runner.sh +++ b/src/runner.sh @@ -782,6 +782,14 @@ function bashunit::runner::run_test() { bashunit::reports::add_test_failed "$test_file" "$failure_label" "$duration" "$total_assertions" "$error_message" bashunit::runner::write_failure_result_output "$test_file" "$failure_function" "$error_message" "$runtime_output" bashunit::internal_log "Test error" "$failure_label" "$error_message" + + if bashunit::env::is_stop_on_failure_enabled; then + if bashunit::parallel::is_enabled; then + bashunit::parallel::mark_stop_on_failure + else + exit "$EXIT_CODE_STOP_ON_FAILURE" + fi + fi return fi diff --git a/tests/acceptance/bashunit_stop_on_failure_test.sh b/tests/acceptance/bashunit_stop_on_failure_test.sh index 8c922d1e..0f1480e6 100644 --- a/tests/acceptance/bashunit_stop_on_failure_test.sh +++ b/tests/acceptance/bashunit_stop_on_failure_test.sh @@ -31,3 +31,13 @@ function test_bashunit_when_stop_on_failure_env_simple_output() { assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_STOP_ON_FAILURE" "$test_file" --simple)" assert_general_error "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_STOP_ON_FAILURE" "$test_file" --simple)" } + +function test_bashunit_stop_on_failure_with_runtime_error() { + local test_file=./tests/acceptance/fixtures/test_bashunit_stop_on_failure_runtime_error.sh + local output + output="$(./bashunit --no-parallel --env "$TEST_ENV_FILE" --stop-on-failure "$test_file")" + + assert_general_error "$?" + assert_contains "A runtime error" "$output" + assert_not_contains "B not executed" "$output" +} diff --git a/tests/acceptance/fixtures/test_bashunit_stop_on_failure_runtime_error.sh b/tests/acceptance/fixtures/test_bashunit_stop_on_failure_runtime_error.sh new file mode 100644 index 00000000..b33a6ff3 --- /dev/null +++ b/tests/acceptance/fixtures/test_bashunit_stop_on_failure_runtime_error.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +function test_a_runtime_error() { + nonexistent_command_bashunit_383_xyz +} + +function test_b_not_executed() { + assert_same 1 1 +} From 4672fb702868420f051da9546b00fffa367f8b55 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Sat, 18 Apr 2026 11:56:44 +0200 Subject: [PATCH 2/2] test(runner): fix strict-mode capture in stop-on-failure runtime error test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Under `--strict` (`set -euo pipefail`), `output=$(./bashunit …)` would abort the test body on the inner non-zero exit. Capture the exit code via `|| exit_code=$?` and compare with `assert_same`, since `assert_general_error` reads `$?` (or arg3), not arg1. --- tests/acceptance/bashunit_stop_on_failure_test.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/acceptance/bashunit_stop_on_failure_test.sh b/tests/acceptance/bashunit_stop_on_failure_test.sh index 0f1480e6..d76f58a5 100644 --- a/tests/acceptance/bashunit_stop_on_failure_test.sh +++ b/tests/acceptance/bashunit_stop_on_failure_test.sh @@ -34,10 +34,12 @@ function test_bashunit_when_stop_on_failure_env_simple_output() { function test_bashunit_stop_on_failure_with_runtime_error() { local test_file=./tests/acceptance/fixtures/test_bashunit_stop_on_failure_runtime_error.sh - local output - output="$(./bashunit --no-parallel --env "$TEST_ENV_FILE" --stop-on-failure "$test_file")" + local output="" + local exit_code=0 - assert_general_error "$?" + output="$(./bashunit --no-parallel --env "$TEST_ENV_FILE" --stop-on-failure "$test_file")" || exit_code=$? + + assert_same 1 "$exit_code" assert_contains "A runtime error" "$output" assert_not_contains "B not executed" "$output" }