From f8404213b540fee39c9fe954dcad1139edd9f0ca Mon Sep 17 00:00:00 2001 From: Bradford Hovinen Date: Fri, 30 Jun 2023 15:09:43 +0200 Subject: [PATCH] Improve the test assertion failure message when the wrong enum variant is used in `matches_pattern!`. Previously, the match explanation when the wrong enum variant was used would just state that there was no such field: ``` Value of: actual Expected: is AnEnum :: B which has field `0`, which is equal to 123 Actual: A(123), which has no field `0` ``` This is confusing, since the actual value _does_ have such a field. It's just of the wrong enum variant. This fixes the error message to indicate that the wrong variant was supplied: ``` Value of: actual Expected: is AnEnum :: B which has field `0`, which is equal to 123 Actual: A(123), which has the wrong enum variant `A` ``` To output the supplied enum variant, it is necessary to construct the debug output and strip it of any fields it may have. This is inefficient, but unfortunately there is no obvious way to directly debug-output just the enum variant with no fields. --- googletest/src/matchers/field_matcher.rs | 8 +-- googletest/tests/field_matcher_test.rs | 44 ++++++++++++++++- googletest/tests/matches_pattern_test.rs | 63 ++++++++++++++++-------- 3 files changed, 90 insertions(+), 25 deletions(-) diff --git a/googletest/src/matchers/field_matcher.rs b/googletest/src/matchers/field_matcher.rs index 0f5b6a2c..cd2b53de 100644 --- a/googletest/src/matchers/field_matcher.rs +++ b/googletest/src/matchers/field_matcher.rs @@ -183,10 +183,10 @@ pub mod internal { self.inner.explain_match(actual) ) } else { - // TODO(hovinen): This message could be misinterpreted to mean that there were a - // typo in the field, when it actually means that the actual value uses the - // wrong enum variant. Reword this appropriately. - format!("which has no field `{}`", self.field_path) + let formatted_actual_value = format!("{actual:?}"); + let without_fields = formatted_actual_value.split('(').next().unwrap_or(""); + let without_fields = without_fields.split('{').next().unwrap_or("").trim_end(); + format!("which has the wrong enum variant `{without_fields}`") } } diff --git a/googletest/tests/field_matcher_test.rs b/googletest/tests/field_matcher_test.rs index 626aa2fa..9b985a51 100644 --- a/googletest/tests/field_matcher_test.rs +++ b/googletest/tests/field_matcher_test.rs @@ -121,7 +121,49 @@ fn shows_correct_failure_message_for_wrong_enum_value() -> Result<()> { let result = verify_that!(value, field!(AnEnum::AValue.a, eq(123))); - verify_that!(result, err(displays_as(contains_substring("which has no field `a`")))) + verify_that!( + result, + err(displays_as(contains_substring("which has the wrong enum variant `AnotherValue`"))) + ) +} + +#[test] +fn shows_correct_failure_message_for_wrong_enum_value_with_tuple_field() -> Result<()> { + #[derive(Debug)] + enum AnEnum { + #[allow(dead_code)] // This variant is intentionally unused. + AValue(u32), + AnotherValue(u32), + } + let value = AnEnum::AnotherValue(123); + + let result = verify_that!(value, field!(AnEnum::AValue.0, eq(123))); + + verify_that!( + result, + err(displays_as(contains_substring("which has the wrong enum variant `AnotherValue`"))) + ) +} + +#[test] +fn shows_correct_failure_message_for_wrong_enum_value_with_named_field() -> Result<()> { + #[derive(Debug)] + enum AnEnum { + #[allow(dead_code)] // This variant is intentionally unused. + AValue(u32), + AnotherValue { + #[allow(unused)] + a: u32, + }, + } + let value = AnEnum::AnotherValue { a: 123 }; + + let result = verify_that!(value, field!(AnEnum::AValue.0, eq(123))); + + verify_that!( + result, + err(displays_as(contains_substring("which has the wrong enum variant `AnotherValue`"))) + ) } #[test] diff --git a/googletest/tests/matches_pattern_test.rs b/googletest/tests/matches_pattern_test.rs index df7b0995..ac3f72ea 100644 --- a/googletest/tests/matches_pattern_test.rs +++ b/googletest/tests/matches_pattern_test.rs @@ -188,6 +188,29 @@ fn has_correct_assertion_failure_message_for_field_and_property() -> Result<()> ) } +#[test] +fn has_meaningful_assertion_failure_message_when_wrong_enum_variant_is_used() -> Result<()> { + #[derive(Debug)] + enum AnEnum { + A(u32), + #[allow(unused)] + B(u32), + } + let actual = AnEnum::A(123); + let result = verify_that!(actual, matches_pattern!(AnEnum::B(eq(123)))); + + verify_that!( + result, + err(displays_as(contains_substring(indoc! {" + Value of: actual + Expected: is AnEnum :: B which has field `0`, which is equal to 123 + Actual: A(123), + which has the wrong enum variant `A` + " + }))) + ) +} + #[test] fn supports_qualified_struct_names() -> Result<()> { mod a_module { @@ -972,8 +995,8 @@ fn matches_struct_with_a_method_returning_reference_followed_by_a_field() -> Res } #[test] -fn matches_struct_with_a_method_returning_reference_followed_by_a_field_with_trailing_comma() --> Result<()> { +fn matches_struct_with_a_method_returning_reference_followed_by_a_field_with_trailing_comma( +) -> Result<()> { #[derive(Debug)] struct AStruct { a_field: u32, @@ -1043,8 +1066,8 @@ fn matches_struct_with_a_method_taking_enum_value_param_ret_ref_followed_by_fiel } #[test] -fn matches_struct_with_a_method_taking_two_parameters_with_trailing_comma_ret_ref_and_field() --> Result<()> { +fn matches_struct_with_a_method_taking_two_parameters_with_trailing_comma_ret_ref_and_field( +) -> Result<()> { #[derive(Debug)] struct AStruct { a_field: u32, @@ -1270,8 +1293,8 @@ fn matches_struct_with_field_followed_by_method_taking_enum_value_param_ret_ref( } #[test] -fn matches_struct_with_a_field_followed_by_a_method_with_params_and_trailing_comma_ret_ref() --> Result<()> { +fn matches_struct_with_a_field_followed_by_a_method_with_params_and_trailing_comma_ret_ref( +) -> Result<()> { #[derive(Debug)] struct AStruct { a_field: u32, @@ -1320,8 +1343,8 @@ fn matches_struct_with_a_field_followed_by_a_method_followed_by_a_field() -> Res } #[test] -fn matches_struct_with_a_field_followed_by_a_method_followed_by_a_field_with_trailing_comma() --> Result<()> { +fn matches_struct_with_a_field_followed_by_a_method_followed_by_a_field_with_trailing_comma( +) -> Result<()> { #[derive(Debug)] struct AStruct { a_field: u32, @@ -1376,8 +1399,8 @@ fn matches_struct_with_a_field_followed_by_a_method_with_params_followed_by_a_fi } #[test] -fn matches_struct_with_a_field_followed_by_a_method_with_params_and_trailing_comma_followed_by_a_field() --> Result<()> { +fn matches_struct_with_a_field_followed_by_a_method_with_params_and_trailing_comma_followed_by_a_field( +) -> Result<()> { #[derive(Debug)] struct AStruct { a_field: u32, @@ -1404,8 +1427,8 @@ fn matches_struct_with_a_field_followed_by_a_method_with_params_and_trailing_com } #[test] -fn matches_struct_with_field_followed_by_method_taking_enum_value_param_followed_by_field() --> Result<()> { +fn matches_struct_with_field_followed_by_method_taking_enum_value_param_followed_by_field( +) -> Result<()> { enum AnEnum { AVariant, } @@ -1463,8 +1486,8 @@ fn matches_struct_with_a_field_followed_by_a_method_ret_ref_followed_by_a_field( } #[test] -fn matches_struct_with_a_field_followed_by_a_method_ret_ref_followed_by_a_field_with_trailing_comma() --> Result<()> { +fn matches_struct_with_a_field_followed_by_a_method_ret_ref_followed_by_a_field_with_trailing_comma( +) -> Result<()> { #[derive(Debug)] struct AStruct { a_field: u32, @@ -1491,8 +1514,8 @@ fn matches_struct_with_a_field_followed_by_a_method_ret_ref_followed_by_a_field_ } #[test] -fn matches_struct_with_a_field_followed_by_a_method_with_params_ret_ref_followed_by_a_field() --> Result<()> { +fn matches_struct_with_a_field_followed_by_a_method_with_params_ret_ref_followed_by_a_field( +) -> Result<()> { #[derive(Debug)] struct AStruct { a_field: u32, @@ -1519,8 +1542,8 @@ fn matches_struct_with_a_field_followed_by_a_method_with_params_ret_ref_followed } #[test] -fn matches_struct_with_field_followed_by_method_taking_enum_value_param_ret_ref_followed_by_field() --> Result<()> { +fn matches_struct_with_field_followed_by_method_taking_enum_value_param_ret_ref_followed_by_field( +) -> Result<()> { enum AnEnum { AVariant, } @@ -1551,8 +1574,8 @@ fn matches_struct_with_field_followed_by_method_taking_enum_value_param_ret_ref_ } #[test] -fn matches_struct_with_a_field_followed_by_a_method_with_params_trailing_comma_ret_ref_followed_by_a_field() --> Result<()> { +fn matches_struct_with_a_field_followed_by_a_method_with_params_trailing_comma_ret_ref_followed_by_a_field( +) -> Result<()> { #[derive(Debug)] struct AStruct { a_field: u32,