1use std::fmt::Debug;
79use std::ops::{BitAnd, BitOr};
80use std::sync::atomic::AtomicBool;
81use std::sync::atomic::Ordering::SeqCst;
82use std::sync::Arc;
83use std::sync::Mutex;
84use tracing::field::Field;
85use tracing::Event;
86use tracing::Subscriber;
87use tracing_subscriber::field::Visit;
88use tracing_subscriber::layer::Context;
89
90#[cfg(feature = "regex")]
91use regex::Regex;
92
93#[derive(Default, Clone, Debug)]
95pub struct Layer(Arc<InnerLayer>);
96
97#[derive(Default, Debug)]
101struct InnerLayer {
102 pass_all: AtomicBool,
103 assertions: Mutex<Vec<Arc<InnerAssertion>>>,
104}
105
106impl Layer {
107 pub fn matches(&self, s: impl Into<String>) -> Assertion {
113 let inner_assertion = Arc::new(InnerAssertion {
114 boolean: AtomicBool::new(false),
115 assertion_type: AssertionType::Matches(s.into()),
116 });
117 self.0
118 .assertions
119 .lock()
120 .unwrap()
121 .push(inner_assertion.clone());
122 Assertion(AssertionWrapper::One {
123 assertion: inner_assertion.clone(),
124 asserter: self.0.clone(),
125 })
126 }
127 pub fn debug(&self, s: impl Debug) -> Assertion {
151 self.matches(format!("{s:?}"))
152 }
153 #[cfg(feature = "regex")]
163 pub fn regex<T>(&self, s: T) -> Result<Assertion, <Regex as TryFrom<T>>::Error>
164 where
165 Regex: TryFrom<T>,
166 {
167 let inner_assertion = Arc::new(InnerAssertion {
168 boolean: AtomicBool::new(false),
169 assertion_type: AssertionType::Regex(Regex::try_from(s)?),
170 });
171 self.0
172 .assertions
173 .lock()
174 .unwrap()
175 .push(inner_assertion.clone());
176 Ok(Assertion(AssertionWrapper::One {
177 assertion: inner_assertion.clone(),
178 asserter: self.0.clone(),
179 }))
180 }
181 pub fn enable(&self) {
183 self.0.pass_all.store(false, SeqCst);
184 }
185 pub fn disable(&self) {
191 self.0.pass_all.store(true, SeqCst);
192 }
193}
194
195#[derive(Debug, Clone)]
196enum AssertionType {
197 Matches(String),
198 #[cfg(feature = "regex")]
199 Regex(Regex),
200}
201
202impl std::fmt::Display for AssertionType {
203 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
204 use AssertionType::*;
205 match self {
206 Matches(matches) => write!(f, "{matches}"),
207 #[cfg(feature = "regex")]
208 Regex(regex) => write!(f, "{regex}"),
209 }
210 }
211}
212
213#[derive(Debug, Clone)]
215pub struct Assertion(AssertionWrapper);
216
217#[derive(Debug)]
219enum AssertionWrapper {
220 And {
221 lhs: Box<Assertion>,
222 rhs: Box<Assertion>,
223 },
224 Or {
225 lhs: Box<Assertion>,
226 rhs: Box<Assertion>,
227 },
228 One {
229 assertion: Arc<InnerAssertion>,
230 asserter: Arc<InnerLayer>,
231 },
232 Not {
233 assertion: Box<Assertion>,
234 },
235}
236impl Clone for AssertionWrapper {
237 fn clone(&self) -> AssertionWrapper {
238 use AssertionWrapper::*;
239 match &self {
240 One {
241 assertion,
242 asserter,
243 } => {
244 let new_assertion = Arc::new(InnerAssertion {
245 boolean: AtomicBool::from(assertion.boolean.load(SeqCst)),
246 assertion_type: assertion.assertion_type.clone(),
247 });
248 asserter
249 .assertions
250 .lock()
251 .unwrap()
252 .push(new_assertion.clone());
253 One {
254 assertion: new_assertion,
255 asserter: asserter.clone(),
256 }
257 }
258 Not { assertion } => Not {
259 assertion: assertion.clone(),
260 },
261 And { lhs, rhs } => And {
262 lhs: lhs.clone(),
263 rhs: rhs.clone(),
264 },
265 Or { lhs, rhs } => Or {
266 lhs: lhs.clone(),
267 rhs: rhs.clone(),
268 },
269 }
270 }
271}
272
273impl Assertion {
274 #[allow(clippy::must_use_candidate)] #[track_caller]
281 pub fn assert(&self) -> &Self {
282 assert!(bool::from(self), "{}", self.ansi());
283 self
284 }
285 #[must_use]
306 pub fn repeat(&self) -> Self {
307 use AssertionWrapper::*;
308 let inner = match &self.0 {
309 One {
310 assertion,
311 asserter,
312 } => {
313 let new_assertion = Arc::new(InnerAssertion {
314 boolean: AtomicBool::new(false),
315 assertion_type: assertion.assertion_type.clone(),
316 });
317 asserter
318 .assertions
319 .lock()
320 .unwrap()
321 .push(new_assertion.clone());
322 One {
323 assertion: new_assertion,
324 asserter: asserter.clone(),
325 }
326 }
327 Not { assertion } => Not {
328 assertion: Box::new(assertion.repeat()),
329 },
330 And { lhs, rhs } => And {
331 lhs: Box::new(lhs.repeat()),
332 rhs: Box::new(rhs.repeat()),
333 },
334 Or { lhs, rhs } => Or {
335 lhs: Box::new(lhs.repeat()),
336 rhs: Box::new(rhs.repeat()),
337 },
338 };
339 Self(inner)
340 }
341
342 pub fn reset(&self) {
362 use AssertionWrapper::*;
363 match &self.0 {
364 One {
365 assertion,
366 asserter,
367 } => {
368 if assertion.boolean.swap(false, SeqCst) {
369 asserter.assertions.lock().unwrap().push(assertion.clone());
370 }
371 }
372 Not { assertion } => assertion.reset(),
373 And { lhs, rhs } | Or { lhs, rhs } => {
374 lhs.reset();
375 rhs.reset();
376 }
377 }
378 }
379
380 fn ansi(&self) -> String {
381 use AssertionWrapper::*;
382
383 match &self.0 {
384 One {
385 assertion,
386 asserter,
387 } => {
388 let is_true = if asserter.pass_all.load(SeqCst) {
389 true
390 } else {
391 assertion.boolean.load(std::sync::atomic::Ordering::SeqCst)
392 };
393 let str = format!("{:?}", assertion.assertion_type.to_string());
394 let out = if is_true {
395 ansi_term::Colour::Green.paint(str)
396 } else {
397 ansi_term::Colour::Red.paint(str)
398 };
399 out.to_string()
400 }
401 And { lhs, rhs } => format!("({} && {})", lhs.ansi(), rhs.ansi()),
402 Or { lhs, rhs } => format!("({} || {})", lhs.ansi(), rhs.ansi()),
403 Not { assertion } => format!("!{}", assertion.ansi()),
404 }
405 }
406}
407
408impl std::ops::Not for Assertion {
409 type Output = Self;
410 fn not(self) -> Self::Output {
411 !&self
412 }
413}
414impl std::ops::Not for &Assertion {
415 type Output = Assertion;
416 fn not(self) -> Self::Output {
417 Assertion(AssertionWrapper::Not {
418 assertion: Box::new(self.clone()),
419 })
420 }
421}
422
423impl BitAnd for Assertion {
424 type Output = Self;
425 fn bitand(self, rhs: Self) -> Self::Output {
426 Assertion(AssertionWrapper::And {
427 lhs: Box::new(self.clone()),
428 rhs: Box::new(rhs.clone()),
429 })
430 }
431}
432impl BitAnd for &Assertion {
433 type Output = Assertion;
434 fn bitand(self, rhs: Self) -> Self::Output {
435 Assertion(AssertionWrapper::And {
436 lhs: Box::new(self.clone()),
437 rhs: Box::new(rhs.clone()),
438 })
439 }
440}
441impl BitAnd<&Assertion> for Assertion {
442 type Output = Assertion;
443 fn bitand(self, rhs: &Self) -> Self::Output {
444 Assertion(AssertionWrapper::And {
445 lhs: Box::new(self.clone()),
446 rhs: Box::new(rhs.clone()),
447 })
448 }
449}
450impl BitAnd<Assertion> for &Assertion {
451 type Output = Assertion;
452 fn bitand(self, rhs: Assertion) -> Self::Output {
453 Assertion(AssertionWrapper::And {
454 lhs: Box::new(self.clone()),
455 rhs: Box::new(rhs.clone()),
456 })
457 }
458}
459impl BitOr for Assertion {
460 type Output = Self;
461 fn bitor(self, rhs: Self) -> Self::Output {
462 Assertion(AssertionWrapper::Or {
463 lhs: Box::new(self.clone()),
464 rhs: Box::new(rhs.clone()),
465 })
466 }
467}
468impl BitOr for &Assertion {
469 type Output = Assertion;
470 fn bitor(self, rhs: Self) -> Self::Output {
471 Assertion(AssertionWrapper::Or {
472 lhs: Box::new(self.clone()),
473 rhs: Box::new(rhs.clone()),
474 })
475 }
476}
477impl BitOr<&Assertion> for Assertion {
478 type Output = Self;
479 fn bitor(self, rhs: &Assertion) -> Self::Output {
480 Assertion(AssertionWrapper::Or {
481 lhs: Box::new(self.clone()),
482 rhs: Box::new(rhs.clone()),
483 })
484 }
485}
486impl BitOr<Assertion> for &Assertion {
487 type Output = Assertion;
488 fn bitor(self, rhs: Assertion) -> Self::Output {
489 Assertion(AssertionWrapper::Or {
490 lhs: Box::new(self.clone()),
491 rhs: Box::new(rhs.clone()),
492 })
493 }
494}
495
496impl From<&Assertion> for bool {
497 fn from(value: &Assertion) -> Self {
498 use AssertionWrapper::*;
499 match &value.0 {
500 One {
501 assertion,
502 asserter,
503 } => {
504 if asserter.pass_all.load(SeqCst) {
505 return true;
506 }
507 assertion.boolean.load(std::sync::atomic::Ordering::SeqCst)
508 }
509 And { lhs, rhs } => bool::from(&**lhs) && bool::from(&**rhs),
510 Or { lhs, rhs } => bool::from(&**lhs) || bool::from(&**rhs),
511 Not { assertion } => !bool::from(&**assertion),
512 }
513 }
514}
515impl From<Assertion> for bool {
516 fn from(value: Assertion) -> Self {
517 bool::from(&value)
518 }
519}
520
521#[derive(Debug)]
525struct InnerAssertion {
526 boolean: AtomicBool,
527 assertion_type: AssertionType,
528}
529
530struct EventVisitor<'a>(&'a mut String);
531impl Visit for EventVisitor<'_> {
532 fn record_debug(&mut self, _field: &Field, value: &dyn std::fmt::Debug) {
533 *self.0 = format!("{value:?}");
534 }
535}
536
537impl<S: Subscriber> tracing_subscriber::layer::Layer<S> for Layer {
538 fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
539 let mut message = String::new();
541 event.record(&mut EventVisitor(&mut message) as &mut dyn Visit);
542 let mut assertions = self.0.assertions.lock().unwrap();
543 let mut i = 0;
544 while i < assertions.len() {
545 let result = match &assertions[i].assertion_type {
546 AssertionType::Matches(expected) => *expected == message,
547 AssertionType::Regex(regex) => regex.is_match(&message),
548 };
549 assertions[i].boolean.store(result, SeqCst);
550 if result {
551 assertions.remove(i);
552 } else {
553 i += 1;
554 }
555 }
556 }
557}
558
559#[cfg(test)]
560mod tests {
561 use tracing::info;
562
563 use super::*;
564 use tracing_subscriber::{layer::SubscriberExt, Registry};
565
566 #[cfg(feature = "regex")]
567 #[test]
568 fn regex_pass() {
569 let asserter = Layer::default();
570 let base_subscriber = Registry::default();
571 let subscriber = base_subscriber.with(asserter.clone());
572 let guard = tracing::subscriber::set_default(subscriber);
573 let condition = asserter.regex("01234.6789").unwrap();
574 info!("0123456789");
575 condition.assert();
576 drop(guard);
577 }
578
579 #[cfg(feature = "regex")]
580 #[should_panic(expected = "\u{1b}[31m\"01234.789\"\u{1b}[0m")]
581 #[test]
582 fn regex_fail() {
583 let asserter = Layer::default();
584 let base_subscriber = Registry::default();
585 let subscriber = base_subscriber.with(asserter.clone());
586 let guard = tracing::subscriber::set_default(subscriber);
587 let condition = asserter.regex("01234.789").unwrap();
588 info!("0123456789");
589 condition.assert();
590 drop(guard);
591 }
592
593 #[test]
594 fn debug() {
595 #[allow(dead_code)]
596 #[derive(Debug)]
597 struct MyStruct {
598 x: i32,
599 y: i32,
600 }
601 let asserter = Layer::default();
602 let base_subscriber = Registry::default();
603 let subscriber = base_subscriber.with(asserter.clone());
604 let guard = tracing::subscriber::set_default(subscriber);
605 let value = MyStruct { x: 2, y: 3 };
606 let condition = asserter.debug(&value);
607 info!("{value:?}");
608 condition.assert();
609 drop(guard);
610 }
611
612 #[test]
613 fn pass_all() {
614 let asserter = Layer::default();
615 let base_subscriber = Registry::default();
616 let subscriber = base_subscriber.with(asserter.clone());
617 let guard = tracing::subscriber::set_default(subscriber);
618
619 info!("stuff");
620 let condition = asserter.matches("missing");
621 asserter.disable();
622 info!("more stuff");
623 condition.assert();
624 asserter.enable();
625 (!condition).assert();
626
627 drop(guard);
628 }
629
630 #[test]
631 #[should_panic(
632 expected = "((\u{1b}[32m\"one\"\u{1b}[0m && \u{1b}[31m\"two\"\u{1b}[0m) || (\u{1b}[31m\"three\"\u{1b}[0m && !\u{1b}[31m\"four\"\u{1b}[0m))"
633 )]
634 fn panics() {
635 let asserter = Layer::default();
636 let registry = Registry::default();
637 let subscriber = registry.with(asserter.clone());
638 let guard = tracing::subscriber::set_default(subscriber);
639 let one = asserter.matches("one");
640 let two = asserter.matches("two");
641 let three = asserter.matches("three");
642 let four = asserter.matches("four");
643 let assertion = one & two | three & !four;
644 info!("one");
645 asserter.disable();
646 assertion.assert();
647 assert_eq!(assertion.ansi(),"((\u{1b}[32m\"one\"\u{1b}[0m && \u{1b}[32m\"two\"\u{1b}[0m) || (\u{1b}[32m\"three\"\u{1b}[0m && !\u{1b}[32m\"four\"\u{1b}[0m))");
648 asserter.enable();
649 assertion.assert();
650 drop(guard);
651 }
652
653 #[test]
654 fn and() {
655 let asserter = Layer::default();
656 let registry = Registry::default();
657 let subscriber = registry.with(asserter.clone());
658 let guard = tracing::subscriber::set_default(subscriber);
659 let one = asserter.matches("one");
660 let two = asserter.matches("two");
661 let a = &one & two.clone();
662 let b = one.clone() & &two;
663 let c = &one & &two;
664 let d = one & two;
665 info!("one");
666 info!("two");
667 a.assert();
668 b.assert();
669 c.assert();
670 d.assert();
671 drop(guard);
672 }
673
674 #[test]
675 fn or() {
676 let asserter = Layer::default();
677 let registry = Registry::default();
678 let subscriber = registry.with(asserter.clone());
679 let guard = tracing::subscriber::set_default(subscriber);
680 let one = asserter.matches("one");
681 let two = asserter.matches("two");
682 let a = &one | two.clone();
683 let b = one.clone() | &two;
684 let c = &one | &two;
685 let d = one | two;
686 info!("one");
687 a.assert();
688 b.assert();
689 c.assert();
690 d.assert();
691 drop(guard);
692 }
693
694 #[test]
695 fn matches() {
696 let asserter = Layer::default();
697 let base_subscriber = Registry::default();
698 let subscriber = base_subscriber.with(asserter.clone());
699 let guard = tracing::subscriber::set_default(subscriber);
700
701 let two = asserter.matches("two");
702 let three = asserter.matches("three");
703 let or = &two | &three;
704 let and = &two & &three;
705 let or2 = two.clone() | three.clone();
706 let and2 = two.clone() & three.clone();
707
708 (!&two).assert();
710
711 info!("one");
712
713 (!&two).assert();
715 (!&or).assert();
716 (!&or2).assert();
717
718 info!("two");
719
720 two.assert();
722 or.assert();
723 or2.assert();
724 (!&and).assert();
725 (!&and2).assert();
726
727 info!("three");
728
729 two.assert();
731 and.assert();
732 and2.assert();
733
734 let two = asserter.matches("two");
737 (!&two).assert();
738 assert!(!bool::from(two));
739
740 drop(guard);
741 }
742
743 #[test]
744 fn repeat() {
745 let asserter = Layer::default();
746 let base_subscriber = Registry::default();
747 let subscriber = base_subscriber.with(asserter.clone());
748 let guard = tracing::subscriber::set_default(subscriber);
749
750 let one = asserter.matches("one");
751 let two = asserter.matches("two");
752 let or = &one | &two;
753 let and = &one & &two;
754 let not = !&one;
755
756 info!("one");
757 info!("two");
758
759 one.assert();
760 two.assert();
761 or.assert();
762 and.assert();
763 (!¬).assert();
764
765 let one2 = one.repeat();
766 let two2 = two.repeat();
767 let or2 = or.repeat();
768 let and2 = and.repeat();
769 let not2 = not.repeat();
770
771 (!&one2).assert();
772 (!&two2).assert();
773 (!&or2).assert();
774 (!&and2).assert();
775 (!(!¬2)).assert();
776
777 info!("one");
778 info!("two");
779
780 one2.assert();
781 two2.assert();
782 or2.assert();
783 and2.assert();
784 (!¬2).assert();
785
786 drop(guard);
787 }
788
789 #[test]
790 fn reset() {
791 let asserter = Layer::default();
792 let base_subscriber = Registry::default();
793 let subscriber = base_subscriber.with(asserter.clone());
794 let guard = tracing::subscriber::set_default(subscriber);
795
796 let one = asserter.matches("one");
797 let two = asserter.matches("two");
798 let or = &one | &two;
799 let and = &one & &two;
800 let not = !&one;
801
802 not.assert().reset();
803
804 info!("one");
805 info!("two");
806
807 one.assert().reset();
808 two.assert().reset();
809 or.assert().reset();
810 and.assert().reset();
811
812 (!&one).assert();
813 (!&two).assert();
814 (!&or).assert();
815 (!&and).assert();
816 (!¬).assert();
817
818 info!("one");
819 info!("two");
820
821 one.assert();
822 two.assert();
823 or.assert();
824 and.assert();
825 (!¬).assert();
826
827 drop(guard);
828 }
829}