Skip to main content

fhp_core/
error.rs

1/// Errors that can occur during HTML parsing.
2#[derive(Debug, thiserror::Error)]
3pub enum ParseError {
4    /// Encountered an unexpected byte during tokenization.
5    #[error("unexpected byte 0x{byte:02X} at offset {offset}")]
6    UnexpectedByte {
7        /// The byte value encountered.
8        byte: u8,
9        /// The byte offset in the input.
10        offset: usize,
11    },
12
13    /// The input ended in the middle of a token.
14    #[error("unexpected end of input at offset {offset}, state: {state}")]
15    UnexpectedEof {
16        /// The byte offset where input ended.
17        offset: usize,
18        /// Description of the tokenizer state when EOF was hit.
19        state: &'static str,
20    },
21
22    /// A nesting depth limit was exceeded.
23    #[error("nesting depth limit exceeded ({depth} > {limit})")]
24    NestingTooDeep {
25        /// Current depth.
26        depth: u32,
27        /// Configured limit.
28        limit: u32,
29    },
30}
31
32/// Errors that can occur during CSS selector parsing.
33#[derive(Debug, thiserror::Error)]
34pub enum SelectorError {
35    /// Invalid selector syntax.
36    #[error("invalid selector: {reason}")]
37    Invalid {
38        /// Description of what went wrong.
39        reason: String,
40    },
41}
42
43/// Errors that can occur during XPath expression parsing or evaluation.
44#[derive(Debug, thiserror::Error)]
45pub enum XPathError {
46    /// Invalid XPath syntax.
47    #[error("invalid xpath: {reason}")]
48    Invalid {
49        /// Description of what went wrong.
50        reason: String,
51    },
52}
53
54/// Errors that can occur during encoding detection or conversion.
55#[derive(Debug, thiserror::Error)]
56pub enum EncodingError {
57    /// The decoder encountered bytes that could not be mapped to Unicode.
58    #[error("decode error: malformed {encoding} input at byte offset {offset}")]
59    MalformedInput {
60        /// Name of the encoding being decoded.
61        encoding: &'static str,
62        /// Approximate byte offset of the first invalid sequence.
63        offset: usize,
64    },
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn parse_error_display() {
73        let err = ParseError::UnexpectedByte {
74            byte: 0xFF,
75            offset: 42,
76        };
77        assert_eq!(err.to_string(), "unexpected byte 0xFF at offset 42");
78    }
79
80    #[test]
81    fn selector_error_display() {
82        let err = SelectorError::Invalid {
83            reason: "unclosed bracket".to_string(),
84        };
85        assert_eq!(err.to_string(), "invalid selector: unclosed bracket");
86    }
87
88    #[test]
89    fn xpath_error_display() {
90        let err = XPathError::Invalid {
91            reason: "unexpected token".to_string(),
92        };
93        assert_eq!(err.to_string(), "invalid xpath: unexpected token");
94    }
95
96    #[test]
97    fn encoding_error_display() {
98        let err = EncodingError::MalformedInput {
99            encoding: "windows-1252",
100            offset: 42,
101        };
102        assert_eq!(
103            err.to_string(),
104            "decode error: malformed windows-1252 input at byte offset 42"
105        );
106    }
107
108    #[test]
109    fn nesting_error_display() {
110        let err = ParseError::NestingTooDeep {
111            depth: 513,
112            limit: 512,
113        };
114        assert_eq!(err.to_string(), "nesting depth limit exceeded (513 > 512)");
115    }
116}