#!/usr/bin/env bash
set -eET

# Variables used in other scripts.
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:-}"
BATS_TEST_NAME_PREFIX="${BATS_TEST_NAME_PREFIX:-}"

while [[ "$#" -ne 0 ]]; do
  case "$1" in
  -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"
BATS_TEST_TRY_NUMBER="$5"

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%d: %s\n' "$BATS_TEST_TRY_NUMBER" "$BATS_TEST_TMPDIR" >&2
    exit 1
  fi

  printf "%s\n" "$BATS_TEST_NAME" >> "$BATS_TEST_TMPDIR.name" # append name in case of test retries

  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/$BATS_LIBDIR/bats-core/test_functions.bash"
_bats_test_functions_setup "$BATS_TEST_NUMBER"

# shellcheck source=lib/bats-core/tracing.bash disable=SC2153
source "$BATS_ROOT/$BATS_LIBDIR/bats-core/tracing.bash"

bats_teardown_trap() {
  bats_check_status_from_trap
  local bats_teardown_trap_status=0

  bats_set_stacktrace_limit

  # 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 || bats_teardown_trap_status="$?"

  if [[ $bats_teardown_trap_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="$bats_teardown_trap_status"
  fi

  bats_exit_trap
}

# shellcheck source=lib/bats-core/common.bash
source "$BATS_ROOT/$BATS_LIBDIR/bats-core/common.bash"

bats_exit_trap() {
  local status
  local exit_metadata=''
  trap - ERR EXIT
  if [[ -n "${BATS_TEST_TIMEOUT:-}" ]]; then
    # Kill the watchdog in the case of of kernel finished before the timeout
    bats_abort_timeout_countdown || status=1
  fi

  if [[ -n "$BATS_TEST_SKIPPED" ]]; then
    exit_metadata=' # skip'
    if [[ "$BATS_TEST_SKIPPED" != '1' ]]; then
      exit_metadata+=" $BATS_TEST_SKIPPED"
    fi
  elif [[ "${BATS_TIMED_OUT-NOTSET}" != NOTSET ]]; then
    exit_metadata=" # timeout after ${BATS_TEST_TIMEOUT}s"
  fi

  BATS_TEST_TIME=''
  if [[ -n "$BATS_ENABLE_TIMING" ]]; then
    get_mills_since_epoch BATS_TEST_END_TIME
    BATS_TEST_TIME=" in "$((BATS_TEST_END_TIME - BATS_TEST_START_TIME))"ms"
  fi

  local print_bats_out="${BATS_SHOW_OUTPUT_OF_SUCCEEDING_TESTS}"

  local should_retry=''
  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
    if bats_should_retry_test; then
      should_retry=1
      status=126                # signify retry
      rm -r "$BATS_TEST_TMPDIR" # clean up for retry
    else
      printf 'not ok %d %s%s\n' "$BATS_SUITE_TEST_NUMBER" "${BATS_TEST_NAME_PREFIX:-}${BATS_TEST_DESCRIPTION}${BATS_TEST_TIME}" "$exit_metadata" >&3
      if (( ${#BATS_TEST_TAGS[@]} > 0 )); then
        printf '# tags:'
        printf ' %s' "${BATS_TEST_TAGS[@]}"
        printf '\n'
      fi >&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 ]]; then
        if [[ -n "${output:-}" ]]; then
          printf "Last output:\n%s\n" "$output"
        fi
        if [[ -n "${stderr:-}" ]]; then
          printf "Last stderr: \n%s\n" "$stderr"
        fi
      fi >>"$BATS_OUT"

      print_bats_out=1
      status=1
      local state=failed
    fi
  else
    printf 'ok %d %s%s\n' "$BATS_SUITE_TEST_NUMBER" "${BATS_TEST_NAME_PREFIX:-}${BATS_TEST_DESCRIPTION}${BATS_TEST_TIME}" \
      "$exit_metadata" >&3
    status=0
    local state=passed
  fi

  if [[ -z "$should_retry" ]]; then
    printf "%s %s\t%s\n" "$state" "$BATS_TEST_FILENAME" "$BATS_TEST_NAME" >>"$BATS_RUNLOG_FILE"

    if [[ $print_bats_out ]]; then
      bats_prefix_lines_for_tap_output <"$BATS_OUT" | bats_replace_filename >&3
    fi
  fi
  if [[ $BATS_GATHER_TEST_OUTPUTS_IN ]]; then
    local try_suffix=
    if [[ -n "$should_retry" ]]; then
      try_suffix="-try$BATS_TEST_TRY_NUMBER"
    fi
    # Only copy if BATS_OUT exists (it may not exist if test produced no output)
    if [[ -f "$BATS_OUT" ]]; then
      cp "$BATS_OUT" "$BATS_GATHER_TEST_OUTPUTS_IN/$BATS_SUITE_TEST_NUMBER$try_suffix-${BATS_TEST_DESCRIPTION//\//%2F}.log"
    fi
  fi
  rm -f "$BATS_OUT"
  exit "$status"
}

# Marks the test as failed due to timeout.
# The actual                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  