mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-13 07:24:00 +00:00
Update report output and fix examples
This commit is contained in:
parent
1386a15529
commit
4420cc33d6
@ -808,9 +808,11 @@ impl dyn Error + Send + Sync {
|
||||
}
|
||||
}
|
||||
|
||||
/// An error reporter that exposes the entire error chain for printing.
|
||||
/// It also exposes options for formatting the error chain, either entirely on a single line,
|
||||
/// or in multi-line format with each cause in the error chain on a new line.
|
||||
/// An error reporter that print's an error and its sources.
|
||||
///
|
||||
/// Report also exposes configuration options for formatting the error chain, either entirely on a
|
||||
/// single line, or in multi-line format with each cause in the error chain on a new line.
|
||||
///
|
||||
/// `Report` only requires that the wrapped error implements `Error`. It doesn't require that the
|
||||
/// wrapped error be `Send`, `Sync`, or `'static`.
|
||||
///
|
||||
@ -818,33 +820,51 @@ impl dyn Error + Send + Sync {
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(error_reporter)]
|
||||
/// #![feature(negative_impls)]
|
||||
///
|
||||
/// use std::error::{Error, Report};
|
||||
/// use std::fmt;
|
||||
///
|
||||
/// #[derive(Debug)]
|
||||
/// struct SuperError<'a> {
|
||||
/// side: &'a str,
|
||||
/// struct SuperError {
|
||||
/// source: SuperErrorSideKick,
|
||||
/// }
|
||||
///
|
||||
/// impl<'a> fmt::Display for SuperError<'a> {
|
||||
/// impl fmt::Display for SuperError {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// write!(f, "SuperError is here: {}", self.side)
|
||||
/// write!(f, "SuperError is here!")
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl<'a> Error for SuperError<'a> {}
|
||||
/// 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 {}
|
||||
///
|
||||
/// fn get_super_error() -> Result<(), SuperError> {
|
||||
/// Err(SuperError { source: SuperErrorSideKick })
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let msg = String::from("Huzzah!");
|
||||
/// let error = SuperError { side: &msg };
|
||||
/// let report = Report::new(&error).pretty(true);
|
||||
///
|
||||
/// println!("{}", report);
|
||||
/// match get_super_error() {
|
||||
/// Err(e) => {
|
||||
/// let report = Report::new(e).pretty(true);
|
||||
/// println!("Error: {}", report);
|
||||
/// }
|
||||
/// _ => println!("No error"),
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
pub struct Report<E> {
|
||||
/// The error being reported.
|
||||
@ -865,14 +885,129 @@ where
|
||||
Report { error, show_backtrace: false, pretty: false }
|
||||
}
|
||||
|
||||
/// Enable pretty-printing the report.
|
||||
/// Enable pretty-printing the report across multiple lines.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(error_reporter)]
|
||||
/// use std::error::Report;
|
||||
/// # use std::error::Error;
|
||||
/// # use std::fmt;
|
||||
/// # #[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 {}
|
||||
///
|
||||
/// let error = SuperError { source: SuperErrorSideKick };
|
||||
/// let report = Report::new(error).pretty(true);
|
||||
/// eprintln!("Error: {:?}", report);
|
||||
/// ```
|
||||
///
|
||||
/// This example produces the following output:
|
||||
///
|
||||
/// ```console
|
||||
/// Error: SuperError is here!
|
||||
///
|
||||
/// Caused by:
|
||||
/// SuperErrorSideKick is here!
|
||||
/// ```
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
pub fn pretty(mut self, pretty: bool) -> Self {
|
||||
self.pretty = pretty;
|
||||
self
|
||||
}
|
||||
|
||||
/// Enable showing a backtrace for the report.
|
||||
/// Display backtrace if available when using pretty output format.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(error_reporter)]
|
||||
/// #![feature(backtrace)]
|
||||
/// use std::error::{Error, Report};
|
||||
/// use std::backtrace::Backtrace;
|
||||
/// use std::fmt;
|
||||
///
|
||||
/// #[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 {
|
||||
/// backtrace: Backtrace,
|
||||
/// }
|
||||
///
|
||||
/// impl fmt::Display for SuperErrorSideKick {
|
||||
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// write!(f, "SuperErrorSideKick is here!")
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// impl Error for SuperErrorSideKick {
|
||||
/// fn backtrace(&self) -> Option<&Backtrace> {
|
||||
/// Some(&self.backtrace)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let source = SuperErrorSideKick { backtrace: Backtrace::force_capture() };
|
||||
/// let error = SuperError { source };
|
||||
/// let report = Report::new(error).pretty(true).show_backtrace(true);
|
||||
/// eprintln!("Error: {:?}", report);
|
||||
/// ```
|
||||
///
|
||||
/// This example produces something similar to the following output:
|
||||
///
|
||||
/// ```console
|
||||
/// Error: SuperError is here!
|
||||
///
|
||||
/// Caused by:
|
||||
/// SuperErrorSideKick is here!
|
||||
///
|
||||
/// Stack backtrace:
|
||||
/// 0: rust_out::main::_doctest_main_src_error_rs_943_0
|
||||
/// 1: rust_out::main
|
||||
/// 2: core::ops::function::FnOnce::call_once
|
||||
/// 3: std::sys_common::backtrace::__rust_begin_short_backtrace
|
||||
/// 4: std::rt::lang_start::{{closure}}
|
||||
/// 5: std::panicking::try
|
||||
/// 6: std::rt::lang_start_internal
|
||||
/// 7: std::rt::lang_start
|
||||
/// 8: main
|
||||
/// 9: __libc_start_main
|
||||
/// 10: _start
|
||||
/// ```
|
||||
#[unstable(feature = "error_reporter", issue = "90172")]
|
||||
pub fn show_backtrace(mut self, show_backtrace: bool) -> Self {
|
||||
self.show_backtrace = show_backtrace;
|
||||
@ -922,10 +1057,12 @@ where
|
||||
writeln!(f)?;
|
||||
let mut indented = Indented {
|
||||
inner: f,
|
||||
number: if multiple { Some(ind) } else { None },
|
||||
started: false,
|
||||
};
|
||||
write!(indented, "{}", error)?;
|
||||
if multiple {
|
||||
write!(indented, "{: >4}: {}", ind, error)?;
|
||||
} else {
|
||||
write!(indented, " {}", error)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -979,8 +1116,6 @@ where
|
||||
/// Wrapper type for indenting the inner source.
|
||||
struct Indented<'a, D> {
|
||||
inner: &'a mut D,
|
||||
number: Option<usize>,
|
||||
started: bool,
|
||||
}
|
||||
|
||||
impl<T> Write for Indented<'_, T>
|
||||
@ -989,19 +1124,9 @@ where
|
||||
{
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
for (i, line) in s.split('\n').enumerate() {
|
||||
if !self.started {
|
||||
self.started = true;
|
||||
match self.number {
|
||||
Some(number) => write!(self.inner, "{: >5}: ", number)?,
|
||||
None => self.inner.write_str(" ")?,
|
||||
}
|
||||
} else if i > 0 {
|
||||
if i > 0 {
|
||||
self.inner.write_char('\n')?;
|
||||
if self.number.is_some() {
|
||||
self.inner.write_str(" ")?;
|
||||
} else {
|
||||
self.inner.write_str(" ")?;
|
||||
}
|
||||
self.inner.write_str(" ")?;
|
||||
}
|
||||
|
||||
self.inner.write_str(line)?;
|
||||
|
@ -82,8 +82,11 @@ 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!\n\nCaused by:\n SuperErrorSideKick is here!");
|
||||
let expected = String::from("\
|
||||
SuperError is here!
|
||||
|
||||
Caused by:
|
||||
SuperErrorSideKick is here!");
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
@ -109,10 +112,11 @@ fn error_with_no_sources_formats_multi_line_correctly() {
|
||||
#[test]
|
||||
fn error_with_backtrace_outputs_correctly_with_one_source() {
|
||||
let trace = Backtrace::force_capture();
|
||||
let expected = format!("The source of the error
|
||||
let expected = format!("\
|
||||
The source of the error
|
||||
|
||||
Caused by:
|
||||
Error with backtrace
|
||||
Error with backtrace
|
||||
|
||||
Stack backtrace:
|
||||
{}", trace);
|
||||
@ -129,11 +133,12 @@ Stack backtrace:
|
||||
#[test]
|
||||
fn error_with_backtrace_outputs_correctly_with_two_sources() {
|
||||
let trace = Backtrace::force_capture();
|
||||
let expected = format!("Error with two sources
|
||||
let expected = format!("\
|
||||
Error with two sources
|
||||
|
||||
Caused by:
|
||||
0: The source of the error
|
||||
1: Error with backtrace
|
||||
0: The source of the error
|
||||
1: Error with backtrace
|
||||
|
||||
Stack backtrace:
|
||||
{}", trace);
|
||||
@ -211,7 +216,8 @@ fn error_formats_single_line_with_rude_display_impl() {
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let report = Report::new(error);
|
||||
let expected = r#"line 1
|
||||
let expected = "\
|
||||
line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
@ -231,7 +237,7 @@ line 2
|
||||
line 3
|
||||
line 4
|
||||
line 5
|
||||
line 6"#;
|
||||
line 6";
|
||||
|
||||
let actual = report.to_string();
|
||||
assert_eq!(expected, actual);
|
||||
@ -256,7 +262,7 @@ fn error_formats_multi_line_with_rude_display_impl() {
|
||||
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 = r#"line 1
|
||||
let expected = "line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
@ -264,24 +270,24 @@ 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"#;
|
||||
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);
|
||||
@ -302,22 +308,51 @@ fn errors_that_start_with_newline_formats_correctly() {
|
||||
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 = r#"
|
||||
let expected = "
|
||||
The message
|
||||
|
||||
|
||||
Caused by:
|
||||
0:
|
||||
The message
|
||||
|
||||
1:
|
||||
The message
|
||||
"#;
|
||||
0:
|
||||
The message
|
||||
|
||||
1:
|
||||
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)]
|
||||
@ -333,10 +368,11 @@ fn errors_with_string_interpolation_formats_correctly() {
|
||||
let error = GenericError::new(MyMessage(10));
|
||||
let error = GenericError::new_with_source(MyMessage(20), error);
|
||||
let report = Report::new(error).pretty(true);
|
||||
let expected = r#"Got an error code: (20). What would you like to do in response?
|
||||
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?"#;
|
||||
Got an error code: (10). What would you like to do in response?";
|
||||
let actual = report.to_string();
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
@ -356,17 +392,18 @@ fn empty_lines_mid_message() {
|
||||
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 = r#"line 1
|
||||
let expected = "\
|
||||
line 1
|
||||
|
||||
line 2
|
||||
|
||||
Caused by:
|
||||
0: line 1
|
||||
|
||||
line 2
|
||||
1: line 1
|
||||
|
||||
line 2"#;
|
||||
0: line 1
|
||||
|
||||
line 2
|
||||
1: line 1
|
||||
|
||||
line 2";
|
||||
|
||||
let actual = report.to_string();
|
||||
assert_eq!(expected, actual);
|
||||
@ -386,12 +423,13 @@ fn only_one_source() {
|
||||
let error = GenericError::new(MyMessage);
|
||||
let error = GenericError::new_with_source(MyMessage, error);
|
||||
let report = Report::new(error).pretty(true);
|
||||
let expected = r#"line 1
|
||||
let expected = "\
|
||||
line 1
|
||||
line 2
|
||||
|
||||
Caused by:
|
||||
line 1
|
||||
line 2"#;
|
||||
line 1
|
||||
line 2";
|
||||
|
||||
let actual = report.to_string();
|
||||
assert_eq!(expected, actual);
|
||||
|
Loading…
Reference in New Issue
Block a user