aboutsummaryrefslogtreecommitdiff
path: root/absl/status
diff options
context:
space:
mode:
Diffstat (limited to 'absl/status')
-rw-r--r--absl/status/BUILD.bazel36
-rw-r--r--absl/status/CMakeLists.txt38
-rw-r--r--absl/status/internal/status_matchers.cc68
-rw-r--r--absl/status/internal/status_matchers.h246
-rw-r--r--absl/status/internal/statusor_internal.h63
-rw-r--r--absl/status/status.cc4
-rw-r--r--absl/status/status.h8
-rw-r--r--absl/status/status_matchers.h118
-rw-r--r--absl/status/status_matchers_test.cc119
-rw-r--r--absl/status/status_test.cc4
-rw-r--r--absl/status/statusor.h250
-rw-r--r--absl/status/statusor_test.cc167
12 files changed, 824 insertions, 297 deletions
diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel
index 981b37fd..8822e0f6 100644
--- a/absl/status/BUILD.bazel
+++ b/absl/status/BUILD.bazel
@@ -118,6 +118,7 @@ cc_test(
srcs = ["statusor_test.cc"],
deps = [
":status",
+ ":status_matchers",
":statusor",
"//absl/base",
"//absl/memory",
@@ -129,3 +130,38 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
+
+cc_library(
+ name = "status_matchers",
+ testonly = 1,
+ srcs = [
+ "internal/status_matchers.cc",
+ "internal/status_matchers.h",
+ ],
+ hdrs = ["status_matchers.h"],
+ copts = ABSL_DEFAULT_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":status",
+ ":statusor",
+ "//absl/base:config",
+ "//absl/strings:string_view",
+ "@com_google_googletest//:gtest",
+ ],
+)
+
+cc_test(
+ name = "status_matchers_test",
+ size = "small",
+ srcs = ["status_matchers_test.cc"],
+ copts = ABSL_TEST_COPTS,
+ linkopts = ABSL_DEFAULT_LINKOPTS,
+ deps = [
+ ":status",
+ ":status_matchers",
+ ":statusor",
+ "//absl/strings",
+ "@com_google_googletest//:gtest",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt
index 00415ab9..24c01e7a 100644
--- a/absl/status/CMakeLists.txt
+++ b/absl/status/CMakeLists.txt
@@ -98,7 +98,45 @@ absl_cc_test(
${ABSL_TEST_COPTS}
DEPS
absl::status
+ absl::status_matchers
absl::statusor
absl::strings
GTest::gmock_main
)
+
+absl_cc_library(
+ NAME
+ status_matchers
+ HDRS
+ "status_matchers.h"
+ SRCS
+ "internal/status_matchers.h"
+ "internal/status_matchers.cc"
+ COPTS
+ ${ABSL_DEFAULT_COPTS}
+ LINKOPTS
+ ${ABSL_DEFAULT_LINKOPTS}
+ DEPS
+ absl::base
+ absl::status
+ absl::statusor
+ absl::strings
+ GTest::gmock
+ GTest::gtest
+ PUBLIC
+ TESTONLY
+)
+
+absl_cc_test(
+ NAME
+ status_matchers_test
+ SRCS
+ "status_matchers_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::status
+ absl::statusor
+ absl::status_matchers
+ GTest::gmock_main
+)
diff --git a/absl/status/internal/status_matchers.cc b/absl/status/internal/status_matchers.cc
new file mode 100644
index 00000000..908b70bb
--- /dev/null
+++ b/absl/status/internal/status_matchers.cc
@@ -0,0 +1,68 @@
+// Copyright 2024 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: status_matchers.cc
+// -----------------------------------------------------------------------------
+
+#include "absl/status/internal/status_matchers.h"
+
+#include <ostream>
+#include <string>
+
+#include "gmock/gmock.h" // gmock_for_status_matchers.h
+#include "absl/base/config.h"
+#include "absl/status/status.h"
+
+namespace absl_testing {
+ABSL_NAMESPACE_BEGIN
+namespace status_internal {
+
+void StatusIsMatcherCommonImpl::DescribeTo(std::ostream* os) const {
+ *os << ", has a status code that ";
+ code_matcher_.DescribeTo(os);
+ *os << ", and has an error message that ";
+ message_matcher_.DescribeTo(os);
+}
+
+void StatusIsMatcherCommonImpl::DescribeNegationTo(std::ostream* os) const {
+ *os << ", or has a status code that ";
+ code_matcher_.DescribeNegationTo(os);
+ *os << ", or has an error message that ";
+ message_matcher_.DescribeNegationTo(os);
+}
+
+bool StatusIsMatcherCommonImpl::MatchAndExplain(
+ const ::absl::Status& status,
+ ::testing::MatchResultListener* result_listener) const {
+ ::testing::StringMatchResultListener inner_listener;
+ if (!code_matcher_.MatchAndExplain(status.code(), &inner_listener)) {
+ *result_listener << (inner_listener.str().empty()
+ ? "whose status code is wrong"
+ : "which has a status code " +
+ inner_listener.str());
+ return false;
+ }
+
+ if (!message_matcher_.Matches(std::string(status.message()))) {
+ *result_listener << "whose error message is wrong";
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace status_internal
+ABSL_NAMESPACE_END
+} // namespace absl_testing
diff --git a/absl/status/internal/status_matchers.h b/absl/status/internal/status_matchers.h
new file mode 100644
index 00000000..0750622e
--- /dev/null
+++ b/absl/status/internal/status_matchers.h
@@ -0,0 +1,246 @@
+// Copyright 2024 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_STATUS_INTERNAL_STATUS_MATCHERS_H_
+#define ABSL_STATUS_INTERNAL_STATUS_MATCHERS_H_
+
+#include <ostream> // NOLINT
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "gmock/gmock.h" // gmock_for_status_matchers.h
+#include "absl/base/config.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/string_view.h"
+
+namespace absl_testing {
+ABSL_NAMESPACE_BEGIN
+namespace status_internal {
+
+inline const absl::Status& GetStatus(const absl::Status& status) {
+ return status;
+}
+
+template <typename T>
+inline const absl::Status& GetStatus(const absl::StatusOr<T>& status) {
+ return status.status();
+}
+
+////////////////////////////////////////////////////////////
+// Implementation of IsOkAndHolds().
+
+// Monomorphic implementation of matcher IsOkAndHolds(m). StatusOrType is a
+// reference to StatusOr<T>.
+template <typename StatusOrType>
+class IsOkAndHoldsMatcherImpl
+ : public ::testing::MatcherInterface<StatusOrType> {
+ public:
+ typedef
+ typename std::remove_reference<StatusOrType>::type::value_type value_type;
+
+ template <typename InnerMatcher>
+ explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher)
+ : inner_matcher_(::testing::SafeMatcherCast<const value_type&>(
+ std::forward<InnerMatcher>(inner_matcher))) {}
+
+ void DescribeTo(std::ostream* os) const override {
+ *os << "is OK and has a value that ";
+ inner_matcher_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const override {
+ *os << "isn't OK or has a value that ";
+ inner_matcher_.DescribeNegationTo(os);
+ }
+
+ bool MatchAndExplain(
+ StatusOrType actual_value,
+ ::testing::MatchResultListener* result_listener) const override {
+ if (!GetStatus(actual_value).ok()) {
+ *result_listener << "which has status " << GetStatus(actual_value);
+ return false;
+ }
+
+ // Call through to the inner matcher.
+ return inner_matcher_.MatchAndExplain(*actual_value, result_listener);
+ }
+
+ private:
+ const ::testing::Matcher<const value_type&> inner_matcher_;
+};
+
+// Implements IsOkAndHolds(m) as a polymorphic matcher.
+template <typename InnerMatcher>
+class IsOkAndHoldsMatcher {
+ public:
+ explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher)
+ : inner_matcher_(std::forward<InnerMatcher>(inner_matcher)) {}
+
+ // Converts this polymorphic matcher to a monomorphic matcher of the
+ // given type. StatusOrType can be either StatusOr<T> or a
+ // reference to StatusOr<T>.
+ template <typename StatusOrType>
+ operator ::testing::Matcher<StatusOrType>() const { // NOLINT
+ return ::testing::Matcher<StatusOrType>(
+ new IsOkAndHoldsMatcherImpl<const StatusOrType&>(inner_matcher_));
+ }
+
+ private:
+ const InnerMatcher inner_matcher_;
+};
+
+////////////////////////////////////////////////////////////
+// Implementation of StatusIs().
+
+// `StatusCode` is implicitly convertible from `int`, `absl::StatusCode`, and
+// is explicitly convertible to these types as well.
+//
+// We need this class because `absl::StatusCode` (as a scoped enum) is not
+// implicitly convertible to `int`. In order to handle use cases like
+// ```
+// StatusIs(Anyof(absl::StatusCode::kUnknown, absl::StatusCode::kCancelled))
+// ```
+// which uses polymorphic matchers, we need to unify the interfaces into
+// `Matcher<StatusCode>`.
+class StatusCode {
+ public:
+ /*implicit*/ StatusCode(int code) // NOLINT
+ : code_(static_cast<::absl::StatusCode>(code)) {}
+ /*implicit*/ StatusCode(::absl::StatusCode code) : code_(code) {} // NOLINT
+
+ explicit operator int() const { return static_cast<int>(code_); }
+
+ friend inline void PrintTo(const StatusCode& code, std::ostream* os) {
+ // TODO(b/321095377): Change this to print the status code as a string.
+ *os << static_cast<int>(code);
+ }
+
+ private:
+ ::absl::StatusCode code_;
+};
+
+// Relational operators to handle matchers like Eq, Lt, etc..
+inline bool operator==(const StatusCode& lhs, const StatusCode& rhs) {
+ return static_cast<int>(lhs) == static_cast<int>(rhs);
+}
+inline bool operator!=(const StatusCode& lhs, const StatusCode& rhs) {
+ return static_cast<int>(lhs) != static_cast<int>(rhs);
+}
+
+// StatusIs() is a polymorphic matcher. This class is the common
+// implementation of it shared by all types T where StatusIs() can be
+// used as a Matcher<T>.
+class StatusIsMatcherCommonImpl {
+ public:
+ StatusIsMatcherCommonImpl(
+ ::testing::Matcher<StatusCode> code_matcher,
+ ::testing::Matcher<absl::string_view> message_matcher)
+ : code_matcher_(std::move(code_matcher)),
+ message_matcher_(std::move(message_matcher)) {}
+
+ void DescribeTo(std::ostream* os) const;
+
+ void DescribeNegationTo(std::ostream* os) const;
+
+ bool MatchAndExplain(const absl::Status& status,
+ ::testing::MatchResultListener* result_listener) const;
+
+ private:
+ const ::testing::Matcher<StatusCode> code_matcher_;
+ const ::testing::Matcher<absl::string_view> message_matcher_;
+};
+
+// Monomorphic implementation of matcher StatusIs() for a given type
+// T. T can be Status, StatusOr<>, or a reference to either of them.
+template <typename T>
+class MonoStatusIsMatcherImpl : public ::testing::MatcherInterface<T> {
+ public:
+ explicit MonoStatusIsMatcherImpl(StatusIsMatcherCommonImpl common_impl)
+ : common_impl_(std::move(common_impl)) {}
+
+ void DescribeTo(std::ostream* os) const override {
+ common_impl_.DescribeTo(os);
+ }
+
+ void DescribeNegationTo(std::ostream* os) const override {
+ common_impl_.DescribeNegationTo(os);
+ }
+
+ bool MatchAndExplain(
+ T actual_value,
+ ::testing::MatchResultListener* result_listener) const override {
+ return common_impl_.MatchAndExplain(GetStatus(actual_value),
+ result_listener);
+ }
+
+ private:
+ StatusIsMatcherCommonImpl common_impl_;
+};
+
+// Implements StatusIs() as a polymorphic matcher.
+class StatusIsMatcher {
+ public:
+ template <typename StatusCodeMatcher, typename StatusMessageMatcher>
+ StatusIsMatcher(StatusCodeMatcher&& code_matcher,
+ StatusMessageMatcher&& message_matcher)
+ : common_impl_(::testing::MatcherCast<StatusCode>(
+ std::forward<StatusCodeMatcher>(code_matcher)),
+ ::testing::MatcherCast<absl::string_view>(
+ std::forward<StatusMessageMatcher>(message_matcher))) {
+ }
+
+ // Converts this polymorphic matcher to a monomorphic matcher of the
+ // given type. T can be StatusOr<>, Status, or a reference to
+ // either of them.
+ template <typename T>
+ /*implicit*/ operator ::testing::Matcher<T>() const { // NOLINT
+ return ::testing::Matcher<T>(
+ new MonoStatusIsMatcherImpl<const T&>(common_impl_));
+ }
+
+ private:
+ const StatusIsMatcherCommonImpl common_impl_;
+};
+
+// Monomorphic implementation of matcher IsOk() for a given type T.
+// T can be Status, StatusOr<>, or a reference to either of them.
+template <typename T>
+class MonoIsOkMatcherImpl : public ::testing::MatcherInterface<T> {
+ public:
+ void DescribeTo(std::ostream* os) const override { *os << "is OK"; }
+ void DescribeNegationTo(std::ostream* os) const override {
+ *os << "is not OK";
+ }
+ bool MatchAndExplain(T actual_value,
+ ::testing::MatchResultListener*) const override {
+ return GetStatus(actual_value).ok();
+ }
+};
+
+// Implements IsOk() as a polymorphic matcher.
+class IsOkMatcher {
+ public:
+ template <typename T>
+ /*implicit*/ operator ::testing::Matcher<T>() const { // NOLINT
+ return ::testing::Matcher<T>(new MonoIsOkMatcherImpl<const T&>());
+ }
+};
+
+} // namespace status_internal
+ABSL_NAMESPACE_END
+} // namespace absl_testing
+
+#endif // ABSL_STATUS_INTERNAL_STATUS_MATCHERS_H_
diff --git a/absl/status/internal/statusor_internal.h b/absl/status/internal/statusor_internal.h
index 5be94903..67603156 100644
--- a/absl/status/internal/statusor_internal.h
+++ b/absl/status/internal/statusor_internal.h
@@ -123,11 +123,70 @@ using IsForwardingAssignmentValid = absl::disjunction<
std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>,
IsForwardingAssignmentAmbiguous<T, U>>>>;
+template <bool Value, typename T>
+using Equality = std::conditional_t<Value, T, absl::negation<T>>;
+
+template <bool Explicit, typename T, typename U, bool Lifetimebound>
+using IsConstructionValid = absl::conjunction<
+ Equality<Lifetimebound,
+ type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
+ IsDirectInitializationValid<T, U&&>, std::is_constructible<T, U&&>,
+ Equality<!Explicit, std::is_convertible<U&&, T>>,
+ absl::disjunction<
+ std::is_same<T, absl::remove_cvref_t<U>>,
+ absl::conjunction<
+ std::conditional_t<
+ Explicit,
+ absl::negation<std::is_constructible<absl::Status, U&&>>,
+ absl::negation<std::is_convertible<U&&, absl::Status>>>,
+ absl::negation<
+ internal_statusor::HasConversionOperatorToStatusOr<T, U&&>>>>>;
+
+template <typename T, typename U, bool Lifetimebound>
+using IsAssignmentValid = absl::conjunction<
+ Equality<Lifetimebound,
+ type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
+ std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>,
+ absl::disjunction<
+ std::is_same<T, absl::remove_cvref_t<U>>,
+ absl::conjunction<
+ absl::negation<std::is_convertible<U&&, absl::Status>>,
+ absl::negation<HasConversionOperatorToStatusOr<T, U&&>>>>,
+ IsForwardingAssignmentValid<T, U&&>>;
+
+template <bool Explicit, typename T, typename U>
+using IsConstructionFromStatusValid = absl::conjunction<
+ absl::negation<std::is_same<absl::StatusOr<T>, absl::remove_cvref_t<U>>>,
+ absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>,
+ absl::negation<std::is_same<absl::in_place_t, absl::remove_cvref_t<U>>>,
+ Equality<!Explicit, std::is_convertible<U, absl::Status>>,
+ std::is_constructible<absl::Status, U>,
+ absl::negation<HasConversionOperatorToStatusOr<T, U>>>;
+
+template <bool Explicit, typename T, typename U, bool Lifetimebound,
+ typename UQ>
+using IsConstructionFromStatusOrValid = absl::conjunction<
+ absl::negation<std::is_same<T, U>>,
+ Equality<Lifetimebound,
+ type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
+ std::is_constructible<T, UQ>,
+ Equality<!Explicit, std::is_convertible<UQ, T>>,
+ absl::negation<IsConstructibleOrConvertibleFromStatusOr<T, U>>>;
+
+template <typename T, typename U, bool Lifetimebound>
+using IsStatusOrAssignmentValid = absl::conjunction<
+ absl::negation<std::is_same<T, absl::remove_cvref_t<U>>>,
+ Equality<Lifetimebound,
+ type_traits_internal::IsLifetimeBoundAssignment<T, U>>,
+ std::is_constructible<T, U>, std::is_assignable<T, U>,
+ absl::negation<IsConstructibleOrConvertibleOrAssignableFromStatusOr<
+ T, absl::remove_cvref_t<U>>>>;
+
class Helper {
public:
// Move type-agnostic error handling to the .cc.
static void HandleInvalidStatusCtorArg(absl::Nonnull<Status*>);
- ABSL_ATTRIBUTE_NORETURN static void Crash(const absl::Status& status);
+ [[noreturn]] static void Crash(const absl::Status& status);
};
// Construct an instance of T in `p` through placement new, passing Args... to
@@ -379,7 +438,7 @@ struct MoveAssignBase<T, false> {
MoveAssignBase& operator=(MoveAssignBase&&) = delete;
};
-ABSL_ATTRIBUTE_NORETURN void ThrowBadStatusOrAccess(absl::Status status);
+[[noreturn]] void ThrowBadStatusOrAccess(absl::Status status);
// Used to introduce jitter into the output of printing functions for
// `StatusOr` (i.e. `AbslStringify` and `operator<<`).
diff --git a/absl/status/status.cc b/absl/status/status.cc
index 4dd5ae06..745ab889 100644
--- a/absl/status/status.cc
+++ b/absl/status/status.cc
@@ -273,14 +273,12 @@ StatusCode ErrnoToStatusCode(int error_number) {
case EFAULT: // Bad address
case EILSEQ: // Illegal byte sequence
case ENOPROTOOPT: // Protocol not available
- case ENOSTR: // Not a STREAM
case ENOTSOCK: // Not a socket
case ENOTTY: // Inappropriate I/O control operation
case EPROTOTYPE: // Protocol wrong type for socket
case ESPIPE: // Invalid seek
return StatusCode::kInvalidArgument;
case ETIMEDOUT: // Connection timed out
- case ETIME: // Timer expired
return StatusCode::kDeadlineExceeded;
case ENODEV: // No such device
case ENOENT: // No such file or directory
@@ -339,9 +337,7 @@ StatusCode ErrnoToStatusCode(int error_number) {
case EMLINK: // Too many links
case ENFILE: // Too many open files in system
case ENOBUFS: // No buffer space available
- case ENODATA: // No message is available on the STREAM read queue
case ENOMEM: // Not enough space
- case ENOSR: // No STREAM resources
#ifdef EUSERS
case EUSERS: // Too many users
#endif
diff --git a/absl/status/status.h b/absl/status/status.h
index 9ce16db9..6cfe49f2 100644
--- a/absl/status/status.h
+++ b/absl/status/status.h
@@ -452,7 +452,7 @@ class ABSL_ATTRIBUTE_TRIVIAL_ABI Status final {
// The moved-from state is valid but unspecified.
Status(Status&&) noexcept;
- Status& operator=(Status&&);
+ Status& operator=(Status&&) noexcept;
~Status();
@@ -539,7 +539,7 @@ class ABSL_ATTRIBUTE_TRIVIAL_ABI Status final {
// swap()
//
// Swap the contents of one status with another.
- friend void swap(Status& a, Status& b);
+ friend void swap(Status& a, Status& b) noexcept;
//----------------------------------------------------------------------------
// Payload Management APIs
@@ -789,7 +789,7 @@ inline Status::Status(Status&& x) noexcept : Status(x.rep_) {
x.rep_ = MovedFromRep();
}
-inline Status& Status::operator=(Status&& x) {
+inline Status& Status::operator=(Status&& x) noexcept {
uintptr_t old_rep = rep_;
if (x.rep_ != old_rep) {
rep_ = x.rep_;
@@ -852,7 +852,7 @@ inline void Status::IgnoreError() const {
// no-op
}
-inline void swap(absl::Status& a, absl::Status& b) {
+inline void swap(absl::Status& a, absl::Status& b) noexcept {
using std::swap;
swap(a.rep_, b.rep_);
}
diff --git a/absl/status/status_matchers.h b/absl/status/status_matchers.h
new file mode 100644
index 00000000..837660eb
--- /dev/null
+++ b/absl/status/status_matchers.h
@@ -0,0 +1,118 @@
+// Copyright 2024 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: status_matchers.h
+// -----------------------------------------------------------------------------
+//
+// Testing utilities for working with `absl::Status` and `absl::StatusOr`.
+//
+// Defines the following utilities:
+//
+// ===============
+// `IsOkAndHolds(m)`
+// ===============
+//
+// This gMock matcher matches a StatusOr<T> value whose status is OK
+// and whose inner value matches matcher m. Example:
+//
+// ```
+// using ::testing::MatchesRegex;
+// using ::absl_testing::IsOkAndHolds;
+// ...
+// absl::StatusOr<string> maybe_name = ...;
+// EXPECT_THAT(maybe_name, IsOkAndHolds(MatchesRegex("John .*")));
+// ```
+//
+// ===============================
+// `StatusIs(status_code_matcher)`
+// ===============================
+//
+// This is a shorthand for
+// `StatusIs(status_code_matcher, ::testing::_)`
+// In other words, it's like the two-argument `StatusIs()`, except that it
+// ignores error message.
+//
+// ===============
+// `IsOk()`
+// ===============
+//
+// Matches an `absl::Status` or `absl::StatusOr<T>` value whose status value
+// is `absl::StatusCode::kOk.`
+//
+// Equivalent to 'StatusIs(absl::StatusCode::kOk)'.
+// Example:
+// ```
+// using ::absl_testing::IsOk;
+// ...
+// absl::StatusOr<string> maybe_name = ...;
+// EXPECT_THAT(maybe_name, IsOk());
+// Status s = ...;
+// EXPECT_THAT(s, IsOk());
+// ```
+
+#ifndef ABSL_STATUS_STATUS_MATCHERS_H_
+#define ABSL_STATUS_STATUS_MATCHERS_H_
+
+#include <ostream> // NOLINT
+#include <type_traits>
+#include <utility>
+
+#include "gmock/gmock.h" // gmock_for_status_matchers.h
+#include "absl/base/config.h"
+#include "absl/status/internal/status_matchers.h"
+
+namespace absl_testing {
+ABSL_NAMESPACE_BEGIN
+
+// Returns a gMock matcher that matches a StatusOr<> whose status is
+// OK and whose value matches the inner matcher.
+template <typename InnerMatcherT>
+status_internal::IsOkAndHoldsMatcher<typename std::decay<InnerMatcherT>::type>
+IsOkAndHolds(InnerMatcherT&& inner_matcher) {
+ return status_internal::IsOkAndHoldsMatcher<
+ typename std::decay<InnerMatcherT>::type>(
+ std::forward<InnerMatcherT>(inner_matcher));
+}
+
+// Returns a gMock matcher that matches a Status or StatusOr<> whose status code
+// matches code_matcher and whose error message matches message_matcher.
+// Typically, code_matcher will be an absl::StatusCode, e.g.
+//
+// StatusIs(absl::StatusCode::kInvalidArgument, "...")
+template <typename StatusCodeMatcherT, typename StatusMessageMatcherT>
+status_internal::StatusIsMatcher StatusIs(
+ StatusCodeMatcherT&& code_matcher,
+ StatusMessageMatcherT&& message_matcher) {
+ return status_internal::StatusIsMatcher(
+ std::forward<StatusCodeMatcherT>(code_matcher),
+ std::forward<StatusMessageMatcherT>(message_matcher));
+}
+
+// Returns a gMock matcher that matches a Status or StatusOr<> and whose status
+// code matches code_matcher. See above for details.
+template <typename StatusCodeMatcherT>
+status_internal::StatusIsMatcher StatusIs(StatusCodeMatcherT&& code_matcher) {
+ return StatusIs(std::forward<StatusCodeMatcherT>(code_matcher), ::testing::_);
+}
+
+// Returns a gMock matcher that matches a Status or StatusOr<> which is OK.
+inline status_internal::IsOkMatcher IsOk() {
+ return status_internal::IsOkMatcher();
+}
+
+ABSL_NAMESPACE_END
+} // namespace absl_testing
+
+#endif // ABSL_STATUS_STATUS_MATCHERS_H_
diff --git a/absl/status/status_matchers_test.cc b/absl/status/status_matchers_test.cc
new file mode 100644
index 00000000..3af03053
--- /dev/null
+++ b/absl/status/status_matchers_test.cc
@@ -0,0 +1,119 @@
+// Copyright 2024 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// File: status_matchers_test.cc
+// -----------------------------------------------------------------------------
+#include "absl/status/status_matchers.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/string_view.h"
+
+namespace {
+
+using ::absl_testing::IsOk;
+using ::absl_testing::IsOkAndHolds;
+using ::absl_testing::StatusIs;
+using ::testing::Gt;
+
+TEST(StatusMatcherTest, StatusIsOk) { EXPECT_THAT(absl::OkStatus(), IsOk()); }
+
+TEST(StatusMatcherTest, StatusOrIsOk) {
+ absl::StatusOr<int> ok_int = {0};
+ EXPECT_THAT(ok_int, IsOk());
+}
+
+TEST(StatusMatcherTest, StatusIsNotOk) {
+ absl::Status error = absl::UnknownError("Smigla");
+ EXPECT_NONFATAL_FAILURE(EXPECT_THAT(error, IsOk()), "Smigla");
+}
+
+TEST(StatusMatcherTest, StatusOrIsNotOk) {
+ absl::StatusOr<int> error = absl::UnknownError("Smigla");
+ EXPECT_NONFATAL_FAILURE(EXPECT_THAT(error, IsOk()), "Smigla");
+}
+
+TEST(StatusMatcherTest, IsOkAndHolds) {
+ absl::StatusOr<int> ok_int = {4};
+ absl::StatusOr<absl::string_view> ok_str = {"text"};
+ EXPECT_THAT(ok_int, IsOkAndHolds(4));
+ EXPECT_THAT(ok_int, IsOkAndHolds(Gt(0)));
+ EXPECT_THAT(ok_str, IsOkAndHolds("text"));
+}
+
+TEST(StatusMatcherTest, IsOkAndHoldsFailure) {
+ absl::StatusOr<int> ok_int = {502};
+ absl::StatusOr<int> error = absl::UnknownError("Smigla");
+ absl::StatusOr<absl::string_view> ok_str = {"actual"};
+ EXPECT_NONFATAL_FAILURE(EXPECT_THAT(ok_int, IsOkAndHolds(0)), "502");
+ EXPECT_NONFATAL_FAILURE(EXPECT_THAT(error, IsOkAndHolds(0)), "Smigla");
+ EXPECT_NONFATAL_FAILURE(EXPECT_THAT(ok_str, IsOkAndHolds("expected")),
+ "actual");
+}
+
+TEST(StatusMatcherTest, StatusIs) {
+ absl::Status unknown = absl::UnknownError("unbekannt");
+ absl::Status invalid = absl::InvalidArgumentError("ungueltig");
+ EXPECT_THAT(absl::OkStatus(), StatusIs(absl::StatusCode::kOk));
+ EXPECT_THAT(absl::OkStatus(), StatusIs(0));
+ EXPECT_THAT(unknown, StatusIs(absl::StatusCode::kUnknown));
+ EXPECT_THAT(unknown, StatusIs(2));
+ EXPECT_THAT(unknown, StatusIs(absl::StatusCode::kUnknown, "unbekannt"));
+ EXPECT_THAT(invalid, StatusIs(absl::StatusCode::kInvalidArgument));
+ EXPECT_THAT(invalid, StatusIs(3));
+ EXPECT_THAT(invalid,
+ StatusIs(absl::StatusCode::kInvalidArgument, "ungueltig"));
+}
+
+TEST(StatusMatcherTest, StatusOrIs) {
+ absl::StatusOr<int> ok = {42};
+ absl::StatusOr<int> unknown = absl::UnknownError("unbekannt");
+ absl::StatusOr<absl::string_view> invalid =
+ absl::InvalidArgumentError("ungueltig");
+ EXPECT_THAT(ok, StatusIs(absl::StatusCode::kOk));
+ EXPECT_THAT(ok, StatusIs(0));
+ EXPECT_THAT(unknown, StatusIs(absl::StatusCode::kUnknown));
+ EXPECT_THAT(unknown, StatusIs(2));
+ EXPECT_THAT(unknown, StatusIs(absl::StatusCode::kUnknown, "unbekannt"));
+ EXPECT_THAT(invalid, StatusIs(absl::StatusCode::kInvalidArgument));
+ EXPECT_THAT(invalid, StatusIs(3));
+ EXPECT_THAT(invalid,
+ StatusIs(absl::StatusCode::kInvalidArgument, "ungueltig"));
+}
+
+TEST(StatusMatcherTest, StatusIsFailure) {
+ absl::Status unknown = absl::UnknownError("unbekannt");
+ absl::Status invalid = absl::InvalidArgumentError("ungueltig");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT(absl::OkStatus(),
+ StatusIs(absl::StatusCode::kInvalidArgument)),
+ "OK");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT(unknown, StatusIs(absl::StatusCode::kCancelled)), "UNKNOWN");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT(unknown, StatusIs(absl::StatusCode::kUnknown, "inconnu")),
+ "unbekannt");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT(invalid, StatusIs(absl::StatusCode::kOutOfRange)), "INVALID");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THAT(invalid,
+ StatusIs(absl::StatusCode::kInvalidArgument, "invalide")),
+ "ungueltig");
+}
+
+} // namespace
diff --git a/absl/status/status_test.cc b/absl/status/status_test.cc
index 585e7807..c3327ad7 100644
--- a/absl/status/status_test.cc
+++ b/absl/status/status_test.cc
@@ -497,8 +497,8 @@ TEST(Status, MoveAssignment) {
{
absl::Status status(absl::StatusCode::kInvalidArgument, "message");
absl::Status copy(status);
- status = static_cast<absl::Status&&>(status);
- EXPECT_EQ(status, copy);
+ assignee = static_cast<absl::Status&&>(status);
+ EXPECT_EQ(assignee, copy);
}
}
diff --git a/absl/status/statusor.h b/absl/status/statusor.h
index cd35e5b4..b1da45e6 100644
--- a/absl/status/statusor.h
+++ b/absl/status/statusor.h
@@ -236,57 +236,55 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
// is explicit if and only if the corresponding construction of `T` from `U`
// is explicit. (This constructor inherits its explicitness from the
// underlying constructor.)
- template <
- typename U,
- absl::enable_if_t<
- absl::conjunction<
- absl::negation<std::is_same<T, U>>,
- std::is_constructible<T, const U&>,
- std::is_convertible<const U&, T>,
- absl::negation<
- internal_statusor::IsConstructibleOrConvertibleFromStatusOr<
- T, U>>>::value,
- int> = 0>
+ template <typename U, absl::enable_if_t<
+ internal_statusor::IsConstructionFromStatusOrValid<
+ false, T, U, false, const U&>::value,
+ int> = 0>
StatusOr(const StatusOr<U>& other) // NOLINT
: Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
- template <
- typename U,
- absl::enable_if_t<
- absl::conjunction<
- absl::negation<std::is_same<T, U>>,
- std::is_constructible<T, const U&>,
- absl::negation<std::is_convertible<const U&, T>>,
- absl::negation<
- internal_statusor::IsConstructibleOrConvertibleFromStatusOr<
- T, U>>>::value,
- int> = 0>
+ template <typename U, absl::enable_if_t<
+ internal_statusor::IsConstructionFromStatusOrValid<
+ false, T, U, true, const U&>::value,
+ int> = 0>
+ StatusOr(const StatusOr<U>& other ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT
+ : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
+ template <typename U, absl::enable_if_t<
+ internal_statusor::IsConstructionFromStatusOrValid<
+ true, T, U, false, const U&>::value,
+ int> = 0>
explicit StatusOr(const StatusOr<U>& other)
: Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
+ template <typename U, absl::enable_if_t<
+ internal_statusor::IsConstructionFromStatusOrValid<
+ true, T, U, true, const U&>::value,
+ int> = 0>
+ explicit StatusOr(const StatusOr<U>& other ABSL_ATTRIBUTE_LIFETIME_BOUND)
+ : Base(static_cast<const typename StatusOr<U>::Base&>(other)) {}
- template <
- typename U,
- absl::enable_if_t<
- absl::conjunction<
- absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
- std::is_convertible<U&&, T>,
- absl::negation<
- internal_statusor::IsConstructibleOrConvertibleFromStatusOr<
- T, U>>>::value,
- int> = 0>
+ template <typename U, absl::enable_if_t<
+ internal_statusor::IsConstructionFromStatusOrValid<
+ false, T, U, false, U&&>::value,
+ int> = 0>
StatusOr(StatusOr<U>&& other) // NOLINT
: Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
- template <
- typename U,
- absl::enable_if_t<
- absl::conjunction<
- absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
- absl::negation<std::is_convertible<U&&, T>>,
- absl::negation<
- internal_statusor::IsConstructibleOrConvertibleFromStatusOr<
- T, U>>>::value,
- int> = 0>
+ template <typename U, absl::enable_if_t<
+ internal_statusor::IsConstructionFromStatusOrValid<
+ false, T, U, true, U&&>::value,
+ int> = 0>
+ StatusOr(StatusOr<U>&& other ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT
+ : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
+ template <typename U, absl::enable_if_t<
+ internal_statusor::IsConstructionFromStatusOrValid<
+ true, T, U, false, U&&>::value,
+ int> = 0>
explicit StatusOr(StatusOr<U>&& other)
: Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
+ template <typename U, absl::enable_if_t<
+ internal_statusor::IsConstructionFromStatusOrValid<
+ true, T, U, true, U&&>::value,
+ int> = 0>
+ explicit StatusOr(StatusOr<U>&& other ABSL_ATTRIBUTE_LIFETIME_BOUND)
+ : Base(static_cast<typename StatusOr<U>::Base&&>(other)) {}
// Converting Assignment Operators
@@ -307,37 +305,38 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
// These overloads only apply if `absl::StatusOr<T>` is constructible and
// assignable from `absl::StatusOr<U>` and `StatusOr<T>` cannot be directly
// assigned from `StatusOr<U>`.
- template <
- typename U,
- absl::enable_if_t<
- absl::conjunction<
- absl::negation<std::is_same<T, U>>,
- std::is_constructible<T, const U&>,
- std::is_assignable<T, const U&>,
- absl::negation<
- internal_statusor::
- IsConstructibleOrConvertibleOrAssignableFromStatusOr<
- T, U>>>::value,
- int> = 0>
+ template <typename U,
+ absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid<
+ T, const U&, false>::value,
+ int> = 0>
StatusOr& operator=(const StatusOr<U>& other) {
this->Assign(other);
return *this;
}
- template <
- typename U,
- absl::enable_if_t<
- absl::conjunction<
- absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
- std::is_assignable<T, U&&>,
- absl::negation<
- internal_statusor::
- IsConstructibleOrConvertibleOrAssignableFromStatusOr<
- T, U>>>::value,
- int> = 0>
+ template <typename U,
+ absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid<
+ T, const U&, true>::value,
+ int> = 0>
+ StatusOr& operator=(const StatusOr<U>& other ABSL_ATTRIBUTE_LIFETIME_BOUND) {
+ this->Assign(other);
+ return *this;
+ }
+ template <typename U,
+ absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid<
+ T, U&&, false>::value,
+ int> = 0>
StatusOr& operator=(StatusOr<U>&& other) {
this->Assign(std::move(other));
return *this;
}
+ template <typename U,
+ absl::enable_if_t<internal_statusor::IsStatusOrAssignmentValid<
+ T, U&&, true>::value,
+ int> = 0>
+ StatusOr& operator=(StatusOr<U>&& other ABSL_ATTRIBUTE_LIFETIME_BOUND) {
+ this->Assign(std::move(other));
+ return *this;
+ }
// Constructs a new `absl::StatusOr<T>` with a non-ok status. After calling
// this constructor, `this->ok()` will be `false` and calls to `value()` will
@@ -350,46 +349,21 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
// REQUIRES: !Status(std::forward<U>(v)).ok(). This requirement is DCHECKed.
// In optimized builds, passing absl::OkStatus() here will have the effect
// of passing absl::StatusCode::kInternal as a fallback.
- template <
- typename U = absl::Status,
- absl::enable_if_t<
- absl::conjunction<
- std::is_convertible<U&&, absl::Status>,
- std::is_constructible<absl::Status, U&&>,
- absl::negation<std::is_same<absl::decay_t<U>, absl::StatusOr<T>>>,
- absl::negation<std::is_same<absl::decay_t<U>, T>>,
- absl::negation<std::is_same<absl::decay_t<U>, absl::in_place_t>>,
- absl::negation<internal_statusor::HasConversionOperatorToStatusOr<
- T, U&&>>>::value,
- int> = 0>
+ template <typename U = absl::Status,
+ absl::enable_if_t<internal_statusor::IsConstructionFromStatusValid<
+ false, T, U>::value,
+ int> = 0>
StatusOr(U&& v) : Base(std::forward<U>(v)) {}
- template <
- typename U = absl::Status,
- absl::enable_if_t<
- absl::conjunction<
- absl::negation<std::is_convertible<U&&, absl::Status>>,
- std::is_constructible<absl::Status, U&&>,
- absl::negation<std::is_same<absl::decay_t<U>, absl::StatusOr<T>>>,
- absl::negation<std::is_same<absl::decay_t<U>, T>>,
- absl::negation<std::is_same<absl::decay_t<U>, absl::in_place_t>>,
- absl::negation<internal_statusor::HasConversionOperatorToStatusOr<
- T, U&&>>>::value,
- int> = 0>
+ template <typename U = absl::Status,
+ absl::enable_if_t<internal_statusor::IsConstructionFromStatusValid<
+ true, T, U>::value,
+ int> = 0>
explicit StatusOr(U&& v) : Base(std::forward<U>(v)) {}
-
- template <
- typename U = absl::Status,
- absl::enable_if_t<
- absl::conjunction<
- std::is_convertible<U&&, absl::Status>,
- std::is_constructible<absl::Status, U&&>,
- absl::negation<std::is_same<absl::decay_t<U>, absl::StatusOr<T>>>,
- absl::negation<std::is_same<absl::decay_t<U>, T>>,
- absl::negation<std::is_same<absl::decay_t<U>, absl::in_place_t>>,
- absl::negation<internal_statusor::HasConversionOperatorToStatusOr<
- T, U&&>>>::value,
- int> = 0>
+ template <typename U = absl::Status,
+ absl::enable_if_t<internal_statusor::IsConstructionFromStatusValid<
+ false, T, U>::value,
+ int> = 0>
StatusOr& operator=(U&& v) {
this->AssignStatus(std::forward<U>(v));
return *this;
@@ -411,21 +385,22 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
// StatusOr<bool> s1 = true; // s1.ok() && *s1 == true
// StatusOr<bool> s2 = false; // s2.ok() && *s2 == false
// s1 = s2; // ambiguous, `s1 = *s2` or `s1 = bool(s2)`?
- template <
- typename U = T,
- typename = typename std::enable_if<absl::conjunction<
- std::is_constructible<T, U&&>, std::is_assignable<T&, U&&>,
- absl::disjunction<
- std::is_same<absl::remove_cvref_t<U>, T>,
- absl::conjunction<
- absl::negation<std::is_convertible<U&&, absl::Status>>,
- absl::negation<internal_statusor::
- HasConversionOperatorToStatusOr<T, U&&>>>>,
- internal_statusor::IsForwardingAssignmentValid<T, U&&>>::value>::type>
+ template <typename U = T,
+ typename std::enable_if<
+ internal_statusor::IsAssignmentValid<T, U, false>::value,
+ int>::type = 0>
StatusOr& operator=(U&& v) {
this->Assign(std::forward<U>(v));
return *this;
}
+ template <typename U = T,
+ typename std::enable_if<
+ internal_statusor::IsAssignmentValid<T, U, true>::value,
+ int>::type = 0>
+ StatusOr& operator=(U&& v ABSL_ATTRIBUTE_LIFETIME_BOUND) {
+ this->Assign(std::forward<U>(v));
+ return *this;
+ }
// Constructs the inner value `T` in-place using the provided args, using the
// `T(args...)` constructor.
@@ -442,40 +417,31 @@ class StatusOr : private internal_statusor::StatusOrData<T>,
// This constructor is explicit if `U` is not convertible to `T`. To avoid
// ambiguity, this constructor is disabled if `U` is a `StatusOr<J>`, where
// `J` is convertible to `T`.
- template <
- typename U = T,
- absl::enable_if_t<
- absl::conjunction<
- internal_statusor::IsDirectInitializationValid<T, U&&>,
- std::is_constructible<T, U&&>, std::is_convertible<U&&, T>,
- absl::disjunction<
- std::is_same<absl::remove_cvref_t<U>, T>,
- absl::conjunction<
- absl::negation<std::is_convertible<U&&, absl::Status>>,
- absl::negation<
- internal_statusor::HasConversionOperatorToStatusOr<
- T, U&&>>>>>::value,
- int> = 0>
+ template <typename U = T,
+ absl::enable_if_t<internal_statusor::IsConstructionValid<
+ false, T, U, false>::value,
+ int> = 0>
StatusOr(U&& u) // NOLINT
: StatusOr(absl::in_place, std::forward<U>(u)) {}
+ template <typename U = T,
+ absl::enable_if_t<internal_statusor::IsConstructionValid<
+ false, T, U, true>::value,
+ int> = 0>
+ StatusOr(U&& u ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT
+ : StatusOr(absl::in_place, std::forward<U>(u)) {}
- template <
- typename U = T,
- absl::enable_if_t<
- absl::conjunction<
- internal_statusor::IsDirectInitializationValid<T, U&&>,
- absl::disjunction<
- std::is_same<absl::remove_cvref_t<U>, T>,
- absl::conjunction<
- absl::negation<std::is_constructible<absl::Status, U&&>>,
- absl::negation<
- internal_statusor::HasConversionOperatorToStatusOr<
- T, U&&>>>>,
- std::is_constructible<T, U&&>,
- absl::negation<std::is_convertible<U&&, T>>>::value,
- int> = 0>
+ template <typename U = T,
+ absl::enable_if_t<internal_statusor::IsConstructionValid<
+ true, T, U, false>::value,
+ int> = 0>
explicit StatusOr(U&& u) // NOLINT
: StatusOr(absl::in_place, std::forward<U>(u)) {}
+ template <typename U = T,
+ absl::enable_if_t<
+ internal_statusor::IsConstructionValid<true, T, U, true>::value,
+ int> = 0>
+ explicit StatusOr(U&& u ABSL_ATTRIBUTE_LIFETIME_BOUND) // NOLINT
+ : StatusOr(absl::in_place, std::forward<U>(u)) {}
// StatusOr<T>::ok()
//
diff --git a/absl/status/statusor_test.cc b/absl/status/statusor_test.cc
index 09ffc658..83410404 100644
--- a/absl/status/statusor_test.cc
+++ b/absl/status/statusor_test.cc
@@ -31,6 +31,7 @@
#include "absl/base/casts.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
+#include "absl/status/status_matchers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/types/any.h"
@@ -39,6 +40,8 @@
namespace {
+using ::absl_testing::IsOk;
+using ::absl_testing::IsOkAndHolds;
using ::testing::AllOf;
using ::testing::AnyOf;
using ::testing::AnyWith;
@@ -52,128 +55,6 @@ using ::testing::Pointee;
using ::testing::StartsWith;
using ::testing::VariantWith;
-#ifdef GTEST_HAS_STATUS_MATCHERS
-using ::testing::status::IsOk;
-using ::testing::status::IsOkAndHolds;
-#else // GTEST_HAS_STATUS_MATCHERS
-inline const ::absl::Status& GetStatus(const ::absl::Status& status) {
- return status;
-}
-
-template <typename T>
-inline const ::absl::Status& GetStatus(const ::absl::StatusOr<T>& status) {
- return status.status();
-}
-
-// Monomorphic implementation of matcher IsOkAndHolds(m). StatusOrType is a
-// reference to StatusOr<T>.
-template <typename StatusOrType>
-class IsOkAndHoldsMatcherImpl
- : public ::testing::MatcherInterface<StatusOrType> {
- public:
- typedef
- typename std::remove_reference<StatusOrType>::type::value_type value_type;
-
- template <typename InnerMatcher>
- explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher)
- : inner_matcher_(::testing::SafeMatcherCast<const value_type&>(
- std::forward<InnerMatcher>(inner_matcher))) {}
-
- void DescribeTo(std::ostream* os) const override {
- *os << "is OK and has a value that ";
- inner_matcher_.DescribeTo(os);
- }
-
- void DescribeNegationTo(std::ostream* os) const override {
- *os << "isn't OK or has a value that ";
- inner_matcher_.DescribeNegationTo(os);
- }
-
- bool MatchAndExplain(
- StatusOrType actual_value,
- ::testing::MatchResultListener* result_listener) const override {
- if (!actual_value.ok()) {
- *result_listener << "which has status " << actual_value.status();
- return false;
- }
-
- ::testing::StringMatchResultListener inner_listener;
- const bool matches =
- inner_matcher_.MatchAndExplain(*actual_value, &inner_listener);
- const std::string inner_explanation = inner_listener.str();
- if (!inner_explanation.empty()) {
- *result_listener << "which contains value "
- << ::testing::PrintToString(*actual_value) << ", "
- << inner_explanation;
- }
- return matches;
- }
-
- private:
- const ::testing::Matcher<const value_type&> inner_matcher_;
-};
-
-// Implements IsOkAndHolds(m) as a polymorphic matcher.
-template <typename InnerMatcher>
-class IsOkAndHoldsMatcher {
- public:
- explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher)
- : inner_matcher_(std::move(inner_matcher)) {}
-
- // Converts this polymorphic matcher to a monomorphic matcher of the
- // given type. StatusOrType can be either StatusOr<T> or a
- // reference to StatusOr<T>.
- template <typename StatusOrType>
- operator ::testing::Matcher<StatusOrType>() const { // NOLINT
- return ::testing::Matcher<StatusOrType>(
- new IsOkAndHoldsMatcherImpl<const StatusOrType&>(inner_matcher_));
- }
-
- private:
- const InnerMatcher inner_matcher_;
-};
-
-// Monomorphic implementation of matcher IsOk() for a given type T.
-// T can be Status, StatusOr<>, or a reference to either of them.
-template <typename T>
-class MonoIsOkMatcherImpl : public ::testing::MatcherInterface<T> {
- public:
- void DescribeTo(std::ostream* os) const override { *os << "is OK"; }
- void DescribeNegationTo(std::ostream* os) const override {
- *os << "is not OK";
- }
- bool MatchAndExplain(T actual_value,
- ::testing::MatchResultListener*) const override {
- return GetStatus(actual_value).ok();
- }
-};
-
-// Implements IsOk() as a polymorphic matcher.
-class IsOkMatcher {
- public:
- template <typename T>
- operator ::testing::Matcher<T>() const { // NOLINT
- return ::testing::Matcher<T>(new MonoIsOkMatcherImpl<T>());
- }
-};
-
-// Macros for testing the results of functions that return absl::Status or
-// absl::StatusOr<T> (for any type T).
-#define EXPECT_OK(expression) EXPECT_THAT(expression, IsOk())
-
-// Returns a gMock matcher that matches a StatusOr<> whose status is
-// OK and whose value matches the inner matcher.
-template <typename InnerMatcher>
-IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type> IsOkAndHolds(
- InnerMatcher&& inner_matcher) {
- return IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type>(
- std::forward<InnerMatcher>(inner_matcher));
-}
-
-// Returns a gMock matcher that matches a Status or StatusOr<> which is OK.
-inline IsOkMatcher IsOk() { return IsOkMatcher(); }
-#endif // GTEST_HAS_STATUS_MATCHERS
-
struct CopyDetector {
CopyDetector() = default;
explicit CopyDetector(int xx) : x(xx) {}
@@ -527,7 +408,7 @@ TEST(StatusOr, TestCopyCtorStatusOk) {
const int kI = 4;
const absl::StatusOr<int> original(kI);
const absl::StatusOr<int> copy(original);
- EXPECT_OK(copy.status());
+ EXPECT_THAT(copy.status(), IsOk());
EXPECT_EQ(*original, *copy);
}
@@ -542,7 +423,7 @@ TEST(StatusOr, TestCopyCtorNonAssignable) {
CopyNoAssign value(kI);
absl::StatusOr<CopyNoAssign> original(value);
absl::StatusOr<CopyNoAssign> copy(original);
- EXPECT_OK(copy.status());
+ EXPECT_THAT(copy.status(), IsOk());
EXPECT_EQ(original->foo, copy->foo);
}
@@ -550,7 +431,7 @@ TEST(StatusOr, TestCopyCtorStatusOKConverting) {
const int kI = 4;
absl::StatusOr<int> original(kI);
absl::StatusOr<double> copy(original);
- EXPECT_OK(copy.status());
+ EXPECT_THAT(copy.status(), IsOk());
EXPECT_DOUBLE_EQ(*original, *copy);
}
@@ -570,11 +451,11 @@ TEST(StatusOr, TestAssignmentStatusOk) {
target = source;
ASSERT_TRUE(target.ok());
- EXPECT_OK(target.status());
+ EXPECT_THAT(target.status(), IsOk());
EXPECT_EQ(p, *target);
ASSERT_TRUE(source.ok());
- EXPECT_OK(source.status());
+ EXPECT_THAT(source.status(), IsOk());
EXPECT_EQ(p, *source);
}
@@ -587,11 +468,11 @@ TEST(StatusOr, TestAssignmentStatusOk) {
target = std::move(source);
ASSERT_TRUE(target.ok());
- EXPECT_OK(target.status());
+ EXPECT_THAT(target.status(), IsOk());
EXPECT_EQ(p, *target);
ASSERT_TRUE(source.ok());
- EXPECT_OK(source.status());
+ EXPECT_THAT(source.status(), IsOk());
EXPECT_EQ(nullptr, *source);
}
}
@@ -638,11 +519,11 @@ TEST(StatusOr, TestAssignmentStatusOKConverting) {
target = source;
ASSERT_TRUE(target.ok());
- EXPECT_OK(target.status());
+ EXPECT_THAT(target.status(), IsOk());
EXPECT_DOUBLE_EQ(kI, *target);
ASSERT_TRUE(source.ok());
- EXPECT_OK(source.status());
+ EXPECT_THAT(source.status(), IsOk());
EXPECT_DOUBLE_EQ(kI, *source);
}
@@ -655,11 +536,11 @@ TEST(StatusOr, TestAssignmentStatusOKConverting) {
target = std::move(source);
ASSERT_TRUE(target.ok());
- EXPECT_OK(target.status());
+ EXPECT_THAT(target.status(), IsOk());
EXPECT_EQ(p, target->get());
ASSERT_TRUE(source.ok());
- EXPECT_OK(source.status());
+ EXPECT_THAT(source.status(), IsOk());
EXPECT_EQ(nullptr, source->get());
}
}
@@ -1078,7 +959,7 @@ TEST(StatusOr, SelfAssignment) {
so = *&so;
ASSERT_TRUE(so.ok());
- EXPECT_OK(so.status());
+ EXPECT_THAT(so.status(), IsOk());
EXPECT_EQ(long_str, *so);
}
@@ -1101,7 +982,7 @@ TEST(StatusOr, SelfAssignment) {
so = std::move(same);
ASSERT_TRUE(so.ok());
- EXPECT_OK(so.status());
+ EXPECT_THAT(so.status(), IsOk());
EXPECT_EQ(17, *so);
}
@@ -1128,7 +1009,7 @@ TEST(StatusOr, SelfAssignment) {
so = std::move(same);
ASSERT_TRUE(so.ok());
- EXPECT_OK(so.status());
+ EXPECT_THAT(so.status(), IsOk());
EXPECT_EQ(raw, so->get());
}
@@ -1361,7 +1242,7 @@ TEST(StatusOr, TestPointerValueCtor) {
{
absl::StatusOr<const int*> so(&kI);
EXPECT_TRUE(so.ok());
- EXPECT_OK(so.status());
+ EXPECT_THAT(so.status(), IsOk());
EXPECT_EQ(&kI, *so);
}
@@ -1369,7 +1250,7 @@ TEST(StatusOr, TestPointerValueCtor) {
{
absl::StatusOr<const int*> so(nullptr);
EXPECT_TRUE(so.ok());
- EXPECT_OK(so.status());
+ EXPECT_THAT(so.status(), IsOk());
EXPECT_EQ(nullptr, *so);
}
@@ -1379,7 +1260,7 @@ TEST(StatusOr, TestPointerValueCtor) {
absl::StatusOr<const int*> so(p);
EXPECT_TRUE(so.ok());
- EXPECT_OK(so.status());
+ EXPECT_THAT(so.status(), IsOk());
EXPECT_EQ(nullptr, *so);
}
}
@@ -1388,7 +1269,7 @@ TEST(StatusOr, TestPointerCopyCtorStatusOk) {
const int kI = 0;
absl::StatusOr<const int*> original(&kI);
absl::StatusOr<const int*> copy(original);
- EXPECT_OK(copy.status());
+ EXPECT_THAT(copy.status(), IsOk());
EXPECT_EQ(*original, *copy);
}
@@ -1402,7 +1283,7 @@ TEST(StatusOr, TestPointerCopyCtorStatusOKConverting) {
Derived derived;
absl::StatusOr<Derived*> original(&derived);
absl::StatusOr<Base2*> copy(original);
- EXPECT_OK(copy.status());
+ EXPECT_THAT(copy.status(), IsOk());
EXPECT_EQ(static_cast<const Base2*>(*original), *copy);
}
@@ -1417,7 +1298,7 @@ TEST(StatusOr, TestPointerAssignmentStatusOk) {
absl::StatusOr<const int*> source(&kI);
absl::StatusOr<const int*> target;
target = source;
- EXPECT_OK(target.status());
+ EXPECT_THAT(target.status(), IsOk());
EXPECT_EQ(*source, *target);
}
@@ -1433,7 +1314,7 @@ TEST(StatusOr, TestPointerAssignmentStatusOKConverting) {
absl::StatusOr<Derived*> source(&derived);
absl::StatusOr<Base2*> target;
target = source;
- EXPECT_OK(target.status());
+ EXPECT_THAT(target.status(), IsOk());
EXPECT_EQ(static_cast<const Base2*>(*source), *target);
}