use super::super::*;
use crate::state::ShellState;
use std::env;
use std::sync::Mutex;
static ENV_LOCK: Mutex<()> = Mutex::new(());
#[test]
fn test_tilde_expansion_unquoted() {
let _lock = ENV_LOCK.lock().unwrap();
let shell_state = ShellState::new();
let home = env::var("HOME").unwrap_or_else(|_| "/home/user".to_string());
let result = lex("echo ~", &shell_state).unwrap();
assert_eq!(
result,
vec![Token::Word("echo".to_string()), Token::Word(home)]
);
}
#[test]
fn test_tilde_expansion_single_quoted() {
let shell_state = ShellState::new();
let result = lex("echo '~'", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word("~".to_string())
]
);
}
#[test]
fn test_tilde_expansion_double_quoted() {
let shell_state = ShellState::new();
let result = lex("echo \"~\"", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word("~".to_string())
]
);
}
#[test]
fn test_tilde_expansion_mixed_quotes() {
let _lock = ENV_LOCK.lock().unwrap();
let shell_state = ShellState::new();
let home = env::var("HOME").unwrap_or_else(|_| "/home/user".to_string());
let result = lex("echo ~ '~' \"~\"", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word(home),
Token::Word("~".to_string()),
Token::Word("~".to_string())
]
);
}
#[test]
fn test_tilde_expansion_pwd() {
let mut shell_state = ShellState::new();
let test_pwd = "/test/current/dir";
shell_state.set_var("PWD", test_pwd.to_string());
let result = lex("echo ~+", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word(test_pwd.to_string())
]
);
}
#[test]
fn test_tilde_expansion_oldpwd() {
let mut shell_state = ShellState::new();
let test_oldpwd = "/test/old/dir";
shell_state.set_var("OLDPWD", test_oldpwd.to_string());
let result = lex("echo ~-", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word(test_oldpwd.to_string())
]
);
}
#[test]
fn test_tilde_expansion_pwd_unset() {
let _lock = ENV_LOCK.lock().unwrap();
let shell_state = ShellState::new();
let result = lex("echo ~+", &shell_state).unwrap();
assert_eq!(result.len(), 2);
assert_eq!(result[0], Token::Word("echo".to_string()));
if let Token::Word(path) = &result[1] {
assert!(path.starts_with('/') || path == "~+");
} else {
panic!("Expected Word token");
}
}
#[test]
fn test_tilde_expansion_oldpwd_unset() {
let _lock = ENV_LOCK.lock().unwrap();
let original_oldpwd = env::var("OLDPWD").ok();
unsafe {
env::remove_var("OLDPWD");
}
let shell_state = ShellState::new();
let result = lex("echo ~-", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word("~-".to_string())
]
);
unsafe {
if let Some(oldpwd) = original_oldpwd {
env::set_var("OLDPWD", oldpwd);
}
}
}
#[test]
fn test_tilde_expansion_pwd_in_quotes() {
let mut shell_state = ShellState::new();
shell_state.set_var("PWD", "/test/dir".to_string());
let result = lex("echo '~+'", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word("~+".to_string())
]
);
let result = lex("echo \"~+\"", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word("~+".to_string())
]
);
}
#[test]
fn test_tilde_expansion_oldpwd_in_quotes() {
let mut shell_state = ShellState::new();
shell_state.set_var("OLDPWD", "/test/old".to_string());
let result = lex("echo '~-'", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word("~-".to_string())
]
);
let result = lex("echo \"~-\"", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word("~-".to_string())
]
);
}
#[test]
fn test_tilde_expansion_mixed() {
let _lock = ENV_LOCK.lock().unwrap();
let mut shell_state = ShellState::new();
let home = env::var("HOME").unwrap_or_else(|_| "/home/user".to_string());
shell_state.set_var("PWD", "/current".to_string());
shell_state.set_var("OLDPWD", "/previous".to_string());
let result = lex("echo ~ ~+ ~-", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word(home),
Token::Word("/current".to_string()),
Token::Word("/previous".to_string())
]
);
}
#[test]
fn test_tilde_expansion_not_at_start() {
let mut shell_state = ShellState::new();
shell_state.set_var("PWD", "/test".to_string());
let result = lex("echo prefix~+", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word("prefix~+".to_string())
]
);
}
#[test]
fn test_tilde_expansion_username() {
let shell_state = ShellState::new();
let result = lex("echo ~root", &shell_state).unwrap();
assert_eq!(result.len(), 2);
assert_eq!(result[0], Token::Word("echo".to_string()));
if let Token::Word(path) = &result[1] {
assert!(path == "/root" || path == "~root");
} else {
panic!("Expected Word token");
}
}
#[test]
fn test_tilde_expansion_username_with_path() {
let shell_state = ShellState::new();
let result = lex("echo ~root/documents", &shell_state).unwrap();
assert_eq!(result.len(), 2);
assert_eq!(result[0], Token::Word("echo".to_string()));
if let Token::Word(path) = &result[1] {
assert!(path == "/root/documents" || path == "~root/documents");
} else {
panic!("Expected Word token");
}
}
#[test]
fn test_tilde_expansion_nonexistent_user() {
let shell_state = ShellState::new();
let result = lex("echo ~nonexistentuser12345", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word("~nonexistentuser12345".to_string())
]
);
}
#[test]
fn test_tilde_expansion_username_in_quotes() {
let shell_state = ShellState::new();
let result = lex("echo '~root'", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word("~root".to_string())
]
);
let result = lex("echo \"~root\"", &shell_state).unwrap();
assert_eq!(
result,
vec![
Token::Word("echo".to_string()),
Token::Word("~root".to_string())
]
);
}
#[test]
fn test_tilde_expansion_mixed_with_username() {
let _lock = ENV_LOCK.lock().unwrap();
let mut shell_state = ShellState::new();
let home = env::var("HOME").unwrap_or_else(|_| "/home/user".to_string());
shell_state.set_var("PWD", "/current".to_string());
let result = lex("echo ~ ~+ ~root", &shell_state).unwrap();
assert_eq!(result.len(), 4);
assert_eq!(result[0], Token::Word("echo".to_string()));
assert_eq!(result[1], Token::Word(home));
assert_eq!(result[2], Token::Word("/current".to_string()));
if let Token::Word(path) = &result[3] {
assert!(path == "/root" || path == "~root");
} else {
panic!("Expected Word token");
}
}
#[test]
fn test_tilde_expansion_username_with_special_chars() {
let shell_state = ShellState::new();
let result = lex("echo ~user@host", &shell_state).unwrap();
assert_eq!(result.len(), 2);
assert_eq!(result[0], Token::Word("echo".to_string()));
if let Token::Word(path) = &result[1] {
assert!(path.contains("@host") || path == "~user@host");
} else {
panic!("Expected Word token");
}
}