status_matchers.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // Copyright 2024 The Abseil Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef Y_ABSL_STATUS_INTERNAL_STATUS_MATCHERS_H_
  15. #define Y_ABSL_STATUS_INTERNAL_STATUS_MATCHERS_H_
  16. #include <ostream> // NOLINT
  17. #include <util/generic/string.h>
  18. #include <type_traits>
  19. #include <utility>
  20. #include "gmock/gmock.h" // gmock_for_status_matchers.h
  21. #include "y_absl/base/config.h"
  22. #include "y_absl/status/status.h"
  23. #include "y_absl/status/statusor.h"
  24. #include "y_absl/strings/string_view.h"
  25. namespace absl_testing {
  26. Y_ABSL_NAMESPACE_BEGIN
  27. namespace status_internal {
  28. inline const y_absl::Status& GetStatus(const y_absl::Status& status) {
  29. return status;
  30. }
  31. template <typename T>
  32. inline const y_absl::Status& GetStatus(const y_absl::StatusOr<T>& status) {
  33. return status.status();
  34. }
  35. ////////////////////////////////////////////////////////////
  36. // Implementation of IsOkAndHolds().
  37. // Monomorphic implementation of matcher IsOkAndHolds(m). StatusOrType is a
  38. // reference to StatusOr<T>.
  39. template <typename StatusOrType>
  40. class IsOkAndHoldsMatcherImpl
  41. : public ::testing::MatcherInterface<StatusOrType> {
  42. public:
  43. typedef
  44. typename std::remove_reference<StatusOrType>::type::value_type value_type;
  45. template <typename InnerMatcher>
  46. explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher)
  47. : inner_matcher_(::testing::SafeMatcherCast<const value_type&>(
  48. std::forward<InnerMatcher>(inner_matcher))) {}
  49. void DescribeTo(std::ostream* os) const override {
  50. *os << "is OK and has a value that ";
  51. inner_matcher_.DescribeTo(os);
  52. }
  53. void DescribeNegationTo(std::ostream* os) const override {
  54. *os << "isn't OK or has a value that ";
  55. inner_matcher_.DescribeNegationTo(os);
  56. }
  57. bool MatchAndExplain(
  58. StatusOrType actual_value,
  59. ::testing::MatchResultListener* result_listener) const override {
  60. if (!GetStatus(actual_value).ok()) {
  61. *result_listener << "which has status " << GetStatus(actual_value);
  62. return false;
  63. }
  64. // Call through to the inner matcher.
  65. return inner_matcher_.MatchAndExplain(*actual_value, result_listener);
  66. }
  67. private:
  68. const ::testing::Matcher<const value_type&> inner_matcher_;
  69. };
  70. // Implements IsOkAndHolds(m) as a polymorphic matcher.
  71. template <typename InnerMatcher>
  72. class IsOkAndHoldsMatcher {
  73. public:
  74. explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher)
  75. : inner_matcher_(std::forward<InnerMatcher>(inner_matcher)) {}
  76. // Converts this polymorphic matcher to a monomorphic matcher of the
  77. // given type. StatusOrType can be either StatusOr<T> or a
  78. // reference to StatusOr<T>.
  79. template <typename StatusOrType>
  80. operator ::testing::Matcher<StatusOrType>() const { // NOLINT
  81. return ::testing::Matcher<StatusOrType>(
  82. new IsOkAndHoldsMatcherImpl<const StatusOrType&>(inner_matcher_));
  83. }
  84. private:
  85. const InnerMatcher inner_matcher_;
  86. };
  87. ////////////////////////////////////////////////////////////
  88. // Implementation of StatusIs().
  89. // `StatusCode` is implicitly convertible from `int`, `y_absl::StatusCode`, and
  90. // is explicitly convertible to these types as well.
  91. //
  92. // We need this class because `y_absl::StatusCode` (as a scoped enum) is not
  93. // implicitly convertible to `int`. In order to handle use cases like
  94. // ```
  95. // StatusIs(Anyof(y_absl::StatusCode::kUnknown, y_absl::StatusCode::kCancelled))
  96. // ```
  97. // which uses polymorphic matchers, we need to unify the interfaces into
  98. // `Matcher<StatusCode>`.
  99. class StatusCode {
  100. public:
  101. /*implicit*/ StatusCode(int code) // NOLINT
  102. : code_(static_cast<::y_absl::StatusCode>(code)) {}
  103. /*implicit*/ StatusCode(::y_absl::StatusCode code) : code_(code) {} // NOLINT
  104. explicit operator int() const { return static_cast<int>(code_); }
  105. friend inline void PrintTo(const StatusCode& code, std::ostream* os) {
  106. // TODO(b/321095377): Change this to print the status code as a string.
  107. *os << static_cast<int>(code);
  108. }
  109. private:
  110. ::y_absl::StatusCode code_;
  111. };
  112. // Relational operators to handle matchers like Eq, Lt, etc..
  113. inline bool operator==(const StatusCode& lhs, const StatusCode& rhs) {
  114. return static_cast<int>(lhs) == static_cast<int>(rhs);
  115. }
  116. inline bool operator!=(const StatusCode& lhs, const StatusCode& rhs) {
  117. return static_cast<int>(lhs) != static_cast<int>(rhs);
  118. }
  119. // StatusIs() is a polymorphic matcher. This class is the common
  120. // implementation of it shared by all types T where StatusIs() can be
  121. // used as a Matcher<T>.
  122. class StatusIsMatcherCommonImpl {
  123. public:
  124. StatusIsMatcherCommonImpl(
  125. ::testing::Matcher<StatusCode> code_matcher,
  126. ::testing::Matcher<y_absl::string_view> message_matcher)
  127. : code_matcher_(std::move(code_matcher)),
  128. message_matcher_(std::move(message_matcher)) {}
  129. void DescribeTo(std::ostream* os) const;
  130. void DescribeNegationTo(std::ostream* os) const;
  131. bool MatchAndExplain(const y_absl::Status& status,
  132. ::testing::MatchResultListener* result_listener) const;
  133. private:
  134. const ::testing::Matcher<StatusCode> code_matcher_;
  135. const ::testing::Matcher<y_absl::string_view> message_matcher_;
  136. };
  137. // Monomorphic implementation of matcher StatusIs() for a given type
  138. // T. T can be Status, StatusOr<>, or a reference to either of them.
  139. template <typename T>
  140. class MonoStatusIsMatcherImpl : public ::testing::MatcherInterface<T> {
  141. public:
  142. explicit MonoStatusIsMatcherImpl(StatusIsMatcherCommonImpl common_impl)
  143. : common_impl_(std::move(common_impl)) {}
  144. void DescribeTo(std::ostream* os) const override {
  145. common_impl_.DescribeTo(os);
  146. }
  147. void DescribeNegationTo(std::ostream* os) const override {
  148. common_impl_.DescribeNegationTo(os);
  149. }
  150. bool MatchAndExplain(
  151. T actual_value,
  152. ::testing::MatchResultListener* result_listener) const override {
  153. return common_impl_.MatchAndExplain(GetStatus(actual_value),
  154. result_listener);
  155. }
  156. private:
  157. StatusIsMatcherCommonImpl common_impl_;
  158. };
  159. // Implements StatusIs() as a polymorphic matcher.
  160. class StatusIsMatcher {
  161. public:
  162. template <typename StatusCodeMatcher, typename StatusMessageMatcher>
  163. StatusIsMatcher(StatusCodeMatcher&& code_matcher,
  164. StatusMessageMatcher&& message_matcher)
  165. : common_impl_(::testing::MatcherCast<StatusCode>(
  166. std::forward<StatusCodeMatcher>(code_matcher)),
  167. ::testing::MatcherCast<y_absl::string_view>(
  168. std::forward<StatusMessageMatcher>(message_matcher))) {
  169. }
  170. // Converts this polymorphic matcher to a monomorphic matcher of the
  171. // given type. T can be StatusOr<>, Status, or a reference to
  172. // either of them.
  173. template <typename T>
  174. /*implicit*/ operator ::testing::Matcher<T>() const { // NOLINT
  175. return ::testing::Matcher<T>(
  176. new MonoStatusIsMatcherImpl<const T&>(common_impl_));
  177. }
  178. private:
  179. const StatusIsMatcherCommonImpl common_impl_;
  180. };
  181. // Monomorphic implementation of matcher IsOk() for a given type T.
  182. // T can be Status, StatusOr<>, or a reference to either of them.
  183. template <typename T>
  184. class MonoIsOkMatcherImpl : public ::testing::MatcherInterface<T> {
  185. public:
  186. void DescribeTo(std::ostream* os) const override { *os << "is OK"; }
  187. void DescribeNegationTo(std::ostream* os) const override {
  188. *os << "is not OK";
  189. }
  190. bool MatchAndExplain(T actual_value,
  191. ::testing::MatchResultListener*) const override {
  192. return GetStatus(actual_value).ok();
  193. }
  194. };
  195. // Implements IsOk() as a polymorphic matcher.
  196. class IsOkMatcher {
  197. public:
  198. template <typename T>
  199. /*implicit*/ operator ::testing::Matcher<T>() const { // NOLINT
  200. return ::testing::Matcher<T>(new MonoIsOkMatcherImpl<const T&>());
  201. }
  202. };
  203. } // namespace status_internal
  204. Y_ABSL_NAMESPACE_END
  205. } // namespace absl_testing
  206. #endif // Y_ABSL_STATUS_INTERNAL_STATUS_MATCHERS_H_