1use std::{marker::PhantomData, sync::Arc};
3
4use crate::{
5 matcher::SpanMatcher,
6 state::{EntryState, State},
7};
8
9enum AssertionCriterion {
10 WasCreated,
11 WasEntered,
12 WasExited,
13 WasClosed,
14 WasNotCreated,
15 WasNotEntered,
16 WasNotExited,
17 WasNotClosed,
18 CreatedExactly(usize),
19 EnteredExactly(usize),
20 ExitedExactly(usize),
21 ClosedExactly(usize),
22 CreatedAtLeast(usize),
23 EnteredAtLeast(usize),
24 ExitedAtLeast(usize),
25 ClosedAtLeast(usize),
26}
27
28impl AssertionCriterion {
29 pub fn assert(&self, state: &Arc<EntryState>) {
30 match self {
31 AssertionCriterion::WasCreated => assert!(state.num_created() != 0),
32 AssertionCriterion::WasEntered => assert!(state.num_entered() != 0),
33 AssertionCriterion::WasExited => assert!(state.num_exited() != 0),
34 AssertionCriterion::WasClosed => assert!(state.num_closed() != 0),
35 AssertionCriterion::WasNotCreated => assert_eq!(0, state.num_created()),
36 AssertionCriterion::WasNotEntered => assert_eq!(0, state.num_entered()),
37 AssertionCriterion::WasNotExited => assert_eq!(0, state.num_exited()),
38 AssertionCriterion::WasNotClosed => assert_eq!(0, state.num_closed()),
39 AssertionCriterion::CreatedExactly(times) => assert_eq!(state.num_created(), *times),
40 AssertionCriterion::EnteredExactly(times) => assert_eq!(state.num_entered(), *times),
41 AssertionCriterion::ExitedExactly(times) => assert_eq!(state.num_exited(), *times),
42 AssertionCriterion::ClosedExactly(times) => assert_eq!(state.num_closed(), *times),
43 AssertionCriterion::CreatedAtLeast(times) => assert!(state.num_created() >= *times),
44 AssertionCriterion::EnteredAtLeast(times) => assert!(state.num_entered() >= *times),
45 AssertionCriterion::ExitedAtLeast(times) => assert!(state.num_exited() >= *times),
46 AssertionCriterion::ClosedAtLeast(times) => assert!(state.num_closed() >= *times),
47 }
48 }
49
50 pub fn try_assert(&self, state: &Arc<EntryState>) -> bool {
51 match self {
52 AssertionCriterion::WasCreated => state.num_created() != 0,
53 AssertionCriterion::WasEntered => state.num_entered() != 0,
54 AssertionCriterion::WasExited => state.num_exited() != 0,
55 AssertionCriterion::WasClosed => state.num_closed() != 0,
56 AssertionCriterion::WasNotCreated => state.num_created() == 0,
57 AssertionCriterion::WasNotEntered => state.num_entered() == 0,
58 AssertionCriterion::WasNotExited => state.num_exited() == 0,
59 AssertionCriterion::WasNotClosed => state.num_closed() == 0,
60 AssertionCriterion::CreatedExactly(times) => state.num_created() == *times,
61 AssertionCriterion::EnteredExactly(times) => state.num_entered() == *times,
62 AssertionCriterion::ExitedExactly(times) => state.num_exited() == *times,
63 AssertionCriterion::ClosedExactly(times) => state.num_closed() == *times,
64 AssertionCriterion::CreatedAtLeast(times) => state.num_created() >= *times,
65 AssertionCriterion::EnteredAtLeast(times) => state.num_entered() >= *times,
66 AssertionCriterion::ExitedAtLeast(times) => state.num_exited() >= *times,
67 AssertionCriterion::ClosedAtLeast(times) => state.num_closed() >= *times,
68 }
69 }
70}
71
72pub struct Assertion {
88 state: Arc<State>,
89 entry_state: Arc<EntryState>,
90 matcher: SpanMatcher,
91 criteria: Vec<AssertionCriterion>,
92}
93
94impl Assertion {
95 pub fn assert(&self) {
103 for criterion in &self.criteria {
104 criterion.assert(&self.entry_state);
105 }
106 }
107
108 pub fn try_assert(&self) -> bool {
115 for criterion in &self.criteria {
116 if !criterion.try_assert(&self.entry_state) {
117 return false;
118 }
119 }
120
121 true
122 }
123}
124
125impl Drop for Assertion {
126 fn drop(&mut self) {
127 self.state.remove_entry(&self.matcher);
128 }
129}
130
131pub struct NoMatcher {
140 _p: PhantomData<()>,
141}
142
143pub struct NoCriteria {
149 _p: PhantomData<()>,
150}
151
152pub struct Constrained {
154 _p: PhantomData<()>,
155}
156
157pub struct AssertionBuilder<S> {
169 state: Arc<State>,
170 matcher: Option<SpanMatcher>,
171 criteria: Vec<AssertionCriterion>,
172 _builder_state: PhantomData<fn(S)>,
173}
174
175impl AssertionBuilder<NoMatcher> {
176 pub fn with_name<S>(mut self, name: S) -> AssertionBuilder<NoCriteria>
182 where
183 S: Into<String>,
184 {
185 let matcher = self.matcher.get_or_insert_with(SpanMatcher::default);
186 matcher.set_name(name.into());
187
188 AssertionBuilder {
189 state: self.state,
190 matcher: self.matcher,
191 criteria: self.criteria,
192 _builder_state: PhantomData,
193 }
194 }
195
196 pub fn with_target<S>(mut self, target: S) -> AssertionBuilder<NoCriteria>
202 where
203 S: Into<String>,
204 {
205 let matcher = self.matcher.get_or_insert_with(SpanMatcher::default);
206 matcher.set_target(target.into());
207
208 AssertionBuilder {
209 state: self.state,
210 matcher: self.matcher,
211 criteria: self.criteria,
212 _builder_state: PhantomData,
213 }
214 }
215}
216
217impl AssertionBuilder<NoCriteria> {
218 pub fn with_name<S>(mut self, name: S) -> AssertionBuilder<NoCriteria>
224 where
225 S: Into<String>,
226 {
227 let matcher = self.matcher.get_or_insert_with(SpanMatcher::default);
228 matcher.set_name(name.into());
229
230 AssertionBuilder {
231 state: self.state,
232 matcher: self.matcher,
233 criteria: self.criteria,
234 _builder_state: PhantomData,
235 }
236 }
237
238 pub fn with_target<S>(mut self, target: S) -> AssertionBuilder<NoCriteria>
244 where
245 S: Into<String>,
246 {
247 let matcher = self.matcher.get_or_insert_with(SpanMatcher::default);
248 matcher.set_target(target.into());
249
250 AssertionBuilder {
251 state: self.state,
252 matcher: self.matcher,
253 criteria: self.criteria,
254 _builder_state: PhantomData,
255 }
256 }
257
258 pub fn with_parent_name<S>(mut self, name: S) -> AssertionBuilder<NoCriteria>
267 where
268 S: Into<String>,
269 {
270 let matcher = self.matcher.get_or_insert_with(SpanMatcher::default);
271 matcher.set_parent_name(name.into());
272
273 AssertionBuilder {
274 state: self.state,
275 matcher: self.matcher,
276 criteria: self.criteria,
277 _builder_state: PhantomData,
278 }
279 }
280
281 pub fn with_span_field<S>(mut self, field: S) -> AssertionBuilder<NoCriteria>
288 where
289 S: Into<String>,
290 {
291 if let Some(matcher) = self.matcher.as_mut() {
292 matcher.add_field_exists(field.into());
293 }
294
295 AssertionBuilder {
296 state: self.state,
297 matcher: self.matcher,
298 criteria: self.criteria,
299 _builder_state: PhantomData,
300 }
301 }
302
303 pub fn was_created(mut self) -> AssertionBuilder<Constrained> {
305 self.criteria.push(AssertionCriterion::WasCreated);
306
307 AssertionBuilder {
308 state: self.state,
309 matcher: self.matcher,
310 criteria: self.criteria,
311 _builder_state: PhantomData,
312 }
313 }
314
315 pub fn was_entered(mut self) -> AssertionBuilder<Constrained> {
317 self.criteria.push(AssertionCriterion::WasEntered);
318
319 AssertionBuilder {
320 state: self.state,
321 matcher: self.matcher,
322 criteria: self.criteria,
323 _builder_state: PhantomData,
324 }
325 }
326
327 pub fn was_exited(mut self) -> AssertionBuilder<Constrained> {
329 self.criteria.push(AssertionCriterion::WasExited);
330
331 AssertionBuilder {
332 state: self.state,
333 matcher: self.matcher,
334 criteria: self.criteria,
335 _builder_state: PhantomData,
336 }
337 }
338
339 pub fn was_closed(mut self) -> AssertionBuilder<Constrained> {
341 self.criteria.push(AssertionCriterion::WasClosed);
342
343 AssertionBuilder {
344 state: self.state,
345 matcher: self.matcher,
346 criteria: self.criteria,
347 _builder_state: PhantomData,
348 }
349 }
350
351 pub fn was_not_created(mut self) -> AssertionBuilder<Constrained> {
353 self.criteria.push(AssertionCriterion::WasNotCreated);
354
355 AssertionBuilder {
356 state: self.state,
357 matcher: self.matcher,
358 criteria: self.criteria,
359 _builder_state: PhantomData,
360 }
361 }
362
363 pub fn was_not_entered(mut self) -> AssertionBuilder<Constrained> {
365 self.criteria.push(AssertionCriterion::WasNotEntered);
366
367 AssertionBuilder {
368 state: self.state,
369 matcher: self.matcher,
370 criteria: self.criteria,
371 _builder_state: PhantomData,
372 }
373 }
374
375 pub fn was_not_exited(mut self) -> AssertionBuilder<Constrained> {
377 self.criteria.push(AssertionCriterion::WasNotExited);
378
379 AssertionBuilder {
380 state: self.state,
381 matcher: self.matcher,
382 criteria: self.criteria,
383 _builder_state: PhantomData,
384 }
385 }
386
387 pub fn was_not_closed(mut self) -> AssertionBuilder<Constrained> {
389 self.criteria.push(AssertionCriterion::WasNotClosed);
390
391 AssertionBuilder {
392 state: self.state,
393 matcher: self.matcher,
394 criteria: self.criteria,
395 _builder_state: PhantomData,
396 }
397 }
398
399 pub fn was_created_exactly(mut self, n: usize) -> AssertionBuilder<Constrained> {
401 self.criteria.push(AssertionCriterion::CreatedExactly(n));
402
403 AssertionBuilder {
404 state: self.state,
405 matcher: self.matcher,
406 criteria: self.criteria,
407 _builder_state: PhantomData,
408 }
409 }
410
411 pub fn was_entered_exactly(mut self, n: usize) -> AssertionBuilder<Constrained> {
413 self.criteria.push(AssertionCriterion::EnteredExactly(n));
414
415 AssertionBuilder {
416 state: self.state,
417 matcher: self.matcher,
418 criteria: self.criteria,
419 _builder_state: PhantomData,
420 }
421 }
422
423 pub fn was_exited_exactly(mut self, n: usize) -> AssertionBuilder<Constrained> {
425 self.criteria.push(AssertionCriterion::ExitedExactly(n));
426
427 AssertionBuilder {
428 state: self.state,
429 matcher: self.matcher,
430 criteria: self.criteria,
431 _builder_state: PhantomData,
432 }
433 }
434
435 pub fn was_closed_exactly(mut self, n: usize) -> AssertionBuilder<Constrained> {
437 self.criteria.push(AssertionCriterion::ClosedExactly(n));
438
439 AssertionBuilder {
440 state: self.state,
441 matcher: self.matcher,
442 criteria: self.criteria,
443 _builder_state: PhantomData,
444 }
445 }
446
447 pub fn was_created_at_least(mut self, n: usize) -> AssertionBuilder<Constrained> {
449 self.criteria.push(AssertionCriterion::CreatedAtLeast(n));
450
451 AssertionBuilder {
452 state: self.state,
453 matcher: self.matcher,
454 criteria: self.criteria,
455 _builder_state: PhantomData,
456 }
457 }
458
459 pub fn was_entered_at_least(mut self, n: usize) -> AssertionBuilder<Constrained> {
461 self.criteria.push(AssertionCriterion::EnteredAtLeast(n));
462
463 AssertionBuilder {
464 state: self.state,
465 matcher: self.matcher,
466 criteria: self.criteria,
467 _builder_state: PhantomData,
468 }
469 }
470
471 pub fn was_exited_at_least(mut self, n: usize) -> AssertionBuilder<Constrained> {
473 self.criteria.push(AssertionCriterion::ExitedAtLeast(n));
474
475 AssertionBuilder {
476 state: self.state,
477 matcher: self.matcher,
478 criteria: self.criteria,
479 _builder_state: PhantomData,
480 }
481 }
482
483 pub fn was_closed_at_least(mut self, n: usize) -> AssertionBuilder<Constrained> {
485 self.criteria.push(AssertionCriterion::ClosedAtLeast(n));
486
487 AssertionBuilder {
488 state: self.state,
489 matcher: self.matcher,
490 criteria: self.criteria,
491 _builder_state: PhantomData,
492 }
493 }
494}
495
496impl AssertionBuilder<Constrained> {
497 pub fn was_created(mut self) -> Self {
499 self.criteria.push(AssertionCriterion::WasCreated);
500 self
501 }
502
503 pub fn was_entered(mut self) -> Self {
505 self.criteria.push(AssertionCriterion::WasEntered);
506 self
507 }
508
509 pub fn was_exited(mut self) -> Self {
511 self.criteria.push(AssertionCriterion::WasExited);
512 self
513 }
514
515 pub fn was_closed(mut self) -> Self {
517 self.criteria.push(AssertionCriterion::WasClosed);
518 self
519 }
520
521 pub fn was_not_created(mut self) -> Self {
523 self.criteria.push(AssertionCriterion::WasNotCreated);
524 self
525 }
526
527 pub fn was_not_entered(mut self) -> Self {
529 self.criteria.push(AssertionCriterion::WasNotEntered);
530 self
531 }
532
533 pub fn was_not_exited(mut self) -> Self {
535 self.criteria.push(AssertionCriterion::WasNotExited);
536 self
537 }
538
539 pub fn was_not_closed(mut self) -> Self {
541 self.criteria.push(AssertionCriterion::WasNotClosed);
542 self
543 }
544
545 pub fn was_created_exactly(mut self, n: usize) -> Self {
547 self.criteria.push(AssertionCriterion::CreatedExactly(n));
548 self
549 }
550
551 pub fn was_entered_exactly(mut self, n: usize) -> Self {
553 self.criteria.push(AssertionCriterion::EnteredExactly(n));
554 self
555 }
556
557 pub fn was_exited_exactly(mut self, n: usize) -> Self {
559 self.criteria.push(AssertionCriterion::ExitedExactly(n));
560 self
561 }
562
563 pub fn was_closed_exactly(mut self, n: usize) -> Self {
565 self.criteria.push(AssertionCriterion::ClosedExactly(n));
566 self
567 }
568
569 pub fn was_created_at_least(mut self, n: usize) -> Self {
571 self.criteria.push(AssertionCriterion::CreatedAtLeast(n));
572 self
573 }
574
575 pub fn was_entered_at_least(mut self, n: usize) -> Self {
577 self.criteria.push(AssertionCriterion::EnteredAtLeast(n));
578 self
579 }
580
581 pub fn was_exited_at_least(mut self, n: usize) -> Self {
583 self.criteria.push(AssertionCriterion::ExitedAtLeast(n));
584 self
585 }
586
587 pub fn was_closed_at_least(mut self, n: usize) -> Self {
589 self.criteria.push(AssertionCriterion::ClosedAtLeast(n));
590 self
591 }
592
593 pub fn finalize(mut self) -> Assertion {
597 let matcher = self
598 .matcher
599 .take()
600 .expect("matcher must be present at this point");
601 let entry_state = self.state.create_entry(matcher.clone());
602 Assertion {
603 state: Arc::clone(&self.state),
604 entry_state,
605 matcher,
606 criteria: self.criteria,
607 }
608 }
609}
610
611#[derive(Clone, Default)]
613pub struct AssertionRegistry {
614 state: Arc<State>,
615}
616
617impl AssertionRegistry {
618 pub(crate) fn state(&self) -> &Arc<State> {
619 &self.state
620 }
621
622 pub fn build(&self) -> AssertionBuilder<NoMatcher> {
624 AssertionBuilder {
625 state: Arc::clone(&self.state),
626 matcher: None,
627 criteria: Vec::new(),
628 _builder_state: PhantomData,
629 }
630 }
631}