diff --git a/CHANGELOG.md b/CHANGELOG.md index b5693793..9165ac7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Improve clock performance - Make install.sh args more flexible - Improve Windows detection allowing parallel tests on Git Bash, MSYS and Cygwin +- 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 diff --git a/bashunit b/bashunit index d06795f8..0091b481 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" @@ -63,6 +64,9 @@ while [[ $# -gt 0 ]]; do fi set -x ;; + -pb|--progress-bar) + export BASHUNIT_PROGRESS_BAR=true + ;; -b|--bench) _BENCH_MODE=true export BASHUNIT_BENCH_MODE=true 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/docs/command-line.md b/docs/command-line.md index 5f68c40c..eb82daf5 100644 --- a/docs/command-line.md +++ b/docs/command-line.md @@ -340,6 +340,22 @@ Duration: 48 ms ``` ::: +## Progress bar + +> `bashunit -pb|--progress-bar` + +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 +``` +::: + ## Version > `bashunit --version` diff --git a/docs/configuration.md b/docs/configuration.md index 59819fdc..c59f9675 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -247,6 +247,22 @@ BASHUNIT_VERBOSE=true ``` ::: +## Progress bar + +> `BASHUNIT_PROGRESS_BAR=true|false` + +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/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..d6ba623e 100644 --- a/src/benchmark.sh +++ b/src/benchmark.sh @@ -94,12 +94,16 @@ 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 + 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/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/src/console_results.sh b/src/console_results.sh index 7e57a024..12490eb5 100644 --- a/src/console_results.sh +++ b/src/console_results.sh @@ -13,7 +13,7 @@ function console_results::render_result() { fi if env::is_simple_output_enabled; then - printf "\n\n" + progress::blank_line fi local total_tests=0 @@ -67,36 +67,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 +149,25 @@ function console_results::print_successful_test() { state::print_line "successful" "$full_line" } +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 +175,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 +190,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 +206,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 +237,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 +257,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 +277,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 +314,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 +328,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 +341,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..2ede2472 100644 --- a/src/env.sh +++ b/src/env.sh @@ -28,6 +28,7 @@ _DEFAULT_STOP_ON_FAILURE="false" _DEFAULT_SHOW_EXECUTION_TIME="true" _DEFAULT_VERBOSE="false" _DEFAULT_BENCH_MODE="false" +_DEFAULT_PROGRESS_BAR="false" : "${BASHUNIT_PARALLEL_RUN:=${PARALLEL_RUN:=$_DEFAULT_PARALLEL_RUN}}" : "${BASHUNIT_SHOW_HEADER:=${SHOW_HEADER:=$_DEFAULT_SHOW_HEADER}}" @@ -37,6 +38,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_BAR:=${PROGRESS_BAR:=$_DEFAULT_PROGRESS_BAR}}" function env::is_parallel_run_enabled() { [[ "$BASHUNIT_PARALLEL_RUN" == "true" ]] @@ -74,6 +76,10 @@ function env::is_bench_mode_enabled() { [[ "$BASHUNIT_BENCH_MODE" == "true" ]] } +function env::is_progress_bar_enabled() { + [[ "$BASHUNIT_PROGRESS_BAR" == "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..68e554b1 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}" @@ -44,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[@]}" @@ -59,6 +67,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 +114,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..1938075d --- /dev/null +++ b/src/progress.sh @@ -0,0 +1,95 @@ +#!/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_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" \ + "${_COLOR_INCOMPLETE}" "${_COLOR_DEFAULT}" + fi + + if progress::enabled; then + progress::render 0 "$PROGRESS_BAR_TOTAL" + fi +} + +# Render the progress bar line +function progress::render() { + local current total width filled empty i bar line + + current=$1 + total=$2 + PROGRESS_BAR_CURRENT=$current + + if ! progress::enabled || [[ ! -t 1 ]] || [[ -z "$total" || "$total" -eq 0 ]]; then + return + fi + + width=$((TERMINAL_WIDTH - 20)) + [ "$width" -lt 10 ] && width=10 + + filled=$(( current * width / total )) + empty=$(( width - filled )) + + bar='' + i=0 + while [ $i -lt $filled ]; do + bar="${bar}#" + i=$((i + 1)) + done + i=0 + while [ $i -lt $empty ]; do + bar="${bar}-" + i=$((i + 1)) + done + + line=$(printf '[%s] %d/%d' "$bar" "$current" "$total") + + if command -v tput >/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 +} + +# Finish and clear the progress bar line +function progress::finish() { + if ! progress::enabled; then + return + fi + + if command -v tput >/dev/null; then + tput sc + tput cup $(( $(tput lines) - 1 )) 0 + printf '%*s' "$TERMINAL_WIDTH" '' + tput rc + else + printf '\r%-*s' "$TERMINAL_WIDTH" '' + fi +} + +# Redraw the progress bar using the current known state +function progress::refresh() { + if progress::enabled; then + progress::render "${PROGRESS_BAR_CURRENT:-0}" "${PROGRESS_BAR_TOTAL:-0}" + fi +} + +# Print an empty line, clearing any previous progress bar content +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 e440dc44..57700238 100755 --- a/src/runner.sh +++ b/src/runner.sh @@ -48,7 +48,6 @@ 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" @@ -56,6 +55,9 @@ function runner::spinner() { 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}" @@ -125,7 +127,7 @@ function runner::call_test_functions() { done if ! env::is_simple_output_enabled; then - echo "" + progress::blank_line fi } @@ -154,7 +156,7 @@ function runner::call_bench_functions() { done if ! env::is_simple_output_enabled; then - echo "" + progress::blank_line fi } @@ -164,13 +166,20 @@ 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" + 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 - elif env::is_verbose_enabled; then - printf "\n\n${_COLOR_BOLD}%s${_COLOR_DEFAULT}" "Running $script" + + if env::is_simple_output_enabled && env::is_verbose_enabled; then + progress::refresh fi } @@ -230,7 +239,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 +292,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 +301,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 +317,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_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_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..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 @@ -1,4 +1,4 @@ -..F.. +..FF.. There was 1 failure: @@ -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 f1c6b334..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 @@ -1,4 +1,4 @@ -..F.. +..FF.. There was 1 failure: @@ -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_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_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_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_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..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 @@ -1,4 +1,4 @@ -.F +.FF Stop on failure enabled... @@ -10,7 +10,6 @@ | but got  '2' - Tests:  1 passed, 1 failed, 2 total Assertions: 3 passed, 1 failed, 4 total 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/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. 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"