use std::fmt; use std::fmt::Debug; pub trait Report { fn report(self, q: Q); } pub struct ReportDump; impl Report> for ReportDump { #[track_caller] fn report(self, q: ResultTest) { if q.fail { for msg in q.msg.iter() { println!("{}", msg); } panic!(); } } } pub struct ReportValues; impl Report> for ReportValues where O: Debug, E: Debug, { fn report(self, q: ResultTest) { match (q.ok.as_ref(), q.err.as_ref()) { (Some(ok), None) => { println!("{:?}", ok); } (None, Some(err)) => { println!("{:?}", err); } _ => unreachable!(), } for msg in q.msg.iter() { println!(" {}", msg); } } } pub struct ResultTest { pub ok: Option, pub err: Option, pub fail: bool, pub msg: Vec, } impl ResultTest where O: Debug, E: Debug, { #[allow(dead_code)] #[must_use] pub fn new(result: Result) -> Self { match result { Ok(v) => Self { ok: Some(v), err: None, fail: false, msg: Default::default(), }, Err(v) => Self { ok: None, err: Some(v), fail: false, msg: Default::default(), }, } } #[allow(dead_code)] #[track_caller] pub fn q>(self, q: Q) { q.report(self); } #[allow(dead_code)] #[must_use] pub fn ok(mut self) -> Self { if self.err.is_some() { self.msg.push("expected err but was ok".into()); self.fail = true; } self } #[allow(dead_code)] #[must_use] pub fn err(mut self) -> Self { if self.ok.is_some() { self.msg.push("expected ok but was err".into()); self.fail = true; } self } #[allow(dead_code)] #[must_use] pub fn test(mut self, cmp: impl Fn(&O, &T) -> bool, test: &T) -> Self { if let Some(ok) = &self.ok { if !cmp(ok, test) { self.msg .push(format!("test failed: {:?} <> {:?}", ok, test)); self.fail = true; } else { // ok } } else { self.msg.push("expected ok but was err".into()); self.fail = true; } self } } impl ResultTest { #[allow(dead_code)] #[must_use] pub fn str(mut self, test: &str) -> Self { if let Some(ok) = &self.ok { if ok.as_str() != test { self.msg .push(format!("test failed: {:?} <> {:?}", ok, test)); self.fail = true; } else { // ok } } else { self.msg.push("expected ok but was err".into()); } self } } #[allow(dead_code)] #[must_use] pub fn test(r: Result) -> ResultTest { ResultTest::new(r) } #[allow(dead_code)] #[must_use] pub fn test_ok(r: T) -> ResultTest { ResultTest::new(Ok(r)) }