#[cfg(test)]
mod tests;
use std::ffi::OsString;
use std::fs::{create_dir_all, read, read_dir, remove_dir_all, remove_file, write};
use std::io::Result;
use std::path::Path;
pub struct TestDirUtils {
test_dir: OsString,
delete_on_terminate: bool,
}
impl TestDirUtils {
pub const DEFAULT_TEST_DIR: &'static str = "test_dir.tmp";
pub fn new(name: &str) -> Result<Self> {
Self::with_root(Path::new(Self::DEFAULT_TEST_DIR), name)
}
pub fn with_root(test_root: &Path, name: &str) -> Result<Self> {
let unique_test_dir = Self::create_unique_name_for_thread(name);
let full_path = test_root.join(Path::new(&unique_test_dir));
if full_path.is_file() {
remove_file(full_path.as_path())?;
}
if !full_path.exists() {
create_dir_all(full_path.as_path())?;
}
Ok(Self {
test_dir: full_path.into_os_string(),
delete_on_terminate: true,
})
}
pub fn delete_on_terminate(&self) -> bool {
self.delete_on_terminate
}
pub fn set_delete_on_terminate(&mut self, delete_on_terminate: bool) {
self.delete_on_terminate = delete_on_terminate;
}
fn create_unique_name_for_thread(name: &str) -> String {
format!("{}-{:?}", name, std::thread::current().id())
}
pub fn test_dir(&self) -> &Path {
Path::new(&self.test_dir)
}
pub fn reset(&self) -> Result<()> {
for entry in read_dir(self.test_dir())? {
match entry {
Ok(e) => {
let file_type = e.file_type()?;
if file_type.is_file() || file_type.is_symlink() {
remove_file(e.path())?;
} else if file_type.is_dir() {
remove_dir_all(e.path())?;
}
}
Err(e) => return Err(e),
}
}
Ok(())
}
pub fn get_test_file_path(&self, name: &str) -> OsString {
let path = Path::new(&self.test_dir);
path.join(name).into_os_string()
}
pub fn create_test_file(&self, name: &str, contents: &[u8]) -> Result<OsString> {
let full_path = self.get_test_file_path(name);
let p = Path::new(&full_path);
write(p, contents)?;
Ok(full_path)
}
pub fn touch_test_file(&self, name: &str) -> Result<OsString> {
self.create_test_file(name, b"")
}
pub fn read_test_file(&self, name: &str) -> Result<Vec<u8>> {
let full_path = self.get_test_file_path(name);
let p = Path::new(&full_path);
Ok(read(p)?)
}
pub fn delete_test_file(&self, name: &str) -> Result<()> {
let full_path = self.get_test_file_path(name);
let p = Path::new(&full_path);
if p.exists() {
remove_file(p)
} else {
Ok(())
}
}
}
impl Drop for TestDirUtils {
fn drop(&mut self) {
if self.delete_on_terminate {
remove_dir_all(Path::new(self.test_dir())).unwrap();
}
}
}