use crate::{AppErrorKind, Error};
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum TurnkeyErrorKind {
#[error("label already exists")]
UniqueLabel,
#[error("rate limited or throttled")]
RateLimited,
#[error("request timed out")]
Timeout,
#[error("authentication/authorization failed")]
Auth,
#[error("network error")]
Network,
#[error("service error")]
Service
}
#[derive(Debug, Error, Clone, PartialEq, Eq)]
#[error("{kind}: {msg}")]
pub struct TurnkeyError {
pub kind: TurnkeyErrorKind,
pub msg: String
}
impl TurnkeyError {
#[inline]
pub fn new(kind: TurnkeyErrorKind, msg: impl Into<String>) -> Self {
Self {
kind,
msg: msg.into()
}
}
}
#[must_use]
#[inline]
pub fn map_turnkey_kind(kind: TurnkeyErrorKind) -> AppErrorKind {
match kind {
TurnkeyErrorKind::UniqueLabel => AppErrorKind::Conflict,
TurnkeyErrorKind::RateLimited => AppErrorKind::RateLimited,
TurnkeyErrorKind::Timeout => AppErrorKind::Timeout,
TurnkeyErrorKind::Auth => AppErrorKind::Unauthorized,
TurnkeyErrorKind::Network => AppErrorKind::Network,
TurnkeyErrorKind::Service => AppErrorKind::Turnkey,
#[allow(unreachable_patterns)]
_ => AppErrorKind::Turnkey
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn turnkey_error_new_with_string() {
let err = TurnkeyError::new(TurnkeyErrorKind::Timeout, "operation timed out".to_string());
assert_eq!(err.kind, TurnkeyErrorKind::Timeout);
assert_eq!(err.msg, "operation timed out");
}
#[test]
fn turnkey_error_new_with_str() {
let err = TurnkeyError::new(TurnkeyErrorKind::Network, "connection failed");
assert_eq!(err.kind, TurnkeyErrorKind::Network);
assert_eq!(err.msg, "connection failed");
}
#[test]
fn turnkey_error_new_with_empty_message() {
let err = TurnkeyError::new(TurnkeyErrorKind::Service, "");
assert_eq!(err.kind, TurnkeyErrorKind::Service);
assert_eq!(err.msg, "");
}
#[test]
fn turnkey_error_new_with_long_message() {
let long_msg = "a".repeat(1000);
let err = TurnkeyError::new(TurnkeyErrorKind::Auth, &long_msg);
assert_eq!(err.kind, TurnkeyErrorKind::Auth);
assert_eq!(err.msg, long_msg);
}
#[test]
fn turnkey_error_new_with_unicode() {
let err = TurnkeyError::new(TurnkeyErrorKind::RateLimited, "Quota exceeded");
assert_eq!(err.kind, TurnkeyErrorKind::RateLimited);
assert_eq!(err.msg, "Quota exceeded");
}
#[test]
fn turnkey_error_display_format() {
let err = TurnkeyError::new(TurnkeyErrorKind::UniqueLabel, "duplicate resource");
assert_eq!(err.to_string(), "label already exists: duplicate resource");
}
#[test]
fn turnkey_error_display_with_empty_message() {
let err = TurnkeyError::new(TurnkeyErrorKind::Timeout, "");
assert_eq!(err.to_string(), "request timed out: ");
}
#[test]
fn turnkey_error_clone_creates_identical_copy() {
let err1 = TurnkeyError::new(TurnkeyErrorKind::Network, "connection error");
let err2 = err1.clone();
assert_eq!(err1, err2);
assert_eq!(err1.kind, err2.kind);
assert_eq!(err1.msg, err2.msg);
}
#[test]
fn turnkey_error_partial_eq_compares_kind_and_message() {
let err1 = TurnkeyError::new(TurnkeyErrorKind::Auth, "invalid token");
let err2 = TurnkeyError::new(TurnkeyErrorKind::Auth, "invalid token");
let err3 = TurnkeyError::new(TurnkeyErrorKind::Auth, "different message");
let err4 = TurnkeyError::new(TurnkeyErrorKind::Network, "invalid token");
assert_eq!(err1, err2);
assert_ne!(err1, err3);
assert_ne!(err1, err4);
}
#[test]
fn turnkey_error_kind_clone_works() {
let kind1 = TurnkeyErrorKind::Timeout;
let kind2 = kind1;
assert_eq!(kind1, kind2);
}
#[test]
fn turnkey_error_kind_partial_eq_works() {
assert_eq!(TurnkeyErrorKind::UniqueLabel, TurnkeyErrorKind::UniqueLabel);
assert_ne!(TurnkeyErrorKind::UniqueLabel, TurnkeyErrorKind::Timeout);
}
#[test]
fn turnkey_error_kind_display_unique_label() {
assert_eq!(
TurnkeyErrorKind::UniqueLabel.to_string(),
"label already exists"
);
}
#[test]
fn turnkey_error_kind_display_rate_limited() {
assert_eq!(
TurnkeyErrorKind::RateLimited.to_string(),
"rate limited or throttled"
);
}
#[test]
fn turnkey_error_kind_display_timeout() {
assert_eq!(TurnkeyErrorKind::Timeout.to_string(), "request timed out");
}
#[test]
fn turnkey_error_kind_display_auth() {
assert_eq!(
TurnkeyErrorKind::Auth.to_string(),
"authentication/authorization failed"
);
}
#[test]
fn turnkey_error_kind_display_network() {
assert_eq!(TurnkeyErrorKind::Network.to_string(), "network error");
}
#[test]
fn turnkey_error_kind_display_service() {
assert_eq!(TurnkeyErrorKind::Service.to_string(), "service error");
}
#[test]
fn map_turnkey_kind_unique_label() {
assert_eq!(
map_turnkey_kind(TurnkeyErrorKind::UniqueLabel),
AppErrorKind::Conflict
);
}
#[test]
fn map_turnkey_kind_rate_limited() {
assert_eq!(
map_turnkey_kind(TurnkeyErrorKind::RateLimited),
AppErrorKind::RateLimited
);
}
#[test]
fn map_turnkey_kind_timeout() {
assert_eq!(
map_turnkey_kind(TurnkeyErrorKind::Timeout),
AppErrorKind::Timeout
);
}
#[test]
fn map_turnkey_kind_auth() {
assert_eq!(
map_turnkey_kind(TurnkeyErrorKind::Auth),
AppErrorKind::Unauthorized
);
}
#[test]
fn map_turnkey_kind_network() {
assert_eq!(
map_turnkey_kind(TurnkeyErrorKind::Network),
AppErrorKind::Network
);
}
#[test]
fn map_turnkey_kind_service() {
assert_eq!(
map_turnkey_kind(TurnkeyErrorKind::Service),
AppErrorKind::Turnkey
);
}
}