1use anyhow::Context;
8use anyhow::Result;
9use std::path::PathBuf;
10
11const TEST_CONFIG_DIR_VAR: &str = "__AGENTIC_CONFIG_DIR_FOR_TESTS";
13
14fn env_path(var: &str) -> Option<PathBuf> {
16 std::env::var(var)
17 .ok()
18 .map(|v| v.trim().to_string())
19 .filter(|v| !v.is_empty())
20 .map(PathBuf::from)
21}
22
23pub fn xdg_config_home() -> Result<PathBuf> {
35 if let Some(p) = env_path(TEST_CONFIG_DIR_VAR) {
36 return Ok(p);
37 }
38 if let Some(p) = env_path("XDG_CONFIG_HOME") {
39 return Ok(p);
40 }
41 let home = env_path("HOME")
42 .or_else(dirs::home_dir)
43 .context("Could not determine $HOME for XDG config path")?;
44 Ok(home.join(".config"))
45}
46
47pub fn agentic_config_dir() -> Result<PathBuf> {
49 Ok(xdg_config_home()?.join("agentic"))
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use crate::test_support::EnvGuard;
56 use serial_test::serial;
57
58 #[test]
59 #[serial]
60 fn test_hook_overrides_xdg() {
61 let _guard = EnvGuard::set(TEST_CONFIG_DIR_VAR, "/test/override");
62 let result = xdg_config_home().unwrap();
63 assert_eq!(result, PathBuf::from("/test/override"));
64 }
65
66 #[test]
67 #[serial]
68 fn test_xdg_config_home_honored() {
69 let _g1 = EnvGuard::remove(TEST_CONFIG_DIR_VAR);
70 let _guard = EnvGuard::set("XDG_CONFIG_HOME", "/custom/config");
71 let result = xdg_config_home().unwrap();
72 assert_eq!(result, PathBuf::from("/custom/config"));
73 }
74
75 #[test]
76 #[serial]
77 fn test_empty_xdg_falls_back_to_home() {
78 let _g1 = EnvGuard::remove(TEST_CONFIG_DIR_VAR);
79 let _g2 = EnvGuard::set("XDG_CONFIG_HOME", "");
80 let _g3 = EnvGuard::set("HOME", "/home/test");
81 let result = xdg_config_home().unwrap();
82 assert_eq!(result, PathBuf::from("/home/test/.config"));
83 }
84
85 #[test]
86 #[serial]
87 fn test_agentic_config_dir() {
88 let _guard = EnvGuard::set(TEST_CONFIG_DIR_VAR, "/test/base");
89 let result = agentic_config_dir().unwrap();
90 assert_eq!(result, PathBuf::from("/test/base/agentic"));
91 }
92}