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