Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,13 @@ impl<E: std::fmt::Debug> std::fmt::Display for WireframeError<E> {

impl<E> std::error::Error for WireframeError<E>
where
E: std::fmt::Debug + std::error::Error + 'static,
E: std::fmt::Debug + 'static,
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(error) => Some(error),
Self::Protocol(error) => Some(error),
Self::Codec(error) => Some(error),
Self::DuplicateRoute(_) => None,
Self::DuplicateRoute(_) | Self::Protocol(_) => None,
}
}
}
Expand Down
8 changes: 2 additions & 6 deletions src/testkit/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ pub enum TestError {
#[error("{0}")]
Msg(String),
/// Root crate error surfaced while exercising a helper.
#[error("wireframe error: {0}")]
Wireframe(WireframeError),
#[error(transparent)]
Wireframe(#[from] WireframeError),
/// Client-side error surfaced while exercising a helper.
#[cfg(not(loom))]
#[error(transparent)]
Expand Down Expand Up @@ -95,10 +95,6 @@ impl From<&str> for TestError {
fn from(value: &str) -> Self { Self::Msg(value.to_string()) }
}

impl From<WireframeError> for TestError {
fn from(value: WireframeError) -> Self { Self::Wireframe(value) }
}

impl<T> From<tokio::sync::mpsc::error::SendError<T>> for TestError {
fn from(err: tokio::sync::mpsc::error::SendError<T>) -> Self { Self::Msg(err.to_string()) }
}
Expand Down
42 changes: 38 additions & 4 deletions tests/error_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ impl std::error::Error for ProtoErr {}
fn wireframe_error_messages() {
let proto = WireframeError::Protocol(ProtoErr);
assert_eq!(proto.to_string(), "protocol error: ProtoErr");
let proto_source = proto
.source()
.expect("protocol variant must expose its underlying source");
assert_eq!(proto_source.to_string(), "boom");
assert!(
proto.source().is_none(),
"Protocol variants should not expose a source without specialization"
);

let duplicate_route = WireframeError::<ProtoErr>::DuplicateRoute(7);
assert_eq!(
Expand All @@ -50,6 +50,40 @@ fn wireframe_error_messages() {
);
}

#[test]
fn wireframe_error_unit_implements_error() {
let io = WireframeError::<()>::from_io(io::Error::other("socket closed"));
let io_source = io
.source()
.expect("io variant must expose its underlying source")
.downcast_ref::<io::Error>()
.expect("io source should be std::io::Error");
assert_eq!(io_source.to_string(), "socket closed");

let codec = WireframeError::<()>::from_codec(CodecError::from(FramingError::EmptyFrame));
let codec_source = codec
.source()
.expect("codec variant must expose its underlying source")
.downcast_ref::<CodecError>()
.expect("codec source should be wireframe::codec::CodecError");
assert!(
matches!(codec_source, CodecError::Framing(FramingError::EmptyFrame)),
"codec source should preserve the original framing error"
);

let protocol = WireframeError::<()>::Protocol(());
assert!(
protocol.source().is_none(),
"unit protocol errors should not expose an error source"
);

let duplicate_route = WireframeError::<()>::DuplicateRoute(7);
assert!(
duplicate_route.source().is_none(),
"DuplicateRoute should not expose an error source"
);
}

#[test]
fn wireframe_error_exposes_sources_for_io_and_codec() {
let io = WireframeError::<ProtoErr>::from_io(io::Error::other("socket closed"));
Expand Down
Loading