1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 use crate::{
16     description::Description,
17     matcher::{Matcher, MatcherResult},
18 };
19 use std::{fmt::Debug, marker::PhantomData};
20 
21 /// Matches an empty container.
22 ///
23 /// `T` can be any container such that `&T` implements `IntoIterator`. For
24 /// instance, `T` can be a common container like `Vec` and
25 /// [`HashSet`][std::collections::HashSet].
26 ///
27 /// ```
28 /// # use googletest::prelude::*;
29 /// # use std::collections::HashSet;
30 /// # fn should_pass() -> Result<()> {
31 /// let value: Vec<i32> = vec![];
32 /// verify_that!(value, empty())?;
33 /// let value: HashSet<i32> = HashSet::new();
34 /// verify_that!(value, empty())?;
35 /// #     Ok(())
36 /// # }
37 /// # should_pass().unwrap();
38 /// ```
39 ///
40 /// One can also check whether a slice is empty by dereferencing it:
41 ///
42 /// ```
43 /// # use googletest::prelude::*;
44 /// # use std::collections::HashSet;
45 /// # fn should_pass() -> Result<()> {
46 /// let value: &[u32] = &[];
47 /// verify_that!(*value, empty())?;
48 /// #     Ok(())
49 /// # }
50 /// # should_pass().unwrap();
51 /// ```
52 
empty<T: Debug + ?Sized>() -> impl Matcher<ActualT = T> where for<'a> &'a T: IntoIterator,53 pub fn empty<T: Debug + ?Sized>() -> impl Matcher<ActualT = T>
54 where
55     for<'a> &'a T: IntoIterator,
56 {
57     EmptyMatcher { phantom: Default::default() }
58 }
59 
60 struct EmptyMatcher<T: ?Sized> {
61     phantom: PhantomData<T>,
62 }
63 
64 impl<T: Debug + ?Sized> Matcher for EmptyMatcher<T>
65 where
66     for<'a> &'a T: IntoIterator,
67 {
68     type ActualT = T;
69 
matches(&self, actual: &T) -> MatcherResult70     fn matches(&self, actual: &T) -> MatcherResult {
71         actual.into_iter().next().is_none().into()
72     }
73 
describe(&self, matcher_result: MatcherResult) -> Description74     fn describe(&self, matcher_result: MatcherResult) -> Description {
75         if matcher_result.into() { "is empty" } else { "isn't empty" }.into()
76     }
77 }
78 
79 #[cfg(test)]
80 mod tests {
81     use super::empty;
82     use crate::prelude::*;
83     use std::collections::HashSet;
84 
85     #[test]
empty_matcher_match_empty_vec() -> Result<()>86     fn empty_matcher_match_empty_vec() -> Result<()> {
87         let value: Vec<i32> = vec![];
88         verify_that!(value, empty())
89     }
90 
91     #[test]
empty_matcher_does_not_match_empty_vec() -> Result<()>92     fn empty_matcher_does_not_match_empty_vec() -> Result<()> {
93         let value = vec![1, 2, 3];
94         verify_that!(value, not(empty()))
95     }
96 
97     #[test]
empty_matcher_matches_empty_slice() -> Result<()>98     fn empty_matcher_matches_empty_slice() -> Result<()> {
99         let value: &[i32] = &[];
100         verify_that!(*value, empty())
101     }
102 
103     #[test]
empty_matcher_matches_empty_hash_set() -> Result<()>104     fn empty_matcher_matches_empty_hash_set() -> Result<()> {
105         let value: HashSet<i32> = HashSet::new();
106         verify_that!(value, empty())
107     }
108 }
109