1
0
mirror of https://github.com/sstephenson/bats.git synced 2025-03-03 23:39:48 +01:00

Merge pull request #8 from bats-core/mbland-optimized

Fix macOS/Bash 3.2 breakage; eliminate subshells from exec-test, preprocess
This commit is contained in:
Mike Bland 2017-09-30 15:46:12 -04:00 committed by GitHub
commit 8538868563
9 changed files with 156 additions and 87 deletions

View File

@ -26,35 +26,58 @@ help() {
echo echo
} }
BATS_READLINK=
resolve_link() { resolve_link() {
$(type -p greadlink readlink | head -1) "$1" if [[ -z "$BATS_READLINK" ]]; then
if command -v 'greadlink' >/dev/null; then
BATS_READLINK='greadlink'
elif command -v 'readlink' >/dev/null; then
BATS_READLINK='readlink'
else
BATS_READLINK='true'
fi
fi
"$BATS_READLINK" "$1" || return 0
} }
abs_dirname() { abs_dirname() {
local cwd="$(pwd)" local cwd="$PWD"
local path="$1" local path="$1"
while [ -n "$path" ]; do while [ -n "$path" ]; do
cd "${path%/*}" cd "${path%/*}"
local name="${path##*/}" local name="${path##*/}"
path="$(resolve_link "$name" || true)" path="$(resolve_link "$name")"
done done
pwd printf -v "$2" -- '%s' "$PWD"
cd "$cwd" cd "$cwd"
} }
expand_path() { expand_path() {
{ cd "$(dirname "$1")" 2>/dev/null local path="${1%/}"
local dirname="$PWD" local dirname="${path%/*}"
if [[ "$dirname" == "$path" ]]; then
dirname="$PWD"
elif cd "$dirname" 2>/dev/null; then
dirname="$PWD"
cd "$OLDPWD" cd "$OLDPWD"
echo "$dirname/$(basename "$1")" else
} || echo "$1" printf '%s' "$path"
return
fi
printf -v "$2" '%s/%s' "$dirname" "${path##*/}"
} }
BATS_LIBEXEC="$(abs_dirname "$0")" abs_dirname "$0" 'BATS_LIBEXEC'
export BATS_PREFIX="$(abs_dirname "$BATS_LIBEXEC")" abs_dirname "$BATS_LIBEXEC" 'BATS_PREFIX'
export BATS_CWD="$(abs_dirname .)" abs_dirname '.' 'BATS_CWD'
export BATS_PREFIX
export BATS_CWD
export BATS_TEST_PATTERN='^ *@test +(.+) +\{ *(.*)$'
export PATH="$BATS_LIBEXEC:$PATH" export PATH="$BATS_LIBEXEC:$PATH"
options=() options=()
@ -113,14 +136,16 @@ fi
filenames=() filenames=()
for filename in "${arguments[@]}"; do for filename in "${arguments[@]}"; do
expand_path "$filename" 'filename'
if [ -d "$filename" ]; then if [ -d "$filename" ]; then
shopt -s nullglob shopt -s nullglob
for suite_filename in "$(expand_path "$filename")"/*.bats; do for suite_filename in "$filename"/*.bats; do
filenames["${#filenames[@]}"]="$suite_filename" filenames["${#filenames[@]}"]="$suite_filename"
done done
shopt -u nullglob shopt -u nullglob
else else
filenames["${#filenames[@]}"]="$(expand_path "$filename")" filenames["${#filenames[@]}"]="$filename"
fi fi
done done
@ -130,13 +155,11 @@ else
command="bats-exec-suite" command="bats-exec-suite"
fi fi
if [ -n "$pretty" ]; then set -o pipefail execfail
if [ -z "$pretty" ]; then
exec "$command" $count_flag "${filenames[@]}"
else
extended_syntax_flag="-x" extended_syntax_flag="-x"
formatter="bats-format-tap-stream" formatter="bats-format-tap-stream"
else exec "$command" $count_flag $extended_syntax_flag "${filenames[@]}" | "$formatter"
extended_syntax_flag=""
formatter="cat"
fi fi
set -o pipefail execfail
exec "$command" $count_flag $extended_syntax_flag "${filenames[@]}" | "$formatter"

View File

@ -17,7 +17,11 @@ trap "kill 0; exit 1" int
count=0 count=0
for filename in "$@"; do for filename in "$@"; do
let count+="$(bats-exec-test -c "$filename")" while IFS= read -r line; do
if [[ "$line" =~ $BATS_TEST_PATTERN ]]; then
let count+=1
fi
done <"$filename"
done done
if [ -n "$count_only_flag" ]; then if [ -n "$count_only_flag" ]; then

View File

@ -26,7 +26,7 @@ else
shift shift
fi fi
BATS_TEST_DIRNAME="$(dirname "$BATS_TEST_FILENAME")" BATS_TEST_DIRNAME="${BATS_TEST_FILENAME%/*}"
BATS_TEST_NAMES=() BATS_TEST_NAMES=()
load() { load() {
@ -39,10 +39,10 @@ load() {
filename="$BATS_TEST_DIRNAME/${name}.bash" filename="$BATS_TEST_DIRNAME/${name}.bash"
fi fi
[ -f "$filename" ] || { if [[ ! -f "$filename" ]]; then
echo "bats: $filename does not exist" >&2 echo "bats: $filename does not exist" >&2
exit 1 exit 1
} fi
source "${filename}" source "${filename}"
} }
@ -101,31 +101,33 @@ bats_capture_stack_trace() {
local teardown_pattern=" teardown $BATS_TEST_SOURCE" local teardown_pattern=" teardown $BATS_TEST_SOURCE"
local frame local frame
local index=1 local i
while frame="$(caller "$index")"; do for ((i=2; i != ${#FUNCNAME[@]}; ++i)); do
frame="${BASH_LINENO[$((i-1))]} ${FUNCNAME[$i]} ${BASH_SOURCE[$i]}"
BATS_CURRENT_STACK_TRACE["${#BATS_CURRENT_STACK_TRACE[@]}"]="$frame" BATS_CURRENT_STACK_TRACE["${#BATS_CURRENT_STACK_TRACE[@]}"]="$frame"
if [[ "$frame" = *"$test_pattern" || \ if [[ "$frame" = *"$test_pattern" || \
"$frame" = *"$setup_pattern" || \ "$frame" = *"$setup_pattern" || \
"$frame" = *"$teardown_pattern" ]]; then "$frame" = *"$teardown_pattern" ]]; then
break break
else
let index+=1
fi fi
done done
BATS_SOURCE="$(bats_frame_filename "${BATS_CURRENT_STACK_TRACE[0]}")" bats_frame_filename "${BATS_CURRENT_STACK_TRACE[0]}" 'BATS_SOURCE'
BATS_LINENO="$(bats_frame_lineno "${BATS_CURRENT_STACK_TRACE[0]}")" bats_frame_lineno "${BATS_CURRENT_STACK_TRACE[0]}" 'BATS_LINENO'
} }
bats_print_stack_trace() { bats_print_stack_trace() {
local frame local frame
local index=1 local index=1
local count="${#@}" local count="${#@}"
local filename
local lineno
for frame in "$@"; do for frame in "$@"; do
local filename="$(bats_trim_filename "$(bats_frame_filename "$frame")")" bats_frame_filename "$frame" 'filename'
local lineno="$(bats_frame_lineno "$frame")" bats_trim_filename "$filename" 'filename'
bats_frame_lineno "$frame" 'lineno'
if [ $index -eq 1 ]; then if [ $index -eq 1 ]; then
echo -n "# (" echo -n "# ("
@ -133,7 +135,8 @@ bats_print_stack_trace() {
echo -n "# " echo -n "# "
fi fi
local fn="$(bats_frame_function "$frame")" local fn
bats_frame_function "$frame" 'fn'
if [ "$fn" != "$BATS_TEST_NAME" ]; then if [ "$fn" != "$BATS_TEST_NAME" ]; then
echo -n "from function \`$fn' " echo -n "from function \`$fn' "
fi fi
@ -151,12 +154,16 @@ bats_print_stack_trace() {
bats_print_failed_command() { bats_print_failed_command() {
local frame="$1" local frame="$1"
local status="$2" local status="$2"
local filename="$(bats_frame_filename "$frame")" local filename
local lineno="$(bats_frame_lineno "$frame")" local lineno
local failed_line
local failed_command
local failed_line="$(bats_extract_line "$filename" "$lineno")" bats_frame_filename "$frame" 'filename'
local failed_command="$(bats_strip_string "$failed_line")" bats_frame_lineno "$frame" 'lineno'
echo -n "# \`${failed_command}' " bats_extract_line "$filename" "$lineno" 'failed_line'
bats_strip_string "$failed_line" 'failed_command'
printf '%s' "# \`${failed_command}' "
if [ $status -eq 1 ]; then if [ $status -eq 1 ]; then
echo "failed" echo "failed"
@ -166,49 +173,46 @@ bats_print_failed_command() {
} }
bats_frame_lineno() { bats_frame_lineno() {
local frame="$1" printf -v "$2" '%s' "${1%% *}"
local lineno="${frame%% *}"
echo "$lineno"
} }
bats_frame_function() { bats_frame_function() {
local frame="$1" local __bff_function="${1#* }"
local rest="${frame#* }" printf -v "$2" '%s' "${__bff_function%% *}"
local fn="${rest%% *}"
echo "$fn"
} }
bats_frame_filename() { bats_frame_filename() {
local frame="$1" local __bff_filename="${1#* }"
local rest="${frame#* }" __bff_filename="${__bff_filename#* }"
local filename="${rest#* }"
if [ "$filename" = "$BATS_TEST_SOURCE" ]; then if [ "$__bff_filename" = "$BATS_TEST_SOURCE" ]; then
echo "$BATS_TEST_FILENAME" __bff_filename="$BATS_TEST_FILENAME"
else
echo "$filename"
fi fi
printf -v "$2" '%s' "$__bff_filename"
} }
bats_extract_line() { bats_extract_line() {
local filename="$1" local __bats_extract_line_line
local lineno="$2" local __bats_extract_line_index='0'
sed -n "${lineno}p" "$filename"
while IFS= read -r __bats_extract_line_line; do
if [[ "$((++__bats_extract_line_index))" -eq "$2" ]]; then
printf -v "$3" '%s' "${__bats_extract_line_line%$'\r'}"
break
fi
done <"$1"
} }
bats_strip_string() { bats_strip_string() {
local string="$1" [[ "$1" =~ ^[[:space:]]*(.*)[[:space:]]*$ ]]
printf "%s" "$string" | sed -e "s/^[ "$'\t'"]*//" -e "s/[ "$'\t'"]*$//" printf -v "$2" '%s' "${BASH_REMATCH[1]}"
} }
bats_trim_filename() { bats_trim_filename() {
local filename="$1" if [[ "$1" =~ ^${BATS_CWD}/ ]]; then
local length="${#BATS_CWD}" printf -v "$2" '%s' "${1#$BATS_CWD/}"
if [ "${filename:0:length+1}" = "${BATS_CWD}/" ]; then
echo "${filename:length+1}"
else else
echo "$filename" printf -v "$2" '%s' "$1"
fi fi
} }
@ -289,7 +293,7 @@ bats_perform_tests() {
bats_perform_test() { bats_perform_test() {
BATS_TEST_NAME="$1" BATS_TEST_NAME="$1"
if [ "$(type -t "$BATS_TEST_NAME" || true)" = "function" ]; then if declare -F "$BATS_TEST_NAME" >/dev/null; then
BATS_TEST_NUMBER="$2" BATS_TEST_NUMBER="$2"
if [ -z "$BATS_TEST_NUMBER" ]; then if [ -z "$BATS_TEST_NUMBER" ]; then
echo "1..1" echo "1..1"
@ -322,7 +326,7 @@ BATS_OUT="${BATS_TMPNAME}.out"
bats_preprocess_source() { bats_preprocess_source() {
BATS_TEST_SOURCE="${BATS_TMPNAME}.src" BATS_TEST_SOURCE="${BATS_TMPNAME}.src"
{ tr -d '\r' < "$BATS_TEST_FILENAME"; echo; } | bats-preprocess > "$BATS_TEST_SOURCE" . bats-preprocess <<< "$(< "$BATS_TEST_FILENAME")"$'\n' > "$BATS_TEST_SOURCE"
trap "bats_cleanup_preprocessed_source" err exit trap "bats_cleanup_preprocessed_source" err exit
trap "bats_cleanup_preprocessed_source; exit 1" int trap "bats_cleanup_preprocessed_source; exit 1" int
} }

View File

@ -65,9 +65,15 @@ log() {
} }
summary() { summary() {
printf "\n%d test%s" "$count" "$(plural "$count")" printf "\n%d test" "$count"
if [[ "$count" -ne '1' ]]; then
printf 's'
fi
printf ", %d failure%s" "$failures" "$(plural "$failures")" printf ", %d failure" "$failures"
if [[ "$failures" -ne '1' ]]; then
printf 's'
fi
if [ "$skipped" -gt 0 ]; then if [ "$skipped" -gt 0 ]; then
printf ", %d skipped" "$skipped" printf ", %d skipped" "$skipped"
@ -79,7 +85,9 @@ summary() {
printf_with_truncation() { printf_with_truncation() {
local width="$1" local width="$1"
shift shift
local string="$(printf "$@")" local string
printf -v 'string' -- "$@"
if [ "${#string}" -gt "$width" ]; then if [ "${#string}" -gt "$width" ]; then
printf "%s..." "${string:0:$(( $width - 4 ))}" printf "%s..." "${string:0:$(( $width - 4 ))}"
@ -105,18 +113,18 @@ advance() {
set_color() { set_color() {
local color="$1" local color="$1"
local weight="$2" local weight='22'
printf "\x1B[%d;%dm" $(( 30 + $color )) "$( [ "$weight" = "bold" ] && echo 1 || echo 22 )"
if [[ "$2" == 'bold' ]]; then
weight='1'
fi
printf "\x1B[%d;%dm" $(( 30 + $color )) "$weight"
} }
clear_color() { clear_color() {
printf "\x1B[0m" printf "\x1B[0m"
} }
plural() {
[ "$1" -eq 1 ] || echo "s"
}
_buffer="" _buffer=""
buffer() { buffer() {

View File

@ -4,6 +4,7 @@ set -e
encode_name() { encode_name() {
local name="$1" local name="$1"
local result="test_" local result="test_"
local hex_code
if [[ ! "$name" =~ [^[:alnum:]\ _-] ]]; then if [[ ! "$name" =~ [^[:alnum:]\ _-] ]]; then
name="${name//_/-5f}" name="${name//_/-5f}"
@ -21,27 +22,28 @@ encode_name() {
elif [[ "$char" =~ [[:alnum:]] ]]; then elif [[ "$char" =~ [[:alnum:]] ]]; then
result+="$char" result+="$char"
else else
result+="$(printf -- "-%02x" \'"$char")" printf -v 'hex_code' -- "-%02x" \'"$char"
result+="$hex_code"
fi fi
done done
fi fi
echo "$result" printf -v "$2" '%s' "$result"
} }
tests=() tests=()
index=0 index=0
pattern='^ *@test *([^ ].*) *\{ *(.*)$'
while IFS= read -r line; do while IFS= read -r line; do
line="${line//$'\r'}"
let index+=1 let index+=1
if [[ "$line" =~ $pattern ]]; then if [[ "$line" =~ $BATS_TEST_PATTERN ]]; then
quoted_name="${BASH_REMATCH[1]}" name="${BASH_REMATCH[1]#[\'\"]}"
name="${name%[\'\"]}"
body="${BASH_REMATCH[2]}" body="${BASH_REMATCH[2]}"
name="$(eval echo "$quoted_name")" encode_name "$name" 'encoded_name'
encoded_name="$(encode_name "$name")"
tests["${#tests[@]}"]="$encoded_name" tests["${#tests[@]}"]="$encoded_name"
echo "${encoded_name}() { bats_test_begin ${quoted_name} ${index}; ${body}" echo "${encoded_name}() { bats_test_begin \"${name}\" ${index}; ${body}"
else else
printf "%s\n" "$line" printf "%s\n" "$line"
fi fi

View File

@ -41,25 +41,25 @@ fixtures bats
} }
@test "summary passing tests" { @test "summary passing tests" {
run filter_control_sequences bats -p $FIXTURE_ROOT/passing.bats run filter_control_sequences bats -p "$FIXTURE_ROOT/passing.bats"
[ $status -eq 0 ] [ $status -eq 0 ]
[ "${lines[1]}" = "1 test, 0 failures" ] [ "${lines[1]}" = "1 test, 0 failures" ]
} }
@test "summary passing and skipping tests" { @test "summary passing and skipping tests" {
run filter_control_sequences bats -p $FIXTURE_ROOT/passing_and_skipping.bats run filter_control_sequences bats -p "$FIXTURE_ROOT/passing_and_skipping.bats"
[ $status -eq 0 ] [ $status -eq 0 ]
[ "${lines[2]}" = "2 tests, 0 failures, 1 skipped" ] [ "${lines[2]}" = "2 tests, 0 failures, 1 skipped" ]
} }
@test "summary passing and failing tests" { @test "summary passing and failing tests" {
run filter_control_sequences bats -p $FIXTURE_ROOT/failing_and_passing.bats run filter_control_sequences bats -p "$FIXTURE_ROOT/failing_and_passing.bats"
[ $status -eq 0 ] [ $status -eq 0 ]
[ "${lines[4]}" = "2 tests, 1 failure" ] [ "${lines[4]}" = "2 tests, 1 failure" ]
} }
@test "summary passing, failing and skipping tests" { @test "summary passing, failing and skipping tests" {
run filter_control_sequences bats -p $FIXTURE_ROOT/passing_failing_and_skipping.bats run filter_control_sequences bats -p "$FIXTURE_ROOT/passing_failing_and_skipping.bats"
[ $status -eq 0 ] [ $status -eq 0 ]
[ "${lines[5]}" = "3 tests, 1 failure, 1 skipped" ] [ "${lines[5]}" = "3 tests, 1 failure, 1 skipped" ]
} }
@ -268,3 +268,17 @@ fixtures bats
[ $status -eq 0 ] [ $status -eq 0 ]
[ "${lines[1]}" = "ok 1 loop_func" ] [ "${lines[1]}" = "ok 1 loop_func" ]
} }
@test "expand variables in test name" {
SUITE='test/suite' run bats "$FIXTURE_ROOT/expand_var_in_test_name.bats"
[ $status -eq 0 ]
[ "${lines[1]}" = "ok 1 test/suite: test with variable in name" ]
}
@test "handle quoted and unquoted test names" {
run bats "$FIXTURE_ROOT/quoted_and_unquoted_test_names.bats"
[ $status -eq 0 ]
[ "${lines[1]}" = "ok 1 single-quoted name" ]
[ "${lines[2]}" = "ok 2 double-quoted name" ]
[ "${lines[3]}" = "ok 3 unquoted name" ]
}

View File

@ -0,0 +1,3 @@
@test "$SUITE: test with variable in name" {
true
}

View File

@ -0,0 +1,11 @@
@test 'single-quoted name' {
true
}
@test "double-quoted name" {
true
}
@test unquoted name {
true
}

View File

@ -1,6 +1,6 @@
fixtures() { fixtures() {
FIXTURE_ROOT="$BATS_TEST_DIRNAME/fixtures/$1" FIXTURE_ROOT="$BATS_TEST_DIRNAME/fixtures/$1"
RELATIVE_FIXTURE_ROOT="$(bats_trim_filename "$FIXTURE_ROOT")" bats_trim_filename "$FIXTURE_ROOT" 'RELATIVE_FIXTURE_ROOT'
} }
setup() { setup() {