Add a way to print inputs on failure
When there is a panic in an extensive test, tracing down where it came from can be difficult since no information is provides (messeges are e.g. "attempted to subtract with overflow"). Resolve this by calling the functions within `panic::catch_unwind`, printing the input, and continuing.
This commit is contained in:
parent
aa26cab257
commit
e106d63516
7 changed files with 27 additions and 8 deletions
|
|
@ -14,6 +14,7 @@
|
|||
//! level. `Op` is also used as the name for generic parameters since it is terse.
|
||||
|
||||
use std::fmt;
|
||||
use std::panic::{RefUnwindSafe, UnwindSafe};
|
||||
|
||||
pub use shared::{ALL_OPERATIONS, FloatTy, MathOpInfo, Ty};
|
||||
|
||||
|
|
@ -64,7 +65,7 @@ pub trait MathOp {
|
|||
type CRet;
|
||||
|
||||
/// The signature of the Rust function as a `fn(...) -> ...` type.
|
||||
type RustFn: Copy;
|
||||
type RustFn: Copy + UnwindSafe;
|
||||
|
||||
/// Arguments passed to the Rust library function as a tuple.
|
||||
///
|
||||
|
|
@ -72,7 +73,8 @@ pub trait MathOp {
|
|||
/// to the Rust function.
|
||||
type RustArgs: Copy
|
||||
+ TupleCall<Self::RustFn, Output = Self::RustRet>
|
||||
+ TupleCall<Self::CFn, Output = Self::RustRet>;
|
||||
+ TupleCall<Self::CFn, Output = Self::RustRet>
|
||||
+ RefUnwindSafe;
|
||||
|
||||
/// Type returned from the Rust function.
|
||||
type RustRet: CheckOutput<Self::RustArgs>;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
//! - `CheckOutput`: implemented on anything that is an output type for validation against an
|
||||
//! expected value.
|
||||
|
||||
use std::fmt;
|
||||
use std::panic::{RefUnwindSafe, UnwindSafe};
|
||||
use std::{fmt, panic};
|
||||
|
||||
use anyhow::{Context, anyhow, bail, ensure};
|
||||
use libm::support::Hexf;
|
||||
|
|
@ -23,6 +24,22 @@ use crate::{
|
|||
pub trait TupleCall<Func>: fmt::Debug {
|
||||
type Output;
|
||||
fn call(self, f: Func) -> Self::Output;
|
||||
|
||||
/// Intercept panics and print the input to stderr before continuing.
|
||||
fn call_intercept_panics(self, f: Func) -> Self::Output
|
||||
where
|
||||
Self: RefUnwindSafe + Copy,
|
||||
Func: UnwindSafe,
|
||||
{
|
||||
let res = panic::catch_unwind(|| self.call(f));
|
||||
match res {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
eprintln!("panic with the following input: {self:?}");
|
||||
panic::resume_unwind(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait to implement on any output type so we can verify it in a generic way.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ fn musl_runner<Op: MathOp>(
|
|||
) {
|
||||
for input in cases {
|
||||
let musl_res = input.call(musl_fn);
|
||||
let crate_res = input.call(Op::ROUTINE);
|
||||
let crate_res = input.call_intercept_panics(Op::ROUTINE);
|
||||
|
||||
crate_res.validate(musl_res, input, ctx).unwrap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ fn mp_runner<Op: MathOp + MpOp>(ctx: &CheckCtx, cases: impl Iterator<Item = Op::
|
|||
let mut mp_vals = Op::new_mp();
|
||||
for input in cases {
|
||||
let mp_res = Op::run(&mut mp_vals, input);
|
||||
let crate_res = input.call(Op::ROUTINE);
|
||||
let crate_res = input.call_intercept_panics(Op::ROUTINE);
|
||||
|
||||
crate_res.validate(mp_res, input, ctx).unwrap();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ fn standalone_runner<Op: MathOp>(
|
|||
cases: impl Iterator<Item = (Op::RustArgs, Op::RustRet)>,
|
||||
) {
|
||||
for (input, expected) in cases {
|
||||
let crate_res = input.call(Op::ROUTINE);
|
||||
let crate_res = input.call_intercept_panics(Op::ROUTINE);
|
||||
crate_res.validate(expected, input, ctx).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ where
|
|||
for input in input_vec {
|
||||
// Test the input.
|
||||
let mp_res = Op::run(mp_vals, input);
|
||||
let crate_res = input.call(Op::ROUTINE);
|
||||
let crate_res = input.call_intercept_panics(Op::ROUTINE);
|
||||
crate_res.validate(mp_res, input, ctx)?;
|
||||
|
||||
let completed = completed.fetch_add(1, Ordering::Relaxed) + 1;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ macro_rules! handle_call {
|
|||
let libm_fn: <Op as MathOp>::RustFn = libm::$fn_name;
|
||||
|
||||
let output = match $basis {
|
||||
"libm" => input.call(libm_fn),
|
||||
"libm" => input.call_intercept_panics(libm_fn),
|
||||
#[cfg(feature = "build-musl")]
|
||||
"musl" => {
|
||||
let musl_fn: <Op as MathOp>::CFn =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue