diff --git a/CHANGELOG.md b/CHANGELOG.md index c8541f7b..33effbd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased ### Fixed +- `bashunit::helper::get_function_line_number` no longer disables `extdebug` for its caller: it enables the option only inside a subshell (also dropping an `awk` fork) - `--test-timeout` no longer intermittently reports a fast test as timed out; the watchdog now signals by pid and skips a test that already completed ### Added diff --git a/src/helpers.sh b/src/helpers.sh index 2e6492c9..8d4cba53 100755 --- a/src/helpers.sh +++ b/src/helpers.sh @@ -615,12 +615,16 @@ function bashunit::helper::load_bench_files() { function bashunit::helper::get_function_line_number() { local fn_name=$1 - shopt -s extdebug - local line_number - line_number=$(declare -F "$fn_name" | awk '{print $2}') - shopt -u extdebug - - echo "$line_number" + # Enable extdebug only inside the subshell so the caller's setting is not + # clobbered. With extdebug, `declare -F` prints " "; parse + # the line number with shell word-splitting instead of forking awk. + local declaration + declaration=$( + shopt -s extdebug + declare -F "$fn_name" + ) + declaration="${declaration#* }" + echo "${declaration%% *}" } # Writes a sanitized, process-unique id into _BASHUNIT_HELPER_ID_OUT. diff --git a/tests/unit/helpers_test.sh b/tests/unit/helpers_test.sh index a1b4c410..01da1734 100644 --- a/tests/unit/helpers_test.sh +++ b/tests/unit/helpers_test.sh @@ -586,3 +586,26 @@ function test_find_function_at_line_nonexistent_file() { bashunit::helper::find_function_at_line "/nonexistent/file.sh" 10 2>/dev/null || exit_code=$? assert_same 1 "$exit_code" } + +function test_get_function_line_number_returns_the_definition_line() { + # shellcheck disable=SC2317 # invoked indirectly via declare -F + function _bashunit_line_fixture() { :; } + + local line + line="$(bashunit::helper::get_function_line_number _bashunit_line_fixture)" + + assert_matches '^[0-9]+$' "$line" +} + +function test_get_function_line_number_preserves_caller_extdebug() { + # extdebug is toggled inside a subshell so the assertion never enables it in + # the test runner's shell. The helper must not turn it off for its caller. + local state + state=$( + shopt -s extdebug + bashunit::helper::get_function_line_number test_get_function_line_number_preserves_caller_extdebug >/dev/null + if shopt -q extdebug; then echo "on"; else echo "off"; fi + ) + + assert_same "on" "$state" +}