You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
--test-timeout and --retry are run-wide switches, but the need is almost always per test: one integration test needs 30 seconds, one network test is known-flaky, the other 400 tests should stay strict and non-retrying. Today the choice is to loosen the setting for the entire suite.
The annotation mechanism to fix this already exists for benchmarks. src/benchmark/annotations.sh:29parse_annotations reads @revs, @its and @max_ms from the comment block above a bench function, and src/helper/tags.sh:10 does the same single-awk-pass scan for # @tag. Tests get tags and nothing else.
Proposal
Per-test annotations in the comment block directly above the function, consistent with # @tag:
# @timeout 30# @retry 3# @skip requires a live databasefunctiontest_slow_integration() { … }
@timeout <seconds> — overrides --test-timeout for this test, in both directions (a test can be stricter than the global setting). 0 disables the timeout for this test.
@retry <n> — overrides --retry for this test.
@skip [reason] — the test is skipped without executing the body, reported with the reason. Unlike bashunit::skip, this needs no body edit and is visible when reading the file.
A malformed value must fail loudly, matching the precedent set by Malformed benchmark annotations are silently ignored #884 for @revs=abc (reject_malformed_marker, src/benchmark/annotations.sh:12) — silently falling back to the default runs a different test than the one asked for.
Both function test_x and test_x() definition styles are recognised
No measurable per-test fork regression — the existing fork-budget acceptance tests must still pass
Works under --parallel
Documented in docs/test-files.md
Repo checklist (agent)
TDD: RED → GREEN → REFACTOR. Write the failing test first.
Bash 3.0+ only: no printf -v, no += append, no declare -A, no [[ ]], no ${var,,}, no &>>, no ${arr[-1]}. Expanding a possibly-empty array under set -u needs ${arr[@]+"${arr[@]}"}.
A new CLI flag must be wired in all of these or a parity test fails:
parse in src/main/test.sh (report-style flags need export -n, see src/main/test.sh:188-196 for why)
Problem
--test-timeoutand--retryare run-wide switches, but the need is almost always per test: one integration test needs 30 seconds, one network test is known-flaky, the other 400 tests should stay strict and non-retrying. Today the choice is to loosen the setting for the entire suite.The annotation mechanism to fix this already exists for benchmarks.
src/benchmark/annotations.sh:29parse_annotationsreads@revs,@itsand@max_msfrom the comment block above a bench function, andsrc/helper/tags.sh:10does the same single-awk-pass scan for# @tag. Tests get tags and nothing else.Proposal
Per-test annotations in the comment block directly above the function, consistent with
# @tag:@timeout <seconds>— overrides--test-timeoutfor this test, in both directions (a test can be stricter than the global setting).0disables the timeout for this test.@retry <n>— overrides--retryfor this test.@skip [reason]— the test is skipped without executing the body, reported with the reason. Unlikebashunit::skip, this needs no body edit and is visible when reading the file.@revs=abc(reject_malformed_marker,src/benchmark/annotations.sh:12) — silently falling back to the default runs a different test than the one asked for.Where to change
src/helper/tags.sh:10— reuse the same single-pass awk scan and memoization so this does not reintroduce a per-function file walk (perf(tags): build per-file function-to-tags map in one pass instead of per-function grep/sed walk #773).src/runner/exec.sh:298-345— the retry/timeout resolution point (bashunit::env::resolve_retry_count,is_test_timeout_enabled).src/helper/discovery.sh:62get_functions_to_runfor@skip.Acceptance criteria
# @timeout 1fails a test that sleeps 3 seconds, while the rest of the suite runs with no timeout# @timeout 0disables the timeout for that test even when--test-timeout 1is passed globally# @retry 2retries only that test# @skip reasonreports the test as skipped, with the reason, and the body never executes# @tagin the same comment block# @timeout abc/# @retry -1exit non-zero with a clear error (Malformed benchmark annotations are silently ignored #884 precedent)function test_xandtest_x()definition styles are recognised--paralleldocs/test-files.mdRepo checklist (agent)
printf -v, no+=append, nodeclare -A, no[[ ]], no${var,,}, no&>>, no${arr[-1]}. Expanding a possibly-empty array underset -uneeds${arr[@]+"${arr[@]}"}.src/main/test.sh(report-style flags needexport -n, seesrc/main/test.sh:188-196for why)bashunit::main::validate_config_or_exit(src/main/validate.sh:60) — unvalidated input used to run the wrong thing and exit 0 (Unknown options are silently ignored: a typo'd flag runs a different suite and exits 0 #871, --jobs with a non-integer value hangs on Bash 3.x and is silently ignored on Bash 4.3+ #873)src/config/env.shand a documented line in.env.example--helptext in the same block it belongs tocompletions/bashunit.bashandcompletions/_bashunit(anti-drift test feat(cli): bash and zsh completion scripts with an anti-drift test #778 fails otherwise)make sa,make lint,./bashunit tests/,./bashunit --parallel tests/. Never runshfmt -w.docs/command-line.md. Editingdocs/assertions.mdinvalidates thebashunit docacceptance snapshot — regenerate it.## Unreleased.tests/acceptance/fixtures/must not end in*test.sh.