shoulda_core 0.1.2

derive macro for test assertions
Documentation
pub mod array_like;
pub mod assertion_hook;
pub mod empty_types;
pub mod float_diff_provider;
pub mod should_result;
pub mod specifics;
#[cfg(test)]
mod tests;
pub mod wrapper_types;

use crate::assertion_hook::{AssertionHook, NoOpAssertionHook, NotAssertionHook, OrAssertionHook};
use crate::float_diff_provider::{EnvFloatDiffProvider, FloatDiffProvider};
use crate::should_result::ResultsContainer;
use std::borrow::Borrow;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::DerefMut;

pub struct Should<
    'a,
    Inner,
    Hook: AssertionHook = NoOpAssertionHook,
    FloatDiff: FloatDiffProvider = EnvFloatDiffProvider,
> {
    results: ResultsContainer,
    inner: &'a Inner,
    hook: PhantomData<Hook>,
    float_diff: PhantomData<FloatDiff>,
}

impl<'a, Inner, Hook, FloatDiff> Should<'a, Inner, Hook, FloatDiff>
where
    Hook: AssertionHook,
    FloatDiff: FloatDiffProvider,
{
    pub(crate) fn internal_assert(&mut self, initial: bool, message: String) {
        Hook::create_result(initial, message, self.results.deref_mut())
    }
    pub(crate) fn change_optional_generics<T: AssertionHook, L: FloatDiffProvider>(
        self,
    ) -> Should<'a, Inner, T, L> {
        Should::new(self.inner, self.results)
    }
    pub(crate) fn normalize(self) -> Should<'a, Inner, NoOpAssertionHook, FloatDiff> {
        self.change_optional_generics()
    }
    pub(crate) fn new(inner: &'a Inner, results: ResultsContainer) -> Self {
        Self {
            results,
            inner,
            hook: Default::default(),
            float_diff: Default::default(),
        }
    }
}

impl<'a, Inner, Hook, FloatDiff> Should<'a, Inner, Hook, FloatDiff>
where
    Inner: Shoulda,
    Hook: AssertionHook,
    FloatDiff: FloatDiffProvider,
{
    pub fn eq<K: Borrow<Inner>>(mut self, other: K) -> Self {
        let other = other.borrow();
        self.internal_assert(
            self.inner.test_eq::<FloatDiff>(other),
            format!("expected = {:?}, actual = {:?}", &self.inner, other),
        );
        self
    }
    pub fn equal<K: Borrow<Inner>>(self, other: K) -> Self {
        self.eq(other)
    }
    pub fn be(self) -> Self {
        self
    }
    pub fn and(self) -> Self {
        self
    }
    pub fn float_diff<T: FloatDiffProvider>(self) -> Should<'a, Inner, Hook, T> {
        self.change_optional_generics()
    }
}

impl<'a, Inner, FloatDiff> Should<'a, Inner, NoOpAssertionHook, FloatDiff>
where
    Inner: Shoulda,
    FloatDiff: FloatDiffProvider,
{
    pub fn not(self) -> Should<'a, Inner, NotAssertionHook, FloatDiff> {
        self.change_optional_generics()
    }
}

impl<'a, Inner, FloatDiff> Should<'a, Inner, NoOpAssertionHook, FloatDiff>
where
    Inner: Shoulda,
    FloatDiff: FloatDiffProvider,
{
    pub fn or(self) -> Should<'a, Inner, OrAssertionHook, FloatDiff> {
        self.change_optional_generics()
    }
}

impl<'a, Inner, FloatDiff> Should<'a, Inner, NotAssertionHook, FloatDiff>
where
    Inner: Shoulda,
    FloatDiff: FloatDiffProvider,
{
    pub fn not(self) -> Should<'a, Inner, NoOpAssertionHook, FloatDiff> {
        self.change_optional_generics()
    }
}

pub trait Shoulda: Debug {
    fn test_eq<FloatDiff: FloatDiffProvider>(&self, other: &Self) -> bool;
    fn should(&self) -> Should<Self>
    where
        Self: Sized,
    {
        Should::new(self, ResultsContainer::default())
    }
}

pub fn expect<T: Shoulda>(t: &T) -> Should<T> {
    t.should()
}

macro_rules! eq_assertable_impl {
    ($x:ty) => {
        impl Shoulda for $x {
            fn test_eq<FloatDiff: FloatDiffProvider>(&self, other: &Self) -> bool {
                self.eq(other)
            }
        }
    };
}

macro_rules! float_assertable_impl {
    ($x:ty) => {
        impl Shoulda for $x {
            fn test_eq<FloatDiff: FloatDiffProvider>(&self, other: &Self) -> bool {
                (self - other).abs() < (FloatDiff::diff() as $x)
            }
        }
    };
}

eq_assertable_impl!(String);
eq_assertable_impl!(str);
eq_assertable_impl!(bool);
eq_assertable_impl!(u8);
eq_assertable_impl!(i8);
eq_assertable_impl!(u16);
eq_assertable_impl!(i16);
eq_assertable_impl!(u32);
eq_assertable_impl!(i32);
eq_assertable_impl!(u64);
eq_assertable_impl!(i64);
eq_assertable_impl!(u128);
eq_assertable_impl!(i128);
eq_assertable_impl!(usize);
eq_assertable_impl!(isize);

float_assertable_impl!(f32);
float_assertable_impl!(f64);

impl<T> Shoulda for &T
where
    T: Shoulda,
{
    fn test_eq<FloatDiff: FloatDiffProvider>(&self, other: &Self) -> bool {
        T::test_eq::<FloatDiff>(self, other)
    }
}