1#[derive(Debug, Clone, PartialEq)]
8pub enum AnomalyGridError {
9 SequenceTooShort {
11 expected: usize,
13 actual: usize,
15 operation: String,
17 },
18
19 InvalidMaxOrder {
21 value: usize,
23 context: String,
25 },
26
27 InvalidThreshold {
29 value: f64,
31 expected_range: String,
33 },
34
35 MemoryLimitExceeded {
37 current: usize,
39 limit: usize,
41 suggestion: String,
43 },
44
45 EmptyContextTree {
47 suggestion: String,
49 },
50
51 InvalidConfiguration {
53 parameter: String,
55 value: String,
57 expected: String,
59 },
60}
61
62impl std::fmt::Display for AnomalyGridError {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 match self {
65 AnomalyGridError::SequenceTooShort {
66 expected,
67 actual,
68 operation,
69 } => {
70 write!(
71 f,
72 "Sequence too short for {operation}: expected at least {expected} elements, got {actual}"
73 )
74 }
75 AnomalyGridError::InvalidMaxOrder { value, context } => {
76 write!(f, "Invalid max_order {value}: {context}")
77 }
78 AnomalyGridError::InvalidThreshold {
79 value,
80 expected_range,
81 } => {
82 write!(f, "Invalid threshold {value}: expected {expected_range}")
83 }
84 AnomalyGridError::MemoryLimitExceeded {
85 current,
86 limit,
87 suggestion,
88 } => {
89 write!(
90 f,
91 "Memory limit exceeded: {current} contexts created, limit is {limit}. {suggestion}"
92 )
93 }
94 AnomalyGridError::EmptyContextTree { suggestion } => {
95 write!(
96 f,
97 "Context tree is empty: no training data processed. {suggestion}"
98 )
99 }
100 AnomalyGridError::InvalidConfiguration {
101 parameter,
102 value,
103 expected,
104 } => {
105 write!(
106 f,
107 "Invalid configuration for '{parameter}': got '{value}', expected {expected}"
108 )
109 }
110 }
111 }
112}
113
114impl std::error::Error for AnomalyGridError {}
115
116pub type AnomalyGridResult<T> = std::result::Result<T, AnomalyGridError>;
118
119impl AnomalyGridError {
120 pub fn sequence_too_short(expected: usize, actual: usize, operation: &str) -> Self {
122 Self::SequenceTooShort {
123 expected,
124 actual,
125 operation: operation.to_string(),
126 }
127 }
128
129 pub fn invalid_max_order(value: usize) -> Self {
131 Self::InvalidMaxOrder {
132 value,
133 context: "max_order must be greater than 0".to_string(),
134 }
135 }
136
137 pub fn invalid_threshold(value: f64) -> Self {
139 Self::InvalidThreshold {
140 value,
141 expected_range: "a value between 0.0 and 1.0 (inclusive)".to_string(),
142 }
143 }
144
145 pub fn memory_limit_exceeded(current: usize, limit: usize) -> Self {
147 Self::MemoryLimitExceeded {
148 current,
149 limit,
150 suggestion: "Consider reducing max_order, alphabet size, or increasing memory_limit"
151 .to_string(),
152 }
153 }
154
155 pub fn empty_context_tree() -> Self {
157 Self::EmptyContextTree {
158 suggestion: "Call train() with a valid sequence before detection".to_string(),
159 }
160 }
161
162 pub fn invalid_configuration(parameter: &str, value: &str, expected: &str) -> Self {
164 Self::InvalidConfiguration {
165 parameter: parameter.to_string(),
166 value: value.to_string(),
167 expected: expected.to_string(),
168 }
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 #[test]
177 fn test_sequence_too_short_error() {
178 let error = AnomalyGridError::sequence_too_short(5, 3, "training");
179 let message = error.to_string();
180
181 assert!(message.contains("training"));
182 assert!(message.contains("expected at least 5"));
183 assert!(message.contains("got 3"));
184 }
185
186 #[test]
187 fn test_invalid_max_order_error() {
188 let error = AnomalyGridError::invalid_max_order(0);
189 let message = error.to_string();
190
191 assert!(message.contains("Invalid max_order 0"));
192 assert!(message.contains("must be greater than 0"));
193 }
194
195 #[test]
196 fn test_invalid_threshold_error() {
197 let error = AnomalyGridError::invalid_threshold(1.5);
198 let message = error.to_string();
199
200 assert!(message.contains("Invalid threshold 1.5"));
201 assert!(message.contains("between 0.0 and 1.0"));
202 }
203
204 #[test]
205 fn test_memory_limit_exceeded_error() {
206 let error = AnomalyGridError::memory_limit_exceeded(150000, 100000);
207 let message = error.to_string();
208
209 assert!(message.contains("150000 contexts"));
210 assert!(message.contains("limit is 100000"));
211 assert!(message.contains("Consider reducing"));
212 }
213
214 #[test]
215 fn test_empty_context_tree_error() {
216 let error = AnomalyGridError::empty_context_tree();
217 let message = error.to_string();
218
219 assert!(message.contains("Context tree is empty"));
220 assert!(message.contains("Call train()"));
221 }
222
223 #[test]
224 fn test_error_equality() {
225 let error1 = AnomalyGridError::invalid_max_order(0);
226 let error2 = AnomalyGridError::invalid_max_order(0);
227 let error3 = AnomalyGridError::invalid_max_order(1);
228
229 assert_eq!(error1, error2);
230 assert_ne!(error1, error3);
231 }
232
233 #[test]
234 fn test_error_debug() {
235 let error = AnomalyGridError::sequence_too_short(5, 3, "testing");
236 let debug_str = format!("{error:?}");
237
238 assert!(debug_str.contains("SequenceTooShort"));
239 assert!(debug_str.contains("expected: 5"));
240 assert!(debug_str.contains("actual: 3"));
241 }
242}