Ok(())
}
-// tests change working directory, so need to be run with:
-// cargo test -- --test-threads=1 --nocapture
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
use std::process::{Command, Stdio};
- struct TempWorkDir {
+ pub static TEST_LOCK: std::sync::Mutex<u32> = std::sync::Mutex::new(0);
+
+ struct TempWorkDir<'a> {
+ // Hold a mutex alongside directory change, to avoid failures due to
+ // multi-threaded "cargo test".
+ cwd_lock: std::sync::MutexGuard<'a, u32>,
prev_dir: PathBuf,
parent_tmp_dir: PathBuf,
cleanup_files: Vec<PathBuf>,
ignore_cleanup: bool, // useful for debugging
}
- impl TempWorkDir {
+ impl TempWorkDir<'_> {
// create a temporary directory under CWD and cd into it.
// The directory will be cleaned up when twd goes out of scope.
- pub fn new() -> TempWorkDir {
+ pub fn new() -> TempWorkDir<'static> {
let mut buf = [0u8; 16];
let mut s = String::from("cpio-selftest-");
fs::File::open("/dev/urandom")
for i in &buf {
s.push_str(&format!("{:02x}", i).to_string());
}
+
let mut twd = TempWorkDir {
+ cwd_lock: TEST_LOCK.lock().unwrap_or_else(|mut e| {
+ // another test panicked while holding the lock
+ **e.get_mut() = 1;
+ TEST_LOCK.clear_poison();
+ e.into_inner()
+ }),
prev_dir: env::current_dir().unwrap(),
parent_tmp_dir: {
let mut t = env::current_dir().unwrap().clone();
}
}
- impl Drop for TempWorkDir {
+ impl Drop for TempWorkDir<'_> {
fn drop(&mut self) {
for f in self.cleanup_files.iter().rev() {
if self.ignore_cleanup {
}
println!("returning cwd to {}", self.prev_dir.display());
env::set_current_dir(self.prev_dir.as_path()).unwrap();
+ // cwd_lock should be dropped automatically
}
}