1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
pub mod array_like;
pub mod assertion_hook;
pub mod empty_types;
pub mod epsilon_provider;
pub mod should_result;
pub mod shoulda_equal;
pub mod shoulda_of_type;
pub mod specifics;
#[cfg(test)]
mod tests;
pub mod wrapper_types;

use crate::assertion_hook::{AssertionHook, NoOpAssertionHook, NotAssertionHook, OrAssertionHook};
use crate::epsilon_provider::{EnvEpsilonProvider, EpsilonProvider};
use crate::should_result::ResultsContainer;
use crate::shoulda_equal::ShouldaEqual;
use std::borrow::Borrow;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::DerefMut;

pub struct Should<
    'a,
    Inner,
    Hook: AssertionHook = NoOpAssertionHook,
    Epsilon: EpsilonProvider = EnvEpsilonProvider,
> {
    results: ResultsContainer,
    inner: &'a Inner,
    hook: PhantomData<Hook>,
    float_diff: PhantomData<Epsilon>,
}

impl<'a, Inner, Hook, Epsilon> Should<'a, Inner, Hook, Epsilon>
where
    Hook: AssertionHook,
    Epsilon: EpsilonProvider,
{
    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: EpsilonProvider>(
        self,
    ) -> Should<'a, Inner, T, L> {
        Should::new(self.inner, self.results)
    }
    pub(crate) fn normalize(self) -> Should<'a, Inner, NoOpAssertionHook, Epsilon> {
        self.change_optional_generics()
    }
    pub(crate) fn new(inner: &'a Inner, results: ResultsContainer) -> Self {
        Self {
            results,
            inner,
            hook: Default::default(),
            float_diff: Default::default(),
        }
    }

    pub fn be(self) -> Self {
        self
    }
    pub fn and(self) -> Self {
        self
    }
    pub fn float_diff<T: EpsilonProvider>(self) -> Should<'a, Inner, Hook, T> {
        self.change_optional_generics()
    }
}

impl<'a, Inner, Hook, Epsilon> Should<'a, Inner, Hook, Epsilon>
where
    Inner: ShouldaEqual + Debug,
    Hook: AssertionHook,
    Epsilon: EpsilonProvider,
{
    pub fn eq<K: Borrow<Inner>>(mut self, other: K) -> Self {
        let other = other.borrow();
        self.internal_assert(
            self.inner.should_eq::<Epsilon>(other),
            format!("expected = {:?}, actual = {:?}", &self.inner, other),
        );
        self
    }
    pub fn equal<K: Borrow<Inner>>(self, other: K) -> Self {
        self.eq(other)
    }
}

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

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

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

pub trait Shoulda {
    fn should(&self) -> Should<Self>
    where
        Self: Sized,
    {
        Should::new(self, ResultsContainer::default())
    }
}

impl<T> Shoulda for T {}