• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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