use std::{env, io::ErrorKind, path::Path};
use crate::{fs_path::{FsOpError, FsOpResult},
ok};
#[macro_export]
macro_rules! serial_preserve_pwd_test {
($name:ident, $block:block) => {
#[serial_test::serial]
#[test]
fn $name() {
$crate::with_saved_pwd!($block);
}
};
}
#[macro_export]
macro_rules! serial_async_test_with_safe_cd {
($name:ident, $block:block) => {
#[tokio::test]
#[serial_test::serial]
async fn $name() -> miette::Result<()> {
let og_pwd = std::env::current_dir().unwrap();
let result = { $block };
std::env::set_current_dir(og_pwd).unwrap();
result
}
};
}
#[macro_export]
macro_rules! with_saved_pwd {
($block:block) => {{
let og_pwd = std::env::current_dir().unwrap();
let result = { $block };
std::env::set_current_dir(og_pwd).unwrap();
result
}};
}
pub fn try_cd(new_dir: impl AsRef<Path>) -> FsOpResult<()> {
match env::set_current_dir(new_dir.as_ref()) {
Ok(_) => ok!(),
Err(err) => match err.kind() {
ErrorKind::NotFound => {
FsOpResult::Err(FsOpError::DirectoryDoesNotExist(err.to_string()))
}
ErrorKind::PermissionDenied => {
FsOpResult::Err(FsOpError::PermissionDenied(err.to_string()))
}
ErrorKind::InvalidInput => {
FsOpResult::Err(FsOpError::InvalidName(err.to_string()))
}
_ => FsOpResult::Err(FsOpError::IoError(err)),
},
}
}
#[cfg(test)]
mod tests_directory_change {
use std::{fs, os::unix::fs::PermissionsExt as _};
use super::*;
use crate::{directory_change::try_cd,
fs_path::FsOpError,
fs_paths,
try_create_temp_dir};
serial_preserve_pwd_test!(test_try_change_directory_permissions_errors, {
let root = try_create_temp_dir().unwrap();
let new_tmp_dir =
fs_paths!(with_root: root => "test_change_dir_permissions_errors");
fs::create_dir_all(&new_tmp_dir).unwrap();
assert!(new_tmp_dir.exists());
let no_permissions_dir =
fs_paths!(with_root: new_tmp_dir => "no_permissions_dir");
fs::create_dir_all(&no_permissions_dir).unwrap();
let mut permissions = fs::metadata(&no_permissions_dir).unwrap().permissions();
permissions.set_mode(0o000);
fs::set_permissions(&no_permissions_dir, permissions).unwrap();
assert!(no_permissions_dir.exists());
let result = try_cd(&no_permissions_dir);
println!("✅ err: {result:?}");
assert!(result.is_err());
assert!(matches!(result, Err(FsOpError::PermissionDenied(_))));
let mut permissions = fs::metadata(&no_permissions_dir).unwrap().permissions();
permissions.set_mode(0o777);
fs::set_permissions(&no_permissions_dir, permissions).unwrap();
});
serial_preserve_pwd_test!(test_try_change_directory_happy_path, {
let root = try_create_temp_dir().unwrap();
let new_tmp_dir = fs_paths!(with_root: root => "test_change_dir_happy_path");
fs::create_dir_all(&new_tmp_dir).unwrap();
assert!(new_tmp_dir.exists());
try_cd(&new_tmp_dir).unwrap();
assert_eq!(env::current_dir().unwrap(), new_tmp_dir);
try_cd(&root).unwrap();
assert_eq!(env::current_dir().unwrap(), *root);
});
serial_preserve_pwd_test!(test_try_change_directory_non_existent, {
let root = try_create_temp_dir().unwrap();
let new_tmp_dir = fs_paths!(with_root: root => "test_change_dir_non_existent");
fs::create_dir_all(&new_tmp_dir).unwrap();
assert!(new_tmp_dir.exists());
let non_existent_dir = fs_paths!(with_root: new_tmp_dir => "non_existent_dir");
let result = try_cd(&non_existent_dir);
assert!(result.is_err());
assert!(matches!(result, Err(FsOpError::DirectoryDoesNotExist(_))));
try_cd(&root).unwrap();
assert_eq!(env::current_dir().unwrap(), *root);
});
serial_preserve_pwd_test!(test_try_change_directory_invalid_name, {
let root = try_create_temp_dir().unwrap();
let new_tmp_dir = fs_paths!(with_root: root => "test_change_dir_invalid_name");
fs::create_dir_all(&new_tmp_dir).unwrap();
assert!(new_tmp_dir.exists());
let invalid_name_dir = fs_paths!(with_root: new_tmp_dir => "invalid_name_dir\0");
let result = try_cd(&invalid_name_dir);
assert!(result.is_err());
println!("✅ err: {result:?}");
assert!(matches!(result, Err(FsOpError::InvalidName(_))));
try_cd(&root).unwrap();
assert_eq!(env::current_dir().unwrap(), *root);
});
}