Summary
Every test forks a subshell to read a line number, and the per-file scan already read it.
Measured
$(shopt -s extdebug; declare -F fn) costs 1.08 ms per call on macOS arm64, bash 3.2.57, best of 3 over 2000 calls. It runs once per test, unconditionally. Over this suite's ~2491 tests that is roughly 2.7 seconds of a sequential run.
A bare $( ) costs 1.1 to 1.4 ms on the same box. Worth noting: perf-fork-budget.md records 0.46 ms, which predates arm64. The old figure should not be reused for estimates.
Current behavior
bashunit::runner::resolve_test_location, src/runner/context.sh:80-100:
def="$(shopt -s extdebug; declare -F "$fn_name" 2>/dev/null)" || true
It is called from export_test_identity (src/runner/context.sh:65) for every test, to build <file>:<line> for a failure message most tests never emit.
Meanwhile bashunit::runner::functions_for_script (src/runner/discovery.sh:340-380) already runs $( shopt -s extdebug; declare -F $all_fn_names ) once per file, reads <name> <line> <file> for every function in it, sorts by definition line, and then throws the line numbers away.
Expected behavior
Cache name to line in that existing per-file pass and make the per-test lookup a scan of it. Bash 3 parallel arrays, following _BASHUNIT_TAGS_MAP_FNS / _BASHUNIT_TAGS_MAP_TAGS in src/helper/tags.sh. Keep the current $( ) as the fallback for a name that is not in the map, so nothing regresses for a function defined some other way.
extdebug must stay inside the subshell (#808). Verify against a data-provider test, where one function runs for many rows, and against an interpolated title.
Summary
Every test forks a subshell to read a line number, and the per-file scan already read it.
Measured
$(shopt -s extdebug; declare -F fn)costs 1.08 ms per call on macOS arm64, bash 3.2.57, best of 3 over 2000 calls. It runs once per test, unconditionally. Over this suite's ~2491 tests that is roughly 2.7 seconds of a sequential run.A bare
$( )costs 1.1 to 1.4 ms on the same box. Worth noting:perf-fork-budget.mdrecords 0.46 ms, which predates arm64. The old figure should not be reused for estimates.Current behavior
bashunit::runner::resolve_test_location,src/runner/context.sh:80-100:It is called from
export_test_identity(src/runner/context.sh:65) for every test, to build<file>:<line>for a failure message most tests never emit.Meanwhile
bashunit::runner::functions_for_script(src/runner/discovery.sh:340-380) already runs$( shopt -s extdebug; declare -F $all_fn_names )once per file, reads<name> <line> <file>for every function in it, sorts by definition line, and then throws the line numbers away.Expected behavior
Cache name to line in that existing per-file pass and make the per-test lookup a scan of it. Bash 3 parallel arrays, following
_BASHUNIT_TAGS_MAP_FNS/_BASHUNIT_TAGS_MAP_TAGSinsrc/helper/tags.sh. Keep the current$( )as the fallback for a name that is not in the map, so nothing regresses for a function defined some other way.extdebugmust stay inside the subshell (#808). Verify against a data-provider test, where one function runs for many rows, and against an interpolated title.