1 // Copyright 2023 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 // There are no visible documentation elements in this module; the declarative 16 // macro is documented in the matcher module. 17 #![doc(hidden)] 18 19 /// Matches an object which, upon calling the given method on it with the given 20 /// arguments, produces a value matched by the given inner matcher. 21 /// 22 /// This is particularly useful as a nested matcher when the desired 23 /// property cannot be accessed through a field and must instead be 24 /// extracted through a method call. For example: 25 /// 26 /// ``` 27 /// # use googletest::prelude::*; 28 /// #[derive(Debug)] 29 /// pub struct MyStruct { 30 /// a_field: u32, 31 /// } 32 /// 33 /// impl MyStruct { 34 /// pub fn get_a_field(&self) -> u32 { self.a_field } 35 /// } 36 /// 37 /// let value = vec![MyStruct { a_field: 100 }]; 38 /// verify_that!(value, contains(property!(&MyStruct.get_a_field(), eq(100)))) 39 /// # .unwrap(); 40 /// ``` 41 /// 42 /// 43 /// If the inner matcher is `eq(...)`, it can be omitted: 44 /// 45 /// ``` 46 /// # use googletest::prelude::*; 47 /// #[derive(Debug)] 48 /// pub struct MyStruct { 49 /// a_field: u32, 50 /// } 51 /// 52 /// impl MyStruct { 53 /// pub fn get_a_field(&self) -> u32 { self.a_field } 54 /// } 55 /// 56 /// let value = vec![MyStruct { a_field: 100 }]; 57 /// verify_that!(value, contains(property!(&MyStruct.get_a_field(), 100))) 58 /// # .unwrap(); 59 /// ``` 60 /// 61 /// **Important**: The method should be pure function with a deterministic 62 /// output and no side effects. In particular, in the event of an assertion 63 /// failure, it will be invoked a second time, with the assertion failure output 64 /// reflecting the *second* invocation. 65 /// 66 /// The method may also take additional litteral arguments: 67 /// 68 /// ``` 69 /// # use googletest::prelude::*; 70 /// # #[derive(Debug)] 71 /// # pub struct MyStruct { 72 /// # a_field: u32, 73 /// # } 74 /// impl MyStruct { 75 /// pub fn add_to_a_field(&self, a: u32) -> u32 { self.a_field + a } 76 /// } 77 /// 78 /// # let value = vec![MyStruct { a_field: 100 }]; 79 /// verify_that!(value, contains(property!(&MyStruct.add_to_a_field(50), eq(150)))) 80 /// # .unwrap(); 81 /// ``` 82 /// 83 /// The arguments must be litteral as `property!` is not able to capture them. 84 /// 85 /// # Specification of the property pattern 86 /// 87 /// The specification of the field follow the syntax: `(ref)? (&)? 88 /// $TYPE.$PROPERTY\($ARGUMENT\)`. 89 /// 90 /// The `&` allows to specify whether this matcher matches against an actual of 91 /// type `$TYPE` (`$TYPE` must implement `Copy`) or a `&$TYPE`. 92 /// 93 /// For instance: 94 /// 95 /// ``` 96 /// # use googletest::prelude::*; 97 /// #[derive(Debug)] 98 /// pub struct AStruct; 99 /// 100 /// impl AStruct { 101 /// fn a_property(&self) -> i32 {32} 102 /// } 103 /// # fn should_pass() -> Result<()> { 104 /// verify_that!(AStruct, property!(&AStruct.a_property(), eq(32)))?; 105 /// # Ok(()) 106 /// # } 107 /// # should_pass().unwrap(); 108 /// ``` 109 /// 110 /// ``` 111 /// # use googletest::prelude::*; 112 /// #[derive(Debug, Clone, Copy)] 113 /// pub struct AStruct; 114 /// 115 /// impl AStruct { 116 /// fn a_property(self) -> i32 {32} 117 /// } 118 /// # fn should_pass() -> Result<()> { 119 /// verify_that!(AStruct, property!(AStruct.a_property(), eq(32)))?; 120 /// # Ok(()) 121 /// # } 122 /// # should_pass().unwrap(); 123 /// ``` 124 /// 125 /// The `ref` allows to bind the property returned value by reference, which is 126 /// required if the field type does not implement `Copy`. 127 /// 128 /// For instance: 129 /// 130 /// ``` 131 /// # use googletest::prelude::*; 132 /// #[derive(Debug)] 133 /// pub struct AStruct; 134 /// 135 /// impl AStruct { 136 /// fn a_property(&self) -> i32 {32} 137 /// } 138 /// # fn should_pass() -> Result<()> { 139 /// verify_that!(AStruct, property!(&AStruct.a_property(), eq(32)))?; 140 /// # Ok(()) 141 /// # } 142 /// # should_pass().unwrap(); 143 /// ``` 144 /// 145 /// If `property!` is qualified by both `&` and `ref`, they can both be omitted. 146 /// 147 /// ``` 148 /// # use googletest::prelude::*; 149 /// #[derive(Debug)] 150 /// pub struct AStruct; 151 /// 152 /// impl AStruct { 153 /// fn a_property(&self) -> String {"32".into()} 154 /// } 155 /// # fn should_pass() -> Result<()> { 156 /// verify_that!(AStruct, property!(&AStruct.a_property(), ref eq("32")))?; 157 /// verify_that!(AStruct, property!(AStruct.a_property(), eq("32")))?; 158 /// # Ok(()) 159 /// # } 160 /// # should_pass().unwrap(); 161 /// ``` 162 /// 163 /// This macro is analogous to [`field`][crate::matchers::field], except that it 164 /// extracts the datum to be matched from the given object by invoking a method 165 /// rather than accessing a field. 166 /// 167 /// The list of arguments may optionally have a trailing comma. 168 #[macro_export] 169 #[doc(hidden)] 170 macro_rules! __property { 171 ($($t:tt)*) => { $crate::property_internal!($($t)*) } 172 } 173 174 // Internal-only macro created so that the macro definition does not appear in 175 // generated documentation. 176 #[doc(hidden)] 177 #[macro_export] 178 macro_rules! property_internal { 179 180 (&$($t:ident)::+.$method:tt($($argument:tt),* $(,)?), ref $m:expr) => {{ 181 $crate::matchers::__internal_unstable_do_not_depend_on_these::property_ref_matcher( 182 |o: &$($t)::+| $($t)::+::$method(o, $($argument),*), 183 &stringify!($method($($argument),*)), 184 $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m)) 185 }}; 186 ($($t:ident)::+.$method:tt($($argument:tt),* $(,)?), ref $m:expr) => {{ 187 $crate::matchers::__internal_unstable_do_not_depend_on_these::property_ref_matcher( 188 |o: $($t)::+| $($t)::+::$method(o, $($argument),*), 189 &stringify!($method($($argument),*)), 190 $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m)) 191 }}; 192 (& $($t:ident)::+.$method:tt($($argument:tt),* $(,)?), $m:expr) => {{ 193 $crate::matchers::__internal_unstable_do_not_depend_on_these::property_matcher( 194 |o: &&$($t)::+| o.$method($($argument),*), 195 &stringify!($method($($argument),*)), 196 $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m)) 197 }}; 198 ($($t:ident)::+.$method:tt($($argument:tt),* $(,)?), $m:expr) => {{ 199 $crate::matchers::__internal_unstable_do_not_depend_on_these::property_matcher( 200 |o: &$($t)::+| o.$method($($argument),*), 201 &stringify!($method($($argument),*)), 202 $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m)) 203 }}; 204 } 205 206 /// Items for use only by the declarative macros in this module. 207 /// 208 /// **For internal use only. API stablility is not guaranteed!** 209 #[doc(hidden)] 210 pub mod internal { 211 use crate::{ 212 description::Description, 213 matcher::{Matcher, MatcherBase, MatcherResult}, 214 }; 215 use std::fmt::Debug; 216 217 /// **For internal use only. API stablility is not guaranteed!** 218 #[doc(hidden)] property_matcher<OuterT: Debug, InnerT: Debug, MatcherT>( extractor: fn(&OuterT) -> InnerT, property_desc: &'static str, inner: MatcherT, ) -> PropertyMatcher<OuterT, InnerT, MatcherT>219 pub fn property_matcher<OuterT: Debug, InnerT: Debug, MatcherT>( 220 extractor: fn(&OuterT) -> InnerT, 221 property_desc: &'static str, 222 inner: MatcherT, 223 ) -> PropertyMatcher<OuterT, InnerT, MatcherT> { 224 PropertyMatcher { extractor, property_desc, inner } 225 } 226 227 #[derive(MatcherBase)] 228 pub struct PropertyMatcher<OuterT, InnerT, MatcherT> { 229 extractor: fn(&OuterT) -> InnerT, 230 property_desc: &'static str, 231 inner: MatcherT, 232 } 233 234 impl<InnerT, OuterT, MatcherT> Matcher<OuterT> for PropertyMatcher<OuterT, InnerT, MatcherT> 235 where 236 InnerT: Debug + Copy, 237 OuterT: Debug + Copy, 238 MatcherT: Matcher<InnerT>, 239 { matches(&self, actual: OuterT) -> MatcherResult240 fn matches(&self, actual: OuterT) -> MatcherResult { 241 self.inner.matches((self.extractor)(&actual)) 242 } 243 describe(&self, matcher_result: MatcherResult) -> Description244 fn describe(&self, matcher_result: MatcherResult) -> Description { 245 format!( 246 "has property `{}`, which {}", 247 self.property_desc, 248 self.inner.describe(matcher_result) 249 ) 250 .into() 251 } 252 explain_match(&self, actual: OuterT) -> Description253 fn explain_match(&self, actual: OuterT) -> Description { 254 let actual_inner = (self.extractor)(&actual); 255 format!( 256 "whose property `{}` is `{:#?}`, {}", 257 self.property_desc, 258 actual_inner, 259 self.inner.explain_match(actual_inner) 260 ) 261 .into() 262 } 263 } 264 265 impl<'a, InnerT, OuterT, MatcherT> Matcher<&'a OuterT> for PropertyMatcher<OuterT, InnerT, MatcherT> 266 where 267 InnerT: Debug, 268 OuterT: Debug, 269 MatcherT: for<'b> Matcher<&'b InnerT>, 270 { matches(&self, actual: &'a OuterT) -> MatcherResult271 fn matches(&self, actual: &'a OuterT) -> MatcherResult { 272 self.inner.matches(&(self.extractor)(actual)) 273 } 274 describe(&self, matcher_result: MatcherResult) -> Description275 fn describe(&self, matcher_result: MatcherResult) -> Description { 276 format!( 277 "has property `{}`, which {}", 278 self.property_desc, 279 self.inner.describe(matcher_result) 280 ) 281 .into() 282 } 283 explain_match(&self, actual: &'a OuterT) -> Description284 fn explain_match(&self, actual: &'a OuterT) -> Description { 285 let actual_inner = (self.extractor)(actual); 286 format!( 287 "whose property `{}` is `{:#?}`, {}", 288 self.property_desc, 289 actual_inner, 290 self.inner.explain_match(&actual_inner) 291 ) 292 .into() 293 } 294 } 295 296 /// **For internal use only. API stablility is not guaranteed!** 297 #[doc(hidden)] property_ref_matcher<OuterT, InnerT, ExtractorT, MatcherT>( extractor: ExtractorT, property_desc: &'static str, inner: MatcherT, ) -> PropertyRefMatcher<ExtractorT, MatcherT> where OuterT: Debug, InnerT: Debug, MatcherT: for<'a> Matcher<&'a InnerT>, ExtractorT: Fn(OuterT) -> InnerT,298 pub fn property_ref_matcher<OuterT, InnerT, ExtractorT, MatcherT>( 299 extractor: ExtractorT, 300 property_desc: &'static str, 301 inner: MatcherT, 302 ) -> PropertyRefMatcher<ExtractorT, MatcherT> 303 where 304 OuterT: Debug, 305 InnerT: Debug, 306 MatcherT: for<'a> Matcher<&'a InnerT>, 307 ExtractorT: Fn(OuterT) -> InnerT, 308 { 309 PropertyRefMatcher { extractor, property_desc, inner } 310 } 311 312 #[derive(MatcherBase)] 313 pub struct PropertyRefMatcher<ExtractorT, MatcherT> { 314 extractor: ExtractorT, 315 property_desc: &'static str, 316 inner: MatcherT, 317 } 318 319 impl< 320 InnerT: Debug, 321 OuterT: Debug + Copy, 322 MatcherT: for<'a> Matcher<&'a InnerT>, 323 ExtractorT: Fn(OuterT) -> InnerT, 324 > Matcher<OuterT> for PropertyRefMatcher<ExtractorT, MatcherT> 325 { matches(&self, actual: OuterT) -> MatcherResult326 fn matches(&self, actual: OuterT) -> MatcherResult { 327 self.inner.matches(&(self.extractor)(actual)) 328 } 329 describe(&self, matcher_result: MatcherResult) -> Description330 fn describe(&self, matcher_result: MatcherResult) -> Description { 331 format!( 332 "has property `{}`, which {}", 333 self.property_desc, 334 self.inner.describe(matcher_result) 335 ) 336 .into() 337 } 338 explain_match(&self, actual: OuterT) -> Description339 fn explain_match(&self, actual: OuterT) -> Description { 340 let actual_inner = (self.extractor)(actual); 341 format!( 342 "whose property `{}` is `{:#?}`, {}", 343 self.property_desc, 344 actual_inner, 345 self.inner.explain_match(&actual_inner) 346 ) 347 .into() 348 } 349 } 350 } 351