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}