oxihuman_core/
debug_console.rs1#[allow(dead_code)]
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6pub enum ConsoleSeverity {
7 Debug,
8 Info,
9 Warn,
10 Error,
11}
12
13#[allow(dead_code)]
15#[derive(Clone, Debug)]
16pub struct ConsoleEntry {
17 pub severity: ConsoleSeverity,
18 pub message: String,
19 pub index: usize,
20}
21
22#[allow(dead_code)]
24pub struct DebugConsoleConfig {
25 pub max_entries: usize,
27}
28
29#[allow(dead_code)]
31pub struct DebugConsole {
32 pub entries: Vec<ConsoleEntry>,
33 pub config: DebugConsoleConfig,
34 next_index: usize,
35}
36
37#[allow(dead_code)]
39pub fn default_debug_console_config() -> DebugConsoleConfig {
40 DebugConsoleConfig { max_entries: 1000 }
41}
42
43#[allow(dead_code)]
45pub fn new_debug_console(cfg: &DebugConsoleConfig) -> DebugConsole {
46 DebugConsole {
47 entries: Vec::new(),
48 config: DebugConsoleConfig {
49 max_entries: cfg.max_entries,
50 },
51 next_index: 0,
52 }
53}
54
55#[allow(dead_code)]
57pub fn console_log(console: &mut DebugConsole, severity: ConsoleSeverity, message: &str) {
58 let idx = console.next_index;
59 console.next_index += 1;
60 console.entries.push(ConsoleEntry {
61 severity,
62 message: message.to_string(),
63 index: idx,
64 });
65 if console.entries.len() > console.config.max_entries {
66 let overflow = console.entries.len() - console.config.max_entries;
67 console.entries.drain(0..overflow);
68 }
69}
70
71#[allow(dead_code)]
73pub fn console_entry_count(console: &DebugConsole) -> usize {
74 console.entries.len()
75}
76
77#[allow(dead_code)]
79pub fn console_entries_by_severity(
80 console: &DebugConsole,
81 severity: ConsoleSeverity,
82) -> Vec<&ConsoleEntry> {
83 console
84 .entries
85 .iter()
86 .filter(|e| e.severity == severity)
87 .collect()
88}
89
90#[allow(dead_code)]
92pub fn console_clear(console: &mut DebugConsole) {
93 console.entries.clear();
94}
95
96#[allow(dead_code)]
98pub fn console_last_entry(console: &DebugConsole) -> Option<&ConsoleEntry> {
99 console.entries.last()
100}
101
102#[allow(dead_code)]
104pub fn console_error_count(console: &DebugConsole) -> usize {
105 console
106 .entries
107 .iter()
108 .filter(|e| e.severity == ConsoleSeverity::Error)
109 .count()
110}
111
112#[allow(dead_code)]
114pub fn console_to_string(console: &DebugConsole) -> String {
115 console
116 .entries
117 .iter()
118 .map(|e| format!("[{}] {}", severity_name(e.severity), e.message))
119 .collect::<Vec<_>>()
120 .join("\n")
121}
122
123#[allow(dead_code)]
125pub fn severity_name(s: ConsoleSeverity) -> &'static str {
126 match s {
127 ConsoleSeverity::Debug => "DEBUG",
128 ConsoleSeverity::Info => "INFO",
129 ConsoleSeverity::Warn => "WARN",
130 ConsoleSeverity::Error => "ERROR",
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 fn make_console() -> DebugConsole {
139 let cfg = default_debug_console_config();
140 new_debug_console(&cfg)
141 }
142
143 #[test]
144 fn test_new_console_empty() {
145 let c = make_console();
146 assert_eq!(console_entry_count(&c), 0);
147 assert!(console_last_entry(&c).is_none());
148 }
149
150 #[test]
151 fn test_console_log_info() {
152 let mut c = make_console();
153 console_log(&mut c, ConsoleSeverity::Info, "hello");
154 assert_eq!(console_entry_count(&c), 1);
155 let last = console_last_entry(&c).expect("should succeed");
156 assert_eq!(last.message, "hello");
157 assert_eq!(last.severity, ConsoleSeverity::Info);
158 }
159
160 #[test]
161 fn test_console_entries_by_severity() {
162 let mut c = make_console();
163 console_log(&mut c, ConsoleSeverity::Info, "info msg");
164 console_log(&mut c, ConsoleSeverity::Error, "error msg");
165 console_log(&mut c, ConsoleSeverity::Warn, "warn msg");
166 let errors = console_entries_by_severity(&c, ConsoleSeverity::Error);
167 assert_eq!(errors.len(), 1);
168 assert_eq!(errors[0].message, "error msg");
169 }
170
171 #[test]
172 fn test_console_clear() {
173 let mut c = make_console();
174 console_log(&mut c, ConsoleSeverity::Debug, "d1");
175 console_log(&mut c, ConsoleSeverity::Debug, "d2");
176 console_clear(&mut c);
177 assert_eq!(console_entry_count(&c), 0);
178 assert!(console_last_entry(&c).is_none());
179 }
180
181 #[test]
182 fn test_console_error_count() {
183 let mut c = make_console();
184 console_log(&mut c, ConsoleSeverity::Info, "i1");
185 console_log(&mut c, ConsoleSeverity::Error, "e1");
186 console_log(&mut c, ConsoleSeverity::Error, "e2");
187 assert_eq!(console_error_count(&c), 2);
188 }
189
190 #[test]
191 fn test_console_to_string() {
192 let mut c = make_console();
193 console_log(&mut c, ConsoleSeverity::Info, "startup");
194 console_log(&mut c, ConsoleSeverity::Warn, "low memory");
195 let s = console_to_string(&c);
196 assert!(s.contains("[INFO] startup"));
197 assert!(s.contains("[WARN] low memory"));
198 }
199
200 #[test]
201 fn test_severity_name() {
202 assert_eq!(severity_name(ConsoleSeverity::Debug), "DEBUG");
203 assert_eq!(severity_name(ConsoleSeverity::Info), "INFO");
204 assert_eq!(severity_name(ConsoleSeverity::Warn), "WARN");
205 assert_eq!(severity_name(ConsoleSeverity::Error), "ERROR");
206 }
207
208 #[test]
209 fn test_max_entries_trimmed() {
210 let cfg = DebugConsoleConfig { max_entries: 3 };
211 let mut c = new_debug_console(&cfg);
212 for i in 0..5 {
213 console_log(&mut c, ConsoleSeverity::Info, &format!("msg {}", i));
214 }
215 assert_eq!(console_entry_count(&c), 3);
216 assert_eq!(
218 console_last_entry(&c).expect("should succeed").message,
219 "msg 4"
220 );
221 }
222
223 #[test]
224 fn test_console_last_entry_multiple() {
225 let mut c = make_console();
226 console_log(&mut c, ConsoleSeverity::Info, "first");
227 console_log(&mut c, ConsoleSeverity::Error, "last");
228 let last = console_last_entry(&c).expect("should succeed");
229 assert_eq!(last.message, "last");
230 assert_eq!(last.severity, ConsoleSeverity::Error);
231 }
232
233 #[test]
234 fn test_entries_by_severity_empty_result() {
235 let mut c = make_console();
236 console_log(&mut c, ConsoleSeverity::Info, "info only");
237 let debug_entries = console_entries_by_severity(&c, ConsoleSeverity::Debug);
238 assert!(debug_entries.is_empty());
239 }
240}