Skip to content

perf(runner): count the header's tests without re-sourcing every file - #1357

Merged
Chemaclass merged 1 commit into
mainfrom
feat/1347-static-header-count
Sep 9, 2026
Merged

perf(runner): count the header's tests without re-sourcing every file#1357
Chemaclass merged 1 commit into
mainfrom
feat/1347-static-header-count

Conversation

@Chemaclass

Copy link
Copy Markdown
Member

🤔 Background

Related #1347

Printing "Running N tests" sourced the whole suite a second time and re-ran every data provider, in a double subshell per file, before the run began — 1.72s over this repo's 241 files.

💡 Changes

  • Extend the existing per-file provider scan (one awk pass, already memoized) to also emit the file's column-0 function definitions, and count the names that survive get_functions_to_run. 124 of 241 files skip the second source; the counting pass drops to 1.51s.
  • The other 117 keep sourcing, because a static scan would be wrong in both directions: a provider's row count needs running, eval/nested source/indented definitions hide tests, and a heredoc or multi-line string contains function test_x() as text — which is how acceptance tests write fixtures. Each marks the file dynamic.
  • The gate is the differential the issue asked for, kept as a test: every file in tests/, three filter settings, static count must equal sourcing count. It runs in a shell that has sourced no test file, or compgen -A function would also see the running file's own tests.
  • That gate found a latent bug: the duplicate check was a substring match, so test_a alongside test_ab read as a duplicate and the file selected nothing. compgen is sorted so a prefix always came first; definition order does not.

https://claude.ai/code/session_01EXYWTGLjf7qM8Ru3GakDRm

Printing "Running N tests" sourced the whole suite a second time and ran
every data provider a second time, in a double subshell per file, before
the run began: 1.72s over this repo's 241 files.

The provider scan already walks every line of every file with awk, and
is already memoized so the runner reuses it. Have that same pass also
emit the file's column-0 function definitions, and count the names that
survive get_functions_to_run. 124 of 241 files are counted this way and
the pass drops to 1.51s.

The other 117 keep sourcing, because a static scan would be wrong about
them, in both directions. A provider's row count is only knowable by
running it. eval, a nested source and an indented definition can define
a test the scan cannot see, which would undercount. A heredoc or a
multi-line string can contain a `function test_x()` that is text rather
than a definition, which would overcount -- acceptance tests write their
fixtures exactly that way. Each of those marks the file dynamic; the
scan does not try to parse where a string ends, because it also builds
the provider map and a line-skipping bug there would mis-wire real
tests.

The gate is the differential the issue asked for, kept as a test: for
every file in tests/, under three filter settings, the static count must
equal the sourcing count. It has to run in a shell that has sourced no
test file, since the sourcing path asks `compgen -A function` and would
otherwise also count the test functions of whichever file is running.

That gate immediately found a latent bug. get_functions_to_run checked
for duplicates with a substring match, so a name another selected name
starts with -- `test_a` against `test_ab` -- read as a duplicate, and the
function returns 1, which made the file select nothing. `compgen` output
is sorted, so a prefix always arrived first and nothing had reached it;
definition order does.

Closes #1347

Claude-Session: https://claude.ai/code/session_01EXYWTGLjf7qM8Ru3GakDRm
@Chemaclass Chemaclass added the enhancement New feature or request label Sep 9, 2026
@Chemaclass Chemaclass self-assigned this Sep 9, 2026
@Chemaclass
Chemaclass merged commit 466fb62 into main Sep 9, 2026
37 checks passed
@Chemaclass
Chemaclass deleted the feat/1347-static-header-count branch September 9, 2026 08:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant