use crate::error::StatsError;
use float_eq::float_ne;
use std::fmt::Debug;
const TOL: f64 = 1e-13;
fn type_of<T>(_: T) -> &'static str {
std::any::type_name::<T>()
}
fn panic_with_types<T>(act: T, exp: T, line: u32)
where
T: Debug + Copy,
{
panic!(
"found {:?} (type: {}), but expected {:?} (type: {}) for line {}. Check TOL?",
act,
type_of(act),
exp,
type_of(exp),
line
);
}
pub trait Checker<T> {
fn assert(self, exp: T, line: u32);
}
impl Checker<f64> for f64 {
fn assert(self, exp: f64, line: u32) {
if float_ne!(self, exp, rmax <= TOL) {
panic_with_types(self, exp, line);
}
}
}
impl Checker<u32> for u32 {
fn assert(self, exp: u32, line: u32) {
if self != exp {
panic_with_types(self, exp, line);
}
}
}
impl Checker<Result<f64, StatsError>> for Result<f64, StatsError> {
fn assert(self, exp: Result<f64, StatsError>, line: u32) {
match (self, exp) {
(Err(err_act), Err(err_exp)) => {
if err_act != err_exp {
panic_with_types(err_act, err_exp, line);
}
}
(Ok(a), Ok(e)) => Checker::assert(a, e, line),
_ => {
panic_with_types(self, exp, line);
}
}
}
}
#[macro_export]
macro_rules! chk {
($e:expr, $value:expr) => {
crate::tests::check::Checker::assert($e, $value, line!())
};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_check_fns() {
Checker::assert(0u32, 0u32, line!());
Checker::assert(1u32, 1u32, line!());
Checker::assert(0.0, 0.0, line!());
Checker::assert(1.0, 1.0, line!());
Checker::assert(
Err(StatsError::NotEnoughData),
Err(StatsError::NotEnoughData),
line!(),
);
Checker::assert(Ok(0.0), Ok(0.0), line!());
Checker::assert(Ok(1.0), Ok(1.0), line!());
}
#[test]
fn test_checks_macro() {
chk!(0u32, 0u32);
chk!(1u32, 1u32);
chk!(0.0, 0.0);
chk!(1.0, 1.0);
chk!(
Err(StatsError::NotEnoughData),
Err(StatsError::NotEnoughData)
);
chk!(Ok(0.0), Ok(0.0));
chk!(Ok(1.0), Ok(1.0));
}
#[test]
#[should_panic]
fn test_check_panic0() {
chk!(0u32, 1u32);
}
#[test]
#[should_panic]
fn test_check_panic1() {
chk!(0.0, 1.0);
}
#[test]
#[should_panic]
fn test_check_panic2() {
chk!(Ok(0.0), Err(StatsError::NotEnoughData));
}
#[test]
#[should_panic]
fn test_check_panic3() {
chk!(Err(StatsError::NotEnoughData), Ok(7.0));
}
#[test]
#[should_panic]
fn test_check_panic4() {
chk!(Ok(6.0), Ok(8.0));
}
}