@@ -107,17 +107,21 @@ pub struct Mock {
107107 calls : Arc < AtomicU64 > ,
108108 name : Option < String > ,
109109 priority : u8 ,
110+ matcher_hit_mask : Arc < AtomicU64 > ,
111+ pending_hit_mask : Arc < AtomicU64 > ,
110112}
111113
112114impl Mock {
113115 pub fn given ( matcher : impl Match + Send + Sync + ' static ) -> Self {
114116 Self {
115117 matcher : vec ! [ Arc :: new( matcher) ] ,
116- expected_calls : Default :: default ( ) ,
117118 responder : Arc :: new ( pending ( ) ) ,
118- calls : Default :: default ( ) ,
119119 name : None ,
120120 priority : 5 ,
121+ expected_calls : Default :: default ( ) ,
122+ calls : Default :: default ( ) ,
123+ matcher_hit_mask : Default :: default ( ) ,
124+ pending_hit_mask : Default :: default ( ) ,
121125 }
122126 }
123127
@@ -132,6 +136,7 @@ impl Mock {
132136 }
133137
134138 pub fn add_matcher ( mut self , matcher : impl Match + Send + Sync + ' static ) -> Self {
139+ assert ! ( self . matcher. len( ) < 65 , "Cannot have more than 65 matchers" ) ;
135140 self . matcher . push ( Arc :: new ( matcher) ) ;
136141 self
137142 }
@@ -159,8 +164,11 @@ impl Mock {
159164 /// You can use this to verify the mock separately to the one you put into the server (if
160165 /// you've cloned it).
161166 pub fn verify ( & self ) -> bool {
162- self . expected_calls
163- . contains ( self . calls . load ( Ordering :: SeqCst ) )
167+ let hit_matches = self . matcher_hit_mask . load ( Ordering :: SeqCst ) . count_ones ( ) as usize ;
168+ let calls = self . calls . load ( Ordering :: SeqCst ) ;
169+ debug ! ( "{}/{} matchers hit over {} calls" , hit_matches, self . matcher. len( ) , calls) ;
170+ // If this mock doesn't need calling we don't need to check the hit matches
171+ self . expected_calls . contains ( calls) && ( self . expected_calls . contains ( 0 ) || hit_matches == self . matcher . len ( ) )
164172 }
165173
166174 fn check_request (
@@ -194,20 +202,31 @@ impl Mock {
194202 let contains_none = values. contains ( & None ) ;
195203
196204 if contains_true {
205+ let mut current_mask = 0u64 ;
206+ for ( i, _val) in values. iter ( ) . enumerate ( ) . filter ( |( _, i) | * * i == Some ( true ) ) {
207+ current_mask |= 1 << i as u64 ;
208+ }
209+ self . pending_hit_mask . store ( current_mask, Ordering :: SeqCst ) ;
210+
197211 if !contains_none {
198212 MatchStatus :: Full
199213 } else {
200214 MatchStatus :: Partial
201215 }
202216 } else {
217+ self . pending_hit_mask . store ( 0 , Ordering :: SeqCst ) ;
203218 MatchStatus :: Potential
204219 }
205220 } else {
221+ self . pending_hit_mask . store ( 0 , Ordering :: SeqCst ) ;
206222 MatchStatus :: Mismatch
207223 }
208224 }
209225
210226 fn register_hit ( & self ) {
227+ // Reset the mask and get the current stored one
228+ let pending_mask = self . pending_hit_mask . fetch_and ( 0 , Ordering :: Acquire ) ;
229+ self . matcher_hit_mask . fetch_or ( pending_mask, Ordering :: SeqCst ) ;
211230 self . calls . fetch_add ( 1 , Ordering :: Acquire ) ;
212231 }
213232}
0 commit comments