Repository navigation
Description
Problem
docs/test-files.md:28 says all three Bash forms are supported: function name(), name() and function name without parentheses. Tests written in the third form run, but every annotation above them is ignored and the header does not count them.
Reproduced on main 776997e9, macOS arm64, Bash 3.2.57:
cat > annot_test.sh <<'EOF'
function provide_rows() {
bashunit::data_set 1
bashunit::data_set 2
}
# @data_provider provide_rows
function test_with_provider {
assert_same 1 "$#"
}
# @skip not ready
function test_skipped_by_annotation {
assert_same 1 2
}
# @tag slow
function test_tagged {
assert_same 1 1
}
EOF
./bashunit --skip-env-file annot_test.sh
./bashunit --skip-env-file --tag slow annot_test.shFirst run: the header shows no test count, test_with_provider runs once with zero arguments and fails, test_skipped_by_annotation runs and fails instead of being skipped. Second run: No tests found. With () added to the three definitions, the provider yields two cases, the skip is honoured and --tag slow selects one test.
A smaller case: function test_a { next to function test_b() { prints Tests: 1 in the header and 2 total in the summary, in both modes.
Where
Every textual scanner requires () after the name:
src/helper/provider.sh:153and:165(provider map, annotations, static header count).src/helper/tags.sh:92(tag map).src/helper/discovery.sh:20(duplicate check).
Execution does not: functions_for_script (src/runner/discovery.sh:324) uses declare -F, so the test runs, which is what makes the mismatch silent.
Why it matters
The docs promise the form, and a test that loses its @skip runs code the author marked as not ready, while a test that loses its @data_provider runs once with no arguments. --tag selections and the header count are wrong for every such file.
Suggested change
Accept [[:space:]]*(\(\))? after the name in the four patterns, so function name { and function name are scanned like name(). Add the form to the fixtures used by the provider, tag, duplicate and header-count tests. If the form is not meant to be supported, change the docs and make discovery refuse it loudly instead.
Acceptance criteria
-
@data_provider,@skip,@timeout,@retryand@tagapply tofunction name {definitions exactly as toname(). - The header count equals the summary total for a file mixing the three forms, in sequential and parallel mode.
- Duplicate detection reports two
function test_x {definitions. - Tests cover each scanner with the parenthesis-free form and fail on the current code.
Proposed fix
Teach the four textual scanners the function name { form. A bare word must not match, so the parenthesis-free form requires the function keyword:
src/helper/provider.sh:153(per-line definition match) and:165(column-0 static count),src/helper/tags.sh:92,src/helper/discovery.sh:20: replace the single pattern with the alternation below, and extend the name extraction (provider.sh:156-157,tags.sh:95,discovery.sh:23-24) to strip[[:space:]]*(\(\)|\{).*after the name.
# definition: `function name`, `function name()`, or `name()`, with or without `{` on the line
is_fn = match($0, /^[[:space:]]*function[[:space:]]+[A-Za-z_][A-Za-z0-9_:]*[[:space:]]*(\(\))?[[:space:]]*(\{|$)/) ||
match($0, /^[[:space:]]*[A-Za-z_][A-Za-z0-9_:]*[[:space:]]*\(\)/)
if (is_fn) {
fn = $0
sub(/^[[:space:]]*(function[[:space:]]+)?/, "", fn)
sub(/[[:space:]]*(\(\)|\{).*/, "", fn)
}The ? quantifier and alternation are POSIX awk ERE and work on macOS awk, gawk and busybox. Bash 3.0: nothing in the shell changes. Public behaviour that must not change: name() and function name() scanning, the "dynamic file" rule for indented definitions (provider.sh:160-171), the @data_provider two-line distance rule, and tests/acceptance/bashunit_test_function_names_test.sh. Docs: docs/test-files.md:28 stays true, no change. CHANGELOG: one line under Unreleased, Fixed.
Agent brief
- Branch:
fix/1422-scan-function-keyword-without-parensfrom freshorigin/main. Commit:fix(provider): honour annotations and tags on functions declared without parentheseswithCloses #1422in the body. - Files:
src/helper/provider.sh,src/helper/tags.sh,src/helper/discovery.sh; extendtests/unit/helper/annotations_test.sh(copy its firstbuild_provider_maptest),tests/unit/helper/tags_map_test.sh, andtests/acceptance/bashunit_test_function_names_test.sh(line 29) for the header count. - RED first:
function test_annotations_apply_to_a_function_declared_without_parentheses() {
local file
file="$(bashunit::temp_file annot)"
printf '# @skip not ready\nfunction test_no_parens {\n :\n}\n' >"$file"
bashunit::helper::build_provider_map "$file"
bashunit::helper::annotations_for_function test_no_parens
assert_same true "$_BASHUNIT_ANNOT_SKIP_OUT"
}Fails on the current code: the slot is empty. Run only that file: ./bashunit tests/unit/helper/annotations_test.sh.
- Non-goals: discovery itself (
functions_for_script,declare -F) already runs these tests; do not touch it. Coordinate with Duplicate test functions are not detected when the opening brace is on the next line #1421, which edits the samediscovery.sh:20pattern; if it is merged first, extend its pattern instead of replacing it. - Gate, once, when the change is complete:
./bashunit tests/,./bashunit --parallel --simple --strict tests/,make sa,make lint.make lintis the formatting authority; nevershfmt -w; 2-space indent. - Done when: every acceptance box is checked, the gate is green, the CHANGELOG line is in, and a PR is open with the
prskill.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity