1use std::path::PathBuf;
10
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
15#[serde(default, deny_unknown_fields)]
16#[non_exhaustive]
17pub struct CacheConfig {
18 pub root: Option<PathBuf>,
20}
21
22impl CacheConfig {
23 pub fn new(root: Option<PathBuf>) -> Self {
27 Self { root }
28 }
29
30 pub fn resolve(&self) -> PathBuf {
33 if let Some(p) = &self.root {
34 return p.clone();
35 }
36 if let Ok(custom) = std::env::var(crate::env::VOXORA_CACHE_DIR)
37 && !custom.is_empty()
38 {
39 return PathBuf::from(custom);
40 }
41 if let Some(base) = dirs::cache_dir() {
42 return base.join("voxora");
43 }
44 PathBuf::from(".voxora-cache")
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn default_resolves_via_xdg_or_fallback() {
57 let cfg = CacheConfig::default();
58 let resolved = cfg.resolve();
59 assert!(!resolved.as_os_str().is_empty());
60 let s = resolved.to_string_lossy();
63 assert!(
64 s.ends_with("voxora") || s.ends_with("voxora-cache"),
65 "got {s:?}"
66 );
67 }
68
69 #[test]
70 fn explicit_root_wins() {
71 let cfg = CacheConfig {
72 root: Some(PathBuf::from("/tmp/explicit")),
73 };
74 assert_eq!(cfg.resolve(), PathBuf::from("/tmp/explicit"));
75 }
76
77 #[test]
78 fn new_matches_struct_expression() {
79 let cfg = CacheConfig::new(Some(PathBuf::from("/tmp/via-new")));
80 assert_eq!(
81 cfg,
82 CacheConfig {
83 root: Some(PathBuf::from("/tmp/via-new")),
84 }
85 );
86 }
87}