@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,383 @@
1
+ #!/usr/bin/env bash
2
+ set -eET
3
+
4
+ # Variables used in other scripts.
5
+ BATS_ENABLE_TIMING=''
6
+ BATS_EXTENDED_SYNTAX=''
7
+ BATS_TRACE_LEVEL="${BATS_TRACE_LEVEL:-0}"
8
+ BATS_PRINT_OUTPUT_ON_FAILURE="${BATS_PRINT_OUTPUT_ON_FAILURE:-}"
9
+ BATS_SHOW_OUTPUT_OF_SUCCEEDING_TESTS="${BATS_SHOW_OUTPUT_OF_SUCCEEDING_TESTS:-}"
10
+ BATS_VERBOSE_RUN="${BATS_VERBOSE_RUN:-}"
11
+ BATS_GATHER_TEST_OUTPUTS_IN="${BATS_GATHER_TEST_OUTPUTS_IN:-}"
12
+ BATS_TEST_NAME_PREFIX="${BATS_TEST_NAME_PREFIX:-}"
13
+
14
+ while [[ "$#" -ne 0 ]]; do
15
+ case "$1" in
16
+ -T)
17
+ BATS_ENABLE_TIMING='-T'
18
+ ;;
19
+ -x)
20
+ # shellcheck disable=SC2034
21
+ BATS_EXTENDED_SYNTAX='-x'
22
+ ;;
23
+ --dummy-flag) ;;
24
+
25
+ --trace)
26
+ ((++BATS_TRACE_LEVEL)) # avoid returning 0
27
+ ;;
28
+ --print-output-on-failure)
29
+ BATS_PRINT_OUTPUT_ON_FAILURE=1
30
+ ;;
31
+ --show-output-of-passing-tests)
32
+ BATS_SHOW_OUTPUT_OF_SUCCEEDING_TESTS=1
33
+ ;;
34
+ --verbose-run)
35
+ BATS_VERBOSE_RUN=1
36
+ ;;
37
+ --gather-test-outputs-in)
38
+ shift
39
+ BATS_GATHER_TEST_OUTPUTS_IN="$1"
40
+ ;;
41
+ *)
42
+ break
43
+ ;;
44
+ esac
45
+ shift
46
+ done
47
+
48
+ export BATS_TEST_FILENAME="$1"
49
+ export BATS_TEST_NAME="$2"
50
+ export BATS_SUITE_TEST_NUMBER="$3"
51
+ export BATS_TEST_NUMBER="$4"
52
+ BATS_TEST_TRY_NUMBER="$5"
53
+
54
+ if [[ -z "$BATS_TEST_FILENAME" ]]; then
55
+ printf 'usage: bats-exec-test <filename>\n' >&2
56
+ exit 1
57
+ elif [[ ! -f "$BATS_TEST_FILENAME" ]]; then
58
+ printf 'bats: %s does not exist\n' "$BATS_TEST_FILENAME" >&2
59
+ exit 1
60
+ fi
61
+
62
+ bats_create_test_tmpdirs() {
63
+ local tests_tmpdir="${BATS_RUN_TMPDIR}/test"
64
+ if ! mkdir -p "$tests_tmpdir"; then
65
+ printf 'Failed to create: %s\n' "$tests_tmpdir" >&2
66
+ exit 1
67
+ fi
68
+
69
+ BATS_TEST_TMPDIR="$tests_tmpdir/$BATS_SUITE_TEST_NUMBER"
70
+ if ! mkdir "$BATS_TEST_TMPDIR"; then
71
+ printf 'Failed to create BATS_TEST_TMPDIR%d: %s\n' "$BATS_TEST_TRY_NUMBER" "$BATS_TEST_TMPDIR" >&2
72
+ exit 1
73
+ fi
74
+
75
+ printf "%s\n" "$BATS_TEST_NAME" >> "$BATS_TEST_TMPDIR.name" # append name in case of test retries
76
+
77
+ export BATS_TEST_TMPDIR
78
+ }
79
+
80
+ # load the test helper functions like `load` or `run` that are needed to run a (preprocessed) .bats file without bash errors
81
+ # shellcheck source=lib/bats-core/test_functions.bash disable=SC2153
82
+ source "$BATS_ROOT/$BATS_LIBDIR/bats-core/test_functions.bash"
83
+ _bats_test_functions_setup "$BATS_TEST_NUMBER"
84
+
85
+ # shellcheck source=lib/bats-core/tracing.bash disable=SC2153
86
+ source "$BATS_ROOT/$BATS_LIBDIR/bats-core/tracing.bash"
87
+
88
+ bats_teardown_trap() {
89
+ bats_check_status_from_trap
90
+ local bats_teardown_trap_status=0
91
+
92
+ bats_set_stacktrace_limit
93
+
94
+ # mark the start of this function to distinguish where skip is called
95
+ # parameter 1 will signify the reason why this function was called
96
+ # this is used to identify when this is called as exit trap function
97
+ BATS_TEARDOWN_STARTED=${1:-1}
98
+ teardown >>"$BATS_OUT" 2>&1 || bats_teardown_trap_status="$?"
99
+
100
+ if [[ $bats_teardown_trap_status -eq 0 ]]; then
101
+ BATS_TEARDOWN_COMPLETED=1
102
+ elif [[ -n "$BATS_TEST_COMPLETED" ]]; then
103
+ BATS_DEBUG_LAST_STACK_TRACE_IS_VALID=1
104
+ BATS_ERROR_STATUS="$bats_teardown_trap_status"
105
+ fi
106
+
107
+ bats_exit_trap
108
+ }
109
+
110
+ # shellcheck source=lib/bats-core/common.bash
111
+ source "$BATS_ROOT/$BATS_LIBDIR/bats-core/common.bash"
112
+
113
+ bats_exit_trap() {
114
+ local status
115
+ local exit_metadata=''
116
+ trap - ERR EXIT
117
+ if [[ -n "${BATS_TEST_TIMEOUT:-}" ]]; then
118
+ # Kill the watchdog in the case of of kernel finished before the timeout
119
+ bats_abort_timeout_countdown || status=1
120
+ fi
121
+
122
+ if [[ -n "$BATS_TEST_SKIPPED" ]]; then
123
+ exit_metadata=' # skip'
124
+ if [[ "$BATS_TEST_SKIPPED" != '1' ]]; then
125
+ exit_metadata+=" $BATS_TEST_SKIPPED"
126
+ fi
127
+ elif [[ "${BATS_TIMED_OUT-NOTSET}" != NOTSET ]]; then
128
+ exit_metadata=" # timeout after ${BATS_TEST_TIMEOUT}s"
129
+ fi
130
+
131
+ BATS_TEST_TIME=''
132
+ if [[ -n "$BATS_ENABLE_TIMING" ]]; then
133
+ get_mills_since_epoch BATS_TEST_END_TIME
134
+ BATS_TEST_TIME=" in "$((BATS_TEST_END_TIME - BATS_TEST_START_TIME))"ms"
135
+ fi
136
+
137
+ local print_bats_out="${BATS_SHOW_OUTPUT_OF_SUCCEEDING_TESTS}"
138
+
139
+ local should_retry=''
140
+ if [[ -z "$BATS_TEST_COMPLETED" || -z "$BATS_TEARDOWN_COMPLETED" || "${BATS_INTERRUPTED-NOTSET}" != NOTSET ]]; then
141
+ if [[ "$BATS_ERROR_STATUS" -eq 0 ]]; then
142
+ # For some versions of bash, `$?` may not be set properly for some error
143
+ # conditions before triggering the EXIT trap directly (see #72 and #81).
144
+ # Thanks to the `BATS_TEARDOWN_COMPLETED` signal, this will pinpoint such
145
+ # errors if they happen during `teardown()` when `bats_perform_test` calls
146
+ # `bats_teardown_trap` directly after the test itself passes.
147
+ #
148
+ # If instead the test fails, and the `teardown()` error happens while
149
+ # `bats_teardown_trap` runs as the EXIT trap, the test will fail with no
150
+ # output, since there's no way to reach the `bats_exit_trap` call.
151
+ BATS_ERROR_STATUS=1
152
+ fi
153
+ if bats_should_retry_test; then
154
+ should_retry=1
155
+ status=126 # signify retry
156
+ rm -r "$BATS_TEST_TMPDIR" # clean up for retry
157
+ else
158
+ printf 'not ok %d %s%s\n' "$BATS_SUITE_TEST_NUMBER" "${BATS_TEST_NAME_PREFIX:-}${BATS_TEST_DESCRIPTION}${BATS_TEST_TIME}" "$exit_metadata" >&3
159
+ if (( ${#BATS_TEST_TAGS[@]} > 0 )); then
160
+ printf '# tags:'
161
+ printf ' %s' "${BATS_TEST_TAGS[@]}"
162
+ printf '\n'
163
+ fi >&3
164
+ local stack_trace
165
+ bats_get_failure_stack_trace stack_trace
166
+ bats_print_stack_trace "${stack_trace[@]}" >&3
167
+ bats_print_failed_command "${stack_trace[@]}" >&3
168
+
169
+ if [[ $BATS_PRINT_OUTPUT_ON_FAILURE ]]; then
170
+ if [[ -n "${output:-}" ]]; then
171
+ printf "Last output:\n%s\n" "$output"
172
+ fi
173
+ if [[ -n "${stderr:-}" ]]; then
174
+ printf "Last stderr: \n%s\n" "$stderr"
175
+ fi
176
+ fi >>"$BATS_OUT"
177
+
178
+ print_bats_out=1
179
+ status=1
180
+ local state=failed
181
+ fi
182
+ else
183
+ printf 'ok %d %s%s\n' "$BATS_SUITE_TEST_NUMBER" "${BATS_TEST_NAME_PREFIX:-}${BATS_TEST_DESCRIPTION}${BATS_TEST_TIME}" \
184
+ "$exit_metadata" >&3
185
+ status=0
186
+ local state=passed
187
+ fi
188
+
189
+ if [[ -z "$should_retry" ]]; then
190
+ printf "%s %s\t%s\n" "$state" "$BATS_TEST_FILENAME" "$BATS_TEST_NAME" >>"$BATS_RUNLOG_FILE"
191
+
192
+ if [[ $print_bats_out ]]; then
193
+ bats_prefix_lines_for_tap_output <"$BATS_OUT" | bats_replace_filename >&3
194
+ fi
195
+ fi
196
+ if [[ $BATS_GATHER_TEST_OUTPUTS_IN ]]; then
197
+ local try_suffix=
198
+ if [[ -n "$should_retry" ]]; then
199
+ try_suffix="-try$BATS_TEST_TRY_NUMBER"
200
+ fi
201
+ # Only copy if BATS_OUT exists (it may not exist if test produced no output)
202
+ if [[ -f "$BATS_OUT" ]]; then
203
+ cp "$BATS_OUT" "$BATS_GATHER_TEST_OUTPUTS_IN/$BATS_SUITE_TEST_NUMBER$try_suffix-${BATS_TEST_DESCRIPTION//\//%2F}.log"
204
+ fi
205
+ fi
206
+ rm -f "$BATS_OUT"
207
+ exit "$status"
208
+ }
209
+
210
+ # Marks the test as failed due to timeout.
211
+ # The actual termination of subprocesses is done via pkill in the background
212
+ # process in bats_start_timeout_countdown
213
+ # shellcheck disable=SC2317,SC2329
214
+ bats_timeout_trap() {
215
+ BATS_TIMED_OUT=1
216
+ BATS_DEBUG_LAST_STACK_TRACE_IS_VALID=
217
+ exit 1
218
+ }
219
+
220
+ # find pids of process and all its descendants
221
+ bats_find_processes_of() { # <parent-pid>
222
+ local -ri parent_pid=$1
223
+ child_pids=("$1")
224
+ {
225
+ read -ra header
226
+ local pid_col ppid_col
227
+ for ((i = 0; i < ${#header[@]}; ++i)); do
228
+ if [[ ${header[$i]} == "PID" ]]; then
229
+ pid_col=$i
230
+ fi
231
+ if [[ ${header[$i]} == "PPID" ]]; then
232
+ ppid_col=$i
233
+ fi
234
+ done
235
+ # PID PPID child_pids
236
+ # 1 0 (2)
237
+ # 2 1 (2)
238
+ # 3 1 (2)
239
+ # 4 3 (2)
240
+ # 5 2 (2 5)
241
+ # 6 5 (2 5 6)
242
+ # assumes pids are in ascending order and there are no orphans in the chain
243
+
244
+ if (( BASH_VERSINFO[0] < 4 )); then
245
+ # BASHPID is not available before bash 4
246
+ BASHPID=$(sh -c 'echo $PPID')
247
+ fi
248
+ while read -ra row; do
249
+ local -i ppid=${row[ppid_col]} pid=${row[$pid_col]}
250
+ if (( ppid == parent_pid)) || bats_linear_reverse_search "$ppid" child_pids; then
251
+ # exclude `ps` command substitution below
252
+ if (( pid != BASHPID)); then
253
+ child_pids+=("$pid")
254
+ fi
255
+ fi
256
+ done
257
+ # MSYS does not support -o and rows are not sorted by pid
258
+ } < <(ps -Ao pid,ppid,args 2>/dev/null || { ps -ef | sort -k 2 -h; })
259
+ }
260
+
261
+ # send signal to process and all its descendants
262
+ bats_kill_processes_of() { # <parent-pid> [<signal>]
263
+ local -ir parent_pid="${1?}"
264
+ local -r signal=${2?}
265
+ bats_find_processes_of "$parent_pid"
266
+ kill "-$signal" "${child_pids[@]}"
267
+ }
268
+
269
+ # sets a timeout for this process
270
+ bats_start_timeout_countdown() { # <timeout>
271
+ local -ri timeout=$1
272
+ local -ri target_pid=$$
273
+ # shellcheck disable=SC2064
274
+ trap "bats_timeout_trap $target_pid" TERM
275
+ if ! (command -v ps || command -v pkill) >/dev/null; then
276
+ printf "Error: Cannot execute timeout because neither pkill nor ps are available on this system!\n" >&2
277
+ exit 1
278
+ fi
279
+ # Start another process to kill the children of this process
280
+ (
281
+ # with sleep in foreground this shell wouldn't receive signals,
282
+ # so we use wait below and kill sleep explicitly when signalled to do so
283
+ # On Windows the TERM signal does not seem to shut down sleep ->
284
+ # close all fds to avoid blocking IO when sleep does not turn off
285
+ (eval exec {0..255}">&-"; sleep "$timeout") &
286
+ # shellcheck disable=SC2064
287
+ trap "kill $!; exit 0" TERM
288
+ wait
289
+ trap '' TERM
290
+ bats_kill_processes_of $target_pid TERM
291
+ ) &
292
+ }
293
+
294
+ bats_abort_timeout_countdown() {
295
+ # kill the countdown process, don't care if its still there
296
+ kill "$BATS_killer_pid" &>/dev/null || true
297
+ }
298
+
299
+
300
+ if [[ -n "${EPOCHREALTIME-}" ]]; then
301
+ get_mills_since_epoch() { # <output-variable>
302
+ local -r output_variable="$1"
303
+ local int frac
304
+ # allow for different decimal separators
305
+ IFS=., read -r int frac <<<"$EPOCHREALTIME"
306
+ printf -v "$output_variable" "%d" "${int}${frac::3}"
307
+ }
308
+ else
309
+ get_mills_since_epoch() { # <output-variable>
310
+ local -r output_variable="$1"
311
+ local ms_since_epoch
312
+ ms_since_epoch=$(bats_execute date +%s%N)
313
+ if [[ "$ms_since_epoch" == *N || "${#ms_since_epoch}" -lt 19 ]]; then
314
+ ms_since_epoch=$(($(bats_execute date +%s) * 1000))
315
+ else
316
+ ms_since_epoch=$((ms_since_epoch / 1000000))
317
+ fi
318
+ printf -v "$output_variable" "%d" "$ms_since_epoch"
319
+ }
320
+ fi
321
+
322
+ bats_perform_test() {
323
+ if ! declare -F "${BATS_TEST_NAME%% *}" &>/dev/null; then
324
+ local quoted_test_name
325
+ bats_quote_code quoted_test_name "$BATS_TEST_NAME"
326
+ printf "bats: unknown test name %s\n" "$quoted_test_name" >&2
327
+ exit 1
328
+ fi
329
+
330
+ # is this skipped from outside ?
331
+ if [[ -n "${BATS_TEST_SKIPPED-}" ]]; then
332
+ # forward skip (with message) by overriding setup
333
+ # shellcheck disable=SC2317
334
+ setup() {
335
+ skip "$BATS_TEST_SKIPPED"
336
+ }
337
+ fi
338
+
339
+ if [[ -n "${BATS_TEST_TIMEOUT:-}" ]]; then
340
+ bats_start_timeout_countdown "$BATS_TEST_TIMEOUT"
341
+ declare -r BATS_killer_pid=$!
342
+ fi
343
+ BATS_TEST_COMPLETED=
344
+ BATS_TEST_SKIPPED=${BATS_TEST_SKIPPED-}
345
+ BATS_TEARDOWN_COMPLETED=
346
+ BATS_ERROR_STATUS=
347
+ bats_setup_tracing
348
+ # use parameter to mark this call as trap call
349
+ # shellcheck disable=SC2064
350
+ trap "bats_teardown_trap as-exit-trap" EXIT
351
+
352
+ if [[ -n "$BATS_EXTENDED_SYNTAX" ]]; then
353
+ printf 'begin %d %s\n' "$BATS_SUITE_TEST_NUMBER" "${BATS_TEST_NAME_PREFIX:-}$BATS_TEST_DESCRIPTION" >&3
354
+ fi
355
+
356
+ get_mills_since_epoch BATS_TEST_START_TIME
357
+ {
358
+ bats_set_stacktrace_limit
359
+ setup "$@"
360
+ "$@"
361
+ } >>"$BATS_OUT" 2>&1 4>&1
362
+
363
+ BATS_TEST_COMPLETED=1
364
+ # shellcheck disable=SC2064
365
+ trap "bats_exit_trap" EXIT
366
+ bats_teardown_trap "" # pass empty parameter to signify call outside trap
367
+ }
368
+
369
+ trap bats_interrupt_trap INT
370
+
371
+ # shellcheck source=lib/bats-core/preprocessing.bash
372
+ source "$BATS_ROOT/$BATS_LIBDIR/bats-core/preprocessing.bash"
373
+
374
+ exec 3<&1
375
+ BATS_OUT="$BATS_RUN_TMPDIR/test/$BATS_SUITE_TEST_NUMBER.out"
376
+
377
+ bats_create_test_tmpdirs
378
+ bats_evaluate_preprocessed_source
379
+
380
+ readonly BATS_TEST_TAGS
381
+
382
+ # use eval to parse (internally quoted!) test command into parameters
383
+ bats_perform_test "${BATS_TEST_COMMAND[@]}"
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ trap '' INT
5
+
6
+ cat
@@ -0,0 +1,293 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # shellcheck source=lib/bats-core/formatter.bash
5
+ source "$BATS_ROOT/$BATS_LIBDIR/bats-core/formatter.bash"
6
+
7
+ init_suite() {
8
+ suite_test_exec_time=0
9
+ # since we have to print the suite header before its contents but we don't know the contents before the header,
10
+ # we have to buffer the contents
11
+ _suite_buffer=""
12
+ test_result_state="" # declare for the first flush, when no test has been encountered
13
+ }
14
+
15
+ init_file() {
16
+ file_count=0
17
+ file_failures=0
18
+ file_skipped=0
19
+ file_exec_time=0
20
+ test_exec_time=0
21
+ name=""
22
+ _buffer=""
23
+ _buffer_log=""
24
+ _system_out_log=""
25
+ test_result_state="" # mark that no test has run in this file so far
26
+ }
27
+
28
+ host() {
29
+ local hostname="${HOST:-}"
30
+ [[ -z "$hostname" ]] && hostname="${HOSTNAME:-}"
31
+ [[ -z "$hostname" ]] && hostname="$(uname -n)"
32
+ [[ -z "$hostname" ]] && hostname="$(hostname -f)"
33
+
34
+ echo "$hostname"
35
+ }
36
+
37
+ # convert $1 (time in milliseconds) to seconds
38
+ milliseconds_to_seconds() {
39
+ # we cannot rely on having bc for this calculation
40
+ full_seconds=$(($1 / 1000))
41
+ remaining_milliseconds=$(($1 % 1000))
42
+ if [[ $remaining_milliseconds -eq 0 ]]; then
43
+ printf "%d" "$full_seconds"
44
+ else
45
+ printf "%d.%03d" "$full_seconds" "$remaining_milliseconds"
46
+ fi
47
+ }
48
+
49
+ suite_header() {
50
+ printf "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
51
+ <testsuites time=\"%s\">\n" "$(milliseconds_to_seconds "${suite_test_exec_time}")"
52
+ }
53
+
54
+ file_header() {
55
+ timestamp=$(date -u +"%Y-%m-%dT%H:%M:%S")
56
+ printf "<testsuite name=\"%s\" tests=\"%s\" failures=\"%s\" errors=\"0\" skipped=\"%s\" time=\"%s\" timestamp=\"%s\" hostname=\"%s\">\n" \
57
+ "$(xml_escape "${class}")" "${file_count}" "${file_failures}" "${file_skipped}" "$(milliseconds_to_seconds "${file_exec_time}")" "${timestamp}" "$(host)"
58
+ }
59
+
60
+ file_footer() {
61
+ printf "</testsuite>\n"
62
+ }
63
+
64
+ suite_footer() {
65
+ printf "</testsuites>\n"
66
+ }
67
+
68
+ print_test_case() {
69
+ if [[ "$test_result_state" == ok && -z "$_system_out_log" && -z "$_buffer_log" ]]; then
70
+ # pass and no output can be shortened
71
+ printf " <testcase classname=\"%s\" name=\"%s\" time=\"%s\" />\n" "$(xml_escape "${class}")" "$(xml_escape "${name}")" "$(milliseconds_to_seconds "${test_exec_time}")"
72
+ else
73
+ printf " <testcase classname=\"%s\" name=\"%s\" time=\"%s\">\n" "$(xml_escape "${class}")" "$(xml_escape "${name}")" "$(milliseconds_to_seconds "${test_exec_time}")"
74
+ if [[ -n "$_system_out_log" ]]; then
75
+ printf " <system-out>%s</system-out>\n" "$(xml_escape "${_system_out_log}")"
76
+ fi
77
+ if [[ "$test_result_state" == not_ok ]]; then # Failed tests need a <failure> element.
78
+ # If we have system err output, we use that as the failure text.
79
+ printf " <failure type=\"failure\">%s</failure>\n" "$(xml_escape "${_buffer_log}")"
80
+ else
81
+ if [[ -n "$_buffer_log" ]]; then
82
+ printf " <system-err>%s</system-err>\n" "$(xml_escape "${_buffer_log}")"
83
+ fi
84
+ fi
85
+ if [[ "$test_result_state" == skipped ]]; then
86
+ printf " <skipped>%s</skipped>\n" "$(xml_escape "$test_skip_message")"
87
+ fi
88
+ printf " </testcase>\n"
89
+ fi
90
+ }
91
+
92
+ xml_escape() { # <string to escape>
93
+ local output=${1//&/\&amp;}
94
+ output=${output//</\&lt;}
95
+ output=${output//>/\&gt;}
96
+ output=${output//'"'/\&quot;}
97
+ output=${output//\'/\&#39;}
98
+ # remove ANSI escape sequences (e.g. color codes, cursor movements)
99
+ local CONTROL_CHAR=$'\033'
100
+ local REGEX="$CONTROL_CHAR\[[0-9;]*[a-zA-Z]"
101
+ while [[ "$output" =~ $REGEX ]]; do
102
+ output=${output//${BASH_REMATCH[0]}/}
103
+ done
104
+ printf "%s" "$output"
105
+ }
106
+
107
+ suite_buffer() {
108
+ local output
109
+ output="$(
110
+ "$@"
111
+ printf "x"
112
+ )" # use x marker to avoid losing trailing newlines
113
+ _suite_buffer="${_suite_buffer}${output%x}"
114
+ }
115
+
116
+ suite_flush() {
117
+ echo -n "${_suite_buffer}"
118
+ _suite_buffer=""
119
+ }
120
+
121
+ buffer() {
122
+ local output
123
+ output="$(
124
+ "$@"
125
+ printf "x"
126
+ )" # use x marker to avoid losing trailing newlines
127
+ _buffer="${_buffer}${output%x}"
128
+ }
129
+
130
+ flush() {
131
+ echo -n "${_buffer}"
132
+ _buffer=""
133
+ }
134
+
135
+ log_system_err() {
136
+ if [[ -n "$_buffer_log" ]]; then
137
+ _buffer_log="${_buffer_log}
138
+ $1"
139
+ else
140
+ _buffer_log="$1"
141
+ fi
142
+ }
143
+
144
+ flush_log() {
145
+ if [[ -n "$test_result_state" ]]; then
146
+ buffer print_test_case
147
+ fi
148
+ _buffer_log=""
149
+ _system_out_log=""
150
+ test_result_state="" # Clean out result from last test. Retried tests will have multiple begin calls.
151
+ }
152
+
153
+ log_system_out() {
154
+ if [[ -n "$_system_out_log" ]]; then
155
+ _system_out_log="${_system_out_log}
156
+ $1"
157
+ else
158
+ _system_out_log="$1"
159
+ fi
160
+ }
161
+
162
+ finish_file() {
163
+ if [[ "${class}" != JUNIT_FORMATTER_NO_FILE_ENCOUNTERED ]]; then
164
+ file_header
165
+ printf "%s" "${_buffer}"
166
+ file_footer
167
+ class=''
168
+ name=''
169
+ fi
170
+ }
171
+
172
+ finish_suite() {
173
+ flush_log
174
+ suite_header
175
+ suite_flush
176
+ finish_file # must come after suite flush to not print the last file before the others
177
+ suite_footer
178
+ }
179
+
180
+ bats_tap_stream_plan() { # <number of tests>
181
+ :
182
+ }
183
+
184
+ bats_tap_stream_begin() { # <test index> <test name>
185
+ flush_log
186
+ # set after flushing to avoid overriding name of test
187
+ name="$2"
188
+ }
189
+
190
+ bats_tap_stream_ok() { # <test index> <test name>
191
+ test_exec_time=${BATS_FORMATTER_TEST_DURATION:-0}
192
+ ((file_count += 1))
193
+ test_result_state='ok'
194
+ file_exec_time="$((file_exec_time + test_exec_time))"
195
+ suite_test_exec_time=$((suite_test_exec_time + test_exec_time))
196
+ }
197
+
198
+ bats_tap_stream_skipped() { # <test index> <test name> <skip reason>
199
+ test_exec_time=${BATS_FORMATTER_TEST_DURATION:-0}
200
+ ((file_count += 1))
201
+ ((file_skipped += 1))
202
+ test_result_state='skipped'
203
+ test_exec_time=0
204
+ test_skip_message="$3"
205
+ }
206
+
207
+ bats_tap_stream_not_ok() { # <test index> <test name>
208
+ if [[ -z "${name:-}" ]]; then
209
+ # Can be called (after bats_tap_stream_plan) before anything else if the test fails in setup_suite
210
+ bats_tap_stream_suite "setup_suite"
211
+ bats_tap_stream_begin "$1" "$2"
212
+ fi
213
+ test_exec_time=${BATS_FORMATTER_TEST_DURATION:-0}
214
+ ((file_count += 1))
215
+ ((file_failures += 1))
216
+ test_result_state=not_ok
217
+ file_exec_time="$((file_exec_time + test_exec_time))"
218
+ suite_test_exec_time=$((suite_test_exec_time + test_exec_time))
219
+ }
220
+
221
+ bats_tap_stream_comment() { # <comment text without leading '# '> <scope>
222
+ local comment="$1" scope="$2"
223
+ case "$scope" in
224
+ begin)
225
+ # everything that happens between begin and [not] ok is FD3 output from the test
226
+ log_system_out "$comment"
227
+ ;;
228
+ ok | skipped)
229
+ # non failed tests can produce FD3 output
230
+ log_system_out "$comment"
231
+ ;;
232
+ *)
233
+ # everything else is considered error output
234
+ log_system_err "$1"
235
+ ;;
236
+ esac
237
+ }
238
+
239
+ bats_tap_stream_suite() { # <file name>
240
+ flush_log
241
+ suite_buffer finish_file
242
+ init_file
243
+ class="${1/$BASE_PATH/}"
244
+ }
245
+
246
+ bats_tap_stream_unknown() { # <full line>
247
+ local line="$1" scope="$2"
248
+ log_system_out "$line"
249
+ }
250
+
251
+ main() {
252
+ local _buffer_log="" \
253
+ name="" \
254
+ class="JUNIT_FORMATTER_NO_FILE_ENCOUNTERED" \
255
+ _buffer="" \
256
+ _buffer_log="" \
257
+ _suite_buffer="" \
258
+ _system_out_log="" \
259
+ test_result_state="" \
260
+ test_skip_message=""
261
+
262
+ local -i file_count=0 \
263
+ file_failures=0 \
264
+ file_skipped=0 \
265
+ file_exec_time=0 \
266
+ test_exec_time=0 \
267
+ suite_test_exec_time=0
268
+
269
+ local BASE_PATH=.
270
+
271
+ while [[ "$#" -ne 0 ]]; do
272
+ case "$1" in
273
+ --base-path)
274
+ shift
275
+ normalize_base_path BASE_PATH "$1"
276
+ ;;
277
+ esac
278
+ shift
279
+ done
280
+
281
+ init_suite
282
+ trap finish_suite EXIT
283
+ trap '' INT
284
+
285
+ bats_parse_internal_extended_tap
286
+
287
+ trap - EXIT
288
+ finish_suite # ensure we run this with the local variables still in scope
289
+ }
290
+
291
+ # [\x00-\x08\x0B\x0C\x0E-\x1F] can't use $'\x00' as this terminates the string early
292
+ BATS_JUNIT_FORMATTER_DELETE_CHARS_DEFAULT='\000'$'\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F'
293
+ main "$@" | tr -d "${BATS_JUNIT_FORMATTER_DELETE_CHARS-$BATS_JUNIT_FORMATTER_DELETE_CHARS_DEFAULT}"