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 (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!(1, lt(2))?; // Passes
31 /// # Ok(())
32 /// # }
33 /// # fn should_fail() -> Result<()> {
34 /// verify_that!(2, lt(2))?; // 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, lt(0u64))?; // Does not compile
49 /// verify_that!(123u32 as u64, lt(100000000u64))?; // 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 = 70;
59 /// verify_that!(actual, lt(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 = 70;
69 /// verify_that!(actual, lt(&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>
lt<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug>( expected: ExpectedT, ) -> impl Matcher<ActualT = ActualT>77 pub fn lt<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug>(
78 expected: ExpectedT,
79 ) -> impl Matcher<ActualT = ActualT> {
80 LtMatcher::<ActualT, _> { expected, phantom: Default::default() }
81 }
82
83 struct LtMatcher<ActualT, ExpectedT> {
84 expected: ExpectedT,
85 phantom: PhantomData<ActualT>,
86 }
87
88 impl<ActualT: Debug + PartialOrd<ExpectedT>, ExpectedT: Debug> Matcher
89 for LtMatcher<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 {:?}", self.expected).into(),
100 MatcherResult::NoMatch => {
101 format!("is greater than or equal to {:?}", self.expected).into()
102 }
103 }
104 }
105 }
106
107 #[cfg(test)]
108 mod tests {
109 use super::lt;
110 use crate::matcher::{Matcher, MatcherResult};
111 use crate::prelude::*;
112 use indoc::indoc;
113 use std::ffi::OsString;
114
115 #[test]
lt_matches_i32_with_i32() -> Result<()>116 fn lt_matches_i32_with_i32() -> Result<()> {
117 let actual: i32 = 10000;
118 let expected: i32 = 20000;
119 verify_that!(actual, lt(expected))
120 }
121
122 #[test]
lt_does_not_match_equal_i32() -> Result<()>123 fn lt_does_not_match_equal_i32() -> Result<()> {
124 let matcher = lt(10);
125 let result = matcher.matches(&10);
126 verify_that!(result, eq(MatcherResult::NoMatch))
127 }
128
129 #[test]
lt_does_not_match_lower_i32() -> Result<()>130 fn lt_does_not_match_lower_i32() -> Result<()> {
131 let matcher = lt(-50);
132 let result = matcher.matches(&50);
133 verify_that!(result, eq(MatcherResult::NoMatch))
134 }
135
136 #[test]
lt_matches_lesser_str() -> Result<()>137 fn lt_matches_lesser_str() -> Result<()> {
138 verify_that!("A", lt("B"))
139 }
140
141 #[test]
lt_does_not_match_bigger_str() -> Result<()>142 fn lt_does_not_match_bigger_str() -> Result<()> {
143 let matcher = lt("ab");
144 let result = matcher.matches(&"az");
145 verify_that!(result, eq(MatcherResult::NoMatch))
146 }
147
148 #[test]
lt_mismatch_contains_actual_and_expected() -> Result<()>149 fn lt_mismatch_contains_actual_and_expected() -> Result<()> {
150 let result = verify_that!(481, lt(45));
151 let formatted_message = format!("{}", result.unwrap_err());
152
153 verify_that!(
154 formatted_message.as_str(),
155 contains_substring(indoc!(
156 "
157 Value of: 481
158 Expected: is less than 45
159 Actual: 481,
160 which is greater than or equal to 45
161 "
162 ))
163 )
164 }
165
166 // Test `lt` matcher where actual is `&OsString` and expected is `&str`.
167 // Note that stdlib is a little bit inconsistent: `PartialOrd` exists for
168 // `OsString` and `str`, but only in one direction: it's only possible to
169 // compare `OsString` with `str` if `OsString` is on the left side of the
170 // "<" operator (`impl PartialOrd<str> for OsString`).
171 //
172 // The comparison in the other direction is not defined.
173 //
174 // This means that the test case bellow effectively ensures that
175 // `verify_that(actual, lt(expected))` works if `actual < expected` works
176 // (regardless whether the `expected < actual` works`).
177 #[test]
lt_matches_owned_osstring_reference_with_string_reference() -> Result<()>178 fn lt_matches_owned_osstring_reference_with_string_reference() -> Result<()> {
179 let expected = "C";
180 let actual: OsString = "B".to_string().into();
181 verify_that!(&actual, lt(expected))
182 }
183
184 #[test]
lt_matches_ipv6addr_with_ipaddr() -> Result<()>185 fn lt_matches_ipv6addr_with_ipaddr() -> Result<()> {
186 use std::net::IpAddr;
187 use std::net::Ipv6Addr;
188 let actual: IpAddr = "127.0.0.1".parse().unwrap();
189 let expected: Ipv6Addr = "2001:4860:4860::8844".parse().unwrap();
190 verify_that!(actual, lt(expected))
191 }
192
193 #[test]
lt_matches_with_custom_partial_ord() -> Result<()>194 fn lt_matches_with_custom_partial_ord() -> Result<()> {
195 /// A custom "number" that is smaller than all other numbers. The only
196 /// things we define about this "special" number is `PartialOrd` and
197 /// `PartialEq` against `u32`.
198 #[derive(Debug)]
199 struct VeryLowNumber {}
200
201 impl std::cmp::PartialEq<u32> for VeryLowNumber {
202 fn eq(&self, _other: &u32) -> bool {
203 false
204 }
205 }
206
207 // PartialOrd (required for >) requires PartialEq.
208 impl std::cmp::PartialOrd<u32> for VeryLowNumber {
209 fn partial_cmp(&self, _other: &u32) -> Option<std::cmp::Ordering> {
210 Some(std::cmp::Ordering::Less)
211 }
212 }
213
214 impl std::cmp::PartialEq<VeryLowNumber> for u32 {
215 fn eq(&self, _other: &VeryLowNumber) -> bool {
216 false
217 }
218 }
219
220 impl std::cmp::PartialOrd<VeryLowNumber> for u32 {
221 fn partial_cmp(&self, _other: &VeryLowNumber) -> Option<std::cmp::Ordering> {
222 Some(std::cmp::Ordering::Greater)
223 }
224 }
225
226 let actual = VeryLowNumber {};
227 let expected: u32 = 42;
228
229 verify_that!(actual, lt(expected))
230 }
231 }
232