test_matchers.cc (7186B)
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: 54 explicit AsStringImpl( 55 const Matcher<const std::string&>& str_matcher) 56 : str_matcher_(str_matcher) {} 57 bool MatchAndExplain( 58 absl::string_view actual, 59 MatchResultListener* listener) const override { 60 return str_matcher_.MatchAndExplain(std::string(actual), listener); 61 } 62 void DescribeTo(std::ostream* os) const override { 63 return str_matcher_.DescribeTo(os); 64 } 65 66 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: 77 explicit MatchesOstreamImpl(std::string expected) 78 : expected_(std::move(expected)) {} 79 bool MatchAndExplain(absl::string_view actual, 80 MatchResultListener*) const override { 81 return actual == expected_; 82 } 83 void DescribeTo(std::ostream* os) const override { 84 *os << "matches the contents of the ostringstream, which are \"" 85 << expected_ << "\""; 86 } 87 88 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 98 Matcher<absl::string_view> AsString( 99 const Matcher<const std::string&>& str_matcher) { 100 return MakeMatcher(new AsStringImpl(str_matcher)); 101 } 102 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 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 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 120 Matcher<const absl::LogEntry&> Prefix( 121 const Matcher<bool>& prefix) { 122 return Property("prefix", &absl::LogEntry::prefix, prefix); 123 } 124 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 130 Matcher<const absl::LogEntry&> Timestamp( 131 const Matcher<absl::Time>& timestamp) { 132 return Property("timestamp", &absl::LogEntry::timestamp, timestamp); 133 } 134 135 Matcher<absl::Time> InMatchWindow() { 136 return AllOf(Ge(absl::Now()), 137 Truly([](absl::Time arg) { return arg <= absl::Now(); })); 138 } 139 140 Matcher<const absl::LogEntry&> ThreadID( 141 const Matcher<absl::LogEntry::tid_t>& tid) { 142 return Property("tid", &absl::LogEntry::tid, tid); 143 } 144 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 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 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 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 } 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 181 Matcher<const absl::LogEntry&> Verbosity( 182 const Matcher<int>& verbosity) { 183 return Property("verbosity", &absl::LogEntry::verbosity, verbosity); 184 } 185 186 Matcher<const absl::LogEntry&> Stacktrace( 187 const Matcher<absl::string_view>& stacktrace) { 188 return Property("stacktrace", &absl::LogEntry::stacktrace, stacktrace); 189 } 190 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. 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