aptu_core/config/
graph.rs1use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Deserialize, Serialize, Clone)]
19#[serde(default)]
20pub struct GraphConfig {
21 #[serde(default = "default_enabled")]
23 pub enabled: bool,
24 #[serde(default = "default_cache_ttl_hours")]
26 pub cache_ttl_hours: u64,
27 #[serde(default = "default_max_nodes")]
29 pub max_nodes: usize,
30}
31
32fn default_enabled() -> bool {
33 false
34}
35
36fn default_cache_ttl_hours() -> u64 {
37 24
38}
39
40fn default_max_nodes() -> usize {
41 50_000
42}
43
44impl Default for GraphConfig {
45 fn default() -> Self {
46 Self {
47 enabled: default_enabled(),
48 cache_ttl_hours: default_cache_ttl_hours(),
49 max_nodes: default_max_nodes(),
50 }
51 }
52}
53
54impl GraphConfig {
55 #[must_use]
60 pub fn validate_consistency(&self) -> Vec<String> {
61 let mut warnings = Vec::new();
62
63 if self.enabled && self.max_nodes == 0 {
64 warnings.push(
65 "max_nodes is 0 while graph is enabled: blast-radius subgraph will always be empty"
66 .to_string(),
67 );
68 }
69
70 if self.enabled && self.cache_ttl_hours == 0 {
71 warnings.push(
72 "cache_ttl_hours is 0 while graph is enabled: cache is rebuilt on every review"
73 .to_string(),
74 );
75 }
76
77 warnings
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_default_disabled() {
87 let config = GraphConfig::default();
88 assert!(!config.enabled, "graph should be disabled by default");
89 assert_eq!(config.cache_ttl_hours, 24);
90 assert_eq!(config.max_nodes, 50_000);
91 }
92
93 #[test]
94 fn test_validate_consistency_ok() {
95 let config = GraphConfig::default();
96 let warnings = config.validate_consistency();
97 assert!(
98 warnings.is_empty(),
99 "default config should produce no warnings: {:?}",
100 warnings
101 );
102 }
103
104 #[test]
105 fn test_validate_consistency_zero_max_nodes_enabled() {
106 let config = GraphConfig {
107 enabled: true,
108 max_nodes: 0,
109 ..GraphConfig::default()
110 };
111 let warnings = config.validate_consistency();
112 assert_eq!(warnings.len(), 1, "should produce exactly 1 warning");
113 assert!(warnings[0].contains("max_nodes is 0"));
114 }
115
116 #[test]
117 fn test_deserializes_from_toml_with_missing_fields() {
118 let toml_str = "";
119 let config: GraphConfig = toml::from_str(toml_str).unwrap();
120 assert!(!config.enabled);
121 assert_eq!(config.cache_ttl_hours, 24);
122 assert_eq!(config.max_nodes, 50_000);
123 }
124}