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