Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1745)

Unified Diff: base/logging_unittest.cc

Issue 1193873004: Make CHECK_EQ and friends work properly in an if/else structure without braces. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Proposed re-working of unit-tests. Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« base/logging.h ('K') | « base/logging.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« base/logging.h ('K') | « base/logging.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698