#!/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 \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