@@ -17,13 +17,19 @@ function runner::load_test_files() {
17
17
internal_log " Loading file" " $test_file "
18
18
# shellcheck source=/dev/null
19
19
source " $test_file "
20
- runner::run_set_up_before_script
20
+ if ! runner::run_set_up_before_script " $test_file " ; then
21
+ runner::clean_set_up_and_tear_down_after_script
22
+ if ! parallel::is_enabled; then
23
+ cleanup_script_temp_files
24
+ fi
25
+ continue
26
+ fi
21
27
if parallel::is_enabled; then
22
28
runner::call_test_functions " $test_file " " $filter " 2> /dev/null &
23
29
else
24
30
runner::call_test_functions " $test_file " " $filter "
25
31
fi
26
- runner::run_tear_down_after_script
32
+ runner::run_tear_down_after_script " $test_file "
27
33
runner::clean_set_up_and_tear_down_after_script
28
34
if ! parallel::is_enabled; then
29
35
cleanup_script_temp_files
@@ -57,9 +63,13 @@ function runner::load_bench_files() {
57
63
export BASHUNIT_CURRENT_SCRIPT_ID=" $( helper::generate_id " ${test_file} " ) "
58
64
# shellcheck source=/dev/null
59
65
source " $bench_file "
60
- runner::run_set_up_before_script
66
+ if ! runner::run_set_up_before_script " $bench_file " ; then
67
+ runner::clean_set_up_and_tear_down_after_script
68
+ cleanup_script_temp_files
69
+ continue
70
+ fi
61
71
runner::call_bench_functions " $bench_file " " $filter "
62
- runner::run_tear_down_after_script
72
+ runner::run_tear_down_after_script " $bench_file "
63
73
runner::clean_set_up_and_tear_down_after_script
64
74
cleanup_script_temp_files
65
75
done
@@ -284,18 +294,27 @@ function runner::run_test() {
284
294
exec 3>&1
285
295
286
296
local test_execution_result=$(
297
+ # shellcheck disable=SC2064
287
298
# shellcheck disable=SC2154
288
- trap '
289
- exit_code=$?
299
+ trap "
300
+ exit_code=\ $ ?
290
301
set +e
291
- state::set_test_exit_code "$exit_code"
292
- runner::run_tear_down
302
+ teardown_status=0
303
+ runner::run_tear_down \" $test_file \" || teardown_status= \$ ?
293
304
runner::clear_mocks
294
305
cleanup_testcase_temp_files
306
+ if [[ \$ teardown_status -ne 0 ]]; then
307
+ state::set_test_exit_code \"\$ teardown_status\"
308
+ else
309
+ state::set_test_exit_code \"\$ exit_code\"
310
+ fi
295
311
state::export_subshell_context
296
- ' EXIT
312
+ " EXIT
297
313
state::initialize_assertions_count
298
- runner::run_set_up
314
+ if ! runner::run_set_up " $test_file " ; then
315
+ status=$?
316
+ exit " $status "
317
+ fi
299
318
300
319
# 2>&1: Redirects the std-error (FD 2) to the std-output (FD 1).
301
320
# points to the original std-output.
@@ -369,17 +388,46 @@ function runner::run_test() {
369
388
local test_title=" "
370
389
[[ -n " $encoded_test_title " ]] && test_title=" $( helper::decode_base64 " $encoded_test_title " ) "
371
390
391
+ local encoded_hook_failure
392
+ encoded_hook_failure=" ${test_execution_result##*## TEST_HOOK_FAILURE=} "
393
+ encoded_hook_failure=" ${encoded_hook_failure%%##* } "
394
+ local hook_failure=" "
395
+ if [[ " $encoded_hook_failure " != " $test_execution_result " ]]; then
396
+ hook_failure=" $encoded_hook_failure "
397
+ fi
398
+
399
+ local encoded_hook_message
400
+ encoded_hook_message=" ${test_execution_result##*## TEST_HOOK_MESSAGE=} "
401
+ encoded_hook_message=" ${encoded_hook_message%%##* } "
402
+ local hook_message=" "
403
+ if [[ -n " $encoded_hook_message " ]]; then
404
+ hook_message=" $( helper::decode_base64 " $encoded_hook_message " ) "
405
+ fi
406
+
372
407
state::set_test_title " $test_title "
373
408
local label
374
409
label=" $( helper::normalize_test_function_name " $fn_name " " $interpolated_fn_name " ) "
375
410
state::reset_test_title
376
411
412
+ local failure_label=" $label "
413
+ local failure_function=" $fn_name "
414
+ if [[ -n " $hook_failure " ]]; then
415
+ failure_label=" $( helper::normalize_test_function_name " $hook_failure " ) "
416
+ failure_function=" $hook_failure "
417
+ fi
418
+
377
419
if [[ -n $runtime_error || $test_exit_code -ne 0 ]]; then
378
420
state::add_tests_failed
379
- console_results::print_error_test " $label " " $runtime_error "
380
- reports::add_test_failed " $test_file " " $label " " $duration " " $total_assertions "
381
- runner::write_failure_result_output " $test_file " " $fn_name " " $runtime_error "
382
- internal_log " Test error" " $label " " $runtime_error "
421
+ local error_message=" $runtime_error "
422
+ if [[ -n " $hook_failure " && -n " $hook_message " ]]; then
423
+ error_message=" $hook_message "
424
+ elif [[ -z " $error_message " && -n " $hook_message " ]]; then
425
+ error_message=" $hook_message "
426
+ fi
427
+ console_results::print_error_test " $failure_function " " $error_message "
428
+ reports::add_test_failed " $test_file " " $failure_label " " $duration " " $total_assertions "
429
+ runner::write_failure_result_output " $test_file " " $failure_function " " $error_message "
430
+ internal_log " Test error" " $failure_label " " $error_message "
383
431
return
384
432
fi
385
433
@@ -555,19 +603,135 @@ function runner::write_failure_result_output() {
555
603
echo -e " $test_nr ) $test_file :$line_number \n$error_msg " >> " $FAILURES_OUTPUT_PATH "
556
604
}
557
605
606
+ function runner::record_file_hook_failure() {
607
+ local hook_name=" $1 "
608
+ local test_file=" $2 "
609
+ local hook_output=" $3 "
610
+ local status=" $4 "
611
+ local render_header=" ${5:- false} "
612
+
613
+ if [[ " $render_header " == true ]]; then
614
+ runner::render_running_file_header " $test_file "
615
+ fi
616
+
617
+ if [[ -z " $hook_output " ]]; then
618
+ hook_output=" Hook '$hook_name ' failed with exit code $status "
619
+ fi
620
+
621
+ state::add_tests_failed
622
+ console_results::print_error_test " $hook_name " " $hook_output "
623
+ reports::add_test_failed " $test_file " " $( helper::normalize_test_function_name " $hook_name " ) " 0 0
624
+ runner::write_failure_result_output " $test_file " " $hook_name " " $hook_output "
625
+
626
+ return " $status "
627
+ }
628
+
629
+ function runner::execute_file_hook() {
630
+ local hook_name=" $1 "
631
+ local test_file=" $2 "
632
+ local render_header=" ${3:- false} "
633
+
634
+ if [[ " $( type -t " $hook_name " ) " != " function" ]]; then
635
+ return 0
636
+ fi
637
+
638
+ local hook_output=" "
639
+ local status=0
640
+ local hook_output_file
641
+ hook_output_file=$( temp_file " ${hook_name} _output" )
642
+
643
+ {
644
+ " $hook_name "
645
+ } > " $hook_output_file " 2>&1 || status=$?
646
+
647
+ if [[ -f " $hook_output_file " ]]; then
648
+ hook_output=$( cat " $hook_output_file " )
649
+ rm -f " $hook_output_file "
650
+ fi
651
+
652
+ if [[ $status -ne 0 ]]; then
653
+ runner::record_file_hook_failure " $hook_name " " $test_file " " $hook_output " " $status " " $render_header "
654
+ return $status
655
+ fi
656
+
657
+ if [[ -n " $hook_output " ]]; then
658
+ printf " %s\n" " $hook_output "
659
+ fi
660
+
661
+ return 0
662
+ }
663
+
558
664
function runner::run_set_up() {
665
+ local _test_file=" ${1-} "
559
666
internal_log " run_set_up"
560
- helper::execute_function_if_exists ' set_up'
667
+ runner::execute_test_hook ' set_up'
561
668
}
562
669
563
670
function runner::run_set_up_before_script() {
671
+ local test_file=" $1 "
564
672
internal_log " run_set_up_before_script"
565
- helper::execute_function_if_exists ' set_up_before_script'
673
+ runner::execute_file_hook ' set_up_before_script' " $test_file " true
566
674
}
567
675
568
676
function runner::run_tear_down() {
677
+ local _test_file=" ${1-} "
569
678
internal_log " run_tear_down"
570
- helper::execute_function_if_exists ' tear_down'
679
+ runner::execute_test_hook ' tear_down'
680
+ }
681
+
682
+ function runner::execute_test_hook() {
683
+ local hook_name=" $1 "
684
+
685
+ if [[ " $( type -t " $hook_name " ) " != " function" ]]; then
686
+ return 0
687
+ fi
688
+
689
+ local hook_output=" "
690
+ local status=0
691
+ local hook_output_file
692
+ hook_output_file=$( temp_file " ${hook_name} _output" )
693
+
694
+ {
695
+ " $hook_name "
696
+ } > " $hook_output_file " 2>&1 || status=$?
697
+
698
+ if [[ -f " $hook_output_file " ]]; then
699
+ hook_output=$( cat " $hook_output_file " )
700
+ rm -f " $hook_output_file "
701
+ fi
702
+
703
+ if [[ $status -ne 0 ]]; then
704
+ local message=" $hook_output "
705
+ if [[ -n " $hook_output " ]]; then
706
+ printf " %s" " $hook_output "
707
+ else
708
+ message=" Hook '$hook_name ' failed with exit code $status "
709
+ printf " %s\n" " $message " >&2
710
+ fi
711
+ runner::record_test_hook_failure " $hook_name " " $message " " $status "
712
+ return " $status "
713
+ fi
714
+
715
+ if [[ -n " $hook_output " ]]; then
716
+ printf " %s" " $hook_output "
717
+ fi
718
+
719
+ return 0
720
+ }
721
+
722
+ function runner::record_test_hook_failure() {
723
+ local hook_name=" $1 "
724
+ local hook_message=" $2 "
725
+ local status=" $3 "
726
+
727
+ if [[ -n " $( state::get_test_hook_failure) " ]]; then
728
+ return " $status "
729
+ fi
730
+
731
+ state::set_test_hook_failure " $hook_name "
732
+ state::set_test_hook_message " $hook_message "
733
+
734
+ return " $status "
571
735
}
572
736
573
737
function runner::clear_mocks() {
@@ -577,8 +741,9 @@ function runner::clear_mocks() {
577
741
}
578
742
579
743
function runner::run_tear_down_after_script() {
744
+ local test_file=" $1 "
580
745
internal_log " run_tear_down_after_script"
581
- helper::execute_function_if_exists ' tear_down_after_script'
746
+ runner::execute_file_hook ' tear_down_after_script' " $test_file "
582
747
}
583
748
584
749
function runner::clean_set_up_and_tear_down_after_script() {
0 commit comments