use std::fmt;
#[derive(Debug)]
pub enum ReqresError {
Io(std::io::Error),
Connection(String),
InvalidUrl(String),
InvalidResponse(String),
Timeout,
Tls(String),
TooManyRedirects,
Json(serde_json::Error),
Other(String),
}
impl fmt::Display for ReqresError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ReqresError::Io(e) => write!(f, "IO error: {}", e),
ReqresError::Connection(msg) => write!(f, "Connection error: {}", msg),
ReqresError::InvalidUrl(msg) => write!(f, "Invalid URL: {}", msg),
ReqresError::InvalidResponse(msg) => write!(f, "Invalid response: {}", msg),
ReqresError::Timeout => write!(f, "Request timeout"),
ReqresError::Tls(msg) => write!(f, "TLS error: {}", msg),
ReqresError::TooManyRedirects => write!(f, "Too many redirects"),
ReqresError::Json(e) => write!(f, "JSON error: {}", e),
ReqresError::Other(msg) => write!(f, "Error: {}", msg),
}
}
}
impl std::error::Error for ReqresError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
ReqresError::Io(e) => Some(e),
ReqresError::Json(e) => Some(e),
_ => None,
}
}
}
impl From<std::io::Error> for ReqresError {
fn from(err: std::io::Error) -> Self {
ReqresError::Io(err)
}
}
impl From<serde_json::Error> for ReqresError {
fn from(err: serde_json::Error) -> Self {
ReqresError::Json(err)
}
}
impl From<&str> for ReqresError {
fn from(err: &str) -> Self {
ReqresError::Other(err.to_string())
}
}
impl From<String> for ReqresError {
fn from(err: String) -> Self {
ReqresError::Other(err)
}
}
impl From<http::Error> for ReqresError {
fn from(err: http::Error) -> Self {
ReqresError::Other(format!("HTTP error: {}", err))
}
}
impl From<h2::Error> for ReqresError {
fn from(err: h2::Error) -> Self {
ReqresError::Connection(format!("HTTP/2 error: {}", err))
}
}
pub type Result<T> = std::result::Result<T, ReqresError>;
#[cfg(test)]
mod tests {
use super::*;
use std::io;
#[test]
fn test_error_display_io() {
let io_error = io::Error::new(io::ErrorKind::NotFound, "file not found");
let error = ReqresError::Io(io_error);
assert_eq!(error.to_string(), "IO error: file not found");
}
#[test]
fn test_error_display_connection() {
let error = ReqresError::Connection("connection failed".to_string());
assert_eq!(error.to_string(), "Connection error: connection failed");
}
#[test]
fn test_error_display_invalid_url() {
let error = ReqresError::InvalidUrl("missing scheme".to_string());
assert_eq!(error.to_string(), "Invalid URL: missing scheme");
}
#[test]
fn test_error_display_invalid_response() {
let error = ReqresError::InvalidResponse("malformed".to_string());
assert_eq!(error.to_string(), "Invalid response: malformed");
}
#[test]
fn test_error_display_timeout() {
let error = ReqresError::Timeout;
assert_eq!(error.to_string(), "Request timeout");
}
#[test]
fn test_error_display_tls() {
let error = ReqresError::Tls("handshake failed".to_string());
assert_eq!(error.to_string(), "TLS error: handshake failed");
}
#[test]
fn test_error_display_too_many_redirects() {
let error = ReqresError::TooManyRedirects;
assert_eq!(error.to_string(), "Too many redirects");
}
#[test]
fn test_error_display_json() {
let json_error = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
let error = ReqresError::Json(json_error);
assert!(error.to_string().starts_with("JSON error:"));
}
#[test]
fn test_error_display_other() {
let error = ReqresError::Other("custom error".to_string());
assert_eq!(error.to_string(), "Error: custom error");
}
#[test]
fn test_from_io_error() {
let io_error = io::Error::new(io::ErrorKind::PermissionDenied, "access denied");
let reqres_error: ReqresError = io_error.into();
matches!(reqres_error, ReqresError::Io(_));
}
#[test]
fn test_from_json_error() {
let json_error = serde_json::from_str::<serde_json::Value>("invalid").unwrap_err();
let reqres_error: ReqresError = json_error.into();
matches!(reqres_error, ReqresError::Json(_));
}
#[test]
fn test_from_str() {
let error: ReqresError = "test error".into();
assert!(matches!(error, ReqresError::Other(_)));
if let ReqresError::Other(msg) = error {
assert_eq!(msg, "test error");
}
}
#[test]
fn test_from_string() {
let error: ReqresError = "test error".to_string().into();
assert!(matches!(error, ReqresError::Other(_)));
if let ReqresError::Other(msg) = error {
assert_eq!(msg, "test error");
}
}
#[test]
fn test_from_http_error() {
let error = ReqresError::Other("HTTP error: test".to_string());
matches!(error, ReqresError::Other(_));
assert!(error.to_string().contains("HTTP error:"));
}
#[test]
fn test_from_h2_error() {
let h2_error = h2::Error::from(h2::Reason::INTERNAL_ERROR);
let error: ReqresError = h2_error.into();
matches!(error, ReqresError::Connection(_));
assert!(error.to_string().contains("HTTP/2 error:"));
}
#[test]
fn test_result_ok() {
let result: Result<i32> = Ok(42);
assert_eq!(result.unwrap(), 42);
}
#[test]
fn test_result_err() {
let result: Result<i32> = Err(ReqresError::Timeout);
assert!(result.is_err());
}
#[test]
fn test_error_source() {
use std::error::Error as StdError;
let io_error = io::Error::new(io::ErrorKind::Other, "test");
let error = ReqresError::Io(io_error);
assert!(error.source().is_some());
let other_error = ReqresError::Other("test".to_string());
assert!(other_error.source().is_none());
}
#[test]
fn test_error_debug() {
let error = ReqresError::Timeout;
let debug_str = format!("{:?}", error);
assert!(debug_str.contains("Timeout"));
}
#[test]
fn test_error_equality() {
let error1 = ReqresError::Timeout;
let error2 = ReqresError::Timeout;
assert!(matches!(error1, ReqresError::Timeout));
assert!(matches!(error2, ReqresError::Timeout));
}
}