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