1use std::path::PathBuf;
12
13fn home_dir() -> Option<PathBuf> {
15 std::env::var_os("HOME").map(PathBuf::from)
16}
17
18pub fn config_dir() -> Option<PathBuf> {
23 #[cfg(target_os = "macos")]
24 {
25 home_dir().map(|h| h.join("Library/Application Support"))
26 }
27 #[cfg(not(target_os = "macos"))]
28 {
29 std::env::var_os("XDG_CONFIG_HOME")
30 .map(PathBuf::from)
31 .filter(|p| p.is_absolute())
32 .or_else(|| home_dir().map(|h| h.join(".config")))
33 }
34}
35
36pub fn data_dir() -> Option<PathBuf> {
41 #[cfg(target_os = "macos")]
42 {
43 home_dir().map(|h| h.join("Library/Application Support"))
44 }
45 #[cfg(not(target_os = "macos"))]
46 {
47 std::env::var_os("XDG_DATA_HOME")
48 .map(PathBuf::from)
49 .filter(|p| p.is_absolute())
50 .or_else(|| home_dir().map(|h| h.join(".local/share")))
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn config_dir_returns_some_when_home_is_set() {
60 let dir = config_dir();
62 assert!(dir.is_some(), "config_dir should return Some");
63 assert!(dir.unwrap().is_absolute(), "config_dir should be absolute");
64 }
65
66 #[test]
67 fn data_dir_returns_some_when_home_is_set() {
68 let dir = data_dir();
69 assert!(dir.is_some(), "data_dir should return Some");
70 assert!(dir.unwrap().is_absolute(), "data_dir should be absolute");
71 }
72
73 #[test]
74 fn config_and_data_dirs_live_under_home() {
75 let home = home_dir().expect("HOME should be set in tests");
76 let config = config_dir().unwrap();
77 let data = data_dir().unwrap();
78 assert!(
79 config.starts_with(&home),
80 "config_dir {config:?} should be under HOME {home:?}"
81 );
82 assert!(
83 data.starts_with(&home),
84 "data_dir {data:?} should be under HOME {home:?}"
85 );
86 }
87
88 #[test]
89 fn config_and_data_dirs_are_distinct_from_home() {
90 let home = home_dir().unwrap();
91 let config = config_dir().unwrap();
92 let data = data_dir().unwrap();
93 assert_ne!(config, home, "config_dir should not be HOME itself");
94 assert_ne!(data, home, "data_dir should not be HOME itself");
95 }
96}