|  | #![feature(error_generic_member_access, error_reporter)] | 
|  |  | 
|  | use std::backtrace::Backtrace; | 
|  | use std::error::{Error, Report, Request}; | 
|  | use std::fmt; | 
|  |  | 
|  | #[derive(Debug, PartialEq)] | 
|  | struct A; | 
|  | #[derive(Debug, PartialEq)] | 
|  | struct B; | 
|  |  | 
|  | impl fmt::Display for A { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | write!(f, "A") | 
|  | } | 
|  | } | 
|  | impl fmt::Display for B { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | write!(f, "B") | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Error for A {} | 
|  | impl Error for B {} | 
|  |  | 
|  | #[test] | 
|  | fn downcasting() { | 
|  | let mut a = A; | 
|  | let a = &mut a as &mut (dyn Error + 'static); | 
|  | assert_eq!(a.downcast_ref::<A>(), Some(&A)); | 
|  | assert_eq!(a.downcast_ref::<B>(), None); | 
|  | assert_eq!(a.downcast_mut::<A>(), Some(&mut A)); | 
|  | assert_eq!(a.downcast_mut::<B>(), None); | 
|  |  | 
|  | let a: Box<dyn Error> = Box::new(A); | 
|  | match a.downcast::<B>() { | 
|  | Ok(..) => panic!("expected error"), | 
|  | Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A), | 
|  | } | 
|  | } | 
|  |  | 
|  | #[derive(Debug)] | 
|  | struct SuperError { | 
|  | source: SuperErrorSideKick, | 
|  | } | 
|  |  | 
|  | impl fmt::Display for SuperError { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | write!(f, "SuperError is here!") | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Error for SuperError { | 
|  | fn source(&self) -> Option<&(dyn Error + 'static)> { | 
|  | Some(&self.source) | 
|  | } | 
|  | } | 
|  |  | 
|  | #[derive(Debug)] | 
|  | struct SuperErrorSideKick; | 
|  |  | 
|  | impl fmt::Display for SuperErrorSideKick { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | write!(f, "SuperErrorSideKick is here!") | 
|  | } | 
|  | } | 
|  |  | 
|  | impl Error for SuperErrorSideKick {} | 
|  |  | 
|  | #[test] | 
|  | fn single_line_formatting() { | 
|  | let error = SuperError { source: SuperErrorSideKick }; | 
|  | let report = Report::new(&error); | 
|  | let actual = report.to_string(); | 
|  | let expected = String::from("SuperError is here!: SuperErrorSideKick is here!"); | 
|  |  | 
|  | assert_eq!(expected, actual); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn multi_line_formatting() { | 
|  | let error = SuperError { source: SuperErrorSideKick }; | 
|  | let report = Report::new(&error).pretty(true); | 
|  | let actual = report.to_string(); | 
|  | let expected = String::from( | 
|  | "\ | 
|  | SuperError is here! | 
|  |  | 
|  | Caused by: | 
|  | SuperErrorSideKick is here!", | 
|  | ); | 
|  |  | 
|  | assert_eq!(expected, actual); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn error_with_no_sources_formats_single_line_correctly() { | 
|  | let report = Report::new(SuperErrorSideKick); | 
|  | let actual = report.to_string(); | 
|  | let expected = String::from("SuperErrorSideKick is here!"); | 
|  |  | 
|  | assert_eq!(expected, actual); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn error_with_no_sources_formats_multi_line_correctly() { | 
|  | let report = Report::new(SuperErrorSideKick).pretty(true); | 
|  | let actual = report.to_string(); | 
|  | let expected = String::from("SuperErrorSideKick is here!"); | 
|  |  | 
|  | assert_eq!(expected, actual); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn error_with_backtrace_outputs_correctly_with_one_source() { | 
|  | let trace = Backtrace::force_capture(); | 
|  | let expected = format!( | 
|  | "\ | 
|  | The source of the error | 
|  |  | 
|  | Caused by: | 
|  | Error with backtrace | 
|  |  | 
|  | Stack backtrace: | 
|  | {}", | 
|  | trace | 
|  | ); | 
|  | let error = GenericError::new("Error with backtrace"); | 
|  | let mut error = GenericError::new_with_source("The source of the error", error); | 
|  | error.backtrace = Some(trace); | 
|  | let report = Report::new(error).pretty(true).show_backtrace(true); | 
|  |  | 
|  | println!("Error: {report}"); | 
|  | assert_eq!(expected.trim_end(), report.to_string()); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn error_with_backtrace_outputs_correctly_with_two_sources() { | 
|  | let trace = Backtrace::force_capture(); | 
|  | let expected = format!( | 
|  | "\ | 
|  | Error with two sources | 
|  |  | 
|  | Caused by: | 
|  | 0: The source of the error | 
|  | 1: Error with backtrace | 
|  |  | 
|  | Stack backtrace: | 
|  | {}", | 
|  | trace | 
|  | ); | 
|  | let mut error = GenericError::new("Error with backtrace"); | 
|  | error.backtrace = Some(trace); | 
|  | let error = GenericError::new_with_source("The source of the error", error); | 
|  | let error = GenericError::new_with_source("Error with two sources", error); | 
|  | let report = Report::new(error).pretty(true).show_backtrace(true); | 
|  |  | 
|  | println!("Error: {report}"); | 
|  | assert_eq!(expected.trim_end(), report.to_string()); | 
|  | } | 
|  |  | 
|  | #[derive(Debug)] | 
|  | struct GenericError<D> { | 
|  | message: D, | 
|  | backtrace: Option<Backtrace>, | 
|  | source: Option<Box<dyn Error + 'static>>, | 
|  | } | 
|  |  | 
|  | impl<D> GenericError<D> { | 
|  | fn new(message: D) -> GenericError<D> { | 
|  | Self { message, backtrace: None, source: None } | 
|  | } | 
|  |  | 
|  | fn new_with_source<E>(message: D, source: E) -> GenericError<D> | 
|  | where | 
|  | E: Error + 'static, | 
|  | { | 
|  | let source: Box<dyn Error + 'static> = Box::new(source); | 
|  | let source = Some(source); | 
|  | GenericError { message, backtrace: None, source } | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<D> fmt::Display for GenericError<D> | 
|  | where | 
|  | D: fmt::Display, | 
|  | { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | fmt::Display::fmt(&self.message, f) | 
|  | } | 
|  | } | 
|  |  | 
|  | impl<D> Error for GenericError<D> | 
|  | where | 
|  | D: fmt::Debug + fmt::Display, | 
|  | { | 
|  | fn source(&self) -> Option<&(dyn Error + 'static)> { | 
|  | self.source.as_deref() | 
|  | } | 
|  |  | 
|  | fn provide<'a>(&'a self, req: &mut Request<'a>) { | 
|  | self.backtrace.as_ref().map(|bt| req.provide_ref::<Backtrace>(bt)); | 
|  | } | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn error_formats_single_line_with_rude_display_impl() { | 
|  | #[derive(Debug)] | 
|  | struct MyMessage; | 
|  |  | 
|  | impl fmt::Display for MyMessage { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | f.write_str("line 1\nline 2")?; | 
|  | f.write_str("\nline 3\nline 4\n")?; | 
|  | f.write_str("line 5\nline 6")?; | 
|  | Ok(()) | 
|  | } | 
|  | } | 
|  |  | 
|  | let error = GenericError::new(MyMessage); | 
|  | let error = GenericError::new_with_source(MyMessage, error); | 
|  | let error = GenericError::new_with_source(MyMessage, error); | 
|  | let error = GenericError::new_with_source(MyMessage, error); | 
|  | let report = Report::new(error); | 
|  | let expected = "\ | 
|  | line 1 | 
|  | line 2 | 
|  | line 3 | 
|  | line 4 | 
|  | line 5 | 
|  | line 6: line 1 | 
|  | line 2 | 
|  | line 3 | 
|  | line 4 | 
|  | line 5 | 
|  | line 6: line 1 | 
|  | line 2 | 
|  | line 3 | 
|  | line 4 | 
|  | line 5 | 
|  | line 6: line 1 | 
|  | line 2 | 
|  | line 3 | 
|  | line 4 | 
|  | line 5 | 
|  | line 6"; | 
|  |  | 
|  | let actual = report.to_string(); | 
|  | assert_eq!(expected, actual); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn error_formats_multi_line_with_rude_display_impl() { | 
|  | #[derive(Debug)] | 
|  | struct MyMessage; | 
|  |  | 
|  | impl fmt::Display for MyMessage { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | f.write_str("line 1\nline 2")?; | 
|  | f.write_str("\nline 3\nline 4\n")?; | 
|  | f.write_str("line 5\nline 6")?; | 
|  | Ok(()) | 
|  | } | 
|  | } | 
|  |  | 
|  | let error = GenericError::new(MyMessage); | 
|  | let error = GenericError::new_with_source(MyMessage, error); | 
|  | let error = GenericError::new_with_source(MyMessage, error); | 
|  | let error = GenericError::new_with_source(MyMessage, error); | 
|  | let report = Report::new(error).pretty(true); | 
|  | let expected = "line 1 | 
|  | line 2 | 
|  | line 3 | 
|  | line 4 | 
|  | line 5 | 
|  | line 6 | 
|  |  | 
|  | Caused by: | 
|  | 0: line 1 | 
|  | line 2 | 
|  | line 3 | 
|  | line 4 | 
|  | line 5 | 
|  | line 6 | 
|  | 1: line 1 | 
|  | line 2 | 
|  | line 3 | 
|  | line 4 | 
|  | line 5 | 
|  | line 6 | 
|  | 2: line 1 | 
|  | line 2 | 
|  | line 3 | 
|  | line 4 | 
|  | line 5 | 
|  | line 6"; | 
|  |  | 
|  | let actual = report.to_string(); | 
|  | assert_eq!(expected, actual); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn errors_that_start_with_newline_formats_correctly() { | 
|  | #[derive(Debug)] | 
|  | struct MyMessage; | 
|  |  | 
|  | impl fmt::Display for MyMessage { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | f.write_str("\nThe message\n") | 
|  | } | 
|  | } | 
|  |  | 
|  | let error = GenericError::new(MyMessage); | 
|  | let error = GenericError::new_with_source(MyMessage, error); | 
|  | let error = GenericError::new_with_source(MyMessage, error); | 
|  | let report = Report::new(error).pretty(true); | 
|  | let expected = " | 
|  | The message | 
|  |  | 
|  |  | 
|  | Caused by: | 
|  | 0: \ | 
|  | \n      The message | 
|  | \ | 
|  | \n   1: \ | 
|  | \n      The message | 
|  | "; | 
|  |  | 
|  | let actual = report.to_string(); | 
|  | assert_eq!(expected, actual); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn errors_with_multiple_writes_on_same_line_dont_insert_erroneous_newlines() { | 
|  | #[derive(Debug)] | 
|  | struct MyMessage; | 
|  |  | 
|  | impl fmt::Display for MyMessage { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | f.write_str("The message")?; | 
|  | f.write_str(" goes on")?; | 
|  | f.write_str(" and on.") | 
|  | } | 
|  | } | 
|  |  | 
|  | let error = GenericError::new(MyMessage); | 
|  | let error = GenericError::new_with_source(MyMessage, error); | 
|  | let error = GenericError::new_with_source(MyMessage, error); | 
|  | let report = Report::new(error).pretty(true); | 
|  | let expected = "\ | 
|  | The message goes on and on. | 
|  |  | 
|  | Caused by: | 
|  | 0: The message goes on and on. | 
|  | 1: The message goes on and on."; | 
|  |  | 
|  | let actual = report.to_string(); | 
|  | println!("{actual}"); | 
|  | assert_eq!(expected, actual); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn errors_with_string_interpolation_formats_correctly() { | 
|  | #[derive(Debug)] | 
|  | struct MyMessage(usize); | 
|  |  | 
|  | impl fmt::Display for MyMessage { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | write!(f, "Got an error code: ({}). ", self.0)?; | 
|  | write!(f, "What would you like to do in response?") | 
|  | } | 
|  | } | 
|  |  | 
|  | let error = GenericError::new(MyMessage(10)); | 
|  | let error = GenericError::new_with_source(MyMessage(20), error); | 
|  | let report = Report::new(error).pretty(true); | 
|  | let expected = "\ | 
|  | Got an error code: (20). What would you like to do in response? | 
|  |  | 
|  | Caused by: | 
|  | Got an error code: (10). What would you like to do in response?"; | 
|  | let actual = report.to_string(); | 
|  | assert_eq!(expected, actual); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn empty_lines_mid_message() { | 
|  | #[derive(Debug)] | 
|  | struct MyMessage; | 
|  |  | 
|  | impl fmt::Display for MyMessage { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | f.write_str("line 1\n\nline 2") | 
|  | } | 
|  | } | 
|  |  | 
|  | let error = GenericError::new(MyMessage); | 
|  | let error = GenericError::new_with_source(MyMessage, error); | 
|  | let error = GenericError::new_with_source(MyMessage, error); | 
|  | let report = Report::new(error).pretty(true); | 
|  | let expected = "\ | 
|  | line 1 | 
|  |  | 
|  | line 2 | 
|  |  | 
|  | Caused by: | 
|  | 0: line 1 | 
|  | \ | 
|  | \n      line 2 | 
|  | 1: line 1 | 
|  | \ | 
|  | \n      line 2"; | 
|  |  | 
|  | let actual = report.to_string(); | 
|  | assert_eq!(expected, actual); | 
|  | } | 
|  |  | 
|  | #[test] | 
|  | fn only_one_source() { | 
|  | #[derive(Debug)] | 
|  | struct MyMessage; | 
|  |  | 
|  | impl fmt::Display for MyMessage { | 
|  | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|  | f.write_str("line 1\nline 2") | 
|  | } | 
|  | } | 
|  |  | 
|  | let error = GenericError::new(MyMessage); | 
|  | let error = GenericError::new_with_source(MyMessage, error); | 
|  | let report = Report::new(error).pretty(true); | 
|  | let expected = "\ | 
|  | line 1 | 
|  | line 2 | 
|  |  | 
|  | Caused by: | 
|  | line 1 | 
|  | line 2"; | 
|  |  | 
|  | let actual = report.to_string(); | 
|  | assert_eq!(expected, actual); | 
|  | } |