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

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: More WIP. 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
« no previous file with comments | « 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..765067b03733a1e81e456186e7ca1170573b97e5 100644
--- a/base/logging_unittest.cc
+++ b/base/logging_unittest.cc
@@ -42,6 +42,61 @@ class LogStateSaver {
DISALLOW_COPY_AND_ASSIGN(LogStateSaver);
};
+// Validates that exactly N log messages are received during its lifetime.
+template <int N>
+class ExpectNLogs {
+ public:
+ ExpectNLogs() {
+ SetLogAssertHandler(&LogSink);
+ log_sink_call_count = 0;
+ }
+
+ ~ExpectNLogs() {
+ SetLogAssertHandler(NULL);
+ EXPECT_EQ(N, log_sink_call_count);
+ }
+
+ private:
+ LogStateSaver log_state_saver_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExpectNLogs);
+};
+
+using ExpectNoLogs = ExpectNLogs<0>;
+using ExpectOneLog = ExpectNLogs<1>;
+using ExpectOneLogIfDCheckIsOn = ExpectNLogs<DCHECK_IS_ON() ? 1 : 0>;
+
+// A convenience function to aid in test readability.
+bool UnreachedBoolExpr() {
+ ADD_FAILURE() << "Unexpectedly evaluated.";
+ return false;
+}
+
+// Validates that operator()() is invoked exactly N times.
+template<int N>
+class EvaluatedNTimes {
+ public:
+ EvaluatedNTimes() {}
+ ~EvaluatedNTimes() {
+ EXPECT_EQ(N, evaluations_) << "Expected to be evaluated exactly " << N
+ << " times.";
+ }
+
+ bool operator()() {
+ EXPECT_GT(N, evaluations_) << "Evaluated more than the expected " << N
+ << " times.";
+ ++evaluations_;
+ return true;
+ };
+
+ private:
+ int evaluations_ = 0;
+ DISALLOW_COPY_AND_ASSIGN(EvaluatedNTimes);
+};
+
+using EvaluatedOnce = EvaluatedNTimes<1>;
+using EvaluatedOnceIfDCheckIsOn = EvaluatedNTimes<DCHECK_IS_ON() ? 1 : 0>;
+
class LoggingTest : public testing::Test {
private:
LogStateSaver log_state_saver_;
@@ -234,6 +289,636 @@ TEST_F(LoggingTest, DcheckReleaseBehavior) {
DCHECK_EQ(some_variable, 1) << "test";
}
+// Test that DCHECK acts as a single statement in variety of syntactic
+// situations.
+TEST_F(LoggingTest, DCheckStatements) {
+ // The next three blocks validate that the DCHECK is correctly bound to the
+ // 'if' statement.
+ {
+ ExpectNoLogs expect_no_logs;
+
+ // Unreached DCHECK.
+ if (false)
+ DCHECK(UnreachedBoolExpr());
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
Sigurður Ásgeirsson 2015/07/16 10:51:28 nit: IMHO the use of this would be marginally more
+ ExpectNoLogs expect_no_logs;
+
+ // Reached, successful DCHECK.
+ if (true)
+ DCHECK(bool_expr());
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectOneLogIfDCheckIsOn expect_one_dlog;
+
+ // Reached, failed DCHECK.
+ if (true)
+ DCHECK(!bool_expr());
+ }
+
+ // The following four cases validate that the DCHECK is correctly bound in an
+ // 'if/else' statement.
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Unreached if, successful else.
+ if (false)
+ DCHECK(UnreachedBoolExpr());
+ else
+ DCHECK(bool_expr());
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Successful if, unreached else.
+ if (true)
+ DCHECK(bool_expr());
+ else
+ DCHECK(UnreachedBoolExpr());
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectOneLogIfDCheckIsOn expect_one_dlog;
+
+ // Unreached if, failed else.
+ if (false)
+ DCHECK(UnreachedBoolExpr());
+ else
+ DCHECK(!bool_expr());
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectOneLogIfDCheckIsOn expect_one_dlog;
+
+ // Failed if, unreached else.
+ if (true)
+ DCHECK(!bool_expr());
+ else
+ DCHECK(UnreachedBoolExpr());
+ }
+
+ // These cases validate that a DCHECK may appear in a switch statement.
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectNoLogs expect_no_logs;
+ switch (2) {
+ case 1:
+ DCHECK(UnreachedBoolExpr());
+ case 2:
+ DCHECK(bool_expr());
+ default:
+ break;
+ }
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectOneLogIfDCheckIsOn expect_one_dlog;
+ switch (2) {
+ case 1:
+ DCHECK(UnreachedBoolExpr());
+ case 2:
+ DCHECK(!bool_expr());
+ default:
+ break;
+ }
+ }
+}
+
+// Test that CHECK acts as a single statement in variety of syntactic
+// situations.
+TEST_F(LoggingTest, CheckStatements) {
+ // The next three blocks validate that the CHECK is correctly bound to the
+ // 'if' statement.
+ {
+ ExpectNoLogs expect_no_logs;
+
+ // Unreached CHECK.
+ if (false)
+ CHECK(UnreachedBoolExpr());
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Reached, successful CHECK.
+ if (true)
+ CHECK(bool_expr());
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectOneLog expect_one_log;
+
+ // Reached, failed CHECK.
+ if (true)
+ CHECK(!bool_expr());
+ }
+
+ // The following four cases validate that the CHECK is correctly bound in an
+ // 'if/else' statement.
+ {
+ EvaluatedOnce bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Unreached if, successful else.
+ if (false)
+ CHECK(UnreachedBoolExpr());
+ else
+ CHECK(bool_expr());
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Successful if, unreached else.
+ if (true)
+ CHECK(bool_expr());
+ else
+ CHECK(UnreachedBoolExpr());
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectOneLog expect_one_log;
+
+ // Unreached if, failed else.
+ if (false)
+ CHECK(UnreachedBoolExpr());
+ else
+ CHECK(!bool_expr());
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectOneLog expect_one_log;
+
+ // Failed if, unreached else.
+ if (true)
+ CHECK(!bool_expr());
+ else
+ CHECK(UnreachedBoolExpr());
+ }
+
+ // These cases validate that a CHECK may appear in a switch statement.
+ {
+ EvaluatedOnce bool_expr;
+ ExpectNoLogs expect_no_logs;
+ switch (2) {
+ case 1:
+ CHECK(UnreachedBoolExpr());
+ case 2:
+ CHECK(bool_expr());
+ default:
+ break;
+ }
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectOneLog expect_one_log;
+ switch (2) {
+ case 1:
+ CHECK(UnreachedBoolExpr());
+ case 2:
+ CHECK(!bool_expr());
+ default:
+ break;
+ }
+ }
+}
+
+// Test that DCHECK_EQ acts as a single statement in variety of syntactic
+// situations.
+TEST_F(LoggingTest, DCheckEqStatements) {
+ // The next three blocks validate that the DCHECK_EQ is correctly bound to the
+ // 'if' statement.
+ {
+ ExpectNoLogs expect_no_logs;
+
+ // Unreached DCHECK_EQ.
+ if (false)
+ DCHECK_EQ(false, UnreachedBoolExpr());
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Reached, successful DCHECK_EQ.
+ if (true)
+ DCHECK_EQ(true, bool_expr());
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectOneLogIfDCheckIsOn expect_one_dlog;
+
+ // Reached, failed DCHECK_EQ.
+ if (true)
+ DCHECK_EQ(false, bool_expr());
+ }
+
+ // The following four cases validate that the DCHECK_EQ is correctly bound in
+ // an 'if/else' statement.
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Unreached if, successful else.
+ if (false)
+ DCHECK_EQ(false, UnreachedBoolExpr());
+ else
+ DCHECK_EQ(true, bool_expr());
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Successful if, unreached else.
+ if (true)
+ DCHECK_EQ(true, bool_expr());
+ else
+ DCHECK_EQ(false, UnreachedBoolExpr());
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectOneLogIfDCheckIsOn expect_one_dlog;
+
+ // Unreached if, failed else.
+ if (false)
+ DCHECK_EQ(false, UnreachedBoolExpr());
+ else
+ DCHECK_EQ(false, bool_expr());
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectOneLogIfDCheckIsOn expect_one_dlog;
+
+ // Failed if, unreached else.
+ if (true)
+ DCHECK_EQ(false, bool_expr());
+ else
+ DCHECK_EQ(false, UnreachedBoolExpr());
+ }
+
+ // These cases validate that a DCHECK_EQ may appear in a switch statement.
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectNoLogs expect_no_logs;
+ switch (2) {
+ case 1:
+ DCHECK_EQ(false, UnreachedBoolExpr());
+ case 2:
+ DCHECK_EQ(true, bool_expr());
+ default:
+ break;
+ }
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectOneLogIfDCheckIsOn expect_one_dlog;
+ switch (2) {
+ case 1:
+ DCHECK_EQ(false, UnreachedBoolExpr());
+ case 2:
+ DCHECK_EQ(false, bool_expr());
+ default:
+ break;
+ }
+ }
+}
+
+// Test that CHECK_EQ acts as a single statement in variety of syntactic
+// situations.
+TEST_F(LoggingTest, CheckEqStatements) {
+ // The next three blocks validate that the CHECK_EQ is correctly bound to the
+ // 'if' statement.
+ {
+ ExpectNoLogs expect_no_logs;
+
+ // Unreached CHECK_EQ.
+ if (false)
+ CHECK_EQ(false, UnreachedBoolExpr());
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Reached, successful CHECK_EQ.
+ if (true)
+ CHECK_EQ(true, bool_expr());
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectOneLog expect_one_log;
+
+ // Reached, failed CHECK_EQ.
+ if (true)
+ CHECK_EQ(false, bool_expr());
+ }
+
+ // The following four cases validate that the CHECK_EQ is correctly bound in
+ // an 'if/else' statement.
+ {
+ EvaluatedOnce bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Unreached if, successful else.
+ if (false)
+ CHECK_EQ(false, UnreachedBoolExpr());
+ else
+ CHECK_EQ(true, bool_expr());
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Successful if, unreached else.
+ if (true)
+ CHECK_EQ(true, bool_expr());
+ else
+ CHECK_EQ(false, UnreachedBoolExpr());
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectOneLog expect_one_log;
+
+ // Unreached if, failed else.
+ if (false)
+ CHECK_EQ(false, UnreachedBoolExpr());
+ else
+ CHECK_EQ(false, bool_expr());
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectOneLog expect_one_log;
+
+ // Failed if, unreached else.
+ if (true)
+ CHECK_EQ(false, bool_expr());
+ else
+ CHECK_EQ(false, UnreachedBoolExpr());
+ }
+
+ // These cases validate that a CHECK_EQ may appear in a switch statement.
+ {
+ EvaluatedOnce bool_expr;
+ ExpectNoLogs expect_no_logs;
+ switch (2) {
+ case 1:
+ CHECK_EQ(false, UnreachedBoolExpr());
+ case 2:
+ CHECK_EQ(true, bool_expr());
+ default:
+ break;
+ }
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectOneLog expect_one_log;
+ switch (2) {
+ case 1:
+ CHECK_EQ(false, UnreachedBoolExpr());
+ case 2:
+ CHECK_EQ(false, bool_expr());
+ default:
+ break;
+ }
+ }
+}
+
+// Test that DLOG_IF acts as a single statement in variety of syntactic
+// situations.
+TEST_F(LoggingTest, DLogIfStatements) {
+ // The next three blocks validate that the DLOG_IF is correctly bound to the
+ // 'if' statement.
+ {
+ ExpectNoLogs expect_no_logs;
+
+ // Unreached DLOG_IF.
+ if (false)
+ DLOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Reached, negative DLOG_IF.
+ if (true)
+ DLOG_IF(FATAL, !bool_expr()) << "message";
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectOneLogIfDCheckIsOn expect_one_dlog;
+
+ // Reached, positive DLOG_IF.
+ if (true)
+ DLOG_IF(FATAL, bool_expr()) << "message";
+ }
+
+ // The following four cases validate that the DLOG_IF is correctly bound in an
+ // 'if/else' statement.
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Unreached if, negative else.
+ if (false)
+ DLOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ else
+ DLOG_IF(FATAL, !bool_expr()) << "message";
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Negative if, unreached else.
+ if (true)
+ DLOG_IF(FATAL, !bool_expr()) << "message";
+ else
+ DLOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectOneLogIfDCheckIsOn expect_one_dlog;
+
+ // Unreached if, positive else.
+ if (false)
+ DLOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ else
+ DLOG_IF(FATAL, bool_expr()) << "message";
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectOneLogIfDCheckIsOn expect_one_dlog;
+
+ // Positive if, unreached else.
+ if (true)
+ DLOG_IF(FATAL, bool_expr()) << "message";
+ else
+ DLOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ }
+
+ // These cases validate that a DLOG_IF may appear in a switch statement.
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectNoLogs expect_no_logs;
+ switch (2) {
+ case 1:
+ DLOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ case 2:
+ DLOG_IF(FATAL, !bool_expr()) << "message";
+ default:
+ break;
+ }
+ }
+
+ {
+ EvaluatedOnceIfDCheckIsOn bool_expr;
+ ExpectOneLogIfDCheckIsOn expect_one_dlog;
+ switch (2) {
+ case 1:
+ DLOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ case 2:
+ DLOG_IF(FATAL, bool_expr()) << "message";
+ default:
+ break;
+ }
+ }
+}
+
+// Test that LOG_IF acts as a single statement in variety of syntactic
+// situations.
+TEST_F(LoggingTest, LogIfStatements) {
+ // The next three blocks validate that the LOG_IF is correctly bound to the
+ // 'if' statement.
+ {
+ ExpectNoLogs expect_no_logs;
+
+ // Unreached LOG_IF.
+ if (false)
+ LOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Reached, negative LOG_IF.
+ if (true)
+ LOG_IF(FATAL, !bool_expr()) << "message";
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectOneLog expect_one_log;
+
+ // Reached, positive LOG_IF.
+ if (true)
+ LOG_IF(FATAL, bool_expr()) << "message";
+ }
+
+ // The following four cases validate that the LOG_IF is correctly bound in an
+ // 'if/else' statement.
+ {
+ EvaluatedOnce bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Unreached if, negative else.
+ if (false)
+ LOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ else
+ LOG_IF(FATAL, !bool_expr()) << "message";
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectNoLogs expect_no_logs;
+
+ // Negative if, unreached else.
+ if (true)
+ LOG_IF(FATAL, !bool_expr()) << "message";
+ else
+ LOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectOneLog expect_one_log;
+
+ // Unreached if, positive else.
+ if (false)
+ LOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ else
+ LOG_IF(FATAL, bool_expr()) << "message";
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectOneLog expect_one_log;
+
+ // Positive if, unreached else.
+ if (true)
+ LOG_IF(FATAL, bool_expr()) << "message";
+ else
+ LOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ }
+
+ // These cases validate that a LOG_IF may appear in a switch statement.
+ {
+ EvaluatedOnce bool_expr;
+ ExpectNoLogs expect_no_logs;
+ switch (2) {
+ case 1:
+ LOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ case 2:
+ LOG_IF(FATAL, !bool_expr()) << "message";
+ default:
+ break;
+ }
+ }
+
+ {
+ EvaluatedOnce bool_expr;
+ ExpectOneLog expect_one_log;
+ switch (2) {
+ case 1:
+ LOG_IF(FATAL, UnreachedBoolExpr()) << "message";
+ case 2:
+ LOG_IF(FATAL, bool_expr()) << "message";
+ default:
+ break;
+ }
+ }
+}
+
// 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
« no previous file with comments | « base/logging.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698