Macro to identify which test is being run?


#1

I’m wondering if there is some macro (or way to construct a macro?) that could identify which test is being run. Currently I use line!() to create unique temporary directories for each test case, but that is a nuisance, because I have to look up the file to determine which directory corresponds to which test.

Is there some way to identify (in a macro) either the name of the currently running test, or the name of the function which calls a macro?


#2

There isn’t. You may need to create your own.

Keep in mind that tests are run in parallel, so technically all tests may be running at the same time.

You can create a context object/folder path in each test and pass it explicitly to the code being tested.

Or if it’s too hard to connect test with code that needs this knowledge, maybe use some thread-local storage?


#3

Using line numbers works fine, it just means that the directories created for each test end up having meaningless names. I could, of course, manually create a unique directory name for each test, but that’s pretty tedious.


#4

If you just need a temporary directory to run your tests in then why not use something like tempdir?


#5

I want the directory to persist and be findable so I can debug failed
tests. That’s why I’d prefer a nice name.


#6

Maybe you can use module_path!()? You’d have to put each test in its own module though.


#7

It sounds like this is a bit of an X-Y problem. If the reason you want the directory to stick around is to debug a test, then why not still use tempdir and then if that test fails you can “leak” the temporary directory with TempDir::into_path().


#8

That was very helpful, thanks! I ended up creating a little macro to do some setup and cleanup, and to define both the module and the function. I’ll include it here in case anyone finds it helpful:

macro_rules! test_case {
    (fn $testname:ident($t:ident) $body:block) => {
        mod $testname {
            use super::*;
            #[test]
            fn $testname() {
                let path = std::path::PathBuf::from(
                    format!("tmp/{}", module_path!()));
                {
                    let $t = TempDir::new(&path);
                    $body;
                }
                std::thread::sleep(std::time::Duration::from_secs(1));
                // Remove temporary directory (we did not panic!), but
                // ignore errors that might happen on windows or NFS.
                std::fs::remove_dir_all(&path).ok();
            }
        }
    }
}