use anyhow::{Context, Result};
use std::path::PathBuf;
pub fn get_home_dir() -> Result<PathBuf> {
if let Ok(home) = std::env::var("ATM_HOME") {
let trimmed = home.trim();
if !trimmed.is_empty() {
let path = PathBuf::from(trimmed);
return Ok(path);
}
}
dirs::home_dir().context("Could not determine home directory")
}
pub fn get_os_home_dir() -> Result<PathBuf> {
dirs::home_dir().context("Could not determine OS home directory")
}
#[cfg(test)]
mod tests {
use super::*;
use serial_test::serial;
use std::env;
#[test]
#[serial]
fn test_atm_home_set() {
let original = env::var("ATM_HOME").ok();
unsafe { env::set_var("ATM_HOME", "/custom/home") };
let home = get_home_dir().unwrap();
assert_eq!(home, PathBuf::from("/custom/home"));
unsafe {
match original {
Some(v) => env::set_var("ATM_HOME", v),
None => env::remove_var("ATM_HOME"),
}
}
}
#[test]
#[serial]
fn test_atm_home_not_set_uses_platform_default() {
let original = env::var("ATM_HOME").ok();
unsafe { env::remove_var("ATM_HOME") };
let home = get_home_dir().unwrap();
assert_eq!(home, dirs::home_dir().unwrap());
unsafe {
if let Some(v) = original {
env::set_var("ATM_HOME", v);
}
}
}
#[test]
#[serial]
fn test_atm_home_empty_string_uses_platform_default() {
let original = env::var("ATM_HOME").ok();
unsafe { env::set_var("ATM_HOME", "") };
let home = get_home_dir().unwrap();
assert_eq!(home, dirs::home_dir().unwrap());
unsafe {
match original {
Some(v) => env::set_var("ATM_HOME", v),
None => env::remove_var("ATM_HOME"),
}
}
}
#[test]
#[serial]
fn test_atm_home_whitespace_only_uses_platform_default() {
let original = env::var("ATM_HOME").ok();
unsafe { env::set_var("ATM_HOME", " ") };
let home = get_home_dir().unwrap();
assert_eq!(home, dirs::home_dir().unwrap());
unsafe {
match original {
Some(v) => env::set_var("ATM_HOME", v),
None => env::remove_var("ATM_HOME"),
}
}
}
#[test]
#[serial]
fn test_atm_home_with_trailing_slash() {
let original = env::var("ATM_HOME").ok();
unsafe { env::set_var("ATM_HOME", "/custom/home/") };
let home = get_home_dir().unwrap();
let expected = PathBuf::from("/custom/home/");
assert_eq!(home, expected);
unsafe {
match original {
Some(v) => env::set_var("ATM_HOME", v),
None => env::remove_var("ATM_HOME"),
}
}
}
#[test]
#[serial]
fn test_atm_home_with_spaces_in_path() {
let original = env::var("ATM_HOME").ok();
unsafe { env::set_var("ATM_HOME", "/path with spaces/home") };
let home = get_home_dir().unwrap();
assert_eq!(home, PathBuf::from("/path with spaces/home"));
unsafe {
match original {
Some(v) => env::set_var("ATM_HOME", v),
None => env::remove_var("ATM_HOME"),
}
}
}
#[test]
#[serial]
fn test_atm_home_relative_path() {
let original = env::var("ATM_HOME").ok();
unsafe { env::set_var("ATM_HOME", "relative/path") };
let home = get_home_dir().unwrap();
assert_eq!(home, PathBuf::from("relative/path"));
unsafe {
match original {
Some(v) => env::set_var("ATM_HOME", v),
None => env::remove_var("ATM_HOME"),
}
}
}
#[test]
#[serial]
fn test_atm_home_with_leading_trailing_whitespace() {
let original = env::var("ATM_HOME").ok();
unsafe { env::set_var("ATM_HOME", " /custom/home ") };
let home = get_home_dir().unwrap();
assert_eq!(home, PathBuf::from("/custom/home"));
unsafe {
match original {
Some(v) => env::set_var("ATM_HOME", v),
None => env::remove_var("ATM_HOME"),
}
}
}
#[test]
#[serial]
fn test_multiple_calls_consistent() {
let original = env::var("ATM_HOME").ok();
unsafe { env::set_var("ATM_HOME", "/test/home") };
let home1 = get_home_dir().unwrap();
let home2 = get_home_dir().unwrap();
assert_eq!(home1, home2);
unsafe {
match original {
Some(v) => env::set_var("ATM_HOME", v),
None => env::remove_var("ATM_HOME"),
}
}
}
}