Files
wraith/crates/wraith-core/src/error.rs

153 lines
4.4 KiB
Rust

use std::io;
#[derive(Debug, thiserror::Error)]
pub enum TransportError {
#[error("connection failed")]
ConnectionFailed,
#[error("handshake failed")]
HandshakeFailed {
#[source]
source: io::Error,
},
#[error("transport timeout")]
Timeout,
#[error("proxy failed")]
ProxyFailed {
#[source]
source: io::Error,
},
}
#[derive(Debug, PartialEq, thiserror::Error)]
pub enum AuthError {
#[error("key rejected")]
KeyRejected,
#[error("certificate invalid")]
CertInvalid,
#[error("certificate expired")]
CertExpired,
#[error("certificate principal mismatch")]
CertPrincipalMismatch,
#[error("no matching key")]
NoMatchingKey,
}
#[derive(Debug, thiserror::Error)]
pub enum ChannelError {
#[error("target unreachable")]
TargetUnreachable,
#[error("proxy connect failed")]
ProxyConnectFailed {
#[source]
source: io::Error,
},
#[error("channel closed")]
ChannelClosed,
}
#[derive(Debug, thiserror::Error)]
pub enum ConfigError {
#[error("invalid flag: {name}")]
InvalidFlag { name: String },
#[error("key file not found: {path}")]
KeyFileNotFound { path: String },
#[error("bind failed")]
BindFailed {
#[source]
source: io::Error,
},
#[error("incompatible options")]
IncompatibleOptions,
}
#[cfg(test)]
mod tests {
use super::*;
use std::error::Error;
#[test]
fn transport_error_display() {
assert_eq!(TransportError::ConnectionFailed.to_string(), "connection failed");
assert_eq!(
TransportError::HandshakeFailed {
source: io::Error::new(io::ErrorKind::ConnectionRefused, "tls failed")
}
.to_string(),
"handshake failed"
);
assert_eq!(TransportError::Timeout.to_string(), "transport timeout");
assert_eq!(
TransportError::ProxyFailed {
source: io::Error::new(io::ErrorKind::ConnectionRefused, "proxy err")
}
.to_string(),
"proxy failed"
);
}
#[test]
fn auth_error_display() {
assert_eq!(AuthError::KeyRejected.to_string(), "key rejected");
assert_eq!(AuthError::CertInvalid.to_string(), "certificate invalid");
assert_eq!(AuthError::CertExpired.to_string(), "certificate expired");
assert_eq!(AuthError::CertPrincipalMismatch.to_string(), "certificate principal mismatch");
assert_eq!(AuthError::NoMatchingKey.to_string(), "no matching key");
}
#[test]
fn channel_error_display() {
assert_eq!(ChannelError::TargetUnreachable.to_string(), "target unreachable");
assert_eq!(
ChannelError::ProxyConnectFailed {
source: io::Error::new(io::ErrorKind::ConnectionRefused, "refused")
}
.to_string(),
"proxy connect failed"
);
assert_eq!(ChannelError::ChannelClosed.to_string(), "channel closed");
}
#[test]
fn config_error_display() {
assert_eq!(
ConfigError::InvalidFlag {
name: "--bad".to_string()
}
.to_string(),
"invalid flag: --bad"
);
assert_eq!(
ConfigError::KeyFileNotFound {
path: "/missing".to_string()
}
.to_string(),
"key file not found: /missing"
);
assert_eq!(
ConfigError::BindFailed {
source: io::Error::new(io::ErrorKind::AddrInUse, "in use")
}
.to_string(),
"bind failed"
);
assert_eq!(ConfigError::IncompatibleOptions.to_string(), "incompatible options");
}
#[test]
fn error_source_chaining() {
let io_err = io::Error::new(io::ErrorKind::ConnectionRefused, "refused");
let transport_err = TransportError::HandshakeFailed { source: io_err };
assert!(transport_err.source().is_some());
let io_err = io::Error::new(io::ErrorKind::ConnectionRefused, "proxy");
let channel_err = ChannelError::ProxyConnectFailed { source: io_err };
assert!(channel_err.source().is_some());
let io_err = io::Error::new(io::ErrorKind::AddrInUse, "addr");
let config_err = ConfigError::BindFailed { source: io_err };
assert!(config_err.source().is_some());
let plain = AuthError::KeyRejected;
assert!(plain.source().is_none());
}
}