From e458e5255ad9aff8b4831a288c4f694f329fc7f3 Mon Sep 17 00:00:00 2001 From: Kane York Date: Sun, 9 Aug 2020 17:39:13 -0700 Subject: [PATCH] feat(tvix/tests): add gtest matchers for absl::Status This allows you to write EXPECT_OK(statusor), as well as EXPECT_THAT(status, IsStatusCode(StatusCode::kInvalidArgument). Change-Id: I53bed694d812c501eb305ed4ddb358e1f9a68277 Reviewed-on: https://cl.tvl.fyi/c/depot/+/1704 Tested-by: BuildkiteCI Reviewed-by: glittershark --- third_party/nix/src/tests/status_helpers.h | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 third_party/nix/src/tests/status_helpers.h diff --git a/third_party/nix/src/tests/status_helpers.h b/third_party/nix/src/tests/status_helpers.h new file mode 100644 index 000000000..ca596dbb5 --- /dev/null +++ b/third_party/nix/src/tests/status_helpers.h @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace testing { + +/* + * This file contains gtest matchers for absl::Status. + * + * Example usage: + * + * EXPECT_OK(status); -- fails the test if 'status' is an error + * ASSERT_OK(status); -- instantly fails the test if error + * + * using ::testing::IsStatusCode; + * EXPECT_THAT(status, IsStatusCode(absl::StatusCode::kInternal)); + */ + +namespace nix_internal { + +using ::testing::MakeMatcher; +using ::testing::Matcher; +using ::testing::MatcherInterface; +using ::testing::MatchResultListener; + +MATCHER_P(IsStatusCode, code, "") { return arg.code() == code; } + +class StatusCodeMatcher { + public: + StatusCodeMatcher(absl::StatusCode code) : code_(code) {} + + // Match on absl::Status. + template ::value, + int>::type int_ = 0> + bool MatchAndExplain(const T& status, + MatchResultListener* /* listener */) const { + return status.code() == code_; + } + + // Match on absl::StatusOr. + // + // note: I check for the return value of ConsumeValueOrDie because it's the + // only non-overloaded member I could figure out how to select. Checking for + // the presence of .status() didn't work because it's overloaded, so + // std::invoke_result can't pick which overload to use. + template ::type, + typename T::value_type>::value, + int>::type int_ = 0> + bool MatchAndExplain(const T& statusor, + MatchResultListener* /* listener */) const { + return statusor.status().code() == code_; + } + + void DescribeTo(std::ostream* os) const { *os << "is " << code_; } + + void DescribeNegationTo(std::ostream* os) const { *os << "isn't " << code_; } + + private: + absl::StatusCode code_; +}; + +} // namespace nix_internal + +PolymorphicMatcher IsStatusCode( + absl::StatusCode code) { + return MakePolymorphicMatcher(nix_internal::StatusCodeMatcher(code)); +} + +#define EXPECT_OK(status) \ + EXPECT_THAT((status), testing::IsStatusCode(absl::StatusCode::kOk)) + +#define ASSERT_OK(status) \ + ASSERT_THAT((status), testing::IsStatusCode(absl::StatusCode::kOk)) + +} // namespace testing