check_unittest.cc 17 KB

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