googletest_predicates/
lib.rs

1use googletest::matcher::{Matcher, MatcherResult};
2use predicates::{reflection::PredicateReflection, Predicate};
3use std::{
4    fmt::{Debug, Display},
5    marker::PhantomData,
6};
7
8/// Provides a [Predicate] implementation for a given googletest [Matcher].
9pub fn matcher<M: ToPredicate<T, P>, T: Debug, P: Predicate<T>>(matcher: M) -> impl Predicate<T> {
10    matcher.to_predicate()
11}
12
13/// Some type that can be converted into a [Predicate].
14pub trait ToPredicate<T, P: Predicate<T>> {
15    /// Converts the type into a [Predicate].
16    fn to_predicate(self) -> P;
17}
18
19/// Implementation of [ToPredicate] for all googletest [Matcher]'s.
20impl<M, T> ToPredicate<T, MatcherPredicate<M, T>> for M
21where
22    M: Matcher<ActualT = T>,
23    T: Debug,
24{
25    fn to_predicate(self) -> MatcherPredicate<M, T> {
26        MatcherPredicate {
27            matcher: self,
28            _phantom_data_t: Default::default(),
29        }
30    }
31}
32
33struct MatcherPredicate<M, T>
34where
35    M: Matcher<ActualT = T>,
36    T: Debug,
37{
38    matcher: M,
39    _phantom_data_t: PhantomData<T>,
40}
41
42impl<M, T> Predicate<T> for MatcherPredicate<M, T>
43where
44    M: Matcher<ActualT = T>,
45    T: Debug,
46{
47    fn eval(&self, variable: &T) -> bool {
48        match self.matcher.matches(variable) {
49            MatcherResult::Match => true,
50            MatcherResult::NoMatch => false,
51        }
52    }
53}
54
55impl<M, T> PredicateReflection for MatcherPredicate<M, T>
56where
57    M: Matcher<ActualT = T>,
58    T: Debug,
59{
60}
61
62impl<M, T> Display for MatcherPredicate<M, T>
63where
64    M: Matcher<ActualT = T>,
65    T: Debug,
66{
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        f.write_str(&self.matcher.describe(MatcherResult::Match))
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75    use googletest::{expect_that, matchers::*};
76    use mockall::automock;
77
78    #[cfg_attr(test, automock)]
79    trait MyTrait {
80        fn foo(&self, x: u32) -> u32;
81    }
82
83    #[googletest::test]
84    fn test_matcher_eq_1_to_string() {
85        expect_that!(matcher(eq(1)).to_string(), eq("is equal to 1"));
86    }
87
88    #[googletest::test]
89    fn test_matcher_eq_1_eval_returns_true() {
90        expect_that!(matcher(eq(1)).eval(&1), eq(true));
91    }
92
93    #[googletest::test]
94    fn test_matcher_eq_1_eval_returns_false() {
95        expect_that!(matcher(eq(1)).eval(&2), eq(false));
96    }
97
98    #[googletest::test]
99    fn test_mockall_with_matcher_fn() {
100        let mut mock = MockMyTrait::new();
101        mock.expect_foo()
102            .with(matcher(eq(1)))
103            .times(1)
104            .returning(|x| x + 1);
105        expect_that!(mock.foo(1), eq(2))
106    }
107}