Skip to main content

googletest/matchers/
le_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 less than or equal to (in the sense of `<=`) `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!(0, le(0))?; // Passes
31/// #     Ok(())
32/// # }
33/// # fn should_fail() -> Result<()> {
34/// verify_that!(1, le(0))?; // 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!(1u32, le(2u64))?; // Does not compile
49/// verify_that!(1u32 as u64, le(2u64))?; // Passes
50/// #     Ok(())
51/// # }
52/// ```
53///
54/// ```compile_fail
55/// # use googletest::prelude::*;
56/// # fn should_not_compile() -> Result<()> {
57/// let actual: &u32 = &1;
58/// let expected: u32 = 2;
59/// verify_that!(actual, le(expected))?; // Does not compile
60/// #     Ok(())
61/// # }
62/// ```
63///
64/// ```
65/// # use googletest::prelude::*;
66/// # fn should_pass() -> Result<()> {
67/// let actual: &u32 = &1;
68/// let expected: u32 = 2;
69/// verify_that!(actual, le(&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 le<ExpectedT>(expected: ExpectedT) -> LeMatcher<ExpectedT> {
78    LeMatcher { expected }
79}
80
81#[derive(MatcherBase)]
82pub struct LeMatcher<ExpectedT> {
83    expected: ExpectedT,
84}
85
86impl<ActualT: Debug + PartialOrd<ExpectedT> + Copy, ExpectedT: Debug> Matcher<ActualT>
87    for LeMatcher<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 less than or equal to {:?}", self.expected).into(),
96            MatcherResult::NoMatch => format!("is greater than {:?}", self.expected).into(),
97        }
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use crate::matcher::MatcherResult;
104    use crate::prelude::*;
105    use crate::Result;
106    use indoc::indoc;
107    use std::ffi::OsString;
108
109    #[test]
110    fn le_matches_i32_with_i32() -> Result<()> {
111        let actual: i32 = 0;
112        let expected: i32 = 0;
113        verify_that!(actual, le(expected))
114    }
115
116    #[test]
117    fn le_does_not_match_bigger_i32() -> Result<()> {
118        let matcher = le(0);
119        let result = matcher.matches(1);
120        verify_that!(result, eq(MatcherResult::NoMatch))
121    }
122
123    #[test]
124    fn le_matches_smaller_str() -> Result<()> {
125        verify_that!("A", le("B"))
126    }
127
128    #[test]
129    fn le_does_not_match_bigger_str() -> Result<()> {
130        let matcher = le("a");
131        let result = matcher.matches("z");
132        verify_that!(result, eq(MatcherResult::NoMatch))
133    }
134
135    #[test]
136    fn le_mismatch_contains_actual_and_expected() -> Result<()> {
137        let result = verify_that!(489, le(294));
138        let formatted_message = format!("{}", result.unwrap_err());
139
140        verify_that!(
141            formatted_message.as_str(),
142            contains_substring(indoc!(
143                "
144                Value of: 489
145                Expected: is less than or equal to 294
146                Actual: 489,
147                  which is greater than 294
148                "
149            ))
150        )
151    }
152
153    // Test `le` matcher where actual is `&OsString` and expected is `&str`.
154    // Note that stdlib is a little bit inconsistent: `PartialOrd` exists for
155    // `OsString` and `str`, but only in one direction: it's only possible to
156    // compare `OsString` with `str` if `OsString` is on the left side of the
157    // "<=" operator (`impl PartialOrd<str> for OsString`).
158    //
159    // The comparison in the other direction is not defined.
160    //
161    // This means that the test case bellow effectively ensures that
162    // `verify_that(actual, le(expected))` works if `actual <= expected` works
163    // (regardless whether the `expected <= actual` works`).
164    #[test]
165    fn le_matches_owned_osstring_reference_with_string_reference() -> Result<()> {
166        let expected = "B";
167        let actual: OsString = "A".into();
168        verify_that!(&actual, le(expected))
169    }
170
171    #[test]
172    fn le_matches_ipv6addr_with_ipaddr() -> Result<()> {
173        use std::net::IpAddr;
174        use std::net::Ipv6Addr;
175        let actual: IpAddr = "127.0.0.1".parse().unwrap();
176        let expected: Ipv6Addr = "2001:4860:4860::8844".parse().unwrap();
177        verify_that!(actual, le(expected))
178    }
179
180    #[test]
181    fn le_matches_with_custom_partial_ord() -> Result<()> {
182        /// A custom "number" that is lower than all other numbers. The only
183        /// things we define about this "special" number is `PartialOrd` and
184        /// `PartialEq` against `u32`.
185        #[derive(Debug, Clone, Copy)]
186        struct VeryLowNumber {}
187
188        impl std::cmp::PartialEq<u32> for VeryLowNumber {
189            fn eq(&self, _other: &u32) -> bool {
190                false
191            }
192        }
193
194        // PartialOrd (required for >) requires PartialEq.
195        impl std::cmp::PartialOrd<u32> for VeryLowNumber {
196            fn partial_cmp(&self, _other: &u32) -> Option<std::cmp::Ordering> {
197                Some(std::cmp::Ordering::Less)
198            }
199        }
200
201        impl std::cmp::PartialEq<VeryLowNumber> for u32 {
202            fn eq(&self, _other: &VeryLowNumber) -> bool {
203                false
204            }
205        }
206
207        impl std::cmp::PartialOrd<VeryLowNumber> for u32 {
208            fn partial_cmp(&self, _other: &VeryLowNumber) -> Option<std::cmp::Ordering> {
209                Some(std::cmp::Ordering::Greater)
210            }
211        }
212
213        let actual = VeryLowNumber {};
214        let expected: u32 = 42;
215
216        verify_that!(actual, le(expected))
217    }
218}