Skip to main content

googletest/matchers/
len_matcher.rs

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