xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/util/status_matchers.h (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1 // Copyright 2019 Google LLC
2 //
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 #ifndef SANDBOXED_API_UTIL_STATUS_MATCHERS_H_
16 #define SANDBOXED_API_UTIL_STATUS_MATCHERS_H_
17 
18 #include <ostream>
19 #include <string>
20 #include <type_traits>
21 #include <utility>
22 
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "absl/status/status.h"
26 #include "absl/status/statusor.h"
27 #include "absl/strings/string_view.h"
28 #include "absl/types/optional.h"
29 #include "sandboxed_api/util/status_macros.h"
30 
31 #define SAPI_ASSERT_OK(expr) ASSERT_THAT(expr, ::sapi::IsOk())
32 
33 #define SAPI_ASSERT_OK_AND_ASSIGN(lhs, rexpr) \
34   SAPI_ASSERT_OK_AND_ASSIGN_IMPL(             \
35       SAPI_MACROS_IMPL_CONCAT(_sapi_statusor, __LINE__), lhs, rexpr)
36 
37 #define SAPI_ASSERT_OK_AND_ASSIGN_IMPL(statusor, lhs, rexpr) \
38   auto statusor = (rexpr);                                   \
39   ASSERT_THAT(statusor.status(), ::sapi::IsOk());            \
40   lhs = std::move(statusor).value()
41 
42 namespace sapi {
43 namespace internal {
44 
45 class IsOkMatcher {
46  public:
47   template <typename StatusT>
MatchAndExplain(const StatusT & status_container,::testing::MatchResultListener * listener)48   bool MatchAndExplain(const StatusT& status_container,
49                        ::testing::MatchResultListener* listener) const {
50     if (!status_container.ok()) {
51       *listener << "which is not OK";
52       return false;
53     }
54     return true;
55   }
56 
DescribeTo(std::ostream * os)57   void DescribeTo(std::ostream* os) const { *os << "is OK"; }
58 
DescribeNegationTo(std::ostream * os)59   void DescribeNegationTo(std::ostream* os) const { *os << "is not OK"; }
60 };
61 
62 class StatusIsMatcher {
63  public:
64   StatusIsMatcher(const StatusIsMatcher&) = default;
65 
StatusIsMatcher(absl::StatusCode code,absl::optional<absl::string_view> message)66   StatusIsMatcher(absl::StatusCode code,
67                   absl::optional<absl::string_view> message)
68       : code_(code), message_(message) {}
69 
70   template <typename T>
MatchAndExplain(const T & value,::testing::MatchResultListener * listener)71   bool MatchAndExplain(const T& value,
72                        ::testing::MatchResultListener* listener) const {
73     auto status = GetStatus(value);
74     if (code_ != status.code()) {
75       *listener << "whose error code is "
76                 << absl::StatusCodeToString(status.code());
77       return false;
78     }
79     if (message_.has_value() && status.message() != message_.value()) {
80       *listener << "whose error message is '" << message_.value() << "'";
81       return false;
82     }
83     return true;
84   }
85 
DescribeTo(std::ostream * os)86   void DescribeTo(std::ostream* os) const {
87     *os << "has a status code that is " << absl::StatusCodeToString(code_);
88     if (message_.has_value()) {
89       *os << ", and has an error message that is '" << message_.value() << "'";
90     }
91   }
92 
DescribeNegationTo(std::ostream * os)93   void DescribeNegationTo(std::ostream* os) const {
94     *os << "has a status code that is not " << absl::StatusCodeToString(code_);
95     if (message_.has_value()) {
96       *os << ", and has an error message that is not '" << message_.value()
97           << "'";
98     }
99   }
100 
101  private:
102   template <typename StatusT,
103             typename std::enable_if<
104                 !std::is_void<decltype(std::declval<StatusT>().code())>::value,
105                 int>::type = 0>
GetStatus(const StatusT & status)106   static const StatusT& GetStatus(const StatusT& status) {
107     return status;
108   }
109 
110   template <typename StatusOrT,
111             typename StatusT = decltype(std::declval<StatusOrT>().status())>
GetStatus(const StatusOrT & status_or)112   static StatusT GetStatus(const StatusOrT& status_or) {
113     return status_or.status();
114   }
115 
116   const absl::StatusCode code_;
117   const absl::optional<std::string> message_;
118 };
119 
120 }  // namespace internal
121 
IsOk()122 inline ::testing::PolymorphicMatcher<internal::IsOkMatcher> IsOk() {
123   return ::testing::MakePolymorphicMatcher(internal::IsOkMatcher{});
124 }
125 
126 inline ::testing::PolymorphicMatcher<internal::StatusIsMatcher> StatusIs(
127     absl::StatusCode code,
128     absl::optional<absl::string_view> message = absl::nullopt) {
129   return ::testing::MakePolymorphicMatcher(
130       internal::StatusIsMatcher(code, message));
131 }
132 
133 }  // namespace sapi
134 
135 #endif  // SANDBOXED_API_UTIL_STATUS_MATCHERS_H_
136