Skip to content

perf(runner): cache data-provider lookup per file instead of grep+sed per test #763

Description

@Chemaclass

Part of #761.

Problem

bashunit::runner::call_test_functions calls bashunit::helper::get_provider_data "$fn_name" "$script" for every test function (src/runner.sh:778-782). get_provider_data (src/helpers.sh:295-319) runs grep -B 2 -E ... "$script" | sed -nE ... — two external forks plus a full re-read of the test file from disk — just to discover whether a # @data_provider annotation exists above the function. For the overwhelming majority of tests there is no provider.

Measured cost: ~3.3ms per test on macOS bash 3.2, ~4s across the suite, compounding inside the 258 nested ./bashunit acceptance runs.

Task

Scan each test file once (when its functions are enumerated in call_test_functions, src/runner.sh:757 area) and build a test-function -> provider-function map for that file; per-test lookup becomes pure bash.

Implementation sketch (Bash 3.0 compatible — no associative arrays):

  • One grep/awk pass per file extracting pairs of (annotation provider name, following test function name). Must match the same things the current probe matches: # data_provider fn and # @data_provider fn (see sed pattern at src/helpers.sh:313), annotation up to 2 lines above a function defined either as function test_x or test_x().
  • Store as a newline-delimited global string of test_fn provider_fn records (or two parallel indexed arrays); reset it per file. Lookup with a plain loop or case match.
  • Keep bashunit::helper::execute_function_if_exists behavior for missing provider functions.
  • Preserve the issue Data providers don't work when changing directory in set_up_before_script #529 fallback: if the script path is not readable, retry with $BASHUNIT_WORKING_DIR/$script (src/helpers.sh:301-303), and return no providers if still unreadable.
  • get_provider_data can remain as a thin wrapper over the cache so its unit tests keep passing, or be replaced — follow whichever keeps the public surface unchanged.

Tests first (TDD)

  • Existing provider behavior tests: tests/functional/provider_test.sh must pass unchanged (both sequential and --parallel).
  • Add unit tests for the new scanner: file with multiple providers, provider with @ and without, annotation 2 lines above the function, two functions sharing one provider, file with none, unreadable path (issue Data providers don't work when changing directory in set_up_before_script #529 case).

Constraints

  • Bash 3.0+ only: no declare -A, no [[ ]], no ${var,,}, no negative array indexing, no &>>.
  • Return values on the hot path must follow the outvar/global-slot pattern from .claude/rules/bash-style.md — no new $(...) per-test call.
  • Data-provider execution order and row order must not change (test names include interpolated provider data).

Acceptance criteria

  • ./bashunit tests/ and ./bashunit --parallel tests/ pass.
  • make sa, make lint pass; shfmt -w . produces no diff.
  • Fork census shows the per-test grep+sed pair replaced by at most one scan per file.
  • Before/after timing of the 100-noop benchmark reported in the PR.

Line references valid at commit 4d80e7c.

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