LukasKalbertodt / libtest-mimic

A small test framework to write your own test harness that looks and behaves like the built-in test harness used by `rustc --test`
https://docs.rs/libtest-mimic
Apache License 2.0
99 stars 28 forks source link

Catch panics and report them as test failures #8

Closed Ekleog closed 2 years ago

Ekleog commented 3 years ago

This doesn't yet fill in an output message (because stdout is not captured yet), but with this change it should at least keep going after a failed test

Note: this PR builds on top of #7 because this way I can git-depend on this commit, so feel free to review only the second commit as the first one is the one in #7, I'll rebase when/if #7 lands :)

janosimas commented 2 years ago

Looks like this PR is not active anymore but as a note, std::panic::set_hook can be used to catch the panic data, including the stack trace when the env flag is set. This would require a global storage for the data but more information is available for reporting.

#[derive(Debug)]
struct ErrorInfo {
    #[allow(unused)]
    location: String,
    #[allow(unused)]
    message: Option<String>,
    #[allow(unused)]
    backtrace: Backtrace,
}

fn panic_handler(panic_info: &PanicInfo) -> ErrorInfo {
    let location = match panic_info.location() {
        Some(location) => format!(
            "{}:{}:{}",
            location.file(),
            location.line(),
            location.column()
        ),
        None => "<Panic location unknown>".to_owned(),
    };

    #[cfg(feature = "nightly")]
    let message = panic_info.message().map(|m| format!("{}", m));

    #[cfg(not(feature = "nightly"))]
    let message = match (
        panic_info.payload().downcast_ref::<&str>(),
        panic_info.payload().downcast_ref::<String>(),
    ) {
        (Some(s), _) => Some(s.to_string()),
        (_, Some(s)) => Some(s.to_string()),
        (None, None) => None,
    };

    let backtrace = Backtrace::capture();

    ErrorInfo {
        location,
        message,
        backtrace,
    }
}

// main.rs

let errs = Arc::new(Mutex::new(vec![]));
std::panic::set_hook({
    let errs = errs.clone();
    Box::new(move |info| {
        errs.lock().unwrap().push(panic_handler(info));
    })
})
LukasKalbertodt commented 2 years ago

This feature is still something that libtest might implement in the future, but this PR has not been active for more than a year, so I will close it for now. This might be implemented as part of a bigger refactoring in the future.