@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.
- package/LICENSE.md +53 -0
- package/README.md +135 -0
- package/bin/bats +75 -0
- package/install.sh +29 -0
- package/lib/bats-core/common.bash +278 -0
- package/lib/bats-core/formatter.bash +151 -0
- package/lib/bats-core/preprocessing.bash +19 -0
- package/lib/bats-core/semaphore.bash +113 -0
- package/lib/bats-core/test_functions.bash +539 -0
- package/lib/bats-core/tracing.bash +425 -0
- package/lib/bats-core/validator.bash +37 -0
- package/lib/bats-core/warnings.bash +44 -0
- package/libexec/bats-core/bats +555 -0
- package/libexec/bats-core/bats-exec-file +402 -0
- package/libexec/bats-core/bats-exec-suite +346 -0
- package/libexec/bats-core/bats-exec-test +383 -0
- package/libexec/bats-core/bats-format-cat +6 -0
- package/libexec/bats-core/bats-format-junit +293 -0
- package/libexec/bats-core/bats-format-pretty +360 -0
- package/libexec/bats-core/bats-format-tap +55 -0
- package/libexec/bats-core/bats-format-tap13 +89 -0
- package/libexec/bats-core/bats-gather-tests +402 -0
- package/libexec/bats-core/bats-preprocess +118 -0
- package/man/Makefile +23 -0
- package/man/README.md +5 -0
- package/man/bats.1 +143 -0
- package/man/bats.1.ronn +201 -0
- package/man/bats.7 +300 -0
- package/man/bats.7.ronn +404 -0
- package/package.json +36 -0
- package/uninstall.sh +63 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# reads (extended) bats tap streams from stdin and calls callback functions for each line
|
|
4
|
+
#
|
|
5
|
+
# Segmenting functions
|
|
6
|
+
# ====================
|
|
7
|
+
# bats_tap_stream_plan <number of tests> -> when the test plan is encountered
|
|
8
|
+
# bats_tap_stream_suite <file name> -> when a new file is begun WARNING: extended only
|
|
9
|
+
# bats_tap_stream_begin <test index> <test name> -> when a new test is begun WARNING: extended only
|
|
10
|
+
#
|
|
11
|
+
# Test result functions
|
|
12
|
+
# =====================
|
|
13
|
+
# If timing was enabled, BATS_FORMATTER_TEST_DURATION will be set to their duration in milliseconds
|
|
14
|
+
# bats_tap_stream_ok <test index> <test name> -> when a test was successful
|
|
15
|
+
# bats_tap_stream_not_ok <test index> <test name> -> when a test has failed. If the failure was due to a timeout,
|
|
16
|
+
# BATS_FORMATTER_TEST_TIMEOUT is set to the timeout duration in seconds
|
|
17
|
+
# bats_tap_stream_skipped <test index> <test name> <skip reason> -> when a test was skipped
|
|
18
|
+
#
|
|
19
|
+
# Context functions
|
|
20
|
+
# =================
|
|
21
|
+
# bats_tap_stream_comment <comment text without leading '# '> <scope> -> when a comment line was encountered,
|
|
22
|
+
# scope tells the last encountered of plan, begin, ok, not_ok, skipped, suite
|
|
23
|
+
# bats_tap_stream_unknown <full line> <scope> -> when a line is encountered that does not match the previous entries,
|
|
24
|
+
# scope @see bats_tap_stream_comment
|
|
25
|
+
# forwards all input as is, when there is no TAP test plan header
|
|
26
|
+
function bats_parse_internal_extended_tap() {
|
|
27
|
+
local header_pattern='[0-9]+\.\.[0-9]+'
|
|
28
|
+
IFS= read -r header
|
|
29
|
+
|
|
30
|
+
if [[ "$header" =~ $header_pattern ]]; then
|
|
31
|
+
bats_tap_stream_plan "${header:3}"
|
|
32
|
+
else
|
|
33
|
+
# If the first line isn't a TAP plan, print it and pass the rest through
|
|
34
|
+
printf '%s\n' "$header"
|
|
35
|
+
exec cat
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
ok_line_regexpr="ok ([0-9]+) (.*)"
|
|
39
|
+
skip_line_regexpr="ok ([0-9]+) (.*) # skip( (.*))?$"
|
|
40
|
+
timeout_line_regexpr="not ok ([0-9]+) (.*) # timeout after ([0-9]+)s$"
|
|
41
|
+
not_ok_line_regexpr="not ok ([0-9]+) (.*)"
|
|
42
|
+
|
|
43
|
+
timing_expr="in ([0-9]+)ms$"
|
|
44
|
+
local test_name begin_index last_begin_index try_index ok_index not_ok_index index scope
|
|
45
|
+
begin_index=0
|
|
46
|
+
last_begin_index=-1
|
|
47
|
+
try_index=0
|
|
48
|
+
index=0
|
|
49
|
+
scope=plan
|
|
50
|
+
while IFS= read -r line; do
|
|
51
|
+
unset BATS_FORMATTER_TEST_DURATION BATS_FORMATTER_TEST_TIMEOUT
|
|
52
|
+
case "$line" in
|
|
53
|
+
'begin '*) # this might only be called in extended tap output
|
|
54
|
+
scope=begin
|
|
55
|
+
begin_index=${line#begin }
|
|
56
|
+
begin_index=${begin_index%% *}
|
|
57
|
+
if [[ $begin_index == "$last_begin_index" ]]; then
|
|
58
|
+
(( ++try_index ))
|
|
59
|
+
else
|
|
60
|
+
try_index=0
|
|
61
|
+
fi
|
|
62
|
+
test_name="${line#begin "$begin_index" }"
|
|
63
|
+
bats_tap_stream_begin "$begin_index" "$test_name"
|
|
64
|
+
;;
|
|
65
|
+
'ok '*)
|
|
66
|
+
((++index))
|
|
67
|
+
if [[ "$line" =~ $ok_line_regexpr ]]; then
|
|
68
|
+
ok_index="${BASH_REMATCH[1]}"
|
|
69
|
+
test_name="${BASH_REMATCH[2]}"
|
|
70
|
+
if [[ "$line" =~ $skip_line_regexpr ]]; then
|
|
71
|
+
scope=skipped
|
|
72
|
+
test_name="${BASH_REMATCH[2]}" # cut off name before "# skip"
|
|
73
|
+
local skip_reason="${BASH_REMATCH[4]}"
|
|
74
|
+
if [[ "$test_name" =~ $timing_expr ]]; then
|
|
75
|
+
local BATS_FORMATTER_TEST_DURATION="${BASH_REMATCH[1]}"
|
|
76
|
+
test_name="${test_name% in "${BATS_FORMATTER_TEST_DURATION}"ms}"
|
|
77
|
+
bats_tap_stream_skipped "$ok_index" "$test_name" "$skip_reason"
|
|
78
|
+
else
|
|
79
|
+
bats_tap_stream_skipped "$ok_index" "$test_name" "$skip_reason"
|
|
80
|
+
fi
|
|
81
|
+
else
|
|
82
|
+
scope=ok
|
|
83
|
+
if [[ "$line" =~ $timing_expr ]]; then
|
|
84
|
+
local BATS_FORMATTER_TEST_DURATION="${BASH_REMATCH[1]}"
|
|
85
|
+
bats_tap_stream_ok "$ok_index" "${test_name% in "${BASH_REMATCH[1]}"ms}"
|
|
86
|
+
else
|
|
87
|
+
bats_tap_stream_ok "$ok_index" "$test_name"
|
|
88
|
+
fi
|
|
89
|
+
fi
|
|
90
|
+
else
|
|
91
|
+
printf "ERROR: could not match ok line: %s" "$line" >&2
|
|
92
|
+
exit 1
|
|
93
|
+
fi
|
|
94
|
+
;;
|
|
95
|
+
'not ok '*)
|
|
96
|
+
((++index))
|
|
97
|
+
scope=not_ok
|
|
98
|
+
if [[ "$line" =~ $not_ok_line_regexpr ]]; then
|
|
99
|
+
not_ok_index="${BASH_REMATCH[1]}"
|
|
100
|
+
test_name="${BASH_REMATCH[2]}"
|
|
101
|
+
if [[ "$line" =~ $timeout_line_regexpr ]]; then
|
|
102
|
+
not_ok_index="${BASH_REMATCH[1]}"
|
|
103
|
+
test_name="${BASH_REMATCH[2]}"
|
|
104
|
+
# shellcheck disable=SC2034 # used in bats_tap_stream_ok
|
|
105
|
+
local BATS_FORMATTER_TEST_TIMEOUT="${BASH_REMATCH[3]}"
|
|
106
|
+
fi
|
|
107
|
+
if [[ "$test_name" =~ $timing_expr ]]; then
|
|
108
|
+
# shellcheck disable=SC2034 # used in bats_tap_stream_ok
|
|
109
|
+
local BATS_FORMATTER_TEST_DURATION="${BASH_REMATCH[1]}"
|
|
110
|
+
test_name="${test_name% in "${BASH_REMATCH[1]}"ms}"
|
|
111
|
+
fi
|
|
112
|
+
bats_tap_stream_not_ok "$not_ok_index" "$test_name"
|
|
113
|
+
else
|
|
114
|
+
printf "ERROR: could not match not ok line: %s" "$line" >&2
|
|
115
|
+
exit 1
|
|
116
|
+
fi
|
|
117
|
+
;;
|
|
118
|
+
'# '*)
|
|
119
|
+
bats_tap_stream_comment "${line:2}" "$scope"
|
|
120
|
+
;;
|
|
121
|
+
'#')
|
|
122
|
+
bats_tap_stream_comment "" "$scope"
|
|
123
|
+
;;
|
|
124
|
+
'suite '*)
|
|
125
|
+
scope=suite
|
|
126
|
+
# pass on the
|
|
127
|
+
bats_tap_stream_suite "${line:6}"
|
|
128
|
+
;;
|
|
129
|
+
*)
|
|
130
|
+
bats_tap_stream_unknown "$line" "$scope"
|
|
131
|
+
;;
|
|
132
|
+
esac
|
|
133
|
+
done
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
normalize_base_path() { # <target variable> <base path>
|
|
137
|
+
# the relative path root to use for reporting filenames
|
|
138
|
+
# this is mainly intended for suite mode, where this will be the suite root folder
|
|
139
|
+
local base_path="$2"
|
|
140
|
+
# use the containing directory when --base-path is a file
|
|
141
|
+
if [[ ! -d "$base_path" ]]; then
|
|
142
|
+
base_path="$(dirname "$base_path")"
|
|
143
|
+
fi
|
|
144
|
+
# get the absolute path
|
|
145
|
+
base_path="$(cd "$base_path" && pwd)"
|
|
146
|
+
# ensure the path ends with / to strip that later on
|
|
147
|
+
if [[ "${base_path}" != *"/" ]]; then
|
|
148
|
+
base_path="$base_path/"
|
|
149
|
+
fi
|
|
150
|
+
printf -v "$1" "%s" "$base_path"
|
|
151
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
bats_export_preprocess_source_BATS_TEST_SOURCE() {
|
|
4
|
+
# export to make it visible to bats_evaluate_preprocessed_source
|
|
5
|
+
# since the latter runs in bats-exec-test's bash while this runs in bats-exec-file's
|
|
6
|
+
export BATS_TEST_SOURCE="$BATS_RUN_TMPDIR/${BATS_TEST_FILE_NUMBER?}-${BATS_TEST_FILENAME##*/}.src"
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
bats_preprocess_source() { # index
|
|
10
|
+
bats_export_preprocess_source_BATS_TEST_SOURCE
|
|
11
|
+
# shellcheck disable=SC2153
|
|
12
|
+
CHECK_BATS_COMMENT_COMMANDS=1 "$BATS_ROOT/libexec/bats-core/bats-preprocess" "$BATS_TEST_FILENAME" >"$BATS_TEST_SOURCE"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
bats_evaluate_preprocessed_source() {
|
|
16
|
+
# Dynamically loaded user files provided outside of Bats.
|
|
17
|
+
# shellcheck disable=SC1090
|
|
18
|
+
source "${BATS_TEST_SOURCE?}"
|
|
19
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
bats_run_under_flock() {
|
|
4
|
+
flock "$BATS_SEMAPHORE_DIR" "$@"
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
bats_run_under_shlock() {
|
|
8
|
+
local lockfile="$BATS_SEMAPHORE_DIR/shlock.lock"
|
|
9
|
+
while ! shlock -p $$ -f "$lockfile"; do
|
|
10
|
+
sleep 1
|
|
11
|
+
done
|
|
12
|
+
# we got the lock now, execute the command
|
|
13
|
+
"$@"
|
|
14
|
+
local status=$?
|
|
15
|
+
# free the lock
|
|
16
|
+
rm -f "$lockfile"
|
|
17
|
+
return $status
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
# setup the semaphore environment for the loading file
|
|
21
|
+
bats_semaphore_setup() {
|
|
22
|
+
export -f bats_semaphore_get_free_slot_count
|
|
23
|
+
export -f bats_semaphore_acquire_while_locked
|
|
24
|
+
export BATS_SEMAPHORE_DIR="$BATS_RUN_TMPDIR/semaphores"
|
|
25
|
+
|
|
26
|
+
if command -v flock >/dev/null; then
|
|
27
|
+
BATS_LOCKING_IMPLEMENTATION=flock
|
|
28
|
+
elif command -v shlock >/dev/null; then
|
|
29
|
+
BATS_LOCKING_IMPLEMENTATION=shlock
|
|
30
|
+
else
|
|
31
|
+
printf "ERROR: flock/shlock is required for parallelization within files!\n" >&2
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# $1 - output directory for stdout/stderr
|
|
37
|
+
# $@ - command to run
|
|
38
|
+
# run the given command in a semaphore
|
|
39
|
+
# block when there is no free slot for the semaphore
|
|
40
|
+
# when there is a free slot, run the command in background
|
|
41
|
+
# gather the output of the command in files in the given directory
|
|
42
|
+
bats_semaphore_run() {
|
|
43
|
+
local output_dir=$1
|
|
44
|
+
shift
|
|
45
|
+
local semaphore_slot
|
|
46
|
+
semaphore_slot=$(bats_semaphore_acquire_slot)
|
|
47
|
+
bats_semaphore_release_wrapper "$output_dir" "$semaphore_slot" "$@" &
|
|
48
|
+
printf "%d\n" "$!"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# $1 - output directory for stdout/stderr
|
|
52
|
+
# $@ - command to run
|
|
53
|
+
# this wraps the actual function call to install some traps on exiting
|
|
54
|
+
bats_semaphore_release_wrapper() {
|
|
55
|
+
local output_dir="$1"
|
|
56
|
+
local semaphore_name="$2"
|
|
57
|
+
shift 2 # all other parameters will be use for the command to execute
|
|
58
|
+
|
|
59
|
+
# shellcheck disable=SC2064 # we want to expand the semaphore_name right now!
|
|
60
|
+
trap "status=$?; bats_semaphore_release_slot '$semaphore_name'; exit $status" EXIT
|
|
61
|
+
|
|
62
|
+
mkdir -p "$output_dir"
|
|
63
|
+
"$@" 2>"$output_dir/stderr" >"$output_dir/stdout"
|
|
64
|
+
local status=$?
|
|
65
|
+
|
|
66
|
+
# bash bug: the exit trap is not called for the background process
|
|
67
|
+
bats_semaphore_release_slot "$semaphore_name"
|
|
68
|
+
trap - EXIT # avoid calling release twice
|
|
69
|
+
return $status
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
bats_semaphore_acquire_while_locked() {
|
|
73
|
+
if [[ $(bats_semaphore_get_free_slot_count) -gt 0 ]]; then
|
|
74
|
+
local slot=0
|
|
75
|
+
while [[ -e "$BATS_SEMAPHORE_DIR/slot-$slot" ]]; do
|
|
76
|
+
((++slot))
|
|
77
|
+
done
|
|
78
|
+
if [[ $slot -lt $BATS_SEMAPHORE_NUMBER_OF_SLOTS ]]; then
|
|
79
|
+
touch "$BATS_SEMAPHORE_DIR/slot-$slot" && printf "%d\n" "$slot" && return 0
|
|
80
|
+
fi
|
|
81
|
+
fi
|
|
82
|
+
return 1
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# block until a semaphore slot becomes free
|
|
86
|
+
# prints the number of the slot that it received
|
|
87
|
+
bats_semaphore_acquire_slot() {
|
|
88
|
+
mkdir -p "$BATS_SEMAPHORE_DIR"
|
|
89
|
+
# wait for a slot to become free
|
|
90
|
+
# TODO: avoid busy waiting by using signals -> this opens op prioritizing possibilities as well
|
|
91
|
+
while true; do
|
|
92
|
+
# don't lock for reading, we are fine with spuriously getting no free slot
|
|
93
|
+
if [[ $(bats_semaphore_get_free_slot_count) -gt 0 ]]; then
|
|
94
|
+
bats_run_under_"$BATS_LOCKING_IMPLEMENTATION" \
|
|
95
|
+
bash -c bats_semaphore_acquire_while_locked \
|
|
96
|
+
&& break
|
|
97
|
+
fi
|
|
98
|
+
sleep 1
|
|
99
|
+
done
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
bats_semaphore_release_slot() {
|
|
103
|
+
# we don't need to lock this, since only our process owns this file
|
|
104
|
+
# and freeing a semaphore cannot lead to conflicts with others
|
|
105
|
+
rm "$BATS_SEMAPHORE_DIR/slot-$1" # this will fail if we had not acquired a semaphore!
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
bats_semaphore_get_free_slot_count() {
|
|
109
|
+
# find might error out without returning something useful when a file is deleted,
|
|
110
|
+
# while the directory is traversed -> only continue when there was no error
|
|
111
|
+
until used_slots=$(find "$BATS_SEMAPHORE_DIR" -name 'slot-*' 2>/dev/null | wc -l); do :; done
|
|
112
|
+
echo $((BATS_SEMAPHORE_NUMBER_OF_SLOTS - used_slots))
|
|
113
|
+
}
|