From 82df24c286db3ba350439df6358c54da6387b6d7 Mon Sep 17 00:00:00 2001 From: Bradford Hovinen Date: Wed, 6 Dec 2023 13:59:37 +0100 Subject: [PATCH] Support an extra failure message directly in `assert_that!` and `expect_that!`. This adds optional additional parameters to `assert_that!` and `expect_that!` which, if present, are formatted via `format!` into a failure message in the event of an assertion failure. The formatting takes place only if the assertion fails. Otherwise, the extra arguments have no effect. Fixes #331 --- googletest/src/assertions.rs | 78 +++++++++++++++++++ integration_tests/src/custom_error_message.rs | 56 +++++++++++++ integration_tests/src/integration_tests.rs | 26 ++++++- 3 files changed, 159 insertions(+), 1 deletion(-) diff --git a/googletest/src/assertions.rs b/googletest/src/assertions.rs index c741d3f8..9fd93adc 100644 --- a/googletest/src/assertions.rs +++ b/googletest/src/assertions.rs @@ -309,9 +309,42 @@ macro_rules! fail { /// Matches the given value against the given matcher, panicking if it does not /// match. /// +/// ```should_panic +/// # use googletest::prelude::*; +/// # fn should_fail() { +/// let value = 2; +/// assert_that!(value, eq(3)); // Fails and panics. +/// # } +/// # should_fail(); +/// ``` +/// /// This is analogous to assertions in most Rust test libraries, where a failed /// assertion causes a panic. /// +/// One may optionally add arguments which will be formatted and appended to a +/// failure message. For example: +/// +/// ```should_panic +/// # use googletest::prelude::*; +/// # fn should_fail() { +/// let value = 2; +/// let extra_information = "Some additional information"; +/// assert_that!(value, eq(3), "Test failed. Extra information: {extra_information}."); +/// # } +/// # should_fail(); +/// ``` +/// +/// This is output as follows: +/// +/// ```text +/// Value of: value +/// Expected: is equal to 3 +/// Actual: 2, +/// which isn't equal to 3 +/// at ... +/// Test failed. Extra information: Some additional information. +/// ``` +/// /// **Note for users of [GoogleTest for C++](http://google.github.io/googletest/):** /// This differs from the `ASSERT_THAT` macro in that it panics rather /// than triggering an early return from the invoking function. To get behaviour @@ -328,6 +361,19 @@ macro_rules! assert_that { } } }; + + ($actual:expr, $expected:expr, $($format_args:expr),* $(,)?) => { + match $crate::verify_that!($actual, $expected) + .with_failure_message(|| format!($($format_args),*)) + { + Ok(_) => {} + Err(e) => { + // The extra newline before the assertion failure message makes the failure a + // bit easier to read when there's some generic boilerplate from the panic. + panic!("\n{}", e); + } + } + }; } /// Asserts that the given predicate applied to the given arguments returns @@ -368,12 +414,44 @@ macro_rules! assert_pred { /// ```ignore /// verify_that!(actual, expected).and_log_failure() /// ``` +/// +/// One may optionally add arguments which will be formatted and appended to a +/// failure message. For example: +/// +/// ``` +/// # use googletest::prelude::*; +/// # fn should_fail() -> std::result::Result<(), googletest::internal::test_outcome::TestFailure> { +/// # googletest::internal::test_outcome::TestOutcome::init_current_test_outcome(); +/// let value = 2; +/// let extra_information = "Some additional information"; +/// expect_that!(value, eq(3), "Test failed. Extra information: {extra_information}."); +/// # googletest::internal::test_outcome::TestOutcome::close_current_test_outcome::<&str>(Ok(())) +/// # } +/// # should_fail().unwrap_err(); +/// ``` +/// +/// This is output as follows: +/// +/// ```text +/// Value of: value +/// Expected: is equal to 3 +/// Actual: 2, +/// which isn't equal to 3 +/// at ... +/// Test failed. Extra information: Some additional information. +/// ``` #[macro_export] macro_rules! expect_that { ($actual:expr, $expected:expr) => {{ use $crate::GoogleTestSupport; $crate::verify_that!($actual, $expected).and_log_failure(); }}; + + ($actual:expr, $expected:expr, $($format_args:expr),* $(,)?) => { + $crate::verify_that!($actual, $expected) + .with_failure_message(|| format!($($format_args),*)) + .and_log_failure() + }; } /// Asserts that the given predicate applied to the given arguments returns diff --git a/integration_tests/src/custom_error_message.rs b/integration_tests/src/custom_error_message.rs index 623e3aa5..74db8ef9 100644 --- a/integration_tests/src/custom_error_message.rs +++ b/integration_tests/src/custom_error_message.rs @@ -36,4 +36,60 @@ mod tests { verify_that!(value, eq(3)) .with_failure_message(|| "A custom error message from a closure".to_string()) } + + #[test] + fn should_include_failure_message_in_third_parameter_to_assert_that() { + let value = 2; + assert_that!(value, eq(3), "assert_that: A custom error message for value {value}"); + } + + #[test] + fn should_include_failure_message_in_third_parameter_with_format_arguments_to_assert_that() { + let value = 2; + assert_that!( + value, + eq(3), + "assert_that: A custom error message for incremented value {}", + value + 1 + ); + } + + #[test] + fn should_accept_trailing_comma_after_format_arguments_in_assert_that() { + let value = 2; + assert_that!( + value, + eq(3), + "assert_that: A custom error message for twice incremented value {}", + value + 2, + ); + } + + #[googletest::test] + fn should_include_failure_message_in_third_parameter_to_expect_that() { + let value = 2; + expect_that!(value, eq(3), "expect_that: A custom error message for value {value}"); + } + + #[googletest::test] + fn should_include_failure_message_in_third_parameter_with_format_arguments_to_expect_that() { + let value = 2; + expect_that!( + value, + eq(3), + "expect_that: A custom error message for incremented value {}", + value + 1 + ); + } + + #[googletest::test] + fn should_accept_trailing_comma_after_format_arguments_in_expect_that() { + let value = 2; + expect_that!( + value, + eq(3), + "expect_that: A custom error message for twice incremented value {}", + value + 2, + ); + } } diff --git a/integration_tests/src/integration_tests.rs b/integration_tests/src/integration_tests.rs index 14301ab1..fe747296 100644 --- a/integration_tests/src/integration_tests.rs +++ b/integration_tests/src/integration_tests.rs @@ -291,7 +291,31 @@ mod tests { verify_that!(output, contains_substring("A custom error message"))?; verify_that!(output, contains_substring("A custom error message in a String"))?; - verify_that!(output, contains_substring("A custom error message from a closure")) + verify_that!(output, contains_substring("A custom error message from a closure"))?; + verify_that!( + output, + contains_substring("assert_that: A custom error message for value 2") + )?; + verify_that!( + output, + contains_substring("assert_that: A custom error message for incremented value 3") + )?; + verify_that!( + output, + contains_substring("assert_that: A custom error message for twice incremented value 4") + )?; + verify_that!( + output, + contains_substring("expect_that: A custom error message for value 2") + )?; + verify_that!( + output, + contains_substring("expect_that: A custom error message for incremented value 3") + )?; + verify_that!( + output, + contains_substring("expect_that: A custom error message for twice incremented value 4") + ) } #[test]