/thirdparty/breakpad/third_party/glog/src/logging_unittest.cc
C++ | 1210 lines | 911 code | 180 blank | 119 comment | 58 complexity | a40288f6bebb3a090f7bcfa29a527585 MD5 | raw file
1// Copyright (c) 2002, Google Inc. 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are 6// met: 7// 8// * Redistributions of source code must retain the above copyright 9// notice, this list of conditions and the following disclaimer. 10// * Redistributions in binary form must reproduce the above 11// copyright notice, this list of conditions and the following disclaimer 12// in the documentation and/or other materials provided with the 13// distribution. 14// * Neither the name of Google Inc. nor the names of its 15// contributors may be used to endorse or promote products derived from 16// this software without specific prior written permission. 17// 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29// 30// Author: Ray Sidney 31 32#include "config_for_unittests.h" 33#include "utilities.h" 34 35#include <fcntl.h> 36#ifdef HAVE_GLOB_H 37# include <glob.h> 38#endif 39#include <sys/stat.h> 40#ifdef HAVE_UNISTD_H 41# include <unistd.h> 42#endif 43 44#include <iomanip> 45#include <iostream> 46#include <memory> 47#include <queue> 48#include <sstream> 49#include <string> 50#include <vector> 51 52#include <stdio.h> 53#include <stdlib.h> 54 55#include "base/commandlineflags.h" 56#include "glog/logging.h" 57#include "glog/raw_logging.h" 58#include "googletest.h" 59 60DECLARE_string(log_backtrace_at); // logging.cc 61 62#ifdef HAVE_LIB_GFLAGS 63#include <gflags/gflags.h> 64#endif 65 66#ifdef HAVE_LIB_GMOCK 67#include <gmock/gmock.h> 68#include "mock-log.h" 69// Introduce several symbols from gmock. 70using testing::_; 71using testing::AnyNumber; 72using testing::HasSubstr; 73using testing::AllOf; 74using testing::StrNe; 75using testing::StrictMock; 76using testing::InitGoogleMock; 77using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog; 78#endif 79 80using namespace std; 81using namespace GOOGLE_NAMESPACE; 82 83// Some non-advertised functions that we want to test or use. 84_START_GOOGLE_NAMESPACE_ 85namespace base { 86namespace internal { 87bool GetExitOnDFatal(); 88void SetExitOnDFatal(bool value); 89} // namespace internal 90} // namespace base 91_END_GOOGLE_NAMESPACE_ 92 93static void TestLogging(bool check_counts); 94static void TestRawLogging(); 95static void LogWithLevels(int v, int severity, bool err, bool alsoerr); 96static void TestLoggingLevels(); 97static void TestLogString(); 98static void TestLogSink(); 99static void TestLogToString(); 100static void TestLogSinkWaitTillSent(); 101static void TestCHECK(); 102static void TestDCHECK(); 103static void TestSTREQ(); 104static void TestBasename(); 105static void TestSymlink(); 106static void TestExtension(); 107static void TestWrapper(); 108static void TestErrno(); 109static void TestTruncate(); 110 111static int x = -1; 112static void BM_Check1(int n) { 113 while (n-- > 0) { 114 CHECK_GE(n, x); 115 CHECK_GE(n, x); 116 CHECK_GE(n, x); 117 CHECK_GE(n, x); 118 CHECK_GE(n, x); 119 CHECK_GE(n, x); 120 CHECK_GE(n, x); 121 CHECK_GE(n, x); 122 } 123} 124BENCHMARK(BM_Check1); 125 126static void CheckFailure(int a, int b, const char* file, int line, const char* msg); 127static void BM_Check3(int n) { 128 while (n-- > 0) { 129 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x"); 130 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x"); 131 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x"); 132 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x"); 133 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x"); 134 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x"); 135 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x"); 136 if (n < x) CheckFailure(n, x, __FILE__, __LINE__, "n < x"); 137 } 138} 139BENCHMARK(BM_Check3); 140 141static void BM_Check2(int n) { 142 if (n == 17) { 143 x = 5; 144 } 145 while (n-- > 0) { 146 CHECK(n >= x); 147 CHECK(n >= x); 148 CHECK(n >= x); 149 CHECK(n >= x); 150 CHECK(n >= x); 151 CHECK(n >= x); 152 CHECK(n >= x); 153 CHECK(n >= x); 154 } 155} 156BENCHMARK(BM_Check2); 157 158static void CheckFailure(int a, int b, const char* file, int line, const char* msg) { 159} 160 161static void BM_logspeed(int n) { 162 while (n-- > 0) { 163 LOG(INFO) << "test message"; 164 } 165} 166BENCHMARK(BM_logspeed); 167 168static void BM_vlog(int n) { 169 while (n-- > 0) { 170 VLOG(1) << "test message"; 171 } 172} 173BENCHMARK(BM_vlog); 174 175int main(int argc, char **argv) { 176#ifdef HAVE_LIB_GFLAGS 177 ParseCommandLineFlags(&argc, &argv, true); 178#endif 179 180 // Test some basics before InitGoogleLogging: 181 CaptureTestStderr(); 182 LogWithLevels(FLAGS_v, FLAGS_stderrthreshold, 183 FLAGS_logtostderr, FLAGS_alsologtostderr); 184 LogWithLevels(0, 0, 0, 0); // simulate "before global c-tors" 185 const string early_stderr = GetCapturedTestStderr(); 186 187 InitGoogleLogging(argv[0]); 188 189 RunSpecifiedBenchmarks(); 190 191 FLAGS_logtostderr = true; 192 193 InitGoogleTest(&argc, argv); 194#ifdef HAVE_LIB_GMOCK 195 InitGoogleMock(&argc, argv); 196#endif 197 198 // so that death tests run before we use threads 199 CHECK_EQ(RUN_ALL_TESTS(), 0); 200 201 CaptureTestStderr(); 202 203 // re-emit early_stderr 204 LogMessage("dummy", LogMessage::kNoLogPrefix, INFO).stream() << early_stderr; 205 206 TestLogging(true); 207 TestRawLogging(); 208 TestLoggingLevels(); 209 TestLogString(); 210 TestLogSink(); 211 TestLogToString(); 212 TestLogSinkWaitTillSent(); 213 TestCHECK(); 214 TestDCHECK(); 215 TestSTREQ(); 216 217 // TODO: The golden test portion of this test is very flakey. 218 EXPECT_TRUE( 219 MungeAndDiffTestStderr(FLAGS_test_srcdir + "/src/logging_unittest.err")); 220 221 FLAGS_logtostderr = false; 222 223 TestBasename(); 224 TestSymlink(); 225 TestExtension(); 226 TestWrapper(); 227 TestErrno(); 228 TestTruncate(); 229 230 ShutdownGoogleLogging(); 231 232 fprintf(stdout, "PASS\n"); 233 return 0; 234} 235 236void TestLogging(bool check_counts) { 237 int64 base_num_infos = LogMessage::num_messages(INFO); 238 int64 base_num_warning = LogMessage::num_messages(WARNING); 239 int64 base_num_errors = LogMessage::num_messages(ERROR); 240 241 LOG(INFO) << string("foo ") << "bar " << 10 << ' ' << 3.4; 242 for ( int i = 0; i < 10; ++i ) { 243 int old_errno = errno; 244 errno = i; 245 PLOG_EVERY_N(ERROR, 2) << "Plog every 2, iteration " << COUNTER; 246 errno = old_errno; 247 248 LOG_EVERY_N(ERROR, 3) << "Log every 3, iteration " << COUNTER << endl; 249 LOG_EVERY_N(ERROR, 4) << "Log every 4, iteration " << COUNTER << endl; 250 251 LOG_IF_EVERY_N(WARNING, true, 5) << "Log if every 5, iteration " << COUNTER; 252 LOG_IF_EVERY_N(WARNING, false, 3) 253 << "Log if every 3, iteration " << COUNTER; 254 LOG_IF_EVERY_N(INFO, true, 1) << "Log if every 1, iteration " << COUNTER; 255 LOG_IF_EVERY_N(ERROR, (i < 3), 2) 256 << "Log if less than 3 every 2, iteration " << COUNTER; 257 } 258 LOG_IF(WARNING, true) << "log_if this"; 259 LOG_IF(WARNING, false) << "don't log_if this"; 260 261 char s[] = "array"; 262 LOG(INFO) << s; 263 const char const_s[] = "const array"; 264 LOG(INFO) << const_s; 265 int j = 1000; 266 LOG(ERROR) << string("foo") << ' '<< j << ' ' << setw(10) << j << " " 267 << setw(1) << hex << j; 268 269 LogMessage("foo", LogMessage::kNoLogPrefix, INFO).stream() << "no prefix"; 270 271 if (check_counts) { 272 CHECK_EQ(base_num_infos + 14, LogMessage::num_messages(INFO)); 273 CHECK_EQ(base_num_warning + 3, LogMessage::num_messages(WARNING)); 274 CHECK_EQ(base_num_errors + 15, LogMessage::num_messages(ERROR)); 275 } 276} 277 278static void NoAllocNewHook() { 279 CHECK(false) << "unexpected new"; 280} 281 282struct NewHook { 283 NewHook() { 284 g_new_hook = &NoAllocNewHook; 285 } 286 ~NewHook() { 287 g_new_hook = NULL; 288 } 289}; 290 291TEST(DeathNoAllocNewHook, logging) { 292 // tests that NewHook used below works 293 NewHook new_hook; 294 ASSERT_DEATH({ 295 new int; 296 }, "unexpected new"); 297} 298 299void TestRawLogging() { 300 string* foo = new string("foo "); 301 string huge_str(50000, 'a'); 302 303 FlagSaver saver; 304 305 // Check that RAW loggging does not use mallocs. 306 NewHook new_hook; 307 308 RAW_LOG(INFO, "%s%s%d%c%f", foo->c_str(), "bar ", 10, ' ', 3.4); 309 char s[] = "array"; 310 RAW_LOG(WARNING, "%s", s); 311 const char const_s[] = "const array"; 312 RAW_LOG(INFO, "%s", const_s); 313 void* p = reinterpret_cast<void*>(0x12345678); 314 RAW_LOG(INFO, "ptr %p", p); 315 p = NULL; 316 RAW_LOG(INFO, "ptr %p", p); 317 int j = 1000; 318 RAW_LOG(ERROR, "%s%d%c%010d%s%1x", foo->c_str(), j, ' ', j, " ", j); 319 RAW_VLOG(0, "foo %d", j); 320 321#ifdef NDEBUG 322 RAW_LOG(INFO, "foo %d", j); // so that have same stderr to compare 323#else 324 RAW_DLOG(INFO, "foo %d", j); // test RAW_DLOG in debug mode 325#endif 326 327 // test how long messages are chopped: 328 RAW_LOG(WARNING, "Huge string: %s", huge_str.c_str()); 329 RAW_VLOG(0, "Huge string: %s", huge_str.c_str()); 330 331 FLAGS_v = 0; 332 RAW_LOG(INFO, "log"); 333 RAW_VLOG(0, "vlog 0 on"); 334 RAW_VLOG(1, "vlog 1 off"); 335 RAW_VLOG(2, "vlog 2 off"); 336 RAW_VLOG(3, "vlog 3 off"); 337 FLAGS_v = 2; 338 RAW_LOG(INFO, "log"); 339 RAW_VLOG(1, "vlog 1 on"); 340 RAW_VLOG(2, "vlog 2 on"); 341 RAW_VLOG(3, "vlog 3 off"); 342 343#ifdef NDEBUG 344 RAW_DCHECK(1 == 2, " RAW_DCHECK's shouldn't be compiled in normal mode"); 345#endif 346 347 RAW_CHECK(1 == 1, "should be ok"); 348 RAW_DCHECK(true, "should be ok"); 349 350 delete foo; 351} 352 353void LogWithLevels(int v, int severity, bool err, bool alsoerr) { 354 RAW_LOG(INFO, 355 "Test: v=%d stderrthreshold=%d logtostderr=%d alsologtostderr=%d", 356 v, severity, err, alsoerr); 357 358 FlagSaver saver; 359 360 FLAGS_v = v; 361 FLAGS_stderrthreshold = severity; 362 FLAGS_logtostderr = err; 363 FLAGS_alsologtostderr = alsoerr; 364 365 RAW_VLOG(-1, "vlog -1"); 366 RAW_VLOG(0, "vlog 0"); 367 RAW_VLOG(1, "vlog 1"); 368 RAW_LOG(INFO, "log info"); 369 RAW_LOG(WARNING, "log warning"); 370 RAW_LOG(ERROR, "log error"); 371 372 VLOG(-1) << "vlog -1"; 373 VLOG(0) << "vlog 0"; 374 VLOG(1) << "vlog 1"; 375 LOG(INFO) << "log info"; 376 LOG(WARNING) << "log warning"; 377 LOG(ERROR) << "log error"; 378 379 VLOG_IF(-1, true) << "vlog_if -1"; 380 VLOG_IF(-1, false) << "don't vlog_if -1"; 381 VLOG_IF(0, true) << "vlog_if 0"; 382 VLOG_IF(0, false) << "don't vlog_if 0"; 383 VLOG_IF(1, true) << "vlog_if 1"; 384 VLOG_IF(1, false) << "don't vlog_if 1"; 385 LOG_IF(INFO, true) << "log_if info"; 386 LOG_IF(INFO, false) << "don't log_if info"; 387 LOG_IF(WARNING, true) << "log_if warning"; 388 LOG_IF(WARNING, false) << "don't log_if warning"; 389 LOG_IF(ERROR, true) << "log_if error"; 390 LOG_IF(ERROR, false) << "don't log_if error"; 391 392 int c; 393 c = 1; VLOG_IF(100, c -= 2) << "vlog_if 100 expr"; EXPECT_EQ(c, -1); 394 c = 1; VLOG_IF(0, c -= 2) << "vlog_if 0 expr"; EXPECT_EQ(c, -1); 395 c = 1; LOG_IF(INFO, c -= 2) << "log_if info expr"; EXPECT_EQ(c, -1); 396 c = 1; LOG_IF(ERROR, c -= 2) << "log_if error expr"; EXPECT_EQ(c, -1); 397 c = 2; VLOG_IF(0, c -= 2) << "don't vlog_if 0 expr"; EXPECT_EQ(c, 0); 398 c = 2; LOG_IF(ERROR, c -= 2) << "don't log_if error expr"; EXPECT_EQ(c, 0); 399 400 c = 3; LOG_IF_EVERY_N(INFO, c -= 4, 1) << "log_if info every 1 expr"; 401 EXPECT_EQ(c, -1); 402 c = 3; LOG_IF_EVERY_N(ERROR, c -= 4, 1) << "log_if error every 1 expr"; 403 EXPECT_EQ(c, -1); 404 c = 4; LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if info every 3 expr"; 405 EXPECT_EQ(c, 0); 406 c = 4; LOG_IF_EVERY_N(ERROR, c -= 4, 3) << "don't log_if error every 3 expr"; 407 EXPECT_EQ(c, 0); 408 c = 5; VLOG_IF_EVERY_N(0, c -= 4, 1) << "vlog_if 0 every 1 expr"; 409 EXPECT_EQ(c, 1); 410 c = 5; VLOG_IF_EVERY_N(100, c -= 4, 3) << "vlog_if 100 every 3 expr"; 411 EXPECT_EQ(c, 1); 412 c = 6; VLOG_IF_EVERY_N(0, c -= 6, 1) << "don't vlog_if 0 every 1 expr"; 413 EXPECT_EQ(c, 0); 414 c = 6; VLOG_IF_EVERY_N(100, c -= 6, 3) << "don't vlog_if 100 every 1 expr"; 415 EXPECT_EQ(c, 0); 416} 417 418void TestLoggingLevels() { 419 LogWithLevels(0, INFO, false, false); 420 LogWithLevels(1, INFO, false, false); 421 LogWithLevels(-1, INFO, false, false); 422 LogWithLevels(0, WARNING, false, false); 423 LogWithLevels(0, ERROR, false, false); 424 LogWithLevels(0, FATAL, false, false); 425 LogWithLevels(0, FATAL, true, false); 426 LogWithLevels(0, FATAL, false, true); 427 LogWithLevels(1, WARNING, false, false); 428 LogWithLevels(1, FATAL, false, true); 429} 430 431TEST(DeathRawCHECK, logging) { 432 ASSERT_DEATH(RAW_CHECK(false, "failure 1"), 433 "RAW: Check false failed: failure 1"); 434 ASSERT_DEBUG_DEATH(RAW_DCHECK(1 == 2, "failure 2"), 435 "RAW: Check 1 == 2 failed: failure 2"); 436} 437 438void TestLogString() { 439 vector<string> errors; 440 vector<string> *no_errors = NULL; 441 442 LOG_STRING(INFO, &errors) << "LOG_STRING: " << "collected info"; 443 LOG_STRING(WARNING, &errors) << "LOG_STRING: " << "collected warning"; 444 LOG_STRING(ERROR, &errors) << "LOG_STRING: " << "collected error"; 445 446 LOG_STRING(INFO, no_errors) << "LOG_STRING: " << "reported info"; 447 LOG_STRING(WARNING, no_errors) << "LOG_STRING: " << "reported warning"; 448 LOG_STRING(ERROR, NULL) << "LOG_STRING: " << "reported error"; 449 450 for (size_t i = 0; i < errors.size(); ++i) { 451 LOG(INFO) << "Captured by LOG_STRING: " << errors[i]; 452 } 453} 454 455void TestLogToString() { 456 string error; 457 string* no_error = NULL; 458 459 LOG_TO_STRING(INFO, &error) << "LOG_TO_STRING: " << "collected info"; 460 LOG(INFO) << "Captured by LOG_TO_STRING: " << error; 461 LOG_TO_STRING(WARNING, &error) << "LOG_TO_STRING: " << "collected warning"; 462 LOG(INFO) << "Captured by LOG_TO_STRING: " << error; 463 LOG_TO_STRING(ERROR, &error) << "LOG_TO_STRING: " << "collected error"; 464 LOG(INFO) << "Captured by LOG_TO_STRING: " << error; 465 466 LOG_TO_STRING(INFO, no_error) << "LOG_TO_STRING: " << "reported info"; 467 LOG_TO_STRING(WARNING, no_error) << "LOG_TO_STRING: " << "reported warning"; 468 LOG_TO_STRING(ERROR, NULL) << "LOG_TO_STRING: " << "reported error"; 469} 470 471class TestLogSinkImpl : public LogSink { 472 public: 473 vector<string> errors; 474 virtual void send(LogSeverity severity, const char* full_filename, 475 const char* base_filename, int line, 476 const struct tm* tm_time, 477 const char* message, size_t message_len) { 478 errors.push_back( 479 ToString(severity, base_filename, line, tm_time, message, message_len)); 480 } 481}; 482 483void TestLogSink() { 484 TestLogSinkImpl sink; 485 LogSink *no_sink = NULL; 486 487 LOG_TO_SINK(&sink, INFO) << "LOG_TO_SINK: " << "collected info"; 488 LOG_TO_SINK(&sink, WARNING) << "LOG_TO_SINK: " << "collected warning"; 489 LOG_TO_SINK(&sink, ERROR) << "LOG_TO_SINK: " << "collected error"; 490 491 LOG_TO_SINK(no_sink, INFO) << "LOG_TO_SINK: " << "reported info"; 492 LOG_TO_SINK(no_sink, WARNING) << "LOG_TO_SINK: " << "reported warning"; 493 LOG_TO_SINK(NULL, ERROR) << "LOG_TO_SINK: " << "reported error"; 494 495 LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, INFO) 496 << "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected info"; 497 LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, WARNING) 498 << "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected warning"; 499 LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, ERROR) 500 << "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "collected error"; 501 502 LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, INFO) 503 << "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "thrashed info"; 504 LOG_TO_SINK_BUT_NOT_TO_LOGFILE(no_sink, WARNING) 505 << "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "thrashed warning"; 506 LOG_TO_SINK_BUT_NOT_TO_LOGFILE(NULL, ERROR) 507 << "LOG_TO_SINK_BUT_NOT_TO_LOGFILE: " << "thrashed error"; 508 509 LOG(INFO) << "Captured by LOG_TO_SINK:"; 510 for (size_t i = 0; i < sink.errors.size(); ++i) { 511 LogMessage("foo", LogMessage::kNoLogPrefix, INFO).stream() 512 << sink.errors[i]; 513 } 514} 515 516// For testing using CHECK*() on anonymous enums. 517enum { 518 CASE_A, 519 CASE_B 520}; 521 522void TestCHECK() { 523 // Tests using CHECK*() on int values. 524 CHECK(1 == 1); 525 CHECK_EQ(1, 1); 526 CHECK_NE(1, 2); 527 CHECK_GE(1, 1); 528 CHECK_GE(2, 1); 529 CHECK_LE(1, 1); 530 CHECK_LE(1, 2); 531 CHECK_GT(2, 1); 532 CHECK_LT(1, 2); 533 534 // Tests using CHECK*() on anonymous enums. 535 // Apple's GCC doesn't like this. 536#if !defined(OS_MACOSX) 537 CHECK_EQ(CASE_A, CASE_A); 538 CHECK_NE(CASE_A, CASE_B); 539 CHECK_GE(CASE_A, CASE_A); 540 CHECK_GE(CASE_B, CASE_A); 541 CHECK_LE(CASE_A, CASE_A); 542 CHECK_LE(CASE_A, CASE_B); 543 CHECK_GT(CASE_B, CASE_A); 544 CHECK_LT(CASE_A, CASE_B); 545#endif 546} 547 548void TestDCHECK() { 549#ifdef NDEBUG 550 DCHECK( 1 == 2 ) << " DCHECK's shouldn't be compiled in normal mode"; 551#endif 552 DCHECK( 1 == 1 ); 553 DCHECK_EQ(1, 1); 554 DCHECK_NE(1, 2); 555 DCHECK_GE(1, 1); 556 DCHECK_GE(2, 1); 557 DCHECK_LE(1, 1); 558 DCHECK_LE(1, 2); 559 DCHECK_GT(2, 1); 560 DCHECK_LT(1, 2); 561 562 auto_ptr<int64> sptr(new int64); 563 int64* ptr = DCHECK_NOTNULL(sptr.get()); 564 CHECK_EQ(ptr, sptr.get()); 565} 566 567void TestSTREQ() { 568 CHECK_STREQ("this", "this"); 569 CHECK_STREQ(NULL, NULL); 570 CHECK_STRCASEEQ("this", "tHiS"); 571 CHECK_STRCASEEQ(NULL, NULL); 572 CHECK_STRNE("this", "tHiS"); 573 CHECK_STRNE("this", NULL); 574 CHECK_STRCASENE("this", "that"); 575 CHECK_STRCASENE(NULL, "that"); 576 CHECK_STREQ((string("a")+"b").c_str(), "ab"); 577 CHECK_STREQ(string("test").c_str(), 578 (string("te") + string("st")).c_str()); 579} 580 581TEST(DeathSTREQ, logging) { 582 ASSERT_DEATH(CHECK_STREQ(NULL, "this"), ""); 583 ASSERT_DEATH(CHECK_STREQ("this", "siht"), ""); 584 ASSERT_DEATH(CHECK_STRCASEEQ(NULL, "siht"), ""); 585 ASSERT_DEATH(CHECK_STRCASEEQ("this", "siht"), ""); 586 ASSERT_DEATH(CHECK_STRNE(NULL, NULL), ""); 587 ASSERT_DEATH(CHECK_STRNE("this", "this"), ""); 588 ASSERT_DEATH(CHECK_STREQ((string("a")+"b").c_str(), "abc"), ""); 589} 590 591TEST(CheckNOTNULL, Simple) { 592 int64 t; 593 void *ptr = static_cast<void *>(&t); 594 void *ref = CHECK_NOTNULL(ptr); 595 EXPECT_EQ(ptr, ref); 596 CHECK_NOTNULL(reinterpret_cast<char *>(ptr)); 597 CHECK_NOTNULL(reinterpret_cast<unsigned char *>(ptr)); 598 CHECK_NOTNULL(reinterpret_cast<int *>(ptr)); 599 CHECK_NOTNULL(reinterpret_cast<int64 *>(ptr)); 600} 601 602TEST(DeathCheckNN, Simple) { 603 ASSERT_DEATH(CHECK_NOTNULL(static_cast<void *>(NULL)), ""); 604} 605 606// Get list of file names that match pattern 607static void GetFiles(const string& pattern, vector<string>* files) { 608 files->clear(); 609#if defined(HAVE_GLOB_H) 610 glob_t g; 611 const int r = glob(pattern.c_str(), 0, NULL, &g); 612 CHECK((r == 0) || (r == GLOB_NOMATCH)) << ": error matching " << pattern; 613 for (int i = 0; i < g.gl_pathc; i++) { 614 files->push_back(string(g.gl_pathv[i])); 615 } 616 globfree(&g); 617#elif defined(OS_WINDOWS) 618 WIN32_FIND_DATAA data; 619 HANDLE handle = FindFirstFileA(pattern.c_str(), &data); 620 size_t index = pattern.rfind('\\'); 621 if (index == string::npos) { 622 LOG(FATAL) << "No directory separator."; 623 } 624 const string dirname = pattern.substr(0, index + 1); 625 if (FAILED(handle)) { 626 // Finding no files is OK. 627 return; 628 } 629 do { 630 files->push_back(dirname + data.cFileName); 631 } while (FindNextFileA(handle, &data)); 632 LOG_SYSRESULT(FindClose(handle)); 633#else 634# error There is no way to do glob. 635#endif 636} 637 638// Delete files patching pattern 639static void DeleteFiles(const string& pattern) { 640 vector<string> files; 641 GetFiles(pattern, &files); 642 for (size_t i = 0; i < files.size(); i++) { 643 CHECK(unlink(files[i].c_str()) == 0) << ": " << strerror(errno); 644 } 645} 646 647static void CheckFile(const string& name, const string& expected_string) { 648 vector<string> files; 649 GetFiles(name + "*", &files); 650 CHECK_EQ(files.size(), 1); 651 652 FILE* file = fopen(files[0].c_str(), "r"); 653 CHECK(file != NULL) << ": could not open " << files[0]; 654 char buf[1000]; 655 while (fgets(buf, sizeof(buf), file) != NULL) { 656 if (strstr(buf, expected_string.c_str()) != NULL) { 657 fclose(file); 658 return; 659 } 660 } 661 fclose(file); 662 LOG(FATAL) << "Did not find " << expected_string << " in " << files[0]; 663} 664 665static void TestBasename() { 666 fprintf(stderr, "==== Test setting log file basename\n"); 667 const string dest = FLAGS_test_tmpdir + "/logging_test_basename"; 668 DeleteFiles(dest + "*"); 669 670 SetLogDestination(INFO, dest.c_str()); 671 LOG(INFO) << "message to new base"; 672 FlushLogFiles(INFO); 673 674 CheckFile(dest, "message to new base"); 675 676 // Release file handle for the destination file to unlock the file in Windows. 677 LogToStderr(); 678 DeleteFiles(dest + "*"); 679} 680 681static void TestSymlink() { 682#ifndef OS_WINDOWS 683 fprintf(stderr, "==== Test setting log file symlink\n"); 684 string dest = FLAGS_test_tmpdir + "/logging_test_symlink"; 685 string sym = FLAGS_test_tmpdir + "/symlinkbase"; 686 DeleteFiles(dest + "*"); 687 DeleteFiles(sym + "*"); 688 689 SetLogSymlink(INFO, "symlinkbase"); 690 SetLogDestination(INFO, dest.c_str()); 691 LOG(INFO) << "message to new symlink"; 692 FlushLogFiles(INFO); 693 CheckFile(sym, "message to new symlink"); 694 695 DeleteFiles(dest + "*"); 696 DeleteFiles(sym + "*"); 697#endif 698} 699 700static void TestExtension() { 701 fprintf(stderr, "==== Test setting log file extension\n"); 702 string dest = FLAGS_test_tmpdir + "/logging_test_extension"; 703 DeleteFiles(dest + "*"); 704 705 SetLogDestination(INFO, dest.c_str()); 706 SetLogFilenameExtension("specialextension"); 707 LOG(INFO) << "message to new extension"; 708 FlushLogFiles(INFO); 709 CheckFile(dest, "message to new extension"); 710 711 // Check that file name ends with extension 712 vector<string> filenames; 713 GetFiles(dest + "*", &filenames); 714 CHECK_EQ(filenames.size(), 1); 715 CHECK(strstr(filenames[0].c_str(), "specialextension") != NULL); 716 717 // Release file handle for the destination file to unlock the file in Windows. 718 LogToStderr(); 719 DeleteFiles(dest + "*"); 720} 721 722struct MyLogger : public base::Logger { 723 string data; 724 725 virtual void Write(bool should_flush, 726 time_t timestamp, 727 const char* message, 728 int length) { 729 data.append(message, length); 730 } 731 732 virtual void Flush() { } 733 734 virtual uint32 LogSize() { return data.length(); } 735}; 736 737static void TestWrapper() { 738 fprintf(stderr, "==== Test log wrapper\n"); 739 740 MyLogger my_logger; 741 base::Logger* old_logger = base::GetLogger(INFO); 742 base::SetLogger(INFO, &my_logger); 743 LOG(INFO) << "Send to wrapped logger"; 744 FlushLogFiles(INFO); 745 base::SetLogger(INFO, old_logger); 746 747 CHECK(strstr(my_logger.data.c_str(), "Send to wrapped logger") != NULL); 748} 749 750static void TestErrno() { 751 fprintf(stderr, "==== Test errno preservation\n"); 752 753 errno = ENOENT; 754 TestLogging(false); 755 CHECK_EQ(errno, ENOENT); 756} 757 758static void TestOneTruncate(const char *path, int64 limit, int64 keep, 759 int64 dsize, int64 ksize, int64 expect) { 760 int fd; 761 CHECK_ERR(fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0600)); 762 763 const char *discardstr = "DISCARDME!", *keepstr = "KEEPME!"; 764 765 // Fill the file with the requested data; first discard data, then kept data 766 int64 written = 0; 767 while (written < dsize) { 768 int bytes = min<int64>(dsize - written, strlen(discardstr)); 769 CHECK_ERR(write(fd, discardstr, bytes)); 770 written += bytes; 771 } 772 written = 0; 773 while (written < ksize) { 774 int bytes = min<int64>(ksize - written, strlen(keepstr)); 775 CHECK_ERR(write(fd, keepstr, bytes)); 776 written += bytes; 777 } 778 779 TruncateLogFile(path, limit, keep); 780 781 // File should now be shorter 782 struct stat statbuf; 783 CHECK_ERR(fstat(fd, &statbuf)); 784 CHECK_EQ(statbuf.st_size, expect); 785 CHECK_ERR(lseek(fd, 0, SEEK_SET)); 786 787 // File should contain the suffix of the original file 788 int buf_size = statbuf.st_size + 1; 789 char* buf = new char[buf_size]; 790 memset(buf, 0, sizeof(buf)); 791 CHECK_ERR(read(fd, buf, buf_size)); 792 793 const char *p = buf; 794 int64 checked = 0; 795 while (checked < expect) { 796 int bytes = min<int64>(expect - checked, strlen(keepstr)); 797 CHECK(!memcmp(p, keepstr, bytes)); 798 checked += bytes; 799 } 800 close(fd); 801 delete[] buf; 802} 803 804static void TestTruncate() { 805#ifdef HAVE_UNISTD_H 806 fprintf(stderr, "==== Test log truncation\n"); 807 string path = FLAGS_test_tmpdir + "/truncatefile"; 808 809 // Test on a small file 810 TestOneTruncate(path.c_str(), 10, 10, 10, 10, 10); 811 812 // And a big file (multiple blocks to copy) 813 TestOneTruncate(path.c_str(), 2<<20, 4<<10, 3<<20, 4<<10, 4<<10); 814 815 // Check edge-case limits 816 TestOneTruncate(path.c_str(), 10, 20, 0, 20, 20); 817 TestOneTruncate(path.c_str(), 10, 0, 0, 0, 0); 818 TestOneTruncate(path.c_str(), 10, 50, 0, 10, 10); 819 TestOneTruncate(path.c_str(), 50, 100, 0, 30, 30); 820 821 // MacOSX 10.4 doesn't fail in this case. 822 // Windows doesn't have symlink. 823 // Let's just ignore this test for these cases. 824#if !defined(OS_MACOSX) && !defined(OS_WINDOWS) 825 // Through a symlink should fail to truncate 826 string linkname = path + ".link"; 827 unlink(linkname.c_str()); 828 CHECK_ERR(symlink(path.c_str(), linkname.c_str())); 829 TestOneTruncate(linkname.c_str(), 10, 10, 0, 30, 30); 830#endif 831 832 // The /proc/self path makes sense only for linux. 833#if defined(OS_LINUX) 834 // Through an open fd symlink should work 835 int fd; 836 CHECK_ERR(fd = open(path.c_str(), O_APPEND | O_WRONLY)); 837 char fdpath[64]; 838 snprintf(fdpath, sizeof(fdpath), "/proc/self/fd/%d", fd); 839 TestOneTruncate(fdpath, 10, 10, 10, 10, 10); 840#endif 841 842#endif 843} 844 845_START_GOOGLE_NAMESPACE_ 846namespace glog_internal_namespace_ { 847extern // in logging.cc 848bool SafeFNMatch_(const char* pattern, size_t patt_len, 849 const char* str, size_t str_len); 850} // namespace glog_internal_namespace_ 851using glog_internal_namespace_::SafeFNMatch_; 852_END_GOOGLE_NAMESPACE_ 853 854static bool WrapSafeFNMatch(string pattern, string str) { 855 pattern += "abc"; 856 str += "defgh"; 857 return SafeFNMatch_(pattern.data(), pattern.size() - 3, 858 str.data(), str.size() - 5); 859} 860 861TEST(SafeFNMatch, logging) { 862 CHECK(WrapSafeFNMatch("foo", "foo")); 863 CHECK(!WrapSafeFNMatch("foo", "bar")); 864 CHECK(!WrapSafeFNMatch("foo", "fo")); 865 CHECK(!WrapSafeFNMatch("foo", "foo2")); 866 CHECK(WrapSafeFNMatch("bar/foo.ext", "bar/foo.ext")); 867 CHECK(WrapSafeFNMatch("*ba*r/fo*o.ext*", "bar/foo.ext")); 868 CHECK(!WrapSafeFNMatch("bar/foo.ext", "bar/baz.ext")); 869 CHECK(!WrapSafeFNMatch("bar/foo.ext", "bar/foo")); 870 CHECK(!WrapSafeFNMatch("bar/foo.ext", "bar/foo.ext.zip")); 871 CHECK(WrapSafeFNMatch("ba?/*.ext", "bar/foo.ext")); 872 CHECK(WrapSafeFNMatch("ba?/*.ext", "baZ/FOO.ext")); 873 CHECK(!WrapSafeFNMatch("ba?/*.ext", "barr/foo.ext")); 874 CHECK(!WrapSafeFNMatch("ba?/*.ext", "bar/foo.ext2")); 875 CHECK(WrapSafeFNMatch("ba?/*", "bar/foo.ext2")); 876 CHECK(WrapSafeFNMatch("ba?/*", "bar/")); 877 CHECK(!WrapSafeFNMatch("ba?/?", "bar/")); 878 CHECK(!WrapSafeFNMatch("ba?/*", "bar")); 879} 880 881// TestWaitingLogSink will save messages here 882// No lock: Accessed only by TestLogSinkWriter thread 883// and after its demise by its creator. 884static vector<string> global_messages; 885 886// helper for TestWaitingLogSink below. 887// Thread that does the logic of TestWaitingLogSink 888// It's free to use LOG() itself. 889class TestLogSinkWriter : public Thread { 890 public: 891 892 TestLogSinkWriter() : should_exit_(false) { 893 SetJoinable(true); 894 Start(); 895 } 896 897 // Just buffer it (can't use LOG() here). 898 void Buffer(const string& message) { 899 mutex_.Lock(); 900 RAW_LOG(INFO, "Buffering"); 901 messages_.push(message); 902 mutex_.Unlock(); 903 RAW_LOG(INFO, "Buffered"); 904 } 905 906 // Wait for the buffer to clear (can't use LOG() here). 907 void Wait() { 908 RAW_LOG(INFO, "Waiting"); 909 mutex_.Lock(); 910 while (!NoWork()) { 911 mutex_.Unlock(); 912 SleepForMilliseconds(1); 913 mutex_.Lock(); 914 } 915 RAW_LOG(INFO, "Waited"); 916 mutex_.Unlock(); 917 } 918 919 // Trigger thread exit. 920 void Stop() { 921 MutexLock l(&mutex_); 922 should_exit_ = true; 923 } 924 925 private: 926 927 // helpers --------------- 928 929 // For creating a "Condition". 930 bool NoWork() { return messages_.empty(); } 931 bool HaveWork() { return !messages_.empty() || should_exit_; } 932 933 // Thread body; CAN use LOG() here! 934 virtual void Run() { 935 while (1) { 936 mutex_.Lock(); 937 while (!HaveWork()) { 938 mutex_.Unlock(); 939 SleepForMilliseconds(1); 940 mutex_.Lock(); 941 } 942 if (should_exit_ && messages_.empty()) { 943 mutex_.Unlock(); 944 break; 945 } 946 // Give the main thread time to log its message, 947 // so that we get a reliable log capture to compare to golden file. 948 // Same for the other sleep below. 949 SleepForMilliseconds(20); 950 RAW_LOG(INFO, "Sink got a messages"); // only RAW_LOG under mutex_ here 951 string message = messages_.front(); 952 messages_.pop(); 953 // Normally this would be some more real/involved logging logic 954 // where LOG() usage can't be eliminated, 955 // e.g. pushing the message over with an RPC: 956 int messages_left = messages_.size(); 957 mutex_.Unlock(); 958 SleepForMilliseconds(20); 959 // May not use LOG while holding mutex_, because Buffer() 960 // acquires mutex_, and Buffer is called from LOG(), 961 // which has its own internal mutex: 962 // LOG()->LogToSinks()->TestWaitingLogSink::send()->Buffer() 963 LOG(INFO) << "Sink is sending out a message: " << message; 964 LOG(INFO) << "Have " << messages_left << " left"; 965 global_messages.push_back(message); 966 } 967 } 968 969 // data --------------- 970 971 Mutex mutex_; 972 bool should_exit_; 973 queue<string> messages_; // messages to be logged 974}; 975 976// A log sink that exercises WaitTillSent: 977// it pushes data to a buffer and wakes up another thread to do the logging 978// (that other thread can than use LOG() itself), 979class TestWaitingLogSink : public LogSink { 980 public: 981 982 TestWaitingLogSink() { 983 tid_ = pthread_self(); // for thread-specific behavior 984 AddLogSink(this); 985 } 986 ~TestWaitingLogSink() { 987 RemoveLogSink(this); 988 writer_.Stop(); 989 writer_.Join(); 990 } 991 992 // (re)define LogSink interface 993 994 virtual void send(LogSeverity severity, const char* full_filename, 995 const char* base_filename, int line, 996 const struct tm* tm_time, 997 const char* message, size_t message_len) { 998 // Push it to Writer thread if we are the original logging thread. 999 // Note: Something like ThreadLocalLogSink is a better choice 1000 // to do thread-specific LogSink logic for real. 1001 if (pthread_equal(tid_, pthread_self())) { 1002 writer_.Buffer(ToString(severity, base_filename, line, 1003 tm_time, message, message_len)); 1004 } 1005 } 1006 virtual void WaitTillSent() { 1007 // Wait for Writer thread if we are the original logging thread. 1008 if (pthread_equal(tid_, pthread_self())) writer_.Wait(); 1009 } 1010 1011 private: 1012 1013 pthread_t tid_; 1014 TestLogSinkWriter writer_; 1015}; 1016 1017// Check that LogSink::WaitTillSent can be used in the advertised way. 1018// We also do golden-stderr comparison. 1019static void TestLogSinkWaitTillSent() { 1020 { TestWaitingLogSink sink; 1021 // Sleeps give the sink threads time to do all their work, 1022 // so that we get a reliable log capture to compare to the golden file. 1023 LOG(INFO) << "Message 1"; 1024 SleepForMilliseconds(60); 1025 LOG(ERROR) << "Message 2"; 1026 SleepForMilliseconds(60); 1027 LOG(WARNING) << "Message 3"; 1028 SleepForMilliseconds(60); 1029 } 1030 for (size_t i = 0; i < global_messages.size(); ++i) { 1031 LOG(INFO) << "Sink capture: " << global_messages[i]; 1032 } 1033 CHECK_EQ(global_messages.size(), 3); 1034} 1035 1036TEST(Strerror, logging) { 1037 int errcode = EINTR; 1038 char *msg = strdup(strerror(errcode)); 1039 int buf_size = strlen(msg) + 1; 1040 char *buf = new char[buf_size]; 1041 CHECK_EQ(posix_strerror_r(errcode, NULL, 0), -1); 1042 buf[0] = 'A'; 1043 CHECK_EQ(posix_strerror_r(errcode, buf, 0), -1); 1044 CHECK_EQ(buf[0], 'A'); 1045 CHECK_EQ(posix_strerror_r(errcode, NULL, buf_size), -1); 1046#if defined(OS_MACOSX) || defined(OS_FREEBSD) || defined(OS_OPENBSD) 1047 // MacOSX or FreeBSD considers this case is an error since there is 1048 // no enough space. 1049 CHECK_EQ(posix_strerror_r(errcode, buf, 1), -1); 1050#else 1051 CHECK_EQ(posix_strerror_r(errcode, buf, 1), 0); 1052#endif 1053 CHECK_STREQ(buf, ""); 1054 CHECK_EQ(posix_strerror_r(errcode, buf, buf_size), 0); 1055 CHECK_STREQ(buf, msg); 1056 free(msg); 1057 delete[] buf; 1058} 1059 1060// Simple routines to look at the sizes of generated code for LOG(FATAL) and 1061// CHECK(..) via objdump 1062void MyFatal() { 1063 LOG(FATAL) << "Failed"; 1064} 1065void MyCheck(bool a, bool b) { 1066 CHECK_EQ(a, b); 1067} 1068 1069#ifdef HAVE_LIB_GMOCK 1070 1071TEST(DVLog, Basic) { 1072 ScopedMockLog log; 1073 1074#if NDEBUG 1075 // We are expecting that nothing is logged. 1076 EXPECT_CALL(log, Log(_, _, _)).Times(0); 1077#else 1078 EXPECT_CALL(log, Log(INFO, __FILE__, "debug log")); 1079#endif 1080 1081 FLAGS_v = 1; 1082 DVLOG(1) << "debug log"; 1083} 1084 1085TEST(DVLog, V0) { 1086 ScopedMockLog log; 1087 1088 // We are expecting that nothing is logged. 1089 EXPECT_CALL(log, Log(_, _, _)).Times(0); 1090 1091 FLAGS_v = 0; 1092 DVLOG(1) << "debug log"; 1093} 1094 1095TEST(LogAtLevel, Basic) { 1096 ScopedMockLog log; 1097 1098 // The function version outputs "logging.h" as a file name. 1099 EXPECT_CALL(log, Log(WARNING, StrNe(__FILE__), "function version")); 1100 EXPECT_CALL(log, Log(INFO, __FILE__, "macro version")); 1101 1102 int severity = WARNING; 1103 LogAtLevel(severity, "function version"); 1104 1105 severity = INFO; 1106 // We can use the macro version as a C++ stream. 1107 LOG_AT_LEVEL(severity) << "macro" << ' ' << "version"; 1108} 1109 1110TEST(TestExitOnDFatal, ToBeOrNotToBe) { 1111 // Check the default setting... 1112 EXPECT_TRUE(base::internal::GetExitOnDFatal()); 1113 1114 // Turn off... 1115 base::internal::SetExitOnDFatal(false); 1116 EXPECT_FALSE(base::internal::GetExitOnDFatal()); 1117 1118 // We don't die. 1119 { 1120 ScopedMockLog log; 1121 //EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); 1122 // LOG(DFATAL) has severity FATAL if debugging, but is 1123 // downgraded to ERROR if not debugging. 1124 const LogSeverity severity = 1125#ifdef NDEBUG 1126 ERROR; 1127#else 1128 FATAL; 1129#endif 1130 EXPECT_CALL(log, Log(severity, __FILE__, "This should not be fatal")); 1131 LOG(DFATAL) << "This should not be fatal"; 1132 } 1133 1134 // Turn back on... 1135 base::internal::SetExitOnDFatal(true); 1136 EXPECT_TRUE(base::internal::GetExitOnDFatal()); 1137 1138#ifdef GTEST_HAS_DEATH_TEST 1139 // Death comes on little cats' feet. 1140 EXPECT_DEBUG_DEATH({ 1141 LOG(DFATAL) << "This should be fatal in debug mode"; 1142 }, "This should be fatal in debug mode"); 1143#endif 1144} 1145 1146#ifdef HAVE_STACKTRACE 1147 1148static void BacktraceAtHelper() { 1149 LOG(INFO) << "Not me"; 1150 1151// The vertical spacing of the next 3 lines is significant. 1152 LOG(INFO) << "Backtrace me"; 1153} 1154static int kBacktraceAtLine = __LINE__ - 2; // The line of the LOG(INFO) above 1155 1156TEST(LogBacktraceAt, DoesNotBacktraceWhenDisabled) { 1157 StrictMock<ScopedMockLog> log; 1158 1159 FLAGS_log_backtrace_at = ""; 1160 1161 EXPECT_CALL(log, Log(_, _, "Backtrace me")); 1162 EXPECT_CALL(log, Log(_, _, "Not me")); 1163 1164 BacktraceAtHelper(); 1165} 1166 1167TEST(LogBacktraceAt, DoesBacktraceAtRightLineWhenEnabled) { 1168 StrictMock<ScopedMockLog> log; 1169 1170 char where[100]; 1171 snprintf(where, 100, "%s:%d", const_basename(__FILE__), kBacktraceAtLine); 1172 FLAGS_log_backtrace_at = where; 1173 1174 // The LOG at the specified line should include a stacktrace which includes 1175 // the name of the containing function, followed by the log message. 1176 // We use HasSubstr()s instead of ContainsRegex() for environments 1177 // which don't have regexp. 1178 EXPECT_CALL(log, Log(_, _, AllOf(HasSubstr("stacktrace:"), 1179 HasSubstr("BacktraceAtHelper"), 1180 HasSubstr("main"), 1181 HasSubstr("Backtrace me")))); 1182 // Other LOGs should not include a backtrace. 1183 EXPECT_CALL(log, Log(_, _, "Not me")); 1184 1185 BacktraceAtHelper(); 1186} 1187 1188#endif // HAVE_STACKTRACE 1189 1190#endif // HAVE_LIB_GMOCK 1191 1192struct UserDefinedClass { 1193 bool operator==(const UserDefinedClass& rhs) const { return true; } 1194}; 1195 1196inline ostream& operator<<(ostream& out, const UserDefinedClass& u) { 1197 out << "OK"; 1198 return out; 1199} 1200 1201TEST(UserDefinedClass, logging) { 1202 UserDefinedClass u; 1203 vector<string> buf; 1204 LOG_STRING(INFO, &buf) << u; 1205 CHECK_EQ(1, buf.size()); 1206 CHECK(buf[0].find("OK") != string::npos); 1207 1208 // We must be able to compile this. 1209 CHECK_EQ(u, u); 1210}