googletest/matchers/
each_matcher.rs1use crate::description::Description;
16use crate::matcher::{Matcher, MatcherBase, MatcherResult};
17use std::fmt::Debug;
18
19pub fn each<MatcherT>(inner: MatcherT) -> EachMatcher<MatcherT> {
53 EachMatcher { inner }
54}
55
56#[derive(MatcherBase)]
57pub struct EachMatcher<MatcherT> {
58 inner: MatcherT,
59}
60
61impl<ElementT: Debug + Copy, ActualT: Debug + Copy, MatcherT> Matcher<ActualT>
62 for EachMatcher<MatcherT>
63where
64 ActualT: IntoIterator<Item = ElementT>,
65 MatcherT: Matcher<ElementT>,
66{
67 fn matches(&self, actual: ActualT) -> MatcherResult {
68 for element in actual {
69 if self.inner.matches(element).is_no_match() {
70 return MatcherResult::NoMatch;
71 }
72 }
73 MatcherResult::Match
74 }
75
76 fn explain_match(&self, actual: ActualT) -> Description {
77 let mut non_matching_elements = Vec::new();
78 for (index, element) in actual.into_iter().enumerate() {
79 if self.inner.matches(element).is_no_match() {
80 non_matching_elements.push((index, element, self.inner.explain_match(element)));
81 }
82 }
83 if non_matching_elements.is_empty() {
84 return format!("whose each element {}", self.inner.describe(MatcherResult::Match))
85 .into();
86 }
87 if non_matching_elements.len() == 1 {
88 let (idx, element, explanation) = non_matching_elements.remove(0);
89 return format!("whose element #{idx} is {element:?}, {explanation}").into();
90 }
91
92 let failed_indexes = non_matching_elements
93 .iter()
94 .map(|&(idx, _, _)| format!("#{idx}"))
95 .collect::<Vec<_>>()
96 .join(", ");
97 let element_explanations = non_matching_elements
98 .iter()
99 .map(|&(_, element, ref explanation)| format!("{element:?}, {explanation}"))
100 .collect::<Description>()
101 .indent();
102 format!("whose elements {failed_indexes} don't match\n{element_explanations}").into()
103 }
104
105 fn describe(&self, matcher_result: MatcherResult) -> Description {
106 match matcher_result {
107 MatcherResult::Match => {
108 format!("only contains elements that {}", self.inner.describe(MatcherResult::Match))
109 .into()
110 }
111 MatcherResult::NoMatch => {
112 format!("contains no element that {}", self.inner.describe(MatcherResult::Match))
113 .into()
114 }
115 }
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use crate::prelude::*;
122 use crate::Result;
123 use indoc::indoc;
124 use std::collections::HashSet;
125
126 #[test]
127 fn each_matches_empty_vec() -> Result<()> {
128 let value: Vec<i32> = vec![];
129 verify_that!(value, each(gt(&0)))
130 }
131
132 #[test]
133 fn each_matches_vec_with_one_element() -> Result<()> {
134 let value = vec![1];
135 verify_that!(value, each(gt(&0)))
136 }
137
138 #[test]
139 fn each_matches_vec_with_two_elements() -> Result<()> {
140 let value = vec![1, 2];
141 verify_that!(value, each(gt(&0)))
142 }
143
144 #[test]
145 fn each_matches_slice_with_one_element() -> Result<()> {
146 let value = &[1];
147 verify_that!(*value, each(gt(0)))
148 }
149
150 #[test]
151 fn each_matches_hash_set_with_one_element() -> Result<()> {
152 let value: HashSet<i32> = [1].into();
153 verify_that!(value, each(gt(&0)))
154 }
155
156 #[test]
157 fn each_does_not_match_when_first_element_does_not_match() -> Result<()> {
158 let value = vec![0];
159 verify_that!(value, not(each(gt(&1))))
160 }
161
162 #[test]
163 fn each_does_not_match_when_second_element_does_not_match() -> Result<()> {
164 let value = vec![2, 0];
165 verify_that!(value, not(each(gt(&1))))
166 }
167
168 #[test]
169 fn each_shows_correct_message_when_first_item_does_not_match() -> Result<()> {
170 let result = verify_that!(vec![0, 2, 3], each(gt(&0)));
171
172 verify_that!(
173 result,
174 err(displays_as(contains_substring(indoc!(
175 "
176 Value of: vec![0, 2, 3]
177 Expected: only contains elements that is greater than 0
178 Actual: [0, 2, 3],
179 whose element #0 is 0, which is less than or equal to 0"
180 ))))
181 )
182 }
183
184 #[test]
185 fn each_shows_correct_message_when_second_item_does_not_match() -> Result<()> {
186 let result = verify_that!(vec![1, 0, 3], each(gt(&0)));
187
188 verify_that!(
189 result,
190 err(displays_as(contains_substring(indoc!(
191 "
192 Value of: vec![1, 0, 3]
193 Expected: only contains elements that is greater than 0
194 Actual: [1, 0, 3],
195 whose element #1 is 0, which is less than or equal to 0"
196 ))))
197 )
198 }
199
200 #[test]
201 fn each_shows_correct_message_when_first_two_items_do_not_match() -> Result<()> {
202 let result = verify_that!(vec![0, 1, 3], each(gt(&1)));
203
204 verify_that!(
205 result,
206 err(displays_as(contains_substring(indoc!(
207 "
208 Value of: vec![0, 1, 3]
209 Expected: only contains elements that is greater than 1
210 Actual: [0, 1, 3],
211 whose elements #0, #1 don't match
212 0, which is less than or equal to 1
213 1, which is less than or equal to 1"
214 ))))
215 )
216 }
217 #[test]
218 fn each_shows_inner_explanation() -> Result<()> {
219 let result = verify_that!(vec![vec![1, 2], vec![1]], each(each(eq(&1))));
220
221 verify_that!(
222 result,
223 err(displays_as(contains_substring(indoc!(
224 "
225 Expected: only contains elements that only contains elements that is equal to 1
226 Actual: [[1, 2], [1]],
227 whose element #0 is [1, 2], whose element #1 is 2, which isn't equal to 1"
228 ))))
229 )
230 }
231}