@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 ADDED
@@ -0,0 +1,53 @@
1
+ Copyright (c) 2017 bats-core contributors
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ ---
23
+
24
+ * [bats-core] is a continuation of [bats]. Copyright for portions of the
25
+ bats-core project are held by Sam Stephenson, 2014 as part of the project
26
+ [bats], licensed under MIT:
27
+
28
+ Copyright (c) 2014 Sam Stephenson
29
+
30
+ Permission is hereby granted, free of charge, to any person obtaining
31
+ a copy of this software and associated documentation files (the
32
+ "Software"), to deal in the Software without restriction, including
33
+ without limitation the rights to use, copy, modify, merge, publish,
34
+ distribute, sublicense, and/or sell copies of the Software, and to
35
+ permit persons to whom the Software is furnished to do so, subject to
36
+ the following conditions:
37
+
38
+ The above copyright notice and this permission notice shall be
39
+ included in all copies or substantial portions of the Software.
40
+
41
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
42
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
43
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
44
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
45
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
46
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
47
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48
+
49
+ For details, please see the [version control history][commits].
50
+
51
+ [bats-core]: https://github.com/bats-core/bats-core
52
+ [bats]:https://github.com/sstephenson/bats
53
+ [commits]:https://github.com/bats-core/bats-core/commits/master
package/README.md ADDED
@@ -0,0 +1,135 @@
1
+ [![Latest release](https://img.shields.io/github/release/bats-core/bats-core.svg)](https://github.com/bats-core/bats-core/releases/latest)
2
+ [![npm package](https://img.shields.io/npm/v/bats.svg)](https://www.npmjs.com/package/bats)
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/bats-core/bats-core/blob/master/LICENSE.md)
4
+ [![Continuous integration status](https://github.com/bats-core/bats-core/workflows/Tests/badge.svg)](https://github.com/bats-core/bats-core/actions?query=workflow%3ATests)
5
+ [![Read the docs status](https://readthedocs.org/projects/bats-core/badge/)](https://bats-core.readthedocs.io)
6
+
7
+ [![Join the chat in bats-core/bats-core on gitter](https://badges.gitter.im/bats-core/bats-core.svg)][gitter]
8
+
9
+ <div align="center">
10
+ <picture>
11
+ <source media="(prefers-color-scheme: dark)" srcset="docs/source/assets/dark_mode_cube.svg">
12
+ <img alt="" src="docs/source/assets/light_mode_cube.svg">
13
+ </picture>
14
+ </div>
15
+
16
+ # Bats-core: Bash Automated Testing System
17
+
18
+ Bats is a [TAP](https://testanything.org/)-compliant testing framework for Bash
19
+ 3.2 or above. It provides a simple way to verify that the UNIX programs you
20
+ write behave as expected.
21
+
22
+ A Bats test file is a Bash script with special syntax for defining test cases.
23
+ Under the hood, each test case is just a function with a description.
24
+
25
+ ```bash
26
+ #!/usr/bin/env bats
27
+
28
+ @test "addition using bc" {
29
+ result="$(echo 2+2 | bc)"
30
+ [ "$result" -eq 4 ]
31
+ }
32
+
33
+ @test "addition using dc" {
34
+ result="$(echo 2 2+p | dc)"
35
+ [ "$result" -eq 4 ]
36
+ }
37
+ ```
38
+
39
+ Bats is most useful when testing software written in Bash, but you can use it to
40
+ test any UNIX program.
41
+
42
+ Test cases consist of standard shell commands. Bats makes use of Bash's
43
+ `errexit` (`set -e`) option when running test cases. If every command in the
44
+ test case exits with a `0` status code (success), the test passes. In this way,
45
+ each line is an assertion of truth.
46
+
47
+ ## Table of contents
48
+
49
+ **NOTE** The documentation has moved to <https://bats-core.readthedocs.io>
50
+
51
+ <!-- toc -->
52
+
53
+ - [Testing](#testing)
54
+ - [Support](#support)
55
+ - [Contributing](#contributing)
56
+ - [Contact](#contact)
57
+ - [Version history](#version-history)
58
+ - [Background](#background)
59
+ * [What's the plan and why?](#whats-the-plan-and-why)
60
+ * [Why was this fork created?](#why-was-this-fork-created)
61
+ - [Copyright](#copyright)
62
+
63
+ <!-- tocstop -->
64
+
65
+ ## Testing
66
+
67
+ ```sh
68
+ bin/bats --tap test
69
+ ```
70
+
71
+ See also the [CI](./.github/workflows/tests.yml) settings for the current test environment and
72
+ scripts.
73
+
74
+ ## Support
75
+
76
+ The Bats source code repository is [hosted on
77
+ GitHub](https://github.com/bats-core/bats-core). There you can file bugs on the
78
+ issue tracker or submit tested pull requests for review.
79
+
80
+ For real-world examples from open-source projects using Bats, see [Projects
81
+ Using Bats](https://github.com/bats-core/bats-core/wiki/Projects-Using-Bats) on
82
+ the wiki.
83
+
84
+ To learn how to set up your editor for Bats syntax highlighting, see [Syntax
85
+ Highlighting](https://github.com/bats-core/bats-core/wiki/Syntax-Highlighting)
86
+ on the wiki.
87
+
88
+ ## Contributing
89
+
90
+ For now see the [`docs`](docs) folder for project guides, work with us on the wiki
91
+ or look at the other communication channels.
92
+
93
+ ## Contact
94
+
95
+ - You can find and chat with us on our [Gitter].
96
+
97
+ ## Version history
98
+
99
+ See `docs/CHANGELOG.md`.
100
+
101
+ ## Background
102
+
103
+ <!-- markdownlint-disable MD026 -->
104
+ ### Why was this fork created?
105
+ <!-- markdownlint-enable MD026 -->
106
+
107
+ There was an initial [call for maintainers][call-maintain] for the original Bats repository, but write access to it could not be obtained. With development activity stalled, this fork allowed ongoing maintenance and forward progress for Bats.
108
+
109
+ **Tuesday, September 19, 2017:** This was forked from [Bats][bats-orig] at
110
+ commit [0360811][]. It was created via `git clone --bare` and `git push
111
+ --mirror`.
112
+
113
+ As of **Thursday, April 29, 2021:** the original [Bats][bats-orig] has been
114
+ archived by the owner and is now read-only.
115
+
116
+ This [bats-core](https://github.com/bats-core/bats-core) repo is now the community-maintained Bats project.
117
+
118
+ [call-maintain]: https://github.com/sstephenson/bats/issues/150
119
+ [bats-orig]: https://github.com/sstephenson/bats
120
+ [0360811]: https://github.com/sstephenson/bats/commit/03608115df2071fff4eaaff1605768c275e5f81f
121
+
122
+ ## Copyright
123
+
124
+ The Bats Logo was created by [Vukory](https://www.artstation.com/vukory) ([Github](https://github.com/vukory)) and sponsored by [SethFalco](https://github.com/SethFalco). If you want to use our logo, have a look at our [guidelines](./docs/source/assets/README.md#Usage-Guide-for-Third-Parties).
125
+
126
+ © 2017-2024 bats-core organization
127
+
128
+ © 2011-2016 Sam Stephenson
129
+
130
+ Bats is released under an MIT-style license; see `LICENSE.md` for details.
131
+
132
+ See the [parent project](https://github.com/bats-core) at GitHub or the
133
+ [AUTHORS](AUTHORS) file for the current project maintainer team.
134
+
135
+ [gitter]: https://gitter.im/bats-core/bats-core
package/bin/bats ADDED
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euo pipefail
4
+
5
+ # Note: We first need to use POSIX's `[ ... ]' instead of Bash's `[[ ... ]]'
6
+ # because this is the check for Bash, where the shell may not be Bash. Once we
7
+ # confirm that we are in Bash, we can use [[ ... ]] and (( ... )). Note that
8
+ # these [[ ... ]] and (( ... )) do not cause syntax errors in POSIX shells,
9
+ # though they can be parsed differently.
10
+ if [ -z "${BASH_VERSION-}" ] ||
11
+ [[ -z "${BASH_VERSINFO-}" ]] ||
12
+ ((BASH_VERSINFO[0] < 3 || (BASH_VERSINFO[0] == 3 && BASH_VERSINFO[1] < 2)))
13
+ then
14
+ printf 'bats: this program needs to be run by Bash >= 3.2\n' >&2
15
+ exit 1
16
+ fi
17
+
18
+ if command -v greadlink >/dev/null; then
19
+ bats_readlinkf() {
20
+ greadlink -f "$1"
21
+ }
22
+ else
23
+ bats_readlinkf() {
24
+ readlink -f "$1"
25
+ }
26
+ fi
27
+
28
+ fallback_to_readlinkf_posix() {
29
+ bats_readlinkf() {
30
+ [ "${1:-}" ] || return 1
31
+ max_symlinks=40
32
+ CDPATH='' # to avoid changing to an unexpected directory
33
+
34
+ target=$1
35
+ [ -e "${target%/}" ] || target=${1%"${1##*[!/]}"} # trim trailing slashes
36
+ [ -d "${target:-/}" ] && target="$target/"
37
+
38
+ cd -P . 2>/dev/null || return 1
39
+ while [ "$max_symlinks" -ge 0 ] && max_symlinks=$((max_symlinks - 1)); do
40
+ if [ ! "$target" = "${target%/*}" ]; then
41
+ case $target in
42
+ /*) cd -P "${target%/*}/" 2>/dev/null || break ;;
43
+ *) cd -P "./${target%/*}" 2>/dev/null || break ;;
44
+ esac
45
+ target=${target##*/}
46
+ fi
47
+
48
+ if [ ! -L "$target" ]; then
49
+ target="${PWD%/}${target:+/}${target}"
50
+ printf '%s\n' "${target:-/}"
51
+ return 0
52
+ fi
53
+
54
+ # `ls -dl` format: "%s %u %s %s %u %s %s -> %s\n",
55
+ # <file mode>, <number of links>, <owner name>, <group name>,
56
+ # <size>, <date and time>, <pathname of link>, <contents of link>
57
+ # https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html
58
+ link=$(ls -dl -- "$target" 2>/dev/null) || break
59
+ target=${link#*" $target -> "}
60
+ done
61
+ return 1
62
+ }
63
+ }
64
+
65
+ if ! BATS_PATH=$(bats_readlinkf "${BASH_SOURCE[0]}" 2>/dev/null); then
66
+ fallback_to_readlinkf_posix
67
+ BATS_PATH=$(bats_readlinkf "${BASH_SOURCE[0]}")
68
+ fi
69
+
70
+ export BATS_SAVED_PATH=$PATH
71
+ BATS_BASE_LIBDIR=lib # this will be patched with the true value in install.sh
72
+
73
+ export BATS_ROOT=${BATS_PATH%/*/*}
74
+ export -f bats_readlinkf
75
+ exec env BATS_ROOT="$BATS_ROOT" BATS_LIBDIR="${BATS_BASE_LIBDIR:-lib}" "$BATS_ROOT/libexec/bats-core/bats" "$@"
package/install.sh ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ BATS_ROOT="${0%/*}"
6
+ PREFIX="${1%/}"
7
+ LIBDIR="${2:-lib}"
8
+
9
+ if [[ -z "$PREFIX" ]]; then
10
+ printf '%s\n' \
11
+ "usage: $0 <prefix> [base_libdir]" \
12
+ " e.g. $0 /usr/local" \
13
+ " $0 /usr/local lib64" >&2
14
+ exit 1
15
+ fi
16
+
17
+ install -d -m 755 "$PREFIX"/{bin,libexec/bats-core,"${LIBDIR}"/bats-core,share/man/man{1,7}}
18
+
19
+ install -m 755 "$BATS_ROOT/bin"/* "$PREFIX/bin"
20
+ install -m 755 "$BATS_ROOT/libexec/bats-core"/* "$PREFIX/libexec/bats-core"
21
+ install -m 755 "$BATS_ROOT/lib/bats-core"/* "$PREFIX/${LIBDIR}/bats-core"
22
+ install -m 644 "$BATS_ROOT/man/bats.1" "$PREFIX/share/man/man1"
23
+ install -m 644 "$BATS_ROOT/man/bats.7" "$PREFIX/share/man/man7"
24
+
25
+ read -rd '' BATS_EXE_CONTENTS <"$PREFIX/bin/bats" || true
26
+ BATS_EXE_CONTENTS=${BATS_EXE_CONTENTS/"BATS_BASE_LIBDIR=lib"/"BATS_BASE_LIBDIR=${LIBDIR}"}
27
+ printf "%s" "$BATS_EXE_CONTENTS" >| "$PREFIX/bin/bats"
28
+
29
+ echo "Installed Bats to $PREFIX/bin/bats"
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env bash
2
+
3
+ bats_prefix_lines_for_tap_output() {
4
+ while IFS= read -r line; do
5
+ printf '# %s\n' "$line" || break # avoid feedback loop when errors are redirected into BATS_OUT (see #353)
6
+ done
7
+ if [[ -n "$line" ]]; then
8
+ printf '# %s\n' "$line"
9
+ fi
10
+ }
11
+
12
+ function bats_replace_filename() {
13
+ local line
14
+ while read -r line; do
15
+ printf "%s\n" "${line//$BATS_TEST_SOURCE/$BATS_TEST_FILENAME}"
16
+ done
17
+ if [[ -n "$line" ]]; then
18
+ printf "%s\n" "${line//$BATS_TEST_SOURCE/$BATS_TEST_FILENAME}"
19
+ fi
20
+ }
21
+
22
+ bats_quote_code() { # <var> <code>
23
+ printf -v "$1" -- "%s%s%s" "$BATS_BEGIN_CODE_QUOTE" "$2" "$BATS_END_CODE_QUOTE"
24
+ }
25
+
26
+ bats_check_valid_version() {
27
+ if [[ ! $1 =~ [0-9]+.[0-9]+.[0-9]+ ]]; then
28
+ printf "ERROR: version '%s' must be of format <major>.<minor>.<patch>!\n" "$1" >&2
29
+ exit 1
30
+ fi
31
+ }
32
+
33
+ # compares two versions. Return 0 when version1 < version2
34
+ bats_version_lt() { # <version1> <version2>
35
+ bats_check_valid_version "$1"
36
+ bats_check_valid_version "$2"
37
+
38
+ local -a version1_parts version2_parts
39
+ IFS=. read -ra version1_parts <<<"$1"
40
+ IFS=. read -ra version2_parts <<<"$2"
41
+
42
+ local -i i
43
+ for i in {0..2}; do
44
+ if ((version1_parts[i] < version2_parts[i])); then
45
+ return 0
46
+ elif ((version1_parts[i] > version2_parts[i])); then
47
+ return 1
48
+ fi
49
+ done
50
+ # if we made it this far, they are equal -> also not less then
51
+ return 2 # use other failing return code to distinguish equal from gt
52
+ }
53
+
54
+ # ensure a minimum version of bats is running or exit with failure
55
+ bats_require_minimum_version() { # <required version>
56
+ local required_minimum_version=$1
57
+
58
+ if bats_version_lt "$BATS_VERSION" "$required_minimum_version"; then
59
+ printf "BATS_VERSION=%s does not meet required minimum %s\n" "$BATS_VERSION" "$required_minimum_version"
60
+ exit 1
61
+ fi
62
+
63
+ if bats_version_lt "$BATS_GUARANTEED_MINIMUM_VERSION" "$required_minimum_version"; then
64
+ BATS_GUARANTEED_MINIMUM_VERSION="$required_minimum_version"
65
+ fi
66
+ }
67
+
68
+ # returns 0 when search-value is found in array
69
+ bats_linear_reverse_search() { # <search-value> <array-name>
70
+ local -r search_value=$1 array_name=$2
71
+ eval "local -ri array_length=\${#${array_name}[@]}"
72
+ # shellcheck disable=SC2154
73
+ for ((i=array_length - 1; i >=0; --i)); do
74
+ eval "local value=\"\${${array_name}[i]}\""
75
+ # shellcheck disable=SC2154
76
+ if [[ $value == "$search_value" ]]; then
77
+ return 0
78
+ fi
79
+ done
80
+ return 1
81
+ }
82
+
83
+ # returns 0 when search-value is found in array
84
+ bats_binary_search() { # <search-value> <array-name>
85
+ if [[ $# -ne 2 ]]; then
86
+ printf "ERROR: bats_binary_search requires exactly 2 arguments: <search value> <array name>\n" >&2
87
+ return 2
88
+ fi
89
+
90
+ local -r search_value=$1 array_name=$2
91
+
92
+ # we'd like to test if array is set but we cannot distinguish unset from empty arrays, so we need to skip that
93
+
94
+ local start=0 mid end mid_value
95
+ # start is inclusive, end is exclusive ...
96
+ eval "end=\${#${array_name}[@]}"
97
+
98
+ # so start == end means empty search space
99
+ while ((start < end)); do
100
+ mid=$(((start + end) / 2))
101
+ eval "mid_value=\${${array_name}[$mid]}"
102
+ if [[ "$mid_value" == "$search_value" ]]; then
103
+ return 0
104
+ elif [[ "$mid_value" < "$search_value" ]]; then
105
+ # This branch excludes equality -> +1 to skip the mid element.
106
+ # This +1 also avoids endless recursion on odd sized search ranges.
107
+ start=$((mid + 1))
108
+ else
109
+ end=$mid
110
+ fi
111
+ done
112
+
113
+ # did not find it -> its not there
114
+ return 1
115
+ }
116
+
117
+ # store the values in ascending (string!) order in result array
118
+ # Intended for short lists! (uses insertion sort)
119
+ bats_sort() { # <result-array-name> <values to sort...>
120
+ local -r result_name=$1
121
+ shift
122
+
123
+ if (($# == 1)) && [[ $1 == "" ]]; then
124
+ shift # remove leading "" to deal with bash 3 expanding "${empty_array[@]}" to one ""
125
+ fi
126
+
127
+ if (($# == 0)); then
128
+ eval "$result_name=()"
129
+ return 0
130
+ fi
131
+
132
+ local -a sorted_array=()
133
+ local -i i
134
+ while (( $# > 0 )); do # loop over input values
135
+ local current_value="$1"
136
+ shift
137
+ for ((i = ${#sorted_array[@]}; i >= 0; --i)); do # loop over output array from end
138
+ if (( i == 0 )) || [[ ${sorted_array[i - 1]} < $current_value ]]; then
139
+ # insert new element at (freed) desired location
140
+ sorted_array[i]=$current_value
141
+ break
142
+ else
143
+ # shift bigger elements one position to the end
144
+ sorted_array[i]=${sorted_array[i - 1]}
145
+ fi
146
+ done
147
+ done
148
+
149
+ eval "$result_name=(\"\${sorted_array[@]}\")"
150
+ }
151
+
152
+ # check if all search values (must be sorted!) are in the (sorted!) array
153
+ # Intended for short lists/arrays!
154
+ bats_all_in() { # <sorted-array> <sorted search values...>
155
+ local -r haystack_array=$1
156
+ shift
157
+
158
+ local -i haystack_length # just to appease shellcheck
159
+ eval "local -r haystack_length=\${#${haystack_array}[@]}"
160
+
161
+ local -i haystack_index=0 # initialize only here to continue from last search position
162
+ local search_value haystack_value # just to appease shellcheck
163
+ local -i i
164
+ for ((i = 1; i <= $#; ++i)); do
165
+ eval "local search_value=${!i}"
166
+ for (( ; haystack_index < haystack_length; ++haystack_index)); do
167
+ eval "local haystack_value=\${${haystack_array}[$haystack_index]}"
168
+ if [[ $haystack_value > "$search_value" ]]; then
169
+ # we passed the location this value would have been at -> not found
170
+ return 1
171
+ elif [[ $haystack_value == "$search_value" ]]; then
172
+ continue 2 # search value found -> try the next one
173
+ fi
174
+ done
175
+ return 1 # we ran of the end of the haystack without finding the value!
176
+ done
177
+
178
+ # did not return from loop above -> all search values were found
179
+ return 0
180
+ }
181
+
182
+ # check if any search value (must be sorted!) is in the (sorted!) array
183
+ # intended for short lists/arrays
184
+ bats_any_in() { # <sorted-array> <sorted search values>
185
+ local -r haystack_array=$1
186
+ shift
187
+
188
+ local -i haystack_length # just to appease shellcheck
189
+ eval "local -r haystack_length=\${#${haystack_array}[@]}"
190
+
191
+ local -i haystack_index=0 # initialize only here to continue from last search position
192
+ local search_value haystack_value # just to appease shellcheck
193
+ local -i i
194
+ for ((i = 1; i <= $#; ++i)); do
195
+ eval "local search_value=${!i}"
196
+ for (( ; haystack_index < haystack_length; ++haystack_index)); do
197
+ eval "local haystack_value=\${${haystack_array}[$haystack_index]}"
198
+ if [[ $haystack_value > "$search_value" ]]; then
199
+ continue 2 # search value not in array! -> try next
200
+ elif [[ $haystack_value == "$search_value" ]]; then
201
+ return 0 # search value found
202
+ fi
203
+ done
204
+ done
205
+
206
+ # did not return from loop above -> no search value was found
207
+ return 1
208
+ }
209
+
210
+ bats_trim() { # <output-variable> <string>
211
+ local -r bats_trim_ltrimmed=${2#"${2%%[![:space:]]*}"} # cut off leading whitespace
212
+ # shellcheck disable=SC2034 # used in eval!
213
+ local -r bats_trim_trimmed=${bats_trim_ltrimmed%"${bats_trim_ltrimmed##*[![:space:]]}"} # cut off trailing whitespace
214
+ eval "$1=\$bats_trim_trimmed"
215
+ }
216
+
217
+ # a helper function to work around unbound variable errors with ${arr[@]} on Bash 3
218
+ bats_append_arrays_as_args() { # <array...> -- <command ...>
219
+ local -a trailing_args=()
220
+ while (($# > 0)) && [[ $1 != -- ]]; do
221
+ local array=$1
222
+ shift
223
+
224
+ if eval "(( \${#${array}[@]} > 0 ))"; then
225
+ eval "trailing_args+=(\"\${${array}[@]}\")"
226
+ fi
227
+ done
228
+ shift # remove -- separator
229
+
230
+ if (($# == 0)); then
231
+ printf "Error: append_arrays_as_args is missing a command or -- separator\n" >&2
232
+ return 1
233
+ fi
234
+
235
+ if ((${#trailing_args[@]} > 0)); then
236
+ "$@" "${trailing_args[@]}"
237
+ else
238
+ "$@"
239
+ fi
240
+ }
241
+
242
+ bats_format_file_line_reference() { # <output> <file> <line>
243
+ # shellcheck disable=SC2034 # will be used in subimplementation
244
+ local output="${1?}"
245
+ shift
246
+ "bats_format_file_line_reference_${BATS_LINE_REFERENCE_FORMAT?}" "$@"
247
+ }
248
+
249
+ bats_format_file_line_reference_comma_line() {
250
+ printf -v "$output" "%s, line %d" "$@"
251
+ }
252
+
253
+ bats_format_file_line_reference_colon() {
254
+ printf -v "$output" "%s:%d" "$@"
255
+ }
256
+
257
+ # approximate realpath without subshell
258
+ bats_approx_realpath() { # <output-variable> <path>
259
+ local output=$1 path=$2
260
+ if [[ $path != /* ]]; then
261
+ path="$PWD/$path"
262
+ fi
263
+ # x/./y -> x/y
264
+ path=${path//\/.\//\/}
265
+ printf -v "$output" "%s" "$path"
266
+ }
267
+
268
+ bats_format_file_line_reference_uri() {
269
+ local filename=${1?} line=${2?}
270
+ bats_approx_realpath filename "$filename"
271
+ printf -v "$output" "file://%s:%d" "$filename" "$line"
272
+ }
273
+
274
+ # execute command with backed up path
275
+ # to prevent path mocks from interfering with our internals
276
+ bats_execute() { # <command...>
277
+ PATH="${BATS_SAVED_PATH?}" "$@"
278
+ }