Skip to content

Commit 0b44890

Browse files
authored
Merge pull request #196 from mbland/run-script-helpers
bats/helpers: Add `run` convenience functions
2 parents 736eb12 + 0c0536a commit 0b44890

2 files changed

Lines changed: 155 additions & 3 deletions

File tree

lib/bats/helpers

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,69 @@ restore_program_in_path() {
428428
restore_bats_shell_options "$result"
429429
}
430430

431+
# Removes multiple stub programs from `PATH` at once
432+
#
433+
# Arguments:
434+
# $@: Names of stub programs to restore
435+
restore_programs_in_path() {
436+
set "$DISABLE_BATS_SHELL_OPTIONS"
437+
local stub
438+
local result='0'
439+
440+
for stub in "$@"; do
441+
if ! restore_program_in_path "$stub"; then
442+
result='1'
443+
fi
444+
done
445+
restore_bats_shell_options "$result"
446+
}
447+
448+
# Creates and runs a test script in one step
449+
#
450+
# Arguments:
451+
# $@: Passed directly through to `create_bats_test_script`
452+
run_test_script() {
453+
create_bats_test_script "$@"
454+
run "$BATS_TEST_ROOTDIR/$1"
455+
}
456+
457+
# Creates and runs a Bats test suite in one step
458+
#
459+
# If the first line of the script isn't an interpreter specification beginning
460+
# with '#!', it will be set to '#! /usr/bin/env bats'.
461+
#
462+
# Arguments:
463+
# suite_name: File name of the test suite
464+
# ...: Lines comprising the test suite
465+
run_bats_test_suite() {
466+
local suite_name="$1"
467+
local script=("${@:2}")
468+
469+
if [[ "${script[0]:0:2}" != '#!' ]]; then
470+
script=('#! /usr/bin/env bats' "${script[@]}")
471+
fi
472+
run_test_script "$suite_name" "${script[@]}"
473+
}
474+
475+
# Creates and runs a Bats test suite with a restricted `PATH` in one step
476+
#
477+
# The suite will run with `PATH` set to `BATS_TEST_BINDIR` plus the Bats
478+
# `libexec` directory. This is useful for testing functions that skip tests
479+
# based on available system programs, using `create_forwarding_script` to make
480+
# only selected programs available in `BATS_TEST_BINDIR`.
481+
#
482+
# `bash` and `rm` are forwarded by this function, so your test cases should not
483+
# call `create_forwarding_script` or `restore_program_in_path` for them.
484+
#
485+
# Arguments:
486+
# $@: Passed directly through to `run_bats_test_suite`
487+
run_bats_test_suite_in_isolation() {
488+
create_forwarding_script --path "$_GO_ROOTDIR/${_GO_BATS_PATH%/*}" 'bash'
489+
create_forwarding_script --path '' 'rm'
490+
run_bats_test_suite "$@"
491+
restore_programs_in_path 'bash' 'rm'
492+
}
493+
431494
# --------------------------------
432495
# IMPLEMENTATION - HERE BE DRAGONS
433496
#

tests/bats-helpers.bats

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,33 @@ __check_dirs_exist() {
307307
assert_failure 'No command name provided.'
308308
}
309309

310+
@test "$SUITE: restore_programs_in_path restores multiple programs at once" {
311+
local orig_paths=($(command -v cp mkdir ls))
312+
stub_program_in_path 'cp'
313+
stub_program_in_path 'mkdir'
314+
stub_program_in_path 'ls'
315+
run command -v 'cp' 'mkdir' 'ls'
316+
assert_success "${BATS_TEST_BINDIR[@]}"/{cp,mkdir,ls}
317+
318+
restore_programs_in_path 'cp' 'mkdir' 'ls'
319+
run command -v 'cp' 'mkdir' 'ls'
320+
assert_success "${orig_paths[@]}"
321+
}
322+
323+
@test "$SUITE: restore_programs_in_path reports an error if no stub exists" {
324+
local orig_paths=($(command -v cp ls))
325+
stub_program_in_path 'cp'
326+
stub_program_in_path 'ls'
327+
run restore_programs_in_path 'cp' 'mkdir' 'ls'
328+
assert_failure "Bats test stub program doesn't exist: mkdir"
329+
330+
# Since we ran `restore_programs_in_path` in a subshell via `run`, the Bash
331+
# executable path hash table in this process needs to be cleared manually.
332+
hash -r
333+
run command -v 'cp' 'ls'
334+
assert_success "${orig_paths[@]}"
335+
}
336+
310337
@test "$SUITE: create_forwarding_script does nothing if program doesn't exist" {
311338
create_forwarding_script 'some-noexistent-program-name'
312339
fail_if matches "^${BATS_TEST_BINDIR}:" "$PATH"
@@ -369,9 +396,7 @@ __check_dirs_exist() {
369396

370397
create_forwarding_scripts 'bash' 'cp' 'rm'
371398
run command -v 'bash' 'cp' 'rm'
372-
restore_program_in_path 'bash'
373-
restore_program_in_path 'cp'
374-
restore_program_in_path 'rm'
399+
restore_programs_in_path 'bash' 'cp' 'rm'
375400
assert_success "$BATS_TEST_BINDIR"/{bash,cp,rm}
376401

377402
run command -v 'bash' 'cp' 'rm'
@@ -391,3 +416,67 @@ __check_dirs_exist() {
391416
restore_program_in_path 'printenv'
392417
assert_success "$BATS_TEST_BINDIR:$path"
393418
}
419+
420+
@test "$SUITE: run_test_script creates and runs a script in one step" {
421+
run_test_script 'one-step' \
422+
'printf "%s\n" "Hello, World!"'
423+
assert_success 'Hello, World!'
424+
}
425+
426+
# Note that we use `[[ ... ]] || return 1` because Bash 3.x otherwise won't
427+
# return properly when a `[[ ... ]]` condition fails. The `[ ... ]` construct
428+
# works for all versions of Bash, but since `[[ ... ]]` is a generally safer and
429+
# more versatile construct, this seemed a good opportunity to demonstrate the
430+
# use of `|| return 1`.
431+
#
432+
# Incidentally, it should be easy to inject `|| return 1` automatically via
433+
# `bats-preprocess`.
434+
@test "$SUITE: run_bats_test_suite creates and runs a passing test suite" {
435+
run_bats_test_suite 'passing' \
436+
'@test "should pass" {' \
437+
' [[ $((2 + 2)) -eq 4 ]] || return 1' \
438+
'}'
439+
assert_success '1..1' 'ok 1 should pass'
440+
}
441+
442+
@test "$SUITE: run_bats_test_suite runs a test suite with skips" {
443+
run_bats_test_suite 'skipping' \
444+
'@test "should skip" {' \
445+
' skip "just because"' \
446+
' [[ $((2 + 2)) -eq 5 ]] || return 1' \
447+
'}'
448+
assert_success '1..1' 'ok 1 # skip (just because) should skip'
449+
}
450+
451+
@test "$SUITE: run_bats_test_suite runs a test suite with failures" {
452+
run_bats_test_suite 'failing' \
453+
'@test "should fail" {' \
454+
' [[ $((2 + 2)) -eq 5 ]] || return 1' \
455+
'}'
456+
assert_failure '1..1' 'not ok 1 should fail' \
457+
"# (in test file $BATS_TEST_ROOTDIR/failing, line 3)" \
458+
"# \`[[ \$((2 + 2)) -eq 5 ]] || return 1' failed"
459+
}
460+
461+
@test "$SUITE: run_bats_test_suite_in_isolation only forwards bash and rm" {
462+
skip_if_system_missing cp rm mkdir
463+
run_bats_test_suite_in_isolation 'skipping' \
464+
". '$_GO_ROOTDIR/lib/bats/helpers'" \
465+
'@test "should skip" {' \
466+
' skip_if_system_missing cp rm mkdir' \
467+
'}'
468+
assert_success '1..1' \
469+
'ok 1 # skip (cp, mkdir not installed on the system) should skip'
470+
}
471+
472+
@test "$SUITE: run_bats_test_suite_in_isolation can access forwarding scripts" {
473+
skip_if_system_missing cp rm mkdir
474+
create_forwarding_scripts 'cp' 'mkdir'
475+
run_bats_test_suite_in_isolation 'not-skipping' \
476+
". '$_GO_ROOTDIR/lib/bats/helpers'" \
477+
'@test "should not skip when commands forwarded" {' \
478+
' skip_if_system_missing cp rm mkdir' \
479+
'}'
480+
restore_programs_in_path 'cp' 'mkdir'
481+
assert_success '1..1' 'ok 1 should not skip when commands forwarded'
482+
}

0 commit comments

Comments
 (0)