| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "absl/log/scoped_mock_log.h" |
|
|
| #include <memory> |
| #include <thread> |
|
|
| #include "gmock/gmock.h" |
| #include "gtest/gtest-spi.h" |
| #include "gtest/gtest.h" |
| #include "absl/base/attributes.h" |
| #include "absl/base/log_severity.h" |
| #include "absl/log/globals.h" |
| #include "absl/log/internal/test_helpers.h" |
| #include "absl/log/internal/test_matchers.h" |
| #include "absl/log/log.h" |
| #include "absl/memory/memory.h" |
| #include "absl/strings/match.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/synchronization/barrier.h" |
| #include "absl/synchronization/notification.h" |
|
|
| namespace { |
|
|
| using ::testing::_; |
| using ::testing::AnyNumber; |
| using ::testing::Eq; |
| using ::testing::HasSubstr; |
| using ::testing::InSequence; |
| using ::testing::Lt; |
| using ::testing::Truly; |
| using absl::log_internal::SourceBasename; |
| using absl::log_internal::SourceFilename; |
| using absl::log_internal::SourceLine; |
| using absl::log_internal::TextMessageWithPrefix; |
| using absl::log_internal::ThreadID; |
|
|
| auto* test_env ABSL_ATTRIBUTE_UNUSED = ::testing::AddGlobalTestEnvironment( |
| new absl::log_internal::LogTestEnvironment); |
|
|
| #if GTEST_HAS_DEATH_TEST |
| TEST(ScopedMockLogDeathTest, |
| StartCapturingLogsCannotBeCalledWhenAlreadyCapturing) { |
| EXPECT_DEATH( |
| { |
| absl::ScopedMockLog log; |
| log.StartCapturingLogs(); |
| log.StartCapturingLogs(); |
| }, |
| "StartCapturingLogs"); |
| } |
|
|
| TEST(ScopedMockLogDeathTest, StopCapturingLogsCannotBeCalledWhenNotCapturing) { |
| EXPECT_DEATH( |
| { |
| absl::ScopedMockLog log; |
| log.StopCapturingLogs(); |
| }, |
| "StopCapturingLogs"); |
| } |
|
|
| TEST(ScopedMockLogDeathTest, FailsCheckIfStartCapturingLogsIsNeverCalled) { |
| EXPECT_DEATH({ absl::ScopedMockLog log; }, |
| "Did you forget to call StartCapturingLogs"); |
| } |
| #endif |
|
|
| |
| TEST(ScopedMockLogTest, LogMockCatchAndMatchStrictExpectations) { |
| absl::ScopedMockLog log; |
|
|
| |
| InSequence s; |
| EXPECT_CALL(log, |
| Log(absl::LogSeverity::kWarning, HasSubstr(__FILE__), "Danger.")); |
| EXPECT_CALL(log, Log(absl::LogSeverity::kInfo, _, "Working...")).Times(2); |
| EXPECT_CALL(log, Log(absl::LogSeverity::kError, _, "Bad!!")); |
|
|
| log.StartCapturingLogs(); |
| LOG(WARNING) << "Danger."; |
| LOG(INFO) << "Working..."; |
| LOG(INFO) << "Working..."; |
| LOG(ERROR) << "Bad!!"; |
| } |
|
|
| TEST(ScopedMockLogTest, LogMockCatchAndMatchSendExpectations) { |
| absl::ScopedMockLog log; |
|
|
| EXPECT_CALL( |
| log, |
| Send(AllOf(SourceFilename(Eq("/my/very/very/very_long_source_file.cc")), |
| SourceBasename(Eq("very_long_source_file.cc")), |
| SourceLine(Eq(777)), ThreadID(Eq(absl::LogEntry::tid_t{1234})), |
| TextMessageWithPrefix(Truly([](absl::string_view msg) { |
| return absl::EndsWith( |
| msg, " very_long_source_file.cc:777] Info message"); |
| }))))); |
|
|
| log.StartCapturingLogs(); |
| LOG(INFO) |
| .AtLocation("/my/very/very/very_long_source_file.cc", 777) |
| .WithThreadID(1234) |
| << "Info message"; |
| } |
|
|
| TEST(ScopedMockLogTest, ScopedMockLogCanBeNice) { |
| absl::ScopedMockLog log; |
|
|
| InSequence s; |
| EXPECT_CALL(log, |
| Log(absl::LogSeverity::kWarning, HasSubstr(__FILE__), "Danger.")); |
| EXPECT_CALL(log, Log(absl::LogSeverity::kInfo, _, "Working...")).Times(2); |
| EXPECT_CALL(log, Log(absl::LogSeverity::kError, _, "Bad!!")); |
|
|
| log.StartCapturingLogs(); |
|
|
| |
| LOG(INFO) << "Info message."; |
| |
| LOG(WARNING).AtLocation("SomeOtherFile.cc", 100) << "Danger "; |
|
|
| LOG(WARNING) << "Danger."; |
|
|
| |
| LOG(INFO) << "Info message."; |
| |
| LOG(WARNING).AtLocation("SomeOtherFile.cc", 100) << "Danger "; |
|
|
| LOG(INFO) << "Working..."; |
|
|
| |
| LOG(INFO) << "Info message."; |
| |
| LOG(WARNING).AtLocation("SomeOtherFile.cc", 100) << "Danger "; |
|
|
| LOG(INFO) << "Working..."; |
|
|
| |
| LOG(INFO) << "Info message."; |
| |
| LOG(WARNING).AtLocation("SomeOtherFile.cc", 100) << "Danger "; |
|
|
| LOG(ERROR) << "Bad!!"; |
|
|
| |
| LOG(INFO) << "Info message."; |
| |
| LOG(WARNING).AtLocation("SomeOtherFile.cc", 100) << "Danger "; |
| } |
|
|
| |
| |
| TEST(ScopedMockLogTest, RejectsUnexpectedLogs) { |
| EXPECT_NONFATAL_FAILURE( |
| { |
| absl::ScopedMockLog log(absl::MockLogDefault::kDisallowUnexpected); |
| |
| EXPECT_CALL(log, Log(Lt(absl::LogSeverity::kError), _, _)) |
| .Times(AnyNumber()); |
| log.StartCapturingLogs(); |
| LOG(INFO) << "Ignored"; |
| LOG(WARNING) << "Ignored"; |
| LOG(ERROR) << "Should not be ignored"; |
| }, |
| "Should not be ignored"); |
| } |
|
|
| TEST(ScopedMockLogTest, CapturesLogsAfterStartCapturingLogs) { |
| absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfinity); |
| absl::ScopedMockLog log; |
|
|
| |
| |
| LOG(INFO) << "Ignored info"; |
| LOG(WARNING) << "Ignored warning"; |
| LOG(ERROR) << "Ignored error"; |
|
|
| EXPECT_CALL(log, Log(absl::LogSeverity::kInfo, _, "Expected info")); |
| log.StartCapturingLogs(); |
|
|
| |
| LOG(INFO) << "Expected info"; |
| } |
|
|
| TEST(ScopedMockLogTest, DoesNotCaptureLogsAfterStopCapturingLogs) { |
| absl::ScopedMockLog log; |
| EXPECT_CALL(log, Log(absl::LogSeverity::kInfo, _, "Expected info")); |
|
|
| log.StartCapturingLogs(); |
|
|
| |
| LOG(INFO) << "Expected info"; |
|
|
| log.StopCapturingLogs(); |
|
|
| |
| |
| LOG(INFO) << "Ignored info"; |
| LOG(WARNING) << "Ignored warning"; |
| LOG(ERROR) << "Ignored error"; |
| } |
|
|
| |
| |
| TEST(ScopedMockLogTest, LogFromMultipleThreads) { |
| absl::ScopedMockLog log; |
|
|
| |
| |
| EXPECT_CALL(log, Log(absl::LogSeverity::kInfo, __FILE__, "Thread 1")); |
| EXPECT_CALL(log, Log(absl::LogSeverity::kInfo, __FILE__, "Thread 2")); |
|
|
| log.StartCapturingLogs(); |
|
|
| absl::Barrier barrier(2); |
| std::thread thread1([&barrier]() { |
| barrier.Block(); |
| LOG(INFO) << "Thread 1"; |
| }); |
| std::thread thread2([&barrier]() { |
| barrier.Block(); |
| LOG(INFO) << "Thread 2"; |
| }); |
|
|
| thread1.join(); |
| thread2.join(); |
| } |
|
|
| |
| |
| |
| TEST(ScopedMockLogTest, NoSequenceWithMultipleThreads) { |
| absl::ScopedMockLog log; |
|
|
| absl::Barrier barrier(2); |
| EXPECT_CALL(log, Log(absl::LogSeverity::kInfo, _, _)) |
| .Times(2) |
| .WillRepeatedly([&barrier]() { barrier.Block(); }); |
|
|
| log.StartCapturingLogs(); |
|
|
| std::thread thread1([]() { LOG(INFO) << "Thread 1"; }); |
| std::thread thread2([]() { LOG(INFO) << "Thread 2"; }); |
|
|
| thread1.join(); |
| thread2.join(); |
| } |
|
|
| TEST(ScopedMockLogTsanTest, |
| ScopedMockLogCanBeDeletedWhenAnotherThreadIsLogging) { |
| auto log = absl::make_unique<absl::ScopedMockLog>(); |
| EXPECT_CALL(*log, Log(absl::LogSeverity::kInfo, __FILE__, "Thread log")) |
| .Times(AnyNumber()); |
|
|
| log->StartCapturingLogs(); |
|
|
| absl::Notification logging_started; |
|
|
| std::thread thread([&logging_started]() { |
| for (int i = 0; i < 100; ++i) { |
| if (i == 50) logging_started.Notify(); |
| LOG(INFO) << "Thread log"; |
| } |
| }); |
|
|
| logging_started.WaitForNotification(); |
| log.reset(); |
| thread.join(); |
| } |
|
|
| TEST(ScopedMockLogTest, AsLocalSink) { |
| absl::ScopedMockLog log(absl::MockLogDefault::kDisallowUnexpected); |
|
|
| EXPECT_CALL(log, Log(_, _, "two")); |
| EXPECT_CALL(log, Log(_, _, "three")); |
|
|
| LOG(INFO) << "one"; |
| LOG(INFO).ToSinkOnly(&log.UseAsLocalSink()) << "two"; |
| LOG(INFO).ToSinkAlso(&log.UseAsLocalSink()) << "three"; |
| } |
|
|
| } |
|
|