Skip to content

Commit a3e3372

Browse files
hovinenbcopybara-github
authored andcommitted
Fix support for async tests with googletest::test.
Previously, an async test annotated with `googletest::test` would not compile because the test content was put in an ordinary closure. Any uses of `.await` inside that closure would generate a compiler error. This changes the `googletest::test` macro implementation to detect that the test is async and adjust the generation accordingly. If the test is async, then no closure is generated, but the test content is placed in an async block. Unfortunately, there does not appear to be a single way to cover both the sync and async cases currently, as explained in the code comments. A further refinement of this approach could possibly address #4. PiperOrigin-RevId: 524774676
1 parent fcb8b20 commit a3e3372

File tree

5 files changed

+97
-6
lines changed

5 files changed

+97
-6
lines changed

googletest/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ regex = "1.6.0"
4040
anyhow = { version = "1.0.70", optional = true }
4141
indoc = { version = "2", optional = true }
4242
rstest = { version = "0.17.0", optional = true }
43+
tokio = { version = "1", optional = true, features = ["time", "macros", "rt"] }
4344

4445
[dev-dependencies]
4546
indoc = "2"
@@ -60,6 +61,12 @@ name = "assertion_failure_in_subroutine"
6061
path = "integration_tests/assertion_failure_in_subroutine.rs"
6162
test = false
6263

64+
[[bin]]
65+
name = "async_test_with_expect_that"
66+
path = "integration_tests/async_test_with_expect_that.rs"
67+
test = false
68+
required_features = ["tokio"]
69+
6370
[[bin]]
6471
name = "custom_error_message"
6572
path = "integration_tests/custom_error_message.rs"
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2023 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+
fn main() {}
16+
17+
#[deny(warnings)]
18+
#[cfg(test)]
19+
mod tests {
20+
#[cfg(not(google3))]
21+
use googletest::matchers;
22+
use googletest::{expect_that, verify_that, Result};
23+
use matchers::eq;
24+
use std::time::Duration;
25+
use tokio::time::sleep;
26+
27+
#[googletest::test]
28+
#[tokio::test]
29+
async fn async_test_failure_with_non_fatal_assertion() -> Result<()> {
30+
sleep(Duration::from_millis(1)).await;
31+
expect_that!(2, eq(3));
32+
Ok(())
33+
}
34+
35+
#[googletest::test]
36+
#[tokio::test]
37+
async fn async_test_failure_with_fatal_assertion() -> Result<()> {
38+
sleep(Duration::from_millis(1)).await;
39+
verify_that!(3, eq(4))?;
40+
Ok(())
41+
}
42+
}

googletest/integration_tests/integration_tests.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ mod tests {
1919
#[cfg(not(google3))]
2020
use googletest::{all, matchers, matchers::str_matcher};
2121
use googletest::{
22-
assert_that, expect_pred, expect_that, test, verify_pred, verify_that,
23-
GoogleTestSupport, Result,
22+
assert_that, expect_pred, expect_that, test, verify_pred, verify_that, GoogleTestSupport,
23+
Result,
2424
};
2525
use indoc::indoc;
2626
#[cfg(google3)]
@@ -495,7 +495,24 @@ mod tests {
495495
)
496496
}
497497

498-
#[cfg(feature = "anyhow")]
498+
#[test]
499+
fn async_test_with_google_test_runs_correctly() -> Result<()> {
500+
let output = run_external_process_in_tests_directory("async_test_with_expect_that")?;
501+
502+
expect_that!(
503+
output,
504+
contains_substring("tests::async_test_failure_with_non_fatal_assertion ... FAILED")
505+
.times(eq(1))
506+
);
507+
expect_that!(
508+
output,
509+
contains_substring("tests::async_test_failure_with_fatal_assertion ... FAILED")
510+
.times(eq(1))
511+
);
512+
expect_that!(output, contains_substring("Expected: is equal to 3"));
513+
verify_that!(output, contains_substring("Expected: is equal to 4"))
514+
}
515+
499516
#[test]
500517
fn test_can_return_anyhow_generated_error() -> Result<()> {
501518
let output = run_external_process_in_tests_directory("test_returning_anyhow_error")?;

googletest_macro/src/lib.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,37 @@ pub fn test(
6464
}.into();
6565
};
6666
sig.output = ReturnType::Default;
67+
let (maybe_closure, invocation) = if sig.asyncness.is_some() {
68+
(
69+
// In the async case, the ? operator returns from the *block* rather than the
70+
// surrounding function. So we just put the test content in an async block. Async
71+
// closures are still unstable (see https://github.com/rust-lang/rust/issues/62290),
72+
// so we can't use the same solution as the sync case below.
73+
quote! {},
74+
quote! {
75+
async { #block }.await
76+
},
77+
)
78+
} else {
79+
(
80+
// In the sync case, the ? operator returns from the surrounding function. So we must
81+
// create a separate closure from which the ? operator can return in order to capture
82+
// the output.
83+
quote! {
84+
let test = move || #block;
85+
},
86+
quote! {
87+
test()
88+
},
89+
)
90+
};
6791
let function = quote! {
6892
#(#attrs)*
6993
#sig -> std::result::Result<(), ()> {
70-
let test = move || #block;
94+
#maybe_closure
7195
use googletest::internal::test_outcome::TestOutcome;
7296
TestOutcome::init_current_test_outcome();
73-
let result: #output_type = test();
97+
let result: #output_type = #invocation;
7498
TestOutcome::close_current_test_outcome(result)
7599
}
76100
};

run_integration_tests.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ INTEGRATION_TEST_BINARIES=(
2626
"integration_tests"
2727
"assert_predicate_with_failure"
2828
"assertion_failure_in_subroutine"
29+
"async_test_with_expect_that"
2930
"custom_error_message"
3031
"expect_pred_failure"
3132
"expect_that_failure"
@@ -48,6 +49,6 @@ INTEGRATION_TEST_BINARIES=(
4849

4950
cargo build
5051
for binary in ${INTEGRATION_TEST_BINARIES[@]}; do
51-
cargo rustc -p googletest --bin $binary --features anyhow,indoc,rstest -- --test
52+
cargo rustc -p googletest --bin $binary --features anyhow,indoc,rstest,tokio -- --test
5253
done
5354
./target/debug/integration_tests

0 commit comments

Comments
 (0)