diff options
author | Kane York <kanepyork@gmail.com> | 2020-08-10T00·39-0700 |
---|---|---|
committer | kanepyork <rikingcoding@gmail.com> | 2020-08-15T00·52+0000 |
commit | e458e5255ad9aff8b4831a288c4f694f329fc7f3 (patch) | |
tree | 16ded8d35211571306b4e4c370e20adc5656dcb6 /third_party | |
parent | dae33202fca3b8df6315ab06ae60127a3ec7ef00 (diff) |
feat(tvix/tests): add gtest matchers for absl::Status r/1654
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 <grfn@gws.fyi>
Diffstat (limited to 'third_party')
-rw-r--r-- | third_party/nix/src/tests/status_helpers.h | 83 |
1 files changed, 83 insertions, 0 deletions
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 000000000000..ca596dbb5254 --- /dev/null +++ b/third_party/nix/src/tests/status_helpers.h @@ -0,0 +1,83 @@ +#pragma once + +#include <absl/status/status.h> +#include <absl/status/statusor.h> +#include <absl/strings/str_cat.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +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 <class T, + typename std::enable_if<std::is_same<T, absl::Status>::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 <class T, + typename std::enable_if< + std::is_same<typename std::invoke_result< + decltype(&T::ConsumeValueOrDie), T>::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<nix_internal::StatusCodeMatcher> 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 |