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}