1 //
2 // Copyright 2022 The Abseil Authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // https://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #include "absl/log/internal/test_matchers.h"
17
18 #include <ostream>
19 #include <sstream>
20 #include <string>
21 #include <type_traits>
22 #include <utility>
23
24 #include "gmock/gmock.h"
25 #include "gtest/gtest.h"
26 #include "absl/base/attributes.h"
27 #include "absl/base/config.h"
28 #include "absl/log/internal/test_helpers.h"
29 #include "absl/strings/string_view.h"
30 #include "absl/time/clock.h"
31 #include "absl/time/time.h"
32
33 namespace absl {
34 ABSL_NAMESPACE_BEGIN
35 namespace log_internal {
36 namespace {
37 using ::testing::_;
38 using ::testing::AllOf;
39 using ::testing::Ge;
40 using ::testing::HasSubstr;
41 using ::testing::MakeMatcher;
42 using ::testing::Matcher;
43 using ::testing::MatcherInterface;
44 using ::testing::MatchResultListener;
45 using ::testing::Not;
46 using ::testing::Property;
47 using ::testing::ResultOf;
48 using ::testing::Truly;
49
50 class AsStringImpl final
51 : public MatcherInterface<absl::string_view> {
52 public:
AsStringImpl(const Matcher<const std::string &> & str_matcher)53 explicit AsStringImpl(
54 const Matcher<const std::string&>& str_matcher)
55 : str_matcher_(str_matcher) {}
MatchAndExplain(absl::string_view actual,MatchResultListener * listener) const56 bool MatchAndExplain(
57 absl::string_view actual,
58 MatchResultListener* listener) const override {
59 return str_matcher_.MatchAndExplain(std::string(actual), listener);
60 }
DescribeTo(std::ostream * os) const61 void DescribeTo(std::ostream* os) const override {
62 return str_matcher_.DescribeTo(os);
63 }
64
DescribeNegationTo(std::ostream * os) const65 void DescribeNegationTo(std::ostream* os) const override {
66 return str_matcher_.DescribeNegationTo(os);
67 }
68
69 private:
70 const Matcher<const std::string&> str_matcher_;
71 };
72
73 class MatchesOstreamImpl final
74 : public MatcherInterface<absl::string_view> {
75 public:
MatchesOstreamImpl(std::string expected)76 explicit MatchesOstreamImpl(std::string expected)
77 : expected_(std::move(expected)) {}
MatchAndExplain(absl::string_view actual,MatchResultListener *) const78 bool MatchAndExplain(absl::string_view actual,
79 MatchResultListener*) const override {
80 return actual == expected_;
81 }
DescribeTo(std::ostream * os) const82 void DescribeTo(std::ostream* os) const override {
83 *os << "matches the contents of the ostringstream, which are \""
84 << expected_ << "\"";
85 }
86
DescribeNegationTo(std::ostream * os) const87 void DescribeNegationTo(std::ostream* os) const override {
88 *os << "does not match the contents of the ostringstream, which are \""
89 << expected_ << "\"";
90 }
91
92 private:
93 const std::string expected_;
94 };
95 } // namespace
96
AsString(const Matcher<const std::string &> & str_matcher)97 Matcher<absl::string_view> AsString(
98 const Matcher<const std::string&>& str_matcher) {
99 return MakeMatcher(new AsStringImpl(str_matcher));
100 }
101
SourceFilename(const Matcher<absl::string_view> & source_filename)102 Matcher<const absl::LogEntry&> SourceFilename(
103 const Matcher<absl::string_view>& source_filename) {
104 return Property("source_filename", &absl::LogEntry::source_filename,
105 source_filename);
106 }
107
SourceBasename(const Matcher<absl::string_view> & source_basename)108 Matcher<const absl::LogEntry&> SourceBasename(
109 const Matcher<absl::string_view>& source_basename) {
110 return Property("source_basename", &absl::LogEntry::source_basename,
111 source_basename);
112 }
113
SourceLine(const Matcher<int> & source_line)114 Matcher<const absl::LogEntry&> SourceLine(
115 const Matcher<int>& source_line) {
116 return Property("source_line", &absl::LogEntry::source_line, source_line);
117 }
118
Prefix(const Matcher<bool> & prefix)119 Matcher<const absl::LogEntry&> Prefix(
120 const Matcher<bool>& prefix) {
121 return Property("prefix", &absl::LogEntry::prefix, prefix);
122 }
123
LogSeverity(const Matcher<absl::LogSeverity> & log_severity)124 Matcher<const absl::LogEntry&> LogSeverity(
125 const Matcher<absl::LogSeverity>& log_severity) {
126 return Property("log_severity", &absl::LogEntry::log_severity, log_severity);
127 }
128
Timestamp(const Matcher<absl::Time> & timestamp)129 Matcher<const absl::LogEntry&> Timestamp(
130 const Matcher<absl::Time>& timestamp) {
131 return Property("timestamp", &absl::LogEntry::timestamp, timestamp);
132 }
133
TimestampInMatchWindow()134 Matcher<const absl::LogEntry&> TimestampInMatchWindow() {
135 return Property("timestamp", &absl::LogEntry::timestamp,
136 AllOf(Ge(absl::Now()), Truly([](absl::Time arg) {
137 return arg <= absl::Now();
138 })));
139 }
140
ThreadID(const Matcher<absl::LogEntry::tid_t> & tid)141 Matcher<const absl::LogEntry&> ThreadID(
142 const Matcher<absl::LogEntry::tid_t>& tid) {
143 return Property("tid", &absl::LogEntry::tid, tid);
144 }
145
TextMessageWithPrefixAndNewline(const Matcher<absl::string_view> & text_message_with_prefix_and_newline)146 Matcher<const absl::LogEntry&> TextMessageWithPrefixAndNewline(
147 const Matcher<absl::string_view>&
148 text_message_with_prefix_and_newline) {
149 return Property("text_message_with_prefix_and_newline",
150 &absl::LogEntry::text_message_with_prefix_and_newline,
151 text_message_with_prefix_and_newline);
152 }
153
TextMessageWithPrefix(const Matcher<absl::string_view> & text_message_with_prefix)154 Matcher<const absl::LogEntry&> TextMessageWithPrefix(
155 const Matcher<absl::string_view>& text_message_with_prefix) {
156 return Property("text_message_with_prefix",
157 &absl::LogEntry::text_message_with_prefix,
158 text_message_with_prefix);
159 }
160
TextMessage(const Matcher<absl::string_view> & text_message)161 Matcher<const absl::LogEntry&> TextMessage(
162 const Matcher<absl::string_view>& text_message) {
163 return Property("text_message", &absl::LogEntry::text_message, text_message);
164 }
165
TextPrefix(const Matcher<absl::string_view> & text_prefix)166 Matcher<const absl::LogEntry&> TextPrefix(
167 const Matcher<absl::string_view>& text_prefix) {
168 return ResultOf(
169 [](const absl::LogEntry& entry) {
170 absl::string_view msg = entry.text_message_with_prefix();
171 msg.remove_suffix(entry.text_message().size());
172 return msg;
173 },
174 text_prefix);
175 }
RawEncodedMessage(const Matcher<absl::string_view> & raw_encoded_message)176 Matcher<const absl::LogEntry&> RawEncodedMessage(
177 const Matcher<absl::string_view>& raw_encoded_message) {
178 return Property("encoded_message", &absl::LogEntry::encoded_message,
179 raw_encoded_message);
180 }
181
Verbosity(const Matcher<int> & verbosity)182 Matcher<const absl::LogEntry&> Verbosity(
183 const Matcher<int>& verbosity) {
184 return Property("verbosity", &absl::LogEntry::verbosity, verbosity);
185 }
186
Stacktrace(const Matcher<absl::string_view> & stacktrace)187 Matcher<const absl::LogEntry&> Stacktrace(
188 const Matcher<absl::string_view>& stacktrace) {
189 return Property("stacktrace", &absl::LogEntry::stacktrace, stacktrace);
190 }
191
MatchesOstream(const std::ostringstream & stream)192 Matcher<absl::string_view> MatchesOstream(
193 const std::ostringstream& stream) {
194 return MakeMatcher(new MatchesOstreamImpl(stream.str()));
195 }
196
197 // We need to validate what is and isn't logged as the process dies due to
198 // `FATAL`, `QFATAL`, `CHECK`, etc., but assertions inside a death test
199 // subprocess don't directly affect the pass/fail status of the parent process.
200 // Instead, we use the mock actions `DeathTestExpectedLogging` and
201 // `DeathTestUnexpectedLogging` to write specific phrases to `stderr` that we
202 // can validate in the parent process using this matcher.
DeathTestValidateExpectations()203 Matcher<const std::string&> DeathTestValidateExpectations() {
204 if (log_internal::LoggingEnabledAt(absl::LogSeverity::kFatal)) {
205 return Matcher<const std::string&>(
206 AllOf(HasSubstr("Mock received expected entry"),
207 Not(HasSubstr("Mock received unexpected entry"))));
208 }
209 // If `FATAL` logging is disabled, neither message should have been written.
210 return Matcher<const std::string&>(
211 AllOf(Not(HasSubstr("Mock received expected entry")),
212 Not(HasSubstr("Mock received unexpected entry"))));
213 }
214
215 } // namespace log_internal
216 ABSL_NAMESPACE_END
217 } // namespace absl
218