Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,21 @@ This is analogous to the `EXPECT_*` family of macros in GoogleTest.

To make a non-fatal assertion, use the macro [`expect_that!`]. The test must
also be marked with [`googletest::test`] instead of the Rust-standard `#[test]`.
It must return [`Result<()>`].

```rust
use googletest::prelude::*;

#[googletest::test]
fn three_non_fatal_assertions() {
let value = 2;
expect_that!(value, eq(2)); // Passes; test still considered passing.
expect_that!(value, eq(3)); // Fails; logs failure and marks the test failed.
expect_that!(value, eq(4)); // A second failure, also logged.
}
```

This can be used in the same tests as `verify_that!`, in which case the test
function must also return [`Result<()>`]:

```rust
use googletest::prelude::*;
Expand Down
17 changes: 16 additions & 1 deletion googletest/crate_docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,22 @@ aborts.

To make a non-fatal assertion, use the macro [`expect_that!`]. The test must
also be marked with [`googletest::test`][test] instead of the Rust-standard
`#[test]`. It must return [`Result<()>`].
`#[test]`.

```no_run
use googletest::prelude::*;

#[googletest::test]
fn three_non_fatal_assertions() {
let value = 2;
expect_that!(value, eq(2)); // Passes; test still considered passing.
expect_that!(value, eq(3)); // Fails; logs failure and marks the test failed.
expect_that!(value, eq(4)); // A second failure, also logged.
}
```

This can be used in the same tests as `verify_that!`, in which case the test
function must also return [`Result<()>`]:

```no_run
use googletest::prelude::*;
Expand Down
66 changes: 32 additions & 34 deletions googletest_macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,22 @@ use syn::{parse_macro_input, Attribute, ItemFn, ReturnType};
///
/// ```ignore
/// #[googletest::test]
/// fn should_work() -> googletest::Result {
/// fn should_work() {
/// ...
/// Ok(())
/// }
/// ```
///
/// The test function should return [`googletest::Result`] so that one can use
/// `verify_that!` with the question mark operator to abort execution. The last
/// line of the test should return `Ok(())`.
///
/// Any function your test invokes which contains a `verify_that!` call should
/// be invoked with the `?` operator so that a failure in the subroutine aborts
/// the rest of the test execution:
/// The test function is not required to have a return type. If it does have a
/// return type, that type must be [`googletest::Result`]. One may do this if
/// one wishes to use both fatal and non-fatal assertions in the same test. For
/// example:
///
/// ```ignore
/// #[googletest::test]
/// fn should_work() -> googletest::Result {
/// ...
/// assert_that_everything_is_okay()?;
/// do_some_more_stuff(); // Will not be executed if assert failed.
/// Ok(())
/// }
///
/// fn assert_that_everything_is_okay() -> googletest::Result {
/// verify_that!(...)
/// fn should_work() -> googletest::Result<()> {
/// let value = 2;
/// expect_that!(value, gt(0));
/// verify_that!(value, eq(2))
/// }
/// ```
///
Expand All @@ -59,14 +50,8 @@ pub fn test(
let attrs = parsed_fn.attrs.drain(..).collect::<Vec<_>>();
let (mut sig, block) = (parsed_fn.sig, parsed_fn.block);
let output_type = match sig.output.clone() {
ReturnType::Type(_, output_type) => output_type,
_ => {
return quote! {
compile_error!(
"Test function with the #[googletest::test] attribute must return googletest::Result<()>"
);
}.into()
}
ReturnType::Type(_, output_type) => Some(output_type),
ReturnType::Default => None,
};
sig.output = ReturnType::Default;
let (maybe_closure, invocation) = if sig.asyncness.is_some() {
Expand All @@ -93,14 +78,27 @@ pub fn test(
},
)
};
let function = quote! {
#(#attrs)*
#sig -> std::result::Result<(), googletest::internal::test_outcome::TestFailure> {
#maybe_closure
use googletest::internal::test_outcome::TestOutcome;
TestOutcome::init_current_test_outcome();
let result: #output_type = #invocation;
TestOutcome::close_current_test_outcome(result)
let function = if let Some(output_type) = output_type {
quote! {
#(#attrs)*
#sig -> std::result::Result<(), googletest::internal::test_outcome::TestFailure> {
#maybe_closure
use googletest::internal::test_outcome::TestOutcome;
TestOutcome::init_current_test_outcome();
let result: #output_type = #invocation;
TestOutcome::close_current_test_outcome(result)
}
}
} else {
quote! {
#(#attrs)*
#sig -> std::result::Result<(), googletest::internal::test_outcome::TestFailure> {
#maybe_closure
use googletest::internal::test_outcome::TestOutcome;
TestOutcome::init_current_test_outcome();
#invocation;
TestOutcome::close_current_test_outcome(googletest::Result::Ok(()))
}
}
};
let output = if attrs.iter().any(is_test_attribute) {
Expand Down
6 changes: 6 additions & 0 deletions integration_tests/src/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ mod tests {
Ok(())
}

#[googletest::test]
fn should_pass_with_expect_that_returning_unit() {
let value = 2;
expect_that!(value, eq(2));
}

#[test]
fn should_fail_on_assertion_failure() -> Result<()> {
let status = run_external_process("simple_assertion_failure").status()?;
Expand Down