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