Skip to content

Commit 302f605

Browse files
committed
Track which matchers have been hit!
1 parent c915d6b commit 302f605

File tree

1 file changed

+23
-4
lines changed

1 file changed

+23
-4
lines changed

src/lib.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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

112114
impl 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

Comments
 (0)