1*ec63e07aSXin Li // Copyright 2019 Google LLC
2*ec63e07aSXin Li //
3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*ec63e07aSXin Li // you may not use this file except in compliance with the License.
5*ec63e07aSXin Li // You may obtain a copy of the License at
6*ec63e07aSXin Li //
7*ec63e07aSXin Li // https://www.apache.org/licenses/LICENSE-2.0
8*ec63e07aSXin Li //
9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software
10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*ec63e07aSXin Li // See the License for the specific language governing permissions and
13*ec63e07aSXin Li // limitations under the License.
14*ec63e07aSXin Li
15*ec63e07aSXin Li #ifndef SANDBOXED_API_UTIL_STATUS_MATCHERS_H_
16*ec63e07aSXin Li #define SANDBOXED_API_UTIL_STATUS_MATCHERS_H_
17*ec63e07aSXin Li
18*ec63e07aSXin Li #include <ostream>
19*ec63e07aSXin Li #include <string>
20*ec63e07aSXin Li #include <type_traits>
21*ec63e07aSXin Li #include <utility>
22*ec63e07aSXin Li
23*ec63e07aSXin Li #include "gmock/gmock.h"
24*ec63e07aSXin Li #include "gtest/gtest.h"
25*ec63e07aSXin Li #include "absl/status/status.h"
26*ec63e07aSXin Li #include "absl/status/statusor.h"
27*ec63e07aSXin Li #include "absl/strings/string_view.h"
28*ec63e07aSXin Li #include "absl/types/optional.h"
29*ec63e07aSXin Li #include "sandboxed_api/util/status_macros.h"
30*ec63e07aSXin Li
31*ec63e07aSXin Li #define SAPI_ASSERT_OK(expr) ASSERT_THAT(expr, ::sapi::IsOk())
32*ec63e07aSXin Li
33*ec63e07aSXin Li #define SAPI_ASSERT_OK_AND_ASSIGN(lhs, rexpr) \
34*ec63e07aSXin Li SAPI_ASSERT_OK_AND_ASSIGN_IMPL( \
35*ec63e07aSXin Li SAPI_MACROS_IMPL_CONCAT(_sapi_statusor, __LINE__), lhs, rexpr)
36*ec63e07aSXin Li
37*ec63e07aSXin Li #define SAPI_ASSERT_OK_AND_ASSIGN_IMPL(statusor, lhs, rexpr) \
38*ec63e07aSXin Li auto statusor = (rexpr); \
39*ec63e07aSXin Li ASSERT_THAT(statusor.status(), ::sapi::IsOk()); \
40*ec63e07aSXin Li lhs = std::move(statusor).value()
41*ec63e07aSXin Li
42*ec63e07aSXin Li namespace sapi {
43*ec63e07aSXin Li namespace internal {
44*ec63e07aSXin Li
45*ec63e07aSXin Li class IsOkMatcher {
46*ec63e07aSXin Li public:
47*ec63e07aSXin Li template <typename StatusT>
MatchAndExplain(const StatusT & status_container,::testing::MatchResultListener * listener)48*ec63e07aSXin Li bool MatchAndExplain(const StatusT& status_container,
49*ec63e07aSXin Li ::testing::MatchResultListener* listener) const {
50*ec63e07aSXin Li if (!status_container.ok()) {
51*ec63e07aSXin Li *listener << "which is not OK";
52*ec63e07aSXin Li return false;
53*ec63e07aSXin Li }
54*ec63e07aSXin Li return true;
55*ec63e07aSXin Li }
56*ec63e07aSXin Li
DescribeTo(std::ostream * os)57*ec63e07aSXin Li void DescribeTo(std::ostream* os) const { *os << "is OK"; }
58*ec63e07aSXin Li
DescribeNegationTo(std::ostream * os)59*ec63e07aSXin Li void DescribeNegationTo(std::ostream* os) const { *os << "is not OK"; }
60*ec63e07aSXin Li };
61*ec63e07aSXin Li
62*ec63e07aSXin Li class StatusIsMatcher {
63*ec63e07aSXin Li public:
64*ec63e07aSXin Li StatusIsMatcher(const StatusIsMatcher&) = default;
65*ec63e07aSXin Li
StatusIsMatcher(absl::StatusCode code,absl::optional<absl::string_view> message)66*ec63e07aSXin Li StatusIsMatcher(absl::StatusCode code,
67*ec63e07aSXin Li absl::optional<absl::string_view> message)
68*ec63e07aSXin Li : code_(code), message_(message) {}
69*ec63e07aSXin Li
70*ec63e07aSXin Li template <typename T>
MatchAndExplain(const T & value,::testing::MatchResultListener * listener)71*ec63e07aSXin Li bool MatchAndExplain(const T& value,
72*ec63e07aSXin Li ::testing::MatchResultListener* listener) const {
73*ec63e07aSXin Li auto status = GetStatus(value);
74*ec63e07aSXin Li if (code_ != status.code()) {
75*ec63e07aSXin Li *listener << "whose error code is "
76*ec63e07aSXin Li << absl::StatusCodeToString(status.code());
77*ec63e07aSXin Li return false;
78*ec63e07aSXin Li }
79*ec63e07aSXin Li if (message_.has_value() && status.message() != message_.value()) {
80*ec63e07aSXin Li *listener << "whose error message is '" << message_.value() << "'";
81*ec63e07aSXin Li return false;
82*ec63e07aSXin Li }
83*ec63e07aSXin Li return true;
84*ec63e07aSXin Li }
85*ec63e07aSXin Li
DescribeTo(std::ostream * os)86*ec63e07aSXin Li void DescribeTo(std::ostream* os) const {
87*ec63e07aSXin Li *os << "has a status code that is " << absl::StatusCodeToString(code_);
88*ec63e07aSXin Li if (message_.has_value()) {
89*ec63e07aSXin Li *os << ", and has an error message that is '" << message_.value() << "'";
90*ec63e07aSXin Li }
91*ec63e07aSXin Li }
92*ec63e07aSXin Li
DescribeNegationTo(std::ostream * os)93*ec63e07aSXin Li void DescribeNegationTo(std::ostream* os) const {
94*ec63e07aSXin Li *os << "has a status code that is not " << absl::StatusCodeToString(code_);
95*ec63e07aSXin Li if (message_.has_value()) {
96*ec63e07aSXin Li *os << ", and has an error message that is not '" << message_.value()
97*ec63e07aSXin Li << "'";
98*ec63e07aSXin Li }
99*ec63e07aSXin Li }
100*ec63e07aSXin Li
101*ec63e07aSXin Li private:
102*ec63e07aSXin Li template <typename StatusT,
103*ec63e07aSXin Li typename std::enable_if<
104*ec63e07aSXin Li !std::is_void<decltype(std::declval<StatusT>().code())>::value,
105*ec63e07aSXin Li int>::type = 0>
GetStatus(const StatusT & status)106*ec63e07aSXin Li static const StatusT& GetStatus(const StatusT& status) {
107*ec63e07aSXin Li return status;
108*ec63e07aSXin Li }
109*ec63e07aSXin Li
110*ec63e07aSXin Li template <typename StatusOrT,
111*ec63e07aSXin Li typename StatusT = decltype(std::declval<StatusOrT>().status())>
GetStatus(const StatusOrT & status_or)112*ec63e07aSXin Li static StatusT GetStatus(const StatusOrT& status_or) {
113*ec63e07aSXin Li return status_or.status();
114*ec63e07aSXin Li }
115*ec63e07aSXin Li
116*ec63e07aSXin Li const absl::StatusCode code_;
117*ec63e07aSXin Li const absl::optional<std::string> message_;
118*ec63e07aSXin Li };
119*ec63e07aSXin Li
120*ec63e07aSXin Li } // namespace internal
121*ec63e07aSXin Li
IsOk()122*ec63e07aSXin Li inline ::testing::PolymorphicMatcher<internal::IsOkMatcher> IsOk() {
123*ec63e07aSXin Li return ::testing::MakePolymorphicMatcher(internal::IsOkMatcher{});
124*ec63e07aSXin Li }
125*ec63e07aSXin Li
126*ec63e07aSXin Li inline ::testing::PolymorphicMatcher<internal::StatusIsMatcher> StatusIs(
127*ec63e07aSXin Li absl::StatusCode code,
128*ec63e07aSXin Li absl::optional<absl::string_view> message = absl::nullopt) {
129*ec63e07aSXin Li return ::testing::MakePolymorphicMatcher(
130*ec63e07aSXin Li internal::StatusIsMatcher(code, message));
131*ec63e07aSXin Li }
132*ec63e07aSXin Li
133*ec63e07aSXin Li } // namespace sapi
134*ec63e07aSXin Li
135*ec63e07aSXin Li #endif // SANDBOXED_API_UTIL_STATUS_MATCHERS_H_
136