use std::{
ffi::{OsStr, OsString},
fmt::Debug,
ops::{Deref, DerefMut},
path::{Path, PathBuf},
};
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
pub struct CurrentDir(std::path::PathBuf);
impl Debug for CurrentDir {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
pub fn set_current_dir<P: AsRef<Path>>(path: P) -> Result<CurrentDir, std::io::Error> {
let current_dir = std::env::current_dir()?;
std::env::set_current_dir(&path)?;
Ok(CurrentDir(current_dir))
}
impl Drop for CurrentDir {
fn drop(&mut self) {
std::env::set_current_dir(&self.0).expect("cannot go back to the previous directory");
}
}
pub struct CurrentEnv(OsString);
impl Debug for CurrentEnv {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
pub fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) -> CurrentEnv {
let key = key.as_ref();
std::env::set_var(key, value);
CurrentEnv(key.to_owned())
}
impl Drop for CurrentEnv {
fn drop(&mut self) {
std::env::remove_var(&self.0)
}
}
pub struct TmpDir(pub(crate) PathBuf);
impl Deref for TmpDir {
type Target = PathBuf;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for TmpDir {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Debug for TmpDir {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
pub fn create_temp_dir() -> Result<TmpDir, std::io::Error> {
let tmp_dir = std::env::temp_dir();
let tmp_path = tmp_dir.join(random_path());
std::fs::create_dir(&tmp_path)?;
Ok(TmpDir(tmp_path))
}
impl Drop for TmpDir {
fn drop(&mut self) {
std::fs::remove_dir_all(&self.0).expect("cannot delete the tmp dir")
}
}
fn random_path() -> PathBuf {
let rand_string: String = thread_rng()
.sample_iter(&Alphanumeric)
.take(10)
.map(char::from)
.collect();
PathBuf::from(rand_string)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_env() {
{
let _tmp_env = set_var("TEST_TMP_ENV", "myvalue");
assert_eq!(std::env::var("TEST_TMP_ENV"), Ok(String::from("myvalue")));
}
assert!(std::env::var("TEST_TMP_ENV").is_err());
set_var("TEST_TMP_ENV_DROPPED", "myvaluedropped");
assert!(std::env::var("TEST_TMP_ENV_DROPPED").is_err());
}
#[test]
fn test_current_dir() {
{
let _tmp_current_dir = set_current_dir("src").expect("should set the new current_dir");
let current_dir = std::env::current_dir().expect("cannot get current dir from std env");
assert!(current_dir.ends_with("src"));
}
let current_dir = std::env::current_dir().expect("cannot get current dir from std env");
assert!(!current_dir.ends_with("src"));
set_current_dir("target").expect("should set the new current_dir");
assert!(!current_dir.ends_with("target"));
}
#[test]
fn test_tmp_dir() {
#[allow(unused_assignments)]
let mut tmp_dir_created: Option<PathBuf> = None;
{
let tmp_dir = create_temp_dir().expect("cannot create temp dir");
tmp_dir_created = Some(tmp_dir.0.clone());
assert!(std::fs::metadata(&*tmp_dir).is_ok());
}
assert!(std::fs::metadata(tmp_dir_created.unwrap()).is_err());
}
}