Index: base/logging_unittest.cc |
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc |
index 8b9701a545fbf99415bcf9f640c2000380ed7549..17836e9b9ef41ef88e47a51a5f7e8b23f635e58f 100644 |
--- a/base/logging_unittest.cc |
+++ b/base/logging_unittest.cc |
@@ -24,6 +24,74 @@ void LogSink(const std::string& str) { |
} |
#endif |
+template <int N> |
+class ExpectNLogs { |
+ public: |
+ ExpectNLogs() : previous_log_sing_call_count_(log_sink_call_count) {} |
+ virtual ~ExpectNLogs() { |
+ EXPECT_EQ(previous_log_sing_call_count_ + N, log_sink_call_count); |
+ } |
+ |
+ private: |
+ int n_; |
+ int previous_log_sing_call_count_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ExpectNLogs); |
+}; |
+ |
+using ExpectNoLogs = ExpectNLogs<0>; |
+using ExpectOneLog = ExpectNLogs<1>; |
+using ExpectOneLogIfDCheckIsOn = ExpectNLogs<DCHECK_IS_ON() ? 1 : 0>; |
+ |
+class NeverEvaluated { |
+ public: |
+ NeverEvaluated() {} |
+ virtual ~NeverEvaluated() {} |
+ operator bool() { |
+ LOG(FATAL) << "Unexpectedly evaluated."; |
+ return false; |
+ }; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(NeverEvaluated); |
+}; |
+ |
+class EvaluatedOnce { |
+ public: |
+ explicit EvaluatedOnce(bool value) : value_(value) {} |
+ virtual ~EvaluatedOnce() { |
+ LOG_IF(FATAL, evaluations_ != 1) |
+ << "Expected to be evaluated exactly once."; |
+ } |
+ |
+ operator bool() { |
+ LOG_IF(FATAL, evaluations_ > 0) |
+ << "Unexpectedly evaluated more than once."; |
+ ++evaluations_; |
+ return value_; |
+ }; |
+ |
+ private: |
+ bool value_; |
+ int evaluations_ = 0; |
+ DISALLOW_COPY_AND_ASSIGN(EvaluatedOnce); |
+}; |
+ |
+#if DCHECK_IS_ON() |
+class EvaluatedOnceIfDCheckIsOn : public EvaluatedOnce { |
+ public: |
+ EvaluatedOnceIfDCheckIsOn(bool value) : EvaluatedOnce(value) {} |
+#else |
+class EvaluatedOnceIfDCheckIsOn : public NeverEvaluated { |
+ public: |
+ EvaluatedOnceIfDCheckIsOn(bool /* value */) {} |
+#endif // DCHECK_IS_ON |
+ ~EvaluatedOnceIfDCheckIsOn() override {} |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(EvaluatedOnceIfDCheckIsOn); |
+}; |
+ |
// Class to make sure any manipulations we do to the min log level are |
// contained (i.e., do not affect other unit tests). |
class LogStateSaver { |
@@ -234,6 +302,361 @@ TEST_F(LoggingTest, DcheckReleaseBehavior) { |
DCHECK_EQ(some_variable, 1) << "test"; |
} |
+// Test that DCHECK acts as a single statement in variety of syntactice |
+// situations. |
+TEST_F(LoggingTest, DCheckStatements) { |
+ SetLogAssertHandler(&LogSink); |
+ |
+ { |
+ EvaluatedOnceIfDCheckIsOn bool_expr(true); |
+ NeverEvaluated bool_expr_unreached; |
+ ExpectNoLogs expect_no_logs; |
+ if (false) |
+ DCHECK(bool_expr_unreached); |
+ else |
+ DCHECK(bool_expr); |
+ } |
+ |
+ { |
+ EvaluatedOnceIfDCheckIsOn bool_expr(true); |
+ NeverEvaluated bool_expr_unreached; |
+ ExpectNoLogs expect_no_logs; |
+ if (true) |
+ DCHECK(bool_expr); |
+ else |
+ DCHECK(bool_expr_unreached); |
+ } |
+ |
+ { |
+ EvaluatedOnceIfDCheckIsOn bool_expr(true); |
+ NeverEvaluated bool_expr_unreached; |
+ ExpectNoLogs expect_no_logs; |
+ switch (2) { |
+ case 1: |
+ DCHECK(bool_expr_unreached); |
+ case 2: |
+ DCHECK(bool_expr); |
+ default: |
+ break; |
+ } |
+ } |
+ |
+ // Cases with failing checks. |
+ { |
+ EvaluatedOnceIfDCheckIsOn bool_expr_false(false); |
+ NeverEvaluated bool_expr_unreached; |
+ ExpectOneLogIfDCheckIsOn expect_one_dlog; |
+ if (false) |
+ DCHECK(bool_expr_unreached); |
+ else |
+ DCHECK(bool_expr_false); |
+ } |
+ |
+ { |
+ EvaluatedOnceIfDCheckIsOn bool_expr_false(false); |
+ NeverEvaluated bool_expr_unreached; |
+ ExpectOneLogIfDCheckIsOn expect_one_dlog; |
+ if (true) |
+ DCHECK(bool_expr_false); |
+ else |
+ DCHECK(bool_expr_unreached); |
+ } |
+ |
+ { |
+ EvaluatedOnceIfDCheckIsOn bool_expr_false(false); |
+ NeverEvaluated bool_expr_unreached; |
+ ExpectOneLogIfDCheckIsOn expect_one_dlog; |
+ switch (2) { |
+ case 1: |
+ DCHECK(bool_expr_unreached); |
+ case 2: |
+ DCHECK(bool_expr_false); |
+ default: |
+ break; |
+ } |
+ } |
+} |
+ |
+TEST_F(LoggingTest, CheckStatements) { |
+ SetLogAssertHandler(&LogSink); |
+ |
+ EXPECT_EQ(0, log_sink_call_count); |
+ |
+ bool reached = false; |
+ if (false) |
+ CHECK(false); |
+ else |
+ CHECK(reached = true); |
+ ASSERT_TRUE(reached); |
+ |
+ reached = false; |
+ if (true) |
+ CHECK(reached = true); |
+ else |
+ CHECK(false); |
+ ASSERT_TRUE(reached); |
+ |
+ reached = false; |
+ switch (2) { |
+ case 1: |
+ CHECK(false); |
+ case 2: |
+ CHECK(reached=true); |
+ default: |
+ break; |
+ } |
+ ASSERT_TRUE(reached); |
+ |
+ // Cases with failing checks. |
+ EXPECT_EQ(0, log_sink_call_count); |
+ |
+ reached = false; |
+ if (false) |
+ CHECK(reached = true); |
+ else |
+ CHECK(false); |
+ ASSERT_FALSE(reached); |
+ ASSERT_EQ(1, log_sink_call_count); |
+ |
+ reached = false; |
+ if (true) |
+ CHECK(false); |
+ else |
+ CHECK(reached = true); |
+ ASSERT_FALSE(reached); |
+ ASSERT_EQ(2, log_sink_call_count); |
+ |
+ reached = false; |
+ switch (2) { |
+ case 1: |
+ CHECK(reached = true); |
+ case 2: |
+ CHECK(false); |
+ default: |
+ break; |
+ } |
+ ASSERT_FALSE(reached); |
+ ASSERT_EQ(3, log_sink_call_count); |
+} |
+ |
+TEST_F(LoggingTest, DCheckEqStatements) { |
+ SetLogAssertHandler(&LogSink); |
+ |
+ EXPECT_EQ(0, log_sink_call_count); |
+ |
+ bool reached = false; |
+ if (false) |
+ DCHECK_EQ(false, true); |
+ else |
+ DCHECK_EQ(true, reached = true); |
+ ASSERT_EQ(DCHECK_IS_ON(), reached); |
+ |
+ reached = false; |
+ if (true) |
+ DCHECK_EQ(true, reached = true); |
+ else |
+ DCHECK_EQ(false, true); |
+ ASSERT_EQ(DCHECK_IS_ON(), reached); |
+ |
+ reached = false; |
+ switch (2) { |
+ case 1: |
+ DCHECK_EQ(false, true); |
+ case 2: |
+ DCHECK_EQ(true, reached=true); |
+ default: |
+ break; |
+ } |
+ ASSERT_EQ(DCHECK_IS_ON(), reached); |
+ |
+ // Cases with failing checks. |
+ EXPECT_EQ(0, log_sink_call_count); |
+ |
+ reached = false; |
+ if (false) |
+ DCHECK_EQ(true, reached = true); |
+ else |
+ DCHECK_EQ(false, true); |
+ ASSERT_FALSE(reached); |
+ ASSERT_EQ(DCHECK_IS_ON() ? 1 : 0, log_sink_call_count); |
+ |
+ reached = false; |
+ if (true) |
+ DCHECK_EQ(false, true); |
+ else |
+ DCHECK_EQ(true, reached = true); |
+ ASSERT_FALSE(reached); |
+ ASSERT_EQ(DCHECK_IS_ON() ? 2 : 0, log_sink_call_count); |
+ |
+ reached = false; |
+ switch (2) { |
+ case 1: |
+ DCHECK_EQ(true, reached = true); |
+ case 2: |
+ DCHECK_EQ(false, true); |
+ default: |
+ break; |
+ } |
+ ASSERT_FALSE(reached); |
+ ASSERT_EQ(DCHECK_IS_ON() ? 3 : 0, log_sink_call_count); |
+ |
+ reached = false; |
+ if (false) |
+ DCHECK_EQ(false, reached = true); |
+ ASSERT_FALSE(reached); |
+ ASSERT_EQ(DCHECK_IS_ON() ? 3 : 0, log_sink_call_count); |
+} |
+ |
+TEST_F(LoggingTest, CheckEqStatements) { |
+ SetLogAssertHandler(&LogSink); |
+ |
+ EXPECT_EQ(0, log_sink_call_count); |
+ |
+ bool reached = false; |
+ if (false) |
+ CHECK_EQ(false, true); |
+ else |
+ CHECK_EQ(true, reached = true); |
+ ASSERT_TRUE(reached); |
+ |
+ reached = false; |
+ if (true) |
+ CHECK_EQ(true, reached = true); |
+ else |
+ CHECK_EQ(false, true); |
+ ASSERT_TRUE(reached); |
+ |
+ reached = false; |
+ switch (2) { |
+ case 1: |
+ CHECK_EQ(false, true); |
+ case 2: |
+ CHECK_EQ(true, reached = true); |
+ default: |
+ break; |
+ } |
+ ASSERT_TRUE(reached); |
+ |
+ // Cases with failing checks. |
+ EXPECT_EQ(0, log_sink_call_count); |
+ |
+ reached = false; |
+ if (false) |
+ CHECK_EQ(true, reached = true); |
+ else |
+ CHECK_EQ(false, true); |
+ ASSERT_FALSE(reached); |
+ ASSERT_EQ(1, log_sink_call_count); |
+ |
+ reached = false; |
+ if (true) |
+ CHECK_EQ(false, true); |
+ else |
+ CHECK_EQ(true, reached = true); |
+ ASSERT_FALSE(reached); |
+ ASSERT_EQ(2, log_sink_call_count); |
+ |
+ reached = false; |
+ switch (2) { |
+ case 1: |
+ CHECK_EQ(true, reached = true); |
+ case 2: |
+ CHECK_EQ(false, true); |
+ default: |
+ break; |
+ } |
+ ASSERT_FALSE(reached); |
+ ASSERT_EQ(3, log_sink_call_count); |
+ |
+ reached = false; |
+ if (false) |
+ CHECK_EQ(false, reached = true); |
+ ASSERT_FALSE(reached); |
+ ASSERT_EQ(3, log_sink_call_count); |
+} |
+ |
+TEST_F(LoggingTest, LogStatements) { |
+ bool reached = false; |
+ if (true) |
+ LOG(INFO) << "Hello: " << (reached = true); |
+ else |
+ LOG(FATAL) << "Goodbye."; |
+ ASSERT_TRUE(reached); |
+ |
+ reached = false; |
+ if (false) |
+ LOG(FATAL) << "Goodbye."; |
+ else |
+ LOG(INFO) << "Hello: " << (reached = true); |
+ ASSERT_TRUE(reached); |
+ |
+ reached = false; |
+ if (true) |
+ LOG_IF(INFO, reached = true) << "Hello."; |
+ else |
+ LOG_IF(FATAL, true) << "Goodbye."; |
+ ASSERT_TRUE(reached); |
+ |
+ reached = false; |
+ if (false) |
+ LOG_IF(FATAL, true) << "Goodbye."; |
+ else |
+ LOG_IF(INFO, reached = true) << "Hello."; |
+ ASSERT_TRUE(reached); |
+ |
+ reached = false; |
+ if (false) |
+ LOG_IF(FATAL, true) << "Goodbye."; |
+ else |
+ LOG_IF(INFO, false) << "Derp: " << (reached = true); |
+ ASSERT_FALSE(reached); |
+ |
+ reached = false; |
+ if (false) |
+ LOG_IF(FATAL, reached = true) << "Goodbye."; |
+ ASSERT_FALSE(reached); |
+ |
+ reached = false; |
+ if (true) |
+ DLOG(INFO) << "Hello: " << (reached = true); |
+ else |
+ DLOG(FATAL) << "Goodbye."; |
+ ASSERT_EQ(DLOG_IS_ON(INFO), reached); |
+ |
+ reached = false; |
+ if (false) |
+ DLOG(FATAL) << "Goodbye."; |
+ else |
+ DLOG(INFO) << "Hello: " << (reached = true); |
+ ASSERT_EQ(DLOG_IS_ON(INFO), reached); |
+ |
+ reached = false; |
+ if (true) |
+ DLOG_IF(INFO, true) << "Hello: " << (reached = true); |
+ else |
+ DLOG_IF(FATAL, true) << "Goodbye."; |
+ ASSERT_EQ(DLOG_IS_ON(INFO), reached); |
+ |
+ reached = false; |
+ if (false) |
+ DLOG_IF(FATAL, true) << "Goodbye."; |
+ else |
+ DLOG_IF(INFO, true) << "Hello: " << (reached = true); |
+ ASSERT_EQ(DLOG_IS_ON(INFO), reached); |
+ |
+ reached = false; |
+ if (false) |
+ DLOG_IF(FATAL, true) << "Goodbye."; |
+ else |
+ DLOG_IF(INFO, false) << "Derp: " << (reached = true); |
+ ASSERT_FALSE(reached); |
+ |
+ reached = false; |
+ if (false) |
+ DLOG_IF(FATAL, reached = true) << "Goodbye."; |
+ ASSERT_FALSE(reached); |
+} |
+ |
// Test that defining an operator<< for a type in a namespace doesn't prevent |
// other code in that namespace from calling the operator<<(ostream, wstring) |
// defined by logging.h. This can fail if operator<<(ostream, wstring) can't be |