I've had to do something very similar in other projects, so you might be able to take inspiration from real world examples.
Here's one place I use a macro to generate a large number of tests for parsing expressions in the OpenSCAD programming language:
Similar to you, my tests are almost all identical except for one part (the input string and parsing function in my case, but yours would be the callback method), so the macro definition is fairly straightforward plus/minus some extra bits I add to help debug failing tests.
One of the things I like about this macro is it preserves attributes. That means you can add #[ignore] above a test and Rust's test runner will skip it.
If this constraint is due to build environments and not being allowed to spawn other processes, it's useful to know that code generation doesn't require shelling out to a script. Using @matklad's self-modifying code trick and some inspiration from rust-analyzer, you can write a Rust test that will generate the code for you and automatically keep it up to date.
Here is how I use the pattern elsewhere in that codebase: