google / googletest

GoogleTest - Google Testing and Mocking Framework
https://google.github.io/googletest/
BSD 3-Clause "New" or "Revised" License
34.52k stars 10.09k forks source link

[FR]: Matcher for absl::StatusOr and std::expected #4468

Open neg-c opened 7 months ago

neg-c commented 7 months ago

Does the feature exist in the most recent commit?

No

Why do we need this feature?

Working on code bases that use C++23, std::expected is used extensively for error handling. Having a matcher for it would help on testing.

Describe the proposal.

Similar to VariantWith() add a matcher that uses std::expected and it supports its monadic features. Would be nice to check for compiler features.

Is the feature specific to an operating system, compiler, or build system version?

As of this writing, the big 4 compiler library features support it.

neg-c commented 7 months ago

In case it gets approved, assign it to me

Xadeck commented 7 months ago

Interestingly enough, Optional() can be used.

enum class Error { boom };

std::expected<int, Error> something = 1;
EXPECT_THAT(something, testing::Optional(testing::Gt(0)));

std::expected<int, Error> something = std::unexpected(Error::boom);
EXPECT_EQ(something, std::unexpected(Error::boom));
neg-c commented 7 months ago

Interestingly enough, Optional() can be used.

enum class Error { boom };

std::expected<int, Error> something = 1;
EXPECT_THAT(something, testing::Optional(testing::Gt(0)));

std::expected<int, Error> something = std::unexpected(Error::boom);
EXPECT_EQ(something, std::unexpected(Error::boom));

Thats weird, still believe there should be a dedicated macro

cstratopoulos commented 7 months ago

Thats weird, still believe there should be a dedicated macro

I agree, the Optional thing is a hacky workaround for now but I would want something like EXPECT_THAT(something, testing::Expected(some_val)) where DescribeNegationTo would indicate that either there was a failure (and describe the error object, if possible) or that it succeeded with an unexpected value.

For a more fluent approach, maybe there could be matchers like EXPECT_THAT(something, succeedsWith(successValMatcher)) or EXPECT_THAT(something, failsWith(errorValMatcher))

Similar to how the existing matchers for Optional and Variant are quite general (ie not bound to the std:: classes), I think it should be reasonable to write this matcher with sufficient generality to work with std::expected and other popular value-or-error types. See e.g., https://ned14.github.io/outcome/tutorial/advanced/interop/value-or-error/

We can assume

and public typedefs value_type and error_type. I don't think we need to do any ADL free function stuff like with variant.

This should work with std::expected, TartanLlama tl::expected, Boost.Outcome outcome::result, Boost.System system::result etc

derekmauro commented 7 months ago

The matcher for absl::StatusOr will be released by the abseil-cpp project. Someone is working on it now, but it will take a while.

C++23 and std::expected is not supported yet. We do not want it implemented until C++23 is officially supported.

neg-c commented 7 months ago

For a more fluent approach, maybe there could be matchers like EXPECT_THAT(something, succeedsWith(successValMatcher)) or EXPECT_THAT(something, failsWith(errorValMatcher))

I like this. It's a little bit weird cuz absl version std::expected is StatusOr, there should be matcher name that will be understood by both library users. Having it testing::Expected makes it a bit harder to read because of the EXPECTED_X macros.