use thiserror::Error;
#[derive(Error, Debug)]
pub enum CliError {
#[error("Backend not found: {0}")]
BackendNotFound(String),
#[error("Backend error: {0}")]
BackendError(#[from] canlink_hal::CanError),
#[error("Configuration error: {0}")]
ConfigError(String),
#[error("Invalid argument: {0}")]
InvalidArgument(String),
#[error("I/O error: {0}")]
IoError(#[from] std::io::Error),
#[error("Parse error: {0}")]
ParseError(String),
#[error("Operation timed out")]
Timeout,
#[error("No messages received")]
NoMessages,
}
impl CliError {
pub fn exit_code(&self) -> i32 {
match self {
CliError::BackendNotFound(_) => 2,
CliError::BackendError(_) => 3,
CliError::ConfigError(_) => 4,
CliError::InvalidArgument(_) => 5,
CliError::IoError(_) => 6,
CliError::ParseError(_) => 7,
CliError::Timeout => 8,
CliError::NoMessages => 9,
}
}
}
pub type CliResult<T> = Result<T, CliError>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_exit_codes() {
assert_eq!(CliError::BackendNotFound("test".to_string()).exit_code(), 2);
assert_eq!(CliError::ConfigError("test".to_string()).exit_code(), 4);
assert_eq!(CliError::InvalidArgument("test".to_string()).exit_code(), 5);
assert_eq!(CliError::Timeout.exit_code(), 8);
assert_eq!(CliError::NoMessages.exit_code(), 9);
}
#[test]
fn test_error_display() {
let err = CliError::BackendNotFound("tscan".to_string());
assert_eq!(err.to_string(), "Backend not found: tscan");
let err = CliError::InvalidArgument("bad value".to_string());
assert_eq!(err.to_string(), "Invalid argument: bad value");
}
#[test]
fn test_error_from_io() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
let cli_err: CliError = io_err.into();
assert!(matches!(cli_err, CliError::IoError(_)));
}
}