entrenar/train/tui/
config.rs1use super::callback::TerminalMonitorCallback;
6use super::capability::{DashboardLayout, TerminalCapabilities, TerminalMode};
7
8#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
10#[serde(default)]
11pub struct MonitorConfig {
12 pub enabled: bool,
14 pub layout: String,
16 pub terminal_mode: String,
18 pub refresh_ms: u64,
20 pub sparkline_width: usize,
22 pub show_eta: bool,
24 pub reference_curve: Option<String>,
26}
27
28impl Default for MonitorConfig {
29 fn default() -> Self {
30 Self {
31 enabled: true,
32 layout: "compact".to_string(),
33 terminal_mode: "auto".to_string(),
34 refresh_ms: 100,
35 sparkline_width: 20,
36 show_eta: true,
37 reference_curve: None,
38 }
39 }
40}
41
42impl MonitorConfig {
43 pub fn to_callback(&self) -> TerminalMonitorCallback {
45 let layout = match self.layout.as_str() {
46 "minimal" => DashboardLayout::Minimal,
47 "full" => DashboardLayout::Full,
48 "compact" => DashboardLayout::Compact,
49 _ => {
50 eprintln!("Warning: unknown layout '{}', defaulting to Compact", self.layout);
51 DashboardLayout::Compact
52 }
53 };
54
55 let mode = match self.terminal_mode.as_str() {
56 "ascii" => TerminalMode::Ascii,
57 "ansi" => TerminalMode::Ansi,
58 "unicode" => TerminalMode::Unicode,
59 "auto" => TerminalCapabilities::detect().recommended_mode(),
60 _ => {
61 eprintln!(
62 "Warning: unknown terminal_mode '{}', defaulting to auto-detect",
63 self.terminal_mode
64 );
65 TerminalCapabilities::detect().recommended_mode()
66 }
67 };
68
69 TerminalMonitorCallback::new()
70 .layout(layout)
71 .mode(mode)
72 .sparkline_width(self.sparkline_width)
73 .refresh_interval_ms(self.refresh_ms)
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn test_monitor_config_default() {
83 let config = MonitorConfig::default();
84 assert!(config.enabled);
85 assert_eq!(config.layout, "compact");
86 assert_eq!(config.terminal_mode, "auto");
87 assert_eq!(config.refresh_ms, 100);
88 assert_eq!(config.sparkline_width, 20);
89 assert!(config.show_eta);
90 assert!(config.reference_curve.is_none());
91 }
92
93 #[test]
94 fn test_monitor_config_to_callback() {
95 let config = MonitorConfig::default();
96 let _callback = config.to_callback();
97 }
99
100 #[test]
101 fn test_monitor_config_to_callback_minimal() {
102 let config = MonitorConfig { layout: "minimal".to_string(), ..Default::default() };
103 let _callback = config.to_callback();
104 }
105
106 #[test]
107 fn test_monitor_config_to_callback_full() {
108 let config = MonitorConfig { layout: "full".to_string(), ..Default::default() };
109 let _callback = config.to_callback();
110 }
111
112 #[test]
113 fn test_monitor_config_to_callback_ascii() {
114 let config = MonitorConfig { terminal_mode: "ascii".to_string(), ..Default::default() };
115 let _callback = config.to_callback();
116 }
117
118 #[test]
119 fn test_monitor_config_to_callback_ansi() {
120 let config = MonitorConfig { terminal_mode: "ansi".to_string(), ..Default::default() };
121 let _callback = config.to_callback();
122 }
123
124 #[test]
125 fn test_monitor_config_serde_roundtrip() {
126 let config = MonitorConfig {
127 enabled: true,
128 layout: "full".to_string(),
129 terminal_mode: "unicode".to_string(),
130 refresh_ms: 200,
131 sparkline_width: 30,
132 show_eta: false,
133 reference_curve: Some("golden.json".to_string()),
134 };
135
136 let yaml = serde_yaml::to_string(&config).expect("config should be valid");
137 let parsed: MonitorConfig = serde_yaml::from_str(&yaml).expect("parsing should succeed");
138
139 assert_eq!(parsed.enabled, config.enabled);
140 assert_eq!(parsed.layout, config.layout);
141 assert_eq!(parsed.terminal_mode, config.terminal_mode);
142 assert_eq!(parsed.refresh_ms, config.refresh_ms);
143 assert_eq!(parsed.sparkline_width, config.sparkline_width);
144 assert_eq!(parsed.show_eta, config.show_eta);
145 assert_eq!(parsed.reference_curve, config.reference_curve);
146 }
147
148 #[test]
149 fn test_monitor_config_to_callback_unicode() {
150 let config = MonitorConfig { terminal_mode: "unicode".to_string(), ..Default::default() };
151 let _callback = config.to_callback();
152 }
153
154 #[test]
155 fn test_monitor_config_from_yaml_defaults() {
156 let yaml = "enabled: true\n";
158 let parsed: MonitorConfig = serde_yaml::from_str(yaml).expect("parsing should succeed");
159
160 assert!(parsed.show_eta);
162 assert_eq!(parsed.refresh_ms, 100);
164 assert_eq!(parsed.sparkline_width, 20);
166 }
167
168 #[test]
169 fn test_monitor_config_clone() {
170 let config = MonitorConfig::default();
171 let cloned = config.clone();
172 assert_eq!(config.enabled, cloned.enabled);
173 assert_eq!(config.layout, cloned.layout);
174 }
175
176 #[test]
177 fn test_monitor_config_debug() {
178 let config = MonitorConfig::default();
179 let debug_str = format!("{config:?}");
180 assert!(debug_str.contains("MonitorConfig"));
181 }
182}