Skip to content

Commit db92664

Browse files
committed
fix(runner): fail test file with syntax error instead of silent halt
Capture stderr and exit code of `source "$test_file"`. On syntax error or non-zero exit, record a source hook failure and skip the file so the suite surfaces the problem instead of continuing silently. Closes #220
1 parent b2ddec7 commit db92664

4 files changed

Lines changed: 61 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- Fix `clock::now` shell-time parsing when `EPOCHREALTIME` uses a comma decimal separator
1414
- Fix LCOV and HTML coverage reports generating incomplete/empty output due to post-increment operator causing silent exit under `set -e` (#618)
1515
- Enable parallel test execution on Alpine Linux; previously gated off due to race conditions, now resolved (#370)
16+
- Fix syntax error in test file silently passing; now reported as a failing test (#220)
1617

1718
## [0.34.1](https://github.com/TypedDevs/bashunit/compare/0.34.0...0.34.1) - 2026-03-20
1819

src/runner.sh

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,26 @@ function bashunit::runner::load_test_files() {
7272
scripts_ids[scripts_ids_count]="${BASHUNIT_CURRENT_SCRIPT_ID}"
7373
scripts_ids_count=$((scripts_ids_count + 1))
7474
bashunit::internal_log "Loading file" "$test_file"
75+
local source_err_file source_err source_status
76+
source_err_file="$(bashunit::temp_file "source_err")"
7577
# shellcheck source=/dev/null
76-
source "$test_file"
78+
source "$test_file" 2>"$source_err_file"
79+
source_status=$?
80+
source_err=""
81+
if [ -s "$source_err_file" ]; then
82+
source_err="$(cat "$source_err_file")"
83+
fi
84+
rm -f "$source_err_file"
85+
if [ "$source_status" -ne 0 ] || [ "$(printf '%s' "$source_err" \
86+
| "$GREP" -cE 'syntax error|unexpected EOF' || true)" -gt 0 ]; then
87+
local message="$source_err"
88+
[ -z "$message" ] && message="Failed to source '$test_file' (exit $source_status)"
89+
bashunit::runner::record_file_hook_failure \
90+
"source" "$test_file" "$message" 1 true
91+
bashunit::runner::clean_set_up_and_tear_down_after_script
92+
bashunit::runner::restore_workdir
93+
continue
94+
fi
7795
# Update function cache after sourcing new test file
7896
_BASHUNIT_CACHED_ALL_FUNCTIONS=$(declare -F | awk '{print $3}')
7997
# Check if any tests match the filter before rendering header or running hooks
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
function set_up_before_script() {
5+
TEST_ENV_FILE="tests/acceptance/fixtures/.env.default"
6+
}
7+
8+
function strip_ansi() {
9+
sed -E 's/\x1B\[[0-9;]*[A-Za-z]//g'
10+
}
11+
12+
function test_bashunit_when_test_file_has_syntax_error() {
13+
local test_file=./tests/acceptance/fixtures/test_bashunit_when_syntax_error.sh
14+
15+
local actual_raw
16+
set +e
17+
actual_raw="$(./bashunit --no-parallel --detailed --env "$TEST_ENV_FILE" "$test_file" 2>&1)"
18+
set -e
19+
20+
local actual
21+
actual="$(printf "%s" "$actual_raw" | strip_ansi)"
22+
23+
assert_contains "syntax error" "$actual"
24+
assert_contains "failed" "$actual"
25+
assert_general_error "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file" 2>&1)"
26+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env bash
2+
3+
function test_good() {
4+
assert_equals 1 1
5+
}
6+
7+
function test_with_syntax_error() {
8+
if [ 1 -eq 1 ]
9+
echo "missing then keyword"
10+
fi
11+
}
12+
13+
function test_another() {
14+
assert_equals 2 2
15+
}

0 commit comments

Comments
 (0)