#!/usr/bin/env bash set -e set -E set -T setglobal BATS_COUNT_ONLY = ''"" if test $1 = "-c" { setglobal BATS_COUNT_ONLY = '1' shift } setglobal BATS_EXTENDED_SYNTAX = ''"" if test $1 = "-x" { setglobal BATS_EXTENDED_SYNTAX = $1 shift } setglobal BATS_TEST_FILENAME = $1 if test -z $BATS_TEST_FILENAME { echo "usage: bats-exec " > !2 exit 1 } elif test ! -f $BATS_TEST_FILENAME { echo "bats: $BATS_TEST_FILENAME does not exist" > !2 exit 1 } else { shift } setglobal BATS_TEST_DIRNAME = $[dirname $BATS_TEST_FILENAME] setglobal BATS_TEST_NAMES = ''() proc load { local name="$1" local filename if test $(name:0:1) = "/" { setglobal filename = $(name) } else { setglobal filename = ""$BATS_TEST_DIRNAME/$(name).bash"" } test -f $filename || do { echo "bats: $filename does not exist" > !2 exit 1 } source $(filename) } proc run { local e E T oldIFS [[ ! "$-" =~ e ]] || setglobal e = '1' [[ ! "$-" =~ E ]] || setglobal E = '1' [[ ! "$-" =~ T ]] || setglobal T = '1' set +e set +E set +T setglobal output = $[@Argv !2 > !1] setglobal status = "$Status" setglobal oldIFS = $IFS setglobal IFS = '$'\n',' lines = ''($output) test -z $e || set -e test -z $E || set -E test -z $T || set -T setglobal IFS = $oldIFS } proc setup { true } proc teardown { true } proc skip { setglobal BATS_TEST_SKIPPED = $(1:-1) setglobal BATS_TEST_COMPLETED = '1' exit 0 } proc bats_test_begin { setglobal BATS_TEST_DESCRIPTION = $1 if test -n $BATS_EXTENDED_SYNTAX { echo "begin $BATS_TEST_NUMBER $BATS_TEST_DESCRIPTION" > !3 } setup } proc bats_test_function { local test_name="$1" compat array-assign BATS_TEST_NAMES '"${#BATS_TEST_NAMES[@]}"' $test_name } proc bats_capture_stack_trace { setglobal BATS_PREVIOUS_STACK_TRACE = ''( "${BATS_CURRENT_STACK_TRACE[@]}" ) setglobal BATS_CURRENT_STACK_TRACE = ''() local test_pattern=" $BATS_TEST_NAME $BATS_TEST_SOURCE" local setup_pattern=" setup $BATS_TEST_SOURCE" local teardown_pattern=" teardown $BATS_TEST_SOURCE" local frame local index=1 while setglobal frame = $[caller $index] { compat array-assign BATS_CURRENT_STACK_TRACE '"${#BATS_CURRENT_STACK_TRACE[@]}"' $frame if [[ "$frame" = *"$test_pattern" || \ "$frame" = *"$setup_pattern" || \ "$frame" = *"$teardown_pattern" ]] { break } else { let index+=1 } } setglobal BATS_SOURCE = $[bats_frame_filename $(BATS_CURRENT_STACK_TRACE[0])] setglobal BATS_LINENO = $[bats_frame_lineno $(BATS_CURRENT_STACK_TRACE[0])] } proc bats_print_stack_trace { local frame local index=1 local count="$(#@)" for frame in [@Argv] { local filename="$[bats_trim_filename $[bats_frame_filename $frame]]" local lineno="$[bats_frame_lineno $frame]" if test $index -eq 1 { echo -n "# (" } else { echo -n "# " } local fn="$[bats_frame_function $frame]" if test $fn != $BATS_TEST_NAME { echo -n "from function \`$fn' " } if test $index -eq $count { echo "in test file $filename, line $lineno)" } else { echo "in file $filename, line $lineno," } let index+=1 } } proc bats_print_failed_command { local frame="$1" local status="$2" local filename="$[bats_frame_filename $frame]" local lineno="$[bats_frame_lineno $frame]" local failed_line="$[bats_extract_line $filename $lineno]" local failed_command="$[bats_strip_string $failed_line]" echo -n "# \`$(failed_command)' " if test $status -eq 1 { echo "failed" } else { echo "failed with status $status" } } proc bats_frame_lineno { local frame="$1" local lineno="$(frame%% *)" echo $lineno } proc bats_frame_function { local frame="$1" local rest="$(frame#* )" local fn="$(rest%% *)" echo $fn } proc bats_frame_filename { local frame="$1" local rest="$(frame#* )" local filename="$(rest#* )" if test $filename = $BATS_TEST_SOURCE { echo $BATS_TEST_FILENAME } else { echo $filename } } proc bats_extract_line { local filename="$1" local lineno="$2" sed -n "$(lineno)p" $filename } proc bats_strip_string { local string="$1" printf "%s" $string | sed -e "s/^[ "$'\t'"]*//" -e "s/[ "$'\t'"]*$//" } proc bats_trim_filename { local filename="$1" local length="$(#BATS_CWD)" if test $(filename:0:length+1) = "$(BATS_CWD)/" { echo $(filename:length+1) } else { echo $filename } } proc bats_debug_trap { if test $BASH_SOURCE != $1 { bats_capture_stack_trace } } proc bats_error_trap { setglobal BATS_ERROR_STATUS = "$Status" setglobal BATS_ERROR_STACK_TRACE = ''( "${BATS_PREVIOUS_STACK_TRACE[@]}" ) trap - debug } proc bats_teardown_trap { trap "bats_exit_trap" exit local status=0 teardown >>$BATS_OUT !2 > !1 || setglobal status = "$Status" if test $status -eq 0 { setglobal BATS_TEARDOWN_COMPLETED = '1' } elif test -n $BATS_TEST_COMPLETED { setglobal BATS_ERROR_STATUS = $status setglobal BATS_ERROR_STACK_TRACE = ''( "${BATS_CURRENT_STACK_TRACE[@]}" ) } bats_exit_trap } proc bats_exit_trap { local status local skipped trap - err exit setglobal skipped = ''"" if test -n $BATS_TEST_SKIPPED { setglobal skipped = '" # skip'" if test "1" != $BATS_TEST_SKIPPED { setglobal skipped = "" ($BATS_TEST_SKIPPED)"" } } if test -z $BATS_TEST_COMPLETED || test -z $BATS_TEARDOWN_COMPLETED { echo "not ok $BATS_TEST_NUMBER $BATS_TEST_DESCRIPTION" > !3 bats_print_stack_trace $(BATS_ERROR_STACK_TRACE[@]) > !3 bats_print_failed_command $(BATS_ERROR_STACK_TRACE[${#BATS_ERROR_STACK_TRACE[@]}-1]) $BATS_ERROR_STATUS > !3 sed -e "s/^/# /" < $BATS_OUT > !3 setglobal status = '1' } else { echo "ok $(BATS_TEST_NUMBER)$(skipped) $(BATS_TEST_DESCRIPTION)" > !3 setglobal status = '0' } rm -f $BATS_OUT exit "$status" } proc bats_perform_tests { echo "1..$Argc" setglobal test_number = '1' setglobal status = '0' for test_name in [@Argv] { $0 $BATS_EXTENDED_SYNTAX $BATS_TEST_FILENAME $test_name $test_number || setglobal status = '1' let test_number+=1 } exit "$status" } proc bats_perform_test { setglobal BATS_TEST_NAME = $1 if test $[type -t $BATS_TEST_NAME || true] = "function" { setglobal BATS_TEST_NUMBER = $2 if test -z $BATS_TEST_NUMBER { echo "1..1" setglobal BATS_TEST_NUMBER = '"1'" } setglobal BATS_TEST_COMPLETED = ''"" setglobal BATS_TEARDOWN_COMPLETED = ''"" trap "bats_debug_trap \"\$BASH_SOURCE\"" debug trap "bats_error_trap" err trap "bats_teardown_trap" exit $BATS_TEST_NAME >>$BATS_OUT !2 > !1 setglobal BATS_TEST_COMPLETED = '1' } else { echo "bats: unknown test name \`$BATS_TEST_NAME'" > !2 exit 1 } } if test -z $TMPDIR { setglobal BATS_TMPDIR = '"/tmp'" } else { setglobal BATS_TMPDIR = $(TMPDIR%/) } setglobal BATS_TMPNAME = ""$BATS_TMPDIR/bats.$Pid"" setglobal BATS_PARENT_TMPNAME = ""$BATS_TMPDIR/bats.$PPID"" setglobal BATS_OUT = ""$(BATS_TMPNAME).out"" proc bats_preprocess_source { setglobal BATS_TEST_SOURCE = ""$(BATS_TMPNAME).src"" do { tr -d '\r' < $BATS_TEST_FILENAME; echo; } | bats-preprocess > $BATS_TEST_SOURCE trap "bats_cleanup_preprocessed_source" err exit trap "bats_cleanup_preprocessed_source; exit 1" int } proc bats_cleanup_preprocessed_source { rm -f $BATS_TEST_SOURCE } proc bats_evaluate_preprocessed_source { if test -z $BATS_TEST_SOURCE { setglobal BATS_TEST_SOURCE = ""$(BATS_PARENT_TMPNAME).src"" } source $BATS_TEST_SOURCE } exec !3 3<&1 if test "$Argc" -eq 0 { bats_preprocess_source bats_evaluate_preprocessed_source if test -n $BATS_COUNT_ONLY { echo $(#BATS_TEST_NAMES[@]) } else { bats_perform_tests $(BATS_TEST_NAMES[@]) } } else { bats_evaluate_preprocessed_source bats_perform_test @Argv }