Just to elaborate on the mighty Shepmaster's brilliant solution, and partly in answer to the comment by Vlady Veselinov that this in some way means introducing "superfluous" code into your test, I offer this idea of a "general purpose" Noisy where you stipulate only the cleanup closure you need:
struct Noisy<'a> {
closure: &'a dyn Fn() -> (),
}
impl Noisy<'_> {
fn new(closure: &dyn Fn() -> ()) -> Noisy {
Noisy { closure }
}
}
impl Drop for Noisy<'_> {
fn drop(&mut self) {
let _ = &(self.closure)();
}
}
// the idea with this test is that some files are created in a temporary dir
// and must be deleted regardless of outcome at the end of the test...
#[test]
fn index_gather_documents_does_that() -> Result<()> {
let dir = env::temp_dir();
let delivered_temp_dir_path = dir.as_path();
let temp_rust_testing_dir_path = delivered_temp_dir_path.join("rust_testing");
let cleanup_dir_path = temp_rust_testing_dir_path.clone();
let cleanup_dir_path_str = cleanup_dir_path
.to_str()
.ok_or_else(|| anyhow!("str failure! |{:?}|", cleanup_dir_path))?;
let teardown_binding = || {
std::fs::remove_dir_all(cleanup_dir_path_str);
};
let _noisy = Noisy::new(&teardown_binding);
// NB "_" here will not work: drop() will happen immediately
// ... test proper: start creating the files
}
I am indebted to cafce25 for what looks like a more elegant solution:
use std::fmt::Display;
use std::path::PathBuf;
pub struct Noisy<F: FnMut()> {
closure: F,
}
impl<F: FnMut()> Noisy<F> {
pub fn new(closure: F) -> Self {
Noisy {
closure,
}
}
}
impl<F: FnMut()> Drop for Noisy<F> {
fn drop(&mut self) {
(self.closure)()
}
}
#[test]
fn my_test() {
let cleanup_dir_path = PathBuf::from("src");
let _noisy = Noisy::new(|| {
std::fs::remove_dir_all(&cleanup_dir_path).unwrap()
});
...
}
... unwrap()
in the closure causes the test to fail in case of error (as it should).