| // |
| // 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. |
| |
| // The testcases in this file are expected to pass or be skipped with any value |
| // of ABSL_MIN_LOG_LEVEL |
| |
| #ifndef ABSL_LOG_LOG_BASIC_TEST_IMPL_H_ |
| #define ABSL_LOG_LOG_BASIC_TEST_IMPL_H_ |
| |
| // Verify that both sets of macros behave identically by parameterizing the |
| // entire test file. |
| #ifndef ABSL_TEST_LOG |
| #error ABSL_TEST_LOG must be defined for these tests to work. |
| #endif |
| |
| #include <cerrno> |
| #include <sstream> |
| #include <string> |
| |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| #include "absl/base/internal/sysinfo.h" |
| #include "absl/base/log_severity.h" |
| #include "absl/log/globals.h" |
| #include "absl/log/internal/test_actions.h" |
| #include "absl/log/internal/test_helpers.h" |
| #include "absl/log/internal/test_matchers.h" |
| #include "absl/log/log_entry.h" |
| #include "absl/log/scoped_mock_log.h" |
| |
| namespace absl_log_internal { |
| #if GTEST_HAS_DEATH_TEST |
| using ::absl::log_internal::DeathTestExpectedLogging; |
| using ::absl::log_internal::DeathTestUnexpectedLogging; |
| using ::absl::log_internal::DeathTestValidateExpectations; |
| using ::absl::log_internal::DiedOfFatal; |
| using ::absl::log_internal::DiedOfQFatal; |
| #endif |
| using ::absl::log_internal::LoggingEnabledAt; |
| using ::absl::log_internal::LogSeverity; |
| using ::absl::log_internal::Prefix; |
| using ::absl::log_internal::SourceBasename; |
| using ::absl::log_internal::SourceFilename; |
| using ::absl::log_internal::SourceLine; |
| using ::absl::log_internal::Stacktrace; |
| using ::absl::log_internal::TextMessage; |
| using ::absl::log_internal::ThreadID; |
| using ::absl::log_internal::TimestampInMatchWindow; |
| using ::absl::log_internal::Verbosity; |
| using ::testing::AnyNumber; |
| using ::testing::Eq; |
| using ::testing::IsEmpty; |
| using ::testing::IsTrue; |
| |
| class BasicLogTest : public testing::TestWithParam<absl::LogSeverityAtLeast> {}; |
| |
| std::string ThresholdName( |
| testing::TestParamInfo<absl::LogSeverityAtLeast> severity) { |
| std::stringstream ostr; |
| ostr << severity.param; |
| return ostr.str().substr( |
| severity.param == absl::LogSeverityAtLeast::kInfinity ? 0 : 2); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(WithParam, BasicLogTest, |
| testing::Values(absl::LogSeverityAtLeast::kInfo, |
| absl::LogSeverityAtLeast::kWarning, |
| absl::LogSeverityAtLeast::kError, |
| absl::LogSeverityAtLeast::kFatal, |
| absl::LogSeverityAtLeast::kInfinity), |
| ThresholdName); |
| |
| TEST_P(BasicLogTest, Info) { |
| absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam()); |
| |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int log_line = __LINE__ + 1; |
| auto do_log = [] { ABSL_TEST_LOG(INFO) << "hello world"; }; |
| |
| if (LoggingEnabledAt(absl::LogSeverity::kInfo)) { |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(SourceFilename(Eq(__FILE__)), |
| SourceBasename(Eq("log_basic_test_impl.inc")), |
| SourceLine(Eq(log_line)), Prefix(IsTrue()), |
| LogSeverity(Eq(absl::LogSeverity::kInfo)), |
| TimestampInMatchWindow(), |
| ThreadID(Eq(absl::base_internal::GetTID())), |
| TextMessage(Eq("hello world")), |
| Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)), |
| ENCODED_MESSAGE(EqualsProto(R"pb(value { |
| literal: "hello world" |
| })pb")), |
| Stacktrace(IsEmpty())))); |
| } |
| |
| test_sink.StartCapturingLogs(); |
| do_log(); |
| } |
| |
| TEST_P(BasicLogTest, Warning) { |
| absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam()); |
| |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int log_line = __LINE__ + 1; |
| auto do_log = [] { ABSL_TEST_LOG(WARNING) << "hello world"; }; |
| |
| if (LoggingEnabledAt(absl::LogSeverity::kWarning)) { |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(SourceFilename(Eq(__FILE__)), |
| SourceBasename(Eq("log_basic_test_impl.inc")), |
| SourceLine(Eq(log_line)), Prefix(IsTrue()), |
| LogSeverity(Eq(absl::LogSeverity::kWarning)), |
| TimestampInMatchWindow(), |
| ThreadID(Eq(absl::base_internal::GetTID())), |
| TextMessage(Eq("hello world")), |
| Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)), |
| ENCODED_MESSAGE(EqualsProto(R"pb(value { |
| literal: "hello world" |
| })pb")), |
| Stacktrace(IsEmpty())))); |
| } |
| |
| test_sink.StartCapturingLogs(); |
| do_log(); |
| } |
| |
| TEST_P(BasicLogTest, Error) { |
| absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam()); |
| |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int log_line = __LINE__ + 1; |
| auto do_log = [] { ABSL_TEST_LOG(ERROR) << "hello world"; }; |
| |
| if (LoggingEnabledAt(absl::LogSeverity::kError)) { |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(SourceFilename(Eq(__FILE__)), |
| SourceBasename(Eq("log_basic_test_impl.inc")), |
| SourceLine(Eq(log_line)), Prefix(IsTrue()), |
| LogSeverity(Eq(absl::LogSeverity::kError)), |
| TimestampInMatchWindow(), |
| ThreadID(Eq(absl::base_internal::GetTID())), |
| TextMessage(Eq("hello world")), |
| Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)), |
| ENCODED_MESSAGE(EqualsProto(R"pb(value { |
| literal: "hello world" |
| })pb")), |
| Stacktrace(IsEmpty())))); |
| } |
| |
| test_sink.StartCapturingLogs(); |
| do_log(); |
| } |
| |
| #if GTEST_HAS_DEATH_TEST |
| using BasicLogDeathTest = BasicLogTest; |
| |
| INSTANTIATE_TEST_SUITE_P(WithParam, BasicLogDeathTest, |
| testing::Values(absl::LogSeverityAtLeast::kInfo, |
| absl::LogSeverityAtLeast::kFatal, |
| absl::LogSeverityAtLeast::kInfinity), |
| ThresholdName); |
| |
| TEST_P(BasicLogDeathTest, Fatal) { |
| absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam()); |
| |
| const int log_line = __LINE__ + 1; |
| auto do_log = [] { ABSL_TEST_LOG(FATAL) << "hello world"; }; |
| |
| EXPECT_EXIT( |
| { |
| absl::ScopedMockLog test_sink( |
| absl::MockLogDefault::kDisallowUnexpected); |
| |
| EXPECT_CALL(test_sink, Send) |
| .Times(AnyNumber()) |
| .WillRepeatedly(DeathTestUnexpectedLogging()); |
| |
| ::testing::InSequence s; |
| |
| // Note the logic in DeathTestValidateExpectations() caters for the case |
| // of logging being disabled at FATAL level. |
| |
| if (LoggingEnabledAt(absl::LogSeverity::kFatal)) { |
| // The first call without the stack trace. |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(SourceFilename(Eq(__FILE__)), |
| SourceBasename(Eq("log_basic_test_impl.inc")), |
| SourceLine(Eq(log_line)), Prefix(IsTrue()), |
| LogSeverity(Eq(absl::LogSeverity::kFatal)), |
| TimestampInMatchWindow(), |
| ThreadID(Eq(absl::base_internal::GetTID())), |
| TextMessage(Eq("hello world")), |
| Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)), |
| ENCODED_MESSAGE(EqualsProto( |
| R"pb(value { literal: "hello world" })pb")), |
| Stacktrace(IsEmpty())))) |
| .WillOnce(DeathTestExpectedLogging()); |
| |
| // The second call with the stack trace. |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(SourceFilename(Eq(__FILE__)), |
| SourceBasename(Eq("log_basic_test_impl.inc")), |
| SourceLine(Eq(log_line)), Prefix(IsTrue()), |
| LogSeverity(Eq(absl::LogSeverity::kFatal)), |
| TimestampInMatchWindow(), |
| ThreadID(Eq(absl::base_internal::GetTID())), |
| TextMessage(Eq("hello world")), |
| Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)), |
| ENCODED_MESSAGE(EqualsProto( |
| R"pb(value { literal: "hello world" })pb")), |
| Stacktrace(Not(IsEmpty()))))) |
| .WillOnce(DeathTestExpectedLogging()); |
| } |
| |
| test_sink.StartCapturingLogs(); |
| do_log(); |
| }, |
| DiedOfFatal, DeathTestValidateExpectations()); |
| } |
| |
| TEST_P(BasicLogDeathTest, QFatal) { |
| absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam()); |
| |
| const int log_line = __LINE__ + 1; |
| auto do_log = [] { ABSL_TEST_LOG(QFATAL) << "hello world"; }; |
| |
| EXPECT_EXIT( |
| { |
| absl::ScopedMockLog test_sink( |
| absl::MockLogDefault::kDisallowUnexpected); |
| |
| EXPECT_CALL(test_sink, Send) |
| .Times(AnyNumber()) |
| .WillRepeatedly(DeathTestUnexpectedLogging()); |
| |
| if (LoggingEnabledAt(absl::LogSeverity::kFatal)) { |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(SourceFilename(Eq(__FILE__)), |
| SourceBasename(Eq("log_basic_test_impl.inc")), |
| SourceLine(Eq(log_line)), Prefix(IsTrue()), |
| LogSeverity(Eq(absl::LogSeverity::kFatal)), |
| TimestampInMatchWindow(), |
| ThreadID(Eq(absl::base_internal::GetTID())), |
| TextMessage(Eq("hello world")), |
| Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)), |
| ENCODED_MESSAGE(EqualsProto( |
| R"pb(value { literal: "hello world" })pb")), |
| Stacktrace(IsEmpty())))) |
| .WillOnce(DeathTestExpectedLogging()); |
| } |
| |
| test_sink.StartCapturingLogs(); |
| do_log(); |
| }, |
| DiedOfQFatal, DeathTestValidateExpectations()); |
| } |
| #endif |
| |
| #ifdef NDEBUG |
| TEST_P(BasicLogTest, DFatal) { |
| absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam()); |
| |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int log_line = __LINE__ + 1; |
| auto do_log = [] { ABSL_TEST_LOG(DFATAL) << "hello world"; }; |
| |
| if (LoggingEnabledAt(absl::LogSeverity::kError)) { |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(SourceFilename(Eq(__FILE__)), |
| SourceBasename(Eq("log_basic_test_impl.inc")), |
| SourceLine(Eq(log_line)), Prefix(IsTrue()), |
| LogSeverity(Eq(absl::LogSeverity::kError)), |
| TimestampInMatchWindow(), |
| ThreadID(Eq(absl::base_internal::GetTID())), |
| TextMessage(Eq("hello world")), |
| Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)), |
| ENCODED_MESSAGE(EqualsProto(R"pb(value { |
| literal: "hello world" |
| })pb")), |
| Stacktrace(IsEmpty())))); |
| } |
| |
| test_sink.StartCapturingLogs(); |
| do_log(); |
| } |
| |
| #elif GTEST_HAS_DEATH_TEST |
| TEST_P(BasicLogDeathTest, DFatal) { |
| // TODO(b/242568884): re-enable once bug is fixed. |
| // absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam()); |
| |
| const int log_line = __LINE__ + 1; |
| auto do_log = [] { ABSL_TEST_LOG(DFATAL) << "hello world"; }; |
| |
| EXPECT_EXIT( |
| { |
| absl::ScopedMockLog test_sink( |
| absl::MockLogDefault::kDisallowUnexpected); |
| |
| EXPECT_CALL(test_sink, Send) |
| .Times(AnyNumber()) |
| .WillRepeatedly(DeathTestUnexpectedLogging()); |
| |
| ::testing::InSequence s; |
| |
| if (LoggingEnabledAt(absl::LogSeverity::kFatal)) { |
| // The first call without the stack trace. |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(SourceFilename(Eq(__FILE__)), |
| SourceBasename(Eq("log_basic_test_impl.inc")), |
| SourceLine(Eq(log_line)), Prefix(IsTrue()), |
| LogSeverity(Eq(absl::LogSeverity::kFatal)), |
| TimestampInMatchWindow(), |
| ThreadID(Eq(absl::base_internal::GetTID())), |
| TextMessage(Eq("hello world")), |
| Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)), |
| ENCODED_MESSAGE(EqualsProto( |
| R"pb(value { literal: "hello world" })pb")), |
| Stacktrace(IsEmpty())))) |
| .WillOnce(DeathTestExpectedLogging()); |
| |
| // The second call with the stack trace. |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(SourceFilename(Eq(__FILE__)), |
| SourceBasename(Eq("log_basic_test_impl.inc")), |
| SourceLine(Eq(log_line)), Prefix(IsTrue()), |
| LogSeverity(Eq(absl::LogSeverity::kFatal)), |
| TimestampInMatchWindow(), |
| ThreadID(Eq(absl::base_internal::GetTID())), |
| TextMessage(Eq("hello world")), |
| Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)), |
| ENCODED_MESSAGE(EqualsProto( |
| R"pb(value { literal: "hello world" })pb")), |
| Stacktrace(Not(IsEmpty()))))) |
| .WillOnce(DeathTestExpectedLogging()); |
| } |
| |
| test_sink.StartCapturingLogs(); |
| do_log(); |
| }, |
| DiedOfFatal, DeathTestValidateExpectations()); |
| } |
| #endif |
| |
| TEST_P(BasicLogTest, Level) { |
| absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam()); |
| |
| for (auto severity : {absl::LogSeverity::kInfo, absl::LogSeverity::kWarning, |
| absl::LogSeverity::kError}) { |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| const int log_line = __LINE__ + 2; |
| auto do_log = [severity] { |
| ABSL_TEST_LOG(LEVEL(severity)) << "hello world"; |
| }; |
| |
| if (LoggingEnabledAt(severity)) { |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(SourceFilename(Eq(__FILE__)), |
| SourceBasename(Eq("log_basic_test_impl.inc")), |
| SourceLine(Eq(log_line)), Prefix(IsTrue()), |
| LogSeverity(Eq(severity)), TimestampInMatchWindow(), |
| ThreadID(Eq(absl::base_internal::GetTID())), |
| TextMessage(Eq("hello world")), |
| Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)), |
| ENCODED_MESSAGE(EqualsProto(R"pb(value { |
| literal: "hello world" |
| })pb")), |
| Stacktrace(IsEmpty())))); |
| } |
| test_sink.StartCapturingLogs(); |
| do_log(); |
| } |
| } |
| |
| #if GTEST_HAS_DEATH_TEST |
| TEST_P(BasicLogDeathTest, Level) { |
| // TODO(b/242568884): re-enable once bug is fixed. |
| // absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam()); |
| |
| // Ensure that `severity` is not a compile-time constant to prove that |
| // `LOG(LEVEL(severity))` works regardless: |
| auto volatile severity = absl::LogSeverity::kFatal; |
| |
| const int log_line = __LINE__ + 1; |
| auto do_log = [severity] { ABSL_TEST_LOG(LEVEL(severity)) << "hello world"; }; |
| |
| EXPECT_EXIT( |
| { |
| absl::ScopedMockLog test_sink( |
| absl::MockLogDefault::kDisallowUnexpected); |
| |
| EXPECT_CALL(test_sink, Send) |
| .Times(AnyNumber()) |
| .WillRepeatedly(DeathTestUnexpectedLogging()); |
| |
| ::testing::InSequence s; |
| |
| if (LoggingEnabledAt(absl::LogSeverity::kFatal)) { |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(SourceFilename(Eq(__FILE__)), |
| SourceBasename(Eq("log_basic_test_impl.inc")), |
| SourceLine(Eq(log_line)), Prefix(IsTrue()), |
| LogSeverity(Eq(absl::LogSeverity::kFatal)), |
| TimestampInMatchWindow(), |
| ThreadID(Eq(absl::base_internal::GetTID())), |
| TextMessage(Eq("hello world")), |
| Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)), |
| ENCODED_MESSAGE(EqualsProto( |
| R"pb(value { literal: "hello world" })pb")), |
| Stacktrace(IsEmpty())))) |
| .WillOnce(DeathTestExpectedLogging()); |
| |
| EXPECT_CALL( |
| test_sink, |
| Send(AllOf(SourceFilename(Eq(__FILE__)), |
| SourceBasename(Eq("log_basic_test_impl.inc")), |
| SourceLine(Eq(log_line)), Prefix(IsTrue()), |
| LogSeverity(Eq(absl::LogSeverity::kFatal)), |
| TimestampInMatchWindow(), |
| ThreadID(Eq(absl::base_internal::GetTID())), |
| TextMessage(Eq("hello world")), |
| Verbosity(Eq(absl::LogEntry::kNoVerbosityLevel)), |
| ENCODED_MESSAGE(EqualsProto( |
| R"pb(value { literal: "hello world" })pb")), |
| Stacktrace(Not(IsEmpty()))))) |
| .WillOnce(DeathTestExpectedLogging()); |
| } |
| |
| test_sink.StartCapturingLogs(); |
| do_log(); |
| }, |
| DiedOfFatal, DeathTestValidateExpectations()); |
| } |
| #endif |
| |
| TEST_P(BasicLogTest, LevelClampsNegativeValues) { |
| absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam()); |
| |
| if (!LoggingEnabledAt(absl::LogSeverity::kInfo)) { |
| GTEST_SKIP() << "This test cases required INFO log to be enabled"; |
| return; |
| } |
| |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| EXPECT_CALL(test_sink, Send(LogSeverity(Eq(absl::LogSeverity::kInfo)))); |
| |
| test_sink.StartCapturingLogs(); |
| ABSL_TEST_LOG(LEVEL(-1)) << "hello world"; |
| } |
| |
| TEST_P(BasicLogTest, LevelClampsLargeValues) { |
| absl::log_internal::ScopedMinLogLevel scoped_min_log_level(GetParam()); |
| |
| if (!LoggingEnabledAt(absl::LogSeverity::kError)) { |
| GTEST_SKIP() << "This test cases required ERROR log to be enabled"; |
| return; |
| } |
| |
| absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); |
| |
| EXPECT_CALL(test_sink, Send(LogSeverity(Eq(absl::LogSeverity::kError)))); |
| |
| test_sink.StartCapturingLogs(); |
| ABSL_TEST_LOG(LEVEL(static_cast<int>(absl::LogSeverity::kFatal) + 1)) |
| << "hello world"; |
| } |
| |
| TEST(ErrnoPreservationTest, InSeverityExpression) { |
| errno = 77; |
| int saved_errno; |
| ABSL_TEST_LOG(LEVEL((saved_errno = errno, absl::LogSeverity::kInfo))); |
| EXPECT_THAT(saved_errno, Eq(77)); |
| } |
| |
| TEST(ErrnoPreservationTest, InStreamedExpression) { |
| if (!LoggingEnabledAt(absl::LogSeverity::kInfo)) { |
| GTEST_SKIP() << "This test cases required INFO log to be enabled"; |
| return; |
| } |
| |
| errno = 77; |
| int saved_errno = 0; |
| ABSL_TEST_LOG(INFO) << (saved_errno = errno, "hello world"); |
| EXPECT_THAT(saved_errno, Eq(77)); |
| } |
| |
| TEST(ErrnoPreservationTest, AfterStatement) { |
| errno = 77; |
| ABSL_TEST_LOG(INFO); |
| const int saved_errno = errno; |
| EXPECT_THAT(saved_errno, Eq(77)); |
| } |
| |
| // Tests that using a variable/parameter in a logging statement suppresses |
| // unused-variable/parameter warnings. |
| // ----------------------------------------------------------------------- |
| class UnusedVariableWarningCompileTest { |
| // These four don't prove anything unless `ABSL_MIN_LOG_LEVEL` is greater than |
| // `kInfo`. |
| static void LoggedVariable() { |
| const int x = 0; |
| ABSL_TEST_LOG(INFO) << x; |
| } |
| static void LoggedParameter(const int x) { ABSL_TEST_LOG(INFO) << x; } |
| static void SeverityVariable() { |
| const int x = 0; |
| ABSL_TEST_LOG(LEVEL(x)) << "hello world"; |
| } |
| static void SeverityParameter(const int x) { |
| ABSL_TEST_LOG(LEVEL(x)) << "hello world"; |
| } |
| }; |
| |
| } // namespace absl_log_internal |
| |
| #endif // ABSL_LOG_LOG_BASIC_TEST_IMPL_H_ |