use crate::builtins::check_shell_builtin;
use crate::environment::ENVIRONMENT;
use crate::types::ShadowType;
use once_cell::sync::Lazy;
use std::collections::HashSet;
use std::sync::Mutex;
static MOCK_EXECUTABLES: Lazy<Mutex<HashSet<String>>> = Lazy::new(|| Mutex::new(HashSet::new()));
static USE_MOCK: Lazy<Mutex<bool>> = Lazy::new(|| Mutex::new(false));
#[cfg(test)]
pub fn mock_executable(name: &str) {
MOCK_EXECUTABLES.lock().unwrap().insert(name.to_string());
}
#[allow(dead_code)]
pub fn unmock_executable(name: &str) {
MOCK_EXECUTABLES.lock().unwrap().remove(name);
}
#[cfg(test)]
pub fn enable_mock() {
*USE_MOCK.lock().unwrap() = true;
}
#[allow(dead_code)]
pub fn disable_mock() {
*USE_MOCK.lock().unwrap() = false;
}
#[cfg(test)]
pub fn reset_mock() {
MOCK_EXECUTABLES.lock().unwrap().clear();
*USE_MOCK.lock().unwrap() = false;
}
pub fn check_shadowing(task_name: &str) -> Option<ShadowType> {
if let Some(shadow) = check_shell_builtin(task_name) {
return Some(shadow);
}
check_path_executable(task_name)
}
pub fn check_path_executable(name: &str) -> Option<ShadowType> {
ENVIRONMENT
.lock()
.unwrap()
.check_executable(name)
.map(ShadowType::PathExecutable)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::environment::{reset_to_real_environment, set_test_environment, TestEnvironment};
use serial_test::serial;
#[test]
#[serial]
fn test_check_path_executable() {
let env = TestEnvironment::new()
.with_executable("test_exe1")
.with_executable("test_exe2");
set_test_environment(env);
assert_eq!(
check_path_executable("test_exe1"),
Some(ShadowType::PathExecutable(
"/mock/bin/test_exe1".to_string()
))
);
assert_eq!(
check_path_executable("test_exe2"),
Some(ShadowType::PathExecutable(
"/mock/bin/test_exe2".to_string()
))
);
assert!(check_path_executable("nonexistent_executable_123").is_none());
reset_to_real_environment();
}
#[test]
#[serial]
fn test_check_shadowing_precedence() {
let env = TestEnvironment::new()
.with_shell("/bin/zsh")
.with_executable("cd");
set_test_environment(env);
let result = check_shadowing("cd");
assert!(matches!(result, Some(ShadowType::ShellBuiltin(shell)) if shell == "zsh"));
reset_to_real_environment();
}
#[test]
#[serial]
fn test_check_shadowing_with_invalid_shell() {
let env = TestEnvironment::new()
.with_shell("/bin/invalid_shell")
.with_executable("test_exe");
set_test_environment(env);
let result = check_shadowing("test_exe");
assert!(matches!(result, Some(ShadowType::PathExecutable(_))));
reset_to_real_environment();
}
#[test]
#[serial]
fn test_nonexistent_command() {
let env = TestEnvironment::new().with_shell("/bin/zsh");
set_test_environment(env);
let result = check_shadowing("nonexistentcommandxyz123");
assert!(result.is_none());
reset_to_real_environment();
}
}