Abseil Common Libraries (C++) (grcp 依赖)
https://abseil.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
290 lines
8.6 KiB
290 lines
8.6 KiB
// |
|
// Copyright 2022 The Abseil Authors. |
|
// |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// https://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
|
|
#include "absl/log/scoped_mock_log.h" |
|
|
|
#include <memory> |
|
#include <thread> // NOLINT(build/c++11) |
|
|
|
#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"); |
|
} |
|
#endif |
|
|
|
// Tests that ScopedMockLog intercepts LOG()s when it's alive. |
|
TEST(ScopedMockLogTest, LogMockCatchAndMatchStrictExpectations) { |
|
absl::ScopedMockLog log; |
|
|
|
// The following expectations must match in the order they appear. |
|
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(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(); |
|
|
|
// Any number of these are OK. |
|
LOG(INFO) << "Info message."; |
|
// Any number of these are OK. |
|
LOG(WARNING).AtLocation("SomeOtherFile.cc", 100) << "Danger "; |
|
|
|
LOG(WARNING) << "Danger."; |
|
|
|
// Any number of these are OK. |
|
LOG(INFO) << "Info message."; |
|
// Any number of these are OK. |
|
LOG(WARNING).AtLocation("SomeOtherFile.cc", 100) << "Danger "; |
|
|
|
LOG(INFO) << "Working..."; |
|
|
|
// Any number of these are OK. |
|
LOG(INFO) << "Info message."; |
|
// Any number of these are OK. |
|
LOG(WARNING).AtLocation("SomeOtherFile.cc", 100) << "Danger "; |
|
|
|
LOG(INFO) << "Working..."; |
|
|
|
// Any number of these are OK. |
|
LOG(INFO) << "Info message."; |
|
// Any number of these are OK. |
|
LOG(WARNING).AtLocation("SomeOtherFile.cc", 100) << "Danger "; |
|
|
|
LOG(ERROR) << "Bad!!"; |
|
|
|
// Any number of these are OK. |
|
LOG(INFO) << "Info message."; |
|
// Any number of these are OK. |
|
LOG(WARNING).AtLocation("SomeOtherFile.cc", 100) << "Danger "; |
|
} |
|
|
|
// Tests that ScopedMockLog generates a test failure if a message is logged |
|
// that is not expected (here, that means ERROR or FATAL). |
|
TEST(ScopedMockLogTest, RejectsUnexpectedLogs) { |
|
EXPECT_NONFATAL_FAILURE( |
|
{ |
|
absl::ScopedMockLog log(absl::MockLogDefault::kDisallowUnexpected); |
|
// Any INFO and WARNING messages are permitted. |
|
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; |
|
|
|
// The ScopedMockLog object shouldn't see these LOGs, as it hasn't |
|
// started capturing LOGs yet. |
|
LOG(INFO) << "Ignored info"; |
|
LOG(WARNING) << "Ignored warning"; |
|
LOG(ERROR) << "Ignored error"; |
|
|
|
EXPECT_CALL(log, Log(absl::LogSeverity::kInfo, _, "Expected info")); |
|
log.StartCapturingLogs(); |
|
|
|
// Only this LOG will be seen by the ScopedMockLog. |
|
LOG(INFO) << "Expected info"; |
|
} |
|
|
|
TEST(ScopedMockLogTest, DoesNotCaptureLogsAfterStopCapturingLogs) { |
|
absl::ScopedMockLog log; |
|
EXPECT_CALL(log, Log(absl::LogSeverity::kInfo, _, "Expected info")); |
|
|
|
log.StartCapturingLogs(); |
|
|
|
// This LOG should be seen by the ScopedMockLog. |
|
LOG(INFO) << "Expected info"; |
|
|
|
log.StopCapturingLogs(); |
|
|
|
// The ScopedMockLog object shouldn't see these LOGs, as it has |
|
// stopped capturing LOGs. |
|
LOG(INFO) << "Ignored info"; |
|
LOG(WARNING) << "Ignored warning"; |
|
LOG(ERROR) << "Ignored error"; |
|
} |
|
|
|
// Tests that all messages are intercepted regardless of issuing thread. The |
|
// purpose of this test is NOT to exercise thread-safety. |
|
TEST(ScopedMockLogTest, LogFromMultipleThreads) { |
|
absl::ScopedMockLog log; |
|
|
|
// We don't establish an order to expectations here, since the threads may |
|
// execute their log statements in different order. |
|
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(); |
|
} |
|
|
|
// Tests that no sequence will be imposed on two LOG message expectations from |
|
// different threads. This test would actually deadlock if replaced to two LOG |
|
// statements from the same thread. |
|
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"; |
|
} |
|
|
|
} // namespace
|
|
|