1use thiserror::Error;
4
5#[derive(Error, Debug)]
7pub enum CgCommonError {
8 #[error("HTTP request failed: {0}")]
9 RequestError(#[from] reqwest::Error),
10
11 #[error("JSON parsing error: {0}")]
12 JsonError(#[from] serde_json::Error),
13
14 #[error("IO error: {0}")]
15 IoError(#[from] std::io::Error),
16
17 #[error("Rate limit exceeded: {0}")]
18 RateLimitExceeded(String),
19
20 #[error("Server error ({0}): {1}")]
21 ServerError(u16, String),
22
23 #[error("Client error ({0}): {1}")]
24 ClientError(u16, String),
25
26 #[error("API error: {0}")]
27 ApiError(String),
28
29 #[error("Data parsing error: {0}")]
30 DataError(String),
31
32 #[error("Request timeout: {0}")]
33 TimeoutError(String),
34
35 #[error("Max retries exceeded ({0})")]
36 MaxRetriesExceeded(u32),
37
38 #[error("Invalid coin ID or symbol: {0}")]
39 InvalidCoinId(String),
40
41 #[error("No data available: {0}")]
42 NoData(String),
43}
44
45pub type Result<T> = std::result::Result<T, CgCommonError>;
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn test_error_display() {
54 let err = CgCommonError::RateLimitExceeded("api.coingecko.com".to_string());
55 assert!(err.to_string().contains("Rate limit"));
56 }
57
58 #[test]
59 fn test_error_from_io() {
60 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
61 let err: CgCommonError = io_err.into();
62 assert!(matches!(err, CgCommonError::IoError(_)));
63 }
64
65 #[test]
66 fn test_server_error_display() {
67 let err = CgCommonError::ServerError(500, "Internal Server Error".to_string());
68 let display = err.to_string();
69 assert!(display.contains("500"));
70 assert!(display.contains("Internal Server Error"));
71 }
72
73 #[test]
74 fn test_invalid_coin_id() {
75 let err = CgCommonError::InvalidCoinId("INVALID".to_string());
76 assert!(err.to_string().contains("INVALID"));
77 }
78}