Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,15 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: v18.20.2
- run: npm pack ./
- run: npm install -g ./bats-*.tgz
- name: Run test on OS ${{ matrix.os }}
shell: 'script -q -e -c "bash {0}"' # work around tty issues
env:
TERM: linux # fix tput for tty issue work around
run: |
npm pack ./
sudo npm install -g ./bats-*.tgz
bats test --print-output-on-failure
run: bats test --print-output-on-failure

windows:
runs-on: windows-2019
Expand All @@ -116,6 +117,8 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: v18.20.2
- run: npm pack ./
- run: npm install -g (get-item .\bats-*.tgz).FullName
- run: bats -T --print-output-on-failure test
Expand Down Expand Up @@ -161,6 +164,8 @@ jobs:
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: v18.20.2
- name: Install unbuffer via expect
run: brew install expect
- name: Run test on OS ${{ matrix.os }}
Expand Down
2 changes: 2 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ The format is based on [Keep a Changelog][kac] and this project adheres to

### Fixed

* unbreak test suites with multiple files loading common constants (#904), introduced in v1.11.0

#### Documentation

* fix hard-coded link to readthedocs (#901)
Expand Down
10 changes: 4 additions & 6 deletions lib/bats-core/tracing.bash
Original file line number Diff line number Diff line change
Expand Up @@ -277,19 +277,17 @@ bats_debug_trap() {
# We need to normalize them to a common format!
local NORMALIZED_INPUT
bats_normalize_windows_dir_path NORMALIZED_INPUT "${1%/*}"
local file_excluded='' path
local path
for path in "${BATS_DEBUG_EXCLUDE_PATHS[@]}"; do
if [[ "$NORMALIZED_INPUT" == "$path"* ]]; then
file_excluded=1
break
return # skip this call
fi
done

# don't update the trace within library functions or we get backtraces from inside traps
# also don't record new stack traces while handling interruptions, to avoid overriding the interrupted command
if [[ -z "$file_excluded" &&
"${BATS_INTERRUPTED-NOTSET}" == NOTSET &&
"${BATS_TIMED_OUT-NOTSET}" == NOTSET ]]; then
if [[ "${BATS_INTERRUPTED-NOTSET}" == NOTSET &&
"${BATS_TIMED_OUT-NOTSET}" == NOTSET ]]; then
BATS_DEBUG_LASTLAST_STACK_TRACE=(
${BATS_DEBUG_LAST_STACK_TRACE[@]+"${BATS_DEBUG_LAST_STACK_TRACE[@]}"}
)
Expand Down
112 changes: 89 additions & 23 deletions libexec/bats-core/bats-gather-tests
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ set -eET

args=("$@")
filter_tags_list=()
included_tests=()
excluded_tests=()

# shellcheck source=lib/bats-core/common.bash disable=SC2153
source "$BATS_ROOT/lib/bats-core/common.bash"
Expand Down Expand Up @@ -250,61 +248,129 @@ if [[ -n "${filter_status-}" ]]; then
else
printf "No recording of previous runs found. Running all tests!\n" >&2
fi
else
: #printf "Not filtering by status!\n" >&2
fi

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

BATS_OUT="$BATS_RUN_TMPDIR/gather-tests.out"
touch "$BATS_OUT"

bats_gather_tests_exit_trap() {
local bats_gather_tests_exit_status=$?
trap - ERR EXIT DEBUG
if [[ ${BATS_ERROR_STATUS:-0} != 0 ]]; then
bats_gather_tests_exit_status=$BATS_ERROR_STATUS
if (( bats_gather_tests_exit_status != 0)); then
printf "1..1\nnot ok 1 bats-gather-tests\n"
bats_get_failure_stack_trace stack_trace
bats_print_stack_trace "${stack_trace[@]}"
bats_print_failed_command "${stack_trace[@]}"
# play back traces from test file evaluation
bats_replace_filename < "$BATS_TRACE"
bats_replace_filename <"$BATS_OUT" | bats_prefix_lines_for_tap_output
fi >&2
exit "$bats_gather_tests_exit_status"
}

trap bats_gather_tests_exit_trap EXIT

bats_set_stacktrace_limit
# prepare tracing for errors during test file evaluation
BATS_TRACE="$BATS_RUN_TMPDIR/bats-gather-tests.trace"
touch "$BATS_TRACE"

bats_gather_tests_source_exit_trap() {
local bats_gather_tests_source_exit_status=$?
trap - ERR EXIT DEBUG
if (( bats_gather_tests_source_exit_status != 0)); then
bats_get_failure_stack_trace stack_trace
bats_print_stack_trace "${stack_trace[@]}"
# TODO: why doesn't this work via ERR trap?
BATS_ERROR_STATUS=$bats_gather_tests_source_exit_status
bats_print_failed_command "${stack_trace[@]}"
fi >>"$BATS_TRACE"
exit "$bats_gather_tests_source_exit_status"
}

bats_gather_tests_for_file() {
local test_names=() test_dupes=() included_tests=() excluded_tests=()

trap bats_gather_tests_source_exit_trap EXIT
bats_setup_tracing
bats_set_stacktrace_limit

# do the actual evaluation for gathering the tests
# shellcheck disable=SC1090
BATS_TEST_DIRNAME="${filename%/*}" source "$BATS_TEST_SOURCE" 1>"$BATS_OUT" 2>&1

if [[ "${#test_dupes[@]}" -ne 0 ]]; then
printf 'file_duplicate_test_names="%q"\n' "${test_dupes[*]#$filename$'\t'}"
fi

if [[ -n "$filter_status" ]]; then
# save filtered tests to exclude them again in next round
for test_line in "${excluded_tests[@]}"; do
printf "status-filtered %s %s\n" "$filter_status" "$test_line"
done >>"$BATS_RUNLOG_FILE"
fi


printf "file_test_count=%d\n" "${#test_names[@]}"
printf "file_included_test_count=%d\n" "${#included_tests[@]}"
printf "focus_mode=%d\n" "$focus_mode"
}

bats_setup_tracing
focus_mode=0
total_test_count=0
total_included_test_count=0
for filename in "$@"; do
if [[ ! -f "$filename" ]]; then
abort 'Test file "%s" does not exist.\n' "${filename}"
fi

test_names=()
test_dupes=()

BATS_TEST_FILENAME="$filename"
_bats_test_functions_setup -1 # invalid TEST_NUMBER, as this is not a test

BATS_TEST_NAME=source
BATS_TEST_FILTER="$BATS_TEST_FILTER" bats_preprocess_source # uses BATS_TEST_FILENAME
# shellcheck disable=SC1090
BATS_TEST_DIRNAME="${filename%/*}" source "$BATS_TEST_SOURCE"

if [[ "${#test_dupes[@]}" -ne 0 ]]; then
abort 'Duplicate test name(s) in file "%s": %s' "${filename}" "${test_dupes[*]#$filename$'\t'}"
file_duplicate_test_names=""
file_test_count=0
file_included_test_count=0
saved_focus_mode=$focus_mode

# get new values for the variables above
if [[ $BASH_VERSION == 4.3.* ]]; then
# Bash 4.3 has function scoping issues when this is run in $() -> work around via file
bats_gather_tests_var_transfer_file=$BATS_RUN_TMPDIR/gather-tests-var-transfer
(set -eET; bats_gather_tests_for_file >"$bats_gather_tests_var_transfer_file")
result=$(<"$bats_gather_tests_var_transfer_file")
else
# separate retrieval from eval to avoid hiding the exit code
result="$(set -eET; bats_gather_tests_for_file)"
fi

eval "$result"

if [[ -n "$file_duplicate_test_names" ]]; then
trap - EXIT # prevent 1..1 from being printed
abort 'Duplicate test name(s) in file "%s": %s' "$filename" "$file_duplicate_test_names"
fi

total_test_count=$((total_test_count + file_test_count))

# did focus mode turn on in this file? (cannot turn off afterwards)
if (( saved_focus_mode != focus_mode)); then # -> only count new tests
total_included_test_count=$file_included_test_count
else # -> count previous tests as well
total_included_test_count=$((total_included_test_count + file_included_test_count))
fi
done

if [[ -n "$filter_status" ]]; then
# save filtered tests to exclude them again in next round
for test_line in "${excluded_tests[@]}"; do
printf "status-filtered %s %s\n" "$filter_status" "$test_line"
done >>"$BATS_RUNLOG_FILE"

if [[ ${#test_names[@]} -eq 0 && ${#included_tests[@]} -eq 0 ]]; then
if (( total_test_count == 0 && total_included_test_count == 0 )); then
printf "There were no tests of status '%s' in the last recorded run.\n" "$filter_status" >&2
fi
fi

# communicate to the caller that we are running in focus mode
if (( focus_mode )); then
printf "focus_mode\n"
fi
fi
5 changes: 5 additions & 0 deletions test/fixtures/suite/errors_in_multiple_load/a.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
load test_helper

@test "truth" {
true
}
5 changes: 5 additions & 0 deletions test/fixtures/suite/errors_in_multiple_load/b.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
load test_helper

@test "more truth" {
true
}
5 changes: 5 additions & 0 deletions test/fixtures/suite/errors_in_multiple_load/c.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
load nonexistent

@test "yet more truth" {
true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
call-to-undefined-command
5 changes: 5 additions & 0 deletions test/fixtures/suite/multiple_load_constants/a.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
load test_helper

@test "constant" {
[ "$A_CONSTANT" = "value" ]
}
5 changes: 5 additions & 0 deletions test/fixtures/suite/multiple_load_constants/b.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
load test_helper

@test "constant (again)" {
[ "$A_CONSTANT" = "value" ]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# shellcheck disable=SC2034
readonly A_CONSTANT="value"
43 changes: 43 additions & 0 deletions test/suite.bats
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,56 @@ setup() {
echo "$output" | grep "^ok . quasi-truth"
}

@test "aggregated output of multiple tests in a suite loading common constants" {
reentrant_run bats "$FIXTURE_ROOT/multiple_load_constants"
[ $status -eq 0 ]
[ "${lines[0]}" = "1..2" ]
[ "${lines[1]}" = "ok 1 constant" ]
[ "${lines[2]}" = "ok 2 constant (again)" ]
}

@test "a failing test in a suite results in an error exit code" {
FLUNK=1 reentrant_run bats "$FIXTURE_ROOT/multiple"
[ $status -eq 1 ]
[ "${lines[0]}" = "1..3" ]
echo "$output" | grep "^not ok . quasi-truth"
}

@test "errors when loading common helper from multiple tests in a suite" {
reentrant_run bats "$FIXTURE_ROOT/errors_in_multiple_load"
[ $status -eq 1 ]
[ "${lines[0]}" = "1..1" ]
[ "${lines[1]}" = "not ok 1 bats-gather-tests" ]

# bash > 4.0 returns error codes from source
# bash < 4.0 does not handle the status on source, it fails through the ERREXIT instead, which creates another trace
# bash == 4.0 seems to be sonwhere in between
if (( BASH_VERSINFO[0] > 4 )) || (( BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] > 0 )); then
[ "${lines[2]}" = "# (in test file $RELATIVE_FIXTURE_ROOT/errors_in_multiple_load/a.bats, line 1)" ]
[ "${lines[3]}" = "# \`load test_helper' failed" ]
[ "${lines[4]}" = "# $FIXTURE_ROOT/errors_in_multiple_load/test_helper.bash: line 1: call-to-undefined-command: command not found" ]
[ "${lines[5]}" = "# Error while sourcing library loader at '$FIXTURE_ROOT/errors_in_multiple_load/test_helper.bash'" ]
[ "${#lines[@]}" -eq 6 ]
else
[ "${lines[2]}" = "# (in file $RELATIVE_FIXTURE_ROOT/errors_in_multiple_load/test_helper.bash, line 1," ]
[ "${lines[3]}" = "# from function \`bats_internal_load' in file ${RELATIVE_BATS_ROOT}lib/bats-core/test_functions.bash, line 69," ]
[ "${lines[4]}" = "# from function \`bats_load_safe' in file ${RELATIVE_BATS_ROOT}lib/bats-core/test_functions.bash, line 106," ]
[ "${lines[5]}" = "# from function \`load' in file ${RELATIVE_BATS_ROOT}lib/bats-core/test_functions.bash, line 156," ]
[ "${lines[6]}" = "# in test file $RELATIVE_FIXTURE_ROOT/errors_in_multiple_load/a.bats, line 1)" ]
if (( BASH_VERSINFO[0] == 4)); then
[ "${lines[7]}" = "# \`load test_helper' failed" ]
[ "${lines[8]}" = "# $FIXTURE_ROOT/errors_in_multiple_load/test_helper.bash: line 1: call-to-undefined-command: command not found" ]
[ "${lines[9]}" = "# Error while sourcing library loader at '$FIXTURE_ROOT/errors_in_multiple_load/test_helper.bash'" ]
[ "${#lines[@]}" -eq 10 ]
else
[ "${lines[7]}" = "# \`load test_helper' failed with status 127" ]
[ "${lines[8]}" = "# $FIXTURE_ROOT/errors_in_multiple_load/test_helper.bash: line 1: call-to-undefined-command: command not found" ]
[ "${#lines[@]}" -eq 9 ]
fi
fi

}

@test "running an ad-hoc suite by specifying multiple test files" {
reentrant_run bats "$FIXTURE_ROOT/multiple/a.bats" "$FIXTURE_ROOT/multiple/b.bats"
[ $status -eq 0 ]
Expand Down
8 changes: 8 additions & 0 deletions test/test_helper.bash
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ fixtures() {
FIXTURE_ROOT="$BATS_TEST_DIRNAME/fixtures/$1"
# shellcheck disable=SC2034
RELATIVE_FIXTURE_ROOT="${FIXTURE_ROOT#"$BATS_CWD"/}"
if [[ $BATS_ROOT == "$BATS_CWD" ]]; then
RELATIVE_BATS_ROOT=''
else
RELATIVE_BATS_ROOT=${BATS_ROOT#"$BATS_CWD"/}
fi
if [[ -n "$RELATIVE_BATS_ROOT" && "$RELATIVE_BATS_ROOT" != */ ]]; then
RELATIVE_BATS_ROOT+=/
fi
}

filter_control_sequences() {
Expand Down
9 changes: 0 additions & 9 deletions test/warnings.bats
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,6 @@ bats_require_minimum_version 1.5.0
setup() {
load test_helper
fixtures warnings
if [[ $BATS_ROOT == "$BATS_CWD" ]]; then
RELATIVE_BATS_ROOT=''
else
RELATIVE_BATS_ROOT=${BATS_ROOT#"$BATS_CWD"/}
fi
if [[ -n "$RELATIVE_BATS_ROOT" && "$RELATIVE_BATS_ROOT" != */ ]]; then
RELATIVE_BATS_ROOT+=/
fi
echo "RELATIVE_BATS_ROOT=$RELATIVE_BATS_ROOT" "BATS_ROOT=$BATS_ROOT" "BATS_CWD=$BATS_CWD"
}

@test "invalid warning is an error" {
Expand Down