Skip to main content

minecraft_pinger/
error.rs

1use hickory_resolver::net::NetError;
2use std::string::FromUtf8Error;
3use thiserror::Error;
4use tokio::time::error::Elapsed;
5
6#[derive(Debug, Error)]
7pub enum PingError {
8    #[error("I/O error: {0}")]
9    Io(#[from] std::io::Error),
10
11    #[error("Global ping timeout for {0}")]
12    Timeout(#[from] Elapsed),
13
14    #[error("Connection refused")]
15    ConnectionRefused,
16
17    #[error("Failed to send packet")]
18    SendPacket,
19
20    #[error("Failed to read packet: {0}")]
21    ReadPacket(String),
22
23    #[error("Invalid UTF-8: {0}")]
24    Utf8Error(#[from] FromUtf8Error),
25
26    #[error("Serialization error: {0}")]
27    Serialization(#[from] serde_json::Error),
28
29    #[error("DNS parse error: {0}")]
30    DnsParse(#[source] NetError),
31
32    #[error("DNS IP not found")]
33    DnsIpNotFound,
34
35    #[error("Address parse error: {0}")]
36    AddressParse(#[source] NetError),
37
38    #[error("Failed to parse response")]
39    ParseResponse,
40
41    #[error("Initialization error: {0}")]
42    Init(String),
43
44    #[error("Endpoint blocked by IP filter: {0}")]
45    BlockedEndpoint(String),
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51    use std::error::Error;
52    use std::io;
53
54    #[test]
55    fn test_ping_error_io() {
56        let io_error = io::Error::new(io::ErrorKind::ConnectionRefused, "connection refused");
57        let ping_error: PingError = io_error.into();
58
59        match ping_error {
60            PingError::Io(_) => {}
61            _ => panic!("Expected Io error"),
62        }
63        assert!(ping_error.to_string().contains("I/O error"));
64    }
65
66    #[test]
67    fn test_ping_error_timeout() {
68        // Test that the timeout error type exists
69        // Note: Elapsed has no public constructor, so we can't easily create this variant
70        // We just verify the enum variant exists
71        let _ = PingError::Timeout;
72        // If this compiles, the variant exists
73    }
74
75    #[test]
76    fn test_ping_error_connection_refused() {
77        let ping_error = PingError::ConnectionRefused;
78        assert_eq!(ping_error.to_string(), "Connection refused");
79    }
80
81    #[test]
82    fn test_ping_error_send_packet() {
83        let ping_error = PingError::SendPacket;
84        assert_eq!(ping_error.to_string(), "Failed to send packet");
85    }
86
87    #[test]
88    fn test_ping_error_read_packet() {
89        let ping_error = PingError::ReadPacket("test error".to_string());
90        assert_eq!(ping_error.to_string(), "Failed to read packet: test error");
91    }
92
93    #[test]
94    fn test_ping_error_utf8_error() {
95        let utf8_error = String::from_utf8(vec![0xFF, 0xFE]).unwrap_err();
96        let ping_error: PingError = utf8_error.into();
97
98        match ping_error {
99            PingError::Utf8Error(_) => {}
100            _ => panic!("Expected Utf8Error"),
101        }
102        assert!(ping_error.to_string().contains("Invalid UTF-8"));
103    }
104
105    #[test]
106    fn test_ping_error_serialization() {
107        let json_error = serde_json::from_str::<serde_json::Value>("invalid").unwrap_err();
108        let ping_error: PingError = json_error.into();
109
110        match ping_error {
111            PingError::Serialization(_) => {}
112            _ => panic!("Expected Serialization error"),
113        }
114        assert!(ping_error.to_string().contains("Serialization error"));
115    }
116
117    #[test]
118    fn test_ping_error_dns_parse() {
119        let ping_error = PingError::DnsParse("test".into());
120        assert!(ping_error.to_string().contains("DNS parse error"));
121    }
122
123    #[test]
124    fn test_ping_error_dns_ip_not_found() {
125        let ping_error = PingError::DnsIpNotFound;
126        assert_eq!(ping_error.to_string(), "DNS IP not found");
127    }
128
129    #[test]
130    fn test_ping_error_address_parse() {
131        let ping_error = PingError::AddressParse("test".into());
132        assert!(ping_error.to_string().contains("Address parse error"));
133    }
134
135    #[test]
136    fn test_ping_error_parse_response() {
137        let ping_error = PingError::ParseResponse;
138        assert_eq!(ping_error.to_string(), "Failed to parse response");
139    }
140
141    #[test]
142    fn test_ping_error_init() {
143        let ping_error = PingError::Init("test init error".to_string());
144        assert_eq!(
145            ping_error.to_string(),
146            "Initialization error: test init error"
147        );
148    }
149
150    #[test]
151    fn test_ping_error_blocked_endpoint() {
152        let ping_error = PingError::BlockedEndpoint("10.0.0.1".to_string());
153        assert_eq!(
154            ping_error.to_string(),
155            "Endpoint blocked by IP filter: 10.0.0.1"
156        );
157    }
158
159    #[test]
160    fn test_ping_error_debug() {
161        let ping_error = PingError::ConnectionRefused;
162        let debug_str = format!("{:?}", ping_error);
163        assert!(debug_str.contains("ConnectionRefused"));
164    }
165
166    #[test]
167    fn test_ping_error_source() {
168        let io_error = io::Error::new(io::ErrorKind::ConnectionRefused, "test");
169        let ping_error: PingError = io_error.into();
170        assert!(Error::source(&ping_error).is_some());
171    }
172}