From 205da4175b24ebffdbc02fa05b125390ef6dda51 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 14:06:46 +0200 Subject: [PATCH 01/14] chore: progress bar --- bashunit | 1 + build.sh | 1 + src/assert_snapshot.sh | 9 ++ src/benchmark.sh | 7 +- src/console_results.sh | 98 ++++++++++++++++--- src/env.sh | 9 ++ src/main.sh | 11 ++- src/progress.sh | 81 +++++++++++++++ src/runner.sh | 33 ++++--- src/state.sh | 12 +++ ...unit_when_a_test_returns_non_zero.snapshot | 1 + ...hen_a_test_fail_simple_output_env.snapshot | 2 +- ..._a_test_fail_simple_output_option.snapshot | 2 +- ...en_a_test_fail_verbose_output_env.snapshot | 1 + ...a_test_fail_verbose_output_option.snapshot | 1 + ..._a_test_fail_and_exit_immediately.snapshot | 1 + ...hunit_with_multiple_failing_tests.snapshot | 3 + ....test_bashunit_when_log_junit_env.snapshot | 1 + ...st_bashunit_when_log_junit_option.snapshot | 1 + ...est_bashunit_when_report_html_env.snapshot | 3 + ..._bashunit_when_report_html_option.snapshot | 3 + ...bashunit_when_stop_on_failure_env.snapshot | 1 + ...stop_on_failure_env_simple_output.snapshot | 2 +- ...hunit_when_stop_on_failure_option.snapshot | 1 + tests/unit/directory_test.sh | 24 +++++ 25 files changed, 272 insertions(+), 37 deletions(-) create mode 100644 src/progress.sh diff --git a/bashunit b/bashunit index d06795f8..7ee7d658 100755 --- a/bashunit +++ b/bashunit @@ -19,6 +19,7 @@ source "$BASHUNIT_ROOT_DIR/src/parallel.sh" source "$BASHUNIT_ROOT_DIR/src/env.sh" source "$BASHUNIT_ROOT_DIR/src/clock.sh" source "$BASHUNIT_ROOT_DIR/src/state.sh" +source "$BASHUNIT_ROOT_DIR/src/progress.sh" source "$BASHUNIT_ROOT_DIR/src/colors.sh" source "$BASHUNIT_ROOT_DIR/src/console_header.sh" source "$BASHUNIT_ROOT_DIR/src/console_results.sh" diff --git a/build.sh b/build.sh index 1dcb8665..d4e370e3 100755 --- a/build.sh +++ b/build.sh @@ -94,6 +94,7 @@ function build::dependencies() { "src/env.sh" "src/clock.sh" "src/state.sh" + "src/progress.sh" "src/colors.sh" "src/console_header.sh" "src/console_results.sh" diff --git a/src/assert_snapshot.sh b/src/assert_snapshot.sh index fe51be90..3f92c020 100644 --- a/src/assert_snapshot.sh +++ b/src/assert_snapshot.sh @@ -34,9 +34,17 @@ function snapshot::match_with_placeholder() { fi } +# Remove progress bar output from a given string. Progress bar sequences are +# wrapped between ESC7 and ESC8 control codes when a TTY is present. +function snapshot::strip_progress_line() { + local input="$1" + echo -n "$input" | sed $'s/\x1b7.*\x1b8//' +} + function assert_match_snapshot() { local actual actual=$(echo -n "$1" | tr -d '\r') + actual=$(snapshot::strip_progress_line "$actual") local directory directory="./$(dirname "${BASH_SOURCE[1]}")/snapshots" local test_file @@ -73,6 +81,7 @@ function assert_match_snapshot() { function assert_match_snapshot_ignore_colors() { local actual actual=$(echo -n "$1" | sed -r 's/\x1B\[[0-9;]*[mK]//g' | tr -d '\r') + actual=$(snapshot::strip_progress_line "$actual") local directory directory="./$(dirname "${BASH_SOURCE[1]}")/snapshots" diff --git a/src/benchmark.sh b/src/benchmark.sh index 32b9eb91..15dc652c 100644 --- a/src/benchmark.sh +++ b/src/benchmark.sh @@ -94,12 +94,13 @@ function benchmark::print_results() { fi if env::is_simple_output_enabled; then - printf "\n" + progress::blank_line fi - printf "\nBenchmark Results (avg ms)\n" + progress::blank_line + printf "Benchmark Results (avg ms)\n" print_line 80 "=" - printf "\n" + progress::blank_line local has_threshold=false for val in "${_BENCH_MAX_MILLIS[@]}"; do diff --git a/src/console_results.sh b/src/console_results.sh index 7e57a024..5de26cd7 100644 --- a/src/console_results.sh +++ b/src/console_results.sh @@ -13,7 +13,8 @@ function console_results::render_result() { fi if env::is_simple_output_enabled; then - printf "\n\n" + progress::blank_line + progress::blank_line fi local total_tests=0 @@ -67,36 +68,42 @@ function console_results::render_result() { printf " %s total\n" "$total_assertions" if [[ "$(state::get_tests_failed)" -gt 0 ]]; then - printf "\n%s%s%s\n" "$_COLOR_RETURN_ERROR" " Some tests failed " "$_COLOR_DEFAULT" + progress::blank_line + printf "%s%s%s\n" "$_COLOR_RETURN_ERROR" " Some tests failed " "$_COLOR_DEFAULT" console_results::print_execution_time return 1 fi if [[ "$(state::get_tests_incomplete)" -gt 0 ]]; then - printf "\n%s%s%s\n" "$_COLOR_RETURN_INCOMPLETE" " Some tests incomplete " "$_COLOR_DEFAULT" + progress::blank_line + printf "%s%s%s\n" "$_COLOR_RETURN_INCOMPLETE" " Some tests incomplete " "$_COLOR_DEFAULT" console_results::print_execution_time return 0 fi if [[ "$(state::get_tests_skipped)" -gt 0 ]]; then - printf "\n%s%s%s\n" "$_COLOR_RETURN_SKIPPED" " Some tests skipped " "$_COLOR_DEFAULT" + progress::blank_line + printf "%s%s%s\n" "$_COLOR_RETURN_SKIPPED" " Some tests skipped " "$_COLOR_DEFAULT" console_results::print_execution_time return 0 fi if [[ "$(state::get_tests_snapshot)" -gt 0 ]]; then - printf "\n%s%s%s\n" "$_COLOR_RETURN_SNAPSHOT" " Some snapshots created " "$_COLOR_DEFAULT" + progress::blank_line + printf "%s%s%s\n" "$_COLOR_RETURN_SNAPSHOT" " Some snapshots created " "$_COLOR_DEFAULT" console_results::print_execution_time return 0 fi if [[ $total_tests -eq 0 ]]; then - printf "\n%s%s%s\n" "$_COLOR_RETURN_ERROR" " No tests found " "$_COLOR_DEFAULT" + progress::blank_line + printf "%s%s%s\n" "$_COLOR_RETURN_ERROR" " No tests found " "$_COLOR_DEFAULT" console_results::print_execution_time return 1 fi - printf "\n%s%s%s\n" "$_COLOR_RETURN_SUCCESS" " All tests passed " "$_COLOR_DEFAULT" + progress::blank_line + printf "%s%s%s\n" "$_COLOR_RETURN_SUCCESS" " All tests passed " "$_COLOR_DEFAULT" console_results::print_execution_time return 0 } @@ -143,9 +150,26 @@ function console_results::print_successful_test() { state::print_line "successful" "$full_line" } +# Print a summary line for a failed test with its duration. +function console_results::print_failed_test_summary() { + local test_name=$1 + local duration=${2:-"0"} + + local line + line=$(printf "%s✗ Failed%s: %s" "$_COLOR_FAILED" "$_COLOR_DEFAULT" "$test_name") + + local full_line=$line + if env::is_show_execution_time_enabled; then + full_line="$(printf "%s\n" "$(str::rpad "$line" "$duration ms")")" + fi + + state::print_line "failed" "$full_line" +} + function console_results::print_failure_message() { local test_name=$1 local failure_message=$2 + local duration=${3-} local line line="$(printf "\ @@ -153,7 +177,12 @@ ${_COLOR_FAILED}✗ Failed${_COLOR_DEFAULT}: %s ${_COLOR_FAINT}Message:${_COLOR_DEFAULT} ${_COLOR_BOLD}'%s'${_COLOR_DEFAULT}\n"\ "${test_name}" "${failure_message}")" - state::print_line "failure" "$line" + local full_line=$line + if [[ -n "$duration" ]] && env::is_show_execution_time_enabled; then + full_line="$(printf "%s\n" "$(str::rpad "$line" "$duration ms")")" + fi + + state::print_line "failure" "$full_line" } function console_results::print_failed_test() { @@ -163,6 +192,7 @@ function console_results::print_failed_test() { local actual=$4 local extra_key=${5-} local extra_value=${6-} + local duration=${7-} local line line="$(printf "\ @@ -178,13 +208,19 @@ ${_COLOR_FAILED}✗ Failed${_COLOR_DEFAULT}: %s "${extra_key}" "${extra_value}")" fi - state::print_line "failed" "$line" + local full_line=$line + if [[ -n "$duration" ]] && env::is_show_execution_time_enabled; then + full_line="$(printf "%s\n" "$(str::rpad "$line" "$duration ms")")" + fi + + state::print_line "failed" "$full_line" } function console_results::print_failed_snapshot_test() { local function_name=$1 local snapshot_file=$2 + local duration=${3-} local line line="$(printf "${_COLOR_FAILED}✗ Failed${_COLOR_DEFAULT}: %s @@ -203,12 +239,18 @@ function console_results::print_failed_snapshot_test() { rm "$actual_file" fi - state::print_line "failed_snapshot" "$line" + local full_line=$line + if [[ -n "$duration" ]] && env::is_show_execution_time_enabled; then + full_line="$(printf "%s\n" "$(str::rpad "$line" "$duration ms")")" + fi + + state::print_line "failed_snapshot" "$full_line" } function console_results::print_skipped_test() { local function_name=$1 local reason=${2-} + local duration=${3-} local line line="$(printf "${_COLOR_SKIPPED}↷ Skipped${_COLOR_DEFAULT}: %s\n" "${function_name}")" @@ -217,12 +259,18 @@ function console_results::print_skipped_test() { line+="$(printf "${_COLOR_FAINT} %s${_COLOR_DEFAULT}\n" "${reason}")" fi - state::print_line "skipped" "$line" + local full_line=$line + if [[ -n "$duration" ]] && env::is_show_execution_time_enabled; then + full_line="$(printf "%s\n" "$(str::rpad "$line" "$duration ms")")" + fi + + state::print_line "skipped" "$full_line" } function console_results::print_incomplete_test() { local function_name=$1 local pending=${2-} + local duration=${3-} local line line="$(printf "${_COLOR_INCOMPLETE}✒ Incomplete${_COLOR_DEFAULT}: %s\n" "${function_name}")" @@ -231,23 +279,35 @@ function console_results::print_incomplete_test() { line+="$(printf "${_COLOR_FAINT} %s${_COLOR_DEFAULT}\n" "${pending}")" fi - state::print_line "incomplete" "$line" + local full_line=$line + if [[ -n "$duration" ]] && env::is_show_execution_time_enabled; then + full_line="$(printf "%s\n" "$(str::rpad "$line" "$duration ms")")" + fi + + state::print_line "incomplete" "$full_line" } function console_results::print_snapshot_test() { local function_name=$1 + local duration=${2-} local test_name test_name=$(helper::normalize_test_function_name "$function_name") local line line="$(printf "${_COLOR_SNAPSHOT}✎ Snapshot${_COLOR_DEFAULT}: %s\n" "${test_name}")" - state::print_line "snapshot" "$line" + local full_line=$line + if [[ -n "$duration" ]] && env::is_show_execution_time_enabled; then + full_line="$(printf "%s\n" "$(str::rpad "$line" "$duration ms")")" + fi + + state::print_line "snapshot" "$full_line" } function console_results::print_error_test() { local function_name=$1 local error="$2" + local duration=${3-} local test_name test_name=$(helper::normalize_test_function_name "$function_name") @@ -256,7 +316,12 @@ function console_results::print_error_test() { line="$(printf "${_COLOR_FAILED}✗ Error${_COLOR_DEFAULT}: %s ${_COLOR_FAINT}%s${_COLOR_DEFAULT}\n" "${test_name}" "${error}")" - state::print_line "error" "$line" + local full_line=$line + if [[ -n "$duration" ]] && env::is_show_execution_time_enabled; then + full_line="$(printf "%s\n" "$(str::rpad "$line" "$duration ms")")" + fi + + state::print_line "error" "$full_line" } function console_results::print_failing_tests_and_reset() { @@ -265,7 +330,8 @@ function console_results::print_failing_tests_and_reset() { total_failed=$(state::get_tests_failed) if env::is_simple_output_enabled; then - printf "\n\n" + progress::blank_line + progress::blank_line fi if [[ "$total_failed" -eq 1 ]]; then @@ -277,6 +343,6 @@ function console_results::print_failing_tests_and_reset() { sed '${/^$/d;}' "$FAILURES_OUTPUT_PATH" | sed 's/^/|/' rm "$FAILURES_OUTPUT_PATH" - echo "" + progress::blank_line fi } diff --git a/src/env.sh b/src/env.sh index 77ed9a39..c4a24d41 100644 --- a/src/env.sh +++ b/src/env.sh @@ -28,6 +28,10 @@ _DEFAULT_STOP_ON_FAILURE="false" _DEFAULT_SHOW_EXECUTION_TIME="true" _DEFAULT_VERBOSE="false" _DEFAULT_BENCH_MODE="false" +_DEFAULT_PROGRESS="true" + +# Controls if the progress bar should render during execution +_PROGRESS_ENABLED=true : "${BASHUNIT_PARALLEL_RUN:=${PARALLEL_RUN:=$_DEFAULT_PARALLEL_RUN}}" : "${BASHUNIT_SHOW_HEADER:=${SHOW_HEADER:=$_DEFAULT_SHOW_HEADER}}" @@ -37,6 +41,7 @@ _DEFAULT_BENCH_MODE="false" : "${BASHUNIT_SHOW_EXECUTION_TIME:=${SHOW_EXECUTION_TIME:=$_DEFAULT_SHOW_EXECUTION_TIME}}" : "${BASHUNIT_VERBOSE:=${VERBOSE:=$_DEFAULT_VERBOSE}}" : "${BASHUNIT_BENCH_MODE:=${BENCH_MODE:=$_DEFAULT_BENCH_MODE}}" +: "${BASHUNIT_PROGRESS:=${PROGRESS:=$_DEFAULT_PROGRESS}}" function env::is_parallel_run_enabled() { [[ "$BASHUNIT_PARALLEL_RUN" == "true" ]] @@ -74,6 +79,10 @@ function env::is_bench_mode_enabled() { [[ "$BASHUNIT_BENCH_MODE" == "true" ]] } +function env::is_progress_enabled() { + [[ "$BASHUNIT_PROGRESS" == "true" ]] +} + function env::active_internet_connection() { if ping -c 1 -W 3 google.com &> /dev/null; then return 0 diff --git a/src/main.sh b/src/main.sh index 2955b075..6b9a4c52 100644 --- a/src/main.sh +++ b/src/main.sh @@ -32,9 +32,14 @@ function main::exec_tests() { console_header::print_version_with_env "$filter" "${test_files[@]}" + local total_tests + total_tests=$(helpers::find_total_tests "$filter" "${test_files[@]}") + state::set_total_tests_to_run "$total_tests" + progress::init "$total_tests" + if env::is_verbose_enabled; then if env::is_simple_output_enabled; then - echo "" + progress::blank_line fi printf '%*s\n' "$TERMINAL_WIDTH" '' | tr ' ' '#' printf "%s\n" "Filter: ${filter:-None}" @@ -59,6 +64,7 @@ function main::exec_tests() { console_results::print_failing_tests_and_reset console_results::render_result exit_code=$? + progress::finish if [[ -n "$BASHUNIT_LOG_JUNIT" ]]; then reports::generate_junit_xml "$BASHUNIT_LOG_JUNIT" @@ -105,7 +111,8 @@ function main::cleanup() { } function main::handle_stop_on_failure_sync() { - printf "\n%sStop on failure enabled...%s\n" "${_COLOR_SKIPPED}" "${_COLOR_DEFAULT}" + progress::blank_line + printf "%sStop on failure enabled...%s\n" "${_COLOR_SKIPPED}" "${_COLOR_DEFAULT}" console_results::print_failing_tests_and_reset console_results::render_result cleanup_temp_files diff --git a/src/progress.sh b/src/progress.sh new file mode 100644 index 00000000..4bcb0b16 --- /dev/null +++ b/src/progress.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash + +function progress::init() { + PROGRESS_TOTAL=$1 + + if parallel::is_enabled || [[ ! -t 1 ]] || ! env::is_progress_enabled; then + _PROGRESS_ENABLED=false + else + _PROGRESS_ENABLED=true + progress::blank_line + fi +} + +function progress::render() { + local current=$1 + local total=$2 + + if [[ "$_PROGRESS_ENABLED" != true ]]; then + return + fi + + if [[ ! -t 1 ]]; then + return + fi + + if [[ -z "$total" || "$total" -eq 0 ]]; then + return + fi + + local width=$((TERMINAL_WIDTH - 20)) + (( width < 10 )) && width=10 + + local filled=$(( current * width / total )) + local empty=$(( width - filled )) + local bar + + bar="" + for ((i=0; i /dev/null; then + tput sc + tput cup $(( $(tput lines) - 1 )) 0 + printf '%-*s' "$TERMINAL_WIDTH" "$line" + tput rc + else + printf '\r%-*s' "$TERMINAL_WIDTH" "$line" + fi +} + +function progress::finish() { + if [[ "$_PROGRESS_ENABLED" != true ]]; then + return + fi + + if command -v tput > /dev/null; then + tput sc + tput cup $(( $(tput lines) - 1 )) 0 + printf '%*s\n' "$TERMINAL_WIDTH" '' + tput rc + else + printf '\n' + fi +} + +# Print an empty line, ensuring any residual characters are cleared by +# filling the entire terminal width with spaces before emitting a newline. +function progress::blank_line() { + if [[ -t 1 ]] && command -v tput > /dev/null; then + printf '%*s\n' "$TERMINAL_WIDTH" '' + else + printf '\n' + fi +} diff --git a/src/runner.sh b/src/runner.sh index fad4a14b..e2e3a044 100755 --- a/src/runner.sh +++ b/src/runner.sh @@ -51,7 +51,7 @@ function runner::load_bench_files() { function runner::spinner() { if env::is_simple_output_enabled; then - printf "\n" + progress::blank_line fi local delay=0.1 @@ -125,7 +125,7 @@ function runner::call_test_functions() { done if ! env::is_simple_output_enabled; then - echo "" + progress::blank_line fi } @@ -154,7 +154,7 @@ function runner::call_bench_functions() { done if ! env::is_simple_output_enabled; then - echo "" + progress::blank_line fi } @@ -164,13 +164,16 @@ function runner::render_running_file_header() { fi if ! env::is_simple_output_enabled; then - if env::is_verbose_enabled; then - printf "\n${_COLOR_BOLD}%s${_COLOR_DEFAULT}\n" "Running $script" - else - printf "${_COLOR_BOLD}%s${_COLOR_DEFAULT}\n" "Running $script" - fi - elif env::is_verbose_enabled; then - printf "\n\n${_COLOR_BOLD}%s${_COLOR_DEFAULT}" "Running $script" + if env::is_verbose_enabled; then + progress::blank_line + printf "${_COLOR_BOLD}%s${_COLOR_DEFAULT}\n" "Running $script" + else + printf "${_COLOR_BOLD}%s${_COLOR_DEFAULT}\n" "Running $script" + fi + elif env::is_verbose_enabled; then + progress::blank_line + progress::blank_line + printf "${_COLOR_BOLD}%s${_COLOR_DEFAULT}" "Running $script" fi } @@ -230,7 +233,7 @@ function runner::run_test() { if env::is_verbose_enabled; then if env::is_simple_output_enabled; then - echo "" + progress::blank_line fi printf '%*s\n' "$TERMINAL_WIDTH" '' | tr ' ' '=' @@ -283,7 +286,8 @@ function runner::run_test() { if [[ -n $runtime_error || $test_exit_code -ne 0 ]]; then state::add_tests_failed - console_results::print_error_test "$fn_name" "$runtime_error" + console_results::print_error_test "$fn_name" "$runtime_error" "$duration" + console_results::print_failed_test_summary "$fn_name" "$duration" reports::add_test_failed "$test_file" "$fn_name" "$duration" "$total_assertions" runner::write_failure_result_output "$test_file" "$runtime_error" return @@ -291,6 +295,7 @@ function runner::run_test() { if [[ "$current_assertions_failed" != "$(state::get_assertions_failed)" ]]; then state::add_tests_failed + console_results::print_failed_test_summary "$fn_name" "$duration" reports::add_test_failed "$test_file" "$fn_name" "$duration" "$total_assertions" runner::write_failure_result_output "$test_file" "$subshell_output" @@ -306,19 +311,21 @@ function runner::run_test() { if [[ "$current_assertions_snapshot" != "$(state::get_assertions_snapshot)" ]]; then state::add_tests_snapshot - console_results::print_snapshot_test "$fn_name" + console_results::print_snapshot_test "$fn_name" "$duration" reports::add_test_snapshot "$test_file" "$fn_name" "$duration" "$total_assertions" return fi if [[ "$current_assertions_incomplete" != "$(state::get_assertions_incomplete)" ]]; then state::add_tests_incomplete + console_results::print_incomplete_test "$fn_name" "" "$duration" reports::add_test_incomplete "$test_file" "$fn_name" "$duration" "$total_assertions" return fi if [[ "$current_assertions_skipped" != "$(state::get_assertions_skipped)" ]]; then state::add_tests_skipped + console_results::print_skipped_test "$fn_name" "" "$duration" reports::add_test_skipped "$test_file" "$fn_name" "$duration" "$total_assertions" return fi diff --git a/src/state.sh b/src/state.sh index 8d8fc7ed..8841560c 100644 --- a/src/state.sh +++ b/src/state.sh @@ -15,6 +15,15 @@ _FILE_WITH_DUPLICATED_FUNCTION_NAMES="" _DUPLICATED_TEST_FUNCTIONS_FOUND=false _TEST_OUTPUT="" _TEST_EXIT_CODE=0 +_TOTAL_TESTS_TO_RUN=0 + +function state::set_total_tests_to_run() { + _TOTAL_TESTS_TO_RUN=$1 +} + +function state::get_total_tests_to_run() { + echo "$_TOTAL_TESTS_TO_RUN" +} function state::get_tests_passed() { echo "$_TESTS_PASSED" @@ -195,6 +204,7 @@ function state::print_line() { if ! env::is_simple_output_enabled; then printf "%s\n" "$line" + progress::render "$_TOTAL_TESTS_COUNT" "$(state::get_total_tests_to_run)" return fi @@ -220,4 +230,6 @@ function state::print_line() { printf "%s" "$char" fi fi + + progress::render "$_TOTAL_TESTS_COUNT" "$(state::get_total_tests_to_run)" } diff --git a/tests/acceptance/snapshots/bashunit_exit_code_test_sh.test_bashunit_when_a_test_returns_non_zero.snapshot b/tests/acceptance/snapshots/bashunit_exit_code_test_sh.test_bashunit_when_a_test_returns_non_zero.snapshot index 4b3dbae2..59887a6a 100644 --- a/tests/acceptance/snapshots/bashunit_exit_code_test_sh.test_bashunit_when_a_test_returns_non_zero.snapshot +++ b/tests/acceptance/snapshots/bashunit_exit_code_test_sh.test_bashunit_when_a_test_returns_non_zero.snapshot @@ -1,6 +1,7 @@ Running tests/acceptance/fixtures/test_bashunit_when_a_test_returns_non_zero.sh ✗ Error: Returns non zero  +✗ Failed: test_returns_non_zero There was 1 failure: diff --git a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_env.snapshot b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_env.snapshot index f1c6b334..97b097ab 100644 --- a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_env.snapshot +++ b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_env.snapshot @@ -1,4 +1,4 @@ -..F.. +..FF.. There was 1 failure: diff --git a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_option.snapshot b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_option.snapshot index f1c6b334..97b097ab 100644 --- a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_option.snapshot +++ b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_option.snapshot @@ -1,4 +1,4 @@ -..F.. +..FF.. There was 1 failure: diff --git a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_verbose_output_env.snapshot b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_verbose_output_env.snapshot index 3b2767ac..a7fa80bd 100644 --- a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_verbose_output_env.snapshot +++ b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_verbose_output_env.snapshot @@ -4,6 +4,7 @@ ✗ Failed: Assert failing Expected '1' but got  '0' +✗ Failed: test_assert_failing ✓ Passed: Assert greater and less than ✓ Passed: Assert empty diff --git a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_verbose_output_option.snapshot b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_verbose_output_option.snapshot index 3b2767ac..a7fa80bd 100644 --- a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_verbose_output_option.snapshot +++ b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_verbose_output_option.snapshot @@ -4,6 +4,7 @@ ✗ Failed: Assert failing Expected '1' but got  '0' +✗ Failed: test_assert_failing ✓ Passed: Assert greater and less than ✓ Passed: Assert empty diff --git a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_with_a_test_fail_and_exit_immediately.snapshot b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_with_a_test_fail_and_exit_immediately.snapshot index 44ecfe42..2b209317 100644 --- a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_with_a_test_fail_and_exit_immediately.snapshot +++ b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_with_a_test_fail_and_exit_immediately.snapshot @@ -1,6 +1,7 @@ Running ./tests/acceptance/fixtures/test_bashunit_when_exit_immediately_after_execution_error.sh ✗ Error: Error  +✗ Failed: test_error There was 1 failure: diff --git a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_with_multiple_failing_tests.snapshot b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_with_multiple_failing_tests.snapshot index 16777156..a9351f59 100644 --- a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_with_multiple_failing_tests.snapshot +++ b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_with_multiple_failing_tests.snapshot @@ -6,10 +6,13 @@ ✗ Failed: Assert failing Expected '3' but got  '4' +✗ Failed: test_assert_failing ✒ Incomplete: Assert todo and skip foo ↷ Skipped: Assert todo and skip bar +✒ Incomplete: test_assert_todo_and_skip ↷ Skipped: Assert skip and todo baz ✒ Incomplete: Assert skip and todo yei +✒ Incomplete: test_assert_skip_and_todo There was 1 failure: diff --git a/tests/acceptance/snapshots/bashunit_log_junit_test_sh.test_bashunit_when_log_junit_env.snapshot b/tests/acceptance/snapshots/bashunit_log_junit_test_sh.test_bashunit_when_log_junit_env.snapshot index c5a8817d..7e475a7b 100644 --- a/tests/acceptance/snapshots/bashunit_log_junit_test_sh.test_bashunit_when_log_junit_env.snapshot +++ b/tests/acceptance/snapshots/bashunit_log_junit_test_sh.test_bashunit_when_log_junit_env.snapshot @@ -3,6 +3,7 @@ ✗ Failed: Failure Expected '2' but got  '3' +✗ Failed: test_failure There was 1 failure: diff --git a/tests/acceptance/snapshots/bashunit_log_junit_test_sh.test_bashunit_when_log_junit_option.snapshot b/tests/acceptance/snapshots/bashunit_log_junit_test_sh.test_bashunit_when_log_junit_option.snapshot index c5a8817d..7e475a7b 100644 --- a/tests/acceptance/snapshots/bashunit_log_junit_test_sh.test_bashunit_when_log_junit_option.snapshot +++ b/tests/acceptance/snapshots/bashunit_log_junit_test_sh.test_bashunit_when_log_junit_option.snapshot @@ -3,6 +3,7 @@ ✗ Failed: Failure Expected '2' but got  '3' +✗ Failed: test_failure There was 1 failure: diff --git a/tests/acceptance/snapshots/bashunit_report_html_test_sh.test_bashunit_when_report_html_env.snapshot b/tests/acceptance/snapshots/bashunit_report_html_test_sh.test_bashunit_when_report_html_env.snapshot index deab502d..09b522a8 100644 --- a/tests/acceptance/snapshots/bashunit_report_html_test_sh.test_bashunit_when_report_html_env.snapshot +++ b/tests/acceptance/snapshots/bashunit_report_html_test_sh.test_bashunit_when_report_html_env.snapshot @@ -3,8 +3,11 @@ ✗ Failed: Fail Expected 'to be empty' but got  'non empty' +✗ Failed: test_fail ↷ Skipped: Skipped +↷ Skipped: test_skipped ✒ Incomplete: Todo +✒ Incomplete: test_todo There was 1 failure: diff --git a/tests/acceptance/snapshots/bashunit_report_html_test_sh.test_bashunit_when_report_html_option.snapshot b/tests/acceptance/snapshots/bashunit_report_html_test_sh.test_bashunit_when_report_html_option.snapshot index deab502d..09b522a8 100644 --- a/tests/acceptance/snapshots/bashunit_report_html_test_sh.test_bashunit_when_report_html_option.snapshot +++ b/tests/acceptance/snapshots/bashunit_report_html_test_sh.test_bashunit_when_report_html_option.snapshot @@ -3,8 +3,11 @@ ✗ Failed: Fail Expected 'to be empty' but got  'non empty' +✗ Failed: test_fail ↷ Skipped: Skipped +↷ Skipped: test_skipped ✒ Incomplete: Todo +✒ Incomplete: test_todo There was 1 failure: diff --git a/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_env.snapshot b/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_env.snapshot index 4b7f2bd4..f7924fcc 100644 --- a/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_env.snapshot +++ b/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_env.snapshot @@ -3,6 +3,7 @@ ✗ Failed: B error Expected '1' but got  '2' +✗ Failed: test_b_error Stop on failure enabled... There was 1 failure: diff --git a/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_env_simple_output.snapshot b/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_env_simple_output.snapshot index bccd2609..d21cc275 100644 --- a/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_env_simple_output.snapshot +++ b/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_env_simple_output.snapshot @@ -1,4 +1,4 @@ -.F +.FF Stop on failure enabled... diff --git a/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_option.snapshot b/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_option.snapshot index 4b7f2bd4..f7924fcc 100644 --- a/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_option.snapshot +++ b/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_option.snapshot @@ -3,6 +3,7 @@ ✗ Failed: B error Expected '1' but got  '2' +✗ Failed: test_b_error Stop on failure enabled... There was 1 failure: diff --git a/tests/unit/directory_test.sh b/tests/unit/directory_test.sh index eeb26046..b5424f1b 100644 --- a/tests/unit/directory_test.sh +++ b/tests/unit/directory_test.sh @@ -114,6 +114,10 @@ function test_unsuccessful_assert_is_directory_readable_without_execution_permis if [[ "$_OS" == "Windows" || $_DISTRO = "Alpine" ]]; then return fi + if [[ $(id -u) -eq 0 ]]; then + skip "Running as root" + return + fi local a_directory=$(mktemp -d) chmod a-x "$a_directory" @@ -129,6 +133,10 @@ function test_unsuccessful_assert_is_directory_readable_without_read_permission( if [[ "$_OS" == "Windows" || $_DISTRO = "Alpine" ]]; then return fi + if [[ $(id -u) -eq 0 ]]; then + skip "Running as root" + return + fi local a_directory=$(mktemp -d) chmod a-r "$a_directory" @@ -144,6 +152,10 @@ function test_successful_assert_is_directory_not_readable_without_read_permissio if [[ "$_OS" == "Windows" || $_DISTRO = "Alpine" ]]; then return fi + if [[ $(id -u) -eq 0 ]]; then + skip "Running as root" + return + fi local a_directory=$(mktemp -d) chmod a-r "$a_directory" @@ -155,6 +167,10 @@ function test_successful_assert_is_directory_not_readable_without_execution_perm if [[ "$_OS" == "Windows" || $_DISTRO = "Alpine" ]]; then return fi + if [[ $(id -u) -eq 0 ]]; then + skip "Running as root" + return + fi local a_directory=$(mktemp -d) chmod a-x "$a_directory" @@ -181,6 +197,10 @@ function test_unsuccessful_assert_is_directory_writable() { if [[ "$_OS" == "Windows" || $_DISTRO = "Alpine" ]]; then return fi + if [[ $(id -u) -eq 0 ]]; then + skip "Running as root" + return + fi local a_directory=$(mktemp -d) chmod a-w "$a_directory" @@ -205,6 +225,10 @@ function test_successful_assert_is_directory_not_writable() { if [[ "$_OS" == "Windows" || $_DISTRO = "Alpine" ]]; then return fi + if [[ $(id -u) -eq 0 ]]; then + skip "Running as root" + return + fi local a_directory=$(mktemp -d) chmod a-w "$a_directory" From d176a87f8a157f4746d5a62427b901dff7e63179 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 14:08:42 +0200 Subject: [PATCH 02/14] fix: lint --- src/progress.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/progress.sh b/src/progress.sh index 4bcb0b16..9e7b70d8 100644 --- a/src/progress.sh +++ b/src/progress.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash function progress::init() { - PROGRESS_TOTAL=$1 + export PROGRESS_TOTAL=$1 if parallel::is_enabled || [[ ! -t 1 ]] || ! env::is_progress_enabled; then _PROGRESS_ENABLED=false From 9929fbec3c8cdccfb7baa981f661c5a0e26b285a Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 15:13:16 +0200 Subject: [PATCH 03/14] fix: wrong empty lines --- src/benchmark.sh | 3 +++ src/main.sh | 3 +++ src/progress.sh | 15 +++++++++++++-- src/runner.sh | 4 ++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/benchmark.sh b/src/benchmark.sh index 15dc652c..d6ba623e 100644 --- a/src/benchmark.sh +++ b/src/benchmark.sh @@ -101,6 +101,9 @@ function benchmark::print_results() { printf "Benchmark Results (avg ms)\n" print_line 80 "=" progress::blank_line + if env::is_simple_output_enabled; then + progress::refresh + fi local has_threshold=false for val in "${_BENCH_MAX_MILLIS[@]}"; do diff --git a/src/main.sh b/src/main.sh index 6b9a4c52..68e554b1 100644 --- a/src/main.sh +++ b/src/main.sh @@ -49,6 +49,9 @@ function main::exec_tests() { printf '%*s\n' "$TERMINAL_WIDTH" '' | tr ' ' '.' env::print_verbose printf '%*s\n' "$TERMINAL_WIDTH" '' | tr ' ' '#' + if env::is_simple_output_enabled; then + progress::refresh + fi fi runner::load_test_files "$filter" "${test_files[@]}" diff --git a/src/progress.sh b/src/progress.sh index 9e7b70d8..e3bd32e6 100644 --- a/src/progress.sh +++ b/src/progress.sh @@ -2,6 +2,8 @@ function progress::init() { export PROGRESS_TOTAL=$1 + # Track the last rendered progress state so the bar can be redrawn + export PROGRESS_CURRENT=0 if parallel::is_enabled || [[ ! -t 1 ]] || ! env::is_progress_enabled; then _PROGRESS_ENABLED=false @@ -15,6 +17,8 @@ function progress::render() { local current=$1 local total=$2 + PROGRESS_CURRENT=$current + if [[ "$_PROGRESS_ENABLED" != true ]]; then return fi @@ -63,10 +67,17 @@ function progress::finish() { if command -v tput > /dev/null; then tput sc tput cup $(( $(tput lines) - 1 )) 0 - printf '%*s\n' "$TERMINAL_WIDTH" '' + printf '%*s' "$TERMINAL_WIDTH" '' tput rc else - printf '\n' + printf '\r%-*s' "$TERMINAL_WIDTH" '' + fi +} + +# Re-render the last progress bar if progress display is enabled +function progress::refresh() { + if [[ "$_PROGRESS_ENABLED" == true ]]; then + progress::render "$PROGRESS_CURRENT" "$PROGRESS_TOTAL" fi } diff --git a/src/runner.sh b/src/runner.sh index e2e3a044..7ce76f0e 100755 --- a/src/runner.sh +++ b/src/runner.sh @@ -174,6 +174,10 @@ function runner::render_running_file_header() { progress::blank_line progress::blank_line printf "${_COLOR_BOLD}%s${_COLOR_DEFAULT}" "Running $script" + fi + + if env::is_simple_output_enabled && env::is_verbose_enabled; then + progress::refresh fi } From 0b5ccf83d39492928ed4a8f2be8ffa22aaafb5ab Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 15:22:30 +0200 Subject: [PATCH 04/14] docs: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b385e762..771e455f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Add project overview docs - Improve clock performance - Make install.sh args more flexible +- Add progress bar to non-parallel runner ## [0.20.0](https://github.com/TypedDevs/bashunit/compare/0.19.1...0.20.0) - 2025-06-01 From 4b251c06e4d25d765f9b0c994e6b01655aba7c6d Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 15:28:13 +0200 Subject: [PATCH 05/14] fix: remove empty line after initial version line --- src/progress.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/progress.sh b/src/progress.sh index e3bd32e6..ee3706f4 100644 --- a/src/progress.sh +++ b/src/progress.sh @@ -9,7 +9,7 @@ function progress::init() { _PROGRESS_ENABLED=false else _PROGRESS_ENABLED=true - progress::blank_line + progress::render 0 "$PROGRESS_TOTAL" fi } From 11277f619312ea3d2305df8afd121213e9d49040 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 15:39:25 +0200 Subject: [PATCH 06/14] fix: remove extra new line on runner::spinner() --- src/runner.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/runner.sh b/src/runner.sh index 7ce76f0e..296f6f7f 100755 --- a/src/runner.sh +++ b/src/runner.sh @@ -50,10 +50,6 @@ function runner::load_bench_files() { } function runner::spinner() { - if env::is_simple_output_enabled; then - progress::blank_line - fi - local delay=0.1 local spin_chars="|/-\\" while true; do From 60ac81e7ccfdb2a18005cc555bed93db1132042d Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 17:31:10 +0200 Subject: [PATCH 07/14] chore: disable progress bar by default --- bashunit | 3 +++ docs/command-line.md | 12 ++++++++++++ docs/configuration.md | 12 ++++++++++++ src/env.sh | 2 +- src/progress.sh | 2 +- 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/bashunit b/bashunit index 7ee7d658..77090b37 100755 --- a/bashunit +++ b/bashunit @@ -64,6 +64,9 @@ while [[ $# -gt 0 ]]; do fi set -x ;; + -pb|--progress-bar) + export BASHUNIT_PROGRESS=true + ;; -b|--bench) _BENCH_MODE=true export BASHUNIT_BENCH_MODE=true diff --git a/docs/command-line.md b/docs/command-line.md index 5f68c40c..548c47d8 100644 --- a/docs/command-line.md +++ b/docs/command-line.md @@ -340,6 +340,18 @@ Duration: 48 ms ``` ::: +## Progress bar + +> `bashunit -pb|--progress-bar` + +Enable the progress bar during test execution. By default, the progress bar is disabled. + +::: code-group +```bash [Example] +./bashunit --progress-bar +``` +::: + ## Version > `bashunit --version` diff --git a/docs/configuration.md b/docs/configuration.md index 59819fdc..7407077c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -247,6 +247,18 @@ BASHUNIT_VERBOSE=true ``` ::: +## Progress bar + +> `BASHUNIT_PROGRESS=true|false` + +Controls whether the progress bar is rendered. `false` by default. + +::: code-group +```bash [Example] +BASHUNIT_PROGRESS=true +``` +::: + diff --git a/src/env.sh b/src/env.sh index c4a24d41..ce0b50bd 100644 --- a/src/env.sh +++ b/src/env.sh @@ -28,7 +28,7 @@ _DEFAULT_STOP_ON_FAILURE="false" _DEFAULT_SHOW_EXECUTION_TIME="true" _DEFAULT_VERBOSE="false" _DEFAULT_BENCH_MODE="false" -_DEFAULT_PROGRESS="true" +_DEFAULT_PROGRESS="false" # Controls if the progress bar should render during execution _PROGRESS_ENABLED=true diff --git a/src/progress.sh b/src/progress.sh index ee3706f4..3e3e8af9 100644 --- a/src/progress.sh +++ b/src/progress.sh @@ -77,7 +77,7 @@ function progress::finish() { # Re-render the last progress bar if progress display is enabled function progress::refresh() { if [[ "$_PROGRESS_ENABLED" == true ]]; then - progress::render "$PROGRESS_CURRENT" "$PROGRESS_TOTAL" + progress::render "${PROGRESS_CURRENT:-}" "${PROGRESS_TOTAL:-}" fi } From f10c444b5d8eb0ec0e117a539aa7ff5772c7fc78 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 17:33:03 +0200 Subject: [PATCH 08/14] refactor: use BASHUNIT_PROGRESS_BAR instead of just PROGRESS --- bashunit | 2 +- docs/configuration.md | 4 ++-- src/env.sh | 8 ++++---- src/progress.sh | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bashunit b/bashunit index 77090b37..0091b481 100755 --- a/bashunit +++ b/bashunit @@ -65,7 +65,7 @@ while [[ $# -gt 0 ]]; do set -x ;; -pb|--progress-bar) - export BASHUNIT_PROGRESS=true + export BASHUNIT_PROGRESS_BAR=true ;; -b|--bench) _BENCH_MODE=true diff --git a/docs/configuration.md b/docs/configuration.md index 7407077c..a9f796af 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -249,13 +249,13 @@ BASHUNIT_VERBOSE=true ## Progress bar -> `BASHUNIT_PROGRESS=true|false` +> `BASHUNIT_PROGRESS_BAR=true|false` Controls whether the progress bar is rendered. `false` by default. ::: code-group ```bash [Example] -BASHUNIT_PROGRESS=true +BASHUNIT_PROGRESS_BAR=true ``` ::: diff --git a/src/env.sh b/src/env.sh index ce0b50bd..37139f63 100644 --- a/src/env.sh +++ b/src/env.sh @@ -28,7 +28,7 @@ _DEFAULT_STOP_ON_FAILURE="false" _DEFAULT_SHOW_EXECUTION_TIME="true" _DEFAULT_VERBOSE="false" _DEFAULT_BENCH_MODE="false" -_DEFAULT_PROGRESS="false" +_DEFAULT_PROGRESS_BAR="false" # Controls if the progress bar should render during execution _PROGRESS_ENABLED=true @@ -41,7 +41,7 @@ _PROGRESS_ENABLED=true : "${BASHUNIT_SHOW_EXECUTION_TIME:=${SHOW_EXECUTION_TIME:=$_DEFAULT_SHOW_EXECUTION_TIME}}" : "${BASHUNIT_VERBOSE:=${VERBOSE:=$_DEFAULT_VERBOSE}}" : "${BASHUNIT_BENCH_MODE:=${BENCH_MODE:=$_DEFAULT_BENCH_MODE}}" -: "${BASHUNIT_PROGRESS:=${PROGRESS:=$_DEFAULT_PROGRESS}}" +: "${BASHUNIT_PROGRESS_BAR:=${PROGRESS_BAR:=$_DEFAULT_PROGRESS_BAR}}" function env::is_parallel_run_enabled() { [[ "$BASHUNIT_PARALLEL_RUN" == "true" ]] @@ -79,8 +79,8 @@ function env::is_bench_mode_enabled() { [[ "$BASHUNIT_BENCH_MODE" == "true" ]] } -function env::is_progress_enabled() { - [[ "$BASHUNIT_PROGRESS" == "true" ]] +function env::is_progress_bar_enabled() { + [[ "$BASHUNIT_PROGRESS_BAR" == "true" ]] } function env::active_internet_connection() { diff --git a/src/progress.sh b/src/progress.sh index 3e3e8af9..7ad7bf1b 100644 --- a/src/progress.sh +++ b/src/progress.sh @@ -5,7 +5,7 @@ function progress::init() { # Track the last rendered progress state so the bar can be redrawn export PROGRESS_CURRENT=0 - if parallel::is_enabled || [[ ! -t 1 ]] || ! env::is_progress_enabled; then + if parallel::is_enabled || [[ ! -t 1 ]] || ! env::is_progress_bar_enabled; then _PROGRESS_ENABLED=false else _PROGRESS_ENABLED=true From 2d487107aa4f8b32b98aac97c16fd2b2b3f85fdd Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 17:36:06 +0200 Subject: [PATCH 09/14] refactor: progress.sh extract progress::enabled() --- src/progress.sh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/progress.sh b/src/progress.sh index 7ad7bf1b..8e473856 100644 --- a/src/progress.sh +++ b/src/progress.sh @@ -1,14 +1,15 @@ #!/usr/bin/env bash +function progress::enabled() { + env::is_progress_bar_enabled && ! parallel::is_enabled +} + function progress::init() { export PROGRESS_TOTAL=$1 # Track the last rendered progress state so the bar can be redrawn export PROGRESS_CURRENT=0 - if parallel::is_enabled || [[ ! -t 1 ]] || ! env::is_progress_bar_enabled; then - _PROGRESS_ENABLED=false - else - _PROGRESS_ENABLED=true + if progress::enabled ; then progress::render 0 "$PROGRESS_TOTAL" fi } @@ -19,7 +20,7 @@ function progress::render() { PROGRESS_CURRENT=$current - if [[ "$_PROGRESS_ENABLED" != true ]]; then + if ! progress::enabled ; then return fi @@ -60,7 +61,7 @@ function progress::render() { } function progress::finish() { - if [[ "$_PROGRESS_ENABLED" != true ]]; then + if ! progress::enabled ; then return fi @@ -76,7 +77,7 @@ function progress::finish() { # Re-render the last progress bar if progress display is enabled function progress::refresh() { - if [[ "$_PROGRESS_ENABLED" == true ]]; then + if progress::enabled ; then progress::render "${PROGRESS_CURRENT:-}" "${PROGRESS_TOTAL:-}" fi } From db90663bb4e69cbe7ac89507cc474e149456c0ff Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 17:46:21 +0200 Subject: [PATCH 10/14] docs: add --progress-bar to help output --- src/console_header.sh | 3 +++ ...est_sh.test_bashunit_without_path_env_nor_argument.snapshot | 3 +++ ...bashunit_test_sh.test_bashunit_should_display_help.snapshot | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/console_header.sh b/src/console_header.sh index 0e912e72..2e31916f 100644 --- a/src/console_header.sh +++ b/src/console_header.sh @@ -75,6 +75,9 @@ Options: -p, --parallel || --no-parallel [default] Run each test in child process, randomizing the tests execution order. + -pb, --progress-bar + Display a real-time progress bar during test execution. Requires a TTY and disables parallel mode. + -r, --report-html Create a report HTML file that contains information about the test results. diff --git a/tests/acceptance/snapshots/bashunit_path_test_sh.test_bashunit_without_path_env_nor_argument.snapshot b/tests/acceptance/snapshots/bashunit_path_test_sh.test_bashunit_without_path_env_nor_argument.snapshot index b43fb469..c325f738 100644 --- a/tests/acceptance/snapshots/bashunit_path_test_sh.test_bashunit_without_path_env_nor_argument.snapshot +++ b/tests/acceptance/snapshots/bashunit_path_test_sh.test_bashunit_without_path_env_nor_argument.snapshot @@ -22,6 +22,9 @@ Options: -p, --parallel || --no-parallel [default] Run each test in child process, randomizing the tests execution order. + -pb, --progress-bar + Display a real-time progress bar during test execution. Requires a TTY and disables parallel mode. + -r, --report-html Create a report HTML file that contains information about the test results. diff --git a/tests/acceptance/snapshots/bashunit_test_sh.test_bashunit_should_display_help.snapshot b/tests/acceptance/snapshots/bashunit_test_sh.test_bashunit_should_display_help.snapshot index 43dd8ec2..de03850c 100644 --- a/tests/acceptance/snapshots/bashunit_test_sh.test_bashunit_should_display_help.snapshot +++ b/tests/acceptance/snapshots/bashunit_test_sh.test_bashunit_should_display_help.snapshot @@ -21,6 +21,9 @@ Options: -p, --parallel || --no-parallel [default] Run each test in child process, randomizing the tests execution order. + -pb, --progress-bar + Display a real-time progress bar during test execution. Requires a TTY and disables parallel mode. + -r, --report-html Create a report HTML file that contains information about the test results. From 2734c70f6d579355b71e402076b646a399e1eee2 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 17:51:56 +0200 Subject: [PATCH 11/14] chore: warning when enabling progress-bar when running in parallel --- docs/command-line.md | 4 ++++ docs/configuration.md | 4 ++++ src/progress.sh | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/docs/command-line.md b/docs/command-line.md index 548c47d8..eb82daf5 100644 --- a/docs/command-line.md +++ b/docs/command-line.md @@ -346,6 +346,10 @@ Duration: 48 ms Enable the progress bar during test execution. By default, the progress bar is disabled. +::: warning +The progress bar cannot be used when running tests in parallel. If `--progress-bar` is combined with `--parallel`, a warning is printed and the bar is disabled. +::: + ::: code-group ```bash [Example] ./bashunit --progress-bar diff --git a/docs/configuration.md b/docs/configuration.md index a9f796af..c59f9675 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -253,6 +253,10 @@ BASHUNIT_VERBOSE=true Controls whether the progress bar is rendered. `false` by default. +::: warning +The progress bar is disabled when tests run in parallel. Enabling `BASHUNIT_PROGRESS_BAR` while `BASHUNIT_PARALLEL_RUN` is `true` will print a warning and no bar will be shown. +::: + ::: code-group ```bash [Example] BASHUNIT_PROGRESS_BAR=true diff --git a/src/progress.sh b/src/progress.sh index 8e473856..a0b71083 100644 --- a/src/progress.sh +++ b/src/progress.sh @@ -9,6 +9,10 @@ function progress::init() { # Track the last rendered progress state so the bar can be redrawn export PROGRESS_CURRENT=0 + if env::is_progress_bar_enabled && parallel::is_enabled; then + printf "%sWarning: Progress bar is not supported in parallel mode.%s\n" "${_COLOR_INCOMPLETE}" "${_COLOR_DEFAULT}" + fi + if progress::enabled ; then progress::render 0 "$PROGRESS_TOTAL" fi From b4db09f6a8222ae0d4c718fe3a61d338ba802264 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 18:09:47 +0200 Subject: [PATCH 12/14] fix: runner::spinner new line display --- src/console_results.sh | 1 - src/env.sh | 3 --- src/runner.sh | 8 +++++++- ...rk_test_sh.test_bashunit_functional_benchmark.snapshot | 5 ----- ...ark_test_sh.test_bashunit_runs_benchmark_file.snapshot | 7 ------- ...t_bashunit_when_a_test_fail_simple_output_env.snapshot | 1 - ...ashunit_when_a_test_fail_simple_output_option.snapshot | 1 - ...bashunit_when_a_test_passes_simple_output_env.snapshot | 1 - ...hunit_when_a_test_passes_simple_output_option.snapshot | 1 - ...shunit_when_stop_on_failure_env_simple_output.snapshot | 1 - 10 files changed, 7 insertions(+), 22 deletions(-) delete mode 100644 tests/acceptance/snapshots/bashunit_benchmark_test_sh.test_bashunit_functional_benchmark.snapshot delete mode 100644 tests/acceptance/snapshots/bashunit_benchmark_test_sh.test_bashunit_runs_benchmark_file.snapshot diff --git a/src/console_results.sh b/src/console_results.sh index 5de26cd7..468a747c 100644 --- a/src/console_results.sh +++ b/src/console_results.sh @@ -14,7 +14,6 @@ function console_results::render_result() { if env::is_simple_output_enabled; then progress::blank_line - progress::blank_line fi local total_tests=0 diff --git a/src/env.sh b/src/env.sh index 37139f63..2ede2472 100644 --- a/src/env.sh +++ b/src/env.sh @@ -30,9 +30,6 @@ _DEFAULT_VERBOSE="false" _DEFAULT_BENCH_MODE="false" _DEFAULT_PROGRESS_BAR="false" -# Controls if the progress bar should render during execution -_PROGRESS_ENABLED=true - : "${BASHUNIT_PARALLEL_RUN:=${PARALLEL_RUN:=$_DEFAULT_PARALLEL_RUN}}" : "${BASHUNIT_SHOW_HEADER:=${SHOW_HEADER:=$_DEFAULT_SHOW_HEADER}}" : "${BASHUNIT_HEADER_ASCII_ART:=${HEADER_ASCII_ART:=$_DEFAULT_HEADER_ASCII_ART}}" diff --git a/src/runner.sh b/src/runner.sh index 296f6f7f..9c5ed5da 100755 --- a/src/runner.sh +++ b/src/runner.sh @@ -48,10 +48,16 @@ function runner::load_bench_files() { runner::clean_set_up_and_tear_down_after_script done } - function runner::spinner() { + if env::is_simple_output_enabled; then + printf "\n" + fi + local delay=0.1 local spin_chars="|/-\\" + + trap 'printf "\r \r"' EXIT + while true; do for ((i=0; i<${#spin_chars}; i++)); do printf "\r%s" "${spin_chars:$i:1}" diff --git a/tests/acceptance/snapshots/bashunit_benchmark_test_sh.test_bashunit_functional_benchmark.snapshot b/tests/acceptance/snapshots/bashunit_benchmark_test_sh.test_bashunit_functional_benchmark.snapshot deleted file mode 100644 index ebdd70f1..00000000 --- a/tests/acceptance/snapshots/bashunit_benchmark_test_sh.test_bashunit_functional_benchmark.snapshot +++ /dev/null @@ -1,5 +0,0 @@ -. - -Benchmark Results (avg ms) -Name Revs Its Avg(ms) -bench_run_bashunit_functional 2 1 ::ignore:: diff --git a/tests/acceptance/snapshots/bashunit_benchmark_test_sh.test_bashunit_runs_benchmark_file.snapshot b/tests/acceptance/snapshots/bashunit_benchmark_test_sh.test_bashunit_runs_benchmark_file.snapshot deleted file mode 100644 index fcecaece..00000000 --- a/tests/acceptance/snapshots/bashunit_benchmark_test_sh.test_bashunit_runs_benchmark_file.snapshot +++ /dev/null @@ -1,7 +0,0 @@ -bench bench_sleep [1/2] ::ignore:: -bench bench_sleep [2/2] ::ignore:: - - -Benchmark Results (avg ms) -Name Revs Its Avg(ms) -bench_sleep 5 2 ::ignore:: diff --git a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_env.snapshot b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_env.snapshot index 97b097ab..8fdad5fb 100644 --- a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_env.snapshot +++ b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_env.snapshot @@ -8,7 +8,6 @@ | but got  '0' - Tests:  4 passed, 1 failed, 5 total Assertions: 6 passed, 1 failed, 7 total diff --git a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_option.snapshot b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_option.snapshot index 97b097ab..8fdad5fb 100644 --- a/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_option.snapshot +++ b/tests/acceptance/snapshots/bashunit_fail_test_sh.test_bashunit_when_a_test_fail_simple_output_option.snapshot @@ -8,7 +8,6 @@ | but got  '0' - Tests:  4 passed, 1 failed, 5 total Assertions: 6 passed, 1 failed, 7 total diff --git a/tests/acceptance/snapshots/bashunit_pass_test_sh.test_bashunit_when_a_test_passes_simple_output_env.snapshot b/tests/acceptance/snapshots/bashunit_pass_test_sh.test_bashunit_when_a_test_passes_simple_output_env.snapshot index da114271..3d4daf1d 100644 --- a/tests/acceptance/snapshots/bashunit_pass_test_sh.test_bashunit_when_a_test_passes_simple_output_env.snapshot +++ b/tests/acceptance/snapshots/bashunit_pass_test_sh.test_bashunit_when_a_test_passes_simple_output_env.snapshot @@ -1,5 +1,4 @@ .... - Tests:  4 passed, 4 total Assertions: 6 passed, 6 total diff --git a/tests/acceptance/snapshots/bashunit_pass_test_sh.test_bashunit_when_a_test_passes_simple_output_option.snapshot b/tests/acceptance/snapshots/bashunit_pass_test_sh.test_bashunit_when_a_test_passes_simple_output_option.snapshot index da114271..3d4daf1d 100644 --- a/tests/acceptance/snapshots/bashunit_pass_test_sh.test_bashunit_when_a_test_passes_simple_output_option.snapshot +++ b/tests/acceptance/snapshots/bashunit_pass_test_sh.test_bashunit_when_a_test_passes_simple_output_option.snapshot @@ -1,5 +1,4 @@ .... - Tests:  4 passed, 4 total Assertions: 6 passed, 6 total diff --git a/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_env_simple_output.snapshot b/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_env_simple_output.snapshot index d21cc275..5b218515 100644 --- a/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_env_simple_output.snapshot +++ b/tests/acceptance/snapshots/bashunit_stop_on_failure_test_sh.test_bashunit_when_stop_on_failure_env_simple_output.snapshot @@ -10,7 +10,6 @@ | but got  '2' - Tests:  1 passed, 1 failed, 2 total Assertions: 3 passed, 1 failed, 4 total From b244d3e5f90df9d6058af00d5d58f5304d0487ac Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 18:41:46 +0200 Subject: [PATCH 13/14] refactor: progress.sh --- src/console_results.sh | 1 - src/progress.sh | 66 ++++++++++++++++++++---------------------- 2 files changed, 32 insertions(+), 35 deletions(-) diff --git a/src/console_results.sh b/src/console_results.sh index 468a747c..12490eb5 100644 --- a/src/console_results.sh +++ b/src/console_results.sh @@ -149,7 +149,6 @@ function console_results::print_successful_test() { state::print_line "successful" "$full_line" } -# Print a summary line for a failed test with its duration. function console_results::print_failed_test_summary() { local test_name=$1 local duration=${2:-"0"} diff --git a/src/progress.sh b/src/progress.sh index a0b71083..b0f0e86f 100644 --- a/src/progress.sh +++ b/src/progress.sh @@ -1,60 +1,58 @@ #!/usr/bin/env bash +# Check if progress bar is enabled and not in parallel mode function progress::enabled() { env::is_progress_bar_enabled && ! parallel::is_enabled } +# Initialize progress tracking variables and optionally render the first bar function progress::init() { export PROGRESS_TOTAL=$1 - # Track the last rendered progress state so the bar can be redrawn export PROGRESS_CURRENT=0 if env::is_progress_bar_enabled && parallel::is_enabled; then - printf "%sWarning: Progress bar is not supported in parallel mode.%s\n" "${_COLOR_INCOMPLETE}" "${_COLOR_DEFAULT}" + printf "%sWarning: Progress bar is not supported in parallel mode.%s\n" \ + "${_COLOR_INCOMPLETE}" "${_COLOR_DEFAULT}" fi - if progress::enabled ; then + if progress::enabled; then progress::render 0 "$PROGRESS_TOTAL" fi } +# Render the progress bar line function progress::render() { - local current=$1 - local total=$2 + local current total width filled empty i bar line + current=$1 + total=$2 PROGRESS_CURRENT=$current - if ! progress::enabled ; then + if ! progress::enabled || [[ ! -t 1 ]] || [[ -z "$total" || "$total" -eq 0 ]]; then return fi - if [[ ! -t 1 ]]; then - return - fi - - if [[ -z "$total" || "$total" -eq 0 ]]; then - return - fi - - local width=$((TERMINAL_WIDTH - 20)) - (( width < 10 )) && width=10 + width=$((TERMINAL_WIDTH - 20)) + [ "$width" -lt 10 ] && width=10 - local filled=$(( current * width / total )) - local empty=$(( width - filled )) - local bar + filled=$(( current * width / total )) + empty=$(( width - filled )) - bar="" - for ((i=0; i /dev/null; then + if command -v tput >/dev/null; then tput sc tput cup $(( $(tput lines) - 1 )) 0 printf '%-*s' "$TERMINAL_WIDTH" "$line" @@ -64,12 +62,13 @@ function progress::render() { fi } +# Finish and clear the progress bar line function progress::finish() { - if ! progress::enabled ; then + if ! progress::enabled; then return fi - if command -v tput > /dev/null; then + if command -v tput >/dev/null; then tput sc tput cup $(( $(tput lines) - 1 )) 0 printf '%*s' "$TERMINAL_WIDTH" '' @@ -79,17 +78,16 @@ function progress::finish() { fi } -# Re-render the last progress bar if progress display is enabled +# Redraw the progress bar using the current known state function progress::refresh() { - if progress::enabled ; then - progress::render "${PROGRESS_CURRENT:-}" "${PROGRESS_TOTAL:-}" + if progress::enabled; then + progress::render "${PROGRESS_CURRENT:-0}" "${PROGRESS_TOTAL:-0}" fi } -# Print an empty line, ensuring any residual characters are cleared by -# filling the entire terminal width with spaces before emitting a newline. +# Print an empty line, clearing any previous progress bar content function progress::blank_line() { - if [[ -t 1 ]] && command -v tput > /dev/null; then + if [[ -t 1 ]] && command -v tput >/dev/null; then printf '%*s\n' "$TERMINAL_WIDTH" '' else printf '\n' From 214a9550abcc3c078721511dc00a8efebbffa357 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Mon, 9 Jun 2025 18:44:24 +0200 Subject: [PATCH 14/14] refactor: progress.sh PROGRESS_BAR_ variable --- src/progress.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/progress.sh b/src/progress.sh index b0f0e86f..1938075d 100644 --- a/src/progress.sh +++ b/src/progress.sh @@ -7,8 +7,8 @@ function progress::enabled() { # Initialize progress tracking variables and optionally render the first bar function progress::init() { - export PROGRESS_TOTAL=$1 - export PROGRESS_CURRENT=0 + export PROGRESS_BAR_TOTAL=$1 + export PROGRESS_BAR_CURRENT=0 if env::is_progress_bar_enabled && parallel::is_enabled; then printf "%sWarning: Progress bar is not supported in parallel mode.%s\n" \ @@ -16,7 +16,7 @@ function progress::init() { fi if progress::enabled; then - progress::render 0 "$PROGRESS_TOTAL" + progress::render 0 "$PROGRESS_BAR_TOTAL" fi } @@ -26,7 +26,7 @@ function progress::render() { current=$1 total=$2 - PROGRESS_CURRENT=$current + PROGRESS_BAR_CURRENT=$current if ! progress::enabled || [[ ! -t 1 ]] || [[ -z "$total" || "$total" -eq 0 ]]; then return @@ -81,7 +81,7 @@ function progress::finish() { # Redraw the progress bar using the current known state function progress::refresh() { if progress::enabled; then - progress::render "${PROGRESS_CURRENT:-0}" "${PROGRESS_TOTAL:-0}" + progress::render "${PROGRESS_BAR_CURRENT:-0}" "${PROGRESS_BAR_TOTAL:-0}" fi }