From 2c202b8d0fc06cb493203221cebe21c614141081 Mon Sep 17 00:00:00 2001 From: "Jose M. Valera Reales" Date: Sat, 12 Oct 2024 00:47:23 +0200 Subject: [PATCH] Running in parallel (#358) --- .env.example | 2 + .github/workflows/tests.yml | 26 ++ CHANGELOG.md | 1 + Makefile | 2 +- adrs/adr-003-parallel-testing.md | 50 ++++ bashunit | 9 +- docs/command-line.md | 22 ++ docs/configuration.md | 9 + src/console_header.sh | 6 + src/env.sh | 7 + src/globals.sh | 10 +- src/main.sh | 22 +- src/parallel.sh | 66 +++++ src/runner.sh | 241 ++++++++++++------ src/state.sh | 27 +- .../bashunit_direct_fn_call_test.sh | 24 +- .../bashunit_execution_error_test.sh | 6 +- tests/acceptance/bashunit_fail_test.sh | 16 +- .../bashunit_find_tests_command_line_test.sh | 8 +- tests/acceptance/bashunit_log_junit_test.sh | 4 +- tests/acceptance/bashunit_pass_test.sh | 16 +- tests/acceptance/bashunit_path_test.sh | 16 +- tests/acceptance/bashunit_report_html_test.sh | 4 +- .../bashunit_stop_on_failure_test.sh | 12 +- tests/acceptance/bashunit_test.sh | 8 +- ...nit_without_path_env_nor_argument.snapshot | 6 + ...test_bashunit_should_display_help.snapshot | 6 + tests/functional/provider_test.sh | 8 +- tests/unit/directory_test.sh | 24 +- tests/unit/state_test.sh | 15 +- 30 files changed, 505 insertions(+), 168 deletions(-) create mode 100644 adrs/adr-003-parallel-testing.md create mode 100755 src/parallel.sh diff --git a/.env.example b/.env.example index 6d4f11b3..6e3108a6 100644 --- a/.env.example +++ b/.env.example @@ -4,8 +4,10 @@ BASHUNIT_REPORT_HTML= BASHUNIT_LOAD_FILE= # Booleans +BASHUNIT_PARALLEL_RUN= BASHUNIT_SHOW_HEADER= BASHUNIT_HEADER_ASCII_ART= BASHUNIT_SIMPLE_OUTPUT= BASHUNIT_STOP_ON_FAILURE= BASHUNIT_SHOW_EXECUTION_TIME= +BASHUNIT_DEV_MODE= diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 69c2b869..b8b26afc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -74,3 +74,29 @@ jobs: - name: Run Tests run: | ./bashunit --simple tests/ + + simple-output-parallel: + name: "Simple output in parallel" + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Tests + run: | + ./bashunit --parallel --simple tests/ + + extended-output-parallel: + name: "Extended output in parallel" + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Tests + run: | + ./bashunit --parallel tests/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 146fbc1d..3e2117e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [Unreleased](https://github.com/TypedDevs/bashunit/compare/0.17.0...main) +- Added `-p|--parallel` to enable running tests in parallel - Added `assert_file_contains` and `assert_file_not_contains` - Added `assert_true` and `assert_false` - Added `BASHUNIT_LOG_PATH` diff --git a/Makefile b/Makefile index 1ed321e2..a4605d0b 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ test/list: @echo $(TEST_SCRIPTS) | tr ' ' '\n' test: $(TEST_SCRIPTS) - @./bashunit $(TEST_SCRIPTS) -e tests/bootstrap.sh + @./bashunit $(TEST_SCRIPTS) test/watch: $(TEST_SCRIPTS) @./bashunit $(TEST_SCRIPTS) diff --git a/adrs/adr-003-parallel-testing.md b/adrs/adr-003-parallel-testing.md new file mode 100644 index 00000000..bc4bdebb --- /dev/null +++ b/adrs/adr-003-parallel-testing.md @@ -0,0 +1,50 @@ +# Title: Parallel testing + +* Status: accepted +* Authors: @Chemaclass +* Date: 2024-10-11 + +Technical Story: +- Pull Request: [TypedDevs/bashunit#358](https://github.com/TypedDevs/bashunit/pull/358) + +## Context and Problem Statement + +We aim to enhance testing performance by running tests in parallel processes while capturing and aggregating results effectively. + +## Considered Options + +- Implement parallel execution using subprocesses. +- Aggregate test results from temporary files. +- Use a spinner for user feedback during result aggregation. + +## Decision Outcome + +- Implemented parallel test execution using subprocesses. +- Each test creates a temporary directory to store results, later aggregated. + +### Positive Consequences + +- Reduced test execution time considerably. +- Clear feedback via a spinner during aggregation. + +### Negative Consequences + +- Potential complexity + - with handling temporary files during interruptions. + - in handling temporary files and managing subprocesses. + +## Technical Details + +When the `--parallel` flag is used, each test is run in its own subprocess by calling: + +> runner::call_test_functions "$test_file" "$filter" 2>/dev/null & + +Each test script creates a temporary directory and stores individual test results in temp files. +After all tests finish, the results are aggregated by traversing these directories and files. +This approach ensures isolation of test execution while improving performance by running tests concurrently. + +The aggregation (which collects all test outcomes into a final result set) is handled by the function: + +> parallel::aggregate_test_results "$TEMP_DIR_PARALLEL_TEST_SUITE" + + diff --git a/bashunit b/bashunit index 640b38bc..33a80dd3 100755 --- a/bashunit +++ b/bashunit @@ -9,13 +9,14 @@ declare -r BASHUNIT_ROOT_DIR="$(dirname "${BASH_SOURCE[0]}")" export BASHUNIT_ROOT_DIR source "$BASHUNIT_ROOT_DIR/src/dev/debug.sh" +source "$BASHUNIT_ROOT_DIR/src/check_os.sh" source "$BASHUNIT_ROOT_DIR/src/str.sh" source "$BASHUNIT_ROOT_DIR/src/globals.sh" source "$BASHUNIT_ROOT_DIR/src/dependencies.sh" source "$BASHUNIT_ROOT_DIR/src/io.sh" source "$BASHUNIT_ROOT_DIR/src/math.sh" +source "$BASHUNIT_ROOT_DIR/src/parallel.sh" source "$BASHUNIT_ROOT_DIR/src/env.sh" -source "$BASHUNIT_ROOT_DIR/src/check_os.sh" source "$BASHUNIT_ROOT_DIR/src/clock.sh" source "$BASHUNIT_ROOT_DIR/src/state.sh" source "$BASHUNIT_ROOT_DIR/src/colors.sh" @@ -63,6 +64,12 @@ while [[ $# -gt 0 ]]; do -S|--stop-on-failure) export BASHUNIT_STOP_ON_FAILURE=true ;; + -p|--parallel) + export BASHUNIT_PARALLEL_RUN=true + ;; + --no-parallel) + export BASHUNIT_PARALLEL_RUN=false + ;; -e|--env|--load) # shellcheck disable=SC1090 source "$2" diff --git a/docs/command-line.md b/docs/command-line.md index f84c74c9..c228fc6c 100644 --- a/docs/command-line.md +++ b/docs/command-line.md @@ -99,6 +99,28 @@ Creates a report XML file that follows the JUnit XML format and contains informa ``` ::: +## Parallel + +> `bashunit -p|--parallel` + +bashunit provides an option to run each test in a separate child process, allowing you to parallelize the test execution and potentially speed up the testing process. When running in parallel mode, the execution order of tests is randomized. + +::: code-group +```bash [Example] +./bashunit ./tests --parallel +``` +::: + +This runs the tests in child processes with randomized execution, which may improve overall testing speed, especially for larger test suites. + +You can use `BASHUNIT_PARALLEL_RUN` option in your [configuration](/configuration#parallel). + +### Disabling Parallel Testing + +> `bashunit --no-parallel` + +If parallel testing is enabled by default or within a script, you can disable it using the --no-parallel option. This is useful if you need to run tests in sequence or if parallel execution is causing issues during debugging. + ## Report > `bashunit -r|--report-html ` diff --git a/docs/configuration.md b/docs/configuration.md index f58f780c..32e409e3 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -62,6 +62,15 @@ BASHUNIT_SIMPLE_OUTPUT=false ``` ::: +## Parallel + +> `BASHUNIT_PARALLEL_RUN=true|false` + +Runs the tests in child processes with randomized execution, which may improve overall testing speed, especially for larger test suites. + +Similar as using `-p|--parallel` option on the [command line](/command-line#parallel). + + ## Stop on failure > `BASHUNIT_STOP_ON_FAILURE=true|false` diff --git a/src/console_header.sh b/src/console_header.sh index 01dc2146..d7ff1472 100644 --- a/src/console_header.sh +++ b/src/console_header.sh @@ -76,6 +76,12 @@ Options: -l|--log-junit Create a report JUnit XML file that contains information about the test results. + -p|--parallel + Run each test in child process, randomizing the tests execution order. + + --no-parallel + Disable the --parallel option. Util to disable parallel tests from within another test. + -r|--report-html Create a report HTML file that contains information about the test results. diff --git a/src/env.sh b/src/env.sh index d7b3b202..3ed96928 100644 --- a/src/env.sh +++ b/src/env.sh @@ -27,6 +27,7 @@ _DEFAULT_HEADER_ASCII_ART="false" _DEFAULT_SIMPLE_OUTPUT="false" _DEFAULT_STOP_ON_FAILURE="false" _DEFAULT_SHOW_EXECUTION_TIME="true" +_DEFAULT_DEV_MODE="false" : "${BASHUNIT_PARALLEL_RUN:=${PARALLEL_RUN:=$_DEFAULT_PARALLEL_RUN}}" : "${BASHUNIT_SHOW_HEADER:=${SHOW_HEADER:=$_DEFAULT_SHOW_HEADER}}" @@ -34,6 +35,7 @@ _DEFAULT_SHOW_EXECUTION_TIME="true" : "${BASHUNIT_SIMPLE_OUTPUT:=${SIMPLE_OUTPUT:=$_DEFAULT_SIMPLE_OUTPUT}}" : "${BASHUNIT_STOP_ON_FAILURE:=${STOP_ON_FAILURE:=$_DEFAULT_STOP_ON_FAILURE}}" : "${BASHUNIT_SHOW_EXECUTION_TIME:=${SHOW_EXECUTION_TIME:=$_DEFAULT_SHOW_EXECUTION_TIME}}" +: "${BASHUNIT_DEV_MODE:=${DEV_MODE:=$_DEFAULT_DEV_MODE}}" function env::is_parallel_run_enabled() { [[ "$BASHUNIT_PARALLEL_RUN" == "true" ]] @@ -59,6 +61,10 @@ function env::is_show_execution_time_enabled() { [[ "$BASHUNIT_SHOW_EXECUTION_TIME" == "true" ]] } +function env::is_dev_mode_enabled() { + [[ "$BASHUNIT_DEV_MODE" == "true" ]] +} + function env::find_terminal_width() { local cols="" @@ -73,6 +79,7 @@ function env::find_terminal_width() { echo "${cols:-$_DEFAULT_TERMINAL_WIDTH}" } +TEMP_DIR_PARALLEL_TEST_SUITE="/tmp/bashunit/parallel/${_OS:-Unknown}" TERMINAL_WIDTH="$(env::find_terminal_width)" FAILURES_OUTPUT_PATH=$(mktemp) CAT="$(which cat)" diff --git a/src/globals.sh b/src/globals.sh index 8bbb5ca8..8b4f3250 100644 --- a/src/globals.sh +++ b/src/globals.sh @@ -25,17 +25,17 @@ function random_str() { } function temp_file() { - mkdir -p /tmp/bashunit-tmp && chmod -R 777 /tmp/bashunit-tmp - mktemp /tmp/bashunit-tmp/bashunit.XXXXXXX + mkdir -p /tmp/bashunit/tmp && chmod -R 777 /tmp/bashunit/tmp + mktemp /tmp/bashunit/tmp/bashunit.XXXXXXX } function temp_dir() { - mkdir -p /tmp/bashunit-tmp && chmod -R 777 /tmp/bashunit-tmp - mktemp -d /tmp/bashunit-tmp/bashunit.XXXXXXX + mkdir -p /tmp/bashunit/tmp && chmod -R 777 /tmp/bashunit/tmp + mktemp -d /tmp/bashunit/tmp/bashunit.XXXXXXX } function cleanup_temp_files() { - rm -rf /tmp/bashunit-tmp/* + rm -rf /tmp/bashunit/tmp/* } # shellcheck disable=SC2145 diff --git a/src/main.sh b/src/main.sh index c1536c89..bca384aa 100644 --- a/src/main.sh +++ b/src/main.sh @@ -15,8 +15,21 @@ function main::exec_tests() { exit 1 fi + # Trap SIGINT (Ctrl-C) and call the cleanup function + trap main::cleanup SIGINT + + if env::is_parallel_run_enabled && check_os::is_alpine; then + printf "%sWarning: Parallel test execution on Alpine Linux is currently" "${_COLOR_INCOMPLETE}" + printf "in a beta stage.\nThis means there may be unresolved issues, " + printf "particularly involving race conditions.%s\n" "${_COLOR_DEFAULT}" + fi + console_header::print_version_with_env "$filter" "${test_files[@]}" runner::load_test_files "$filter" "${test_files[@]}" + if env::is_parallel_run_enabled; then + wait + fi + console_results::print_failing_tests_and_reset console_results::render_result exit_code=$? @@ -30,10 +43,17 @@ function main::exec_tests() { fi cleanup_temp_files - exit $exit_code } +function main::cleanup() { + printf "%sCaught Ctrl-C, killing all child processes...%s\n" "${_COLOR_SKIPPED}" "${_COLOR_DEFAULT}" + # Kill all child processes of this script + pkill -P $$ + cleanup_temp_files + exit 1 +} + function main::exec_assert() { local original_assert_fn=$1 local args=("${@:2}") diff --git a/src/parallel.sh b/src/parallel.sh new file mode 100755 index 00000000..e25250b7 --- /dev/null +++ b/src/parallel.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +function parallel::aggregate_test_results() { + local temp_dir_parallel_test_suite=$1 + + local total_failed=0 + local total_passed=0 + local total_skipped=0 + local total_incomplete=0 + local total_snapshot=0 + + for script_dir in "$temp_dir_parallel_test_suite"/*; do + for result_file in "$script_dir"/*.result; do + while IFS= read -r line; do + # Extract assertion counts from the result lines using sed + failed=$(echo "$line" | sed -n 's/.*##ASSERTIONS_FAILED=\([0-9]*\)##.*/\1/p') + passed=$(echo "$line" | sed -n 's/.*##ASSERTIONS_PASSED=\([0-9]*\)##.*/\1/p') + skipped=$(echo "$line" | sed -n 's/.*##ASSERTIONS_SKIPPED=\([0-9]*\)##.*/\1/p') + incomplete=$(echo "$line" | sed -n 's/.*##ASSERTIONS_INCOMPLETE=\([0-9]*\)##.*/\1/p') + snapshot=$(echo "$line" | sed -n 's/.*##ASSERTIONS_SNAPSHOT=\([0-9]*\)##.*/\1/p') + + # Default to 0 if no match is found + failed=${failed:-0} + passed=${passed:-0} + skipped=${skipped:-0} + incomplete=${incomplete:-0} + snapshot=${snapshot:-0} + + # Add to the total counts + total_failed=$((total_failed + failed)) + total_passed=$((total_passed + passed)) + total_skipped=$((total_skipped + skipped)) + total_incomplete=$((total_incomplete + incomplete)) + total_snapshot=$((total_snapshot + snapshot)) + done < "$result_file" + + if [ "${failed:-0}" -gt 0 ]; then + state::add_tests_failed + continue + fi + + if [ "${snapshot:-0}" -gt 0 ]; then + state::add_tests_snapshot + continue + fi + + if [ "${incomplete:-0}" -gt 0 ]; then + state::add_tests_incomplete + continue + fi + + if [ "${skipped:-0}" -gt 0 ]; then + state::add_tests_skipped + continue + fi + + state::add_tests_passed + done + done + + export _ASSERTIONS_FAILED=$total_failed + export _ASSERTIONS_PASSED=$total_passed + export _ASSERTIONS_SKIPPED=$total_skipped + export _ASSERTIONS_INCOMPLETE=$total_incomplete + export _ASSERTIONS_SNAPSHOT=$total_snapshot +} diff --git a/src/runner.sh b/src/runner.sh index 3676ba3c..63b3746c 100755 --- a/src/runner.sh +++ b/src/runner.sh @@ -2,7 +2,13 @@ function runner::load_test_files() { local filter=$1 - local files=("${@:2}") # Store all arguments starting from the second as an array + shift + local files=("${@}") + local pids=() + + if env::is_parallel_run_enabled; then + rm -rf "$TEMP_DIR_PARALLEL_TEST_SUITE" + fi for test_file in "${files[@]}"; do if [[ ! -f $test_file ]]; then @@ -13,13 +19,40 @@ function runner::load_test_files() { source "$test_file" runner::run_set_up_before_script - runner::call_test_functions "$test_file" "$filter" - if [ "$BASHUNIT_PARALLEL_RUN" = true ] ; then - wait + if env::is_parallel_run_enabled; then + runner::call_test_functions "$test_file" "$filter" 2>/dev/null & + pids+=($!) + else + runner::call_test_functions "$test_file" "$filter" fi runner::run_tear_down_after_script runner::clean_set_up_and_tear_down_after_script done + + if env::is_parallel_run_enabled; then + wait + + runner::spinner & + local spinner_pid=$! + + parallel::aggregate_test_results "$TEMP_DIR_PARALLEL_TEST_SUITE" + + # Kill the spinner once the aggregation finishes + disown "$spinner_pid" && kill "$spinner_pid" &>/dev/null + printf "\r " # Clear the spinner output + fi +} + +function runner::spinner() { + printf "\n" + local delay=0.1 + local spin_chars="|/-\\" + while true; do + for ((i=0; i<${#spin_chars}; i++)); do + printf "\r%s" "${spin_chars:$i:1}" + sleep "$delay" + done + done } function runner::functions_for_script() { @@ -55,7 +88,7 @@ function runner::call_test_functions() { functions_to_run=($(runner::functions_for_script "$script" "$filtered_functions")) if [[ "${#functions_to_run[@]}" -gt 0 ]]; then - if ! env::is_simple_output_enabled; then + if ! env::is_simple_output_enabled && ! env::is_parallel_run_enabled; then echo "Running $script" fi @@ -88,51 +121,7 @@ function runner::call_test_functions() { fi } -function runner::parse_execution_result() { - local execution_result=$1 - - local assertions_failed - assertions_failed=$(\ - echo "$execution_result" |\ - tail -n 1 |\ - sed -E -e 's/.*##ASSERTIONS_FAILED=([0-9]*)##.*/\1/g'\ - ) - - local assertions_passed - assertions_passed=$(\ - echo "$execution_result" |\ - tail -n 1 |\ - sed -E -e 's/.*##ASSERTIONS_PASSED=([0-9]*)##.*/\1/g'\ - ) - - local assertions_skipped - assertions_skipped=$(\ - echo "$execution_result" |\ - tail -n 1 |\ - sed -E -e 's/.*##ASSERTIONS_SKIPPED=([0-9]*)##.*/\1/g'\ - ) - - local assertions_incomplete - assertions_incomplete=$(\ - echo "$execution_result" |\ - tail -n 1 |\ - sed -E -e 's/.*##ASSERTIONS_INCOMPLETE=([0-9]*)##.*/\1/g'\ - ) - - local assertions_snapshot - assertions_snapshot=$(\ - echo "$execution_result" |\ - tail -n 1 |\ - sed -E -e 's/.*##ASSERTIONS_SNAPSHOT=([0-9]*)##.*/\1/g'\ - ) - - ((_ASSERTIONS_PASSED += assertions_passed)) || true - ((_ASSERTIONS_FAILED += assertions_failed)) || true - ((_ASSERTIONS_SKIPPED += assertions_skipped)) || true - ((_ASSERTIONS_INCOMPLETE += assertions_incomplete)) || true - ((_ASSERTIONS_SNAPSHOT += assertions_snapshot)) || true -} - +# shellcheck disable=SC2155 function runner::run_test() { local start_time start_time=$(clock::now) @@ -141,22 +130,17 @@ function runner::run_test() { shift local function_name="$1" shift - local current_assertions_failed - current_assertions_failed="$(state::get_assertions_failed)" - local current_assertions_snapshot - current_assertions_snapshot="$(state::get_assertions_snapshot)" - local current_assertions_incomplete - current_assertions_incomplete="$(state::get_assertions_incomplete)" - local current_assertions_skipped - current_assertions_skipped="$(state::get_assertions_skipped)" + local current_assertions_failed="$(state::get_assertions_failed)" + local current_assertions_snapshot="$(state::get_assertions_snapshot)" + local current_assertions_incomplete="$(state::get_assertions_incomplete)" + local current_assertions_skipped="$(state::get_assertions_skipped)" # (FD = File Descriptor) # Duplicate the current std-output (FD 1) and assigns it to FD 3. # This means that FD 3 now points to wherever the std-output was pointing. exec 3>&1 - local test_execution_result - test_execution_result=$( + local test_execution_result=$( state::initialize_assertions_count runner::run_set_up @@ -172,15 +156,15 @@ function runner::run_test() { # Closes FD 3, which was used temporarily to hold the original stdout. exec 3>&- - runner::parse_execution_result "$test_execution_result" + local test_output_base64="${test_execution_result##*##TEST_OUTPUT=}" + test_output_base64="${test_output_base64%%##*}" local subshell_output - subshell_output=$(\ - echo "$test_execution_result" |\ - tail -n 1 |\ - sed -E -e 's/.*##TEST_OUTPUT=(.*)##.*/\1/g' |\ - base64 -d - ) + if command -v base64 >/dev/null; then + subshell_output=$(echo "$test_output_base64" | base64 -d) + else + subshell_output=$(echo "$test_output_base64" | openssl enc -d -base64) + fi if [[ -n "$subshell_output" ]]; then # Formatted as "[type]line" @see `state::print_line()` @@ -192,8 +176,7 @@ function runner::run_test() { subshell_output=$line fi - local runtime_output - runtime_output="${test_execution_result%%##ASSERTIONS*}" + local runtime_output="${test_execution_result%%##TEST_ID=*}" local runtime_error="" for error in "command not found" "unbound variable" "permission denied" \ @@ -201,20 +184,20 @@ function runner::run_test() { "division by 0" "cannot allocate memory" "bad file descriptor" \ "segmentation fault" "illegal option" "argument list too long" \ "readonly variable" "missing keyword" "killed" \ - "cannot execute binary file"; do + "cannot execute binary file" "invalid arithmetic operator"; do if [[ "$runtime_output" == *"$error"* ]]; then runtime_error=$(echo "${runtime_output#*: }" | tr -d '\n') break fi done - local total_assertions - total_assertions="$(state::calculate_total_assertions "$test_execution_result")" + runner::parse_result "$function_name" "$test_execution_result" "$@" + + local total_assertions="$(state::calculate_total_assertions "$test_execution_result")" - local end_time duration_ns duration - end_time=$(clock::now) - duration_ns=$(math::calculate "($end_time - $start_time) ") - duration=$(math::calculate "$duration_ns / 1000000") + local end_time=$(clock::now) + local duration_ns=$(math::calculate "($end_time - $start_time) ") + local duration=$(math::calculate "$duration_ns / 1000000") if [[ -n $runtime_error ]]; then state::add_tests_failed @@ -253,14 +236,116 @@ function runner::run_test() { return fi - local label - label="$(helper::normalize_test_function_name "$function_name")" + local label="$(helper::normalize_test_function_name "$function_name")" console_results::print_successful_test "${label}" "$duration" "$@" state::add_tests_passed logger::test_passed "$test_file" "$function_name" "$duration" "$total_assertions" } +function runner::parse_result() { + local function_name=$1 + shift + local execution_result=$1 + shift + local args=("$@") + + if env::is_parallel_run_enabled; then + runner::parse_result_parallel "$function_name" "$execution_result" "${args[@]}" + else + runner::parse_result_sync "$function_name" "$execution_result" + fi +} + +# shellcheck disable=SC2155 +function runner::parse_result_parallel() { + local function_name=$1 + shift + local execution_result=$1 + shift + local args=("$@") + + local test_suite_dir="${TEMP_DIR_PARALLEL_TEST_SUITE}/$(basename "$test_file" .sh)" + mkdir -p "$test_suite_dir" + + local test_result_file=$(echo "${args[@]}" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-|-$//') + if [[ -z "$test_result_file" ]]; then + test_result_file="${function_name}.$$.result" + else + test_result_file="${function_name}-${test_result_file}.$$.result" + fi + + local unique_test_result_file="${test_suite_dir}/${test_result_file}" + local count=1 + + while [ -e "$unique_test_result_file" ]; do + unique_test_result_file="${test_suite_dir}/${test_result_file%.result}-$count.result" + count=$((count + 1)) + done + + if env::is_dev_mode_enabled; then + local test_id=$(\ + echo "$execution_result" |\ + tail -n 1 |\ + sed -E -e 's/.*##TEST_ID=([a-zA-Z0-9]*)##.*/\1/g'\ + ) + log "debug" "[PARA] test_id:$test_id" "function_name:$function_name" "execution_result:$execution_result" + fi + + echo "$execution_result" > "$unique_test_result_file" +} + +# shellcheck disable=SC2155 +function runner::parse_result_sync() { + local function_name=$1 + local execution_result=$2 + + local assertions_failed=$(\ + echo "$execution_result" |\ + tail -n 1 |\ + sed -E -e 's/.*##ASSERTIONS_FAILED=([0-9]*)##.*/\1/g'\ + ) + + local assertions_passed=$(\ + echo "$execution_result" |\ + tail -n 1 |\ + sed -E -e 's/.*##ASSERTIONS_PASSED=([0-9]*)##.*/\1/g'\ + ) + + local assertions_skipped=$(\ + echo "$execution_result" |\ + tail -n 1 |\ + sed -E -e 's/.*##ASSERTIONS_SKIPPED=([0-9]*)##.*/\1/g'\ + ) + + local assertions_incomplete=$(\ + echo "$execution_result" |\ + tail -n 1 |\ + sed -E -e 's/.*##ASSERTIONS_INCOMPLETE=([0-9]*)##.*/\1/g'\ + ) + + local assertions_snapshot=$(\ + echo "$execution_result" |\ + tail -n 1 |\ + sed -E -e 's/.*##ASSERTIONS_SNAPSHOT=([0-9]*)##.*/\1/g'\ + ) + + if env::is_dev_mode_enabled; then + local test_id=$(\ + echo "$execution_result" |\ + tail -n 1 |\ + sed -E -e 's/.*##TEST_ID=([a-zA-Z0-9]*)##.*/\1/g'\ + ) + log "debug" "[SYNC] test_id:$test_id" "function_name:$function_name" "execution_result:$execution_result" + fi + + ((_ASSERTIONS_PASSED += assertions_passed)) || true + ((_ASSERTIONS_FAILED += assertions_failed)) || true + ((_ASSERTIONS_SKIPPED += assertions_skipped)) || true + ((_ASSERTIONS_INCOMPLETE += assertions_incomplete)) || true + ((_ASSERTIONS_SNAPSHOT += assertions_snapshot)) || true +} + function runner::write_failure_result_output() { local test_file=$1 local error_msg=$2 diff --git a/src/state.sh b/src/state.sh index 1a31b23d..03078121 100644 --- a/src/state.sh +++ b/src/state.sh @@ -140,21 +140,28 @@ function state::initialize_assertions_count() { function state::export_subshell_context() { local encoded_test_output + if base64 --help 2>&1 | grep -q -- "-w"; then - # Alpine needs -w 0 to avoid line wrapping + # Alpine requires the -w 0 option to avoid wrapping encoded_test_output=$(echo -n "$_TEST_OUTPUT" | base64 -w 0) else - # macOS and others don't need -w 0 + # macOS and others: default base64 without wrapping encoded_test_output=$(echo -n "$_TEST_OUTPUT" | base64) fi - echo "##ASSERTIONS_FAILED=$_ASSERTIONS_FAILED\ + local test_id + test_id=$(LC_ALL=C tr -dc A-Za-z0-9 &1)" - assert_general_error "$(./bashunit -a assert_same --env "$TEST_ENV_FILE" "$expected" $actual)" + assert_match_snapshot "$(./bashunit --no-parallel -a assert_same --env "$TEST_ENV_FILE" "$expected" $actual 2>&1)" + assert_general_error "$(./bashunit --no-parallel -a assert_same --env "$TEST_ENV_FILE" "$expected" $actual)" } function test_bashunit_direct_fn_call_non_existing_fn() { - assert_match_snapshot "$(./bashunit -a non_existing_fn --env "$TEST_ENV_FILE" 2>&1)" - assert_command_not_found "$(./bashunit -a non_existing_fn --env "$TEST_ENV_FILE")" + assert_match_snapshot "$(./bashunit --no-parallel -a non_existing_fn --env "$TEST_ENV_FILE" 2>&1)" + assert_command_not_found "$(./bashunit --no-parallel -a non_existing_fn --env "$TEST_ENV_FILE")" } # shellcheck disable=SC2155 function test_bashunit_assert_exit_code_successful_with_inner_func() { - local temp=$(temp_file) + local temp=$(mktemp) # shellcheck disable=SC2116 - local output="$(./bashunit -a exit_code "0" "$(echo "unknown command")" 2> "$temp")" + local output="$(./bashunit --no-parallel -a exit_code "0" "$(echo "unknown command")" 2> "$temp")" assert_empty "$output" assert_file_contains "$temp" "Command not found: unknown command" @@ -99,9 +99,9 @@ function test_bashunit_assert_exit_code_successful_with_inner_func() { # shellcheck disable=SC2155 function test_bashunit_assert_exit_code_error_with_inner_func() { - local temp=$(temp_file) + local temp=$(mktemp) # shellcheck disable=SC2116 - local output="$(./bashunit -a exit_code "1" "$(echo "unknown command")" 2> "$temp")" + local output="$(./bashunit --no-parallel -a exit_code "1" "$(echo "unknown command")" 2> "$temp")" assert_empty "$output" @@ -121,8 +121,8 @@ function test_bashunit_assert_exit_code_str_general_error() { # shellcheck disable=SC2155 function test_bashunit_assert_exit_code_str_successful_but_exit_code_error() { - local temp=$(temp_file) - local output="$(./bashunit -a exit_code "1" "echo something to stdout" 2> "$temp")" + local temp=$(mktemp) + local output="$(./bashunit --no-parallel -a exit_code "1" "echo something to stdout" 2> "$temp")" assert_same "something to stdout" "$output" @@ -132,8 +132,8 @@ function test_bashunit_assert_exit_code_str_successful_but_exit_code_error() { # shellcheck disable=SC2155 function test_bashunit_assert_exit_code_str_successful_and_exit_code_ok() { - local temp=$(temp_file) - local output="$(./bashunit -a exit_code "0" "echo something to stdout" 2> "$temp")" + local temp=$(mktemp) + local output="$(./bashunit --no-parallel -a exit_code "0" "echo something to stdout" 2> "$temp")" assert_same "something to stdout" "$output" assert_empty "$(cat "$temp")" diff --git a/tests/acceptance/bashunit_execution_error_test.sh b/tests/acceptance/bashunit_execution_error_test.sh index 929bbedf..3f95c002 100644 --- a/tests/acceptance/bashunit_execution_error_test.sh +++ b/tests/acceptance/bashunit_execution_error_test.sh @@ -53,7 +53,7 @@ function test_bashunit_when_a_execution_error() { todo "Add snapshots with regex to assert this test (part of the error message is localized)" todo "Add snapshots with simple/verbose modes as in bashunit_pass_test and bashunit_fail_test" - assert_contains "$fixture_start" "$(./bashunit --env "$TEST_ENV_FILE" "$test_file")" - assert_contains "$fixture_end" "$(./bashunit --env "$TEST_ENV_FILE" "$test_file")" - assert_general_error "$(./bashunit --env "$TEST_ENV_FILE" "$test_file")" + assert_contains "$fixture_start" "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file")" + assert_contains "$fixture_end" "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file")" + assert_general_error "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file")" } diff --git a/tests/acceptance/bashunit_fail_test.sh b/tests/acceptance/bashunit_fail_test.sh index d881aaf7..08b23fec 100644 --- a/tests/acceptance/bashunit_fail_test.sh +++ b/tests/acceptance/bashunit_fail_test.sh @@ -9,15 +9,15 @@ function set_up_before_script() { function test_bashunit_when_a_test_fail_verbose_output_env() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_a_test_fail.sh - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE" "$test_file")" - assert_general_error "$(./bashunit --env "$TEST_ENV_FILE" "$test_file")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file")" + assert_general_error "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file")" } function test_bashunit_when_a_test_fail_verbose_output_option() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_a_test_fail.sh - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE_SIMPLE" "$test_file" --verbose)" - assert_general_error "$(./bashunit --env "$TEST_ENV_FILE_SIMPLE" "$test_file" --verbose)" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_SIMPLE" "$test_file" --verbose)" + assert_general_error "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_SIMPLE" "$test_file" --verbose)" } function test_different_verbose_snapshots_matches() { @@ -32,9 +32,9 @@ function test_bashunit_when_a_test_fail_simple_output_env() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_a_test_fail.sh # shellcheck disable=SC2317 - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE_SIMPLE" "$test_file")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_SIMPLE" "$test_file")" # shellcheck disable=SC2317 - assert_general_error "$(./bashunit --env "$TEST_ENV_FILE_SIMPLE" "$test_file")" + assert_general_error "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_SIMPLE" "$test_file")" } function test_bashunit_when_a_test_fail_simple_output_option() { @@ -45,9 +45,9 @@ function test_bashunit_when_a_test_fail_simple_output_option() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_a_test_fail.sh # shellcheck disable=SC2317 - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE" "$test_file" --simple)" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file" --simple)" # shellcheck disable=SC2317 - assert_general_error "$(./bashunit --env "$TEST_ENV_FILE" "$test_file" --simple)" + assert_general_error "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file" --simple)" } function test_different_simple_snapshots_matches() { diff --git a/tests/acceptance/bashunit_find_tests_command_line_test.sh b/tests/acceptance/bashunit_find_tests_command_line_test.sh index fee87666..3162fc8e 100644 --- a/tests/acceptance/bashunit_find_tests_command_line_test.sh +++ b/tests/acceptance/bashunit_find_tests_command_line_test.sh @@ -8,23 +8,23 @@ function set_up_before_script() { function test_all_tests_files_within_a_directory() { local path="./tests/acceptance/fixtures" - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE" "$path")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$path")" } function test_all_tests_files_within_a_file() { local path="./tests/acceptance/fixtures/tests_path/a_test.sh" - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE" "$path")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$path")" } function test_all_tests_files_with_wildcard() { local path='./tests/acceptance/fixtures/tests_path/*' - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE" "$path")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$path")" } function test_error_when_no_tests_found() { local path="./non_existing_path" - assert_general_error "$(./bashunit --env "$TEST_ENV_FILE" "$path")" + assert_general_error "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$path")" } diff --git a/tests/acceptance/bashunit_log_junit_test.sh b/tests/acceptance/bashunit_log_junit_test.sh index 9bbcf151..45966984 100644 --- a/tests/acceptance/bashunit_log_junit_test.sh +++ b/tests/acceptance/bashunit_log_junit_test.sh @@ -8,7 +8,7 @@ function set_up_before_script() { function test_bashunit_when_log_junit_option() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_log_junit.sh - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE" --log-junit custom.xml "$test_file")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" --log-junit custom.xml "$test_file")" assert_file_exists custom.xml rm custom.xml } @@ -16,7 +16,7 @@ function test_bashunit_when_log_junit_option() { function test_bashunit_when_log_junit_env() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_log_junit.sh - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE_BASHUNIT_LOG_JUNIT" "$test_file")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_BASHUNIT_LOG_JUNIT" "$test_file")" assert_file_exists log-junit.xml rm log-junit.xml } diff --git a/tests/acceptance/bashunit_pass_test.sh b/tests/acceptance/bashunit_pass_test.sh index 1234f861..4d71a6f3 100644 --- a/tests/acceptance/bashunit_pass_test.sh +++ b/tests/acceptance/bashunit_pass_test.sh @@ -9,15 +9,15 @@ function set_up_before_script() { function test_bashunit_when_a_test_passes_verbose_output_env() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_a_test_passes.sh - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE" "$test_file")" - assert_successful_code "$(./bashunit --env "$TEST_ENV_FILE" "$test_file")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file")" + assert_successful_code "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file")" } function test_bashunit_when_a_test_passes_verbose_output_option() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_a_test_passes.sh - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE_SIMPLE" "$test_file" --verbose)" - assert_successful_code "$(./bashunit --env "$TEST_ENV_FILE_SIMPLE" "$test_file" --verbose)" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_SIMPLE" "$test_file" --verbose)" + assert_successful_code "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_SIMPLE" "$test_file" --verbose)" } function test_different_verbose_snapshots_matches() { @@ -27,15 +27,15 @@ function test_different_verbose_snapshots_matches() { function test_bashunit_when_a_test_passes_simple_output_env() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_a_test_passes.sh - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE_SIMPLE" "$test_file")" - assert_successful_code "$(./bashunit --env "$TEST_ENV_FILE_SIMPLE" "$test_file")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_SIMPLE" "$test_file")" + assert_successful_code "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_SIMPLE" "$test_file")" } function test_bashunit_when_a_test_passes_simple_output_option() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_a_test_passes.sh - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE" "$test_file" --simple)" - assert_successful_code "$(./bashunit --env "$TEST_ENV_FILE" "$test_file" --simple)" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file" --simple)" + assert_successful_code "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" "$test_file" --simple)" } function test_different_simple_snapshots_matches() { diff --git a/tests/acceptance/bashunit_path_test.sh b/tests/acceptance/bashunit_path_test.sh index 856a158d..e5ab4513 100644 --- a/tests/acceptance/bashunit_path_test.sh +++ b/tests/acceptance/bashunit_path_test.sh @@ -7,25 +7,25 @@ function set_up_before_script() { } function test_bashunit_without_path_env_nor_argument() { - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE")" - assert_general_error "$(./bashunit --env "$TEST_ENV_FILE")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE")" + assert_general_error "$(./bashunit --no-parallel --env "$TEST_ENV_FILE")" } function test_bashunit_with_argument_path() { local path="tests/acceptance/fixtures/tests_path" - assert_match_snapshot "$(./bashunit "$path" --env "$TEST_ENV_FILE")" - assert_successful_code "$(./bashunit "$path" --env "$TEST_ENV_FILE")" + assert_match_snapshot "$(./bashunit --no-parallel "$path" --env "$TEST_ENV_FILE")" + assert_successful_code "$(./bashunit --no-parallel "$path" --env "$TEST_ENV_FILE")" } function test_bashunit_with_env_default_path() { - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE_WITH_PATH")" - assert_successful_code "$(./bashunit --env "$TEST_ENV_FILE_WITH_PATH")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_WITH_PATH")" + assert_successful_code "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_WITH_PATH")" } function test_bashunit_argument_overloads_default_path() { local path="tests/acceptance/fixtures/wrong_path" - assert_match_snapshot "$(./bashunit "$path" --env "$TEST_ENV_FILE_WITH_PATH")" - assert_general_error "$(./bashunit "$path" --env "$TEST_ENV_FILE_WITH_PATH")" + assert_match_snapshot "$(./bashunit --no-parallel "$path" --env "$TEST_ENV_FILE_WITH_PATH")" + assert_general_error "$(./bashunit --no-parallel "$path" --env "$TEST_ENV_FILE_WITH_PATH")" } diff --git a/tests/acceptance/bashunit_report_html_test.sh b/tests/acceptance/bashunit_report_html_test.sh index 2cee8a84..eecb9c15 100644 --- a/tests/acceptance/bashunit_report_html_test.sh +++ b/tests/acceptance/bashunit_report_html_test.sh @@ -9,7 +9,7 @@ function set_up_before_script() { function test_bashunit_when_report_html_option() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_report_html.sh - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE" --report-html custom.html "$test_file")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" --report-html custom.html "$test_file")" assert_file_exists custom.html if [[ -f custom.html ]]; then @@ -20,7 +20,7 @@ function test_bashunit_when_report_html_option() { function test_bashunit_when_report_html_env() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_report_html.sh - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE_REPORT_HTML" "$test_file")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_REPORT_HTML" "$test_file")" assert_file_exists report.html if [[ -f custom.html ]]; then diff --git a/tests/acceptance/bashunit_stop_on_failure_test.sh b/tests/acceptance/bashunit_stop_on_failure_test.sh index 9a6a5923..fa24ab32 100644 --- a/tests/acceptance/bashunit_stop_on_failure_test.sh +++ b/tests/acceptance/bashunit_stop_on_failure_test.sh @@ -9,15 +9,15 @@ function set_up_before_script() { function test_bashunit_when_stop_on_failure_option() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_stop_on_failure.sh - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE" --stop-on-failure "$test_file")" - assert_general_error "$(./bashunit --env "$TEST_ENV_FILE" --stop-on-failure "$test_file")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" --stop-on-failure "$test_file")" + assert_general_error "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" --stop-on-failure "$test_file")" } function test_bashunit_when_stop_on_failure_env() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_stop_on_failure.sh - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE_STOP_ON_FAILURE" "$test_file")" - assert_general_error "$(./bashunit --env "$TEST_ENV_FILE_STOP_ON_FAILURE" "$test_file")" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_STOP_ON_FAILURE" "$test_file")" + assert_general_error "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_STOP_ON_FAILURE" "$test_file")" } function test_different_snapshots_matches() { @@ -32,7 +32,7 @@ function test_bashunit_when_stop_on_failure_env_simple_output() { local test_file=./tests/acceptance/fixtures/test_bashunit_when_stop_on_failure.sh # shellcheck disable=SC2317 - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE_STOP_ON_FAILURE" "$test_file" --simple)" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_STOP_ON_FAILURE" "$test_file" --simple)" # shellcheck disable=SC2317 - assert_general_error "$(./bashunit --env "$TEST_ENV_FILE_STOP_ON_FAILURE" "$test_file" --simple)" + assert_general_error "$(./bashunit --no-parallel --env "$TEST_ENV_FILE_STOP_ON_FAILURE" "$test_file" --simple)" } diff --git a/tests/acceptance/bashunit_test.sh b/tests/acceptance/bashunit_test.sh index 81b96dc8..4c37f874 100644 --- a/tests/acceptance/bashunit_test.sh +++ b/tests/acceptance/bashunit_test.sh @@ -10,11 +10,11 @@ function test_bashunit_should_display_version() { fixture=$(printf "\e[1m\e[32mbashunit\e[0m - %s" "$BASHUNIT_VERSION") todo "Add snapshots with regex to assert this test (part of the output changes every version)" - assert_contains "$fixture" "$(./bashunit --env "$TEST_ENV_FILE" --version)" - assert_successful_code "$(./bashunit --env "$TEST_ENV_FILE" --version)" + assert_contains "$fixture" "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" --version)" + assert_successful_code "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" --version)" } function test_bashunit_should_display_help() { - assert_match_snapshot "$(./bashunit --env "$TEST_ENV_FILE" --help)" - assert_successful_code "$(./bashunit --env "$TEST_ENV_FILE" --help)" + assert_match_snapshot "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" --help)" + assert_successful_code "$(./bashunit --no-parallel --env "$TEST_ENV_FILE" --help)" } 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 cfc0b727..c0945093 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 @@ -23,6 +23,12 @@ Options: -l|--log-junit Create a report JUnit XML file that contains information about the test results. + -p|--parallel + Run each test in child process, randomizing the tests execution order. + + --no-parallel + Disable the --parallel option. Util to disable parallel tests from within another test. + -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 6566ab4d..76737976 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 @@ -22,6 +22,12 @@ Options: -l|--log-junit Create a report JUnit XML file that contains information about the test results. + -p|--parallel + Run each test in child process, randomizing the tests execution order. + + --no-parallel + Disable the --parallel option. Util to disable parallel tests from within another test. + -r|--report-html Create a report HTML file that contains information about the test results. diff --git a/tests/functional/provider_test.sh b/tests/functional/provider_test.sh index bfa0a211..8ba4f9fa 100644 --- a/tests/functional/provider_test.sh +++ b/tests/functional/provider_test.sh @@ -15,7 +15,13 @@ function test_multiple_values_from_data_provider() { function provide_multiples_values() { echo "aa" "bb" - echo "aa" "bb" +} + +# data_provider provide_single_values +function test_single_values_from_data_provider() { + local data="$1" + + assert_not_equals "zero" "$data" } function provide_single_values() { diff --git a/tests/unit/directory_test.sh b/tests/unit/directory_test.sh index 591b9d15..a6c5c581 100644 --- a/tests/unit/directory_test.sh +++ b/tests/unit/directory_test.sh @@ -65,7 +65,7 @@ function test_unsuccessful_assert_is_directory_when_a_file_is_given() { } function test_successful_assert_is_directory_empty() { - local a_directory=$(temp_dir) + local a_directory=$(mktemp -d) assert_empty "$(assert_is_directory_empty "$a_directory")" } @@ -86,7 +86,7 @@ function test_successful_assert_is_directory_not_empty() { } function test_unsuccessful_assert_is_directory_not_empty() { - local a_directory=$(temp_dir) + local a_directory=$(mktemp -d) assert_same\ "$(console_results::print_failed_test \ @@ -95,7 +95,7 @@ function test_unsuccessful_assert_is_directory_not_empty() { } function test_successful_assert_is_directory_readable() { - local a_directory=$(temp_dir) + local a_directory=$(mktemp -d) assert_empty "$(assert_is_directory_readable "$a_directory")" } @@ -115,7 +115,7 @@ function test_unsuccessful_assert_is_directory_readable_without_execution_permis return fi - local a_directory=$(temp_dir) + local a_directory=$(mktemp -d) chmod a-x "$a_directory" assert_same\ @@ -130,7 +130,7 @@ function test_unsuccessful_assert_is_directory_readable_without_read_permission( return fi - local a_directory=$(temp_dir) + local a_directory=$(mktemp -d) chmod a-r "$a_directory" assert_same\ @@ -145,7 +145,7 @@ function test_successful_assert_is_directory_not_readable_without_read_permissio return fi - local a_directory=$(temp_dir) + local a_directory=$(mktemp -d) chmod a-r "$a_directory" assert_empty "$(assert_is_directory_not_readable "$a_directory")" @@ -156,14 +156,14 @@ function test_successful_assert_is_directory_not_readable_without_execution_perm return fi - local a_directory=$(temp_dir) + local a_directory=$(mktemp -d) chmod a-x "$a_directory" assert_empty "$(assert_is_directory_not_readable "$a_directory")" } function test_unsuccessful_assert_is_directory_not_readable() { - local a_directory=$(temp_dir) + local a_directory=$(mktemp -d) assert_same\ "$(console_results::print_failed_test \ @@ -172,7 +172,7 @@ function test_unsuccessful_assert_is_directory_not_readable() { } function test_successful_assert_is_directory_writable() { - local a_directory=$(temp_dir) + local a_directory=$(mktemp -d) assert_empty "$(assert_is_directory_writable "$a_directory")" } @@ -182,7 +182,7 @@ function test_unsuccessful_assert_is_directory_writable() { return fi - local a_directory=$(temp_dir) + local a_directory=$(mktemp -d) chmod a-w "$a_directory" assert_same\ @@ -206,14 +206,14 @@ function test_successful_assert_is_directory_not_writable() { return fi - local a_directory=$(temp_dir) + local a_directory=$(mktemp -d) chmod a-w "$a_directory" assert_empty "$(assert_is_directory_not_writable "$a_directory")" } function test_unsuccessful_assert_is_directory_not_writable() { - local a_directory=$(temp_dir) + local a_directory=$(mktemp -d) assert_same\ "$(console_results::print_failed_test\ diff --git a/tests/unit/state_test.sh b/tests/unit/state_test.sh index 9fa4fda1..047f8cf2 100644 --- a/tests/unit/state_test.sh +++ b/tests/unit/state_test.sh @@ -234,6 +234,8 @@ function test_set_duplicated_functions_merged() { } function test_initialize_assertions_count() { + mock tr echo "abc123" + local export_assertions_count export_assertions_count=$( _ASSERTIONS_PASSED=10 @@ -247,7 +249,8 @@ function test_initialize_assertions_count() { ) assert_same\ - "##ASSERTIONS_FAILED=0\ + "##TEST_ID=abc123\ +##ASSERTIONS_FAILED=0\ ##ASSERTIONS_PASSED=0\ ##ASSERTIONS_SKIPPED=0\ ##ASSERTIONS_INCOMPLETE=0\ @@ -258,6 +261,8 @@ function test_initialize_assertions_count() { } function test_export_assertions_count() { + mock tr echo "abc123" + local export_assertions_count export_assertions_count=$( _ASSERTIONS_PASSED=10 @@ -272,7 +277,8 @@ function test_export_assertions_count() { ) assert_same\ - "##ASSERTIONS_FAILED=5\ + "##TEST_ID=abc123\ +##ASSERTIONS_FAILED=5\ ##ASSERTIONS_PASSED=10\ ##ASSERTIONS_SKIPPED=42\ ##ASSERTIONS_INCOMPLETE=12\ @@ -282,12 +288,13 @@ function test_export_assertions_count() { } function test_calculate_total_assertions() { - local input="##ASSERTIONS_FAILED=1\ + local input="##TEST_ID=abc123\ + ##ASSERTIONS_FAILED=1\ ##ASSERTIONS_PASSED=2\ ##ASSERTIONS_SKIPPED=3\ ##ASSERTIONS_INCOMPLETE=4\ ##ASSERTIONS_SNAPSHOT=5\ - ##TEST_OUTPUT=##" + ##TEST_OUTPUT=3zhbEncodedBase64##" assert_same 15 "$(state::calculate_total_assertions "$input")" }