1use std::borrow::Borrow;
16use std::collections::{BTreeSet, HashSet};
17use std::fmt::Debug;
18use std::hash::Hash;
19
20use crate::assertions::iterator::{check_is_empty, IteratorAssertion};
21use crate::base::{AssertionApi, AssertionResult, AssertionStrategy, Subject};
22use crate::EqualityAssertion;
23
24pub trait SetAssertion<'a, S, T, R> {
53 #[track_caller]
55 fn has_length(&self, length: usize) -> R;
56
57 #[track_caller]
59 fn is_empty(&self) -> R
60 where
61 T: Debug;
62
63 #[track_caller]
65 fn contains<B: Borrow<T>>(&self, expected: B) -> R
66 where
67 T: PartialEq + Eq + Debug + Hash;
68
69 #[track_caller]
71 fn does_not_contain<B>(&self, element: B) -> R
72 where
73 B: Borrow<T>,
74 T: PartialEq + Debug;
75
76 #[track_caller]
78 fn does_not_contain_any<B: Borrow<Vec<T>>>(&self, elements: B) -> R
79 where
80 T: PartialEq + Debug;
81}
82
83impl<'a, T, R, ST> SetAssertion<'a, ST, T, R> for Subject<'a, ST, (), R>
84where
85 AssertionResult: AssertionStrategy<R>,
86 T: Eq + Debug,
87 ST: SetLike<T>,
88{
89 fn has_length(&self, length: usize) -> R {
90 self.new_subject(
91 &self.actual().len(),
92 Some(format!("{}.len()", self.description_or_expr())),
93 (),
94 )
95 .is_equal_to(length)
96 }
97
98 fn is_empty(&self) -> R
99 where
100 T: Debug,
101 {
102 check_is_empty(self.new_result(), self.actual().iter())
103 }
104
105 fn contains<B: Borrow<T>>(&self, expected: B) -> R
106 where
107 T: PartialEq + Eq + Debug + Hash,
108 {
109 self.new_owned_subject(self.actual().iter(), None, ())
110 .contains(expected.borrow())
111 }
112
113 fn does_not_contain<B>(&self, element: B) -> R
114 where
115 B: Borrow<T>,
116 T: PartialEq + Debug,
117 {
118 self.new_owned_subject(self.actual().iter(), None, ())
119 .does_not_contain(element.borrow())
120 }
121
122 fn does_not_contain_any<B: Borrow<Vec<T>>>(&self, elements: B) -> R
123 where
124 T: PartialEq + Debug,
125 {
126 self.new_owned_subject(self.actual().iter(), None, ())
127 .does_not_contain_any(elements.borrow().iter())
128 }
129}
130
131pub trait OrderedSetAssertion<'a, ST, T, R>: SetAssertion<'a, ST, T, R>
161where
162 AssertionResult: AssertionStrategy<R>,
163 T: PartialOrd + Eq + Debug,
164 ST: OrderedSetLike<T>,
165{
166 fn contains_all_of_in_order<OSA, OS>(&self, expected: OSA) -> R
175 where
176 T: PartialOrd + Eq + Debug,
177 OS: OrderedSetLike<T>,
178 OSA: Borrow<OS>;
179
180 fn contains_exactly_in_order<OSA, OS>(&self, expected: OSA) -> R
189 where
190 T: PartialOrd + Eq + Debug,
191 OS: OrderedSetLike<T>,
192 OSA: Borrow<OS>;
193}
194
195impl<'a, T, R, ST> OrderedSetAssertion<'a, ST, T, R> for Subject<'a, ST, (), R>
196where
197 AssertionResult: AssertionStrategy<R>,
198 T: Eq + PartialOrd + Debug,
199 ST: OrderedSetLike<T>,
200{
201 fn contains_all_of_in_order<OSA, OS>(&self, expected: OSA) -> R
202 where
203 T: PartialOrd + Eq + Debug,
204 OS: OrderedSetLike<T>,
205 OSA: Borrow<OS>,
206 {
207 self.new_owned_subject(self.actual().iter(), None, ())
208 .contains_all_of_in_order(expected.borrow().iter())
209 }
210
211 fn contains_exactly_in_order<OSA, OS>(&self, expected: OSA) -> R
212 where
213 T: PartialOrd + Eq + Debug,
214 OS: OrderedSetLike<T>,
215 OSA: Borrow<OS>,
216 {
217 self.new_owned_subject(self.actual().iter(), None, ())
218 .contains_exactly_in_order(expected.borrow().iter())
219 }
220}
221
222pub trait SetLike<T: Eq> {
223 type It<'a>: Iterator<Item = &'a T> + Clone
224 where
225 T: 'a,
226 Self: 'a;
227 fn iter<'a>(&'a self) -> Self::It<'a>;
228
229 fn len(&self) -> usize {
230 self.iter().count()
231 }
232}
233
234pub trait OrderedSetLike<T: PartialOrd + Eq>: SetLike<T> {}
235
236impl<T: Hash + Eq> SetLike<T> for HashSet<T> {
237 type It<'a> = std::collections::hash_set::Iter<'a, T> where T: 'a, Self: 'a;
238
239 fn iter<'a>(&'a self) -> Self::It<'a> {
240 self.into_iter()
241 }
242}
243
244impl<T: Eq + PartialOrd> SetLike<T> for BTreeSet<T> {
245 type It<'a> = std::collections::btree_set::Iter<'a, T> where T: 'a, Self: 'a;
246
247 fn iter<'a>(&'a self) -> Self::It<'a> {
248 self.into_iter()
249 }
250}
251
252impl<T: PartialOrd + Eq> OrderedSetLike<T> for BTreeSet<T> {}
253
254#[cfg(test)]
255mod tests {
256 use std::iter::FromIterator;
257
258 use crate::testing::*;
259
260 use super::*;
261
262 #[test]
263 fn has_length() {
264 assert_that!(HashSet::from_iter(vec![1].iter())).has_length(1);
265 assert_that!(HashSet::from_iter(vec![1, 2, 3].iter())).has_length(3);
266 assert_that!(check_that!(HashSet::from_iter(vec![1].iter())).has_length(3)).facts_are(
267 vec![
268 Fact::new("value of", "HashSet::from_iter(vec![1].iter()).len()"),
269 Fact::new("expected", "3"),
270 Fact::new("actual", "1"),
271 ],
272 );
273 }
274
275 #[test]
276 fn is_empty() {
277 assert_that!(HashSet::<&usize>::from_iter(vec![].iter())).is_empty();
278 assert_that!(check_that!(HashSet::from_iter(vec![1].iter())).is_empty()).facts_are(vec![
279 Fact::new_simple_fact("expected to be empty"),
280 Fact::new_splitter(),
281 Fact::new_multi_value_fact("actual", vec!["1"]),
282 ]);
283 }
284
285 #[test]
286 fn contains() {
287 assert_that!(HashSet::from_iter(vec![1, 2, 3].iter())).contains(&3);
288
289 let result = check_that!(HashSet::from_iter(vec![1, 2, 3].iter())).contains(&10);
291 assert_that!(result).facts_are_at_least(vec![
292 Fact::new("expected to contain", "10"),
293 Fact::new_simple_fact("but did not"),
294 ]);
295 assert_that!(result)
296 .fact_keys()
297 .contains(&"though it did contain".to_string());
298 }
300
301 #[test]
302 fn works_for_btree_set() {
303 let btree_set = BTreeSet::from(["hello", "world"]);
304 let empty: BTreeSet<&str> = BTreeSet::new();
305 assert_that!(btree_set).has_length(2);
306 assert_that!(empty).is_empty();
307 assert_that!(btree_set).contains("hello");
308 assert_that!(btree_set).does_not_contain("nope");
309 assert_that!(btree_set).does_not_contain_any(vec!["one", "two"]);
310 }
311
312 #[test]
313 fn contains_all_of_in_order() {
314 assert_that!(BTreeSet::from([1, 2, 3])).contains_all_of_in_order(BTreeSet::from([]));
315 assert_that!(BTreeSet::from([1, 2, 3])).contains_all_of_in_order(BTreeSet::from([1, 2]));
316 assert_that!(BTreeSet::from([1, 2, 3])).contains_all_of_in_order(BTreeSet::from([2, 3]));
317 assert_that!(BTreeSet::from([1, 2, 3])).contains_all_of_in_order(BTreeSet::from([1, 3]));
318 assert_that!(BTreeSet::from([1, 2, 3])).contains_all_of_in_order(BTreeSet::from([1, 2, 3]));
319 }
320
321 #[test]
322 fn contains_exactly_in_order() {
323 assert_that!(BTreeSet::from([1, 2, 3]))
324 .contains_exactly_in_order(BTreeSet::from([1, 2, 3]));
325 }
326}