1#![allow(dead_code)]
2use std::{io, net::IpAddr};
3
4use thiserror::Error;
5
6use crate::{icmp::PingSequence, PingIdentifier};
7
8pub type Result<T> = std::result::Result<T, SurgeError>;
9
10#[derive(Error, Debug)]
13pub enum SurgeError {
14 #[error("buffer size was too small")]
15 IncorrectBufferSize,
16 #[error("malformed packet: {0}")]
17 MalformedPacket(#[from] MalformedPacketError),
18 #[error("io error: {0}")]
19 IOError(#[from] io::Error),
20 #[error("Request timeout for icmp_seq {seq}")]
21 Timeout { seq: PingSequence },
22 #[error("Echo Request packet.")]
23 EchoRequestPacket,
24 #[error("Network error.")]
25 NetworkError,
26 #[error("Multiple identical request")]
27 IdenticalRequests {
28 host: IpAddr,
29 ident: Option<PingIdentifier>,
30 seq: PingSequence,
31 },
32 #[error("Client has been destroyed, ping operations are no longer available")]
33 ClientDestroyed,
34}
35
36#[derive(Error, Debug)]
37pub enum MalformedPacketError {
38 #[error("expected an Ipv4Packet")]
39 NotIpv4Packet,
40 #[error("expected an Ipv6Packet")]
41 NotIpv6Packet,
42 #[error("expected an Icmpv4Packet payload")]
43 NotIcmpv4Packet,
44 #[error("expected an Icmpv6Packet")]
45 NotIcmpv6Packet,
46 #[error("payload too short, got {got}, want {want}")]
47 PayloadTooShort { got: usize, want: usize },
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn test_surge_error_display() {
56 let err = SurgeError::IncorrectBufferSize;
57 assert_eq!(err.to_string(), "buffer size was too small");
58
59 let err = SurgeError::NetworkError;
60 assert_eq!(err.to_string(), "Network error.");
61
62 let err = SurgeError::EchoRequestPacket;
63 assert_eq!(err.to_string(), "Echo Request packet.");
64
65 let err = SurgeError::ClientDestroyed;
66 assert_eq!(
67 err.to_string(),
68 "Client has been destroyed, ping operations are no longer available"
69 );
70 }
71
72 #[test]
73 fn test_surge_error_timeout() {
74 let err = SurgeError::Timeout { seq: PingSequence(5) };
75 assert_eq!(err.to_string(), "Request timeout for icmp_seq 5");
76 }
77
78 #[test]
79 fn test_surge_error_identical_requests() {
80 let host: IpAddr = "192.168.1.1".parse().unwrap();
81 let err = SurgeError::IdenticalRequests {
82 host,
83 ident: Some(PingIdentifier(42)),
84 seq: PingSequence(10),
85 };
86 assert_eq!(
87 err.to_string(),
88 "Multiple identical request"
89 );
90 }
91
92 #[test]
93 fn test_malformed_packet_error_display() {
94 let err = MalformedPacketError::NotIpv4Packet;
95 assert_eq!(err.to_string(), "expected an Ipv4Packet");
96
97 let err = MalformedPacketError::NotIpv6Packet;
98 assert_eq!(err.to_string(), "expected an Ipv6Packet");
99
100 let err = MalformedPacketError::NotIcmpv4Packet;
101 assert_eq!(err.to_string(), "expected an Icmpv4Packet payload");
102
103 let err = MalformedPacketError::NotIcmpv6Packet;
104 assert_eq!(err.to_string(), "expected an Icmpv6Packet");
105 }
106
107 #[test]
108 fn test_malformed_packet_error_payload_too_short() {
109 let err = MalformedPacketError::PayloadTooShort { got: 10, want: 20 };
110 assert_eq!(err.to_string(), "payload too short, got 10, want 20");
111 }
112
113 #[test]
114 fn test_surge_error_from_io() {
115 let io_err = io::Error::new(io::ErrorKind::PermissionDenied, "test");
116 let surge_err: SurgeError = io_err.into();
117 assert!(matches!(surge_err, SurgeError::IOError(_)));
118 }
119
120 #[test]
121 fn test_surge_error_from_malformed_packet() {
122 let malformed_err = MalformedPacketError::NotIpv4Packet;
123 let surge_err: SurgeError = malformed_err.into();
124 assert!(matches!(surge_err, SurgeError::MalformedPacket(_)));
125 }
126}