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 <sstream>
19 #include <string>
20 #include <utility>
21
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/base/config.h"
25 #include "absl/log/internal/config.h"
26 #include "absl/log/internal/test_helpers.h"
27 #include "absl/strings/string_view.h"
28 #include "absl/time/clock.h"
29 #include "absl/time/time.h"
30
31 namespace absl {
32 ABSL_NAMESPACE_BEGIN
33 namespace log_internal {
34
SourceFilename(const::testing::Matcher<absl::string_view> & source_filename)35 ::testing::Matcher<const absl::LogEntry&> SourceFilename(
36 const ::testing::Matcher<absl::string_view>& source_filename) {
37 return Property("source_filename", &absl::LogEntry::source_filename,
38 source_filename);
39 }
40
SourceBasename(const::testing::Matcher<absl::string_view> & source_basename)41 ::testing::Matcher<const absl::LogEntry&> SourceBasename(
42 const ::testing::Matcher<absl::string_view>& source_basename) {
43 return Property("source_basename", &absl::LogEntry::source_basename,
44 source_basename);
45 }
46
SourceLine(const::testing::Matcher<int> & source_line)47 ::testing::Matcher<const absl::LogEntry&> SourceLine(
48 const ::testing::Matcher<int>& source_line) {
49 return Property("source_line", &absl::LogEntry::source_line, source_line);
50 }
51
Prefix(const::testing::Matcher<bool> & prefix)52 ::testing::Matcher<const absl::LogEntry&> Prefix(
53 const ::testing::Matcher<bool>& prefix) {
54 return Property("prefix", &absl::LogEntry::prefix, prefix);
55 }
56
LogSeverity(const::testing::Matcher<absl::LogSeverity> & log_severity)57 ::testing::Matcher<const absl::LogEntry&> LogSeverity(
58 const ::testing::Matcher<absl::LogSeverity>& log_severity) {
59 return Property("log_severity", &absl::LogEntry::log_severity, log_severity);
60 }
61
Timestamp(const::testing::Matcher<absl::Time> & timestamp)62 ::testing::Matcher<const absl::LogEntry&> Timestamp(
63 const ::testing::Matcher<absl::Time>& timestamp) {
64 return Property("timestamp", &absl::LogEntry::timestamp, timestamp);
65 }
66
TimestampInMatchWindow()67 ::testing::Matcher<const absl::LogEntry&> TimestampInMatchWindow() {
68 return Property("timestamp", &absl::LogEntry::timestamp,
69 ::testing::AllOf(::testing::Ge(absl::Now()),
70 ::testing::Truly([](absl::Time arg) {
71 return arg <= absl::Now();
72 })));
73 }
74
ThreadID(const::testing::Matcher<absl::LogEntry::tid_t> & tid)75 ::testing::Matcher<const absl::LogEntry&> ThreadID(
76 const ::testing::Matcher<absl::LogEntry::tid_t>& tid) {
77 return Property("tid", &absl::LogEntry::tid, tid);
78 }
79
TextMessageWithPrefixAndNewline(const::testing::Matcher<absl::string_view> & text_message_with_prefix_and_newline)80 ::testing::Matcher<const absl::LogEntry&> TextMessageWithPrefixAndNewline(
81 const ::testing::Matcher<absl::string_view>&
82 text_message_with_prefix_and_newline) {
83 return Property("text_message_with_prefix_and_newline",
84 &absl::LogEntry::text_message_with_prefix_and_newline,
85 text_message_with_prefix_and_newline);
86 }
87
TextMessageWithPrefix(const::testing::Matcher<absl::string_view> & text_message_with_prefix)88 ::testing::Matcher<const absl::LogEntry&> TextMessageWithPrefix(
89 const ::testing::Matcher<absl::string_view>& text_message_with_prefix) {
90 return Property("text_message_with_prefix",
91 &absl::LogEntry::text_message_with_prefix,
92 text_message_with_prefix);
93 }
94
TextMessage(const::testing::Matcher<absl::string_view> & text_message)95 ::testing::Matcher<const absl::LogEntry&> TextMessage(
96 const ::testing::Matcher<absl::string_view>& text_message) {
97 return Property("text_message", &absl::LogEntry::text_message, text_message);
98 }
99
TextPrefix(const::testing::Matcher<absl::string_view> & text_prefix)100 ::testing::Matcher<const absl::LogEntry&> TextPrefix(
101 const ::testing::Matcher<absl::string_view>& text_prefix) {
102 return ResultOf(
103 [](const absl::LogEntry& entry) {
104 absl::string_view msg = entry.text_message_with_prefix();
105 msg.remove_suffix(entry.text_message().size());
106 return msg;
107 },
108 text_prefix);
109 }
110
Verbosity(const::testing::Matcher<int> & verbosity)111 ::testing::Matcher<const absl::LogEntry&> Verbosity(
112 const ::testing::Matcher<int>& verbosity) {
113 return Property("verbosity", &absl::LogEntry::verbosity, verbosity);
114 }
115
Stacktrace(const::testing::Matcher<absl::string_view> & stacktrace)116 ::testing::Matcher<const absl::LogEntry&> Stacktrace(
117 const ::testing::Matcher<absl::string_view>& stacktrace) {
118 return Property("stacktrace", &absl::LogEntry::stacktrace, stacktrace);
119 }
120
121 class MatchesOstreamImpl final
122 : public ::testing::MatcherInterface<absl::string_view> {
123 public:
MatchesOstreamImpl(std::string expected)124 explicit MatchesOstreamImpl(std::string expected)
125 : expected_(std::move(expected)) {}
MatchAndExplain(absl::string_view actual,::testing::MatchResultListener *) const126 bool MatchAndExplain(absl::string_view actual,
127 ::testing::MatchResultListener*) const override {
128 return actual == expected_;
129 }
DescribeTo(std::ostream * os) const130 void DescribeTo(std::ostream* os) const override {
131 *os << "matches the contents of the ostringstream, which are \""
132 << expected_ << "\"";
133 }
134
DescribeNegationTo(std::ostream * os) const135 void DescribeNegationTo(std::ostream* os) const override {
136 *os << "does not match the contents of the ostringstream, which are \""
137 << expected_ << "\"";
138 }
139
140 private:
141 const std::string expected_;
142 };
MatchesOstream(const std::ostringstream & stream)143 ::testing::Matcher<absl::string_view> MatchesOstream(
144 const std::ostringstream& stream) {
145 return ::testing::MakeMatcher(new MatchesOstreamImpl(stream.str()));
146 }
147
148 // We need to validate what is and isn't logged as the process dies due to
149 // `FATAL`, `QFATAL`, `CHECK`, etc., but assertions inside a death test
150 // subprocess don't directly affect the pass/fail status of the parent process.
151 // Instead, we use the mock actions `DeathTestExpectedLogging` and
152 // `DeathTestUnexpectedLogging` to write specific phrases to `stderr` that we
153 // can validate in the parent process using this matcher.
DeathTestValidateExpectations()154 ::testing::Matcher<const std::string&> DeathTestValidateExpectations() {
155 if (log_internal::LoggingEnabledAt(absl::LogSeverity::kFatal)) {
156 return ::testing::Matcher<const std::string&>(::testing::AllOf(
157 ::testing::HasSubstr("Mock received expected entry"),
158 Not(::testing::HasSubstr("Mock received unexpected entry"))));
159 }
160 // If `FATAL` logging is disabled, neither message should have been written.
161 return ::testing::Matcher<const std::string&>(::testing::AllOf(
162 Not(::testing::HasSubstr("Mock received expected entry")),
163 Not(::testing::HasSubstr("Mock received unexpected entry"))));
164 }
165
166 } // namespace log_internal
167 ABSL_NAMESPACE_END
168 } // namespace absl
169