use crate::path::get_cwd;
use std::path::{Path, PathBuf};
#[must_use]
pub struct CdGuard {
original_cwd: PathBuf,
}
impl CdGuard {
pub fn new<P: AsRef<Path>>(path: P) -> Self {
let path = path.as_ref();
let original_cwd = get_cwd();
std::env::set_current_dir(path)
.unwrap_or_else(|_| panic!("Failed to change directory to '{path:?}'."));
Self { original_cwd }
}
}
impl Drop for CdGuard {
fn drop(&mut self) {
let original_cwd = self.original_cwd.clone();
std::env::set_current_dir(&original_cwd)
.unwrap_or_else(|_| panic!("Failed to change directory to '{original_cwd:?}'."))
}
}
pub fn cd<P: AsRef<Path>>(path: P) -> CdGuard {
CdGuard::new(path)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::create::create_folder;
use crate::path::to_path_buf;
use crate::test_utils::get_temp_dir_path;
use serial_test::serial;
use tempfile::tempdir;
#[test]
#[serial]
fn test_cd_without_scope() {
let original_cwd_path = get_cwd();
assert!(original_cwd_path.ends_with("file_io"));
let src_path = original_cwd_path.join("src");
let src_paths: Vec<Box<dyn AsRef<Path>>> = vec![
Box::new(src_path.to_str().unwrap()), Box::new(src_path.to_str().unwrap().to_string()), Box::new(src_path.as_path()), Box::new(src_path.clone()), ];
for src_path in src_paths {
let src_path = src_path.as_ref();
let _cd = cd(src_path);
assert_eq!(get_cwd(), to_path_buf(src_path));
let _cd = cd(&original_cwd_path);
assert_eq!(get_cwd(), original_cwd_path);
}
}
#[test]
#[serial]
fn test_cd_with_scope() {
let original_cwd_path = get_cwd();
assert!(original_cwd_path.ends_with("file_io"));
let src_path = original_cwd_path.join("src");
let src_paths: Vec<Box<dyn AsRef<Path>>> = vec![
Box::new(src_path.to_str().unwrap()), Box::new(src_path.to_str().unwrap().to_string()), Box::new(src_path.as_path()), Box::new(src_path.clone()), ];
for src_path in src_paths {
let src_path = src_path.as_ref();
{
let _cd = cd(src_path);
assert_eq!(get_cwd(), to_path_buf(src_path));
}
assert_eq!(get_cwd(), original_cwd_path);
}
}
#[test]
#[serial]
fn test_cd_with_panic() {
let temp_dir = tempdir().unwrap();
let temp_dir_path = get_temp_dir_path(&temp_dir);
let original_cwd_path = get_cwd();
let new_cwd_path = temp_dir_path.join("subfolder");
create_folder(&new_cwd_path);
let result = std::panic::catch_unwind(|| {
let _cd = cd(&temp_dir);
assert_eq!(get_cwd(), new_cwd_path);
panic!("Simulated failure.");
});
assert!(result.is_err());
assert_eq!(get_cwd(), original_cwd_path);
}
}