test: one source cutter for the checks (tests/srccut.py), 79 checks moved to it #27

Open
dyst wants to merge 2 commits from dyst/Longshot:test/srccut into main
Member

Why

123 checks carry their own copy of a brace counter (def block) to cut a function out of a source file; the copies count braces inside strings, character literals and comments too, and when a function is renamed or reshaped they stop with a bare ValueError or IndexError that doesn't say which source or marker (the trap AGENTS.md warns about, "Tests read the source"). This gives the checks one cutter and moves 79 of them to it, each shown to cut exactly what it cut before.

What changed

  • tests: new tests/srccut.py (standard library):
    • block(text, marker): from the marker to the brace that closes the first { after it (_closing_brace()), counting braces outside string and character literals (raw strings too, and C++14 digit separators), comments and preprocessor lines;
    • between(text, start, end), and find();
    • a marker that is missing, or that appears twice, stops the check with one message naming the source and the marker (CutError; unique=False takes the first on purpose);
    • SRCCUT_CHECK_NAIVE=1 also cuts each block the old way (_naive()) and stops if the two differ: what a migration runs to show it changed nothing.
  • tests: 79 checks import block from it in place of their own copy, one commit per source file they read (vk_menu.cpp, vk_draw.cpp, vk_memory.cpp, vk_texture.cpp, longshot_env.h, hos_main.c, ...). Only exact copies of the plain counter moved; each takes sys.path.insert(0, ...) for its own folder, since python -I leaves it off the path.
  • tests: new tests/test_srccut.py: braces in strings, character literals, raw strings, comments and preprocessor lines; a fixture the old counter cut wrongly; a missing marker and a repeated one name the source; between; an unclosed block; the comparison with the old counter.
  • tests: test_audio_voice_biquad.py cuts with test_audio_deadline.py's block, which is srccut's now: its marker for the filter loop is the one render_voice writes with its brace on the line (the second commit; the cut is the same as before, checked against the old counter).
  • Not moved:
    • three checks whose block isn't the plain counter (a start offset; positions returned): left as they were;
    • 13 checks whose marker appears more than once in the source (a declaration before the definition, for example). The old counter took the first one silently, so each needs a look rather than unique=False;
    • 51 checks with other cutters (function, body, between, ...): later, by source file.

Flags and settings

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
SRCCUT_CHECK_NAIVE test only: srccut.block also cuts the old way and stops if the two cuts differ unset off by default (a developer switch) - - -

Measurements

main: 000f19fb (2026-11-13)
this PR: test/srccut @ 39951d5f
Hardware: Ryzen 9 3900X, 64 GB, Windows 11 (RTX 3080; no game run: these are game-free checks)
Scene: none: game-free. The 79 checks this moves, by name
Method: two interleaved rounds of the 79 through run_all.py --jobs 12 (main, this PR, this PR with SRCCUT_CHECK_NAIVE=1: every cut also made the old way and compared), the PC otherwise quiet and the bench lock held. Times by the script's clock
How to reproduce: python -I -B tests/run_all.py <the 79 names> on each, and with SRCCUT_CHECK_NAIVE=1 on this branch

main @ 000f19fb this PR @ 39951d5f
the 79 moved checks passing 79 79 (and 79 with SRCCUT_CHECK_NAIVE=1: no cut differs)
their time (s), median of 2 13.5 13.6 (13.7 with the comparison)
main1: 13.6 s, 79 passed, 0 failed     pr1: 13.9 s, 79 passed, 0 failed     naive1: 14.2 s, 79 passed, 0 failed
main2: 13.3 s, 79 passed, 0 failed     pr2: 13.2 s, 79 passed, 0 failed     naive2: 13.1 s, 79 passed, 0 failed

80 moved on the GitHub version; test_linux_update_skip.py is gone from main since #13, and test_builder_update_back.py, which it moved too, since #181.

Rebased since onto main 0c74253d: its four commits since 000f19fb are #177 (a log line's level, in the renderer's logging), #192, #193 and #194 (the README, the website, the Discord status), none in the runner or the checks measured here, so the numbers hold.

Testing

Tested: the runs above; tests/run_all.py, the whole suite, on this branch and on main 0c74253d, Windows (483 passed and 6 failed on main, 484 passed and 6 failed here, no failure main doesn't have: test_check_third_party, test_display_pointer, test_fpx_sticky, test_release, test_spawn_emit and test_texture_staging_publication fail on main too (the last since #177; #202 fixes it)); tests/test_srccut.py (new).

Not tested: in the game (tests only); on Linux (the cutter is plain Python). The checks that were not moved (3 + 13 + 51) were not changed.

Needs other testers: None

Screenshots

Nothing on screen.

Risk and rollback

Only the checks change. A moved check could cut a different piece of source than before (the new cutter skips braces in literals and comments, which the old one counted); SRCCUT_CHECK_NAIVE=1 showed none of the 80 does today. A marker that now appears twice in a source stops its check where the old counter took the first silently. Reverting the commits is enough.

Reviewer notes

Carried over from https://github.com/NotRexed/Hookshot/pull/2914 with the move to Longshot: the same change on Longshot's main, with its rename applied. Its review and discussion are there.

The dev-loop proposal's D2 (https://github.com/NotRexed/Hookshot/pull/2636). A follow-up after https://github.com/NotRexed/Hookshot/pull/2887: run_all.py --changed runs a test helper's importers (srccut's) rather than every check.

The checks were run on the GitHub version; this branch is the same change with the rename applied (the same files and line counts). Forgejo runs no checks, and they were not run again here. The moved checks and test_srccut.py were run, not the whole run_all.py.

Issues

See https://github.com/NotRexed/Hookshot/pull/2636 (D2).

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above).
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened.

🤖 Generated with Claude Code

## Why 123 checks carry their own copy of a brace counter (`def block`) to cut a function out of a source file; the copies count braces inside strings, character literals and comments too, and when a function is renamed or reshaped they stop with a bare `ValueError` or `IndexError` that doesn't say which source or marker (the trap AGENTS.md warns about, "Tests read the source"). This gives the checks one cutter and moves 79 of them to it, each shown to cut exactly what it cut before. ## What changed - tests: new `tests/srccut.py` (standard library): - `block(text, marker)`: from the marker to the brace that closes the first `{` after it (`_closing_brace()`), counting braces outside string and character literals (raw strings too, and C++14 digit separators), comments and preprocessor lines; - `between(text, start, end)`, and `find()`; - a marker that is missing, or that appears twice, stops the check with one message naming the source and the marker (`CutError`; `unique=False` takes the first on purpose); - `SRCCUT_CHECK_NAIVE=1` also cuts each block the old way (`_naive()`) and stops if the two differ: what a migration runs to show it changed nothing. - tests: 79 checks import `block` from it in place of their own copy, one commit per source file they read (`vk_menu.cpp`, `vk_draw.cpp`, `vk_memory.cpp`, `vk_texture.cpp`, `longshot_env.h`, `hos_main.c`, ...). Only exact copies of the plain counter moved; each takes `sys.path.insert(0, ...)` for its own folder, since `python -I` leaves it off the path. - tests: new `tests/test_srccut.py`: braces in strings, character literals, raw strings, comments and preprocessor lines; a fixture the old counter cut wrongly; a missing marker and a repeated one name the source; `between`; an unclosed block; the comparison with the old counter. - tests: `test_audio_voice_biquad.py` cuts with `test_audio_deadline.py`'s `block`, which is srccut's now: its marker for the filter loop is the one `render_voice` writes with its brace on the line (the second commit; the cut is the same as before, checked against the old counter). - Not moved: - three checks whose `block` isn't the plain counter (a start offset; positions returned): left as they were; - 13 checks whose marker appears more than once in the source (a declaration before the definition, for example). The old counter took the first one silently, so each needs a look rather than `unique=False`; - 51 checks with other cutters (`function`, `body`, `between`, ...): later, by source file. ## Flags and settings | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | `SRCCUT_CHECK_NAIVE` | test only: `srccut.block` also cuts the old way and stops if the two cuts differ | unset | off by default (a developer switch) | - | - | - | ## Measurements main: 000f19fb (2026-11-13) this PR: test/srccut @ 39951d5f Hardware: Ryzen 9 3900X, 64 GB, Windows 11 (RTX 3080; no game run: these are game-free checks) Scene: none: game-free. The 79 checks this moves, by name Method: two interleaved rounds of the 79 through `run_all.py --jobs 12` (main, this PR, this PR with `SRCCUT_CHECK_NAIVE=1`: every cut also made the old way and compared), the PC otherwise quiet and the bench lock held. Times by the script's clock How to reproduce: `python -I -B tests/run_all.py <the 79 names>` on each, and with `SRCCUT_CHECK_NAIVE=1` on this branch | | main @ 000f19fb | this PR @ 39951d5f | |---|---|---| | the 79 moved checks passing | 79 | 79 (and 79 with `SRCCUT_CHECK_NAIVE=1`: no cut differs) | | their time (s), median of 2 | 13.5 | 13.6 (13.7 with the comparison) | ``` main1: 13.6 s, 79 passed, 0 failed pr1: 13.9 s, 79 passed, 0 failed naive1: 14.2 s, 79 passed, 0 failed main2: 13.3 s, 79 passed, 0 failed pr2: 13.2 s, 79 passed, 0 failed naive2: 13.1 s, 79 passed, 0 failed ``` 80 moved on the GitHub version; `test_linux_update_skip.py` is gone from main since #13, and `test_builder_update_back.py`, which it moved too, since #181. Rebased since onto main 0c74253d: its four commits since 000f19fb are #177 (a log line's level, in the renderer's logging), #192, #193 and #194 (the README, the website, the Discord status), none in the runner or the checks measured here, so the numbers hold. ## Testing **Tested:** the runs above; `tests/run_all.py`, the whole suite, on this branch and on main 0c74253d, Windows (483 passed and 6 failed on main, 484 passed and 6 failed here, no failure main doesn't have: test_check_third_party, test_display_pointer, test_fpx_sticky, test_release, test_spawn_emit and test_texture_staging_publication fail on main too (the last since #177; #202 fixes it)); `tests/test_srccut.py` (new). **Not tested:** in the game (tests only); on Linux (the cutter is plain Python). The checks that were not moved (3 + 13 + 51) were not changed. **Needs other testers:** None ## Screenshots Nothing on screen. ## Risk and rollback Only the checks change. A moved check could cut a different piece of source than before (the new cutter skips braces in literals and comments, which the old one counted); `SRCCUT_CHECK_NAIVE=1` showed none of the 80 does today. A marker that now appears twice in a source stops its check where the old counter took the first silently. Reverting the commits is enough. ## Reviewer notes Carried over from https://github.com/NotRexed/Hookshot/pull/2914 with the move to Longshot: the same change on Longshot's `main`, with its rename applied. Its review and discussion are there. The dev-loop proposal's D2 (https://github.com/NotRexed/Hookshot/pull/2636). A follow-up after https://github.com/NotRexed/Hookshot/pull/2887: `run_all.py --changed` runs a test helper's importers (srccut's) rather than every check. The checks were run on the GitHub version; this branch is the same change with the rename applied (the same files and line counts). Forgejo runs no checks, and they were not run again here. The moved checks and `test_srccut.py` were run, not the whole `run_all.py`. ## Issues See https://github.com/NotRexed/Hookshot/pull/2636 (D2). ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
dyst changed title from test: one source cutter for the checks (tests/srccut.py), 80 checks moved to it to WIP: test: one source cutter for the checks (tests/srccut.py), 80 checks moved to it 2026-11-13 01:13:49 +00:00
Author
Member

Back to WIP under #48's process: this was carried over before the new template. Its description will be brought to the template and measured on Longshot (main against this PR, at named commits) when it's wanted for review; ask here if you'd like it sooner.

Back to WIP under #48's process: this was carried over before the new template. Its description will be brought to the template and measured on Longshot (main against this PR, at named commits) when it's wanted for review; ask here if you'd like it sooner.
Author
Member

Description brought to Longshot's PR template (#48). Still WIP: its numbers are from the GitHub version, and it isn't rebased on current main; it gets measured on Longshot (main against this PR, at named commits) before it is marked ready.

Description brought to Longshot's PR template (#48). Still WIP: its numbers are from the GitHub version, and it isn't rebased on current main; it gets measured on Longshot (main against this PR, at named commits) before it is marked ready.
Author
Member

Description moved to the template's Testing section and whole checklist (#72): what was tested, what wasn't, and what needs other testers (their test requests to open while this is WIP).

Description moved to the template's Testing section and whole checklist (#72): what was tested, what wasn't, and what needs other testers (their test requests to open while this is WIP).
Author
Member

The description follows the template after #76 and #106: If applicable keeps only the boxes that apply (one that applies and isn't done yet stays unticked while this is WIP), the Flags table has the template's seven columns (Goal is now Recommendation), and GitHub references are full URLs. Nothing else changed.

The description follows the template after #76 and #106: If applicable keeps only the boxes that apply (one that applies and isn't done yet stays unticked while this is WIP), the Flags table has the template's seven columns (Goal is now Recommendation), and GitHub references are full URLs. Nothing else changed.
dyst force-pushed test/srccut from d8111645c2
All checks were successful
PR description / Description follows the template (pull_request_target) Successful in 5s
to cd56b3b820
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
Website / Website on Cloudflare (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Website / Website on Cloudflare (pull_request_target) Has been skipped
2026-11-13 13:56:34 +00:00
Compare
Author
Member

Rebased onto main 0c74253d, where #13 and #181 removed two of the 80 moved checks (so 79), and a second commit: test_audio_voice_biquad cuts with test_audio_deadline's block, srccut's now, and its marker is made unique (the same cut, checked against the old counter). Measured on Longshot: the 79 pass on main, here, and with SRCCUT_CHECK_NAIVE=1, with no change in time. Whole suite on this head and on main: no failure main doesn't have. Ready for review.

Rebased onto main 0c74253d, where #13 and #181 removed two of the 80 moved checks (so 79), and a second commit: test_audio_voice_biquad cuts with test_audio_deadline's block, srccut's now, and its marker is made unique (the same cut, checked against the old counter). Measured on Longshot: the 79 pass on main, here, and with SRCCUT_CHECK_NAIVE=1, with no change in time. Whole suite on this head and on main: no failure main doesn't have. Ready for review.
dyst changed title from WIP: test: one source cutter for the checks (tests/srccut.py), 80 checks moved to it to WIP: test: one source cutter for the checks (tests/srccut.py), 79 checks moved to it 2026-11-13 13:56:48 +00:00
dyst changed title from WIP: test: one source cutter for the checks (tests/srccut.py), 79 checks moved to it to test: one source cutter for the checks (tests/srccut.py), 79 checks moved to it 2026-11-13 13:57:18 +00:00
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
Website / Website on Cloudflare (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Website / Website on Cloudflare (pull_request_target) Has been skipped
This pull request doesn't have enough approvals yet. 0 of 1 approvals granted.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'test/srccut:dyst-test/srccut'
git switch 'dyst-test/srccut'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!27
No description provided.