Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
status_matchers.h
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#ifndef OR_TOOLS_BASE_STATUS_MATCHERS_H_
15#define OR_TOOLS_BASE_STATUS_MATCHERS_H_
16
17#include <memory>
18#include <ostream>
19#include <string>
20
21#include "absl/status/status.h"
22#include "absl/status/statusor.h"
23#include "absl/strings/str_cat.h"
24#include "gmock/gmock-matchers.h"
25
26namespace testing::status {
27
28inline const ::absl::Status& GetStatus(const ::absl::Status& status) {
29 return status;
30}
31
32template <typename T>
33inline const ::absl::Status& GetStatus(const ::absl::StatusOr<T>& status) {
34 return status.status();
35}
36
37namespace internal {
38
39// Monomorphic implementation of matcher IsOkAndHolds(m).
40// StatusOrType is a reference to StatusOr<T>.
41template <typename StatusOrType>
43 : public ::testing::MatcherInterface<StatusOrType> {
44 public:
45 using value_type =
46 typename std::remove_reference<StatusOrType>::type::value_type;
47
48 template <typename InnerMatcher>
49 explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher)
50 : inner_matcher_(::testing::SafeMatcherCast<const value_type&>(
51 std::forward<InnerMatcher>(inner_matcher))) {}
52
53 void DescribeTo(std::ostream* os) const override {
54 *os << "is OK and has a value that ";
55 inner_matcher_.DescribeTo(os);
56 }
57
58 void DescribeNegationTo(std::ostream* os) const override {
59 *os << "is not OK or has a value that ";
60 inner_matcher_.DescribeNegationTo(os);
61 }
62
64 StatusOrType actual_value,
65 ::testing::MatchResultListener* result_listener) const override {
66 if (!actual_value.ok()) {
67 *result_listener << "which has status " << actual_value.status();
68 return false;
69 }
70
71 ::testing::StringMatchResultListener inner_listener;
72 const bool matches =
73 inner_matcher_.MatchAndExplain(*actual_value, &inner_listener);
74 const std::string inner_explanation = inner_listener.str();
75 if (!inner_explanation.empty()) {
76 *result_listener << "which contains value "
77 << ::testing::PrintToString(*actual_value) << ", "
78 << inner_explanation;
79 }
80 return matches;
81 }
82
83 private:
84 const ::testing::Matcher<const value_type&> inner_matcher_;
85};
86
87// Implements IsOkAndHolds(m) as a polymorphic matcher.
88template <typename InnerMatcher>
90 public:
91 explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher)
92 : inner_matcher_(std::move(inner_matcher)) {}
93
94 // Converts this polymorphic matcher to a monomorphic matcher of the
95 // given type. StatusOrType can be either StatusOr<T> or a
96 // reference to StatusOr<T>.
97 template <typename StatusOrType>
98 operator ::testing::Matcher<StatusOrType>() const { // NOLINT
99 return ::testing::Matcher<StatusOrType>(
101 }
102
103 private:
104 const InnerMatcher inner_matcher_;
105};
106
107} // namespace internal
108
109// Returns a gMock matcher that matches a StatusOr<> whose status is
110// OK and whose value matches the inner matcher.
111template <typename InnerMatcher>
112internal::IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type>
113IsOkAndHolds(InnerMatcher&& inner_matcher) {
115 std::forward<InnerMatcher>(inner_matcher));
116}
117
119// Implementation of IsOk().
120namespace internal {
121
122// Monomorphic implementation of matcher IsOk() for a given type T.
123// T can be Status, StatusOr<>, or a reference to either of them.
124template <typename T>
125class MonoIsOkMatcherImpl : public ::testing::MatcherInterface<T> {
126 public:
127 void DescribeTo(std::ostream* os) const override { *os << "is OK"; }
128 void DescribeNegationTo(std::ostream* os) const override {
129 *os << "is not OK";
130 }
131 bool MatchAndExplain(T actual_value,
132 ::testing::MatchResultListener*) const override {
133 return GetStatus(actual_value).ok();
134 }
135};
136
137// Implements IsOk() as a polymorphic matcher.
138class IsOkMatcher {
139 public:
140 template <typename T>
141 operator ::testing::Matcher<T>() const { // NOLINT
142 return ::testing::Matcher<T>(new MonoIsOkMatcherImpl<T>());
143 }
144};
145} // namespace internal
146
147// Returns a gMock matcher that matches a Status or StatusOr<> which is OK.
148inline internal::IsOkMatcher IsOk() { return internal::IsOkMatcher(); }
151// Implementation of StatusIs().
152//
153// StatusIs() is a polymorphic matcher. This class is the common
154// implementation of it shared by all types T where StatusIs() can be used as
155// a Matcher<T>.
156namespace internal {
157
158class StatusIsMatcherCommonImpl {
159 public:
161 ::testing::Matcher<const absl::StatusCode> code_matcher,
162 ::testing::Matcher<const std::string&> message_matcher)
163 : code_matcher_(std::move(code_matcher)),
164 message_matcher_(std::move(message_matcher)) {}
165
166 void DescribeTo(std::ostream* os) const {
167 *os << "has a status code that ";
168 code_matcher_.DescribeTo(os);
169 *os << ", and has an error message that ";
170 message_matcher_.DescribeTo(os);
171 }
172
173 void DescribeNegationTo(std::ostream* os) const {
174 *os << "has a status code that ";
175 code_matcher_.DescribeNegationTo(os);
176 *os << ", or has an error message that ";
177 message_matcher_.DescribeNegationTo(os);
178 }
179
180 bool MatchAndExplain(const absl::Status& status,
181 ::testing::MatchResultListener* result_listener) const {
182 ::testing::StringMatchResultListener inner_listener;
183
184 inner_listener.Clear();
185 if (!code_matcher_.MatchAndExplain(status.code(), &inner_listener)) {
186 *result_listener << (inner_listener.str().empty()
187 ? "whose status code is wrong"
188 : "which has a status code " +
189 inner_listener.str());
190 return false;
191 }
192
193 if (!message_matcher_.Matches(std::string(status.message()))) {
194 *result_listener << "whose error message is wrong";
195 return false;
196 }
197
198 return true;
199 }
200
201 private:
202 const ::testing::Matcher<const absl::StatusCode> code_matcher_;
203 const ::testing::Matcher<const std::string&> message_matcher_;
204};
205
206// Monomorphic implementation of matcher StatusIs() for a given type T. T can
207// be Status, StatusOr<>, or a reference to either of them.
208template <typename T>
209class MonoStatusIsMatcherImpl : public ::testing::MatcherInterface<T> {
210 public:
212 : common_impl_(std::move(common_impl)) {}
214 void DescribeTo(std::ostream* os) const override {
215 common_impl_.DescribeTo(os);
217
218 void DescribeNegationTo(std::ostream* os) const override {
219 common_impl_.DescribeNegationTo(os);
221
222 bool MatchAndExplain(
223 T actual_value,
224 ::testing::MatchResultListener* result_listener) const override {
225 return common_impl_.MatchAndExplain(GetStatus(actual_value),
226 result_listener);
227 }
228
229 private:
230 StatusIsMatcherCommonImpl common_impl_;
231};
232
233// Implements StatusIs() as a polymorphic matcher.
234class StatusIsMatcher {
235 public:
236 StatusIsMatcher(::testing::Matcher<const absl::StatusCode> code_matcher,
237 ::testing::Matcher<const std::string&> message_matcher)
238 : common_impl_(
239 ::testing::MatcherCast<const absl::StatusCode>(code_matcher),
240 ::testing::MatcherCast<const std::string&>(message_matcher)) {}
241
242 // Converts this polymorphic matcher to a monomorphic matcher of the given
243 // type. T can be StatusOr<>, Status, or a reference to either of them.
244 template <typename T>
245 operator ::testing::Matcher<T>() const { // NOLINT
246 return ::testing::MakeMatcher(new MonoStatusIsMatcherImpl<T>(common_impl_));
247 }
248
249 private:
250 const StatusIsMatcherCommonImpl common_impl_;
251};
252} // namespace internal
253
254// Returns a matcher that matches a Status or StatusOr<> whose status code
255// matches code_matcher, and whose error message matches message_matcher.
256template <typename CodeMatcher, typename MessageMatcher>
257internal::StatusIsMatcher StatusIs(CodeMatcher code_matcher,
258 MessageMatcher message_matcher) {
259 return internal::StatusIsMatcher(std::move(code_matcher),
260 std::move(message_matcher));
261}
262
263// Returns a matcher that matches a Status or StatusOr<> whose status code
264// matches code_matcher.
265template <typename CodeMatcher>
266internal::StatusIsMatcher StatusIs(CodeMatcher code_matcher) {
267 return StatusIs(std::move(code_matcher), ::testing::_);
269
270} // namespace testing::status
271
272// Macros for testing the results of functions that return absl::Status or
273// absl::StatusOr<T> (for any type T).
274#define EXPECT_OK(expression) EXPECT_THAT(expression, ::testing::status::IsOk())
275#define ASSERT_OK(expression) ASSERT_THAT(expression, ::testing::status::IsOk())
277#define STATUS_MATCHERS_IMPL_CONCAT_INNER_(x, y) x##y
278#define STATUS_MATCHERS_IMPL_CONCAT_(x, y) \
279 STATUS_MATCHERS_IMPL_CONCAT_INNER_(x, y)
281#undef ASSERT_OK_AND_ASSIGN
282#define ASSERT_OK_AND_ASSIGN(lhs, rexpr) \
283 ASSERT_OK_AND_ASSIGN_IMPL_( \
284 STATUS_MATCHERS_IMPL_CONCAT_(_status_or_value, __COUNTER__), lhs, rexpr)
285
286#define ASSERT_OK_AND_ASSIGN_IMPL_(statusor, lhs, rexpr) \
287 auto statusor = (rexpr); \
288 ASSERT_TRUE(statusor.ok()) << statusor.status(); \
289 lhs = std::move(statusor.value())
290
291#endif // OR_TOOLS_BASE_STATUS_MATCHERS_H_
IsOkAndHoldsMatcherImpl(InnerMatcher &&inner_matcher)
typename std::remove_reference< StatusOrType >::type::value_type value_type
void DescribeNegationTo(std::ostream *os) const override
void DescribeTo(std::ostream *os) const override
bool MatchAndExplain(StatusOrType actual_value, ::testing::MatchResultListener *result_listener) const override
Implements IsOkAndHolds(m) as a polymorphic matcher.
IsOkAndHoldsMatcher(InnerMatcher inner_matcher)
void DescribeNegationTo(std::ostream *os) const override
void DescribeTo(std::ostream *os) const override
bool MatchAndExplain(T actual_value, ::testing::MatchResultListener *) const override
void DescribeNegationTo(std::ostream *os) const override
bool MatchAndExplain(T actual_value, ::testing::MatchResultListener *result_listener) const override
MonoStatusIsMatcherImpl(StatusIsMatcherCommonImpl common_impl)
void DescribeTo(std::ostream *os) const override
bool MatchAndExplain(const absl::Status &status, ::testing::MatchResultListener *result_listener) const
StatusIsMatcherCommonImpl(::testing::Matcher< const absl::StatusCode > code_matcher, ::testing::Matcher< const std::string & > message_matcher)
Implements StatusIs() as a polymorphic matcher.
StatusIsMatcher(::testing::Matcher< const absl::StatusCode > code_matcher, ::testing::Matcher< const std::string & > message_matcher)
absl::Status status
Definition g_gurobi.cc:44
STL namespace.
internal::IsOkMatcher IsOk()
Returns a gMock matcher that matches a Status or StatusOr<> which is OK.
const ::absl::Status & GetStatus(const ::absl::Status &status)
internal::StatusIsMatcher StatusIs(CodeMatcher code_matcher, MessageMatcher message_matcher)
internal::IsOkAndHoldsMatcher< typename std::decay< InnerMatcher >::type > IsOkAndHolds(InnerMatcher &&inner_matcher)