xref: /aosp_15_r20/external/tink/cc/util/test_matchers.h (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2018 Google Inc.
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 //      http://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 ////////////////////////////////////////////////////////////////////////////////
16 
17 #ifndef TINK_UTIL_TEST_MATCHERS_H_
18 #define TINK_UTIL_TEST_MATCHERS_H_
19 
20 #include <ostream>
21 #include <string>
22 
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "absl/status/status.h"
26 #include "tink/util/status.h"
27 #include "tink/util/statusor.h"
28 
29 namespace crypto {
30 namespace tink {
31 namespace test {
32 namespace internal {
33 
34 ////////////////////////////////////////////////////////////
35 // Implementation of IsOkAndHolds().
36 
37 // Monomorphic implementation of matcher IsOkAndHolds(m).  StatusOrType is a
38 // reference to StatusOr<T>.
39 template <typename StatusOrType>
40 class IsOkAndHoldsMatcherImpl
41     : public ::testing::MatcherInterface<StatusOrType> {
42  public:
43   using value_type =
44       typename std::remove_reference<StatusOrType>::type::value_type;
45 
46   template <typename InnerMatcher>
IsOkAndHoldsMatcherImpl(InnerMatcher && inner_matcher)47   explicit IsOkAndHoldsMatcherImpl(InnerMatcher&& inner_matcher)
48       : inner_matcher_(::testing::SafeMatcherCast<const value_type&>(
49             std::forward<InnerMatcher>(inner_matcher))) {}
50 
DescribeTo(std::ostream * os)51   void DescribeTo(std::ostream* os) const override {
52     *os << "is OK and has a value that ";
53     inner_matcher_.DescribeTo(os);
54   }
55 
DescribeNegationTo(std::ostream * os)56   void DescribeNegationTo(std::ostream* os) const override {
57     *os << "isn't OK or has a value that ";
58     inner_matcher_.DescribeNegationTo(os);
59   }
60 
MatchAndExplain(StatusOrType actual_value,::testing::MatchResultListener * result_listener)61   bool MatchAndExplain(
62       StatusOrType actual_value,
63       ::testing::MatchResultListener* result_listener) const override {
64     if (!actual_value.ok()) {
65       *result_listener << "which has status " << actual_value.status();
66       return false;
67     }
68 
69     ::testing::StringMatchResultListener inner_listener;
70     const bool matches =
71         inner_matcher_.MatchAndExplain(*actual_value, &inner_listener);
72     const std::string inner_explanation = inner_listener.str();
73     if (!inner_explanation.empty()) {
74       *result_listener << "which contains value "
75                        << ::testing::PrintToString(*actual_value) << ", "
76                        << inner_explanation;
77     }
78     return matches;
79   }
80 
81  private:
82   const ::testing::Matcher<const value_type&> inner_matcher_;
83 };
84 
85 // Implements IsOkAndHolds(m) as a polymorphic matcher.
86 template <typename InnerMatcher>
87 class IsOkAndHoldsMatcher {
88  public:
IsOkAndHoldsMatcher(InnerMatcher inner_matcher)89   explicit IsOkAndHoldsMatcher(InnerMatcher inner_matcher)
90       : inner_matcher_(std::move(inner_matcher)) {}
91 
92   // Converts this polymorphic matcher to a monomorphic matcher of the
93   // given type.  StatusOrType can be either StatusOr<T> or a
94   // reference to StatusOr<T>.
95   template <typename StatusOrType>
96   operator ::testing::Matcher<StatusOrType>() const {  // NOLINT
97     return ::testing::Matcher<StatusOrType>(
98         new IsOkAndHoldsMatcherImpl<const StatusOrType&>(inner_matcher_));
99   }
100 
101  private:
102   const InnerMatcher inner_matcher_;
103 };
104 }  // namespace internal
105 
StatusToString(const util::Status & s)106 inline std::string StatusToString(const util::Status& s) {
107   return s.ToString();
108 }
109 
110 template <typename T>
StatusToString(const util::StatusOr<T> & s)111 std::string StatusToString(const util::StatusOr<T>& s) {
112   return s.status().ToString();
113 }
114 
115 // Matches a util::StatusOk() value.
116 // This is better than EXPECT_TRUE(status.ok())
117 // because the error message is a part of the failure messsage.
118 MATCHER(IsOk,
119         absl::StrCat(negation ? "isn't" : "is", " a Status with an OK value")) {
120   if (arg.ok()) {
121     return true;
122   }
123   *result_listener << StatusToString(arg);
124   return false;
125 }
126 
127 // Returns a gMock matcher that matches a StatusOr<> whose status is
128 // OK and whose value matches the inner matcher.
129 template <typename InnerMatcher>
130 internal::IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type>
IsOkAndHolds(InnerMatcher && inner_matcher)131 IsOkAndHolds(InnerMatcher&& inner_matcher) {
132   return internal::IsOkAndHoldsMatcher<typename std::decay<InnerMatcher>::type>(
133       std::forward<InnerMatcher>(inner_matcher));
134 }
135 
136 // Matches a Status with the specified 'code' as code().
137 MATCHER_P(StatusIs, code,
138           "is a Status with a " + absl::StatusCodeToString(code) + " code") {
139   if (arg.code() == code) {
140     return true;
141   }
142   *result_listener << ::testing::PrintToString(arg);
143   return false;
144 }
145 
146 // Matches a Status whose code() equals 'code', and whose message() matches
147 // 'message_macher'.
148 MATCHER_P2(StatusIs, code, message_matcher, "") {
149   return (arg.code() == code) &&
150          testing::Matches(message_matcher)(std::string(arg.message()));
151 }
152 
153 // Matches a Keyset::Key with `key`.
154 MATCHER_P(EqualsKey, key, "is equals to the expected key") {
155   if (arg.key_id() == key.key_id() && arg.status() == key.status() &&
156          arg.output_prefix_type() == key.output_prefix_type() &&
157          arg.key_data().type_url() == key.key_data().type_url() &&
158          arg.key_data().key_material_type() ==
159              key.key_data().key_material_type() &&
160          arg.key_data().value() == key.key_data().value()) {
161     return true;
162   }
163   *result_listener << arg.DebugString();
164   return false;
165 }
166 
167 }  // namespace test
168 }  // namespace tink
169 }  // namespace crypto
170 
171 #endif  // TINK_UTIL_TEST_MATCHERS_H_
172