mirror of https://github.com/sobolevn/git-secret
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
326 lines
9.4 KiB
Bash
326 lines
9.4 KiB
Bash
#!/usr/bin/env bash
|
|
set -eET
|
|
|
|
export flags=('--dummy-flag')
|
|
num_jobs=${BATS_NUMBER_OF_PARALLEL_JOBS:-1}
|
|
filter=''
|
|
extended_syntax=''
|
|
BATS_TRACE_LEVEL="${BATS_TRACE_LEVEL:-0}"
|
|
|
|
while [[ "$#" -ne 0 ]]; do
|
|
case "$1" in
|
|
-c) ;;
|
|
|
|
-f)
|
|
shift
|
|
filter="$1"
|
|
flags+=('-f' "$filter")
|
|
;;
|
|
-j)
|
|
shift
|
|
num_jobs="$1"
|
|
;;
|
|
-T)
|
|
flags+=('-T')
|
|
;;
|
|
-x)
|
|
flags+=('-x')
|
|
extended_syntax=1
|
|
;;
|
|
--no-parallelize-within-files)
|
|
# use singular to allow for users to override in file
|
|
BATS_NO_PARALLELIZE_WITHIN_FILE=1
|
|
;;
|
|
--dummy-flag)
|
|
;;
|
|
--trace)
|
|
flags+=('--trace')
|
|
;;
|
|
--print-output-on-failure)
|
|
flags+=(--print-output-on-failure)
|
|
;;
|
|
--show-output-of-passing-tests)
|
|
flags+=(--show-output-of-passing-tests)
|
|
;;
|
|
--verbose-run)
|
|
flags+=(--verbose-run)
|
|
;;
|
|
--gather-test-outputs-in)
|
|
shift
|
|
flags+=(--gather-test-outputs-in "$1")
|
|
;;
|
|
*)
|
|
break
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
filename="$1"
|
|
TESTS_FILE="$2"
|
|
|
|
if [[ ! -f "$filename" ]]; then
|
|
printf 'Testfile "%s" not found\n' "$filename" >&2
|
|
exit 1
|
|
fi
|
|
|
|
export BATS_TEST_FILENAME="$filename"
|
|
|
|
# shellcheck source=lib/bats-core/preprocessing.bash
|
|
# shellcheck disable=SC2153
|
|
source "$BATS_ROOT/lib/bats-core/preprocessing.bash"
|
|
|
|
bats_run_setup_file() {
|
|
# shellcheck source=lib/bats-core/tracing.bash
|
|
# shellcheck disable=SC2153
|
|
source "$BATS_ROOT/lib/bats-core/tracing.bash"
|
|
# shellcheck source=lib/bats-core/test_functions.bash
|
|
# shellcheck disable=SC2153
|
|
source "$BATS_ROOT/lib/bats-core/test_functions.bash"
|
|
|
|
exec 3<&1
|
|
|
|
# these are defined only to avoid errors when referencing undefined variables down the line
|
|
# shellcheck disable=2034
|
|
BATS_TEST_NAME= # used in tracing.bash
|
|
# shellcheck disable=2034
|
|
BATS_TEST_COMPLETED= # used in tracing.bash
|
|
|
|
BATS_SOURCE_FILE_COMPLETED=
|
|
BATS_SETUP_FILE_COMPLETED=
|
|
BATS_TEARDOWN_FILE_COMPLETED=
|
|
# shellcheck disable=2034
|
|
BATS_ERROR_STATUS= # used in tracing.bash
|
|
touch "$BATS_OUT"
|
|
bats_setup_tracing
|
|
trap 'bats_file_teardown_trap' EXIT
|
|
|
|
local status=0
|
|
# get the setup_file/teardown_file functions for this file (if it has them)
|
|
# shellcheck disable=SC1090
|
|
source "$BATS_TEST_SOURCE" >>"$BATS_OUT" 2>&1
|
|
|
|
BATS_SOURCE_FILE_COMPLETED=1
|
|
|
|
setup_file >>"$BATS_OUT" 2>&1
|
|
|
|
BATS_SETUP_FILE_COMPLETED=1
|
|
}
|
|
|
|
bats_run_teardown_file() {
|
|
# avoid running the therdown trap due to errors in teardown_file
|
|
trap 'bats_file_exit_trap' EXIT
|
|
# rely on bats_error_trap to catch failures
|
|
teardown_file >>"$BATS_OUT" 2>&1
|
|
|
|
BATS_TEARDOWN_FILE_COMPLETED=1
|
|
}
|
|
|
|
bats_file_teardown_trap() {
|
|
bats_run_teardown_file
|
|
local status=0
|
|
bats_file_exit_trap
|
|
}
|
|
|
|
# shellcheck source=lib/bats-core/common.bash
|
|
source "$BATS_ROOT/lib/bats-core/common.bash"
|
|
|
|
bats_file_exit_trap() {
|
|
trap - ERR EXIT
|
|
if [[ -z "$BATS_SETUP_FILE_COMPLETED" || -z "$BATS_TEARDOWN_FILE_COMPLETED" ]]; then
|
|
if [[ -z "$BATS_SETUP_FILE_COMPLETED" ]]; then
|
|
FAILURE_REASON='setup_file'
|
|
elif [[ -z "$BATS_TEARDOWN_FILE_COMPLETED" ]]; then
|
|
FAILURE_REASON='teardown_file'
|
|
elif [[ -z "$BATS_SOURCE_FILE_COMPLETED" ]]; then
|
|
FAILURE_REASON='source'
|
|
else
|
|
FAILURE_REASON='unknown internal'
|
|
fi
|
|
printf "not ok %d %s\n" "$((test_number_in_suite + 1))" "$FAILURE_REASON failed" >&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
|
|
bats_prefix_lines_for_tap_output < "$BATS_OUT" | bats_replace_filename >&3
|
|
rm -rf "$BATS_OUT"
|
|
status=1
|
|
fi
|
|
exit $status
|
|
}
|
|
|
|
function setup_file() {
|
|
return 0
|
|
}
|
|
|
|
function teardown_file() {
|
|
return 0
|
|
}
|
|
|
|
bats_forward_output_of_parallel_test() {
|
|
local test_number_in_suite=$1
|
|
local status=0
|
|
wait "$(cat "$output_folder/$test_number_in_suite/pid")" || status=1
|
|
cat "$output_folder/$test_number_in_suite/stdout"
|
|
cat "$output_folder/$test_number_in_suite/stderr" >&2
|
|
return $status
|
|
}
|
|
|
|
bats_is_next_parallel_test_finished() {
|
|
local PID
|
|
# get the pid of the next potentially finished test
|
|
PID=$(cat "$output_folder/$(( test_number_in_suite_of_last_finished_test + 1 ))/pid")
|
|
# try to send a signal to this process
|
|
# if it fails, the process exited,
|
|
# if it succeeds, the process is still running
|
|
if kill -0 "$PID" 2>/dev/null; then
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# prints output from all tests in the order they were started
|
|
# $1 == "blocking": wait for a test to finish before printing
|
|
# != "blocking": abort printing, when a test has not finished
|
|
bats_forward_output_for_parallel_tests() {
|
|
local status=0
|
|
# was the next test already started?
|
|
while [[ $(( test_number_in_suite_of_last_finished_test + 1 )) -le $test_number_in_suite ]]; do
|
|
# if we are okay with waiting or if the test has already been finished
|
|
if [[ "$1" == "blocking" ]] || bats_is_next_parallel_test_finished ; then
|
|
(( ++test_number_in_suite_of_last_finished_test ))
|
|
bats_forward_output_of_parallel_test "$test_number_in_suite_of_last_finished_test" || status=1
|
|
else
|
|
# non-blocking and the process has not finished -> abort the printing
|
|
break
|
|
fi
|
|
done
|
|
return $status
|
|
}
|
|
|
|
bats_run_tests_in_parallel() {
|
|
local output_folder="$BATS_RUN_TMPDIR/parallel_output"
|
|
local status=0
|
|
mkdir -p "$output_folder"
|
|
# shellcheck source=lib/bats-core/semaphore.bash
|
|
source "$BATS_ROOT/lib/bats-core/semaphore.bash"
|
|
bats_semaphore_setup
|
|
# the test_number_in_file is not yet incremented -> one before the next test to run
|
|
local test_number_in_suite_of_last_finished_test="$test_number_in_suite" # stores which test was printed last
|
|
for test_name in "${tests_to_run[@]}"; do
|
|
# Only handle non-empty lines
|
|
if [[ $test_name ]]; then
|
|
((++test_number_in_suite))
|
|
((++test_number_in_file))
|
|
mkdir -p "$output_folder/$test_number_in_suite"
|
|
bats_semaphore_run "$output_folder/$test_number_in_suite" \
|
|
"$BATS_LIBEXEC/bats-exec-test" "${flags[@]}" "$filename" "$test_name" "$test_number_in_suite" "$test_number_in_file" \
|
|
> "$output_folder/$test_number_in_suite/pid"
|
|
fi
|
|
# print results early to get interactive feedback
|
|
bats_forward_output_for_parallel_tests non-blocking || status=1 # ignore if we did not finish yet
|
|
done
|
|
bats_forward_output_for_parallel_tests blocking || status=1
|
|
return $status
|
|
}
|
|
|
|
bats_read_tests_list_file() {
|
|
local line_number=0
|
|
tests_to_run=()
|
|
# the global test number must be visible to traps -> not local
|
|
first_test_number_in_suite=''
|
|
while read -r test_line; do
|
|
# check if the line begins with filename
|
|
# filename might contain some hard to parse characters,
|
|
# use simple string operations to work around that issue
|
|
if [[ "$filename" == "${test_line::${#filename}}" ]]; then
|
|
# get the rest of the line without the separator \t
|
|
test_name=${test_line:$((1 + ${#filename} ))}
|
|
tests_to_run+=("$test_name")
|
|
# save the first test's number for later iteration
|
|
# this assumes that tests for a file are stored consecutive in the file!
|
|
if [[ -z "$first_test_number_in_suite" ]]; then
|
|
first_test_number_in_suite=$line_number
|
|
fi
|
|
fi
|
|
((++line_number))
|
|
done <"$TESTS_FILE"
|
|
|
|
test_number_in_suite="$first_test_number_in_suite"
|
|
test_number_in_file=0
|
|
}
|
|
|
|
bats_run_tests() {
|
|
status=0
|
|
|
|
if [[ "$num_jobs" != 1 && "${BATS_NO_PARALLELIZE_WITHIN_FILE-False}" == False ]]; then
|
|
export BATS_SEMAPHORE_NUMBER_OF_SLOTS="$num_jobs"
|
|
bats_run_tests_in_parallel "$BATS_RUN_TMPDIR/parallel_output" || status=1
|
|
else
|
|
for test_name in "${tests_to_run[@]}"; do
|
|
if [[ "${BATS_INTERRUPTED-NOTSET}" != NOTSET ]]; then
|
|
status=130 # bash's code for SIGINT exits
|
|
break
|
|
fi
|
|
# Only handle non-empty lines
|
|
if [[ $test_name ]]; then
|
|
((++test_number_in_suite))
|
|
((++test_number_in_file))
|
|
# deal with empty flags to avoid spurious "unbound variable" errors on Bash 4.3 and lower
|
|
if [[ "${#flags[@]}" -gt 0 ]]; then
|
|
"$BATS_LIBEXEC/bats-exec-test" "${flags[@]}" "$filename" "$test_name" "$test_number_in_suite" "$test_number_in_file" || status=1
|
|
else
|
|
"$BATS_LIBEXEC/bats-exec-test" "$filename" "$test_name" "$test_number_in_suite" "$test_number_in_file" || status=1
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
export status
|
|
}
|
|
|
|
bats_create_file_tempdirs() {
|
|
local bats_files_tmpdir="${BATS_RUN_TMPDIR}/file"
|
|
if ! mkdir -p "$bats_files_tmpdir"; then
|
|
printf 'Failed to create %s\n' "$bats_files_tmpdir" >&2
|
|
exit 1
|
|
fi
|
|
BATS_FILE_TMPDIR="$bats_files_tmpdir/$first_test_number_in_suite"
|
|
if ! mkdir "$BATS_FILE_TMPDIR"; then
|
|
printf 'Failed to create BATS_FILE_TMPDIR=%s\n' "$BATS_FILE_TMPDIR" >&2
|
|
exit 1
|
|
fi
|
|
ln -s "$BATS_TEST_FILENAME" "$BATS_FILE_TMPDIR-$(basename "$BATS_TEST_FILENAME").source_file"
|
|
export BATS_FILE_TMPDIR
|
|
}
|
|
|
|
trap 'BATS_INTERRUPTED=true' INT
|
|
|
|
if [[ -n "$extended_syntax" ]]; then
|
|
printf "suite %s\n" "$filename"
|
|
fi
|
|
|
|
bats_read_tests_list_file
|
|
|
|
# don't run potentially expensive setup/teardown_file
|
|
# when there are no tests to run
|
|
if [[ ${#tests_to_run[@]} -eq 0 ]]; then
|
|
exit 0
|
|
fi
|
|
|
|
# requires the test list to be read but not empty
|
|
bats_create_file_tempdirs
|
|
|
|
bats_preprocess_source "$filename"
|
|
|
|
trap bats_interrupt_trap INT
|
|
bats_run_setup_file
|
|
|
|
# during tests, we don't want to get backtraces from this level
|
|
# just wait for the test to be interrupted and display their trace
|
|
trap 'BATS_INTERRUPTED=true' INT
|
|
bats_run_tests
|
|
|
|
trap bats_interrupt_trap INT
|
|
bats_run_teardown_file
|
|
|
|
exit $status
|