@@ -57,71 +57,76 @@ function bashunit::runner::apply_interpolated_title() {
5757 printf ' %s' " $interpolated "
5858}
5959
60- # All four helpers below use the outvar pattern (first argument is the name of
61- # the variable to assign into) so callers can avoid the per-test $(...) subshell
62- # capture in the hot path. Internal locals use a `__bu_` prefix to avoid name
63- # collisions with caller variables passed by name.
64-
65- # Writes the value of an encoded field (##KEY=value##) into the named outvar.
66- # Arguments: $1 outvar name, $2 test_execution_result, $3 key
60+ # Hot-path result helpers below return their value via a dedicated global slot
61+ # (`_BASHUNIT_RUNNER_*_OUT`) instead of stdout. This avoids the per-test
62+ # `$(...)` subshell capture that dominated the result-parsing hot path. Callers
63+ # invoke the helper and immediately read the slot:
64+ #
65+ # bashunit::runner::extract_subshell_type "$subshell_output"
66+ # type=$_BASHUNIT_RUNNER_TYPE_OUT
67+ #
68+ # A dedicated slot per helper (rather than one shared slot) means nested or
69+ # adjacent calls cannot clobber each other and callers don't need to copy out
70+ # before every other helper runs.
71+ _BASHUNIT_RUNNER_FIELD_OUT=" "
72+ _BASHUNIT_RUNNER_TOTAL_OUT=" "
73+ _BASHUNIT_RUNNER_TYPE_OUT=" "
74+ _BASHUNIT_RUNNER_OUTPUT_OUT=" "
75+
76+ # Writes the value of an encoded field (##KEY=value##) into _BASHUNIT_RUNNER_FIELD_OUT.
77+ # Arguments: $1 test_execution_result, $2 key
6778function bashunit::runner::extract_encoded_field() {
68- local __bu_out=$1
69- local __bu_in=$2
70- local __bu_key=$3
71- local __bu_marker=" ##${__bu_key} ="
72- local __bu_val=" "
73- case " $__bu_in " in
74- * " $__bu_marker " * )
75- local __bu_rest=" ${__bu_in#* " $__bu_marker " } "
76- __bu_val=" ${__bu_rest%%##* } "
79+ local test_execution_result=$1
80+ local key=$2
81+ local marker=" ##${key} ="
82+ case " $test_execution_result " in
83+ * " $marker " * )
84+ local rest=" ${test_execution_result#* " $marker " } "
85+ _BASHUNIT_RUNNER_FIELD_OUT=" ${rest%%##* } "
7786 ;;
87+ * ) _BASHUNIT_RUNNER_FIELD_OUT=" " ;;
7888 esac
79- eval " $__bu_out =\$ __bu_val"
8089}
8190
82- # Writes the sum of all ASSERTIONS_* counters into the named outvar .
83- # Arguments: $1 outvar name, $2 test_execution_result
91+ # Writes the sum of all ASSERTIONS_* counters into _BASHUNIT_RUNNER_TOTAL_OUT .
92+ # Arguments: $1 test_execution_result
8493function bashunit::runner::compute_total_assertions() {
85- local __bu_out=$1
86- local __bu_in=$2
87- local __bu_failed __bu_passed __bu_skipped __bu_incomplete __bu_snapshot
88- __bu_failed=" ${__bu_in##*## ASSERTIONS_FAILED=} "
89- __bu_failed=" ${__bu_failed%%##* } "
90- __bu_passed=" ${__bu_in##*## ASSERTIONS_PASSED=} "
91- __bu_passed=" ${__bu_passed%%##* } "
92- __bu_skipped=" ${__bu_in##*## ASSERTIONS_SKIPPED=} "
93- __bu_skipped=" ${__bu_skipped%%##* } "
94- __bu_incomplete=" ${__bu_in##*## ASSERTIONS_INCOMPLETE=} "
95- __bu_incomplete=" ${__bu_incomplete%%##* } "
96- __bu_snapshot=" ${__bu_in##*## ASSERTIONS_SNAPSHOT=} "
97- __bu_snapshot=" ${__bu_snapshot%%##* } "
98- local __bu_val
99- __bu_val=$(( ${__bu_failed:- 0} + ${__bu_passed:- 0} + ${__bu_skipped:- 0} ))
100- __bu_val=$(( __bu_val + ${__bu_incomplete:- 0} + ${__bu_snapshot:- 0} ))
101- eval " $__bu_out =\$ __bu_val"
94+ local test_execution_result=$1
95+ local failed passed skipped incomplete snapshot
96+ failed=" ${test_execution_result##*## ASSERTIONS_FAILED=} "
97+ failed=" ${failed%%##* } "
98+ passed=" ${test_execution_result##*## ASSERTIONS_PASSED=} "
99+ passed=" ${passed%%##* } "
100+ skipped=" ${test_execution_result##*## ASSERTIONS_SKIPPED=} "
101+ skipped=" ${skipped%%##* } "
102+ incomplete=" ${test_execution_result##*## ASSERTIONS_INCOMPLETE=} "
103+ incomplete=" ${incomplete%%##* } "
104+ snapshot=" ${test_execution_result##*## ASSERTIONS_SNAPSHOT=} "
105+ snapshot=" ${snapshot%%##* } "
106+ local total
107+ total=$(( ${failed:- 0} + ${passed:- 0} + ${skipped:- 0} ))
108+ total=$(( total + ${incomplete:- 0} + ${snapshot:- 0} ))
109+ _BASHUNIT_RUNNER_TOTAL_OUT=$total
102110}
103111
104- # Writes the subshell type marker (text inside leading [...]) into the named outvar .
105- # Arguments: $1 outvar name, $2 subshell_output
112+ # Writes the subshell type marker (text inside leading [...]) into _BASHUNIT_RUNNER_TYPE_OUT .
113+ # Arguments: $1 subshell_output
106114function bashunit::runner::extract_subshell_type() {
107- local __bu_out=$1
108- local __bu_in=$2
109- local __bu_val=" ${__bu_in%% ]* } "
110- __bu_val=" ${__bu_val# [} "
111- eval " $__bu_out =\$ __bu_val"
115+ local subshell_output=$1
116+ local type=" ${subshell_output%% ]* } "
117+ _BASHUNIT_RUNNER_TYPE_OUT=" ${type# [} "
112118}
113119
114120# Writes the subshell output (minus the leading [type] marker, with embedded
115- # status markers replaced by newlines) into the named outvar .
116- # Arguments: $1 outvar name, $2 subshell_output
121+ # status markers replaced by newlines) into _BASHUNIT_RUNNER_OUTPUT_OUT .
122+ # Arguments: $1 subshell_output
117123function bashunit::runner::format_subshell_output() {
118- local __bu_out=$1
119- local __bu_in=$2
120- local __bu_val=" ${__bu_in#* ]} "
121- __bu_val=${__bu_val// \[ failed\] / $' \n ' }
122- __bu_val=${__bu_val// \[ skipped\] / $' \n ' }
123- __bu_val=${__bu_val// \[ incomplete\] / $' \n ' }
124- eval " $__bu_out =\$ __bu_val"
124+ local subshell_output=$1
125+ local line=" ${subshell_output#* ]} "
126+ line=${line// \[ failed\] / $' \n ' }
127+ line=${line// \[ skipped\] / $' \n ' }
128+ line=${line// \[ incomplete\] / $' \n ' }
129+ _BASHUNIT_RUNNER_OUTPUT_OUT=$line
125130}
126131
127132function bashunit::runner::detect_runtime_error() {
@@ -837,9 +842,10 @@ function bashunit::runner::run_test() {
837842 local subshell_output=$( bashunit::runner::decode_subshell_output " $test_execution_result " )
838843
839844 if [ -n " $subshell_output " ]; then
840- local type
841- bashunit::runner::extract_subshell_type type " $subshell_output "
842- bashunit::runner::format_subshell_output subshell_output " $subshell_output "
845+ bashunit::runner::extract_subshell_type " $subshell_output "
846+ local type=$_BASHUNIT_RUNNER_TYPE_OUT
847+ bashunit::runner::format_subshell_output " $subshell_output "
848+ subshell_output=$_BASHUNIT_RUNNER_OUTPUT_OUT
843849 if ! bashunit::env::is_failures_only_enabled; then
844850 bashunit::state::print_line " $type " " $subshell_output "
845851 fi
@@ -854,13 +860,15 @@ function bashunit::runner::run_test() {
854860
855861 local test_exit_code=" $_BASHUNIT_TEST_EXIT_CODE "
856862
857- local total_assertions
858- bashunit::runner::compute_total_assertions total_assertions " $test_execution_result "
863+ bashunit::runner::compute_total_assertions " $test_execution_result "
864+ local total_assertions= $_BASHUNIT_RUNNER_TOTAL_OUT
859865
860- local encoded_test_title hook_failure encoded_hook_message
861- bashunit::runner::extract_encoded_field encoded_test_title " $test_execution_result " " TEST_TITLE"
862- bashunit::runner::extract_encoded_field hook_failure " $test_execution_result " " TEST_HOOK_FAILURE"
863- bashunit::runner::extract_encoded_field encoded_hook_message " $test_execution_result " " TEST_HOOK_MESSAGE"
866+ bashunit::runner::extract_encoded_field " $test_execution_result " " TEST_TITLE"
867+ local encoded_test_title=$_BASHUNIT_RUNNER_FIELD_OUT
868+ bashunit::runner::extract_encoded_field " $test_execution_result " " TEST_HOOK_FAILURE"
869+ local hook_failure=$_BASHUNIT_RUNNER_FIELD_OUT
870+ bashunit::runner::extract_encoded_field " $test_execution_result " " TEST_HOOK_MESSAGE"
871+ local encoded_hook_message=$_BASHUNIT_RUNNER_FIELD_OUT
864872
865873 local test_title=" "
866874 [ -n " $encoded_test_title " ] && test_title=" $( bashunit::helper::decode_base64 " $encoded_test_title " ) "
0 commit comments