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 
15 use crate::{
16     description::Description,
17     matcher::{Matcher, MatcherResult},
18 };
19 use std::{fmt::Debug, marker::PhantomData};
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>
le<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug>( expected: ExpectedT, ) -> impl Matcher<ActualT = ActualT>77 pub fn le<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug>(
78     expected: ExpectedT,
79 ) -> impl Matcher<ActualT = ActualT> {
80     LeMatcher::<ActualT, _> { expected, phantom: Default::default() }
81 }
82 
83 struct LeMatcher<ActualT, ExpectedT> {
84     expected: ExpectedT,
85     phantom: PhantomData<ActualT>,
86 }
87 
88 impl<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug> Matcher
89     for LeMatcher<ActualT, ExpectedT>
90 {
91     type ActualT = ActualT;
92 
matches(&self, actual: &ActualT) -> MatcherResult93     fn matches(&self, actual: &ActualT) -> MatcherResult {
94         (*actual <= self.expected).into()
95     }
96 
describe(&self, matcher_result: MatcherResult) -> Description97     fn describe(&self, matcher_result: MatcherResult) -> Description {
98         match matcher_result {
99             MatcherResult::Match => format!("is less than or equal to {:?}", self.expected).into(),
100             MatcherResult::NoMatch => format!("is greater than {:?}", self.expected).into(),
101         }
102     }
103 }
104 
105 #[cfg(test)]
106 mod tests {
107     use super::le;
108     use crate::matcher::{Matcher, MatcherResult};
109     use crate::prelude::*;
110     use indoc::indoc;
111     use std::ffi::OsString;
112 
113     #[test]
le_matches_i32_with_i32() -> Result<()>114     fn le_matches_i32_with_i32() -> Result<()> {
115         let actual: i32 = 0;
116         let expected: i32 = 0;
117         verify_that!(actual, le(expected))
118     }
119 
120     #[test]
le_does_not_match_bigger_i32() -> Result<()>121     fn le_does_not_match_bigger_i32() -> Result<()> {
122         let matcher = le(0);
123         let result = matcher.matches(&1);
124         verify_that!(result, eq(MatcherResult::NoMatch))
125     }
126 
127     #[test]
le_matches_smaller_str() -> Result<()>128     fn le_matches_smaller_str() -> Result<()> {
129         verify_that!("A", le("B"))
130     }
131 
132     #[test]
le_does_not_match_bigger_str() -> Result<()>133     fn le_does_not_match_bigger_str() -> Result<()> {
134         let matcher = le("a");
135         let result = matcher.matches(&"z");
136         verify_that!(result, eq(MatcherResult::NoMatch))
137     }
138 
139     #[test]
le_mismatch_contains_actual_and_expected() -> Result<()>140     fn le_mismatch_contains_actual_and_expected() -> Result<()> {
141         let result = verify_that!(489, le(294));
142         let formatted_message = format!("{}", result.unwrap_err());
143 
144         verify_that!(
145             formatted_message.as_str(),
146             contains_substring(indoc!(
147                 "
148                 Value of: 489
149                 Expected: is less than or equal to 294
150                 Actual: 489,
151                   which is greater than 294
152                 "
153             ))
154         )
155     }
156 
157     // Test `le` matcher where actual is `&OsString` and expected is `&str`.
158     // Note that stdlib is a little bit inconsistent: `PartialOrd` exists for
159     // `OsString` and `str`, but only in one direction: it's only possible to
160     // compare `OsString` with `str` if `OsString` is on the left side of the
161     // "<=" operator (`impl PartialOrd<str> for OsString`).
162     //
163     // The comparison in the other direction is not defined.
164     //
165     // This means that the test case bellow effectively ensures that
166     // `verify_that(actual, le(expected))` works if `actual <= expected` works
167     // (regardless whether the `expected <= actual` works`).
168     #[test]
le_matches_owned_osstring_reference_with_string_reference() -> Result<()>169     fn le_matches_owned_osstring_reference_with_string_reference() -> Result<()> {
170         let expected = "B";
171         let actual: OsString = "A".into();
172         verify_that!(&actual, le(expected))
173     }
174 
175     #[test]
le_matches_ipv6addr_with_ipaddr() -> Result<()>176     fn le_matches_ipv6addr_with_ipaddr() -> Result<()> {
177         use std::net::IpAddr;
178         use std::net::Ipv6Addr;
179         let actual: IpAddr = "127.0.0.1".parse().unwrap();
180         let expected: Ipv6Addr = "2001:4860:4860::8844".parse().unwrap();
181         verify_that!(actual, le(expected))
182     }
183 
184     #[test]
le_matches_with_custom_partial_ord() -> Result<()>185     fn le_matches_with_custom_partial_ord() -> Result<()> {
186         /// A custom "number" that is lower than all other numbers. The only
187         /// things we define about this "special" number is `PartialOrd` and
188         /// `PartialEq` against `u32`.
189         #[derive(Debug)]
190         struct VeryLowNumber {}
191 
192         impl std::cmp::PartialEq<u32> for VeryLowNumber {
193             fn eq(&self, _other: &u32) -> bool {
194                 false
195             }
196         }
197 
198         // PartialOrd (required for >) requires PartialEq.
199         impl std::cmp::PartialOrd<u32> for VeryLowNumber {
200             fn partial_cmp(&self, _other: &u32) -> Option<std::cmp::Ordering> {
201                 Some(std::cmp::Ordering::Less)
202             }
203         }
204 
205         impl std::cmp::PartialEq<VeryLowNumber> for u32 {
206             fn eq(&self, _other: &VeryLowNumber) -> bool {
207                 false
208             }
209         }
210 
211         impl std::cmp::PartialOrd<VeryLowNumber> for u32 {
212             fn partial_cmp(&self, _other: &VeryLowNumber) -> Option<std::cmp::Ordering> {
213                 Some(std::cmp::Ordering::Greater)
214             }
215         }
216 
217         let actual = VeryLowNumber {};
218         let expected: u32 = 42;
219 
220         verify_that!(actual, le(expected))
221     }
222 }
223