Skip to main content

meshcore_rs/
error.rs

1//! Error types for the MeshCore library
2
3use thiserror::Error;
4
5/// The main error type for MeshCore operations
6#[derive(Error, Debug)]
7pub enum Error {
8    /// Connection-related errors
9    #[error("Connection error: {0}")]
10    Connection(String),
11
12    /// Serial port errors
13    #[error("Serial error: {0}")]
14    Serial(#[from] tokio_serial::Error),
15
16    /// I/O errors
17    #[error("I/O error: {0}")]
18    Io(#[from] std::io::Error),
19
20    /// Protocol errors (malformed packets, unexpected responses)
21    #[error("Protocol error: {0}")]
22    Protocol(String),
23
24    /// Timeout waiting for response
25    #[error("Timeout waiting for {0}")]
26    Timeout(String),
27
28    /// Device returned an error
29    #[error("Device error: {0}")]
30    Device(String),
31
32    /// Invalid parameter provided
33    #[error("Invalid parameter: {0}")]
34    InvalidParameter(String),
35
36    /// Feature is disabled on device
37    #[error("Feature disabled: {0}")]
38    Disabled(String),
39
40    /// Not connected to a device
41    #[error("Not connected")]
42    NotConnected,
43
44    /// BLE-specific errors
45    #[cfg(feature = "ble")]
46    #[error("BLE error: {0}")]
47    Ble(#[from] btleplug::Error),
48
49    /// Channel send error
50    #[error("Channel error: {0}")]
51    Channel(String),
52}
53
54impl Error {
55    /// Create a connection error
56    pub fn connection(msg: impl Into<String>) -> Self {
57        Error::Connection(msg.into())
58    }
59
60    /// Create a protocol error
61    pub fn protocol(msg: impl Into<String>) -> Self {
62        Error::Protocol(msg.into())
63    }
64
65    /// Create a timeout error
66    pub fn timeout(msg: impl Into<String>) -> Self {
67        Error::Timeout(msg.into())
68    }
69
70    /// Create a device error
71    pub fn device(msg: impl Into<String>) -> Self {
72        Error::Device(msg.into())
73    }
74
75    /// Create an invalid parameter error
76    pub fn invalid_param(msg: impl Into<String>) -> Self {
77        Error::InvalidParameter(msg.into())
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn test_connection_error() {
87        let err = Error::connection("test connection error");
88        assert!(matches!(err, Error::Connection(_)));
89        assert_eq!(err.to_string(), "Connection error: test connection error");
90    }
91
92    #[test]
93    fn test_protocol_error() {
94        let err = Error::protocol("invalid packet");
95        assert!(matches!(err, Error::Protocol(_)));
96        assert_eq!(err.to_string(), "Protocol error: invalid packet");
97    }
98
99    #[test]
100    fn test_timeout_error() {
101        let err = Error::timeout("response");
102        assert!(matches!(err, Error::Timeout(_)));
103        assert_eq!(err.to_string(), "Timeout waiting for response");
104    }
105
106    #[test]
107    fn test_device_error() {
108        let err = Error::device("busy");
109        assert!(matches!(err, Error::Device(_)));
110        assert_eq!(err.to_string(), "Device error: busy");
111    }
112
113    #[test]
114    fn test_invalid_param_error() {
115        let err = Error::invalid_param("bad value");
116        assert!(matches!(err, Error::InvalidParameter(_)));
117        assert_eq!(err.to_string(), "Invalid parameter: bad value");
118    }
119
120    #[test]
121    fn test_not_connected_error() {
122        let err = Error::NotConnected;
123        assert_eq!(err.to_string(), "Not connected");
124    }
125
126    #[test]
127    fn test_disabled_error() {
128        let err = Error::Disabled("feature X".to_string());
129        assert_eq!(err.to_string(), "Feature disabled: feature X");
130    }
131
132    #[test]
133    fn test_channel_error() {
134        let err = Error::Channel("send failed".to_string());
135        assert_eq!(err.to_string(), "Channel error: send failed");
136    }
137
138    #[test]
139    fn test_from_io_error() {
140        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
141        let err: Error = io_err.into();
142        assert!(matches!(err, Error::Io(_)));
143        assert!(err.to_string().contains("I/O error"));
144    }
145
146    #[test]
147    fn test_error_debug() {
148        let err = Error::connection("test");
149        let debug_str = format!("{:?}", err);
150        assert!(debug_str.contains("Connection"));
151    }
152}