log_macro_hygiene_test.cc (5511B)
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 "gmock/gmock.h" 17 #include "gtest/gtest.h" 18 #include "absl/base/attributes.h" 19 #include "absl/base/log_severity.h" 20 #include "absl/log/log.h" 21 #include "absl/log/scoped_mock_log.h" 22 23 namespace { 24 using ::testing::_; 25 using ::testing::Eq; 26 27 namespace not_absl { 28 29 class Dummy { 30 public: 31 Dummy() {} 32 33 private: 34 Dummy(const Dummy&) = delete; 35 Dummy& operator=(const Dummy&) = delete; 36 }; 37 38 // This line tests that local definitions of INFO, WARNING, ERROR, and 39 // etc don't shadow the global ones used by the logging macros. If 40 // they do, the LOG() calls in the tests won't compile, catching the 41 // bug. 42 const Dummy INFO, WARNING, ERROR, FATAL, NUM_SEVERITIES; 43 44 // These makes sure that the uses of same-named types in the 45 // implementation of the logging macros are fully qualified. 46 class string {}; 47 class vector {}; 48 class LogMessage {}; 49 class LogMessageFatal {}; 50 class LogMessageQuietlyFatal {}; 51 class LogMessageVoidify {}; 52 class LogSink {}; 53 class NullStream {}; 54 class NullStreamFatal {}; 55 56 } // namespace not_absl 57 58 using namespace not_absl; // NOLINT 59 60 // Tests for LOG(LEVEL(()). 61 62 TEST(LogHygieneTest, WorksForQualifiedSeverity) { 63 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); 64 65 ::testing::InSequence seq; 66 EXPECT_CALL(test_sink, Log(absl::LogSeverity::kInfo, _, "To INFO")); 67 EXPECT_CALL(test_sink, Log(absl::LogSeverity::kWarning, _, "To WARNING")); 68 EXPECT_CALL(test_sink, Log(absl::LogSeverity::kError, _, "To ERROR")); 69 70 test_sink.StartCapturingLogs(); 71 // Note that LOG(LEVEL()) expects the severity as a run-time 72 // expression (as opposed to a compile-time constant). Hence we 73 // test that :: is allowed before INFO, etc. 74 LOG(LEVEL(absl::LogSeverity::kInfo)) << "To INFO"; 75 LOG(LEVEL(absl::LogSeverity::kWarning)) << "To WARNING"; 76 LOG(LEVEL(absl::LogSeverity::kError)) << "To ERROR"; 77 } 78 79 TEST(LogHygieneTest, WorksWithAlternativeINFOSymbol) { 80 const double INFO ABSL_ATTRIBUTE_UNUSED = 7.77; 81 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); 82 83 EXPECT_CALL(test_sink, Log(absl::LogSeverity::kInfo, _, "Hello world")); 84 85 test_sink.StartCapturingLogs(); 86 LOG(INFO) << "Hello world"; 87 } 88 89 TEST(LogHygieneTest, WorksWithAlternativeWARNINGSymbol) { 90 const double WARNING ABSL_ATTRIBUTE_UNUSED = 7.77; 91 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); 92 93 EXPECT_CALL(test_sink, Log(absl::LogSeverity::kWarning, _, "Hello world")); 94 95 test_sink.StartCapturingLogs(); 96 LOG(WARNING) << "Hello world"; 97 } 98 99 TEST(LogHygieneTest, WorksWithAlternativeERRORSymbol) { 100 const double ERROR ABSL_ATTRIBUTE_UNUSED = 7.77; 101 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); 102 103 EXPECT_CALL(test_sink, Log(absl::LogSeverity::kError, _, "Hello world")); 104 105 test_sink.StartCapturingLogs(); 106 LOG(ERROR) << "Hello world"; 107 } 108 109 TEST(LogHygieneTest, WorksWithAlternativeLEVELSymbol) { 110 const double LEVEL ABSL_ATTRIBUTE_UNUSED = 7.77; 111 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); 112 113 EXPECT_CALL(test_sink, Log(absl::LogSeverity::kError, _, "Hello world")); 114 115 test_sink.StartCapturingLogs(); 116 LOG(LEVEL(absl::LogSeverity::kError)) << "Hello world"; 117 } 118 119 #define INFO Bogus 120 #ifdef NDEBUG 121 constexpr bool IsOptimized = false; 122 #else 123 constexpr bool IsOptimized = true; 124 #endif 125 126 TEST(LogHygieneTest, WorksWithINFODefined) { 127 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); 128 129 EXPECT_CALL(test_sink, Log(absl::LogSeverity::kInfo, _, "Hello world")) 130 .Times(2 + (IsOptimized ? 2 : 0)); 131 132 test_sink.StartCapturingLogs(); 133 LOG(INFO) << "Hello world"; 134 LOG_IF(INFO, true) << "Hello world"; 135 136 DLOG(INFO) << "Hello world"; 137 DLOG_IF(INFO, true) << "Hello world"; 138 } 139 140 #undef INFO 141 142 #define _INFO Bogus 143 TEST(LogHygieneTest, WorksWithUnderscoreINFODefined) { 144 absl::ScopedMockLog test_sink(absl::MockLogDefault::kDisallowUnexpected); 145 146 EXPECT_CALL(test_sink, Log(absl::LogSeverity::kInfo, _, "Hello world")) 147 .Times(2 + (IsOptimized ? 2 : 0)); 148 149 test_sink.StartCapturingLogs(); 150 LOG(INFO) << "Hello world"; 151 LOG_IF(INFO, true) << "Hello world"; 152 153 DLOG(INFO) << "Hello world"; 154 DLOG_IF(INFO, true) << "Hello world"; 155 } 156 #undef _INFO 157 158 TEST(LogHygieneTest, ExpressionEvaluationInLEVELSeverity) { 159 auto i = static_cast<int>(absl::LogSeverity::kInfo); 160 LOG(LEVEL(++i)) << "hello world"; // NOLINT 161 EXPECT_THAT(i, Eq(static_cast<int>(absl::LogSeverity::kInfo) + 1)); 162 } 163 164 TEST(LogHygieneTest, ExpressionEvaluationInStreamedMessage) { 165 int i = 0; 166 LOG(INFO) << ++i; 167 EXPECT_THAT(i, 1); 168 LOG_IF(INFO, false) << ++i; 169 EXPECT_THAT(i, 1); 170 } 171 172 // Tests that macros are usable in unbraced switch statements. 173 // ----------------------------------------------------------- 174 175 class UnbracedSwitchCompileTest { 176 static void Log() { 177 switch (0) { 178 case 0: 179 LOG(INFO); 180 break; 181 default: 182 break; 183 } 184 } 185 }; 186 187 } // namespace