1use thiserror::Error;
4
5#[derive(Error, Debug)]
7pub enum Error {
8 #[error("Connection error: {0}")]
10 Connection(String),
11
12 #[error("Serial error: {0}")]
14 Serial(#[from] tokio_serial::Error),
15
16 #[error("I/O error: {0}")]
18 Io(#[from] std::io::Error),
19
20 #[error("Protocol error: {0}")]
22 Protocol(String),
23
24 #[error("Timeout waiting for {0}")]
26 Timeout(String),
27
28 #[error("Device error: {0}")]
30 Device(String),
31
32 #[error("Invalid parameter: {0}")]
34 InvalidParameter(String),
35
36 #[error("Feature disabled: {0}")]
38 Disabled(String),
39
40 #[error("Not connected")]
42 NotConnected,
43
44 #[cfg(feature = "ble")]
46 #[error("BLE error: {0}")]
47 Ble(#[from] btleplug::Error),
48
49 #[error("Channel error: {0}")]
51 Channel(String),
52}
53
54impl Error {
55 pub fn connection(msg: impl Into<String>) -> Self {
57 Error::Connection(msg.into())
58 }
59
60 pub fn protocol(msg: impl Into<String>) -> Self {
62 Error::Protocol(msg.into())
63 }
64
65 pub fn timeout(msg: impl Into<String>) -> Self {
67 Error::Timeout(msg.into())
68 }
69
70 pub fn device(msg: impl Into<String>) -> Self {
72 Error::Device(msg.into())
73 }
74
75 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}