use std::io;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum RouterError {
#[error("Configuration error: {0}")]
Config(String),
#[error("Network error on endpoint '{endpoint}': {source}")]
Network {
endpoint: String,
#[source]
source: io::Error,
},
#[error("Serial port error on '{device}': {source}")]
Serial {
device: String,
#[source]
source: tokio_serial::Error,
},
#[error("Filesystem error at '{path}': {source}")]
Filesystem {
path: String,
#[source]
source: io::Error,
},
#[error("Internal error: {0}")]
Internal(String),
}
pub type Result<T> = std::result::Result<T, RouterError>;
impl RouterError {
pub fn config(msg: impl Into<String>) -> Self {
Self::Config(msg.into())
}
pub fn network(endpoint: impl Into<String>, source: io::Error) -> Self {
Self::Network {
endpoint: endpoint.into(),
source,
}
}
pub fn serial(device: impl Into<String>, source: tokio_serial::Error) -> Self {
Self::Serial {
device: device.into(),
source,
}
}
pub fn filesystem(path: impl Into<String>, source: io::Error) -> Self {
Self::Filesystem {
path: path.into(),
source,
}
}
}
impl From<anyhow::Error> for RouterError {
fn from(err: anyhow::Error) -> Self {
Self::Internal(err.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config_error_creation() {
let err = RouterError::config("invalid setting");
assert!(matches!(err, RouterError::Config(_)));
assert!(err.to_string().contains("invalid setting"));
}
#[test]
fn test_network_error_creation() {
let io_err = io::Error::new(io::ErrorKind::ConnectionRefused, "refused");
let err = RouterError::network("127.0.0.1:5760", io_err);
assert!(matches!(err, RouterError::Network { .. }));
assert!(err.to_string().contains("127.0.0.1:5760"));
}
#[test]
fn test_filesystem_error_creation() {
let io_err = io::Error::new(io::ErrorKind::NotFound, "not found");
let err = RouterError::filesystem("/var/log/test.log", io_err);
assert!(matches!(err, RouterError::Filesystem { .. }));
assert!(err.to_string().contains("/var/log/test.log"));
}
#[test]
fn test_io_error_requires_context() {
let io_err = io::Error::new(io::ErrorKind::BrokenPipe, "broken");
let router_err = RouterError::network("test-endpoint", io_err);
assert!(matches!(router_err, RouterError::Network { .. }));
assert!(router_err.to_string().contains("test-endpoint"));
}
#[test]
fn test_anyhow_error_conversion() {
let anyhow_err = anyhow::anyhow!("something went wrong");
let router_err: RouterError = anyhow_err.into();
assert!(matches!(router_err, RouterError::Internal(_)));
assert!(router_err.to_string().contains("something went wrong"));
}
}