22#include <gmock/gmock.h>
23#include <gtest/gtest.h>
25#include "iceberg/result.h"
26#include "iceberg/util/macros.h"
67MATCHER(IsOk,
"is an Ok result") {
68 if (arg.has_value()) {
71 *result_listener <<
"which contains error: " << arg.error().message;
76MATCHER_P(IsError, kind,
"is an Error with the specified kind") {
77 if (!arg.has_value()) {
78 if (arg.error().kind == kind) {
81 *result_listener <<
"which contains error kind " <<
static_cast<int>(arg.error().kind)
82 <<
" but expected " <<
static_cast<int>(kind)
83 <<
", message: " << arg.error().message;
86 *result_listener <<
"which is not an error but a value";
92MATCHER_P(HasErrorMessage, message_substr,
93 "is an Error with message containing the substring") {
94 if (!arg.has_value()) {
95 if (arg.error().message.find(message_substr) != std::string::npos) {
98 *result_listener <<
"which contains error with message '" << arg.error().message
99 <<
"' that doesn't contain '" << message_substr <<
"'";
102 *result_listener <<
"which is not an error but a value";
108template <
typename MatcherT>
111 explicit HasValueMatcher(MatcherT matcher) : matcher_(std::move(matcher)) {}
113 template <
typename T>
114 bool MatchAndExplain(
const T& value,
115 ::testing::MatchResultListener* result_listener)
const {
116 if (!value.has_value()) {
117 *result_listener <<
"which is an error: " << value.error().message;
121 return ::testing::MatcherCast<const typename T::value_type&>(matcher_)
122 .MatchAndExplain(*value, result_listener);
125 void DescribeTo(std::ostream* os)
const {
126 *os <<
"has a value that ";
127 matcher_.DescribeTo(os);
130 void DescribeNegationTo(std::ostream* os)
const {
131 *os <<
"does not have a value that ";
132 matcher_.DescribeTo(os);
140template <
typename MatcherT>
141auto HasValue(MatcherT&& matcher) {
142 return ::testing::MakePolymorphicMatcher(
143 HasValueMatcher<std::remove_cvref_t<MatcherT>>(std::forward<MatcherT>(matcher)));
147inline auto HasValue() {
return IsOk(); }
150template <
typename MatcherT>
153 explicit ResultMatcher(
bool should_have_value, MatcherT matcher)
154 : should_have_value_(should_have_value), matcher_(std::move(matcher)) {}
156 template <
typename T>
157 bool MatchAndExplain(
const T& value,
158 ::testing::MatchResultListener* result_listener)
const {
159 if (value.has_value() != should_have_value_) {
160 if (should_have_value_) {
161 *result_listener <<
"which is an error: " << value.error().message;
163 *result_listener <<
"which is a value, not an error";
168 if (should_have_value_) {
169 return ::testing::MatcherCast<const typename T::value_type&>(matcher_)
170 .MatchAndExplain(*value, result_listener);
172 return ::testing::MatcherCast<const typename T::error_type&>(matcher_)
173 .MatchAndExplain(value.error(), result_listener);
177 void DescribeTo(std::ostream* os)
const {
178 if (should_have_value_) {
179 *os <<
"has a value that ";
181 *os <<
"has an error that ";
183 matcher_.DescribeTo(os);
186 void DescribeNegationTo(std::ostream* os)
const {
187 if (should_have_value_) {
188 *os <<
"does not have a value that ";
190 *os <<
"does not have an error that ";
192 matcher_.DescribeTo(os);
196 bool should_have_value_;
201template <
typename MatcherT>
202auto ResultIs(MatcherT&& matcher) {
203 return ::testing::MakePolymorphicMatcher(
ResultMatcher<std::remove_cvref_t<MatcherT>>(
204 true, std::forward<MatcherT>(matcher)));
208template <
typename MatcherT>
209auto ErrorIs(MatcherT&& matcher) {
210 return ::testing::MakePolymorphicMatcher(ResultMatcher<std::remove_cvref_t<MatcherT>>(
211 false, std::forward<MatcherT>(matcher)));
217#define ICEBERG_UNWRAP_OR_FAIL_IMPL(result_name, lhs, rexpr) \
218 auto&& result_name = (rexpr); \
219 ASSERT_TRUE(result_name.has_value()) \
220 << "Operation failed: " << result_name.error().message; \
221 lhs = std::move(result_name.value());
223#define ICEBERG_UNWRAP_OR_FAIL(lhs, rexpr) \
224 ICEBERG_UNWRAP_OR_FAIL_IMPL(ICEBERG_ASSIGN_OR_RAISE_NAME(result_, __COUNTER__), lhs, \
Definition matchers.h:109
Definition matchers.h:151