Skip to content

perf(tags): build per-file function-to-tags map in one pass instead of per-function grep/sed walk #773

Description

@Chemaclass

Part of #761.

Problem

When --tag/--exclude-tag is used, bashunit::helper::get_tags_for_function (src/helpers.sh:670) runs per test function, and twice per function: once during early load filtering (src/runner.sh:411) and again in call_test_functions (src/runner.sh:733).

Each call forks heavily: grep -n | head to locate the function, then a backward line-by-line walk where every line forks sed -n "${N}p" plus up to three "$GREP" -cE probes (src/helpers.sh:~690-715). That is O(comment-lines) forks per function, times two.

Measured (macOS bash 3.2, commit 1ae3e82): 100 tagged tests with --tag foo run in ~2.10s vs ~0.68s untagged baseline — ~14ms extra per test, and it grows with the size of the comment block above each function.

Task

Mirror the existing single-pass provider map (bashunit::helper::build_provider_map, src/helpers.sh:327, added in #763/PR #767 — use it as the template):

  1. Add bashunit::helper::build_tags_map "$script": one awk pass per file emitting <fn>\t<tag1,tag2,...> records into two parallel indexed arrays (Bash 3.0: no associative arrays), cached by script path so both call sites (src/runner.sh:411 and src/runner.sh:733) share one scan.
  2. Add a pure-bash lookup bashunit::helper::tags_for_function writing to a _BASHUNIT_TAGS_OUT slot, and convert both call sites.
  3. The awk pass must reproduce the current walk semantics exactly (see src/helpers.sh:670-720): collect # @tag <name> comment lines above the function definition, continue walking up through other comment lines, stop at the first blank or non-comment line; function defined as function test_x or test_x(). Multiple @tag lines accumulate comma-separated in the same order the current code produces.
  4. Keep get_tags_for_function as a wrapper (or delete it if nothing else calls it — grep first).

Tests first (TDD)

tests/functional already covers tag filtering — run it before and after. Add unit tests for the new map builder: multiple tags, tag after a non-tag comment, blank line breaking the association, both function-definition styles, two files back to back (cache invalidation by path).

Constraints

  • Bash 3.0+ only; no associative arrays — use the parallel-array pattern from build_provider_map.
  • --tag/--exclude-tag semantics and output must be unchanged.

Acceptance criteria

  • ./bashunit tests/ and ./bashunit --parallel tests/ pass.
  • make sa, make lint pass; shfmt -w . produces no diff.
  • Report before/after timing of 100 tagged tests with --tag in the PR (baseline above).

Line references valid at commit 1ae3e82.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Fields

No fields configured for issues without a type.

Projects

Status
Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions