shoulda_core 0.2.1

derive macro for test assertions
Documentation
use crate::assertion_hook::{AssertionHook, NoOpAssertionHook};
use crate::epsilon_provider::EpsilonProvider;
use crate::{Should, ShouldaEqual};
use std::borrow::Borrow;
use std::fmt::Debug;

fn contains_sequence<Epsilon: EpsilonProvider, K: ShouldaEqual, L: Borrow<K>>(
    sequence: &Vec<L>,
    v: &Vec<&K>,
) -> bool {
    if sequence.is_empty() {
        return true;
    }
    let mut curr: Option<usize> = None;
    let mut iter = v.iter();
    (loop {
        match iter.next() {
            None => break false,
            Some(v) => {
                curr = match curr {
                    None => {
                        if sequence.first().unwrap().borrow().should_eq::<Epsilon>(v) {
                            Some(1)
                        } else {
                            None
                        }
                    }
                    Some(curr) => {
                        if curr == sequence.len() {
                            break true;
                        }
                        if sequence[curr].borrow().should_eq::<Epsilon>(v) {
                            Some(curr + 1)
                        } else {
                            None
                        }
                    }
                }
            }
        }
    } || (curr.is_some() && curr.unwrap() == sequence.len()))
}

impl<'a, T, K, Hook, Epsilon> Should<'a, T, Hook, Epsilon>
where
    &'a T: IntoIterator<Item = &'a K>,
    T: Debug,
    K: Debug,
    K: ShouldaEqual,
    K: 'a,
    Hook: AssertionHook,
    Epsilon: EpsilonProvider,
{
    pub fn contain<I: Borrow<K>>(mut self, item: I) -> Should<'a, T, NoOpAssertionHook, Epsilon> {
        let item = item.borrow();
        let v = self.inner.into_iter().collect::<Vec<&K>>();
        self.internal_assert(
            v.iter().any(|x| x.should_eq::<Epsilon>(&item)),
            format!("{:?} did not contain {:?}", v, item,),
        );
        self.normalize()
    }

    pub fn contain_sequence<L: Borrow<K>, I: IntoIterator<Item = L>>(
        mut self,
        items: I,
    ) -> Should<'a, T, NoOpAssertionHook, Epsilon> {
        let sequence = items.into_iter().collect::<Vec<L>>();
        let v = self.inner.into_iter().collect::<Vec<&K>>();
        self.internal_assert(
            contains_sequence::<Epsilon, _, _>(&sequence, &v),
            format!(
                "{:?} does not contain the sequence {:?}",
                v,
                sequence.iter().map(|x| x.borrow()).collect::<Vec<&K>>()
            ),
        );
        self.normalize()
    }

    pub fn contains<I: Fn(&K) -> bool>(
        mut self,
        predicate: I,
    ) -> Should<'a, T, NoOpAssertionHook, Epsilon> {
        let v = self.inner.into_iter().collect::<Vec<&K>>();
        self.internal_assert(
            v.iter().map(|x| *x).any(predicate),
            format!("{:?} did not fufill the predicate", v),
        );
        self.normalize()
    }
}

#[cfg(test)]
mod tests {
    use crate::Shoulda;

    #[test]
    fn should_contain() {
        vec![1, 2, 3].should().contain(2);
    }

    #[test]
    fn should_not_contain() {
        vec![1, 2, 3].should().not().contain(4);
    }

    #[test]
    fn should_contains() {
        vec![1, 2, 3].should().contains(|x| x % 2 == 0);
    }

    #[test]
    fn should_not_contains() {
        vec![1, 2, 3].should().not().contains(|x| x % 4 == 0);
    }

    #[test]
    fn should_contain_sequence() {
        vec![1, 2, 3, 4]
            .should()
            .contain_sequence(vec![2, 3])
            .and()
            .contain_sequence(vec![1, 2])
            .and()
            .contain_sequence(vec![2, 3]);
    }

    #[test]
    fn should_not_contain_sequence() {
        vec![1, 2, 3, 4]
            .should()
            .not()
            .contain_sequence(vec![1, 3])
            .and()
            .not()
            .contain_sequence(vec![4, 3])
            .and()
            .not()
            .contain_sequence(vec![3, 2]);
    }
}