use derive_ex::derive_ex; use std::collections::HashSet; use std::sync::{Arc, Mutex}; #[derive(Clone)] #[derive_ex(Default)] #[default(Self::new())] pub struct AssertPass { p: Arc>>, print: bool, } impl AssertPass { pub fn new() -> Self { Self::new_with(false) } pub fn new_with(print: bool) -> Self { Self { p: Arc::new(Mutex::new(Vec::new())), print, } } pub fn pass(&self, s: &'static str) { self.p.lock().unwrap().push(s); if self.print { println!("{s}"); } } pub fn assert(&self, s: &[&'static str]) { assert_eq!(&*self.p.lock().unwrap(), s); } pub fn assert_ex(&self, s: &[&[&'static str]]) { let mut i = 0; let mut e = HashSet::<&str>::new(); for a in &*self.p.lock().unwrap() { while e.is_empty() { if i == s.len() { panic!("expect finish but `{a}`"); } e.extend(s[i]); i += 1; } if e.contains(a) { e.remove(a); } else if e.len() == 1 { panic!("expect `{}` but `{}`", e.iter().next().unwrap(), a); } else { panic!("expect one of `{e:?}` but `{a}`"); } } loop { if !e.is_empty() { if e.len() == 1 { panic!("expect finish but `{}`", e.iter().next().unwrap()); } else { panic!("expect finish but one of `{e:?}`"); } } if i == s.len() { break; } e.extend(s[i]); i += 1; } } }