Skip to content

Commit 5f4ab13

Browse files
Googlercopybara-github
authored andcommitted
Add a recursion base-case to verify_pred to avoid stack overflow, allow printing of arbitrary function arguments, and add tests for its current functionality to catch regressions as more changes are added to implement other features.
PiperOrigin-RevId: 684434719
1 parent 8479412 commit 5f4ab13

File tree

3 files changed

+107
-17
lines changed

3 files changed

+107
-17
lines changed

googletest/src/assertions.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -168,24 +168,23 @@ macro_rules! verify_that {
168168
/// # */
169169
/// fn test() -> Result<()> {
170170
/// let a = 1;
171-
/// let b = 7;
172-
/// let n = 5;
173-
/// verify_pred!(equals_modulo(a, b, n))?;
171+
/// fn b(_x: i32) -> i32 { 7 }
172+
/// verify_pred!(equals_modulo(a, b(b(2)), 2 + 3))?;
174173
/// Ok(())
175174
/// }
176175
/// # verify_that!(
177176
/// # test(),
178-
/// # err(displays_as(contains_substring("equals_modulo(a, b, n) was false with")))
177+
/// # err(displays_as(contains_substring("equals_modulo(a, b(b(2)), 2 + 3) was false with")))
179178
/// # ).unwrap();
180179
/// ```
181180
///
182181
/// This results in the following message:
183182
///
184183
/// ```text
185-
/// equals_modulo(a, b, n) was false with
184+
/// equals_modulo(a, b(b(2)), 2 + 3) was false with
186185
/// a = 1,
187-
/// b = 7,
188-
/// n = 5
186+
/// b(v) = 7,
187+
/// 2 + 3 = 5
189188
/// ```
190189
///
191190
/// The function passed to this macro must return `bool`. Each of the arguments
@@ -205,20 +204,30 @@ macro_rules! verify_that {
205204
/// ```
206205
///
207206
/// **Warning:** This macro assumes that the arguments passed to the predicate
208-
/// are either *variables* or *calls to pure functions*. If two subsequent
209-
/// invocations to any of the expresssions passed as arguments result in
210-
/// different values, then the output message of a test failure will deviate
211-
/// from the values actually passed to the predicate. For this reason, *always
212-
/// assign the outputs of non-pure functions to variables before using them in
213-
/// this macro. For example:
207+
/// are pure so that two subsequent invocations to any of the expresssions
208+
/// passed as arguments result in different values, then the output message of a
209+
/// test failure will deviate from the values actually passed to the predicate.
210+
/// For this reason, *always assign the outputs of non-pure functions to
211+
/// variables before using them in this macro. For example:
214212
///
215213
/// ```ignore
216214
/// let output = generate_random_number(); // Assigned outside of verify_pred.
217215
/// verify_pred!(is_sufficiently_random(output))?;
218216
/// ```
219217
#[macro_export]
220218
macro_rules! verify_pred {
221-
([$($predicate:tt)*]($($arg:tt),* $(,)?)) => {
219+
(@internal [$($predicate:tt)+] $(,)?) => {
220+
if !$($predicate)* {
221+
$crate::assertions::internal::report_failed_predicate(
222+
stringify!($($predicate)*),
223+
vec![],
224+
)
225+
} else {
226+
Ok(())
227+
}
228+
};
229+
230+
(@internal [$($predicate:tt)+]($($arg:expr),* $(,)?)) => {
222231
if !$($predicate)*($($arg),*) {
223232
$crate::assertions::internal::report_failed_predicate(
224233
concat!(stringify!($($predicate)*), stringify!(($($arg),*))),
@@ -229,12 +238,12 @@ macro_rules! verify_pred {
229238
}
230239
};
231240

232-
([$($predicate:tt)*] $first:tt $($rest:tt)*) => {
233-
$crate::verify_pred!([$($predicate)* $first] $($rest)*)
241+
(@internal [$($predicate:tt)+] $first:tt $($rest:tt)*) => {
242+
$crate::verify_pred!(@internal [$($predicate)* $first] $($rest)*)
234243
};
235244

236245
($first:tt $($rest:tt)*) => {
237-
$crate::verify_pred!([$first] $($rest)*)
246+
$crate::verify_pred!(@internal [$first] $($rest)*)
238247
};
239248
}
240249

googletest/tests/assertions_test.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
mod verify_pred {
2+
use googletest::prelude::*;
3+
use indoc::indoc;
4+
5+
#[test]
6+
fn supports_function_call() -> Result<()> {
7+
fn f(_a: u32, _b: u32, _c: u32) -> bool {
8+
false
9+
}
10+
fn g(_a: u32) -> u32 {
11+
5
12+
}
13+
14+
let a = 1;
15+
let res = verify_pred!(f(a, g(g(3)), 1 + 2));
16+
verify_that!(
17+
res,
18+
err(displays_as(contains_substring(indoc! {
19+
"
20+
f(a, g(g(3)), 1 + 2) was false with
21+
a = 1,
22+
g(g(3)) = 5,
23+
1 + 2 = 3
24+
"
25+
})))
26+
)?;
27+
28+
Ok(())
29+
}
30+
31+
#[test]
32+
fn supports_trailing_comma() -> Result<()> {
33+
verify_that!(verify_pred!(false,), err(anything()))
34+
}
35+
36+
#[test]
37+
fn supports_non_function() -> Result<()> {
38+
verify_pred!(true)?;
39+
verify_that!(verify_pred!(false), err(anything()))
40+
}
41+
42+
#[test]
43+
fn supports_method_calls() -> Result<()> {
44+
struct Foo {
45+
b: Bar,
46+
}
47+
struct Bar;
48+
impl Bar {
49+
fn c(&self) -> bool {
50+
false
51+
}
52+
}
53+
54+
let a = Foo { b: Bar };
55+
let res = verify_pred!(a.b.c());
56+
verify_that!(res, err(displays_as(contains_substring("a.b.c() was false"))))
57+
}
58+
59+
#[test]
60+
fn supports_chained_method_calls() -> Result<()> {
61+
struct Foo;
62+
impl Foo {
63+
fn b(self) -> Bar {
64+
Bar
65+
}
66+
}
67+
struct Bar;
68+
impl Bar {
69+
fn c(self) -> bool {
70+
false
71+
}
72+
}
73+
74+
let a = Foo;
75+
let res = verify_pred!(a.b().c());
76+
verify_that!(res, err(displays_as(contains_substring("a.b().c() was false"))))?;
77+
78+
Ok(())
79+
}
80+
}

googletest/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
mod all_matcher_test;
1616
mod any_matcher_test;
17+
mod assertions_test;
1718
mod colorized_diff_test;
1819
mod composition_test;
1920
mod elements_are_matcher_test;

0 commit comments

Comments
 (0)