fluent_asserter/
iterator_asserter.rs

1use super::*;
2
3//TODO: check if we need to use mutable, with a test with mutable variable
4
5pub trait IteratorAssertions<T>
6where
7    T: Debug + PartialEq,
8{
9    /// Checks if the iterator contains the specified element
10    fn contains(&self, expected_item: T);
11    /// Checks if the iterator contains the specified elements
12    fn contains_all(&self, expected_items: &[T]);
13    /// Checks if the iterator has the specified count
14    fn has_count(&self, expected_count: usize);
15    /// Checks if the iterator does not contain any of the specified elements
16    fn does_not_contain_any(&self, not_expected_items: &[T]);
17    /// Checks if the iterator is empty
18    fn is_empty(&self);
19    /// Checks if the iterator is not empty
20    fn is_not_empty(&self);
21}
22
23pub trait IteratorSatisfiesAssertion<T> {
24    /// Checks if the elements of the iterators satisfies the specified assertions
25    ///
26    /// # Examples
27    ///
28    /// ```rust
29    /// #[derive(Clone)]
30    /// struct Person {
31    ///     name: String,
32    ///     age: i32,
33    /// }
34    ///
35    /// #[test]
36    /// fn iterator_assertion_for_struct() {
37    ///     let people: Vec<Person> = vec![
38    ///         Person {
39    ///             name: String::from("Daniel"),
40    ///             age: 32,
41    ///         },
42    ///         Person {
43    ///             name: String::from("Jimmy"),
44    ///             age: 45,
45    ///         },
46    ///     ];
47    ///
48    ///     assert_that!(people).satisfies_respectively(with_asserters!(
49    ///             |person1: &Person| {
50    ///                 assert_that!(&person1.name).is_equal_to(&String::from("Daniel"));
51    ///                 assert_that!(&person1.age).is_equal_to(&32);
52    ///             },
53    ///             |person2: &Person| {
54    ///                 assert_that!(&person2.name).is_equal_to(&String::from("Jimmy"));
55    ///                 assert_that!(&person2.age).is_equal_to(&45);
56    ///             }
57    ///         ));
58    /// }
59    /// ```
60    ///
61    fn satisfies_respectively(&self, asserter: Vec<Box<dyn Fn(&T)>>);
62}
63
64impl<T, K> IteratorAssertions<T> for Asserter<K>
65where
66    T: Debug + PartialEq,
67    K: IntoIterator<Item = T> + Clone,
68{
69    fn contains(&self, expected_value: T) {
70        let contains = &self.value.clone().into_iter().any(|i| i == expected_value);
71        if !contains {
72            panic!(
73                "Expected iterator {:?} to contain {:?}, but it does not.",
74                self.name, expected_value
75            );
76        }
77    }
78
79    fn contains_all(&self, expected_values: &[T]) {
80        let mut missing_items = std::vec::Vec::<&T>::new();
81        for expected_value in expected_values {
82            let contains = contains(&self.value, expected_value);
83            if !contains {
84                missing_items.push(expected_value);
85            }
86        }
87
88        if !missing_items.is_empty() {
89            panic!(
90                "Expected iterator {:?} to contain items {:?}, but it does not contain {:?}.",
91                self.name, expected_values, missing_items
92            );
93        }
94    }
95
96    fn has_count(&self, expected_count: usize) {
97        let count = &self.value.clone().into_iter().count();
98        if *count != expected_count {
99            panic!(
100                "Expected iterator {:?} to have count '{}', but it has '{}'.",
101                &self.name, expected_count, count
102            );
103        }
104    }
105
106    fn does_not_contain_any(&self, not_expected_values: &[T]) {
107        let mut missing_items = std::vec::Vec::<&T>::new();
108
109        for not_expected_value in not_expected_values {
110            let contains = contains(&self.value, not_expected_value);
111            if contains {
112                missing_items.push(not_expected_value);
113            }
114        }
115
116        if !missing_items.is_empty() {
117            panic!(
118                "Expected iterator {:?} to not contain items {:?}, but it contains {:?}.",
119                self.name, not_expected_values, missing_items
120            );
121        }
122    }
123
124    fn is_empty(&self) {
125        let is_empty = is_empty(&self.value);
126
127        if !is_empty {
128            panic!(
129                "Expected iterator {:?} to be empty, but it is not.",
130                self.name
131            );
132        }
133    }
134
135    fn is_not_empty(&self) {
136        let is_empty = is_empty(&self.value);
137
138        if is_empty {
139            panic!(
140                "Expected iterator {:?} to be not empty, but it is.",
141                self.name
142            );
143        }
144    }
145}
146
147fn is_empty<T, K>(iterator: &K) -> bool
148where
149    K: Clone + IntoIterator<Item = T>,
150    T: Debug + PartialEq,
151{
152    iterator.clone().into_iter().next().is_none()
153}
154
155fn contains<T, K>(iterator: &K, expected_value: &T) -> bool
156where
157    K: Clone + IntoIterator<Item = T>,
158    T: Debug + PartialEq,
159{
160    iterator.clone().into_iter().any(|i| i == *expected_value)
161}
162
163impl<T, K> IteratorSatisfiesAssertion<T> for Asserter<K>
164where
165    K: IntoIterator<Item = T> + Clone,
166{
167    //TODO: remove Clone somehow
168    fn satisfies_respectively(&self, asserter: Vec<Box<dyn Fn(&T)>>) {
169        //TODO: S - rename to asserters
170        let iter = &self.value.clone().into_iter().collect::<Vec<T>>();
171
172        if iter.len() != asserter.len() {
173            panic!(
174                "Expected number of items to be {}, but was {}.",
175                asserter.len(),
176                iter.len()
177            )
178        }
179
180        for i in 0..asserter.len() {
181            asserter[i](&iter[i])
182        }
183    }
184}
185///Helper macro to be used to specify assertions [`Receiver<T>`]
186#[macro_export]
187macro_rules! with_asserters {
188    ($($closure:expr),*)  => {
189        vec![
190            $( Box::new($closure) as Box<dyn for<'a> Fn(&'a _) -> _> ),*
191        ]
192    };
193}