1 // Copyright (c) 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/bind.h"
6 #include "base/callback.h"
7 #include "base/logging.h"
8 #include "base/strings/string_piece.h"
9 #include "base/test/gtest_util.h"
10 #include "base/test/scoped_feature_list.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 namespace {
15 
16 // Helper class which expects a check to fire with a certain location and
17 // message before the end of the current scope.
18 class ScopedCheckExpectation {
19  public:
ScopedCheckExpectation(const char * file,int line,std::string msg)20   ScopedCheckExpectation(const char* file, int line, std::string msg)
21       : file_(file),
22         line_(line),
23         msg_(msg),
24         assert_handler_(base::BindRepeating(&ScopedCheckExpectation::Check,
25                                             base::Unretained(this))),
26         fired_(false) {}
~ScopedCheckExpectation()27   ~ScopedCheckExpectation() {
28     EXPECT_TRUE(fired_) << "CHECK at " << file_ << ":" << line_
29                         << " never fired!";
30   }
31 
32  private:
Check(const char * file,int line,const base::StringPiece msg,const base::StringPiece stack)33   void Check(const char* file,
34              int line,
35              const base::StringPiece msg,
36              const base::StringPiece stack) {
37     fired_ = true;
38     EXPECT_EQ(file, file_);
39     EXPECT_EQ(line, line_);
40     if (msg_.find("=~") == 0) {
41       EXPECT_THAT(std::string(msg), testing::MatchesRegex(msg_.substr(2)));
42     } else {
43       EXPECT_EQ(std::string(msg), msg_);
44     }
45   }
46 
47   std::string file_;
48   int line_;
49   std::string msg_;
50   logging::ScopedLogAssertHandler assert_handler_;
51   bool fired_;
52 };
53 
54 // Macro which expects a CHECK to fire with a certain message. If msg starts
55 // with "=~", it's interpreted as a regular expression.
56 // Example: EXPECT_CHECK("Check failed: false.", CHECK(false));
57 #if defined(OFFICIAL_BUILD) && defined(NDEBUG)
58 #define EXPECT_CHECK(msg, check_expr) \
59   do {                                \
60     EXPECT_CHECK_DEATH(check_expr);   \
61   } while (0)
62 #else
63 #define EXPECT_CHECK(msg, check_expr)                          \
64   do {                                                         \
65     ScopedCheckExpectation check_exp(__FILE__, __LINE__, msg); \
66     check_expr;                                                \
67   } while (0)
68 #endif
69 
70 // Macro which expects a DCHECK to fire if DCHECKs are enabled.
71 #define EXPECT_DCHECK(msg, check_expr)                                         \
72   do {                                                                         \
73     if (DCHECK_IS_ON() && logging::LOGGING_DCHECK == logging::LOGGING_FATAL) { \
74       ScopedCheckExpectation check_exp(__FILE__, __LINE__, msg);               \
75       check_expr;                                                              \
76     } else {                                                                   \
77       check_expr;                                                              \
78     }                                                                          \
79   } while (0)
80 
81 class CheckTest : public testing::Test {};
82 
TEST_F(CheckTest,Basics)83 TEST_F(CheckTest, Basics) {
84   EXPECT_CHECK("Check failed: false. ", CHECK(false));
85 
86   EXPECT_CHECK("Check failed: false. foo", CHECK(false) << "foo");
87 
88   double a = 2, b = 1;
89   EXPECT_CHECK("Check failed: a < b (2.000000 vs. 1.000000)", CHECK_LT(a, b));
90 
91   EXPECT_CHECK("Check failed: a < b (2.000000 vs. 1.000000)foo",
92                CHECK_LT(a, b) << "foo");
93 }
94 
TEST_F(CheckTest,PCheck)95 TEST_F(CheckTest, PCheck) {
96   const char file[] = "/nonexistentfile123";
97   ignore_result(fopen(file, "r"));
98   std::string err =
99       logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode());
100 
101   EXPECT_CHECK(
102       "Check failed: fopen(file, \"r\") != nullptr."
103       " : " +
104           err,
105       PCHECK(fopen(file, "r") != nullptr));
106 
107   EXPECT_CHECK(
108       "Check failed: fopen(file, \"r\") != nullptr."
109       " foo: " +
110           err,
111       PCHECK(fopen(file, "r") != nullptr) << "foo");
112 
113   EXPECT_DCHECK(
114       "Check failed: fopen(file, \"r\") != nullptr."
115       " : " +
116           err,
117       DPCHECK(fopen(file, "r") != nullptr));
118 
119   EXPECT_DCHECK(
120       "Check failed: fopen(file, \"r\") != nullptr."
121       " foo: " +
122           err,
123       DPCHECK(fopen(file, "r") != nullptr) << "foo");
124 }
125 
TEST_F(CheckTest,CheckOp)126 TEST_F(CheckTest, CheckOp) {
127   int a = 1, b = 2;
128   // clang-format off
129   EXPECT_CHECK("Check failed: a == b (1 vs. 2)", CHECK_EQ(a, b));
130   EXPECT_CHECK("Check failed: a != a (1 vs. 1)", CHECK_NE(a, a));
131   EXPECT_CHECK("Check failed: b <= a (2 vs. 1)", CHECK_LE(b, a));
132   EXPECT_CHECK("Check failed: b < a (2 vs. 1)",  CHECK_LT(b, a));
133   EXPECT_CHECK("Check failed: a >= b (1 vs. 2)", CHECK_GE(a, b));
134   EXPECT_CHECK("Check failed: a > b (1 vs. 2)",  CHECK_GT(a, b));
135 
136   EXPECT_DCHECK("Check failed: a == b (1 vs. 2)", DCHECK_EQ(a, b));
137   EXPECT_DCHECK("Check failed: a != a (1 vs. 1)", DCHECK_NE(a, a));
138   EXPECT_DCHECK("Check failed: b <= a (2 vs. 1)", DCHECK_LE(b, a));
139   EXPECT_DCHECK("Check failed: b < a (2 vs. 1)",  DCHECK_LT(b, a));
140   EXPECT_DCHECK("Check failed: a >= b (1 vs. 2)", DCHECK_GE(a, b));
141   EXPECT_DCHECK("Check failed: a > b (1 vs. 2)",  DCHECK_GT(a, b));
142   // clang-format on
143 }
144 
TEST_F(CheckTest,CheckStreamsAreLazy)145 TEST_F(CheckTest, CheckStreamsAreLazy) {
146   int called_count = 0;
147   int not_called_count = 0;
148 
149   auto Called = [&]() {
150     ++called_count;
151     return 42;
152   };
153   auto NotCalled = [&]() {
154     ++not_called_count;
155     return 42;
156   };
157 
158   CHECK(Called()) << NotCalled();
159   CHECK_EQ(Called(), Called()) << NotCalled();
160   PCHECK(Called()) << NotCalled();
161 
162   DCHECK(Called()) << NotCalled();
163   DCHECK_EQ(Called(), Called()) << NotCalled();
164   DPCHECK(Called()) << NotCalled();
165 
166   EXPECT_EQ(not_called_count, 0);
167 #if DCHECK_IS_ON()
168   EXPECT_EQ(called_count, 8);
169 #else
170   EXPECT_EQ(called_count, 4);
171 #endif
172 }
173 
DcheckEmptyFunction1()174 void DcheckEmptyFunction1() {
175   // Provide a body so that Release builds do not cause the compiler to
176   // optimize DcheckEmptyFunction1 and DcheckEmptyFunction2 as a single
177   // function, which breaks the Dcheck tests below.
178   LOG(INFO) << "DcheckEmptyFunction1";
179 }
DcheckEmptyFunction2()180 void DcheckEmptyFunction2() {}
181 
182 #if defined(DCHECK_IS_CONFIGURABLE)
183 class ScopedDcheckSeverity {
184  public:
ScopedDcheckSeverity(logging::LogSeverity new_severity)185   ScopedDcheckSeverity(logging::LogSeverity new_severity)
186       : old_severity_(logging::LOGGING_DCHECK) {
187     logging::LOGGING_DCHECK = new_severity;
188   }
189 
~ScopedDcheckSeverity()190   ~ScopedDcheckSeverity() { logging::LOGGING_DCHECK = old_severity_; }
191 
192  private:
193   logging::LogSeverity old_severity_;
194 };
195 #endif  // defined(DCHECK_IS_CONFIGURABLE)
196 
197 // https://crbug.com/709067 tracks test flakiness on iOS.
198 #if defined(OS_IOS)
199 #define MAYBE_Dcheck DISABLED_Dcheck
200 #else
201 #define MAYBE_Dcheck Dcheck
202 #endif
TEST_F(CheckTest,MAYBE_Dcheck)203 TEST_F(CheckTest, MAYBE_Dcheck) {
204 #if defined(DCHECK_IS_CONFIGURABLE)
205   // DCHECKs are enabled, and LOGGING_DCHECK is mutable, but defaults to
206   // non-fatal. Set it to LOGGING_FATAL to get the expected behavior from the
207   // rest of this test.
208   ScopedDcheckSeverity dcheck_severity(logging::LOGGING_FATAL);
209 #endif  // defined(DCHECK_IS_CONFIGURABLE)
210 
211 #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
212   // Release build.
213   EXPECT_FALSE(DCHECK_IS_ON());
214   EXPECT_FALSE(DLOG_IS_ON(DCHECK));
215 #elif defined(NDEBUG) && defined(DCHECK_ALWAYS_ON)
216   // Release build with real DCHECKS.
217   EXPECT_TRUE(DCHECK_IS_ON());
218   EXPECT_TRUE(DLOG_IS_ON(DCHECK));
219 #else
220   // Debug build.
221   EXPECT_TRUE(DCHECK_IS_ON());
222   EXPECT_TRUE(DLOG_IS_ON(DCHECK));
223 #endif
224 
225   EXPECT_DCHECK("Check failed: false. ", DCHECK(false));
226   std::string err =
227       logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode());
228   EXPECT_DCHECK("Check failed: false. : " + err, DPCHECK(false));
229   EXPECT_DCHECK("Check failed: 0 == 1 (0 vs. 1)", DCHECK_EQ(0, 1));
230 
231   // Test DCHECK on std::nullptr_t
232   const void* p_null = nullptr;
233   const void* p_not_null = &p_null;
234   DCHECK_EQ(p_null, nullptr);
235   DCHECK_EQ(nullptr, p_null);
236   DCHECK_NE(p_not_null, nullptr);
237   DCHECK_NE(nullptr, p_not_null);
238 
239   // Test DCHECK on a scoped enum.
240   enum class Animal { DOG, CAT };
241   DCHECK_EQ(Animal::DOG, Animal::DOG);
242   EXPECT_DCHECK("Check failed: Animal::DOG == Animal::CAT (0 vs. 1)",
243                 DCHECK_EQ(Animal::DOG, Animal::CAT));
244 
245   // Test DCHECK on functions and function pointers.
246   struct MemberFunctions {
247     void MemberFunction1() {
248       // See the comment in DcheckEmptyFunction1().
249       LOG(INFO) << "Do not merge with MemberFunction2.";
250     }
251     void MemberFunction2() {}
252   };
253   void (MemberFunctions::*mp1)() = &MemberFunctions::MemberFunction1;
254   void (MemberFunctions::*mp2)() = &MemberFunctions::MemberFunction2;
255   void (*fp1)() = DcheckEmptyFunction1;
256   void (*fp2)() = DcheckEmptyFunction2;
257   void (*fp3)() = DcheckEmptyFunction1;
258   DCHECK_EQ(fp1, fp3);
259   DCHECK_EQ(mp1, &MemberFunctions::MemberFunction1);
260   DCHECK_EQ(mp2, &MemberFunctions::MemberFunction2);
261   EXPECT_DCHECK("=~Check failed: fp1 == fp2 \\(\\w+ vs. \\w+\\)",
262                 DCHECK_EQ(fp1, fp2));
263   EXPECT_DCHECK(
264       "Check failed: mp2 == &MemberFunctions::MemberFunction1 (1 vs. 1)",
265       DCHECK_EQ(mp2, &MemberFunctions::MemberFunction1));
266 }
267 
TEST_F(CheckTest,DcheckReleaseBehavior)268 TEST_F(CheckTest, DcheckReleaseBehavior) {
269   int var1 = 1;
270   int var2 = 2;
271   int var3 = 3;
272   int var4 = 4;
273 
274   // No warnings about unused variables even though no check fires and DCHECK
275   // may or may not be enabled.
276   DCHECK(var1) << var2;
277   DPCHECK(var1) << var3;
278   DCHECK_EQ(var1, 1) << var4;
279 }
280 
TEST_F(CheckTest,DCheckEqStatements)281 TEST_F(CheckTest, DCheckEqStatements) {
282   bool reached = false;
283   if (false)
284     DCHECK_EQ(false, true);  // Unreached.
285   else
286     DCHECK_EQ(true, reached = true);  // Reached, passed.
287   ASSERT_EQ(DCHECK_IS_ON() ? true : false, reached);
288 
289   if (false)
290     DCHECK_EQ(false, true);  // Unreached.
291 }
292 
TEST_F(CheckTest,CheckEqStatements)293 TEST_F(CheckTest, CheckEqStatements) {
294   bool reached = false;
295   if (false)
296     CHECK_EQ(false, true);  // Unreached.
297   else
298     CHECK_EQ(true, reached = true);  // Reached, passed.
299   ASSERT_TRUE(reached);
300 
301   if (false)
302     CHECK_EQ(false, true);  // Unreached.
303 }
304 
305 #if defined(DCHECK_IS_CONFIGURABLE)
TEST_F(CheckTest,ConfigurableDCheck)306 TEST_F(CheckTest, ConfigurableDCheck) {
307   // Verify that DCHECKs default to non-fatal in configurable-DCHECK builds.
308   // Note that we require only that DCHECK is non-fatal by default, rather
309   // than requiring that it be exactly INFO, ERROR, etc level.
310   EXPECT_LT(logging::LOGGING_DCHECK, logging::LOGGING_FATAL);
311   DCHECK(false);
312 
313   // Verify that DCHECK* aren't hard-wired to crash on failure.
314   logging::LOGGING_DCHECK = logging::LOG_INFO;
315   DCHECK(false);
316   DCHECK_EQ(1, 2);
317 
318   // Verify that DCHECK does crash if LOGGING_DCHECK is set to LOGGING_FATAL.
319   logging::LOGGING_DCHECK = logging::LOGGING_FATAL;
320   EXPECT_CHECK("Check failed: false. ", DCHECK(false));
321   EXPECT_CHECK("Check failed: 1 == 2 (1 vs. 2)", DCHECK_EQ(1, 2));
322 }
323 
TEST_F(CheckTest,ConfigurableDCheckFeature)324 TEST_F(CheckTest, ConfigurableDCheckFeature) {
325   // Initialize FeatureList with and without DcheckIsFatal, and verify the
326   // value of LOGGING_DCHECK. Note that we don't require that DCHECK take a
327   // specific value when the feature is off, only that it is non-fatal.
328 
329   {
330     base::test::ScopedFeatureList feature_list;
331     feature_list.InitFromCommandLine("DcheckIsFatal", "");
332     EXPECT_EQ(logging::LOGGING_DCHECK, logging::LOGGING_FATAL);
333   }
334 
335   {
336     base::test::ScopedFeatureList feature_list;
337     feature_list.InitFromCommandLine("", "DcheckIsFatal");
338     EXPECT_LT(logging::LOGGING_DCHECK, logging::LOGGING_FATAL);
339   }
340 
341   // The default case is last, so we leave LOGGING_DCHECK in the default state.
342   {
343     base::test::ScopedFeatureList feature_list;
344     feature_list.InitFromCommandLine("", "");
345     EXPECT_LT(logging::LOGGING_DCHECK, logging::LOGGING_FATAL);
346   }
347 }
348 #endif  // defined(DCHECK_IS_CONFIGURABLE)
349 
350 struct StructWithOstream {
operator ==__anona01b87600111::StructWithOstream351   bool operator==(const StructWithOstream& o) const { return &o == this; }
352 };
353 #if !(defined(OFFICIAL_BUILD) && defined(NDEBUG))
operator <<(std::ostream & out,const StructWithOstream &)354 std::ostream& operator<<(std::ostream& out, const StructWithOstream&) {
355   return out << "ostream";
356 }
357 #endif
358 
359 struct StructWithToString {
operator ==__anona01b87600111::StructWithToString360   bool operator==(const StructWithToString& o) const { return &o == this; }
ToString__anona01b87600111::StructWithToString361   std::string ToString() const { return "ToString"; }
362 };
363 
364 struct StructWithToStringAndOstream {
operator ==__anona01b87600111::StructWithToStringAndOstream365   bool operator==(const StructWithToStringAndOstream& o) const {
366     return &o == this;
367   }
ToString__anona01b87600111::StructWithToStringAndOstream368   std::string ToString() const { return "ToString"; }
369 };
370 #if !(defined(OFFICIAL_BUILD) && defined(NDEBUG))
operator <<(std::ostream & out,const StructWithToStringAndOstream &)371 std::ostream& operator<<(std::ostream& out,
372                          const StructWithToStringAndOstream&) {
373   return out << "ostream";
374 }
375 #endif
376 
377 struct StructWithToStringNotStdString {
378   struct PseudoString {};
379 
operator ==__anona01b87600111::StructWithToStringNotStdString380   bool operator==(const StructWithToStringNotStdString& o) const {
381     return &o == this;
382   }
ToString__anona01b87600111::StructWithToStringNotStdString383   PseudoString ToString() const { return PseudoString(); }
384 };
385 #if !(defined(OFFICIAL_BUILD) && defined(NDEBUG))
operator <<(std::ostream & out,const StructWithToStringNotStdString::PseudoString &)386 std::ostream& operator<<(std::ostream& out,
387                          const StructWithToStringNotStdString::PseudoString&) {
388   return out << "ToString+ostream";
389 }
390 #endif
391 
TEST_F(CheckTest,OstreamVsToString)392 TEST_F(CheckTest, OstreamVsToString) {
393   StructWithOstream a, b;
394   EXPECT_CHECK("Check failed: a == b (ostream vs. ostream)", CHECK_EQ(a, b));
395 
396   StructWithToString c, d;
397   EXPECT_CHECK("Check failed: c == d (ToString vs. ToString)", CHECK_EQ(c, d));
398 
399   StructWithToStringAndOstream e, f;
400   EXPECT_CHECK("Check failed: e == f (ostream vs. ostream)", CHECK_EQ(e, f));
401 
402   StructWithToStringNotStdString g, h;
403   EXPECT_CHECK("Check failed: g == h (ToString+ostream vs. ToString+ostream)",
404                CHECK_EQ(g, h));
405 }
406 
407 #define EXPECT_LOG_ERROR(msg, expr, expected_line)                             \
408   do {                                                                         \
409     static bool got_log_message = false;                                       \
410     ASSERT_EQ(logging::GetLogMessageHandler(), nullptr);                       \
411     logging::SetLogMessageHandler([](int severity, const char* file, int line, \
412                                      size_t message_start,                     \
413                                      const std::string& str) {                 \
414       EXPECT_FALSE(got_log_message);                                           \
415       got_log_message = true;                                                  \
416       EXPECT_EQ(severity, logging::LOG_ERROR);                                 \
417       EXPECT_EQ(str.substr(message_start), (msg));                             \
418       EXPECT_STREQ(__FILE__, file);                                            \
419       EXPECT_EQ(expected_line, line);                                          \
420       return true;                                                             \
421     });                                                                        \
422     expr;                                                                      \
423     EXPECT_TRUE(got_log_message);                                              \
424     logging::SetLogMessageHandler(nullptr);                                    \
425   } while (0)
426 
427 #define EXPECT_NO_LOG(expr)                                                    \
428   do {                                                                         \
429     ASSERT_EQ(logging::GetLogMessageHandler(), nullptr);                       \
430     logging::SetLogMessageHandler([](int severity, const char* file, int line, \
431                                      size_t message_start,                     \
432                                      const std::string& str) {                 \
433       EXPECT_TRUE(false) << "Unexpected log: " << str;                         \
434       return true;                                                             \
435     });                                                                        \
436     expr;                                                                      \
437     logging::SetLogMessageHandler(nullptr);                                    \
438   } while (0)
439 
TEST_F(CheckTest,NotReached)440 TEST_F(CheckTest, NotReached) {
441 #if BUILDFLAG(ENABLE_LOG_ERROR_NOT_REACHED)
442   // Expect LOG(ERROR) without the streamed params.
443   EXPECT_LOG_ERROR("NOTREACHED() hit.\n", NOTREACHED() << "foo", __LINE__);
444 #else
445   // Expect a DCHECK with streamed params intact.
446   EXPECT_DCHECK("Check failed: false. foo", NOTREACHED() << "foo");
447 #endif
448 }
449 
TEST_F(CheckTest,NotImplemented)450 TEST_F(CheckTest, NotImplemented) {
451   static const std::string expected_msg =
452       std::string("Not implemented reached in ") + __PRETTY_FUNCTION__;
453 
454 #if DCHECK_IS_ON()
455   // Expect LOG(ERROR) with streamed params intact.
456   EXPECT_LOG_ERROR(expected_msg + "foo\n", NOTIMPLEMENTED() << "foo", __LINE__);
457 #else
458   // Expect nothing.
459   EXPECT_NO_LOG(NOTIMPLEMENTED() << "foo");
460 #endif
461 }
462 
NiLogOnce()463 void NiLogOnce() {
464   // Note: The stream param is not logged.
465   NOTIMPLEMENTED_LOG_ONCE() << "foo";
466 }
467 
TEST_F(CheckTest,NotImplementedLogOnce)468 TEST_F(CheckTest, NotImplementedLogOnce) {
469   static const std::string expected_msg =
470       "Not implemented reached in void (anonymous namespace)::NiLogOnce()\n";
471 
472 #if DCHECK_IS_ON()
473   EXPECT_LOG_ERROR(expected_msg, NiLogOnce(), __LINE__ - 8);
474   EXPECT_NO_LOG(NiLogOnce());
475 #else
476   EXPECT_NO_LOG(NiLogOnce());
477   EXPECT_NO_LOG(NiLogOnce());
478 #endif
479 }
480 
481 }  // namespace
482