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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
- Cache function discovery to avoid duplicate pipeline per test file
- Reduce subshells in test execution hot path
- Batch coverage recording with in-memory buffering
- Cache `uname` result at source time to eliminate repeated subprocess forks in OS detection
- Replace `bc` and `awk` subprocesses with native bash arithmetic in clock and duration formatting
- Cache `base64 -w` flag support at load time instead of detecting per test
- Use direct variable access for assertion state instead of getter subshells in runner hot path

### Fixed
- Mocking `mktemp` no longer breaks spy creation (#602)
Expand Down
9 changes: 6 additions & 3 deletions src/check_os.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ _BASHUNIT_OS="Unknown"
_BASHUNIT_DISTRO="Unknown"

function bashunit::check_os::init() {
_BASHUNIT_UNAME="$(uname)"
if bashunit::check_os::is_linux; then
_BASHUNIT_OS="Linux"
if bashunit::check_os::is_ubuntu; then
Expand Down Expand Up @@ -39,16 +40,18 @@ function bashunit::check_os::is_nixos() {
grep -q '^ID=nixos' /etc/os-release 2>/dev/null
}

_BASHUNIT_UNAME="$(uname)"

function bashunit::check_os::is_linux() {
[[ "$(uname)" == "Linux" ]]
[[ "$_BASHUNIT_UNAME" == "Linux" ]]
}

function bashunit::check_os::is_macos() {
[[ "$(uname)" == "Darwin" ]]
[[ "$_BASHUNIT_UNAME" == "Darwin" ]]
}

function bashunit::check_os::is_windows() {
case "$(uname)" in
case "$_BASHUNIT_UNAME" in
*MINGW* | *MSYS* | *CYGWIN*)
return 0
;;
Expand Down
9 changes: 7 additions & 2 deletions src/clock.sh
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,19 @@ EOF
date-seconds)
local seconds
seconds=$(date +%s)
bashunit::math::calculate "$seconds * 1000000000"
echo "$((seconds * 1000000000))"
;;
shell)
# shellcheck disable=SC2155
local shell_time="$(bashunit::clock::shell_time)"
local seconds="${shell_time%%.*}"
local microseconds="${shell_time#*.}"
bashunit::math::calculate "($seconds * 1000000000) + ($microseconds * 1000)"
# Pad to 6 digits and strip leading zeros for arithmetic
microseconds="${microseconds}000000"
microseconds="${microseconds:0:6}"
microseconds="${microseconds#"${microseconds%%[!0]*}"}"
microseconds="${microseconds:-0}"
echo "$(( (seconds * 1000000000) + (microseconds * 1000) ))"
;;
*)
bashunit::clock::_choose_impl || return 1
Expand Down
18 changes: 14 additions & 4 deletions src/console_results.sh
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,11 @@ function bashunit::console_results::print_execution_time() {
return
fi

local time=$(bashunit::clock::total_runtime_in_milliseconds | awk '{printf "%.0f", $1}')
local time
time=$(bashunit::clock::total_runtime_in_milliseconds)
# Strip decimal portion (integer truncation, Bash 3.0 compatible)
time="${time%%.*}"
time="${time:-0}"

if [[ "$time" -lt 1000 ]]; then
printf "${_BASHUNIT_COLOR_BOLD}%s${_BASHUNIT_COLOR_DEFAULT}\n" \
Expand All @@ -144,8 +148,10 @@ function bashunit::console_results::print_execution_time() {
return
fi

local integer_part=$((time / 1000))
local decimal_part=$(( (time % 1000) / 10 ))
local formatted_seconds
formatted_seconds=$(awk "BEGIN {printf \"%.2f\", $time / 1000}")
formatted_seconds=$(printf "%d.%02d" "$integer_part" "$decimal_part")

printf "${_BASHUNIT_COLOR_BOLD}%s${_BASHUNIT_COLOR_DEFAULT}\n" \
"Time taken: ${formatted_seconds}s"
Expand All @@ -160,8 +166,10 @@ function bashunit::console_results::format_duration() {
local seconds=$((time_in_seconds % 60))
echo "${minutes}m ${seconds}s"
elif [[ "$duration_ms" -ge 1000 ]]; then
local integer_part=$((duration_ms / 1000))
local decimal_part=$(( (duration_ms % 1000) / 10 ))
local formatted_seconds
formatted_seconds=$(awk "BEGIN {printf \"%.2f\", $duration_ms / 1000}")
formatted_seconds=$(printf "%d.%02d" "$integer_part" "$decimal_part")
echo "${formatted_seconds}s"
else
echo "${duration_ms}ms"
Expand Down Expand Up @@ -234,8 +242,10 @@ function bashunit::console_results::print_successful_test() {
local seconds=$((time_in_seconds % 60))
time_display="${minutes}m ${seconds}s"
elif [[ "$duration" -ge 1000 ]]; then
local integer_part=$((duration / 1000))
local decimal_part=$(( (duration % 1000) / 10 ))
local formatted_seconds
formatted_seconds=$(awk "BEGIN {printf \"%.2f\", $duration / 1000}")
formatted_seconds=$(printf "%d.%02d" "$integer_part" "$decimal_part")
time_display="${formatted_seconds}s"
else
time_display="${duration}ms"
Expand Down
6 changes: 4 additions & 2 deletions src/helpers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,10 @@ function bashunit::helper::encode_base64() {
return
fi

if command -v base64 >/dev/null; then
printf '%s' "$value" | base64 -w 0 2>/dev/null || printf '%s' "$value" | base64 | tr -d '\n'
if [[ "$_BASHUNIT_BASE64_WRAP_FLAG" == true ]]; then
printf '%s' "$value" | base64 -w 0
elif command -v base64 >/dev/null; then
printf '%s' "$value" | base64 | tr -d '\n'
else
printf '%s' "$value" | openssl enc -base64 -A
fi
Expand Down
10 changes: 5 additions & 5 deletions src/runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ function bashunit::runner::run_test() {
return
fi

if [[ "$current_assertions_failed" != "$(bashunit::state::get_assertions_failed)" ]]; then
if [[ "$current_assertions_failed" != "$_BASHUNIT_ASSERTIONS_FAILED" ]]; then
bashunit::state::add_tests_failed
bashunit::reports::add_test_failed "$test_file" "$label" "$duration" "$total_assertions" "$subshell_output"
bashunit::runner::write_failure_result_output "$test_file" "$fn_name" "$subshell_output"
Expand All @@ -779,7 +779,7 @@ function bashunit::runner::run_test() {
return
fi

if [[ "$current_assertions_snapshot" != "$(bashunit::state::get_assertions_snapshot)" ]]; then
if [[ "$current_assertions_snapshot" != "$_BASHUNIT_ASSERTIONS_SNAPSHOT" ]]; then
bashunit::state::add_tests_snapshot
# In failures-only mode, suppress snapshot test output
if ! bashunit::env::is_failures_only_enabled; then
Expand All @@ -790,15 +790,15 @@ function bashunit::runner::run_test() {
return
fi

if [[ "$current_assertions_incomplete" != "$(bashunit::state::get_assertions_incomplete)" ]]; then
if [[ "$current_assertions_incomplete" != "$_BASHUNIT_ASSERTIONS_INCOMPLETE" ]]; then
bashunit::state::add_tests_incomplete
bashunit::reports::add_test_incomplete "$test_file" "$label" "$duration" "$total_assertions"
bashunit::runner::write_incomplete_result_output "$test_file" "$fn_name" "$subshell_output"
bashunit::internal_log "Test incomplete" "$label"
return
fi

if [[ "$current_assertions_skipped" != "$(bashunit::state::get_assertions_skipped)" ]]; then
if [[ "$current_assertions_skipped" != "$_BASHUNIT_ASSERTIONS_SKIPPED" ]]; then
bashunit::state::add_tests_skipped
bashunit::reports::add_test_skipped "$test_file" "$label" "$duration" "$total_assertions"
bashunit::runner::write_skipped_result_output "$test_file" "$fn_name" "$subshell_output"
Expand Down Expand Up @@ -1228,7 +1228,7 @@ function bashunit::runner::record_test_hook_failure() {
local hook_message="$2"
local status="$3"

if [[ -n "$(bashunit::state::get_test_hook_failure)" ]]; then
if [[ -n "$_BASHUNIT_TEST_HOOK_FAILURE" ]]; then
return "$status"
fi

Expand Down
9 changes: 8 additions & 1 deletion src/state.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
#!/usr/bin/env bash

# Cache base64 -w flag support (Alpine needs -w 0, macOS does not support -w)
if base64 --help 2>&1 | grep -q -- "-w"; then
_BASHUNIT_BASE64_WRAP_FLAG=true
else
_BASHUNIT_BASE64_WRAP_FLAG=false
fi

_BASHUNIT_TESTS_PASSED=0
_BASHUNIT_TESTS_FAILED=0
_BASHUNIT_TESTS_SKIPPED=0
Expand Down Expand Up @@ -218,7 +225,7 @@ function bashunit::state::export_subshell_context() {

local encoded_test_hook_message

if base64 --help 2>&1 | grep -q -- "-w"; then
if [[ "$_BASHUNIT_BASE64_WRAP_FLAG" == true ]]; then
# Alpine requires the -w 0 option to avoid wrapping
encoded_test_output=$(echo -n "$_BASHUNIT_TEST_OUTPUT" | base64 -w 0)
encoded_test_title=$(echo -n "$_BASHUNIT_TEST_TITLE" | base64 -w 0)
Expand Down
Loading