Skip to main content

googletest/matchers/
gt_matcher.rs

1// Copyright 2022 Google LLC
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
15use crate::{
16    description::Description,
17    matcher::{Matcher, MatcherBase, MatcherResult},
18};
19use std::fmt::Debug;
20
21/// Matches a value greater (in the sense of `>`) than `expected`.
22///
23/// The types of `ActualT` of `actual` and `ExpectedT` of `expected` must be
24/// comparable via the `PartialOrd` trait. Namely, `ActualT` must implement
25/// `PartialOrd<ExpectedT>`.
26///
27/// ```
28/// # use googletest::prelude::*;
29/// # fn should_pass() -> Result<()> {
30/// verify_that!(38, gt(1))?; // Passes
31/// #     Ok(())
32/// # }
33/// # fn should_fail() -> Result<()> {
34/// verify_that!(234, gt(234))?; // Fails
35/// #     Ok(())
36/// # }
37/// # should_pass().unwrap();
38/// # should_fail().unwrap_err();
39/// ```
40///
41/// In most cases the params neeed to be the same type or they need to be cast
42/// explicitly. This can be surprising when comparing integer types or
43/// references:
44///
45/// ```compile_fail
46/// # use googletest::prelude::*;
47/// # fn should_not_compile() -> Result<()> {
48/// verify_that!(123u32, gt(0u64))?; // Does not compile
49/// verify_that!(123u32 as u64, gt(0u64))?; // Passes
50/// #     Ok(())
51/// # }
52/// ```
53///
54/// ```compile_fail
55/// # use googletest::prelude::*;
56/// # fn should_not_compile() -> Result<()> {
57/// let actual: &u32 = &2;
58/// let expected: u32 = 1;
59/// verify_that!(actual, gt(expected))?; // Does not compile
60/// #     Ok(())
61/// # }
62/// ```
63///
64/// ```
65/// # use googletest::prelude::*;
66/// # fn should_pass() -> Result<()> {
67/// let actual: &u32 = &2;
68/// let expected: u32 = 1;
69/// verify_that!(actual, gt(&expected))?; // Compiles and passes
70/// #     Ok(())
71/// # }
72/// # should_pass().unwrap();
73/// ```
74///
75/// You can find the standard library `PartialOrd` implementation in
76/// <https://doc.rust-lang.org/core/cmp/trait.PartialOrd.html#implementors>
77pub fn gt<ExpectedT: Debug>(expected: ExpectedT) -> GtMatcher<ExpectedT> {
78    GtMatcher { expected }
79}
80
81#[derive(MatcherBase)]
82pub struct GtMatcher<ExpectedT> {
83    expected: ExpectedT,
84}
85
86impl<ActualT: Debug + PartialOrd<ExpectedT> + Copy, ExpectedT: Debug> Matcher<ActualT>
87    for GtMatcher<ExpectedT>
88{
89    fn matches(&self, actual: ActualT) -> MatcherResult {
90        (actual > self.expected).into()
91    }
92
93    fn describe(&self, matcher_result: MatcherResult) -> Description {
94        match matcher_result {
95            MatcherResult::Match => format!("is greater than {:?}", self.expected).into(),
96            MatcherResult::NoMatch => {
97                format!("is less than or equal to {:?}", self.expected).into()
98            }
99        }
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use crate::matcher::MatcherResult;
106    use crate::prelude::*;
107    use crate::Result;
108    use indoc::indoc;
109    use std::ffi::OsString;
110
111    #[test]
112    fn gt_matches_i32_with_i32() -> Result<()> {
113        let actual: i32 = 321;
114        let expected: i32 = 123;
115        verify_that!(actual, gt(expected))
116    }
117
118    #[test]
119    fn gt_does_not_match_equal_i32() -> Result<()> {
120        let matcher = gt(10);
121        let result = matcher.matches(10);
122        verify_that!(result, eq(MatcherResult::NoMatch))
123    }
124
125    #[test]
126    fn gt_does_not_match_lower_i32() -> Result<()> {
127        let matcher = gt(-50);
128        let result = matcher.matches(-51);
129        verify_that!(result, eq(MatcherResult::NoMatch))
130    }
131
132    #[test]
133    fn gt_matches_greater_str() -> Result<()> {
134        verify_that!("B", gt("A"))
135    }
136
137    #[test]
138    fn gt_does_not_match_lesser_str() -> Result<()> {
139        let matcher = gt("B");
140        let result = matcher.matches("A");
141        verify_that!(result, eq(MatcherResult::NoMatch))
142    }
143
144    #[test]
145    fn gt_mismatch_contains_actual_and_expected() -> Result<()> {
146        let result = verify_that!(481, gt(632));
147
148        verify_that!(
149            result,
150            err(displays_as(contains_substring(indoc!(
151                "
152                Value of: 481
153                Expected: is greater than 632
154                Actual: 481,
155                "
156            ))))
157        )
158    }
159
160    #[test]
161    fn gt_mismatch_combined_with_each() -> Result<()> {
162        let result = verify_that!(vec![19, 23, 11], each(gt(&15)));
163
164        verify_that!(
165            result,
166            err(displays_as(contains_substring(indoc!(
167                "
168                Value of: vec![19, 23, 11]
169                Expected: only contains elements that is greater than 15
170                Actual: [19, 23, 11],
171                  whose element #2 is 11, which is less than or equal to 15
172                "
173            ))))
174        )
175    }
176
177    #[test]
178    fn gt_describe_matches() -> Result<()> {
179        verify_that!(
180            Matcher::<i32>::describe(&gt(232), MatcherResult::Match),
181            displays_as(eq("is greater than 232"))
182        )
183    }
184
185    #[test]
186    fn gt_describe_does_not_match() -> Result<()> {
187        verify_that!(
188            Matcher::<i32>::describe(&gt(232), MatcherResult::NoMatch),
189            displays_as(eq("is less than or equal to 232"))
190        )
191    }
192
193    // Test `gt` matcher where actual is `&OsString` and expected is `&str`.
194    // Note that stdlib is a little bit inconsistent: `PartialOrd` exists for
195    // `OsString` and `str`, but only in one direction: it's only possible to
196    // compare `OsString` with `str` if `OsString` is on the left side of the
197    // ">" operator (`impl PartialOrd<str> for OsString`).
198    //
199    // The comparison in the other direction is not defined.
200    //
201    // This means that the test case bellow effectively ensures that
202    // `verify_that(actual, gt(expected))` works if `actual > expected` works
203    // (regardless whether the `expected > actual` works`).
204    #[test]
205    fn gt_matches_owned_osstring_reference_with_string_reference() -> Result<()> {
206        let expected = "A";
207        let actual: OsString = "B".to_string().into();
208        verify_that!(&actual, gt(expected))
209    }
210
211    #[test]
212    fn gt_matches_ipv6addr_with_ipaddr() -> Result<()> {
213        use std::net::IpAddr;
214        use std::net::Ipv6Addr;
215        let actual: Ipv6Addr = "2001:4860:4860::8888".parse().unwrap();
216        let expected: IpAddr = "127.0.0.1".parse().unwrap();
217        verify_that!(actual, gt(expected))
218    }
219
220    #[test]
221    fn gt_matches_with_custom_partial_ord() -> Result<()> {
222        /// A custom "number" that is smaller than all other numbers. The only
223        /// things we define about this "special" number is `PartialOrd` and
224        /// `PartialEq` against `u32`.
225        #[derive(Debug)]
226        struct VeryLowNumber {}
227
228        impl std::cmp::PartialEq<u32> for VeryLowNumber {
229            fn eq(&self, _other: &u32) -> bool {
230                false
231            }
232        }
233
234        // PartialOrd (required for >) requires PartialEq.
235        impl std::cmp::PartialOrd<u32> for VeryLowNumber {
236            fn partial_cmp(&self, _other: &u32) -> Option<std::cmp::Ordering> {
237                Some(std::cmp::Ordering::Less)
238            }
239        }
240
241        impl std::cmp::PartialEq<VeryLowNumber> for u32 {
242            fn eq(&self, _other: &VeryLowNumber) -> bool {
243                false
244            }
245        }
246
247        impl std::cmp::PartialOrd<VeryLowNumber> for u32 {
248            fn partial_cmp(&self, _other: &VeryLowNumber) -> Option<std::cmp::Ordering> {
249                Some(std::cmp::Ordering::Greater)
250            }
251        }
252
253        let actual: u32 = 42;
254        let expected = VeryLowNumber {};
255
256        verify_that!(actual, gt(expected))
257    }
258}