shoulda_core/
lib.rs

1pub mod array_like;
2pub mod assertion_hook;
3pub mod empty_types;
4pub mod epsilon_provider;
5pub mod should_result;
6pub mod shoulda_equal;
7pub mod shoulda_of_type;
8pub mod specifics;
9#[cfg(test)]
10mod tests;
11pub mod tuples;
12pub mod wrapper_types;
13
14use crate::assertion_hook::{AssertionHook, NoOpAssertionHook, NotAssertionHook, OrAssertionHook};
15use crate::epsilon_provider::{EnvEpsilonProvider, EpsilonProvider};
16use crate::should_result::ResultsContainer;
17use crate::shoulda_equal::ShouldaEqual;
18use std::fmt::Debug;
19use std::marker::PhantomData;
20use std::ops::DerefMut;
21
22/// A wrapper type around a borrowed value to assert things about it for testing
23pub struct Should<
24    'a,
25    Inner,
26    Hook: AssertionHook = NoOpAssertionHook,
27    Epsilon: EpsilonProvider = EnvEpsilonProvider,
28> {
29    results: ResultsContainer,
30    inner: &'a Inner,
31    hook: PhantomData<Hook>,
32    float_diff: PhantomData<Epsilon>,
33}
34
35impl<'a, Inner, Hook, Epsilon> Should<'a, Inner, Hook, Epsilon>
36where
37    Hook: AssertionHook,
38    Epsilon: EpsilonProvider,
39{
40    pub(crate) fn internal_assert(&mut self, initial: bool, message: String) {
41        Hook::create_result(initial, message, self.results.deref_mut())
42    }
43    pub(crate) fn change_optional_generics<T: AssertionHook, L: EpsilonProvider>(
44        self,
45    ) -> Should<'a, Inner, T, L> {
46        Should::new(self.inner, self.results)
47    }
48    pub(crate) fn normalize(self) -> Should<'a, Inner, NoOpAssertionHook, Epsilon> {
49        self.change_optional_generics()
50    }
51    pub(crate) fn new(inner: &'a Inner, results: ResultsContainer) -> Self {
52        Self {
53            results,
54            inner,
55            hook: Default::default(),
56            float_diff: Default::default(),
57        }
58    }
59
60    /// no-op, there to allow you to write english-like sentences
61    pub fn be(self) -> Self {
62        self
63    }
64
65    /// no-op, there to allow you to write english-like sentences
66    pub fn and(self) -> Self {
67        self
68    }
69
70    /// Changes the generic for which EpsilonProvider to use
71    pub fn float_diff<T: EpsilonProvider>(self) -> Should<'a, Inner, Hook, T> {
72        self.change_optional_generics()
73    }
74}
75
76impl<'a, Inner, Hook, Epsilon> Should<'a, Inner, Hook, Epsilon>
77where
78    Inner: ShouldaEqual + Debug,
79    Hook: AssertionHook,
80    Epsilon: EpsilonProvider,
81{
82    /// Asserts equality
83    pub fn eq<K: Into<Inner>>(mut self, other: K) -> Self {
84        let other = other.into();
85        self.internal_assert(
86            self.inner.should_eq::<Epsilon>(&other),
87            format!("expected = {:?}, actual = {:?}", &self.inner, other),
88        );
89        self
90    }
91
92    /// alias for eq
93    pub fn equal<K: Into<Inner>>(self, other: K) -> Self {
94        self.eq(other)
95    }
96}
97
98impl<'a, Inner, Epsilon> Should<'a, Inner, NoOpAssertionHook, Epsilon>
99where
100    Epsilon: EpsilonProvider,
101{
102    /// Changes the assertion hook to not the next assertion
103    pub fn not(self) -> Should<'a, Inner, NotAssertionHook, Epsilon> {
104        self.change_optional_generics()
105    }
106}
107
108impl<'a, Inner, Epsilon> Should<'a, Inner, NoOpAssertionHook, Epsilon>
109where
110    Epsilon: EpsilonProvider,
111{
112    /// Changes the assertion hook to or the next assertion with the previous, in case of no
113    /// previous assertion this will be a no-op
114    pub fn or(self) -> Should<'a, Inner, OrAssertionHook, Epsilon> {
115        self.change_optional_generics()
116    }
117}
118
119impl<'a, Inner, Epsilon> Should<'a, Inner, NotAssertionHook, Epsilon>
120where
121    Epsilon: EpsilonProvider,
122{
123    /// Changes the assertion hook to not the next assertion
124    pub fn not(self) -> Should<'a, Inner, NoOpAssertionHook, Epsilon> {
125        self.change_optional_generics()
126    }
127}
128
129pub trait Shoulda {
130    fn should(&self) -> Should<Self>
131    where
132        Self: Sized,
133    {
134        Should::new(self, ResultsContainer::default())
135    }
136}
137
138impl<T> Shoulda for T {}