Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Performance
- Faster runtime-error detection: single `case` glob instead of 23-iteration loop in `detect_runtime_error` (#668)
- Hot-path coverage flag now cached in `_BASHUNIT_COVERAGE_ON`, removing a function dispatch per call (#664)

## [0.36.0](https://github.com/TypedDevs/bashunit/compare/0.35.0...0.36.0) - 2026-05-07

Expand Down
29 changes: 21 additions & 8 deletions src/runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ function bashunit::runner::restore_workdir() {
cd "$BASHUNIT_WORKING_DIR" 2>/dev/null || true
}

# Caches BASHUNIT_COVERAGE into _BASHUNIT_COVERAGE_ON ("1"|"0") so hot-path checks
# avoid a function dispatch per call. Call once after arg parsing; tests that
# toggle BASHUNIT_COVERAGE mid-run must call this again to refresh.
function bashunit::runner::sync_coverage_flag() {
if [ "${BASHUNIT_COVERAGE-}" = "true" ]; then
_BASHUNIT_COVERAGE_ON=1
else
_BASHUNIT_COVERAGE_ON=0
fi
}

function bashunit::runner::source_login_shell_profiles() {
# shellcheck disable=SC1091
[ -f /etc/profile ] && source /etc/profile 2>/dev/null || true
Expand All @@ -27,7 +38,7 @@ function bashunit::runner::export_test_identity() {
local test_file=$1
local fn_name=$2
export BASHUNIT_CURRENT_TEST_ID="$(bashunit::helper::generate_id "$fn_name")"
if bashunit::env::is_coverage_enabled; then
if [ "${_BASHUNIT_COVERAGE_ON:-0}" = 1 ]; then
export _BASHUNIT_COVERAGE_CURRENT_TEST_FILE="$test_file"
export _BASHUNIT_COVERAGE_CURRENT_TEST_FN="$fn_name"
fi
Expand Down Expand Up @@ -167,8 +178,10 @@ function bashunit::runner::load_test_files() {
local -a scripts_ids=()
local scripts_ids_count=0

bashunit::runner::sync_coverage_flag

# Initialize coverage tracking if enabled
if bashunit::env::is_coverage_enabled; then
if [ "$_BASHUNIT_COVERAGE_ON" = 1 ]; then
# Auto-discover coverage paths if not explicitly set
if [ -z "$BASHUNIT_COVERAGE_PATHS" ]; then
BASHUNIT_COVERAGE_PATHS=$(bashunit::coverage::auto_discover_paths "${files[@]}")
Expand Down Expand Up @@ -737,7 +750,7 @@ function bashunit::runner::run_test() {
fi

# Enable coverage tracking early to include set_up/tear_down hooks
if bashunit::env::is_coverage_enabled; then
if [ "${_BASHUNIT_COVERAGE_ON:-0}" = 1 ]; then
bashunit::coverage::enable_trap
fi

Expand Down Expand Up @@ -941,7 +954,7 @@ function bashunit::runner::cleanup_on_exit() {
local exit_code="$2"

# Disable coverage trap before cleanup to avoid interference
if bashunit::env::is_coverage_enabled; then
if [ "${_BASHUNIT_COVERAGE_ON:-0}" = 1 ]; then
bashunit::coverage::disable_trap
fi

Expand Down Expand Up @@ -1381,7 +1394,7 @@ function bashunit::runner::run_set_up_before_script() {
start_time=$(bashunit::clock::now)

# Enable coverage trap to attribute lines executed during set_up_before_script
if bashunit::env::is_coverage_enabled; then
if [ "${_BASHUNIT_COVERAGE_ON:-0}" = 1 ]; then
bashunit::coverage::enable_trap
fi

Expand All @@ -1390,7 +1403,7 @@ function bashunit::runner::run_set_up_before_script() {
local status=$?

# Disable coverage trap after hook execution
if bashunit::env::is_coverage_enabled; then
if [ "${_BASHUNIT_COVERAGE_ON:-0}" = 1 ]; then
bashunit::coverage::disable_trap
fi

Expand Down Expand Up @@ -1520,7 +1533,7 @@ function bashunit::runner::run_tear_down_after_script() {
start_time=$(bashunit::clock::now)

# Enable coverage trap to attribute lines executed during tear_down_after_script
if bashunit::env::is_coverage_enabled; then
if [ "${_BASHUNIT_COVERAGE_ON:-0}" = 1 ]; then
bashunit::coverage::enable_trap
fi

Expand All @@ -1529,7 +1542,7 @@ function bashunit::runner::run_tear_down_after_script() {
local status=$?

# Disable coverage trap after hook execution
if bashunit::env::is_coverage_enabled; then
if [ "${_BASHUNIT_COVERAGE_ON:-0}" = 1 ]; then
bashunit::coverage::disable_trap
fi

Expand Down
27 changes: 27 additions & 0 deletions tests/unit/runner_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,33 @@ function test_extract_assertion_runtime_output_keeps_user_output_that_looks_like
assert_same "✗ Failed: emitted by the code under test" "$actual"
}

function test_sync_coverage_flag_sets_one_when_enabled() {
local _orig="${BASHUNIT_COVERAGE-}"
BASHUNIT_COVERAGE="true"
bashunit::runner::sync_coverage_flag
assert_same "1" "$_BASHUNIT_COVERAGE_ON"
BASHUNIT_COVERAGE="$_orig"
bashunit::runner::sync_coverage_flag
}

function test_sync_coverage_flag_sets_zero_when_disabled() {
local _orig="${BASHUNIT_COVERAGE-}"
BASHUNIT_COVERAGE="false"
bashunit::runner::sync_coverage_flag
assert_same "0" "$_BASHUNIT_COVERAGE_ON"
BASHUNIT_COVERAGE="$_orig"
bashunit::runner::sync_coverage_flag
}

function test_sync_coverage_flag_sets_zero_when_unset() {
local _orig="${BASHUNIT_COVERAGE-}"
unset BASHUNIT_COVERAGE
bashunit::runner::sync_coverage_flag
assert_same "0" "$_BASHUNIT_COVERAGE_ON"
BASHUNIT_COVERAGE="$_orig"
bashunit::runner::sync_coverage_flag
}

function test_detect_runtime_error_returns_empty_when_input_is_empty() {
local actual
actual="$(bashunit::runner::detect_runtime_error "")"
Expand Down
Loading