Skip to content
This repository has been archived by the owner on Aug 16, 2021. It is now read-only.

Commit

Permalink
Forward Display implementation for foreign errors
Browse files Browse the repository at this point in the history
  • Loading branch information
cramertj committed Jul 28, 2016
1 parent af80ff1 commit bed8310
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 8 deletions.
19 changes: 14 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,16 @@ macro_rules! error_chain {
fn cause(&self) -> Option<&::std::error::Error> {
match (self.1).0 {
Some(ref c) => Some(&**c),
None => None
None => {
match self.0 {
$(
$error_kind_name::$foreign_link_variant(ref foreign_err) => {
foreign_err.cause()
}
) *
_ => None
}
}
}
}
}
Expand All @@ -467,9 +476,8 @@ macro_rules! error_chain {
impl From<$foreign_link_error_path> for $error_name {
fn from(e: $foreign_link_error_path) -> Self {
$error_name(
$error_kind_name::$foreign_link_variant,
(Some(Box::new(e)),
::std::sync::Arc::new($crate::Backtrace::new())))
$error_kind_name::$foreign_link_variant(e),
(None, ::std::sync::Arc::new($crate::Backtrace::new())))
}
}
) *
Expand Down Expand Up @@ -516,8 +524,9 @@ macro_rules! error_chain {
) *

$(
$foreign_link_variant {
$foreign_link_variant(err: $foreign_link_error_path) {
description(&$foreign_link_desc)
display("{}", err)
}
) *

Expand Down
105 changes: 102 additions & 3 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn smoke_test_1() {

foreign_links { }

errors { }
errors { }
}
}

Expand All @@ -27,7 +27,7 @@ fn smoke_test_2() {

foreign_links { }

errors { }
errors { }
}
}

Expand All @@ -38,7 +38,7 @@ fn smoke_test_3() {

foreign_links { }

errors { }
errors { }
}
}

Expand Down Expand Up @@ -75,3 +75,102 @@ fn smoke_test_5() {
}
}
}

#[cfg(test)]
mod foreign_link_test {

use std::error::Error as StdError;
use std::fmt;

// Note: foreign errors must be `pub` because they appear in the
// signature of the public foreign_link_error_path
#[derive(Debug)]
pub struct ForeignError {
cause: ForeignErrorCause
}

impl StdError for ForeignError {
fn description(&self) -> &'static str {
"Foreign error description"
}

fn cause(&self) -> Option<&StdError> { Some(&self.cause) }
}

impl fmt::Display for ForeignError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "Foreign error display")
}
}

#[derive(Debug)]
pub struct ForeignErrorCause {}

impl StdError for ForeignErrorCause {
fn description(&self) -> &'static str {
"Foreign error cause description"
}

fn cause(&self) -> Option<&StdError> { None }
}

impl fmt::Display for ForeignErrorCause {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "Foreign error cause display")
}
}

error_chain! {
types{
Error, ErrorKind, ChainErr, Result;
}
links {}
foreign_links {
ForeignError, Foreign, "some foreign error";
}
errors {}
}

#[test]
fn display_underlying_error() {
let chained_error = try_foreign_error().err().unwrap();
assert_eq!(
format!("{}", ForeignError{ cause: ForeignErrorCause{} }),
format!("{}", chained_error)
);
}

#[test]
fn finds_cause() {
let chained_error = try_foreign_error().err().unwrap();
assert_eq!(
format!("{}", ForeignErrorCause{}),
format!("{}", chained_error.cause().unwrap())
);
}

#[test]
fn iterates() {
let chained_error = try_foreign_error().err().unwrap();
let mut error_iter = chained_error.iter();
assert_eq!(
format!("{}", ForeignError{ cause: ForeignErrorCause{} }),
format!("{}", error_iter.next().unwrap())
);
assert_eq!(
format!("{}", ForeignErrorCause{}),
format!("{}", error_iter.next().unwrap())
);
assert_eq!(
format!("{:?}", None as Option<&StdError>),
format!("{:?}", error_iter.next())
);
}

fn try_foreign_error() -> Result<()> {
try!(Err(ForeignError{
cause: ForeignErrorCause{}
}));
Ok(())
}
}

0 comments on commit bed8310

Please sign in to comment.