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