googletest/matchers/
some_matcher.rs1use crate::{
16 description::Description,
17 matcher::{Matcher, MatcherBase, MatcherResult},
18};
19use std::fmt::Debug;
20
21pub fn some<Inner>(inner: Inner) -> SomeMatcher<Inner> {
42 SomeMatcher { inner }
43}
44
45#[derive(MatcherBase)]
46pub struct SomeMatcher<InnerMatcherT> {
47 inner: InnerMatcherT,
48}
49
50impl<T: Debug + Copy, InnerMatcherT: Matcher<T>> Matcher<Option<T>> for SomeMatcher<InnerMatcherT> {
51 fn matches(&self, actual: Option<T>) -> MatcherResult {
52 actual.map(|v| self.inner.matches(v)).unwrap_or(MatcherResult::NoMatch)
53 }
54
55 fn explain_match(&self, actual: Option<T>) -> Description {
56 match (self.matches(actual), actual) {
57 (_, Some(t)) => {
58 Description::new().text("which has a value").nested(self.inner.explain_match(t))
59 }
60 (_, None) => "which is None".into(),
61 }
62 }
63
64 fn describe(&self, matcher_result: MatcherResult) -> Description {
65 match matcher_result {
66 MatcherResult::Match => {
67 format!("has a value which {}", self.inner.describe(MatcherResult::Match)).into()
68 }
69 MatcherResult::NoMatch => format!(
70 "is None or has a value which {}",
71 self.inner.describe(MatcherResult::NoMatch)
72 )
73 .into(),
74 }
75 }
76}
77
78impl<'a, T: Debug, InnerMatcherT: Matcher<&'a T>> Matcher<&'a Option<T>>
79 for SomeMatcher<InnerMatcherT>
80{
81 fn matches(&self, actual: &'a Option<T>) -> MatcherResult {
82 actual.as_ref().map(|v| self.inner.matches(v)).unwrap_or(MatcherResult::NoMatch)
83 }
84
85 fn explain_match(&self, actual: &'a Option<T>) -> Description {
86 match (self.matches(actual), actual) {
87 (_, Some(t)) => {
88 Description::new().text("which has a value").nested(self.inner.explain_match(t))
89 }
90 (_, None) => "which is None".into(),
91 }
92 }
93
94 fn describe(&self, matcher_result: MatcherResult) -> Description {
95 match matcher_result {
96 MatcherResult::Match => {
97 format!("has a value which {}", self.inner.describe(MatcherResult::Match)).into()
98 }
99 MatcherResult::NoMatch => format!(
100 "is None or has a value which {}",
101 self.inner.describe(MatcherResult::NoMatch)
102 )
103 .into(),
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use crate::matcher::MatcherResult;
111 use crate::prelude::*;
112 use crate::Result;
113 use indoc::indoc;
114
115 #[test]
116 fn some_matches_option_with_value() -> Result<()> {
117 let matcher = some(eq(1));
118
119 let result = matcher.matches(Some(1));
120
121 verify_that!(result, eq(MatcherResult::Match))
122 }
123
124 #[test]
125 fn some_does_not_match_option_with_wrong_value() -> Result<()> {
126 let matcher = some(eq(1));
127
128 let result = matcher.matches(Some(0));
129
130 verify_that!(result, eq(MatcherResult::NoMatch))
131 }
132
133 #[test]
134 fn some_does_not_match_option_with_none() -> Result<()> {
135 let matcher = some(eq(1));
136
137 let result = matcher.matches(None::<i32>);
138
139 verify_that!(result, eq(MatcherResult::NoMatch))
140 }
141
142 #[test]
143 fn some_matches_option_with_by_ref_value() -> Result<()> {
144 verify_that!(Some("123".to_string()), some(eq("123")))
145 }
146
147 #[test]
148 fn some_does_not_match_option_with_wrong_by_ref_value() -> Result<()> {
149 verify_that!(Some("321".to_string()), not(some(eq("123"))))
150 }
151
152 #[test]
153 fn some_does_not_match_option_with_by_ref_none() -> Result<()> {
154 verify_that!(None::<String>, not(some(eq("123"))))
155 }
156
157 #[test]
158 fn some_full_error_message() -> Result<()> {
159 let result = verify_that!(Some(2), some(eq(1)));
160 verify_that!(
161 result,
162 err(displays_as(contains_substring(indoc!(
163 "
164 Value of: Some(2)
165 Expected: has a value which is equal to 1
166 Actual: Some(2),
167 which has a value
168 which isn't equal to 1
169 "
170 ))))
171 )
172 }
173
174 #[test]
175 fn some_describe_matches() -> Result<()> {
176 verify_that!(
177 Matcher::<Option<i32>>::describe(&some(eq(1)), MatcherResult::Match),
178 displays_as(eq("has a value which is equal to 1"))
179 )
180 }
181
182 #[test]
183 fn some_describe_does_not_match() -> Result<()> {
184 verify_that!(
185 Matcher::<Option<i32>>::describe(&some(eq(1)), MatcherResult::NoMatch),
186 displays_as(eq("is None or has a value which isn't equal to 1"))
187 )
188 }
189
190 #[test]
191 fn some_describe_matches_of_by_ref() -> Result<()> {
192 verify_that!(
193 Matcher::<Option<&String>>::describe(&some(eq("123")), MatcherResult::Match),
194 displays_as(eq("has a value which is equal to \"123\""))
195 )
196 }
197
198 #[test]
199 fn some_describe_does_not_match_of_by_ref() -> Result<()> {
200 verify_that!(
201 Matcher::<Option<&String>>::describe(&some(eq("123")), MatcherResult::NoMatch),
202 displays_as(eq("is None or has a value which isn't equal to \"123\""))
203 )
204 }
205
206 #[test]
207 fn some_explain_match_with_none() -> Result<()> {
208 verify_that!(some(eq(1)).explain_match(None::<i32>), displays_as(eq("which is None")))
209 }
210
211 #[test]
212 fn some_explain_match_with_some_success() -> Result<()> {
213 verify_that!(
214 some(eq(1)).explain_match(Some(1)),
215 displays_as(eq("which has a value\n which is equal to 1"))
216 )
217 }
218
219 #[test]
220 fn some_explain_match_with_some_fail() -> Result<()> {
221 verify_that!(
222 some(eq(1)).explain_match(Some(2)),
223 displays_as(eq("which has a value\n which isn't equal to 1"))
224 )
225 }
226
227 #[test]
228 fn some_explain_match_with_none_by_ref() -> Result<()> {
229 verify_that!(
230 some(eq("123")).explain_match(&None::<String>),
231 displays_as(eq("which is None"))
232 )
233 }
234
235 #[test]
236 fn some_explain_match_with_some_success_by_ref() -> Result<()> {
237 verify_that!(
238 some(eq("123")).explain_match(&Some("123".to_string())),
239 displays_as(eq("which has a value\n which is equal to \"123\""))
240 )
241 }
242
243 #[test]
244 fn some_explain_match_with_some_fail_by_ref() -> Result<()> {
245 verify_that!(
246 some(eq("123")).explain_match(&Some("321".to_string())),
247 displays_as(eq("which has a value\n which isn't equal to \"123\""))
248 )
249 }
250}