From f685726eac07c6b1d4f40dded6f3f55bcfcea5cc Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Tue, 26 Dec 2023 00:48:16 +0200 Subject: [PATCH] melib/email/parser: add backtrace field to ParsingError Add backtrace field to ParsingError when the build is for testing or documentation. Signed-off-by: Manos Pitsidianakis --- melib/src/email/parser.rs | 124 +++++++++++++++++++++++++++++++------- 1 file changed, 102 insertions(+), 22 deletions(-) diff --git a/melib/src/email/parser.rs b/melib/src/email/parser.rs index 517a0c94..0573ec81 100644 --- a/melib/src/email/parser.rs +++ b/melib/src/email/parser.rs @@ -22,6 +22,8 @@ //! Parsers for email. See submodules. #![allow(clippy::type_complexity)] +#[cfg(any(test, doc))] +use std::backtrace::Backtrace; use std::{borrow::Cow, convert::TryFrom, fmt::Write}; use nom::{ @@ -51,27 +53,56 @@ macro_rules! to_str { unsafe { std::str::from_utf8_unchecked($l) } }}; } -#[derive(Eq, PartialEq)] pub struct ParsingError { pub input: I, pub error: Cow<'static, str>, + #[cfg(any(test, doc))] + pub backtrace: Backtrace, +} + +impl PartialEq for ParsingError { + fn eq(&self, other: &Self) -> bool { + self.input.eq(&other.input) && self.error.eq(&other.error) + } } impl std::fmt::Debug for ParsingError<&'_ [u8]> { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - fmt.debug_struct("ParsingError") - .field("input", &to_str!(self.input)) - .field("error", &self.error) - .finish() + #[cfg(any(test, doc))] + { + fmt.debug_struct("ParsingError") + .field("input", &to_str!(self.input)) + .field("error", &self.error) + .field("backtrace", &self.backtrace) + .finish() + } + #[cfg(not(any(test, doc)))] + { + fmt.debug_struct("ParsingError") + .field("input", &to_str!(self.input)) + .field("error", &self.error) + .finish() + } } } impl std::fmt::Debug for ParsingError<&'_ str> { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - fmt.debug_struct("ParsingError") - .field("input", &self.input) - .field("error", &self.error) - .finish() + #[cfg(any(test, doc))] + { + fmt.debug_struct("ParsingError") + .field("input", &self.input) + .field("error", &self.error) + .field("backtrace", &self.backtrace) + .finish() + } + #[cfg(not(any(test, doc)))] + { + fmt.debug_struct("ParsingError") + .field("input", &self.input) + .field("error", &self.error) + .finish() + } } } @@ -94,6 +125,8 @@ impl<'i> ParsingError<&'i str> { ParsingError { input: self.input.as_bytes(), error: self.error, + #[cfg(any(test, doc))] + backtrace: self.backtrace, } } } @@ -103,6 +136,8 @@ impl From<(I, &'static str)> for ParsingError { Self { input, error: error.into(), + #[cfg(any(test, doc))] + backtrace: Backtrace::capture(), } } } @@ -112,6 +147,8 @@ impl From<(I, String)> for ParsingError { Self { input, error: error.into(), + #[cfg(any(test, doc))] + backtrace: Backtrace::capture(), } } } @@ -121,6 +158,8 @@ impl nom::error::ParseError for ParsingError { Self { input, error: kind.description().to_string().into(), + #[cfg(any(test, doc))] + backtrace: Backtrace::capture(), } } @@ -128,6 +167,8 @@ impl nom::error::ParseError for ParsingError { Self { input, error: format!("{}, {}", kind.description(), other.error).into(), + #[cfg(any(test, doc))] + backtrace: Backtrace::capture(), } } } @@ -137,6 +178,8 @@ impl nom::error::FromExternalError for ParsingError { Self { input, error: kind.description().to_string().into(), + #[cfg(any(test, doc))] + backtrace: Backtrace::capture(), } } } @@ -145,26 +188,63 @@ impl nom::error::ContextError for ParsingError {} impl<'i> From> for Error { fn from(val: ParsingError<&'i [u8]>) -> Self { - Self::new("Parsing error").set_summary(format!( - r#"In input: "{}...", + Self::new("Parsing error") + .set_summary(format!( + r#"In input: "{}...", Error: {}"#, - String::from_utf8_lossy(val.input) - .chars() - .take(30) - .collect::(), - val.error - )) + String::from_utf8_lossy(val.input) + .chars() + .take(30) + .collect::(), + val.error + )) + .set_details({ + #[cfg(any(test, doc))] + { + println!( + "\tInput:\n{}\tError:\n{}\n\tBacktrace:\n{}", + String::from_utf8_lossy(val.input) + .chars() + .take(30) + .collect::(), + val.error, + val.backtrace + ); + val.backtrace.to_string() + } + #[cfg(not(any(test, doc)))] + { + "" + } + }) } } impl<'i> From> for Error { fn from(val: ParsingError<&'i str>) -> Self { - Self::new("Parsing error").set_summary(format!( - r#"In input: "{}...", + Self::new("Parsing error") + .set_summary(format!( + r#"In input: "{}...", Error: {}"#, - val.input.chars().take(30).collect::(), - val.error - )) + val.input.chars().take(30).collect::(), + val.error + )) + .set_details({ + #[cfg(any(test, doc))] + { + println!( + "\tInput:\n{}\tError:\n{}\n\tBacktrace:\n{}", + val.input.chars().take(30).collect::(), + val.error, + val.backtrace + ); + val.backtrace.to_string() + } + #[cfg(not(any(test, doc)))] + { + "" + } + }) } }