1use thiserror::Error;
2
3#[derive(Error, Debug, Clone)]
5pub enum FeedError {
6 #[error("XML parsing error: {0}")]
8 XmlError(String),
9
10 #[error("IO error: {0}")]
12 IoError(String),
13
14 #[error("Invalid feed format: {0}")]
16 InvalidFormat(String),
17
18 #[error("Encoding error: {0}")]
20 EncodingError(String),
21
22 #[error("JSON parsing error: {0}")]
24 JsonError(String),
25
26 #[error("HTTP error: {message}")]
28 Http {
29 message: String,
31 },
32
33 #[error("URL parsing error: {0}")]
35 UrlError(String),
36
37 #[error("Unknown error: {0}")]
39 Unknown(String),
40}
41
42pub type Result<T> = std::result::Result<T, FeedError>;
44
45impl From<quick_xml::Error> for FeedError {
46 fn from(err: quick_xml::Error) -> Self {
47 Self::XmlError(err.to_string())
48 }
49}
50
51impl From<serde_json::Error> for FeedError {
52 fn from(err: serde_json::Error) -> Self {
53 Self::JsonError(err.to_string())
54 }
55}
56
57impl From<std::io::Error> for FeedError {
58 fn from(err: std::io::Error) -> Self {
59 Self::IoError(err.to_string())
60 }
61}
62
63impl From<url::ParseError> for FeedError {
64 fn from(err: url::ParseError) -> Self {
65 Self::UrlError(err.to_string())
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn test_error_display() {
75 let err = FeedError::XmlError("test".to_string());
76 assert_eq!(err.to_string(), "XML parsing error: test");
77 }
78
79 #[test]
80 fn test_error_from_io() {
81 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
82 let feed_err = FeedError::from(io_err);
83 assert!(matches!(feed_err, FeedError::IoError(_)));
84 }
85
86 #[test]
87 #[allow(clippy::unnecessary_wraps)]
88 fn test_result_type() {
89 fn get_result() -> Result<i32> {
90 Ok(42)
91 }
92 let result = get_result();
93 assert!(result.is_ok());
94 assert_eq!(result.expect("should be ok"), 42);
95
96 let error: Result<i32> = Err(FeedError::Unknown("test".to_string()));
97 assert!(error.is_err());
98 }
99}