123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- // 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_
|