Skip to content

Commit

Permalink
Merge branch 'feature/improve_run_output_handling'
Browse files Browse the repository at this point in the history
  • Loading branch information
martin-schulze-vireso committed Jul 24, 2021
2 parents 5218bbc + 81324f9 commit c6278fd
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 8 deletions.
119 changes: 111 additions & 8 deletions lib/bats-core/test_functions.bash
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,121 @@ load() {
source "${file}"
}

run() {
bats_suppress_stderr() {
"$@" 2>/dev/null
}

bats_suppress_stdout() {
# throw away stdout and redirect stderr into stdout
# shellcheck disable=SC2069
"$@" 2>&1 >/dev/null
}

bats_redirect_stderr_into_file() {
"$@" 2>>"$bats_run_separate_stderr_file" # use >> to see collisions' content
}

bats_merge_stdout_and_stderr() {
"$@" 2>&1
}

# write separate lines from <input-var> into <output-array>
bats_separate_lines() { # <output-array> <input-var>
output_array_name="$1"
input_var_name="$2"
if [[ $keep_empty_lines ]]; then
local bats_separate_lines_lines=()
while IFS= read -r line; do
bats_separate_lines_lines+=("$line")
done <<<"${!input_var_name}"
eval "${output_array_name}=(\"\${bats_separate_lines_lines[@]}\")"
else
# shellcheck disable=SC2034,SC2206
IFS=$'\n' read -d '' -r -a "$output_array_name" <<<"${!input_var_name}"
fi
}

run() { # [--keep-empty-lines] [--output merged|separate|stderr|stdout] [--] <command to run...>
trap bats_interrupt_trap_in_run INT
local keep_empty_lines=
local output_case=merged
# parse options starting with -
while [[ $# -gt 0 && $1 == -* ]]; do
case "$1" in
--keep-empty-lines)
keep_empty_lines=1
;;
--output)
output_case="$2"
shift 2 # consume the value too!
;;
--)
shift # eat the -- before breaking away
break
;;
esac
shift
done

local pre_command=

case "$output_case" in
merged) # redirects stderr into stdout and fills only $output/$lines
pre_command=bats_merge_stdout_and_stderr
;;
separate) # splits stderr into own file and fills $stderr/$stderr_lines too
local bats_run_separate_stderr_file
bats_run_separate_stderr_file="$(mktemp "${BATS_TEST_TMPDIR}/separate-stderr-XXXXXX")"
pre_command=bats_redirect_stderr_into_file
;;
stderr) # suppresses stdout and fills $stderr/$stderr_lines
pre_command=bats_suppress_stdout
;;
stdout) # suppresses stderr and fills $output/$lines
pre_command=bats_suppress_stderr
;;
*)
printf "ERROR: Unknown --output value %s" "$output_case"
return 1
;;
esac

local origFlags="$-"
set -f +eET
local origIFS="$IFS"
# 'output', 'status', 'lines' are global variables available to tests.
# shellcheck disable=SC2034
output="$("$@" 2>&1)"
# shellcheck disable=SC2034
status="$?"
# shellcheck disable=SC2034,SC2206
IFS=$'\n' lines=($output)
if [[ $keep_empty_lines ]]; then
# 'output', 'status', 'lines' are global variables available to tests.
# preserve trailing newlines by appending . and removing it later
# shellcheck disable=SC2034
output="$($pre_command "$@"; status=$?; printf .; exit $status)"
# shellcheck disable=SC2034
status="$?"
output="${output%.}"
else
# 'output', 'status', 'lines' are global variables available to tests.
# shellcheck disable=SC2034
output="$($pre_command "$@")"
# shellcheck disable=SC2034
status="$?"
fi

bats_separate_lines lines output

case "$output_case" in
stderr)
stderr="$output"
# shellcheck disable=SC2034
stderr_lines=("${lines[@]}")
unset output
unset lines
;;
separate)
# shellcheck disable=SC2034
read -d '' -r stderr < "$bats_run_separate_stderr_file"
bats_separate_lines stderr_lines stderr
;;
esac

IFS="$origIFS"
set "-$origFlags"
}
Expand Down
76 changes: 76 additions & 0 deletions test/run.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
@test "run --keep-empty-lines preserves leading empty lines" {
run --keep-empty-lines -- echo -n $'\na'
printf "'%s'\n" "${lines[@]}"
[ "${lines[0]}" == '' ]
[ "${lines[1]}" == a ]
[ ${#lines[@]} -eq 2 ]
}

@test "run --keep-empty-lines preserves inner empty lines" {
run --keep-empty-lines -- echo -n $'a\n\nb'
printf "'%s'\n" "${lines[@]}"
[ "${lines[0]}" == a ]
[ "${lines[1]}" == '' ]
[ "${lines[2]}" == b ]
[ ${#lines[@]} -eq 3 ]
}

@test "run --keep-empty-lines preserves trailing empty lines" {
run --keep-empty-lines -- echo -n $'a\n'
printf "'%s'\n" "${lines[@]}"
[ "${lines[0]}" == a ]
[ "${lines[1]}" == '' ]
[ ${#lines[@]} -eq 2 ]
}

@test "run --keep-empty-lines preserves multiple trailing empty lines" {
run --keep-empty-lines -- echo -n $'a\n\n'
printf "'%s'\n" "${lines[@]}"
[ "${lines[0]}" == a ]
[ "${lines[1]}" == '' ]
[ "${lines[2]}" == '' ]
[ ${#lines[@]} -eq 3 ]
}

@test "run --keep-empty-lines preserves non-empty trailing line" {
run --keep-empty-lines -- echo -n $'a\nb'
printf "'%s'\n" "${lines[@]}"
[ "${lines[0]}" == a ]
[ "${lines[1]}" == b ]
[ ${#lines[@]} -eq 2 ]
}

print-stderr-stdout() {
printf stdout
printf stderr >&2
}

@test "run --output stdout does not print stderr" {
run --output stdout -- print-stderr-stdout
echo "output='$output' stderr='$stderr'"
[ "$output" = "stdout" ]
[ ${#lines[@]} -eq 1 ]

[ "${stderr-notset}" = notset ]
[ ${#stderr_lines[@]} -eq 0 ]
}

@test "run --output stderr does not print stdout" {
run --output stderr -- print-stderr-stdout
echo "output='$output' stderr='$stderr'"
[ "${output-notset}" = notset ]
[ ${#lines[@]} -eq 0 ]

[ "$stderr" = stderr ]
[ ${#stderr_lines[@]} -eq 1 ]
}

@test "run --output separate splits output" {
run --output separate -- print-stderr-stdout
echo "output='$output' stderr='$stderr'"
[ "$output" = stdout ]
[ ${#lines[@]} -eq 1 ]

[ "$stderr" = stderr ]
[ ${#stderr_lines[@]} -eq 1 ]
}

0 comments on commit c6278fd

Please sign in to comment.