1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* Copyright 2017 Christopher Bacher
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! The variant module contains matchers for asserting properties of enums and convienience functions for Option and Result.

use super::super::*;

/// Matches if the asserted value's variant matches the expected variant.
///
/// # Examples
/// If the enum's variants are already imported one can write:
///
/// ```
/// # #[macro_use] extern crate galvanic_assert;
/// # fn main() {
/// let ok: Result<i32, ()> = Ok(4);
/// assert_that!(&ok, is_variant!(Ok));
/// # }
/// ```
/// If not then the full path of the variant has to be used:
///
/// ```
/// # #[macro_use] extern crate galvanic_assert;
/// # fn main() {
/// enum MyEnum { Foo, Bar(i32), Baz{x: i32} }
/// assert_that!(&MyEnum::Baz{x: 2}, is_variant!(MyEnum::Baz));
/// # }
/// ```
#[macro_export]
macro_rules! is_variant {
    ( $variant: path ) => {
        Box::new(|actual: &_| {
            use galvanic_assert::MatchResultBuilder;
            let builder = MatchResultBuilder::for_("is_variant");
            match actual {
                &$variant {..} => builder.matched(),
                _ => builder.failed_because(
                        &format!("passed variant does not match '{}'", stringify!($variant))
                )
            }
        })
    }
}

/// Matches the contents of an `Option` againts a passed `Matcher`.
///
/// #Examples
/// ```rust
/// # #[macro_use] extern crate galvanic_assert;
/// use galvanic_assert::matchers::*;
/// use galvanic_assert::matchers::variant::*;
/// # fn main() {
/// assert_that!(&Some(32), maybe_some(eq(32)));
/// # }
pub fn maybe_some<'a, T: 'a>(matcher: Box<Matcher<'a,T> + 'a>) -> Box<Matcher<'a,Option<T>> + 'a> {
    Box::new(move |maybe_actual: &'a Option<T>| {
        maybe_actual.as_ref()
                    .map_or(MatchResultBuilder::for_("maybe_some")
                                               .failed_because("passed Option is None; cannot evaluate nested matcher"),
                            |actual| matcher.check(actual)
        )
    })
}

/// Matches the contents of a `Result` if it is `Ok` againts a passed `Matcher`.
///
/// #Examples
/// ```rust
/// # #[macro_use] extern crate galvanic_assert;
/// use galvanic_assert::matchers::*;
/// use galvanic_assert::matchers::variant::*;
/// # fn main() {
/// let ok: Result<i32,()> = Ok(32);
/// assert_that!(&ok, maybe_ok(eq(32)));
/// # }
pub fn maybe_ok<'a, T: 'a, E: 'a>(matcher: Box<Matcher<'a,T> + 'a>) -> Box<Matcher<'a,Result<T,E>> + 'a> {
    Box::new(move |maybe_actual: &'a Result<T,E>| {
        match maybe_actual.as_ref() {
            Ok(actual) => matcher.check(actual),
            Err(_) => MatchResultBuilder::for_("maybe_ok")
                                       .failed_because("passed Result is Err; cannot evaluate nested matcher")
        }
    })
}

/// Matches the contents of a `Result` if it is `Err` againts a passed `Matcher`.
///
/// #Examples
/// ```rust
/// # #[macro_use] extern crate galvanic_assert;
/// use galvanic_assert::matchers::*;
/// use galvanic_assert::matchers::variant::*;
/// # fn main() {
/// let err: Result<i32,i32> = Err(32);
/// assert_that!(&err, maybe_err(eq(32)));
/// # }
pub fn maybe_err<'a, T: 'a, E: 'a>(matcher: Box<Matcher<'a,E> + 'a>) -> Box<Matcher<'a,Result<T,E>> + 'a> {
    Box::new(move |maybe_actual: &'a Result<T,E>| {
        match maybe_actual.as_ref() {
            Err(actual) => matcher.check(actual),
            Ok(_) => MatchResultBuilder::for_("maybe_err")
                                        .failed_because("passed Result is Ok; cannot evaluate nested matcher")
        }
    })
}