oxihuman_core/
result_stack.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, PartialEq)]
9pub enum ResultKind {
10 Ok,
11 Err,
12 Skipped,
13}
14
15#[derive(Debug, Clone)]
16pub struct ResultEntry {
17 pub kind: ResultKind,
18 pub message: String,
19 pub code: i32,
20}
21
22pub struct ResultStack {
24 entries: Vec<ResultEntry>,
25 ok_count: usize,
26 err_count: usize,
27 skip_count: usize,
28}
29
30#[allow(dead_code)]
31impl ResultStack {
32 pub fn new() -> Self {
33 ResultStack {
34 entries: Vec::new(),
35 ok_count: 0,
36 err_count: 0,
37 skip_count: 0,
38 }
39 }
40
41 pub fn push_ok(&mut self, msg: &str) {
42 self.entries.push(ResultEntry {
43 kind: ResultKind::Ok,
44 message: msg.to_string(),
45 code: 0,
46 });
47 self.ok_count += 1;
48 }
49
50 pub fn push_err(&mut self, msg: &str, code: i32) {
51 self.entries.push(ResultEntry {
52 kind: ResultKind::Err,
53 message: msg.to_string(),
54 code,
55 });
56 self.err_count += 1;
57 }
58
59 pub fn push_skipped(&mut self, msg: &str) {
60 self.entries.push(ResultEntry {
61 kind: ResultKind::Skipped,
62 message: msg.to_string(),
63 code: 0,
64 });
65 self.skip_count += 1;
66 }
67
68 pub fn pop(&mut self) -> Option<ResultEntry> {
69 let entry = self.entries.pop()?;
70 match entry.kind {
71 ResultKind::Ok => self.ok_count -= 1,
72 ResultKind::Err => self.err_count -= 1,
73 ResultKind::Skipped => self.skip_count -= 1,
74 }
75 Some(entry)
76 }
77
78 pub fn peek(&self) -> Option<&ResultEntry> {
79 self.entries.last()
80 }
81
82 pub fn has_errors(&self) -> bool {
83 self.err_count > 0
84 }
85
86 pub fn all_ok(&self) -> bool {
87 self.err_count == 0 && self.skip_count == 0 && self.ok_count > 0
88 }
89
90 pub fn ok_count(&self) -> usize {
91 self.ok_count
92 }
93
94 pub fn err_count(&self) -> usize {
95 self.err_count
96 }
97
98 pub fn skip_count(&self) -> usize {
99 self.skip_count
100 }
101
102 pub fn len(&self) -> usize {
103 self.entries.len()
104 }
105
106 pub fn is_empty(&self) -> bool {
107 self.entries.is_empty()
108 }
109
110 pub fn clear(&mut self) {
111 self.entries.clear();
112 self.ok_count = 0;
113 self.err_count = 0;
114 self.skip_count = 0;
115 }
116
117 pub fn errors(&self) -> Vec<&ResultEntry> {
118 self.entries
119 .iter()
120 .filter(|e| e.kind == ResultKind::Err)
121 .collect()
122 }
123
124 pub fn to_summary(&self) -> String {
125 format!(
126 "ok={} err={} skip={}",
127 self.ok_count, self.err_count, self.skip_count
128 )
129 }
130}
131
132impl Default for ResultStack {
133 fn default() -> Self {
134 Self::new()
135 }
136}
137
138pub fn new_result_stack() -> ResultStack {
139 ResultStack::new()
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn push_ok_increments() {
148 let mut s = new_result_stack();
149 s.push_ok("done");
150 assert_eq!(s.ok_count(), 1);
151 assert!(!s.has_errors());
152 }
153
154 #[test]
155 fn push_err_tracked() {
156 let mut s = new_result_stack();
157 s.push_err("fail", -1);
158 assert!(s.has_errors());
159 assert_eq!(s.err_count(), 1);
160 }
161
162 #[test]
163 fn push_skipped() {
164 let mut s = new_result_stack();
165 s.push_skipped("skip me");
166 assert_eq!(s.skip_count(), 1);
167 }
168
169 #[test]
170 fn pop_updates_counts() {
171 let mut s = new_result_stack();
172 s.push_ok("a");
173 s.pop();
174 assert_eq!(s.ok_count(), 0);
175 }
176
177 #[test]
178 fn all_ok_flag() {
179 let mut s = new_result_stack();
180 s.push_ok("a");
181 s.push_ok("b");
182 assert!(s.all_ok());
183 s.push_err("bad", 1);
184 assert!(!s.all_ok());
185 }
186
187 #[test]
188 fn errors_filter() {
189 let mut s = new_result_stack();
190 s.push_ok("ok");
191 s.push_err("e1", 1);
192 s.push_err("e2", 2);
193 assert_eq!(s.errors().len(), 2);
194 }
195
196 #[test]
197 fn clear_resets() {
198 let mut s = new_result_stack();
199 s.push_ok("a");
200 s.push_err("b", 1);
201 s.clear();
202 assert!(s.is_empty());
203 assert_eq!(s.ok_count(), 0);
204 }
205
206 #[test]
207 fn summary_string() {
208 let mut s = new_result_stack();
209 s.push_ok("a");
210 s.push_err("b", 1);
211 s.push_skipped("c");
212 let summary = s.to_summary();
213 assert!(summary.contains("ok=1"));
214 assert!(summary.contains("err=1"));
215 }
216
217 #[test]
218 fn peek_last() {
219 let mut s = new_result_stack();
220 s.push_ok("first");
221 s.push_err("second", 2);
222 assert_eq!(s.peek().expect("should succeed").kind, ResultKind::Err);
223 }
224}