galvanic_assert/matchers/
combinators.rs

1/* Copyright 2017 Christopher Bacher
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16use super::super::*;
17
18/// Takes a list of matchers for the same type combines them conjunctively.
19///
20/// #Examples
21/// ```rust
22/// # #[macro_use] extern crate galvanic_assert;
23/// use galvanic_assert::matchers::*;
24/// # fn main() {
25/// assert_that!(&(1+1), all_of![gt(0), lt(5), not(eq(3))]);
26/// # }
27#[macro_export]
28macro_rules! all_of {
29    ( $matcher: expr ) => {
30        Box::new(All::of($matcher))
31    };
32    ( $matcher: expr, $($matchers: expr),* ) => {
33        Box::new(All::of($matcher)$(.and($matchers))*)
34    };
35}
36
37/// A `Matcher` struct which joins multiple `Matcher`s conjunctively.
38///
39/// Use `of()` to create a new `Matcher` and `and()` to add further `Matcher`s.
40///
41/// #Examples
42/// ```rust
43/// # #[macro_use] extern crate galvanic_assert;
44/// use galvanic_assert::matchers::*;
45/// # fn main() {
46/// assert_that!(&(1+1), All::of(gt(0)).and(lt(5)).and(not(eq(3))));
47/// # }
48pub struct All<'a, T:'a> {
49    pub matcher: Box<Matcher<'a,T> + 'a>,
50    pub next: Option<Box<All<'a,T>>>
51}
52
53impl<'a,T:'a> All<'a, T> {
54    /// Creates a new conjunctive `Matcher` starting with the given `Matcher`.
55    pub fn of(matcher: Box<Matcher<'a,T> + 'a>) -> All<'a,T> {
56        All {
57            matcher: matcher,
58            next: None
59        }
60    }
61
62    /// Adds the given `Matcher` conjunctively.
63    pub fn and(self, matcher: Box<Matcher<'a,T> + 'a>) -> All<'a,T> {
64        All {
65            matcher: matcher,
66            next: Some(Box::new(self))
67        }
68    }
69}
70
71impl<'a,T:'a> Matcher<'a,T> for All<'a,T> {
72    fn check(&self, actual: &'a T) -> MatchResult {
73        match self.matcher.check(actual) {
74            x@MatchResult::Matched {..} => {
75                match self.next {
76                    None => x,
77                    Some(ref next) => next.check(actual)
78                }
79            },
80            x@MatchResult::Failed {..} => x
81        }
82    }
83}
84
85/// Takes a list of matchers for the same type combines them disjunctively.
86///
87/// #Examples
88/// ```rust
89/// # #[macro_use] extern crate galvanic_assert;
90/// use galvanic_assert::matchers::*;
91/// # fn main() {
92/// assert_that!(&(1+1), any_of![lt(0), gt(5), not(eq(3))]);
93/// # }
94#[macro_export]
95macro_rules! any_of {
96    ( $matcher: expr ) => {
97        Box::new(Any::of($matcher))
98    };
99    ( $matcher: expr, $($matchers: expr),* ) => {
100        Box::new(Any::of($matcher)$(.or($matchers))*)
101    };
102}
103
104/// A `Matcher` struct which joins multiple `Matcher`s disjunctively.
105///
106/// Use `of()` to create a new `Matcher` and `or()` to add further `Matcher`s.
107///
108/// #Examples
109/// ```rust
110/// # #[macro_use] extern crate galvanic_assert;
111/// use galvanic_assert::matchers::*;
112/// # fn main() {
113/// assert_that!(&(1+1), Any::of(lt(0)).or(gt(5)).or(not(eq(3))));
114/// # }
115pub struct Any<'a, T:'a> {
116    pub matcher: Box<Matcher<'a,T> + 'a>,
117    pub next: Option<Box<Any<'a,T>>>
118}
119
120impl<'a,T:'a> Any<'a, T> {
121    /// Creates a new conjunctive `Matcher` starting with the given `Matcher`.
122    pub fn of(matcher: Box<Matcher<'a,T> + 'a>) -> Any<'a,T> {
123        Any {
124            matcher: matcher,
125            next: None
126        }
127    }
128
129    /// Adds the given `Matcher` disjunctively.
130    pub fn or(self, matcher: Box<Matcher<'a,T> + 'a>) -> Any<'a,T> {
131        Any {
132            matcher: matcher,
133            next: Some(Box::new(self))
134        }
135    }
136}
137
138impl<'a,T:'a> Matcher<'a,T> for Any<'a,T> {
139    fn check(&self, actual: &'a T) -> MatchResult {
140        match self.matcher.check(actual) {
141            MatchResult::Matched {..} => MatchResult::Matched { name: "any_of".to_owned() },
142            x@MatchResult::Failed {..} => match self.next {
143                None => x,
144                Some(ref next) => next.check(actual)
145            }
146        }
147    }
148}