must/
lazy.rs

1//! Builder style, lazy evaluating matcher.
2//!
3//!
4//!
5//!
6//!
7//! # Examples (extending)
8//!
9//! ```rust
10//! #[macro_use] extern crate must;
11//! use must::prelude::*;
12//! #[derive(Debug, PartialEq)]
13//! pub enum Lit {
14//!     Num(i64),
15//!     Bool(bool),
16//! }
17//!
18//! #[derive(Debug)]
19//! pub struct ParseError;
20//! pub fn parse_lit(i: &str) -> Result<Lit, ParseError> {
21//! 	// showcase..
22//! 	if i == "true" {
23//! 		Ok(Lit::Bool(true))
24//! 	} else if i == "false" {
25//! 		Ok(Lit::Bool(false))
26//! 	} else {
27//! 		Ok(Lit::Num(i.parse().expect("not a number?")))
28//! 	}
29//! }
30//!
31//! // and in your test,
32//! use std::fmt::Debug;
33//! use must::Mutator;
34//! use must::LazyAssertion;
35//! use must::LazyMatcher;
36//!
37//!
38//! pub trait ParserMust<T: Debug + PartialEq> {
39//!     fn must_parse(self, s: &str) -> LazyAssertion<ParseAs<T>>;
40//! }
41//!
42//! impl<T: Debug + PartialEq> ParserMust<T> for fn(&str) -> Result<T, ParseError> {
43//!     fn must_parse(self, s: &str) -> LazyAssertion<ParseAs<T>> {
44//!         LazyAssertion::from(ParseAs {
45//!             parser: self,
46//!             data: s.to_owned(),
47//!             want: None,
48//!         })
49//!     }
50//! }
51//!
52//! // Mutator<ParseAs<T>> is implemented for ParseAs<T> (as logically it is mutator)
53//! pub struct ParseAs<T: Debug + PartialEq> {
54//!     parser: fn(&str) -> Result<T, ParseError>,
55//!     // let's use owned type, to avoid adding a lifetime parameter.
56//!     data: String,
57//!     // Used Option because it will be filled in later call.
58//!     want: Option<T>,
59//! }
60//!
61//! pub trait ParseAsBuilder<T: Debug + PartialEq> : Mutator<ParseAs<T>> {
62//! 	fn as_ok(self, t: T) -> Self {
63//! 		self.mutate(|l| l.want = Some(t))
64//! 	}
65//! }
66//!
67//! impl<T: Debug + PartialEq, M> ParseAsBuilder<T> for M where M: Mutator<ParseAs<T>> {}
68//!
69//!
70//! impl<T: Debug + PartialEq> LazyMatcher for ParseAs<T> {
71//! 	type Ret = ();
72//! 	fn test(self) -> Result<Self::Ret, MustError> {
73//! 		let want = match self.want {
74//! 			Some(want) => want,
75//! 			None => panic!("ParseAs.to() is not called."),
76//! 		};
77//! 		let result = (self.parser)(&self.data);
78//! 		result.must_be_ok_and(|val| {
79//! 			// val.must_be() returns LazyAssertion
80//! 			val.must_be(want)
81//! 		}).into_result().map(|_| ())  // std::result::Result has map method
82//! 	}
83//! }
84//!
85//! // in #[test] function
86//! # fn main() {
87//! // auto coercion for fn type is sometimes strange.
88//! let parser: fn(&str) -> Result<Lit, ParseError> = parse_lit;
89//! parser.must_parse("false").as_ok(Lit::Bool(false)); // .or(fail!()) is optional
90//! parser.must_parse("true").as_ok(Lit::Bool(true)).or(fail!());
91//! parser.must_parse("352").as_ok(Lit::Num(352)).or(fail!());
92//!
93//! // You can change type of ParseAs.want to Option<Result<T, ParseError>>
94//! // and add function like as_err(expected) (optionaly with validation logic).
95//! // And you might add function like with_rem(remain: &str)
96//!
97//! # }
98//! ```
99
100use errors::{Error, ErrorKind, FromError};
101use mutator::Mutator;
102use std::mem::replace;
103
104/// Matcher holds 'got'
105pub trait LazyMatcher: Sized {
106	/// Return type.
107	type Ret;
108
109	/// Called only once.
110	fn test(self) -> Result<Self::Ret, Error>;
111}
112
113
114
115pub struct SimpleMatcher<Ret> {
116	result: Result<Ret, Error>,
117}
118
119pub type SimpleAssert<Ret> = LazyAssertion<SimpleMatcher<Ret>>;
120
121/// Creates a matcher with already matched result.
122fn matched<Ret>(result: Result<Ret, Error>) -> SimpleAssert<Ret> {
123	SimpleMatcher { result: result }.into()
124}
125
126impl<Ret> From<Ret> for LazyAssertion<SimpleMatcher<Ret>> {
127	fn from(ret: Ret) -> Self {
128		matched(Ok(ret))
129	}
130}
131
132impl<Ret> FromError for LazyAssertion<SimpleMatcher<Ret>> {
133	fn from_err(err: ErrorKind, got: String) -> Self {
134		matched(Err(Error {
135				got: got,
136				kind: err,
137			}))
138			.into()
139	}
140}
141
142impl<Ret> LazyMatcher for SimpleMatcher<Ret> {
143	type Ret = Ret;
144	fn test(self) -> Result<Self::Ret, Error> {
145		self.result
146	}
147}
148
149
150pub struct LazyAssertion<M: LazyMatcher> {
151	matcher: Option<M>,
152}
153
154impl<M: LazyMatcher> Mutator<M> for LazyAssertion<M> {
155	fn mutate<F>(mut self, op: F) -> Self
156		where F: FnOnce(&mut M)
157	{
158		match self.matcher {
159			Some(ref mut matcher) => op(matcher),
160			None => panic!("must: cannot call chaining method after assertion"),
161		}
162
163		self
164	}
165}
166
167impl<M: LazyMatcher> Drop for LazyAssertion<M> {
168	fn drop(&mut self) {
169		match replace(&mut self.matcher, None) {
170			None => {
171				trace!("Assertion.drop() called, but test is already done");
172				return;
173			}
174			Some(matcher) => {
175				trace!("running matcher.test() on drop");
176				match matcher.test() {
177					// value does not matter, as it successed.
178					Ok(..) => return,
179					Err(err) => panic!("{}", err),
180				}
181			}
182		}
183	}
184}
185
186impl<M: LazyMatcher> From<M> for LazyAssertion<M> {
187	/// Creates a new lazy assertion with a given lazy matcher.
188	fn from(matcher: M) -> Self {
189		LazyAssertion { matcher: Some(matcher) }
190	}
191}
192
193
194impl<M: LazyMatcher> LazyAssertion<M> {
195	/// Not intended for direct use.
196	///
197	/// Use must_be_ok_and / must_be_err_and / must_be_some_and instead.
198	pub fn and<F, R>(self, op: F) -> LazyAssertion<R>
199		where F: FnOnce(M::Ret) -> LazyAssertion<R>,
200		      R: LazyMatcher
201	{
202		trace!("Assertion.and() is called");
203		match self.into_result() {
204			Ok(val) => op(val).into(),
205			Err(err) => panic!("{}", err),
206		}
207	}
208
209	pub fn or<F>(self, f: F)
210		where F: FnOnce(&Error)
211	{
212		trace!("Assertion.or() is called");
213		match self.into_result() {
214			// Ok(val) => val,
215			Ok(..) => return,
216			Err(err) => {
217				f(&err);
218				panic!("User provided function did not panicked.\n {}", err)
219			}
220		}
221	}
222
223	/// take or panic
224	pub fn take(self) -> M::Ret {
225		trace!("Assertion.take() is called");
226		match self.into_result() {
227			Ok(val) => val,
228			Err(err) => panic!("{}", err),
229		}
230	}
231
232	/// Not intended for direct use in testing, but exported to help extending must.
233	///
234	/// Panics if called twice.
235	pub fn into_result(mut self) -> Result<M::Ret, Error> {
236		match replace(&mut self.matcher, None) {
237			Some(matcher) => matcher.test(),
238			None => panic!("must: Called into_result() twice (how did you do that?)"),
239		}
240	}
241}