Skip to content

Fix find_tests line-number search for test names at the start of a line - #851

Merged
mvandervoord merged 1 commit into
ThrowTheSwitch:masterfrom
joniumGit:fix/find-tests-line-search
Sep 10, 2026
Merged

Fix find_tests line-number search for test names at the start of a line#851
mvandervoord merged 1 commit into
ThrowTheSwitch:masterfrom
joniumGit:fix/find-tests-line-search

Conversation

@joniumGit

Copy link
Copy Markdown
Contributor

Mandatory 🍍

UnityTestRunnerGenerator#find_tests in auto/generate_test_runner.rb locates each test's line number with a forward cursor and the regex /\s+#{name}(?:\s|\()/. The leading \s+ (added in f278c18 for #288) requires whitespace before the name on the same line, so a definition written as

void
test_something(void)

never matches its own line. Two things follow:

  • every such test is reported with line_number 0 in the generated runner;
  • the cursor scans to the end of the file for every test, so the search is O(tests x lines) with the interpolated regex recompiled on each line.

On a 10,000-line file with 367 tests this costs about 14 s of Ruby time per file on an Apple M-series laptop (Ruby 2.6 and 4.0), and 20 s or more on typical CI runners. Projects that write the return type on its own line hit this on every runner generation, including through Ceedling, which vendors this file.

Change

  • Accept start-of-line as well as whitespace before the name: /(?:^|\s)#{name}(?:\s|\()/.
  • Build the regex once per test instead of once per line.
  • The trailing (?:\s|\() is unchanged, so the partial-name case from Invalid line number in runner generator in very specific case #288 (test_my_function vs test_my_function_invalid_behavior) still resolves to the right line.

Tests

Two cases added to test/tests/test_generate_test_runner.rb:

cd test && rake test:scripts: 69/69 before, 71/71 after. rubocop ../auto/generate_test_runner.rb --config .rubocop.yml (1.57.2, as in CI): no offenses.

Measurement

Synthetic file, 367 tests of 25 lines each in the void / test_x(void) style, 11,015 lines, one find_tests call:

Ruby before after line numbers found
2.6.10 13.5 s 0.28 s 0/367 -> 367/367
4.0.2 14.0 s 0.27 s 0/367 -> 367/367

Reproduction (from the repository root, before and after this change):

ruby -e '
  src = "#include \"unity.h\"\n\n"
  367.times { |i| src << "void\ntest_case_#{i}(void)\n{\n" << "    TEST_ASSERT_EQUAL(1, 1);\n" * 25 << "}\n\n" }
  require "./auto/generate_test_runner"
  t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  tests = UnityTestRunnerGenerator.new({}).find_tests(src)
  printf("%.2f s, line numbers found: %d/%d\n", Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0, tests.count { |t| t[:line_number] > 0 }, tests.size)
'

Notes

The regex has had this form in every tag from v2.4.2 to v2.7.0 and on current master. I found no existing issue or PR about it.
I used Claude Code in making this PR.

The line-number search in UnityTestRunnerGenerator#find_tests requires
whitespace before the test name. A definition written as

    void
    test_something(void)

puts the name at column 0, so the regex never matches the definition
line. The search then scans to the end of the file for every test,
O(tests x lines), and reports line number 0 for all of them.

Accept start-of-line as well as whitespace before the name, and compile
the regex once per test instead of once per line.
@mvandervoord
mvandervoord merged commit 2b80d1a into ThrowTheSwitch:master Sep 10, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants