@@ -95,37 +95,54 @@ macro_rules! field {
95
95
pub mod internal {
96
96
#[ cfg( not( google3) ) ]
97
97
use crate as googletest;
98
- use googletest:: matcher:: { Matcher , MatcherResult } ;
98
+ use googletest:: matcher:: { MatchExplanation , Matcher , MatcherResult } ;
99
99
use std:: fmt:: Debug ;
100
100
101
101
/// Creates a matcher to verify a specific field of the actual struct using
102
102
/// the provided inner matcher.
103
103
///
104
104
/// **For internal use only. API stablility is not guaranteed!**
105
105
#[ doc( hidden) ]
106
- pub fn field_matcher < O : Debug , I : Debug , InnerMatcher : Matcher < I > > (
107
- field_accessor : fn ( & O ) -> Option < & I > ,
106
+ pub fn field_matcher < OuterT : Debug , InnerT : Debug , InnerMatcher : Matcher < InnerT > > (
107
+ field_accessor : fn ( & OuterT ) -> Option < & InnerT > ,
108
108
field_path : & ' static str ,
109
109
inner : InnerMatcher ,
110
- ) -> impl Matcher < O > {
110
+ ) -> impl Matcher < OuterT > {
111
111
FieldMatcher { field_accessor, field_path, inner }
112
112
}
113
113
114
- struct FieldMatcher < O , I , InnerMatcher > {
115
- field_accessor : fn ( & O ) -> Option < & I > ,
114
+ struct FieldMatcher < OuterT , InnerT , InnerMatcher > {
115
+ field_accessor : fn ( & OuterT ) -> Option < & InnerT > ,
116
116
field_path : & ' static str ,
117
117
inner : InnerMatcher ,
118
118
}
119
119
120
- impl < O : Debug , I : Debug , InnerMatcher : Matcher < I > > Matcher < O > for FieldMatcher < O , I , InnerMatcher > {
121
- fn matches ( & self , actual : & O ) -> MatcherResult {
120
+ impl < OuterT : Debug , InnerT : Debug , InnerMatcher : Matcher < InnerT > > Matcher < OuterT >
121
+ for FieldMatcher < OuterT , InnerT , InnerMatcher >
122
+ {
123
+ fn matches ( & self , actual : & OuterT ) -> MatcherResult {
122
124
if let Some ( value) = ( self . field_accessor ) ( actual) {
123
125
self . inner . matches ( value)
124
126
} else {
125
127
MatcherResult :: DoesNotMatch
126
128
}
127
129
}
128
130
131
+ fn explain_match ( & self , actual : & OuterT ) -> MatchExplanation {
132
+ if let Some ( actual) = ( self . field_accessor ) ( actual) {
133
+ MatchExplanation :: create ( format ! (
134
+ "which has field `{}`, {}" ,
135
+ self . field_path,
136
+ self . inner. explain_match( actual)
137
+ ) )
138
+ } else {
139
+ // TODO(hovinen): This message could be misinterpreted to mean that there were a
140
+ // typo in the field, when it actually means that the actual value uses the
141
+ // wrong enum variant. Reword this appropriately.
142
+ MatchExplanation :: create ( format ! ( "which has no field `{}`" , self . field_path) )
143
+ }
144
+ }
145
+
129
146
fn describe ( & self , matcher_result : MatcherResult ) -> String {
130
147
format ! (
131
148
"has field `{}`, which {}" ,
@@ -144,7 +161,7 @@ mod tests {
144
161
#[ cfg( not( google3) ) ]
145
162
use googletest:: matchers;
146
163
use googletest:: { google_test, verify_that, Result } ;
147
- use matchers:: { eq , not} ;
164
+ use matchers:: { container_eq , contains_substring , displays_as , eq , err , not} ;
148
165
149
166
#[ derive( Debug ) ]
150
167
struct IntField {
@@ -185,6 +202,7 @@ mod tests {
185
202
pub field : i32 ,
186
203
}
187
204
}
205
+
188
206
#[ google_test]
189
207
fn struct_in_other_module_matches ( ) -> Result < ( ) > {
190
208
verify_that ! ( sub:: SubStruct { field: 32 } , field!( sub:: SubStruct . field, eq( 32 ) ) )
@@ -210,7 +228,25 @@ mod tests {
210
228
}
211
229
212
230
#[ google_test]
213
- fn does_not_match_enum_value_with_wrong_enum_value ( ) -> Result < ( ) > {
231
+ fn shows_correct_failure_message_for_wrong_struct_entry ( ) -> Result < ( ) > {
232
+ #[ derive( Debug ) ]
233
+ struct AStruct {
234
+ a : Vec < u32 > ,
235
+ }
236
+ let value = AStruct { a : vec ! [ 1 ] } ;
237
+
238
+ let result = verify_that ! ( value, field!( AStruct . a, container_eq( [ ] ) ) ) ;
239
+
240
+ verify_that ! (
241
+ result,
242
+ err( displays_as( contains_substring(
243
+ "which has field `a`, which contains the unexpected element 1"
244
+ ) ) )
245
+ )
246
+ }
247
+
248
+ #[ google_test]
249
+ fn does_not_match_enum_value_with_wrong_enum_variant ( ) -> Result < ( ) > {
214
250
#[ derive( Debug ) ]
215
251
enum AnEnum {
216
252
#[ allow( dead_code) ] // This variant is intentionally unused.
@@ -222,6 +258,23 @@ mod tests {
222
258
verify_that ! ( value, not( field!( AnEnum :: AValue . 0 , eq( 123 ) ) ) )
223
259
}
224
260
261
+ #[ google_test]
262
+ fn shows_correct_failure_message_for_wrong_enum_value ( ) -> Result < ( ) > {
263
+ #[ derive( Debug ) ]
264
+ enum AnEnum {
265
+ #[ allow( dead_code) ] // This variant is intentionally unused.
266
+ AValue {
267
+ a : u32 ,
268
+ } ,
269
+ AnotherValue ,
270
+ }
271
+ let value = AnEnum :: AnotherValue ;
272
+
273
+ let result = verify_that ! ( value, field!( AnEnum :: AValue . a, eq( 123 ) ) ) ;
274
+
275
+ verify_that ! ( result, err( displays_as( contains_substring( "which has no field `a`" ) ) ) )
276
+ }
277
+
225
278
#[ google_test]
226
279
fn matches_struct_like_enum_value ( ) -> Result < ( ) > {
227
280
#[ derive( Debug ) ]
0 commit comments