Past, present, and future for Rust testing

THIS. The macro #[test] is special, but this is really the only bit that can't be reproduced with macros 2.0. So if we fill in that bit, we can go wild prototyping better test suites as crates without having to touch the compiler.

Actually, it would be simpler to create a registry that would be accessible at runtime. That way there would be no need to define dependencies between macros and running them in multiple passes. The compiler would put the items aside, the linker would collect them and the test runner would simply iterate an array.

I would suggest something like this:

First a registry array would be defined. Something like:

#[registry]
static test_functions: &[&fn()];

and then each function would be annotated like:

#[register_to(test_functions)]
fn test_function() { … }

And the compiler and linker would conspire to simply make the test_functions be an array of all the appropriately annotated test functions. A code in main would then simply iterate that array.

Now in crate this should be simple to implement as the Rust compiler does have all of the information at some point. But

I would actually see some uses for this being cross-crate global. Even that can be done. On ELF platforms it can be done by putting the array members (references to the annotated items) to a special section and having the linker collect them. And on platforms that don't have special sections, it can still be done using the mechanism provided for C++ static constructors, i.e. there would be a bit of code before main that would collect the pointers. It would mean some code would run before main, but it would be implementation detail hidden in the standard library, so it should still not cause the sort of trouble the fully general mechanism causes for C++.

I even think that the mechanism could be prototyped currently with macros and the cpp crate.


Note that this tool would also be reused for things like the output formatters. The

could similarly desugar to #[register_to(test_runners)] and then the main would look in the test_runners array and pick one by comparing something in it to a command-line option, falling back to either first one or default. If the mechanism was global (i.e. if the attribute permitted qualified name like #[register_to(::test::runners)]), merely adding the formatter crate to Cargo.toml would make the formatter available for selecting.

1 Like