1#[derive(Debug, thiserror::Error)]
14pub enum LibmagicError {
15 #[error("Parse error: {0}")]
17 ParseError(#[from] ParseError),
18
19 #[error("Evaluation error: {0}")]
21 EvaluationError(#[from] EvaluationError),
22
23 #[error("I/O error: {0}")]
25 IoError(#[from] std::io::Error),
26
27 #[error("Evaluation timeout exceeded after {timeout_ms}ms")]
29 Timeout {
30 timeout_ms: u64,
32 },
33
34 #[error("Configuration error: {reason}")]
47 ConfigError {
48 reason: String,
50 },
51
52 #[error("File error: {0}")]
67 FileError(String),
68}
69
70#[derive(Debug, thiserror::Error)]
72pub enum ParseError {
73 #[error("Invalid syntax at line {line}: {message}")]
75 InvalidSyntax {
76 line: usize,
78 message: String,
80 },
81
82 #[error("Unsupported feature at line {line}: {feature}")]
84 UnsupportedFeature {
85 line: usize,
87 feature: String,
89 },
90
91 #[error("Invalid offset specification at line {line}: {offset}")]
93 InvalidOffset {
94 line: usize,
96 offset: String,
98 },
99
100 #[error("Invalid type specification at line {line}: {type_spec}")]
102 InvalidType {
103 line: usize,
105 type_spec: String,
107 },
108
109 #[error("Invalid operator at line {line}: {operator}")]
111 InvalidOperator {
112 line: usize,
114 operator: String,
116 },
117
118 #[error("Invalid value at line {line}: {value}")]
120 InvalidValue {
121 line: usize,
123 value: String,
125 },
126
127 #[error("Unsupported format at line {line}: {format_type}\n{message}")]
129 UnsupportedFormat {
130 line: usize,
132 format_type: String,
134 message: String,
136 },
137
138 #[error("I/O error: {0}")]
140 IoError(#[from] std::io::Error),
141}
142
143#[derive(Debug, thiserror::Error)]
145pub enum EvaluationError {
146 #[error("Buffer overrun at offset {offset}")]
148 BufferOverrun {
149 offset: usize,
151 },
152
153 #[error("Invalid offset: {offset}")]
155 InvalidOffset {
156 offset: i64,
158 },
159
160 #[error("Unsupported type: {type_name}")]
162 UnsupportedType {
163 type_name: String,
165 },
166
167 #[error("Recursion limit exceeded (depth: {depth})")]
169 RecursionLimitExceeded {
170 depth: u32,
172 },
173
174 #[error("String length limit exceeded: {length} > {max_length}")]
176 StringLengthExceeded {
177 length: usize,
179 max_length: usize,
181 },
182
183 #[error("Invalid string encoding at offset {offset}")]
185 InvalidStringEncoding {
186 offset: usize,
188 },
189
190 #[error("Evaluation timeout exceeded after {timeout_ms}ms")]
192 Timeout {
193 timeout_ms: u64,
195 },
196
197 #[error("Type reading error: {0}")]
199 TypeReadError(#[from] crate::evaluator::types::TypeReadError),
200
201 #[error("Internal error: {message}")]
203 InternalError {
204 message: String,
206 },
207}
208
209impl ParseError {
210 #[must_use]
212 pub fn invalid_syntax(line: usize, message: impl Into<String>) -> Self {
213 Self::InvalidSyntax {
214 line,
215 message: message.into(),
216 }
217 }
218
219 #[must_use]
221 pub fn unsupported_feature(line: usize, feature: impl Into<String>) -> Self {
222 Self::UnsupportedFeature {
223 line,
224 feature: feature.into(),
225 }
226 }
227
228 #[must_use]
230 pub fn invalid_offset(line: usize, offset: impl Into<String>) -> Self {
231 Self::InvalidOffset {
232 line,
233 offset: offset.into(),
234 }
235 }
236
237 #[must_use]
239 pub fn invalid_type(line: usize, type_spec: impl Into<String>) -> Self {
240 Self::InvalidType {
241 line,
242 type_spec: type_spec.into(),
243 }
244 }
245
246 #[must_use]
248 pub fn invalid_operator(line: usize, operator: impl Into<String>) -> Self {
249 Self::InvalidOperator {
250 line,
251 operator: operator.into(),
252 }
253 }
254
255 #[must_use]
257 pub fn invalid_value(line: usize, value: impl Into<String>) -> Self {
258 Self::InvalidValue {
259 line,
260 value: value.into(),
261 }
262 }
263
264 #[must_use]
266 pub fn unsupported_format(
267 line: usize,
268 format_type: impl Into<String>,
269 message: impl Into<String>,
270 ) -> Self {
271 Self::UnsupportedFormat {
272 line,
273 format_type: format_type.into(),
274 message: message.into(),
275 }
276 }
277}
278
279impl EvaluationError {
280 #[must_use]
282 pub fn buffer_overrun(offset: usize) -> Self {
283 Self::BufferOverrun { offset }
284 }
285
286 #[must_use]
288 pub fn invalid_offset(offset: i64) -> Self {
289 Self::InvalidOffset { offset }
290 }
291
292 #[must_use]
294 pub fn unsupported_type(type_name: impl Into<String>) -> Self {
295 Self::UnsupportedType {
296 type_name: type_name.into(),
297 }
298 }
299
300 #[must_use]
302 pub fn recursion_limit_exceeded(depth: u32) -> Self {
303 Self::RecursionLimitExceeded { depth }
304 }
305
306 #[must_use]
308 pub fn string_length_exceeded(length: usize, max_length: usize) -> Self {
309 Self::StringLengthExceeded { length, max_length }
310 }
311
312 #[must_use]
314 pub fn invalid_string_encoding(offset: usize) -> Self {
315 Self::InvalidStringEncoding { offset }
316 }
317
318 #[must_use]
320 pub fn timeout(timeout_ms: u64) -> Self {
321 Self::Timeout { timeout_ms }
322 }
323
324 #[must_use]
326 pub fn internal_error(message: impl Into<String>) -> Self {
327 Self::InternalError {
328 message: message.into(),
329 }
330 }
331}
332
333#[cfg(test)]
334mod tests {
335 use super::*;
336 use std::io;
337
338 #[test]
339 fn test_libmagic_error_from_parse_error() {
340 let parse_error = ParseError::invalid_syntax(10, "unexpected token");
341 let libmagic_error = LibmagicError::from(parse_error);
342
343 match libmagic_error {
344 LibmagicError::ParseError(_) => (),
345 _ => panic!("Expected ParseError variant"),
346 }
347 }
348
349 #[test]
350 fn test_libmagic_error_from_evaluation_error() {
351 let eval_error = EvaluationError::buffer_overrun(100);
352 let libmagic_error = LibmagicError::from(eval_error);
353
354 match libmagic_error {
355 LibmagicError::EvaluationError(_) => (),
356 _ => panic!("Expected EvaluationError variant"),
357 }
358 }
359
360 #[test]
361 fn test_libmagic_error_from_io_error() {
362 let io_error = io::Error::new(io::ErrorKind::NotFound, "file not found");
363 let libmagic_error = LibmagicError::from(io_error);
364
365 match libmagic_error {
366 LibmagicError::IoError(_) => (),
367 _ => panic!("Expected IoError variant"),
368 }
369 }
370
371 #[test]
372 fn test_parse_error_display() {
373 let error = ParseError::invalid_syntax(5, "missing operator");
374 let display = format!("{error}");
375 assert_eq!(display, "Invalid syntax at line 5: missing operator");
376 }
377
378 #[test]
379 fn test_parse_error_unsupported_feature() {
380 let error = ParseError::unsupported_feature(12, "regex patterns");
381 let display = format!("{error}");
382 assert_eq!(display, "Unsupported feature at line 12: regex patterns");
383 }
384
385 #[test]
386 fn test_parse_error_invalid_offset() {
387 let error = ParseError::invalid_offset(8, "invalid_offset_spec");
388 let display = format!("{error}");
389 assert_eq!(
390 display,
391 "Invalid offset specification at line 8: invalid_offset_spec"
392 );
393 }
394
395 #[test]
396 fn test_parse_error_invalid_type() {
397 let error = ParseError::invalid_type(15, "unknown_type");
398 let display = format!("{error}");
399 assert_eq!(
400 display,
401 "Invalid type specification at line 15: unknown_type"
402 );
403 }
404
405 #[test]
406 fn test_parse_error_invalid_operator() {
407 let error = ParseError::invalid_operator(20, "??");
408 let display = format!("{error}");
409 assert_eq!(display, "Invalid operator at line 20: ??");
410 }
411
412 #[test]
413 fn test_parse_error_invalid_value() {
414 let error = ParseError::invalid_value(25, "malformed_hex");
415 let display = format!("{error}");
416 assert_eq!(display, "Invalid value at line 25: malformed_hex");
417 }
418
419 #[test]
420 fn test_evaluation_error_buffer_overrun() {
421 let error = EvaluationError::buffer_overrun(1024);
422 let display = format!("{error}");
423 assert_eq!(display, "Buffer overrun at offset 1024");
424 }
425
426 #[test]
427 fn test_evaluation_error_invalid_offset() {
428 let error = EvaluationError::invalid_offset(-50);
429 let display = format!("{error}");
430 assert_eq!(display, "Invalid offset: -50");
431 }
432
433 #[test]
434 fn test_evaluation_error_unsupported_type() {
435 let error = EvaluationError::unsupported_type("complex_type");
436 let display = format!("{error}");
437 assert_eq!(display, "Unsupported type: complex_type");
438 }
439
440 #[test]
441 fn test_evaluation_error_recursion_limit() {
442 let error = EvaluationError::recursion_limit_exceeded(100);
443 let display = format!("{error}");
444 assert_eq!(display, "Recursion limit exceeded (depth: 100)");
445 }
446
447 #[test]
448 fn test_evaluation_error_string_length_exceeded() {
449 let error = EvaluationError::string_length_exceeded(2048, 1024);
450 let display = format!("{error}");
451 assert_eq!(display, "String length limit exceeded: 2048 > 1024");
452 }
453
454 #[test]
455 fn test_evaluation_error_invalid_string_encoding() {
456 let error = EvaluationError::invalid_string_encoding(512);
457 let display = format!("{error}");
458 assert_eq!(display, "Invalid string encoding at offset 512");
459 }
460
461 #[test]
462 fn test_evaluation_error_internal_error() {
463 let error = EvaluationError::internal_error("recursion depth underflow");
464 let display = format!("{error}");
465 assert_eq!(display, "Internal error: recursion depth underflow");
466 }
467
468 #[test]
469 fn test_libmagic_error_display_parse() {
470 let parse_error = ParseError::invalid_syntax(10, "unexpected token");
471 let libmagic_error = LibmagicError::from(parse_error);
472 let display = format!("{libmagic_error}");
473 assert_eq!(
474 display,
475 "Parse error: Invalid syntax at line 10: unexpected token"
476 );
477 }
478
479 #[test]
480 fn test_libmagic_error_display_evaluation() {
481 let eval_error = EvaluationError::buffer_overrun(100);
482 let libmagic_error = LibmagicError::from(eval_error);
483 let display = format!("{libmagic_error}");
484 assert_eq!(display, "Evaluation error: Buffer overrun at offset 100");
485 }
486
487 #[test]
488 fn test_libmagic_error_display_io() {
489 let io_error = io::Error::new(io::ErrorKind::PermissionDenied, "access denied");
490 let libmagic_error = LibmagicError::from(io_error);
491 let display = format!("{libmagic_error}");
492 assert!(display.starts_with("I/O error:"));
493 assert!(display.contains("access denied"));
494 }
495
496 #[test]
497 fn test_error_debug_formatting() {
498 let error = LibmagicError::ParseError(ParseError::invalid_syntax(5, "test"));
499 let debug = format!("{error:?}");
500 assert!(debug.contains("ParseError"));
501 assert!(debug.contains("InvalidSyntax"));
502 }
503
504 #[test]
505 fn test_parse_error_constructors() {
506 let error1 = ParseError::invalid_syntax(1, "test");
507 let error2 = ParseError::unsupported_feature(2, "feature");
508 let error3 = ParseError::invalid_offset(3, "offset");
509 let error4 = ParseError::invalid_type(4, "type");
510 let error5 = ParseError::invalid_operator(5, "op");
511 let error6 = ParseError::invalid_value(6, "value");
512
513 assert!(matches!(error1, ParseError::InvalidSyntax { .. }));
515 assert!(matches!(error2, ParseError::UnsupportedFeature { .. }));
516 assert!(matches!(error3, ParseError::InvalidOffset { .. }));
517 assert!(matches!(error4, ParseError::InvalidType { .. }));
518 assert!(matches!(error5, ParseError::InvalidOperator { .. }));
519 assert!(matches!(error6, ParseError::InvalidValue { .. }));
520 }
521
522 #[test]
523 fn test_evaluation_error_constructors() {
524 let error1 = EvaluationError::buffer_overrun(100);
525 let error2 = EvaluationError::invalid_offset(-1);
526 let error3 = EvaluationError::unsupported_type("test");
527 let error4 = EvaluationError::recursion_limit_exceeded(50);
528 let error5 = EvaluationError::string_length_exceeded(100, 50);
529 let error6 = EvaluationError::invalid_string_encoding(200);
530
531 assert!(matches!(error1, EvaluationError::BufferOverrun { .. }));
533 assert!(matches!(error2, EvaluationError::InvalidOffset { .. }));
534 assert!(matches!(error3, EvaluationError::UnsupportedType { .. }));
535 assert!(matches!(
536 error4,
537 EvaluationError::RecursionLimitExceeded { .. }
538 ));
539 assert!(matches!(
540 error5,
541 EvaluationError::StringLengthExceeded { .. }
542 ));
543 assert!(matches!(
544 error6,
545 EvaluationError::InvalidStringEncoding { .. }
546 ));
547 }
548
549 #[test]
550 fn test_parse_error_unsupported_format() {
551 let error = ParseError::unsupported_format(
552 0,
553 "binary .mgc",
554 "Binary files not supported. Use --use-builtin option.",
555 );
556 let display = format!("{error}");
557 assert!(display.contains("Unsupported format"));
558 assert!(display.contains("binary .mgc"));
559 assert!(display.contains("--use-builtin"));
560 }
561
562 #[test]
563 fn test_parse_error_unsupported_format_constructor() {
564 let error = ParseError::unsupported_format(5, "test_format", "test message");
565
566 match error {
567 ParseError::UnsupportedFormat {
568 line,
569 format_type,
570 message,
571 } => {
572 assert_eq!(line, 5);
573 assert_eq!(format_type, "test_format");
574 assert_eq!(message, "test message");
575 }
576 _ => panic!("Expected UnsupportedFormat variant"),
577 }
578 }
579}