Procedural macro to setup test file

I've been writing macros as a way to reduce boilerplate and (softly) enforce some standardization of how I organize things. I put together one for creating the prefix I use for setting up unit test files.

I'd love feedback on my procedural macro (it's my first), but also any tips on idiomatic ways to organize unit tests. One thing I'll say upfront is that I accept this is probably not a worthwhile use of procedural macros (or macros at all), but even if it was pointless to do, I'd like to know if I did it right.

Currently I'm organizing my unit tests into separate files, located in a "tests" directory alongside the leaf module file. So if general.rs is at <somepath>/general.rs, the tests will be in <somepath>/tests/general_tests.rs, and at the top of general.rs I'll have:

#[cfg(test)]
#[path = "tests/general_test.rs"]
mod general_test;

The first thing I'd like feedback on is if that organization seems sane/standard.
To automate this process, in my proc_macros project I have:

 //This probably needs more clauses, adding as they're encountered
fn sanitize_string(s: &str) -> String {
    s.replace('\"', "").replace('{', "(").replace('}', ")")
}

#[proc_macro]
pub fn test_setup(_item: TokenStream) -> TokenStream {
    //needed so that `module_path` won't find the `proc_macros` location instead of the calling location
    let module_leaf = "module_path!()"
        .parse::<TokenStream>()
        .unwrap()
        .expand_expr()
        .unwrap()
        .to_string()
        .split("::")
        .last()
        .unwrap()
        .to_owned();
    //Otherwise the string includes double quotes
    let sanitized = sanitize_string(&module_leaf); 
    format! {"#[cfg(test)]
    #[path = \"tests/{sanitized}_tests.rs\"]
    mod {sanitized}_tests;"}
    .parse()
    .unwrap()
}

And at my use site general.rs, I call this with test_setup!();, which creates the desired prefix.

So far it works, but I'm guessing I did a bunch of things wrong.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.