@bats-hardened/bats 1.14.1-alpha02

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of @bats-hardened/bats might be problematic. Click here for more details.

@@ -0,0 +1,402 @@
1
+ #!/usr/bin/env bash
2
+ set -eET
3
+
4
+ flags=('--dummy-flag')
5
+ num_jobs=${BATS_NUMBER_OF_PARALLEL_JOBS:-1}
6
+ extended_syntax=''
7
+ BATS_ABORT_ON_FAILURE=
8
+ BATS_TRACE_LEVEL="${BATS_TRACE_LEVEL:-0}"
9
+ declare -r BATS_RETRY_RETURN_CODE=126
10
+ export BATS_TEST_RETRIES=0 # no retries by default
11
+
12
+ while [[ "$#" -ne 0 ]]; do
13
+ case "$1" in
14
+ -j)
15
+ shift
16
+ num_jobs="$1"
17
+ ;;
18
+ -T)
19
+ flags+=('-T')
20
+ ;;
21
+ -x)
22
+ flags+=('-x')
23
+ extended_syntax=1
24
+ ;;
25
+ --abort)
26
+ BATS_ABORT_ON_FAILURE=1
27
+ ;;
28
+ --no-parallelize-within-files)
29
+ # use singular to allow for users to override in file
30
+ BATS_NO_PARALLELIZE_WITHIN_FILE=1
31
+ ;;
32
+ --dummy-flag) ;;
33
+
34
+ --trace)
35
+ flags+=('--trace')
36
+ ;;
37
+ --print-output-on-failure)
38
+ flags+=(--print-output-on-failure)
39
+ ;;
40
+ --show-output-of-passing-tests)
41
+ flags+=(--show-output-of-passing-tests)
42
+ ;;
43
+ --verbose-run)
44
+ flags+=(--verbose-run)
45
+ ;;
46
+ --gather-test-outputs-in)
47
+ shift
48
+ flags+=(--gather-test-outputs-in "$1")
49
+ ;;
50
+ *)
51
+ break
52
+ ;;
53
+ esac
54
+ shift
55
+ done
56
+
57
+ export BATS_TEST_FILE_NUMBER="$1"
58
+ filename="$2"
59
+ TESTS_FILE="$3"
60
+
61
+ if [[ ! -f "$filename" ]]; then
62
+ printf 'Testfile "%s" not found\n' "$filename" >&2
63
+ exit 1
64
+ fi
65
+
66
+ export BATS_TEST_FILENAME="$filename"
67
+
68
+ # shellcheck source=lib/bats-core/preprocessing.bash
69
+ # shellcheck disable=SC2153
70
+ source "$BATS_ROOT/$BATS_LIBDIR/bats-core/preprocessing.bash"
71
+
72
+ bats_run_setup_file() {
73
+ # shellcheck source=lib/bats-core/tracing.bash
74
+ # shellcheck disable=SC2153
75
+ source "$BATS_ROOT/$BATS_LIBDIR/bats-core/tracing.bash"
76
+ # shellcheck source=lib/bats-core/test_functions.bash
77
+ # shellcheck disable=SC2153
78
+ source "$BATS_ROOT/$BATS_LIBDIR/bats-core/test_functions.bash"
79
+
80
+ _bats_test_functions_setup -1 # invalid TEST_NUMBER, as this is not a test
81
+
82
+ exec 3<&1
83
+
84
+ # these are defined only to avoid errors when referencing undefined variables down the line
85
+ # shellcheck disable=2034
86
+ BATS_TEST_NAME= # used in tracing.bash
87
+ # shellcheck disable=2034
88
+ BATS_TEST_COMPLETED= # used in tracing.bash
89
+
90
+ BATS_SOURCE_FILE_COMPLETED=
91
+ BATS_SETUP_FILE_COMPLETED=
92
+ BATS_TEARDOWN_FILE_COMPLETED=
93
+ # shellcheck disable=2034
94
+ BATS_ERROR_STATUS= # used in tracing.bash
95
+
96
+ touch "$BATS_OUT"
97
+ bats_setup_tracing
98
+ trap 'bats_file_teardown_trap' EXIT
99
+
100
+ local status=0
101
+ # get the setup_file/teardown_file functions for this file (if it has them)
102
+ # shellcheck disable=SC1090
103
+ source "$BATS_TEST_SOURCE"
104
+
105
+ BATS_SOURCE_FILE_COMPLETED=1
106
+
107
+ bats_set_stacktrace_limit
108
+ setup_file >>"$BATS_OUT" 2>&1
109
+
110
+ BATS_SETUP_FILE_COMPLETED=1
111
+ }
112
+
113
+ bats_run_teardown_file() {
114
+ local bats_teardown_file_status=0
115
+ # avoid running the therdown trap due to errors in teardown_file
116
+ trap 'bats_file_exit_trap' EXIT
117
+
118
+ bats_set_stacktrace_limit
119
+
120
+ # rely on bats_error_trap to catch failures
121
+ teardown_file >>"$BATS_OUT" 2>&1 || bats_teardown_file_status=$?
122
+
123
+ if ((bats_teardown_file_status == 0)); then
124
+ BATS_TEARDOWN_FILE_COMPLETED=1
125
+ elif [[ -n "${BATS_SETUP_FILE_COMPLETED:-}" ]]; then
126
+ BATS_DEBUG_LAST_STACK_TRACE_IS_VALID=1
127
+ BATS_ERROR_STATUS=$bats_teardown_file_status
128
+ return $BATS_ERROR_STATUS
129
+ fi
130
+ }
131
+
132
+ # shellcheck disable=SC2317,SC2329
133
+ bats_file_teardown_trap() {
134
+ bats_run_teardown_file
135
+ bats_file_exit_trap in-teardown_trap
136
+ }
137
+
138
+ # shellcheck source=lib/bats-core/common.bash
139
+ source "$BATS_ROOT/$BATS_LIBDIR/bats-core/common.bash"
140
+
141
+ # shellcheck disable=SC2317,SC2329
142
+ bats_file_exit_trap() {
143
+ local -r last_return_code=$?
144
+ if [[ ${1:-} != in-teardown_trap ]]; then
145
+ BATS_ERROR_STATUS=$last_return_code
146
+ fi
147
+ trap - ERR EXIT
148
+ local failure_reason
149
+ local -i failure_test_index=$((BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE + 1))
150
+ if [[ -n "${BATS_TEST_SKIPPED-}" ]]; then
151
+ export BATS_TEST_SKIPPED # indicate to exec-test that it should skip
152
+ # print skip message for each test (use this to avoid reimplementing filtering)
153
+ bats_run_tests 1<&3 # restore original stdout (this is running in setup_file's redirection to BATS_OUT)
154
+ bats_exec_file_status=0 # this should not lead to errors
155
+ elif [[ -z "$BATS_SETUP_FILE_COMPLETED" || -z "$BATS_TEARDOWN_FILE_COMPLETED" ]]; then
156
+ if [[ -z "$BATS_SETUP_FILE_COMPLETED" ]]; then
157
+ failure_reason='setup_file'
158
+ elif [[ -z "$BATS_TEARDOWN_FILE_COMPLETED" ]]; then
159
+ failure_reason='teardown_file'
160
+ failure_test_index=$((BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE + ${#tests_to_run[@]} + 1))
161
+ elif [[ -z "$BATS_SOURCE_FILE_COMPLETED" ]]; then
162
+ failure_reason='source'
163
+ else
164
+ failure_reason='unknown internal'
165
+ fi
166
+ printf "not ok %d %s\n" "$failure_test_index" "$failure_reason failed" >&3
167
+ local stack_trace
168
+ bats_get_failure_stack_trace stack_trace
169
+ bats_print_stack_trace "${stack_trace[@]}" >&3
170
+ bats_print_failed_command "${stack_trace[@]}" >&3
171
+ bats_prefix_lines_for_tap_output <"$BATS_OUT" | bats_replace_filename >&3
172
+ rm -rf "$BATS_OUT"
173
+ bats_exec_file_status=1
174
+ fi
175
+
176
+ # setup_file not executed but defined in this test file? -> might be defined in the wrong file
177
+ if [[ -z "${BATS_SETUP_SUITE_COMPLETED-}" ]] && declare -F setup_suite >/dev/null; then
178
+ bats_generate_warning 3 --no-stacktrace "$BATS_TEST_FILENAME"
179
+ fi
180
+
181
+ exit "$bats_exec_file_status"
182
+ }
183
+
184
+ function setup_file() {
185
+ return 0
186
+ }
187
+
188
+ function teardown_file() {
189
+ return 0
190
+ }
191
+
192
+ bats_forward_output_of_parallel_test() {
193
+ local test_number_in_suite=$1
194
+ local status=0
195
+ wait "$(cat "$output_folder/$test_number_in_suite/pid")" || status=1
196
+ cat "$output_folder/$test_number_in_suite/stdout"
197
+ cat "$output_folder/$test_number_in_suite/stderr" >&2
198
+ return $status
199
+ }
200
+
201
+ bats_is_next_parallel_test_finished() {
202
+ local PID
203
+ # get the pid of the next potentially finished test
204
+ PID=$(cat "$output_folder/$((test_number_in_suite_of_last_finished_test + 1))/pid")
205
+ # try to send a signal to this process
206
+ # if it fails, the process exited,
207
+ # if it succeeds, the process is still running
208
+ if kill -0 "$PID" 2>/dev/null; then
209
+ return 1
210
+ fi
211
+ }
212
+
213
+ # prints output from all tests in the order they were started
214
+ # $1 == "blocking": wait for a test to finish before printing
215
+ # != "blocking": abort printing, when a test has not finished
216
+ bats_forward_output_for_parallel_tests() {
217
+ local status=0
218
+ # was the next test already started?
219
+ while ((test_number_in_suite_of_last_finished_test + 1 <= test_number_in_suite)); do
220
+ # if we are okay with waiting or if the test has already been finished
221
+ if [[ "$1" == "blocking" ]] || bats_is_next_parallel_test_finished; then
222
+ ((++test_number_in_suite_of_last_finished_test))
223
+ bats_forward_output_of_parallel_test "$test_number_in_suite_of_last_finished_test" || status=$?
224
+ else
225
+ # non-blocking and the process has not finished -> abort the printing
226
+ break
227
+ fi
228
+ done
229
+ return $status
230
+ }
231
+
232
+ bats_run_test_with_retries() { # <args>
233
+ local status=0
234
+ local should_try_again=1 try_number
235
+ for ((try_number = 1; should_try_again; ++try_number)); do
236
+ if "$BATS_LIBEXEC/bats-exec-test" "$@" "$try_number"; then
237
+ should_try_again=0
238
+ else
239
+ status=$?
240
+ if ((status == BATS_RETRY_RETURN_CODE)); then
241
+ should_try_again=1
242
+ status=0 # this is not the last try -> reset status
243
+ else
244
+ should_try_again=0
245
+ bats_exec_file_status=$status
246
+ fi
247
+ fi
248
+ done
249
+ return $status
250
+ }
251
+
252
+ bats_run_tests_in_parallel() {
253
+ local output_folder="$BATS_RUN_TMPDIR/parallel_output"
254
+ local status=0
255
+ mkdir -p "$output_folder"
256
+ # shellcheck source=lib/bats-core/semaphore.bash
257
+ source "$BATS_ROOT/$BATS_LIBDIR/bats-core/semaphore.bash"
258
+ bats_semaphore_setup
259
+ # the test_number_in_file is not yet incremented -> one before the next test to run
260
+ local test_number_in_suite_of_last_finished_test="$BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE" # stores which test was printed last
261
+ local test_number_in_file=0 test_number_in_suite=$BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE
262
+ for test_name in "${tests_to_run[@]}"; do
263
+ # Only handle non-empty lines
264
+ if [[ $test_name ]]; then
265
+ ((++test_number_in_suite))
266
+ ((++test_number_in_file))
267
+ mkdir -p "$output_folder/$test_number_in_suite"
268
+ bats_semaphore_run "$output_folder/$test_number_in_suite" \
269
+ bats_run_test_with_retries "${flags[@]}" "$filename" "$test_name" "$test_number_in_suite" "$test_number_in_file" \
270
+ >"$output_folder/$test_number_in_suite/pid"
271
+ fi
272
+ # print results early to get interactive feedback
273
+ bats_forward_output_for_parallel_tests non-blocking || status=1 # ignore if we did not finish yet
274
+ if (( BATS_ABORT_ON_FAILURE && status >0 )); then
275
+ break
276
+ fi
277
+ done
278
+ bats_forward_output_for_parallel_tests blocking || status=1
279
+ return $status
280
+ }
281
+
282
+ bats_read_tests_list_file() {
283
+ local line_number=0
284
+ tests_to_run=()
285
+ # the global test number must be visible to traps -> not local
286
+ local test_number_in_suite=''
287
+ while read -r test_line; do
288
+ # check if the line begins with filename
289
+ # filename might contain some hard to parse characters,
290
+ # use simple string operations to work around that issue
291
+ if [[ "$filename" == "${test_line::${#filename}}" ]]; then
292
+ # get the rest of the line without the separator \t
293
+ test_name=${test_line:$((1 + ${#filename}))}
294
+ tests_to_run+=("$test_name")
295
+ # save the first test's number for later iteration
296
+ # this assumes that tests for a file are stored consecutive in the file!
297
+ if [[ -z "$test_number_in_suite" ]]; then
298
+ test_number_in_suite=$line_number
299
+ fi
300
+ fi
301
+ ((++line_number))
302
+ done <"$TESTS_FILE"
303
+ BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE="$test_number_in_suite"
304
+ declare -ri BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE # mark readonly (cannot merge assignment, because value would be lost)
305
+ }
306
+
307
+ bats_run_tests() {
308
+ bats_exec_file_status=0
309
+ # TODO: this does not seem to be used anymore?
310
+ if [[ "${BATS_RUN_TESTS_SKIPPED-}" ]]; then
311
+ # shellcheck disable=SC2317,SC2329
312
+ bats_test_begin() {
313
+ printf "ok %d %s # skip %s\n" "$test_number_in_suite" "$1" "$BATS_RUN_TESTS_SKIPPED_REASON" >&3
314
+ return 1
315
+ }
316
+ local test_number_in_suite=0
317
+ for test_name in "${tests_to_run[@]}"; do
318
+ ((++test_number_in_suite))
319
+ eval "$test_name" || true
320
+ done
321
+ exit 0
322
+ fi
323
+
324
+ if [[ "$num_jobs" -lt 1 ]]; then
325
+ printf 'Invalid number of jobs: %s\n' "$num_jobs" >&2
326
+ exit 1
327
+ fi
328
+
329
+ if [[ "$num_jobs" != 1 && "${BATS_NO_PARALLELIZE_WITHIN_FILE-False}" == False ]]; then
330
+ export BATS_SEMAPHORE_NUMBER_OF_SLOTS="$num_jobs"
331
+ bats_run_tests_in_parallel "$BATS_RUN_TMPDIR/parallel_output" || bats_exec_file_status=1
332
+ else
333
+ local test_number_in_suite=$BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE \
334
+ test_number_in_file=0
335
+ for test_name in "${tests_to_run[@]}"; do
336
+ #echo "bats-exec-file: execute test ${test_name}" >&2
337
+ if [[ "${BATS_INTERRUPTED-NOTSET}" != NOTSET ]]; then
338
+ bats_exec_file_status=130 # bash's code for SIGINT exits
339
+ break
340
+ fi
341
+ # Only handle non-empty lines
342
+ if [[ -n ${test_name-} ]]; then
343
+ ((++test_number_in_suite))
344
+ ((++test_number_in_file))
345
+ bats_run_test_with_retries "${flags[@]}" "$filename" "$test_name" \
346
+ "$test_number_in_suite" "$test_number_in_file" || bats_exec_file_status=$?
347
+ if (( BATS_ABORT_ON_FAILURE && bats_exec_file_status > 0 )); then
348
+ break
349
+ fi
350
+ fi
351
+ done
352
+ fi
353
+ }
354
+
355
+ bats_create_file_tempdirs() {
356
+ local bats_files_tmpdir="${BATS_RUN_TMPDIR}/file"
357
+ if ! mkdir -p "$bats_files_tmpdir"; then
358
+ printf 'Failed to create %s\n' "$bats_files_tmpdir" >&2
359
+ exit 1
360
+ fi
361
+ BATS_FILE_TMPDIR="$bats_files_tmpdir/${BATS_TEST_FILE_NUMBER?}"
362
+ if ! mkdir "$BATS_FILE_TMPDIR"; then
363
+ printf 'Failed to create BATS_FILE_TMPDIR=%s\n' "$BATS_FILE_TMPDIR" >&2
364
+ exit 1
365
+ fi
366
+ ln -s "$BATS_TEST_FILENAME" "$BATS_FILE_TMPDIR-$(basename "$BATS_TEST_FILENAME").source_file"
367
+ export BATS_FILE_TMPDIR
368
+ }
369
+
370
+ trap 'BATS_INTERRUPTED=true' INT
371
+
372
+ BATS_FILE_FIRST_TEST_NUMBER_IN_SUITE=0 # predeclare as Bash 3.2 does not support declare -g
373
+ bats_read_tests_list_file
374
+
375
+ # don't run potentially expensive setup/teardown_file
376
+ # when there are no tests to run
377
+ if [[ ${#tests_to_run[@]} -eq 0 ]]; then
378
+ exit 0
379
+ fi
380
+
381
+ if [[ -n "$extended_syntax" ]]; then
382
+ printf "suite %s\n" "$filename"
383
+ fi
384
+
385
+ # requires the test list to be read but not empty
386
+ bats_create_file_tempdirs
387
+
388
+ export BATS_OUT="${BATS_RUN_TMPDIR}/file/${BATS_TEST_FILE_NUMBER?}-${BATS_TEST_FILENAME##*/}.out"
389
+ bats_export_preprocess_source_BATS_TEST_SOURCE
390
+
391
+ trap bats_interrupt_trap INT
392
+ bats_run_setup_file
393
+
394
+ # during tests, we don't want to get backtraces from this level
395
+ # just wait for the test to be interrupted and display their trace
396
+ trap 'BATS_INTERRUPTED=true' INT
397
+ bats_run_tests
398
+
399
+ trap bats_interrupt_trap INT
400
+ bats_run_teardown_file
401
+
402
+ exit $bats_exec_file_status