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::description::Description;
16 use crate::matcher::{Matcher, MatcherResult};
17 use crate::matcher_support::count_elements::count_elements;
18 use std::{fmt::Debug, marker::PhantomData};
19 
20 /// Matches a container whose number of elements matches `expected`.
21 ///
22 /// This matches against a container over which one can iterate. This includes
23 /// the standard Rust containers, arrays, and (when dereferenced) slices. More
24 /// precisely, a shared borrow of the actual type must implement
25 /// [`IntoIterator`].
26 ///
27 /// ```
28 /// # use googletest::prelude::*;
29 /// # fn should_pass() -> Result<()> {
30 /// let array = [1,2,3];
31 /// verify_that!(array, len(eq(3)))?;
32 /// let vec = vec![1,2,3];
33 /// verify_that!(vec, len(eq(3)))?;
34 /// let slice = vec.as_slice();
35 /// verify_that!(*slice, len(eq(3)))?;
36 /// #     Ok(())
37 /// # }
38 /// # should_pass().unwrap();
39 /// ```
40 ///
41 /// The parameter `expected` can be any integer numeric matcher.
42 ///
43 /// ```
44 /// # use googletest::prelude::*;
45 /// # fn should_pass() -> Result<()> {
46 /// let vec = vec![1,2,3];
47 /// verify_that!(vec, len(gt(1)))?;
48 /// #     Ok(())
49 /// # }
50 /// # should_pass().unwrap();
51 /// ```
len<T: Debug + ?Sized, E: Matcher<ActualT = usize>>(expected: E) -> impl Matcher<ActualT = T> where for<'a> &'a T: IntoIterator,52 pub fn len<T: Debug + ?Sized, E: Matcher<ActualT = usize>>(expected: E) -> impl Matcher<ActualT = T>
53 where
54     for<'a> &'a T: IntoIterator,
55 {
56     LenMatcher { expected, phantom: Default::default() }
57 }
58 
59 struct LenMatcher<T: ?Sized, E> {
60     expected: E,
61     phantom: PhantomData<T>,
62 }
63 
64 impl<T: Debug + ?Sized, E: Matcher<ActualT = usize>> Matcher for LenMatcher<T, E>
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         self.expected.matches(&count_elements(actual))
72     }
73 
describe(&self, matcher_result: MatcherResult) -> Description74     fn describe(&self, matcher_result: MatcherResult) -> Description {
75         match matcher_result {
76             MatcherResult::Match => {
77                 format!("has length, which {}", self.expected.describe(MatcherResult::Match)).into()
78             }
79             MatcherResult::NoMatch => {
80                 format!("has length, which {}", self.expected.describe(MatcherResult::NoMatch))
81                     .into()
82             }
83         }
84     }
85 
explain_match(&self, actual: &T) -> Description86     fn explain_match(&self, actual: &T) -> Description {
87         let actual_size = count_elements(actual);
88         format!("which has length {}, {}", actual_size, self.expected.explain_match(&actual_size))
89             .into()
90     }
91 }
92 
93 #[cfg(test)]
94 mod tests {
95     use super::len;
96     use crate::description::Description;
97     use crate::matcher::{Matcher, MatcherResult};
98     use crate::prelude::*;
99     use indoc::indoc;
100     use std::collections::{
101         BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque,
102     };
103     use std::fmt::Debug;
104     use std::marker::PhantomData;
105 
106     #[test]
len_matcher_match_vec() -> Result<()>107     fn len_matcher_match_vec() -> Result<()> {
108         let value = vec![1, 2, 3];
109         verify_that!(value, len(eq(3)))
110     }
111 
112     #[test]
len_matcher_match_array_reference() -> Result<()>113     fn len_matcher_match_array_reference() -> Result<()> {
114         let value = &[1, 2, 3];
115         verify_that!(*value, len(eq(3)))
116     }
117 
118     #[test]
len_matcher_match_slice_of_array() -> Result<()>119     fn len_matcher_match_slice_of_array() -> Result<()> {
120         let value = &[1, 2, 3];
121         verify_that!(value[0..1], len(eq(1)))
122     }
123 
124     #[test]
len_matcher_match_slice_of_vec() -> Result<()>125     fn len_matcher_match_slice_of_vec() -> Result<()> {
126         let value = vec![1, 2, 3];
127         let slice = value.as_slice();
128         verify_that!(*slice, len(eq(3)))
129     }
130 
131     #[test]
len_matcher_match_sized_slice() -> Result<()>132     fn len_matcher_match_sized_slice() -> Result<()> {
133         let value = [1, 2, 3];
134         verify_that!(value, len(eq(3)))
135     }
136 
137     #[test]
len_matcher_match_btreemap() -> Result<()>138     fn len_matcher_match_btreemap() -> Result<()> {
139         let value = BTreeMap::from([(1, 2), (2, 3), (3, 4)]);
140         verify_that!(value, len(eq(3)))
141     }
142 
143     #[test]
len_matcher_match_btreeset() -> Result<()>144     fn len_matcher_match_btreeset() -> Result<()> {
145         let value = BTreeSet::from([1, 2, 3]);
146         verify_that!(value, len(eq(3)))
147     }
148 
149     #[test]
len_matcher_match_binaryheap() -> Result<()>150     fn len_matcher_match_binaryheap() -> Result<()> {
151         let value = BinaryHeap::from([1, 2, 3]);
152         verify_that!(value, len(eq(3)))
153     }
154 
155     #[test]
len_matcher_match_hashmap() -> Result<()>156     fn len_matcher_match_hashmap() -> Result<()> {
157         let value = HashMap::from([(1, 2), (2, 3), (3, 4)]);
158         verify_that!(value, len(eq(3)))
159     }
160 
161     #[test]
len_matcher_match_hashset() -> Result<()>162     fn len_matcher_match_hashset() -> Result<()> {
163         let value = HashSet::from([1, 2, 3]);
164         verify_that!(value, len(eq(3)))
165     }
166 
167     #[test]
len_matcher_match_linkedlist() -> Result<()>168     fn len_matcher_match_linkedlist() -> Result<()> {
169         let value = LinkedList::from([1, 2, 3]);
170         verify_that!(value, len(eq(3)))
171     }
172 
173     #[test]
len_matcher_match_vecdeque() -> Result<()>174     fn len_matcher_match_vecdeque() -> Result<()> {
175         let value = VecDeque::from([1, 2, 3]);
176         verify_that!(value, len(eq(3)))
177     }
178 
179     #[test]
len_matcher_explain_match() -> Result<()>180     fn len_matcher_explain_match() -> Result<()> {
181         struct TestMatcher<T>(PhantomData<T>);
182         impl<T: Debug> Matcher for TestMatcher<T> {
183             type ActualT = T;
184 
185             fn matches(&self, _: &T) -> MatcherResult {
186                 false.into()
187             }
188 
189             fn describe(&self, _: MatcherResult) -> Description {
190                 "called described".into()
191             }
192 
193             fn explain_match(&self, _: &T) -> Description {
194                 "called explain_match".into()
195             }
196         }
197         verify_that!(
198             len(TestMatcher(Default::default())).explain_match(&[1, 2, 3]),
199             displays_as(eq("which has length 3, called explain_match"))
200         )
201     }
202 
203     #[test]
len_matcher_error_message() -> Result<()>204     fn len_matcher_error_message() -> Result<()> {
205         let result = verify_that!(vec![1, 2, 3, 4], len(eq(3)));
206         verify_that!(
207             result,
208             err(displays_as(contains_substring(indoc!(
209                 "
210                 Value of: vec![1, 2, 3, 4]
211                 Expected: has length, which is equal to 3
212                 Actual: [1, 2, 3, 4],
213                   which has length 4, which isn't equal to 3"
214             ))))
215         )
216     }
217 }
218