xref: /aosp_15_r20/external/abseil-cpp/absl/log/internal/test_matchers.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
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