use crate::core::{
marker::Mark,
matcher::{Matcher, Matcherable},
sourcer::{Location, Source},
};
use std::fmt::Debug;
#[derive(Debug)]
pub struct Expect {
pub diagnostic: Option<String>,
pub location: Option<Location>,
}
#[derive(Clone)]
pub struct ExpectCase<V>
where
V: Clone + Debug + PartialEq
{
value: Matcherable<V>,
source: Option<Source>,
}
impl<V> ExpectCase<V>
where
V: Clone + Debug + PartialEq
{
pub fn new (value: V) -> Self {
ExpectCase {
source: None,
value: Matcherable::new(value),
}
}
pub fn not (&mut self, matcher: Matcherable<V>) -> Result<Expect, Expect> {
self.matching(self.value.clone(), matcher, Mark::Not)
}
pub fn to (&mut self, matcher: Matcherable<V>) -> Result<Expect, Expect> {
self.matching(self.value.clone(), matcher, Mark::To)
}
pub fn source (mut self, source: Source) -> Self {
self.source = Some(source);
self
}
pub fn matching (
&mut self,
received: Matcherable<V>,
expected: Matcherable<V>,
mark: Mark
) -> Result<Expect, Expect> {
let success = if mark.is_assertion() {
received.matches(&expected)
} else {
!received.matches(&expected)
};
match success {
true => {
let message = String::from("ok");
let expect = Expect {
diagnostic: Some(message),
location: Some(self.source.unwrap().location),
};
Ok(expect)
},
_ => {
let message = received.fail(&expected, mark);
let expect = Expect {
diagnostic: Some(message),
location: Some(self.source.unwrap().location),
};
Err(expect)
},
}
}
}
#[macro_export]
macro_rules! expect {
(catch $body:block) => {{
let location = Location::new(file!(), line!(), column!());
let source = Source::new(location);
let catched = std::panic::catch_unwind(|| { $body; });
ExpectCase::new(catched.is_err()).source(source)
}};
($value:expr) => {{
let location = Location::new(file!(), line!(), column!());
let source = Source::new(location);
ExpectCase::new($value).source(source)
}};
}
#[macro_export]
macro_rules! must {
($received:expr; eq $y:expr) => {{
let location = Location::new(file!(), line!(), column!());
let source = Source::new(location);
Ok(expect!($received).source(source).to(be_equal($y))?)
}};
($received:expr; ne $y:expr) => {{
let location = Location::new(file!(), line!(), column!());
let source = Source::new(location);
Ok(expect!($received).source(source).not(be_equal($y))?)
}};
($received:expr; be.falsy) => {{
let location = Location::new(file!(), line!(), column!());
let source = Source::new(location);
Ok(expect!($received).source(source).to(be_false())?)
}};
($received:expr; be.truthy) => {{
let location = Location::new(file!(), line!(), column!());
let source = Source::new(location);
Ok(expect!($received).source(source).to(be_true())?)
}};
(catch $received:block to abort()) => {{
let location = Location::new(file!(), line!(), column!());
let source = Source::new(location);
Ok(expect!(catch { $received }).source(source).to(abort())?)
}};
}