must 0.2.0

assertion library for rust
Documentation
//! Builder style, lazy evaluating matcher.
//!
//!
//!
//!
//!
//! # Examples (extending)
//!
//! ```rust
//! #[macro_use] extern crate must;
//! use must::prelude::*;
//! #[derive(Debug, PartialEq)]
//! pub enum Lit {
//!     Num(i64),
//!     Bool(bool),
//! }
//!
//! #[derive(Debug)]
//! pub struct ParseError;
//! pub fn parse_lit(i: &str) -> Result<Lit, ParseError> {
//! 	// showcase..
//! 	if i == "true" {
//! 		Ok(Lit::Bool(true))
//! 	} else if i == "false" {
//! 		Ok(Lit::Bool(false))
//! 	} else {
//! 		Ok(Lit::Num(i.parse().expect("not a number?")))
//! 	}
//! }
//!
//! // and in your test,
//! use std::fmt::Debug;
//! use must::Mutator;
//! use must::LazyAssertion;
//! use must::LazyMatcher;
//!
//!
//! pub trait ParserMust<T: Debug + PartialEq> {
//!     fn must_parse(self, s: &str) -> LazyAssertion<ParseAs<T>>;
//! }
//!
//! impl<T: Debug + PartialEq> ParserMust<T> for fn(&str) -> Result<T, ParseError> {
//!     fn must_parse(self, s: &str) -> LazyAssertion<ParseAs<T>> {
//!         LazyAssertion::from(ParseAs {
//!             parser: self,
//!             data: s.to_owned(),
//!             want: None,
//!         })
//!     }
//! }
//!
//! // Mutator<ParseAs<T>> is implemented for ParseAs<T> (as logically it is mutator)
//! pub struct ParseAs<T: Debug + PartialEq> {
//!     parser: fn(&str) -> Result<T, ParseError>,
//!     // let's use owned type, to avoid adding a lifetime parameter.
//!     data: String,
//!     // Used Option because it will be filled in later call.
//!     want: Option<T>,
//! }
//!
//! pub trait ParseAsBuilder<T: Debug + PartialEq> : Mutator<ParseAs<T>> {
//! 	fn as_ok(self, t: T) -> Self {
//! 		self.mutate(|l| l.want = Some(t))
//! 	}
//! }
//!
//! impl<T: Debug + PartialEq, M> ParseAsBuilder<T> for M where M: Mutator<ParseAs<T>> {}
//!
//!
//! impl<T: Debug + PartialEq> LazyMatcher for ParseAs<T> {
//! 	type Ret = ();
//! 	fn test(self) -> Result<Self::Ret, MustError> {
//! 		let want = match self.want {
//! 			Some(want) => want,
//! 			None => panic!("ParseAs.to() is not called."),
//! 		};
//! 		let result = (self.parser)(&self.data);
//! 		result.must_be_ok_and(|val| {
//! 			// val.must_be() returns LazyAssertion
//! 			val.must_be(want)
//! 		}).into_result().map(|_| ())  // std::result::Result has map method
//! 	}
//! }
//!
//! // in #[test] function
//! # fn main() {
//! // auto coercion for fn type is sometimes strange.
//! let parser: fn(&str) -> Result<Lit, ParseError> = parse_lit;
//! parser.must_parse("false").as_ok(Lit::Bool(false)); // .or(fail!()) is optional
//! parser.must_parse("true").as_ok(Lit::Bool(true)).or(fail!());
//! parser.must_parse("352").as_ok(Lit::Num(352)).or(fail!());
//!
//! // You can change type of ParseAs.want to Option<Result<T, ParseError>>
//! // and add function like as_err(expected) (optionaly with validation logic).
//! // And you might add function like with_rem(remain: &str)
//!
//! # }
//! ```

use errors::{Error, ErrorKind, FromError};
use mutator::Mutator;
use std::mem::replace;

/// Matcher holds 'got'
pub trait LazyMatcher: Sized {
	/// Return type.
	type Ret;

	/// Called only once.
	fn test(self) -> Result<Self::Ret, Error>;
}



pub struct SimpleMatcher<Ret> {
	result: Result<Ret, Error>,
}

pub type SimpleAssert<Ret> = LazyAssertion<SimpleMatcher<Ret>>;

/// Creates a matcher with already matched result.
fn matched<Ret>(result: Result<Ret, Error>) -> SimpleAssert<Ret> {
	SimpleMatcher { result: result }.into()
}

impl<Ret> From<Ret> for LazyAssertion<SimpleMatcher<Ret>> {
	fn from(ret: Ret) -> Self {
		matched(Ok(ret))
	}
}

impl<Ret> FromError for LazyAssertion<SimpleMatcher<Ret>> {
	fn from_err(err: ErrorKind, got: String) -> Self {
		matched(Err(Error {
				got: got,
				kind: err,
			}))
			.into()
	}
}

impl<Ret> LazyMatcher for SimpleMatcher<Ret> {
	type Ret = Ret;
	fn test(self) -> Result<Self::Ret, Error> {
		self.result
	}
}


pub struct LazyAssertion<M: LazyMatcher> {
	matcher: Option<M>,
}

impl<M: LazyMatcher> Mutator<M> for LazyAssertion<M> {
	fn mutate<F>(mut self, op: F) -> Self
		where F: FnOnce(&mut M)
	{
		match self.matcher {
			Some(ref mut matcher) => op(matcher),
			None => panic!("must: cannot call chaining method after assertion"),
		}

		self
	}
}

impl<M: LazyMatcher> Drop for LazyAssertion<M> {
	fn drop(&mut self) {
		match replace(&mut self.matcher, None) {
			None => {
				trace!("Assertion.drop() called, but test is already done");
				return;
			}
			Some(matcher) => {
				trace!("running matcher.test() on drop");
				match matcher.test() {
					// value does not matter, as it successed.
					Ok(..) => return,
					Err(err) => panic!("{}", err),
				}
			}
		}
	}
}

impl<M: LazyMatcher> From<M> for LazyAssertion<M> {
	/// Creates a new lazy assertion with a given lazy matcher.
	fn from(matcher: M) -> Self {
		LazyAssertion { matcher: Some(matcher) }
	}
}


impl<M: LazyMatcher> LazyAssertion<M> {
	/// Not intended for direct use.
	///
	/// Use must_be_ok_and / must_be_err_and / must_be_some_and instead.
	pub fn and<F, R>(self, op: F) -> LazyAssertion<R>
		where F: FnOnce(M::Ret) -> LazyAssertion<R>,
		      R: LazyMatcher
	{
		trace!("Assertion.and() is called");
		match self.into_result() {
			Ok(val) => op(val).into(),
			Err(err) => panic!("{}", err),
		}
	}

	pub fn or<F>(self, f: F)
		where F: FnOnce(&Error)
	{
		trace!("Assertion.or() is called");
		match self.into_result() {
			// Ok(val) => val,
			Ok(..) => return,
			Err(err) => {
				f(&err);
				panic!("User provided function did not panicked.\n {}", err)
			}
		}
	}

	/// take or panic
	pub fn take(self) -> M::Ret {
		trace!("Assertion.take() is called");
		match self.into_result() {
			Ok(val) => val,
			Err(err) => panic!("{}", err),
		}
	}

	/// Not intended for direct use in testing, but exported to help extending must.
	///
	/// Panics if called twice.
	pub fn into_result(mut self) -> Result<M::Ret, Error> {
		match replace(&mut self.matcher, None) {
			Some(matcher) => matcher.test(),
			None => panic!("must: Called into_result() twice (how did you do that?)"),
		}
	}
}