use crate::LoggableError;
use std::error::Error;
impl<T, E: Error> LoggableError<T> for std::result::Result<T, E> {
fn print_error<F: Fn(&str)>(self, fun: F) -> Self {
if let Err(ref err) = self {
let mut err = err as &dyn std::error::Error;
fun(&format!("Error: {err}"));
while let Some(source_err) = err.source() {
fun(&format!(" because: {source_err}"));
err = source_err;
}
}
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::cell::RefCell;
use std::error::Error;
use std::fmt;
#[derive(Debug)]
pub struct AError(BError);
impl Error for AError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.0)
}
}
impl fmt::Display for AError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "failed because A")
}
}
#[derive(Debug)]
pub struct BError(std::io::Error);
impl Error for BError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.0)
}
}
impl fmt::Display for BError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "failed because B")
}
}
#[test]
fn print_with_source() {
let dump = RefCell::new(String::new());
let err: std::result::Result<(), AError> =
Err(AError(BError(std::io::ErrorKind::NotFound.into())));
let _ = err.print_error(|msg| dump.borrow_mut().push_str(&msg));
for (index, line) in dump.borrow_mut().lines().enumerate() {
match index {
0 => assert!(line.contains("failed because A")),
1 => assert!(line.contains("failed because B")),
2 => assert!(line.contains("entity not found")),
_ => panic!("extra lines found in output: {}", line),
}
}
}
}