Drop bash 5 assumptions from the test harness#70
Merged
Merged
Conversation
Makefile invokes scripts via plain "bash tests/foo.sh", so stock macOS
picks up /bin/bash 3.2.57 regardless of the env-bash shebang. 2 failures
surfaced on a clean Apple Silicon host without Homebrew bash, both under
set -u:
- tests/lib/test-runner.sh:55 read $EPOCHREALTIME (bash 5.0+ builtin),
which expanded to the empty string and tripped the unbound-variable
check. make test-busybox aborted at the first sample.
- tests/driver.sh did "unset 'argv[0]'" then expanded "${argv[@]}".
bash 3.2 reports the emptied array as unbound; the fix in 4.4+ silently
returns zero elements. make check aborted partway through.
Land a shared tests/lib/bash-compat.sh that consolidates the cross-version
shims so each script does not have to re-derive them:
bash_compat_require aborts with rc=127 and a brew-install hint if
BASH_VERSINFO is missing or below 3.2. The minimum is parameterised
through BASH_COMPAT_MIN_MAJOR / BASH_COMPAT_MIN_MINOR so a future bump
is a single-line change.
epoch_us prints integer microseconds. It picks the lowest-cost source
at sourcing time: $EPOCHREALTIME on bash 5.0+ (no fork), "date +%s %N"
when the probe shows the system date emits a 9-digit nanosecond field
(GNU coreutils and macOS 14+/Sonoma date both qualify), python3, perl,
or a whole-second fallback. The chosen implementation is bound to one
function name so callers stay version-agnostic.
The file header documents the supported subset: no EPOCHREALTIME, no
declare -A, no mapfile / readarray, no ${var^^} / ${var,,}, and guard
any potentially empty array expansion with ${arr[@]+"${arr[@]}"} so
set -u does not trip on it.
Wire the shim through the four hot scripts:
tests/lib/test-runner.sh sources bash-compat.sh and uses epoch_us in
the run() watchdog. The four "${TEST_RUNNER[@]}" expansions gain the
${TEST_RUNNER[@]+...} guard so the library is self-defending if a
caller ever sources it without setting the array first.
tests/driver.sh drops the "unset argv[0]" dance for an offset slice
"for arg in "${argv[@]:1}"", which produces zero iterations cleanly
even when argv has one element. The downstream "${args[@]}" expansion
picks up the same +guard so tests with no extra args still launch.
tests/test-perf.sh drops its local epoch_us in favor of the shared
helper and sources bash-compat.sh.
tests/test-rosetta-alpine.sh guards args_a / args_b which could be
empty when a pipeline test omits one side of the "--" separator.
Refactor the two "declare -A" uses to indexed-array + lookup pattern:
tests/fetch-fixtures.sh encodes PKGS as "repo:name:version" tuples and
exposes a pkg_version helper. The case "$entry" in "$target"*) form
with quoted target is glob-safe ("*" and "?" in target match
literally) and the trailing ":" prevents prefix collisions
(main:bash does not match main:bash-completion).
tests/test-matrix.sh encodes EXPECTED_BASELINES as "key |min|max" and
exposes expected_baseline_get with printf -v output parameters.
Parsing is right-anchored (${entry%|*} then ${head##*|}) so a key
containing a literal "|" would still split correctly; current keys
have none but the form removes the trap. The verify_expected_counts
call site flips to "if ! expected_baseline_get" so a miss stays
silent the way the prior "${arr[$key]:-}" empty-string check did.
Close #66
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Makefile invokes scripts via plain "bash tests/foo.sh", so stock macOS picks up /bin/bash 3.2.57 regardless of the env-bash shebang. 2 failures surfaced on a clean Apple Silicon host without Homebrew bash, both under set -u:
Land a shared tests/lib/bash-compat.sh that consolidates the cross-version shims so each script does not have to re-derive them:
bash_compat_require aborts with rc=127 and a brew-install hint if
BASH_VERSINFO is missing or below 3.2. The minimum is parameterised
through BASH_COMPAT_MIN_MAJOR / BASH_COMPAT_MIN_MINOR so a future bump
is a single-line change.
epoch_us prints integer microseconds. It picks the lowest-cost source
at sourcing time: $EPOCHREALTIME on bash 5.0+ (no fork), "date +%s %N"
when the probe shows the system date emits a 9-digit nanosecond field
(GNU coreutils and macOS 14+/Sonoma date both qualify), python3, perl,
or a whole-second fallback. The chosen implementation is bound to one
function name so callers stay version-agnostic.
The file header documents the supported subset: no EPOCHREALTIME, no
declare -A, no mapfile / readarray, no ${var^^} / ${var,,}, and guard
any potentially empty array expansion with ${arr[@]+"${arr[@]}"} so
set -u does not trip on it.
Wire the shim through the four hot scripts:
tests/lib/test-runner.sh sources bash-compat.sh and uses epoch_us in
the run() watchdog. The four "${TEST_RUNNER[@]}" expansions gain the
${TEST_RUNNER[@]+...} guard so the library is self-defending if a
caller ever sources it without setting the array first.
tests/driver.sh drops the "unset argv[0]" dance for an offset slice
"for arg in "${argv[@]:1}"", which produces zero iterations cleanly
even when argv has one element. The downstream "${args[@]}" expansion
picks up the same +guard so tests with no extra args still launch.
tests/test-perf.sh drops its local epoch_us in favor of the shared
helper and sources bash-compat.sh.
tests/test-rosetta-alpine.sh guards args_a / args_b which could be
empty when a pipeline test omits one side of the "--" separator.
Refactor the two "declare -A" uses to indexed-array + lookup pattern:
tests/fetch-fixtures.sh encodes PKGS as "repo:name:version" tuples and
exposes a pkg_version helper. The case "$entry" in "$target") form
with quoted target is glob-safe ("" and "?" in target match
literally) and the trailing ":" prevents prefix collisions
(main:bash does not match main:bash-completion).
tests/test-matrix.sh encodes EXPECTED_BASELINES as "key |min|max" and
exposes expected_baseline_get with printf -v output parameters.
Parsing is right-anchored (${entry%|} then ${head##|}) so a key
containing a literal "|" would still split correctly; current keys
have none but the form removes the trap. The verify_expected_counts
call site flips to "if ! expected_baseline_get" so a miss stays
silent the way the prior "${arr[$key]:-}" empty-string check did.
Close #66
Summary by cubic
Make the test harness run on stock macOS
/bin/bash3.2 by removing bash 5-only features and adding a shared compatibility shim. Fixes set -u errors, hardens array handling, and keeps performance timing precise without requiring Homebrewbash.Bug Fixes
set -ufailures on bash 3.2: replace$EPOCHREALTIME, guard empty array expansions, and switchtests/driver.shto"${argv[@]:1}"instead of unsettingargv[0].${TEST_RUNNER[@]}/${args[@]}expansions across runners; Rosetta pipeline now handles empty sides safely.Refactors
tests/lib/bash-compat.shwithbash_compat_requireandepoch_us(prefers$EPOCHREALTIME, falls back todate +%s %N,python3, orperl) and source it fromtests/lib/test-runner.shandtests/test-perf.sh.PKGS+pkg_versionintests/fetch-fixtures.sh,EXPECTED_BASELINES+expected_baseline_getintests/test-matrix.sh.docs/testing.mdto statebash3.2+ is sufficient and document the portable bash rules (no associative arrays, no${var^^}/${var,,}, guard empty array expansions, etc.).Written for commit 018857e. Summary will update on new commits.