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/log/log_entry.h"
30 #include "absl/strings/string_view.h"
31 #include "absl/time/clock.h"
32 #include "absl/time/time.h"
33
34 namespace absl {
35 ABSL_NAMESPACE_BEGIN
36 namespace log_internal {
37 namespace {
38 using ::testing::_;
39 using ::testing::AllOf;
40 using ::testing::Ge;
41 using ::testing::HasSubstr;
42 using ::testing::MakeMatcher;
43 using ::testing::Matcher;
44 using ::testing::MatcherInterface;
45 using ::testing::MatchResultListener;
46 using ::testing::Not;
47 using ::testing::Property;
48 using ::testing::ResultOf;
49 using ::testing::Truly;
50
51 class AsStringImpl final
52 : public MatcherInterface<absl::string_view> {
53 public:
AsStringImpl(const Matcher<const std::string &> & str_matcher)54 explicit AsStringImpl(
55 const Matcher<const std::string&>& str_matcher)
56 : str_matcher_(str_matcher) {}
MatchAndExplain(absl::string_view actual,MatchResultListener * listener) const57 bool MatchAndExplain(
58 absl::string_view actual,
59 MatchResultListener* listener) const override {
60 return str_matcher_.MatchAndExplain(std::string(actual), listener);
61 }
DescribeTo(std::ostream * os) const62 void DescribeTo(std::ostream* os) const override {
63 return str_matcher_.DescribeTo(os);
64 }
65
DescribeNegationTo(std::ostream * os) const66 void DescribeNegationTo(std::ostream* os) const override {
67 return str_matcher_.DescribeNegationTo(os);
68 }
69
70 private:
71 const Matcher<const std::string&> str_matcher_;
72 };
73
74 class MatchesOstreamImpl final
75 : public MatcherInterface<absl::string_view> {
76 public:
MatchesOstreamImpl(std::string expected)77 explicit MatchesOstreamImpl(std::string expected)
78 : expected_(std::move(expected)) {}
MatchAndExplain(absl::string_view actual,MatchResultListener *) const79 bool MatchAndExplain(absl::string_view actual,
80 MatchResultListener*) const override {
81 return actual == expected_;
82 }
DescribeTo(std::ostream * os) const83 void DescribeTo(std::ostream* os) const override {
84 *os << "matches the contents of the ostringstream, which are \""
85 << expected_ << "\"";
86 }
87
DescribeNegationTo(std::ostream * os) const88 void DescribeNegationTo(std::ostream* os) const override {
89 *os << "does not match the contents of the ostringstream, which are \""
90 << expected_ << "\"";
91 }
92
93 private:
94 const std::string expected_;
95 };
96 } // namespace
97
AsString(const Matcher<const std::string &> & str_matcher)98 Matcher<absl::string_view> AsString(
99 const Matcher<const std::string&>& str_matcher) {
100 return MakeMatcher(new AsStringImpl(str_matcher));
101 }
102
SourceFilename(const Matcher<absl::string_view> & source_filename)103 Matcher<const absl::LogEntry&> SourceFilename(
104 const Matcher<absl::string_view>& source_filename) {
105 return Property("source_filename", &absl::LogEntry::source_filename,
106 source_filename);
107 }
108
SourceBasename(const Matcher<absl::string_view> & source_basename)109 Matcher<const absl::LogEntry&> SourceBasename(
110 const Matcher<absl::string_view>& source_basename) {
111 return Property("source_basename", &absl::LogEntry::source_basename,
112 source_basename);
113 }
114
SourceLine(const Matcher<int> & source_line)115 Matcher<const absl::LogEntry&> SourceLine(
116 const Matcher<int>& source_line) {
117 return Property("source_line", &absl::LogEntry::source_line, source_line);
118 }
119
Prefix(const Matcher<bool> & prefix)120 Matcher<const absl::LogEntry&> Prefix(
121 const Matcher<bool>& prefix) {
122 return Property("prefix", &absl::LogEntry::prefix, prefix);
123 }
124
LogSeverity(const Matcher<absl::LogSeverity> & log_severity)125 Matcher<const absl::LogEntry&> LogSeverity(
126 const Matcher<absl::LogSeverity>& log_severity) {
127 return Property("log_severity", &absl::LogEntry::log_severity, log_severity);
128 }
129
Timestamp(const Matcher<absl::Time> & timestamp)130 Matcher<const absl::LogEntry&> Timestamp(
131 const Matcher<absl::Time>& timestamp) {
132 return Property("timestamp", &absl::LogEntry::timestamp, timestamp);
133 }
134
InMatchWindow()135 Matcher<absl::Time> InMatchWindow() {
136 return AllOf(Ge(absl::Now()),
137 Truly([](absl::Time arg) { return arg <= absl::Now(); }));
138 }
139
ThreadID(const Matcher<absl::LogEntry::tid_t> & tid)140 Matcher<const absl::LogEntry&> ThreadID(
141 const Matcher<absl::LogEntry::tid_t>& tid) {
142 return Property("tid", &absl::LogEntry::tid, tid);
143 }
144
TextMessageWithPrefixAndNewline(const Matcher<absl::string_view> & text_message_with_prefix_and_newline)145 Matcher<const absl::LogEntry&> TextMessageWithPrefixAndNewline(
146 const Matcher<absl::string_view>&
147 text_message_with_prefix_and_newline) {
148 return Property("text_message_with_prefix_and_newline",
149 &absl::LogEntry::text_message_with_prefix_and_newline,
150 text_message_with_prefix_and_newline);
151 }
152
TextMessageWithPrefix(const Matcher<absl::string_view> & text_message_with_prefix)153 Matcher<const absl::LogEntry&> TextMessageWithPrefix(
154 const Matcher<absl::string_view>& text_message_with_prefix) {
155 return Property("text_message_with_prefix",
156 &absl::LogEntry::text_message_with_prefix,
157 text_message_with_prefix);
158 }
159
TextMessage(const Matcher<absl::string_view> & text_message)160 Matcher<const absl::LogEntry&> TextMessage(
161 const Matcher<absl::string_view>& text_message) {
162 return Property("text_message", &absl::LogEntry::text_message, text_message);
163 }
164
TextPrefix(const Matcher<absl::string_view> & text_prefix)165 Matcher<const absl::LogEntry&> TextPrefix(
166 const Matcher<absl::string_view>& text_prefix) {
167 return ResultOf(
168 [](const absl::LogEntry& entry) {
169 absl::string_view msg = entry.text_message_with_prefix();
170 msg.remove_suffix(entry.text_message().size());
171 return msg;
172 },
173 text_prefix);
174 }
RawEncodedMessage(const Matcher<absl::string_view> & raw_encoded_message)175 Matcher<const absl::LogEntry&> RawEncodedMessage(
176 const Matcher<absl::string_view>& raw_encoded_message) {
177 return Property("encoded_message", &absl::LogEntry::encoded_message,
178 raw_encoded_message);
179 }
180
Verbosity(const Matcher<int> & verbosity)181 Matcher<const absl::LogEntry&> Verbosity(
182 const Matcher<int>& verbosity) {
183 return Property("verbosity", &absl::LogEntry::verbosity, verbosity);
184 }
185
Stacktrace(const Matcher<absl::string_view> & stacktrace)186 Matcher<const absl::LogEntry&> Stacktrace(
187 const Matcher<absl::string_view>& stacktrace) {
188 return Property("stacktrace", &absl::LogEntry::stacktrace, stacktrace);
189 }
190
MatchesOstream(const std::ostringstream & stream)191 Matcher<absl::string_view> MatchesOstream(
192 const std::ostringstream& stream) {
193 return MakeMatcher(new MatchesOstreamImpl(stream.str()));
194 }
195
196 // We need to validate what is and isn't logged as the process dies due to
197 // `FATAL`, `QFATAL`, `CHECK`, etc., but assertions inside a death test
198 // subprocess don't directly affect the pass/fail status of the parent process.
199 // Instead, we use the mock actions `DeathTestExpectedLogging` and
200 // `DeathTestUnexpectedLogging` to write specific phrases to `stderr` that we
201 // can validate in the parent process using this matcher.
DeathTestValidateExpectations()202 Matcher<const std::string&> DeathTestValidateExpectations() {
203 if (log_internal::LoggingEnabledAt(absl::LogSeverity::kFatal)) {
204 return Matcher<const std::string&>(
205 AllOf(HasSubstr("Mock received expected entry"),
206 Not(HasSubstr("Mock received unexpected entry"))));
207 }
208 // If `FATAL` logging is disabled, neither message should have been written.
209 return Matcher<const std::string&>(
210 AllOf(Not(HasSubstr("Mock received expected entry")),
211 Not(HasSubstr("Mock received unexpected entry"))));
212 }
213
214 } // namespace log_internal
215 ABSL_NAMESPACE_END
216 } // namespace absl
217