|
|
|
#!/usr/bin/env bash
|
|
|
|
set -eET
|
|
|
|
|
|
|
|
# Variables used in other scripts.
|
|
|
|
BATS_COUNT_ONLY=''
|
|
|
|
BATS_TEST_FILTER=''
|
|
|
|
BATS_ENABLE_TIMING=''
|
|
|
|
BATS_EXTENDED_SYNTAX=''
|
|
|
|
BATS_TRACE_LEVEL="${BATS_TRACE_LEVEL:-0}"
|
|
|
|
BATS_PRINT_OUTPUT_ON_FAILURE="${BATS_PRINT_OUTPUT_ON_FAILURE:-}"
|
|
|
|
BATS_SHOW_OUTPUT_OF_SUCCEEDING_TESTS="${BATS_SHOW_OUTPUT_OF_SUCCEEDING_TESTS:-}"
|
|
|
|
BATS_VERBOSE_RUN="${BATS_VERBOSE_RUN:-}"
|
|
|
|
BATS_GATHER_TEST_OUTPUTS_IN="${BATS_GATHER_TEST_OUTPUTS_IN:-}"
|
|
|
|
|
|
|
|
while [[ "$#" -ne 0 ]]; do
|
|
|
|
case "$1" in
|
|
|
|
-c)
|
|
|
|
# shellcheck disable=SC2034
|
|
|
|
BATS_COUNT_ONLY=1
|
|
|
|
;;
|
|
|
|
-f)
|
|
|
|
shift
|
|
|
|
# shellcheck disable=SC2034
|
|
|
|
BATS_TEST_FILTER="$1"
|
|
|
|
;;
|
|
|
|
-T)
|
|
|
|
BATS_ENABLE_TIMING='-T'
|
|
|
|
;;
|
|
|
|
-x)
|
|
|
|
# shellcheck disable=SC2034
|
|
|
|
BATS_EXTENDED_SYNTAX='-x'
|
|
|
|
;;
|
|
|
|
--dummy-flag)
|
|
|
|
;;
|
|
|
|
--trace)
|
|
|
|
(( ++BATS_TRACE_LEVEL )) # avoid returning 0
|
|
|
|
;;
|
|
|
|
--print-output-on-failure)
|
|
|
|
BATS_PRINT_OUTPUT_ON_FAILURE=1
|
|
|
|
;;
|
|
|
|
--show-output-of-passing-tests)
|
|
|
|
BATS_SHOW_OUTPUT_OF_SUCCEEDING_TESTS=1
|
|
|
|
;;
|
|
|
|
--verbose-run)
|
|
|
|
BATS_VERBOSE_RUN=1
|
|
|
|
;;
|
|
|
|
--gather-test-outputs-in)
|
|
|
|
shift
|
|
|
|
BATS_GATHER_TEST_OUTPUTS_IN="$1"
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
break
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
|
|
|
|
export BATS_TEST_FILENAME="$1"
|
|
|
|
export BATS_TEST_NAME="$2"
|
|
|
|
export BATS_SUITE_TEST_NUMBER="$3"
|
|
|
|
export BATS_TEST_NUMBER="$4"
|
|
|
|
|
|
|
|
if [[ -z "$BATS_TEST_FILENAME" ]]; then
|
|
|
|
printf 'usage: bats-exec-test <filename>\n' >&2
|
|
|
|
exit 1
|
|
|
|
elif [[ ! -f "$BATS_TEST_FILENAME" ]]; then
|
|
|
|
printf 'bats: %s does not exist\n' "$BATS_TEST_FILENAME" >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
bats_create_test_tmpdirs() {
|
|
|
|
local tests_tmpdir="${BATS_RUN_TMPDIR}/test/"
|
|
|
|
if ! mkdir -p "$tests_tmpdir"; then
|
|
|
|
printf 'Failed to create: %s\n' "$tests_tmpdir" >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
BATS_TEST_TMPDIR="$tests_tmpdir/$BATS_SUITE_TEST_NUMBER"
|
|
|
|
if ! mkdir "$BATS_TEST_TMPDIR"; then
|
|
|
|
printf 'Failed to create BATS_TEST_TMPDIR: %s\n' "$BATS_TEST_TMPDIR" >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
printf "%s\n" "$BATS_TEST_NAME" > "$BATS_TEST_TMPDIR.name"
|
|
|
|
|
|
|
|
export BATS_TEST_TMPDIR
|
|
|
|
}
|
|
|
|
|
|
|
|
# load the test helper functions like `load` or `run` that are needed to run a (preprocessed) .bats file without bash errors
|
|
|
|
# shellcheck source=lib/bats-core/test_functions.bash disable=SC2153
|
|
|
|
source "$BATS_ROOT/lib/bats-core/test_functions.bash"
|
|
|
|
# shellcheck source=lib/bats-core/tracing.bash disable=SC2153
|
|
|
|
source "$BATS_ROOT/lib/bats-core/tracing.bash"
|
|
|
|
|
|
|
|
bats_teardown_trap() {
|
|
|
|
bats_check_status_from_trap
|
|
|
|
local status=0
|
|
|
|
# mark the start of this function to distinguish where skip is called
|
|
|
|
# parameter 1 will signify the reason why this function was called
|
|
|
|
# this is used to identify when this is called as exit trap function
|
|
|
|
BATS_TEARDOWN_STARTED=${1:-1}
|
|
|
|
teardown >>"$BATS_OUT" 2>&1 || status="$?"
|
|
|
|
|
|
|
|
if [[ $status -eq 0 ]]; then
|
|
|
|
BATS_TEARDOWN_COMPLETED=1
|
|
|
|
elif [[ -n "$BATS_TEST_COMPLETED" ]]; then
|
|
|
|
BATS_DEBUG_LAST_STACK_TRACE_IS_VALID=1
|
|
|
|
BATS_ERROR_STATUS="$status"
|
|
|
|
fi
|
|
|
|
|
|
|
|
bats_exit_trap
|
|
|
|
}
|
|
|
|
|
|
|
|
# shellcheck source=lib/bats-core/common.bash
|
|
|
|
source "$BATS_ROOT/lib/bats-core/common.bash"
|
|
|
|
|
|
|
|
bats_exit_trap() {
|
|
|
|
local status
|
|
|
|
local skipped=''
|
|
|
|
trap - ERR EXIT
|
|
|
|
|
|
|
|
if [[ -n "$BATS_TEST_SKIPPED" ]]; then
|
|
|
|
skipped=' # skip'
|
|
|
|
if [[ "$BATS_TEST_SKIPPED" != '1' ]]; then
|
|
|
|
skipped+=" $BATS_TEST_SKIPPED"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
BATS_TEST_TIME=''
|
|
|
|
if [[ -z "${skipped}" && -n "$BATS_ENABLE_TIMING" ]]; then
|
|
|
|
BATS_TEST_TIME=" in "$(( $(get_mills_since_epoch) - BATS_TEST_START_TIME ))"ms"
|
|
|
|
fi
|
|
|
|
|
|
|
|
local print_bats_out="${BATS_SHOW_OUTPUT_OF_SUCCEEDING_TESTS}"
|
|
|
|
|
|
|
|
if [[ -z "$BATS_TEST_COMPLETED" || -z "$BATS_TEARDOWN_COMPLETED" || "${BATS_INTERRUPTED-NOTSET}" != NOTSET ]]; then
|
|
|
|
if [[ "$BATS_ERROR_STATUS" -eq 0 ]]; then
|
|
|
|
# For some versions of bash, `$?` may not be set properly for some error
|
|
|
|
# conditions before triggering the EXIT trap directly (see #72 and #81).
|
|
|
|
# Thanks to the `BATS_TEARDOWN_COMPLETED` signal, this will pinpoint such
|
|
|
|
# errors if they happen during `teardown()` when `bats_perform_test` calls
|
|
|
|
# `bats_teardown_trap` directly after the test itself passes.
|
|
|
|
#
|
|
|
|
# If instead the test fails, and the `teardown()` error happens while
|
|
|
|
# `bats_teardown_trap` runs as the EXIT trap, the test will fail with no
|
|
|
|
# output, since there's no way to reach the `bats_exit_trap` call.
|
|
|
|
BATS_ERROR_STATUS=1
|
|
|
|
fi
|
|
|
|
printf 'not ok %d %s\n' "$BATS_SUITE_TEST_NUMBER" "${BATS_TEST_DESCRIPTION}${BATS_TEST_TIME}" >&3
|
|
|
|
local stack_trace
|
|
|
|
bats_get_failure_stack_trace stack_trace
|
|
|
|
bats_print_stack_trace "${stack_trace[@]}" >&3
|
|
|
|
bats_print_failed_command "${stack_trace[@]}" >&3
|
|
|
|
|
|
|
|
if [[ $BATS_PRINT_OUTPUT_ON_FAILURE && -n "${output:-}" ]]; then
|
|
|
|
printf "Last output:\n%s\n" "$output" >> "$BATS_OUT"
|
|
|
|
fi
|
|
|
|
|
|
|
|
print_bats_out=1
|
|
|
|
status=1
|
|
|
|
else
|
|
|
|
printf 'ok %d %s%s\n' "$BATS_SUITE_TEST_NUMBER" "${BATS_TEST_DESCRIPTION}${BATS_TEST_TIME}" \
|
|
|
|
"$skipped" >&3
|
|
|
|
status=0
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [[ $print_bats_out ]]; then
|
|
|
|
bats_prefix_lines_for_tap_output < "$BATS_OUT" | bats_replace_filename >&3
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [[ $BATS_GATHER_TEST_OUTPUTS_IN ]]; then
|
|
|
|
cp "$BATS_OUT" "$BATS_GATHER_TEST_OUTPUTS_IN/$BATS_SUITE_TEST_NUMBER-$BATS_TEST_DESCRIPTION.log"
|
|
|
|
fi
|
|
|
|
|
|
|
|
rm -f "$BATS_OUT"
|
|
|
|
exit "$status"
|
|
|
|
}
|
|
|
|
|
|
|
|
get_mills_since_epoch() {
|
|
|
|
local ms_since_epoch
|
|
|
|
ms_since_epoch=$(date +%s%N)
|
|
|
|
if [[ "$ms_since_epoch" == *N || "${#ms_since_epoch}" -lt 19 ]]; then
|
|
|
|
ms_since_epoch=$(( $(date +%s) * 1000 ))
|
|
|
|
else
|
|
|
|
ms_since_epoch=$(( ms_since_epoch / 1000000 ))
|
|
|
|
fi
|
|
|
|
|
|
|
|
printf "%d\n" "$ms_since_epoch"
|
|
|
|
}
|
|
|
|
|
|
|
|
bats_perform_test() {
|
|
|
|
if ! declare -F "$BATS_TEST_NAME" &>/dev/null; then
|
|
|
|
local quoted_test_name
|
|
|
|
bats_quote_code quoted_test_name "$BATS_TEST_NAME"
|
|
|
|
printf "bats: unknown test name %s\n" "$quoted_test_name" >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Variables for capturing accurate stack traces. See bats_debug_trap for
|
|
|
|
# details.
|
|
|
|
#
|
|
|
|
# BATS_DEBUG_LAST_LINENO, BATS_DEBUG_LAST_SOURCE, and
|
|
|
|
# BATS_DEBUG_LAST_STACK_TRACE hold data from the most recent call to
|
|
|
|
# bats_debug_trap.
|
|
|
|
#
|
|
|
|
# BATS_DEBUG_LASTLAST_STACK_TRACE holds data from two bats_debug_trap calls
|
|
|
|
# ago.
|
|
|
|
#
|
|
|
|
# BATS_DEBUG_LAST_STACK_TRACE_IS_VALID indicates that
|
|
|
|
# BATS_DEBUG_LAST_STACK_TRACE contains the stack trace of the test's error. If
|
|
|
|
# unset, BATS_DEBUG_LAST_STACK_TRACE is unreliable and
|
|
|
|
# BATS_DEBUG_LASTLAST_STACK_TRACE should be used instead.
|
|
|
|
BATS_DEBUG_LASTLAST_STACK_TRACE=()
|
|
|
|
BATS_DEBUG_LAST_LINENO=()
|
|
|
|
BATS_DEBUG_LAST_SOURCE=()
|
|
|
|
BATS_DEBUG_LAST_STACK_TRACE=()
|
|
|
|
BATS_DEBUG_LAST_STACK_TRACE_IS_VALID=
|
|
|
|
|
|
|
|
BATS_TEST_COMPLETED=
|
|
|
|
BATS_TEST_SKIPPED=
|
|
|
|
BATS_TEARDOWN_COMPLETED=
|
|
|
|
BATS_ERROR_STATUS=
|
|
|
|
BATS_ERROR_SUFFIX=
|
|
|
|
bats_setup_tracing
|
|
|
|
# mark this call as trap call
|
|
|
|
trap 'bats_teardown_trap as-exit-trap' EXIT
|
|
|
|
|
|
|
|
BATS_TEST_START_TIME=$(get_mills_since_epoch)
|
|
|
|
"$BATS_TEST_NAME" >>"$BATS_OUT" 2>&1 4>&1
|
|
|
|
|
|
|
|
BATS_TEST_COMPLETED=1
|
|
|
|
trap 'bats_exit_trap' EXIT
|
|
|
|
bats_teardown_trap "" # pass empty parameter to signify call outside trap
|
|
|
|
}
|
|
|
|
|
|
|
|
trap bats_interrupt_trap INT
|
|
|
|
|
|
|
|
# shellcheck source=lib/bats-core/preprocessing.bash
|
|
|
|
source "$BATS_ROOT/lib/bats-core/preprocessing.bash"
|
|
|
|
|
|
|
|
exec 3<&1
|
|
|
|
|
|
|
|
bats_create_test_tmpdirs
|
|
|
|
# Run the given test.
|
|
|
|
bats_evaluate_preprocessed_source
|
|
|
|
bats_perform_test
|