Skip to content

Commit 1e2338e

Browse files
authored
Merge pull request #162 from mbland/bats-function
Multiple small test optimizations based on `lib/bats/helper-function`
2 parents 17ff46d + 65484ad commit 1e2338e

22 files changed

+356
-198
lines changed

lib/bats/helper-function

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,15 @@ restore_bats_shell_options() {
5252
local result="${1:-0}"
5353
local target_stack_item_pattern=" ${FUNCNAME[1]} ${BASH_SOURCE[1]}$"
5454

55-
# After removing our caller from BATS_CURRENT_STACK_TRACE and restoring the
56-
# Bats shell options, the `return` call at the end of the function will fire
57-
# `bats_debug_trap`, which sets BATS_CURRENT_STACK_TRACE to
58-
# BATS_PREVIOUS_STACK_TRACE.
59-
#
60-
# If `result` is nonzero, `bats_error_trap` will fire and set
61-
# BATS_ERROR_STACK_TRACE to BATS_PREVIOUS_STACK_TRACE and fail the test.
6255
if [[ "${BATS_CURRENT_STACK_TRACE[0]}" =~ $target_stack_item_pattern ]]; then
56+
# After removing our caller from BATS_CURRENT_STACK_TRACE and restoring the
57+
# Bats shell options, the `return` call at the end of the function will fire
58+
# `bats_debug_trap`, which sets BATS_CURRENT_STACK_TRACE to
59+
# BATS_PREVIOUS_STACK_TRACE.
60+
#
61+
# Then, if `result` is nonzero, `return` will fire `bats_error_trap`, which
62+
# sets BATS_ERROR_STACK_TRACE to BATS_PREVIOUS_STACK_TRACE, and the error
63+
# response will fail the test.
6364
unset 'BATS_CURRENT_STACK_TRACE[0]'
6465
set -eET
6566
fi

lib/bats/helpers

Lines changed: 98 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
# This is good practice even if you call `remove_bats_test_dirs` in your
4242
# `environment.bash` file.
4343

44+
. "${BASH_SOURCE%/*}/helper-function"
45+
4446
# A subdirectory of BATS_TMPDIR that contains a space.
4547
#
4648
# Using this path instead of BATS_TMPDIR directly helps ensure that shell
@@ -61,8 +63,9 @@ BATS_TEST_BINDIR="$BATS_TEST_ROOTDIR/bin"
6163
# Arguments:
6264
# $1: Path to the project's top-level test directory
6365
set_bats_test_suite_name() {
64-
local test_rootdir="$(cd "$1" && echo "$PWD")"
65-
local relative_filename="${BATS_TEST_FILENAME#$test_rootdir/}"
66+
cd "$1"
67+
local relative_filename="${BATS_TEST_FILENAME#$PWD/}"
68+
cd - &>/dev/null
6669
readonly SUITE="${relative_filename%.bats}"
6770
}
6871

@@ -74,18 +77,9 @@ set_bats_test_suite_name() {
7477
# Arguments:
7578
# $@: Paths of subdirectories relative to BATS_TEST_ROOTDIR
7679
create_bats_test_dirs() {
77-
local dirs_to_create=()
78-
local test_dir
79-
80-
for test_dir in "${@/#/$BATS_TEST_ROOTDIR/}"; do
81-
if [[ ! -d "$test_dir" ]]; then
82-
dirs_to_create+=("$test_dir")
83-
fi
84-
done
85-
86-
if [[ "${#dirs_to_create[@]}" -ne '0' ]]; then
87-
mkdir -p "${dirs_to_create[@]}"
88-
fi
80+
set "$DISABLE_BATS_SHELL_OPTIONS"
81+
__create_bats_test_dirs "$@"
82+
restore_bats_shell_options "$?"
8983
}
9084

9185
# Creates a test script relative to BATS_TEST_ROOTDIR
@@ -100,26 +94,9 @@ create_bats_test_dirs() {
10094
# $1: Path of the script relative to BATS_TEST_ROOTDIR
10195
# ...: Lines comprising the script
10296
create_bats_test_script() {
103-
local script="$1"
104-
shift
105-
local script_dir="${script%/*}"
106-
107-
if [[ -z "$script" ]]; then
108-
echo "No test script specified" >&2
109-
exit 1
110-
elif [[ "$script_dir" == "$script" ]]; then
111-
script_dir=''
112-
fi
113-
114-
create_bats_test_dirs "$script_dir"
115-
script="$BATS_TEST_ROOTDIR/$script"
116-
rm -f "$script"
117-
118-
if [[ "${1:0:2}" != '#!' ]]; then
119-
echo "#! /usr/bin/env bash" >"$script"
120-
fi
121-
printf '%s\n' "$@" >>"$script"
122-
chmod 700 "$script"
97+
set "$DISABLE_BATS_SHELL_OPTIONS"
98+
__create_bats_test_script "$@"
99+
restore_bats_shell_options "$?"
123100
}
124101

125102
# Recursively removes `BATS_TEST_ROOTDIR` and its subdirectories
@@ -183,18 +160,15 @@ skip_if_cannot_trigger_file_permission_failure() {
183160
# Arguments:
184161
# ...: System programs that must be present for the test case to proceed
185162
skip_if_system_missing() {
186-
local missing=()
187-
local program
163+
local __missing=()
188164

189-
for program in "$@"; do
190-
if ! command -v "$program" >/dev/null; then
191-
missing+=("$program")
192-
fi
193-
done
165+
set "$DISABLE_BATS_SHELL_OPTIONS"
166+
__search_for_missing_programs "$@"
167+
restore_bats_shell_options "$?"
194168

195-
if [[ "${#missing[@]}" -ne '0' ]]; then
196-
printf -v missing '%s, ' "${missing[@]}"
197-
skip "${missing%, } not installed on the system"
169+
if [[ "${#__missing[@]}" -ne '0' ]]; then
170+
printf -v __missing '%s, ' "${__missing[@]}"
171+
skip "${__missing%, } not installed on the system"
198172
fi
199173
}
200174

@@ -311,12 +285,9 @@ test_filter() {
311285
# compare the exact lines of `output` using `assert_lines_equal` and other
312286
# `lines`-based assertions.
313287
split_bats_output_into_lines() {
314-
local line
315-
lines=()
316-
317-
while IFS= read -r line; do
318-
lines+=("${line%$'\r'}")
319-
done <<<"$output"
288+
set "$DISABLE_BATS_SHELL_OPTIONS"
289+
__split_bats_output_into_lines
290+
restore_bats_shell_options "$?"
320291
}
321292

322293
# Creates a stub program in PATH for testing purposes
@@ -335,3 +306,80 @@ stub_program_in_path() {
335306
fi
336307
create_bats_test_script "${BATS_TEST_BINDIR#$BATS_TEST_ROOTDIR/}/$1" "${@:2}"
337308
}
309+
310+
# --------------------------------
311+
# IMPLEMENTATION - HERE BE DRAGONS
312+
#
313+
# None of the functions below this line are part of the public interface.
314+
# --------------------------------
315+
316+
# Implementation for `create_bats_test_dirs`
317+
#
318+
# Arguments:
319+
# $@: Paths of subdirectories relative to BATS_TEST_ROOTDIR
320+
__create_bats_test_dirs() {
321+
local dirs_to_create=()
322+
local test_dir
323+
324+
for test_dir in "${@/#/$BATS_TEST_ROOTDIR/}"; do
325+
if [[ ! -d "$test_dir" ]]; then
326+
dirs_to_create+=("$test_dir")
327+
fi
328+
done
329+
330+
if [[ "${#dirs_to_create[@]}" -ne '0' ]]; then
331+
mkdir -p "${dirs_to_create[@]}"
332+
fi
333+
}
334+
335+
# Implementation for `create_bats_test_script`
336+
#
337+
# Arguments:
338+
# $1: Path of the script relative to BATS_TEST_ROOTDIR
339+
# ...: Lines comprising the script
340+
__create_bats_test_script() {
341+
local script="$1"
342+
shift
343+
local script_dir="${script%/*}"
344+
345+
if [[ -z "$script" ]]; then
346+
echo "No test script specified" >&2
347+
exit 1
348+
elif [[ "$script_dir" == "$script" ]]; then
349+
script_dir=''
350+
fi
351+
352+
create_bats_test_dirs "$script_dir"
353+
script="$BATS_TEST_ROOTDIR/$script"
354+
rm -f "$script"
355+
356+
if [[ "${1:0:2}" != '#!' ]]; then
357+
echo "#! /usr/bin/env bash" >"$script"
358+
fi
359+
printf '%s\n' "$@" >>"$script"
360+
chmod 700 "$script"
361+
}
362+
363+
# Enumerates programs not installed on the system for `skip_if_system_missing`
364+
#
365+
# Arguments:
366+
# ...: System programs that must be present for the test case to proceed
367+
__search_for_missing_programs() {
368+
local program
369+
370+
for program in "$@"; do
371+
if ! command -v "$program" >/dev/null; then
372+
__missing+=("$program")
373+
fi
374+
done
375+
}
376+
377+
# Implementation for `split_bats_output_into_lines`
378+
__split_bats_output_into_lines() {
379+
local line
380+
lines=()
381+
382+
while IFS= read -r line; do
383+
lines+=("${line%$'\r'}")
384+
done <<<"$output"
385+
}

lib/testing/environment

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,7 @@ test-go() {
106106
# ...: Names of "child" command scripts
107107
@go.create_parent_and_subcommands() {
108108
set "$DISABLE_BATS_SHELL_OPTIONS"
109-
local parent="$1"
110-
shift
111-
local subcommand
112-
113-
@go.create_test_command_script "$parent"
114-
115-
for subcommand in "$@"; do
116-
@go.create_test_command_script "$parent.d/$subcommand"
117-
done
109+
__@go.create_parent_and_subcommands "$@"
118110
restore_bats_shell_options "$?"
119111
}
120112

@@ -132,3 +124,26 @@ test-go() {
132124
@go.split $'\n' "$(@go.compgen "${@:2}")" "$1"
133125
restore_bats_shell_options "$?"
134126
}
127+
128+
# --------------------------------
129+
# IMPLEMENTATION - HERE BE DRAGONS
130+
#
131+
# None of the functions below this line are part of the public interface.
132+
# --------------------------------
133+
134+
# Implementation for `@go.create_parent_and_subcommands`
135+
#
136+
# Arguments:
137+
# parent_name: Name of the "parent" command script
138+
# ...: Names of "child" command scripts
139+
__@go.create_parent_and_subcommands() {
140+
local parent="$1"
141+
shift
142+
local subcommand
143+
144+
@go.create_test_command_script "$parent"
145+
146+
for subcommand in "$@"; do
147+
@go.create_test_command_script "$parent.d/$subcommand"
148+
done
149+
}

lib/testing/stubbing

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
# You must import `_GO_CORE_DIR/lib/testing/environment` before importing this
1212
# script, and make sure to call `@go.remove_test_go_rootdir` from `teardown`.
1313

14+
. "$_GO_CORE_DIR/lib/bats/helper-function"
15+
1416
export _GO_INJECT_SEARCH_PATH="$TEST_GO_ROOTDIR/test-bin"
1517
export _GO_INJECT_MODULE_PATH="$TEST_GO_ROOTDIR/test-lib"
1618

@@ -20,8 +22,10 @@ export _GO_INJECT_MODULE_PATH="$TEST_GO_ROOTDIR/test-lib"
2022
# module_name: Name of the command script to stub
2123
# ...: Lines comprising the stubbed command script implementation
2224
@go.create_command_script_test_stub() {
25+
set "$DISABLE_BATS_SHELL_OPTIONS"
2326
local script_path="$_GO_INJECT_SEARCH_PATH/$1"
2427
create_bats_test_script "${script_path#$BATS_TEST_ROOTDIR/}" "${@:2}"
28+
restore_bats_shell_options "$?"
2529
}
2630

2731
# Creates a stub module implementation in `_GO_INJECT_MODULE_PATH`
@@ -30,7 +34,9 @@ export _GO_INJECT_MODULE_PATH="$TEST_GO_ROOTDIR/test-lib"
3034
# module_name: Name of the module to stub
3135
# ...: Lines comprising the stubbed module implementation
3236
@go.create_module_test_stub() {
37+
set "$DISABLE_BATS_SHELL_OPTIONS"
3338
local module_path="$_GO_INJECT_MODULE_PATH/$1"
3439
create_bats_test_script "${module_path#$BATS_TEST_ROOTDIR/}" "${@:2}"
3540
chmod 600 "$module_path"
41+
restore_bats_shell_options "$?"
3642
}

tests/assertion-test-helpers.bats

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ emit_debug_info() {
2424
}
2525

2626
run_assertion_test() {
27+
set "$DISABLE_BATS_SHELL_OPTIONS"
28+
setup_assertion_test "$@"
29+
restore_bats_shell_options
30+
run "$BATS_TEST_ROOTDIR/$EXPECT_ASSERTION_TEST_SCRIPT"
31+
}
32+
33+
setup_assertion_test() {
2734
local expected_output=("${@:2}")
2835
local expected_output_line
2936

@@ -43,11 +50,15 @@ run_assertion_test() {
4350
"@test \"$BATS_TEST_DESCRIPTION\" {" \
4451
" $ASSERTION" \
4552
'}'
46-
run "$BATS_TEST_ROOTDIR/$EXPECT_ASSERTION_TEST_SCRIPT"
4753
}
4854

4955
check_failure_output() {
50-
set +eET
56+
set "$DISABLE_BATS_SHELL_OPTIONS"
57+
__check_failure_output "$@"
58+
restore_bats_shell_options "$?"
59+
}
60+
61+
__check_failure_output() {
5162
local test_script="$BATS_TEST_ROOTDIR/$EXPECT_ASSERTION_TEST_SCRIPT"
5263
local assertion_line="${ASSERTION%%$'\n'*}"
5364
local expected_output
@@ -69,7 +80,6 @@ check_failure_output() {
6980
result='1'
7081
fi
7182
unset 'BATS_CURRENT_STACK_TRACE[0]' 'BATS_PREVIOUS_STACK_TRACE[0]'
72-
set -eET
7383
return "$result"
7484
}
7585

0 commit comments

Comments
 (0)