Recompiling rust code based on externally referenced files

Hey,
I'm trying to extend test-case crate with ability to automatically generate tests for each file contained within a directory. To do so I have designed a macro #[test_case::for_each(file in "tests/data/")]. Alas I was met with an issue:
In a scenario where tested dir contains, let's say, files:

a.txt
b.txt

I can run cargo test and I'll get two tests per a method.
Now if I'll add new file, eg. c.txt, and run cargo test I will still end up with only two tests untill I clean target dir. I can see, that include_str! bypasses this, however in my scenario I can't hack my work around by using it as I'm walking a dir. Is there a way to mark a macro for update every time there's recompilation / tie to a directory in such way that end users of test-case don't have to clean their project every time they run tests?

Emitting include_str! seems to be the only supported option?

From a build script you can use cargo:rerun-if-changed=PATH (a helper crate I made). From a procedural macro, the only stable way is indeed to include_str! the file, typically as const _: &str = include_str!($path);, which is an idiom that rustc recognizes as "just constant evaluate this and throw away the result."

There is a nightly API available and my open RFC for improving the situation, but include_str! is the only current stable way.

You should be able to use include_str! by using absolute paths (Path::canonicalize).

However, there is no way to recognize that a new file has been added to a directory that I know of. Even dtolnay's automod crate doesn't recognize new files until recompiled.

Note that you don't need a full clean rebuild, you just need to touch the files that cargo does think impact the build. Adding an empty build.rs that doesn't use rerun-if-changed will cause cargo to assume all files in the project directory are inputs, thus I think getting the result you want if and only if 1) projects aren't already using a buildrs and 2) they're okay with spurious rebuilds when changing other non *.rs files.

One other thing you could do is take the approach of trybuild and log your own output when discovering the tests at runtime, or even set up a harness=false custom test runner.

4 Likes

Good food for thought, alas I was hoping for one size fits all solution. At least I have a bit more knowledge now and may pivot to make this feature nightly only.

Thank you for detailed dive in :slight_smile: