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

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions