1use thiserror::Error;
4
5pub type Result<T> = std::result::Result<T, Error>;
7
8#[derive(Debug, Error)]
10pub enum Error {
11 #[error("failed to parse HTML: {message}")]
13 ParseError {
14 message: String,
16 },
17
18 #[error("invalid CSS selector: {selector}")]
20 InvalidSelector {
21 selector: String,
23 },
24
25 #[error("element not found: {query}")]
27 NotFound {
28 query: String,
30 },
31
32 #[error("attribute '{name}' not found on element")]
34 AttributeNotFound {
35 name: String,
37 },
38
39 #[error("I/O error: {0}")]
41 Io(#[from] std::io::Error),
42}
43
44impl Error {
45 #[must_use]
47 pub fn parse(message: impl Into<String>) -> Self {
48 Self::ParseError { message: message.into() }
49 }
50
51 #[must_use]
53 pub fn invalid_selector(selector: impl Into<String>) -> Self {
54 Self::InvalidSelector { selector: selector.into() }
55 }
56
57 #[must_use]
59 pub fn not_found(query: impl Into<String>) -> Self {
60 Self::NotFound { query: query.into() }
61 }
62
63 #[must_use]
65 pub fn attribute_not_found(name: impl Into<String>) -> Self {
66 Self::AttributeNotFound { name: name.into() }
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 #[test]
75 fn test_error_display() {
76 let err = Error::parse("unexpected end of input");
77 assert_eq!(err.to_string(), "failed to parse HTML: unexpected end of input");
78
79 let err = Error::invalid_selector("div[");
80 assert_eq!(err.to_string(), "invalid CSS selector: div[");
81
82 let err = Error::not_found("div.missing");
83 assert_eq!(err.to_string(), "element not found: div.missing");
84
85 let err = Error::attribute_not_found("href");
86 assert_eq!(err.to_string(), "attribute 'href' not found on element");
87 }
88}