xref: /aosp_15_r20/external/private-join-and-compute/private_join_and_compute/util/status_matchers.h (revision a6aa18fbfbf9cb5cd47356a9d1b057768998488c)
1 /*
2  * Copyright 2019 Google LLC.
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  */
15 
16 /*
17  * Copyright 2020 Google LLC
18  *
19  * Licensed under the Apache License, Version 2.0 (the "License");
20  * you may not use this file except in compliance with the License.
21  * You may obtain a copy of the License at
22  *
23  *      http://www.apache.org/licenses/LICENSE-2.0
24  *
25  * Unless required by applicable law or agreed to in writing, software
26  * distributed under the License is distributed on an "AS IS" BASIS,
27  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28  * See the License for the specific language governing permissions and
29  * limitations under the License.
30  */
31 
32 #ifndef PRIVATE_JOIN_AND_COMPUTE_UTIL_STATUS_MATCHERS_H_
33 #define PRIVATE_JOIN_AND_COMPUTE_UTIL_STATUS_MATCHERS_H_
34 
35 #include <gmock/gmock.h>
36 
37 #include <ostream>
38 #include <string>
39 
40 #include "private_join_and_compute/util/status.inc"
41 
42 namespace private_join_and_compute {
43 namespace testing {
44 
45 #ifdef GTEST_HAS_STATUS_MATCHERS
46 
47 using ::testing::status::IsOk;
48 using ::testing::status::IsOkAndHolds;
49 using ::testing::status::StatusIs;
50 
51 #else  // GTEST_HAS_STATUS_MATCHERS
52 
53 namespace internal {
54 
55 // This function and its overload allow the same matcher to be used for Status
56 // and StatusOr tests.
57 inline Status GetStatus(const Status& status) { return status; }
58 
59 template <typename T>
60 inline Status GetStatus(const StatusOr<T>& statusor) {
61   return statusor.status();
62 }
63 
64 template <typename StatusType>
65 class StatusIsImpl : public ::testing::MatcherInterface<StatusType> {
66  public:
67   StatusIsImpl(const ::testing::Matcher<StatusCode>& code,
68                const ::testing::Matcher<const std::string&>& message)
69       : code_(code), message_(message) {}
70 
71   bool MatchAndExplain(
72       StatusType status,
73       ::testing::MatchResultListener* listener) const override {
74     ::testing::StringMatchResultListener str_listener;
75     Status real_status = GetStatus(status);
76     if (!code_.MatchAndExplain(real_status.code(), &str_listener)) {
77       *listener << str_listener.str();
78       return false;
79     }
80     if (!message_.MatchAndExplain(
81             static_cast<std::string>(real_status.message()), &str_listener)) {
82       *listener << str_listener.str();
83       return false;
84     }
85     return true;
86   }
87 
88   void DescribeTo(std::ostream* os) const override {
89     *os << "has a status code that ";
90     code_.DescribeTo(os);
91     *os << " and a message that ";
92     message_.DescribeTo(os);
93   }
94 
95   void DescribeNegationTo(std::ostream* os) const override {
96     *os << "has a status code that ";
97     code_.DescribeNegationTo(os);
98     *os << " and a message that ";
99     message_.DescribeNegationTo(os);
100   }
101 
102  private:
103   ::testing::Matcher<StatusCode> code_;
104   ::testing::Matcher<const std::string&> message_;
105 };
106 
107 class StatusIsPoly {
108  public:
109   StatusIsPoly(::testing::Matcher<StatusCode>&& code,
110                ::testing::Matcher<const std::string&>&& message)
111       : code_(code), message_(message) {}
112 
113   // Converts this polymorphic matcher to a monomorphic matcher.
114   template <typename StatusType>
115   operator ::testing::Matcher<StatusType>() const {
116     return ::testing::Matcher<StatusType>(
117         new StatusIsImpl<StatusType>(code_, message_));
118   }
119 
120  private:
121   ::testing::Matcher<StatusCode> code_;
122   ::testing::Matcher<const std::string&> message_;
123 };
124 
125 }  // namespace internal
126 
127 // This function allows us to avoid a template parameter when writing tests, so
128 // that we can transparently test both Status and StatusOr returns.
129 inline internal::StatusIsPoly StatusIs(
130     ::testing::Matcher<StatusCode>&& code,
131     ::testing::Matcher<const std::string&>&& message) {
132   return internal::StatusIsPoly(
133       std::forward< ::testing::Matcher<StatusCode> >(code),
134       std::forward< ::testing::Matcher<const std::string&> >(message));
135 }
136 
137 // Monomorphic implementation of matcher IsOkAndHolds(m).  StatusOrType is a
138 // reference to StatusOr<T>.
139 template <typename StatusOrType>
140 class IsOkAndHoldsMatcherImpl
141     : public ::testing::MatcherInterface<StatusOrType> {
142  public:
143   typedef
144       typename std::remove_reference<StatusOrType>::type::value_type value_type;
145 
146   template <typename InnerMatcher>
147   explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher)
148       : inner_matcher_(::testing::SafeMatcherCast<const value_type&>(
149             std::forward<InnerMatcher>(inner_matcher))) {}
150 
151   void DescribeTo(std::ostream* os) const override {
152     *os << "is OK and has a value that ";
153     inner_matcher_.DescribeTo(os);
154   }
155 
156   void DescribeNegationTo(std::ostream* os) const override {
157     *os << "isn't OK or has a value that ";
158     inner_matcher_.DescribeNegationTo(os);
159   }
160 
161   bool MatchAndExplain(
162       StatusOrType actual_value,
163       ::testing::MatchResultListener* result_listener) const override {
164     if (!actual_value.ok()) {
165       *result_listener << "which has status " << actual_value.status();
166       return false;
167     }
168 
169     ::testing::StringMatchResultListener inner_listener;
170     const bool matches =
171         inner_matcher_.MatchAndExplain(*actual_value, &inner_listener);
172     const std::string inner_explanation = inner_listener.str();
173     if (!inner_explanation.empty()) {
174       *result_listener << "which contains value "
175                        << ::testing::PrintToString(*actual_value) << ", "
176                        << inner_explanation;
177     }
178     return matches;
179   }
180 
181  private:
182   const ::testing::Matcher<const value_type&> inner_matcher_;
183 };
184 
185 // Implements IsOkAndHolds(m) as a polymorphic matcher.
186 template <typename InnerMatcher>
187 class IsOkAndHoldsMatcher {
188  public:
189   explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher)
190       : inner_matcher_(std::move(inner_matcher)) {}
191 
192   // Converts this polymorphic matcher to a monomorphic matcher of the
193   // given type.  StatusOrType can be either StatusOr<T> or a
194   // reference to StatusOr<T>.
195   template <typename StatusOrType>
196   operator ::testing::Matcher<StatusOrType>() const {  // NOLINT
197     return ::testing::Matcher<StatusOrType>(
198         new IsOkAndHoldsMatcherImpl<const StatusOrType&>(inner_matcher_));
199   }
200 
201  private:
202   const InnerMatcher inner_matcher_;
203 };
204 
205 // Monomorphic implementation of matcher IsOk() for a given type T.
206 // T can be Status, StatusOr<>, or a reference to either of them.
207 template <typename T>
208 class MonoIsOkMatcherImpl : public ::testing::MatcherInterface<T> {
209  public:
210   void DescribeTo(std::ostream* os) const override { *os << "is OK"; }
211   void DescribeNegationTo(std::ostream* os) const override {
212     *os << "is not OK";
213   }
214   bool MatchAndExplain(T actual_value,
215                        ::testing::MatchResultListener*) const override {
216     return GetStatus(actual_value).ok();
217   }
218 };
219 
220 // Implements IsOk() as a polymorphic matcher.
221 class IsOkMatcher {
222  public:
223   template <typename T>
224   operator ::testing::Matcher<T>() const {  // NOLINT
225     return ::testing::Matcher<T>(new MonoIsOkMatcherImpl<T>());
226   }
227 };
228 
229 // Returns a gMock matcher that matches a StatusOr<> whose status is
230 // OK and whose value matches the inner matcher.
231 template <typename InnerMatcher>
232 IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type> IsOkAndHolds(
233     InnerMatcher&& inner_matcher) {
234   return IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type>(
235       std::forward<InnerMatcher>(inner_matcher));
236 }
237 
238 // Returns a gMock matcher that matches a Status or StatusOr<> which is OK.
239 inline IsOkMatcher IsOk() { return IsOkMatcher(); }
240 
241 #endif  // GTEST_HAS_STATUS_MATCHERS
242 
243 }  // namespace testing
244 }  // namespace private_join_and_compute
245 
246 #endif  // PRIVATE_JOIN_AND_COMPUTE_UTIL_STATUS_MATCHERS_H_
247