diff --git a/src/push.rs b/src/push.rs index aaeedef2..91f16e37 100644 --- a/src/push.rs +++ b/src/push.rs @@ -45,6 +45,17 @@ pub enum PushError { Closed, } +impl std::fmt::Display for PushError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::QueueFull => f.write_str("push queue full"), + Self::Closed => f.write_str("push queue closed"), + } + } +} + +impl std::error::Error for PushError {} + pub(crate) struct PushHandleInner { high_prio_tx: mpsc::Sender, low_prio_tx: mpsc::Sender, diff --git a/src/response.rs b/src/response.rs index 47f22bfc..9e79e0fd 100644 --- a/src/response.rs +++ b/src/response.rs @@ -89,3 +89,24 @@ impl WireframeError { #[must_use] pub fn from_io(e: std::io::Error) -> Self { WireframeError::Io(e) } } + +impl std::fmt::Display for WireframeError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + WireframeError::Io(e) => write!(f, "transport error: {e}"), + WireframeError::Protocol(e) => write!(f, "protocol error: {e:?}"), + } + } +} + +impl std::error::Error for WireframeError +where + E: std::fmt::Debug + std::error::Error + 'static, +{ + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + WireframeError::Io(e) => Some(e), + WireframeError::Protocol(e) => Some(e), + } + } +} diff --git a/tests/error_display.rs b/tests/error_display.rs new file mode 100644 index 00000000..b79b3149 --- /dev/null +++ b/tests/error_display.rs @@ -0,0 +1,40 @@ +//! Tests for Display and Error trait implementations on error types. +//! +//! Verifies that error types provide human-readable messages via Display +//! and correctly expose underlying error sources via `Error::source`. + +use std::error::Error; + +use wireframe::{push::PushError, response::WireframeError}; + +#[rstest::rstest] +#[case(PushError::QueueFull, "push queue full")] +#[case(PushError::Closed, "push queue closed")] +fn push_error_messages(#[case] err: PushError, #[case] expected: &str) { + assert_eq!(err.to_string(), expected); +} + +#[derive(Debug)] +struct ProtoErr; + +impl std::fmt::Display for ProtoErr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("boom") } +} + +impl std::error::Error for ProtoErr {} + +#[test] +fn wireframe_error_messages() { + let io_error = std::io::Error::other("socket closed"); + let io = WireframeError::::Io(io_error); + assert_eq!(io.to_string(), "transport error: socket closed"); + + let source = io.source().expect("io variant must have source"); + assert_eq!(source.to_string(), "socket closed"); + + let proto = WireframeError::Protocol(ProtoErr); + assert_eq!(proto.to_string(), "protocol error: ProtoErr"); + + let source = proto.source().expect("protocol variant must have source"); + assert_eq!(source.to_string(), "boom"); +}