Skip to main content

sqry_core/ast/
error.rs

1//! Error types for AST query system
2
3use thiserror::Error;
4
5/// Errors that can occur during AST query operations
6#[derive(Debug, Error)]
7pub enum AstQueryError {
8    /// Query parsing failed
9    #[error("Parse error: {0}")]
10    ParseError(String),
11
12    /// Unknown predicate in query
13    #[error(
14        "Unknown predicate: '{predicate}'. Available: kind, name~=, parent, in, depth, path, lang"
15    )]
16    UnknownPredicate {
17        /// The unknown predicate name
18        predicate: String,
19    },
20
21    /// Invalid regex pattern
22    #[error("Invalid regex pattern: '{pattern}'")]
23    InvalidRegex {
24        /// The invalid regex pattern
25        pattern: String,
26        /// The underlying regex error
27        #[source]
28        source: regex::Error,
29    },
30
31    /// Invalid depth value
32    #[error("Invalid depth value: '{value}' (must be a positive number)")]
33    InvalidDepth {
34        /// The invalid depth value
35        value: String,
36    },
37
38    /// Unexpected token during parsing
39    #[error("Unexpected token: expected {expected}, got {actual}")]
40    UnexpectedToken {
41        /// Expected token description
42        expected: String,
43        /// Actual token received
44        actual: String,
45    },
46
47    /// Context extraction failed
48    #[error("Context extraction failed: {0}")]
49    ContextExtraction(String),
50
51    /// I/O error
52    #[error(transparent)]
53    Io(#[from] std::io::Error),
54}
55
56/// Convenience type alias for Results
57pub type Result<T> = std::result::Result<T, AstQueryError>;
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use std::error::Error;
63
64    #[test]
65    fn test_error_display_messages() {
66        let cases = vec![
67            (
68                AstQueryError::UnknownPredicate {
69                    predicate: "foo".to_string(),
70                },
71                "Unknown predicate: 'foo'",
72            ),
73            (
74                AstQueryError::InvalidDepth {
75                    value: "abc".to_string(),
76                },
77                "Invalid depth value: 'abc'",
78            ),
79            (
80                AstQueryError::ParseError("test".to_string()),
81                "Parse error: test",
82            ),
83        ];
84
85        for (error, expected) in cases {
86            assert!(
87                error.to_string().contains(expected),
88                "Error message '{error}' should contain '{expected}'"
89            );
90        }
91    }
92
93    #[test]
94    #[allow(clippy::invalid_regex)]
95    fn test_error_source_chaining() {
96        let regex_err = regex::Regex::new("[invalid").unwrap_err();
97        let ast_err = AstQueryError::InvalidRegex {
98            pattern: "[invalid".to_string(),
99            source: regex_err,
100        };
101
102        assert!(ast_err.source().is_some(), "Error should have source");
103    }
104}