blob: 57613614b89d8fbe552e8a1a6a0a26d0429a04f0 [file] [log] [blame]
Austin Schuh906616c2019-01-21 20:25:11 -08001// Copyright (c) 2009, 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: Shinichiro Hamaji
31// (based on googletest: http://code.google.com/p/googletest/)
32
33#ifdef GOOGLETEST_H__
34#error You must not include this file twice.
35#endif
36#define GOOGLETEST_H__
37
38#include "utilities.h"
39
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070040#include <cctype>
41#include <csetjmp>
42#include <cstdio>
43#include <cstdlib>
44#include <ctime>
Austin Schuh906616c2019-01-21 20:25:11 -080045#include <map>
46#include <sstream>
47#include <string>
48#include <vector>
49
Austin Schuh906616c2019-01-21 20:25:11 -080050#include <sys/types.h>
51#include <sys/stat.h>
52#include <fcntl.h>
53#ifdef HAVE_UNISTD_H
54# include <unistd.h>
55#endif
56
57#include "base/commandlineflags.h"
58
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070059#if __cplusplus < 201103L && !defined(_MSC_VER)
60#define GOOGLE_GLOG_THROW_BAD_ALLOC throw (std::bad_alloc)
61#else
62#define GOOGLE_GLOG_THROW_BAD_ALLOC
63#endif
64
Austin Schuh906616c2019-01-21 20:25:11 -080065using std::map;
66using std::string;
67using std::vector;
68
69_START_GOOGLE_NAMESPACE_
70
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070071extern GLOG_EXPORT void (*g_logging_fail_func)();
Austin Schuh906616c2019-01-21 20:25:11 -080072
73_END_GOOGLE_NAMESPACE_
74
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070075#undef GLOG_EXPORT
76#define GLOG_EXPORT
Austin Schuh906616c2019-01-21 20:25:11 -080077
78static inline string GetTempDir() {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070079 vector<string> temp_directories_list;
80 google::GetExistingTempDirectories(&temp_directories_list);
81
82 if (temp_directories_list.empty()) {
83 fprintf(stderr, "No temporary directory found\n");
84 exit(EXIT_FAILURE);
85 }
86
87 // Use first directory from list of existing temporary directories.
88 return temp_directories_list.front();
Austin Schuh906616c2019-01-21 20:25:11 -080089}
90
James Kuszmaulba0ac1a2022-08-12 16:29:30 -070091#if defined(GLOG_OS_WINDOWS) && defined(_MSC_VER) && !defined(TEST_SRC_DIR)
Austin Schuh906616c2019-01-21 20:25:11 -080092// The test will run in glog/vsproject/<project name>
93// (e.g., glog/vsproject/logging_unittest).
94static const char TEST_SRC_DIR[] = "../..";
95#elif !defined(TEST_SRC_DIR)
96# warning TEST_SRC_DIR should be defined in config.h
97static const char TEST_SRC_DIR[] = ".";
98#endif
99
100static const uint32_t PTR_TEST_VALUE = 0x12345678;
101
102DEFINE_string(test_tmpdir, GetTempDir(), "Dir we use for temp files");
103DEFINE_string(test_srcdir, TEST_SRC_DIR,
104 "Source-dir root, needed to find glog_unittest_flagfile");
105DEFINE_bool(run_benchmark, false, "If true, run benchmarks");
106#ifdef NDEBUG
107DEFINE_int32(benchmark_iters, 100000000, "Number of iterations per benchmark");
108#else
109DEFINE_int32(benchmark_iters, 100000, "Number of iterations per benchmark");
110#endif
111
112#ifdef HAVE_LIB_GTEST
113# include <gtest/gtest.h>
114// Use our ASSERT_DEATH implementation.
115# undef ASSERT_DEATH
116# undef ASSERT_DEBUG_DEATH
117using testing::InitGoogleTest;
118#else
119
120_START_GOOGLE_NAMESPACE_
121
122void InitGoogleTest(int*, char**);
123
124void InitGoogleTest(int*, char**) {}
125
126// The following is some bare-bones testing infrastructure
127
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700128#define EXPECT_NEAR(val1, val2, abs_error) \
129 do { \
130 if (abs(val1 - val2) > abs_error) { \
131 fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, #abs_error, \
132 #val2); \
133 exit(EXIT_FAILURE); \
134 } \
135 } while (0)
136
Austin Schuh906616c2019-01-21 20:25:11 -0800137#define EXPECT_TRUE(cond) \
138 do { \
139 if (!(cond)) { \
140 fprintf(stderr, "Check failed: %s\n", #cond); \
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700141 exit(EXIT_FAILURE); \
Austin Schuh906616c2019-01-21 20:25:11 -0800142 } \
143 } while (0)
144
145#define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
146
147#define EXPECT_OP(op, val1, val2) \
148 do { \
149 if (!((val1) op (val2))) { \
150 fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700151 exit(EXIT_FAILURE); \
Austin Schuh906616c2019-01-21 20:25:11 -0800152 } \
153 } while (0)
154
155#define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)
156#define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)
157#define EXPECT_GT(val1, val2) EXPECT_OP(>, val1, val2)
158#define EXPECT_LT(val1, val2) EXPECT_OP(<, val1, val2)
159
160#define EXPECT_NAN(arg) \
161 do { \
162 if (!isnan(arg)) { \
163 fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700164 exit(EXIT_FAILURE); \
Austin Schuh906616c2019-01-21 20:25:11 -0800165 } \
166 } while (0)
167
168#define EXPECT_INF(arg) \
169 do { \
170 if (!isinf(arg)) { \
171 fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700172 exit(EXIT_FAILURE); \
Austin Schuh906616c2019-01-21 20:25:11 -0800173 } \
174 } while (0)
175
176#define EXPECT_DOUBLE_EQ(val1, val2) \
177 do { \
178 if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) { \
179 fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700180 exit(EXIT_FAILURE); \
Austin Schuh906616c2019-01-21 20:25:11 -0800181 } \
182 } while (0)
183
184#define EXPECT_STREQ(val1, val2) \
185 do { \
186 if (strcmp((val1), (val2)) != 0) { \
187 fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700188 exit(EXIT_FAILURE); \
Austin Schuh906616c2019-01-21 20:25:11 -0800189 } \
190 } while (0)
191
192vector<void (*)()> g_testlist; // the tests to run
193
194#define TEST(a, b) \
195 struct Test_##a##_##b { \
196 Test_##a##_##b() { g_testlist.push_back(&Run); } \
197 static void Run() { FlagSaver fs; RunTest(); } \
198 static void RunTest(); \
199 }; \
200 static Test_##a##_##b g_test_##a##_##b; \
201 void Test_##a##_##b::RunTest()
202
203
204static inline int RUN_ALL_TESTS() {
205 vector<void (*)()>::const_iterator it;
206 for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {
207 (*it)();
208 }
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700209 fprintf(stderr, "Passed %d tests\n\nPASS\n",
210 static_cast<int>(g_testlist.size()));
Austin Schuh906616c2019-01-21 20:25:11 -0800211 return 0;
212}
213
214_END_GOOGLE_NAMESPACE_
215
216#endif // ! HAVE_LIB_GTEST
217
218_START_GOOGLE_NAMESPACE_
219
220static bool g_called_abort;
221static jmp_buf g_jmp_buf;
222static inline void CalledAbort() {
223 g_called_abort = true;
224 longjmp(g_jmp_buf, 1);
225}
226
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700227#ifdef GLOG_OS_WINDOWS
Austin Schuh906616c2019-01-21 20:25:11 -0800228// TODO(hamaji): Death test somehow doesn't work in Windows.
229#define ASSERT_DEATH(fn, msg)
230#else
231#define ASSERT_DEATH(fn, msg) \
232 do { \
233 g_called_abort = false; \
234 /* in logging.cc */ \
235 void (*original_logging_fail_func)() = g_logging_fail_func; \
236 g_logging_fail_func = &CalledAbort; \
237 if (!setjmp(g_jmp_buf)) fn; \
238 /* set back to their default */ \
239 g_logging_fail_func = original_logging_fail_func; \
240 if (!g_called_abort) { \
241 fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700242 exit(EXIT_FAILURE); \
Austin Schuh906616c2019-01-21 20:25:11 -0800243 } \
244 } while (0)
245#endif
246
247#ifdef NDEBUG
248#define ASSERT_DEBUG_DEATH(fn, msg)
249#else
250#define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)
251#endif // NDEBUG
252
253// Benchmark tools.
254
255#define BENCHMARK(n) static BenchmarkRegisterer __benchmark_ ## n (#n, &n);
256
257map<string, void (*)(int)> g_benchlist; // the benchmarks to run
258
259class BenchmarkRegisterer {
260 public:
261 BenchmarkRegisterer(const char* name, void (*function)(int iters)) {
262 EXPECT_TRUE(g_benchlist.insert(std::make_pair(name, function)).second);
263 }
264};
265
266static inline void RunSpecifiedBenchmarks() {
267 if (!FLAGS_run_benchmark) {
268 return;
269 }
270
271 int iter_cnt = FLAGS_benchmark_iters;
272 puts("Benchmark\tTime(ns)\tIterations");
273 for (map<string, void (*)(int)>::const_iterator iter = g_benchlist.begin();
274 iter != g_benchlist.end();
275 ++iter) {
276 clock_t start = clock();
277 iter->second(iter_cnt);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700278 double elapsed_ns = (static_cast<double>(clock()) - start) /
279 CLOCKS_PER_SEC * 1000 * 1000 * 1000;
280#if defined(__GNUC__) && !defined(__clang__)
281#pragma GCC diagnostic push
282#pragma GCC diagnostic ignored "-Wformat="
283#endif
Austin Schuh906616c2019-01-21 20:25:11 -0800284 printf("%s\t%8.2lf\t%10d\n",
285 iter->first.c_str(), elapsed_ns / iter_cnt, iter_cnt);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700286#if defined(__GNUC__) && !defined(__clang__)
287#pragma GCC diagnostic pop
288#endif
Austin Schuh906616c2019-01-21 20:25:11 -0800289 }
290 puts("");
291}
292
293// ----------------------------------------------------------------------
294// Golden file functions
295// ----------------------------------------------------------------------
296
297class CapturedStream {
298 public:
299 CapturedStream(int fd, const string & filename) :
300 fd_(fd),
301 uncaptured_fd_(-1),
302 filename_(filename) {
303 Capture();
304 }
305
306 ~CapturedStream() {
307 if (uncaptured_fd_ != -1) {
308 CHECK(close(uncaptured_fd_) != -1);
309 }
310 }
311
312 // Start redirecting output to a file
313 void Capture() {
314 // Keep original stream for later
315 CHECK(uncaptured_fd_ == -1) << ", Stream " << fd_ << " already captured!";
316 uncaptured_fd_ = dup(fd_);
317 CHECK(uncaptured_fd_ != -1);
318
319 // Open file to save stream to
320 int cap_fd = open(filename_.c_str(),
321 O_CREAT | O_TRUNC | O_WRONLY,
322 S_IRUSR | S_IWUSR);
323 CHECK(cap_fd != -1);
324
325 // Send stdout/stderr to this file
326 fflush(NULL);
327 CHECK(dup2(cap_fd, fd_) != -1);
328 CHECK(close(cap_fd) != -1);
329 }
330
331 // Remove output redirection
332 void StopCapture() {
333 // Restore original stream
334 if (uncaptured_fd_ != -1) {
335 fflush(NULL);
336 CHECK(dup2(uncaptured_fd_, fd_) != -1);
337 }
338 }
339
340 const string & filename() const { return filename_; }
341
342 private:
343 int fd_; // file descriptor being captured
344 int uncaptured_fd_; // where the stream was originally being sent to
345 string filename_; // file where stream is being saved
346};
347static CapturedStream * s_captured_streams[STDERR_FILENO+1];
348// Redirect a file descriptor to a file.
349// fd - Should be STDOUT_FILENO or STDERR_FILENO
350// filename - File where output should be stored
351static inline void CaptureTestOutput(int fd, const string & filename) {
352 CHECK((fd == STDOUT_FILENO) || (fd == STDERR_FILENO));
353 CHECK(s_captured_streams[fd] == NULL);
354 s_captured_streams[fd] = new CapturedStream(fd, filename);
355}
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700356static inline void CaptureTestStdout() {
357 CaptureTestOutput(STDOUT_FILENO, FLAGS_test_tmpdir + "/captured.out");
358}
Austin Schuh906616c2019-01-21 20:25:11 -0800359static inline void CaptureTestStderr() {
360 CaptureTestOutput(STDERR_FILENO, FLAGS_test_tmpdir + "/captured.err");
361}
362// Return the size (in bytes) of a file
363static inline size_t GetFileSize(FILE * file) {
364 fseek(file, 0, SEEK_END);
365 return static_cast<size_t>(ftell(file));
366}
367// Read the entire content of a file as a string
368static inline string ReadEntireFile(FILE * file) {
369 const size_t file_size = GetFileSize(file);
370 char * const buffer = new char[file_size];
371
372 size_t bytes_last_read = 0; // # of bytes read in the last fread()
373 size_t bytes_read = 0; // # of bytes read so far
374
375 fseek(file, 0, SEEK_SET);
376
377 // Keep reading the file until we cannot read further or the
378 // pre-determined file size is reached.
379 do {
380 bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
381 bytes_read += bytes_last_read;
382 } while (bytes_last_read > 0 && bytes_read < file_size);
383
384 const string content = string(buffer, buffer+bytes_read);
385 delete[] buffer;
386
387 return content;
388}
389// Get the captured stdout (when fd is STDOUT_FILENO) or stderr (when
390// fd is STDERR_FILENO) as a string
391static inline string GetCapturedTestOutput(int fd) {
392 CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
393 CapturedStream * const cap = s_captured_streams[fd];
394 CHECK(cap)
395 << ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
396
397 // Make sure everything is flushed.
398 cap->StopCapture();
399
400 // Read the captured file.
401 FILE * const file = fopen(cap->filename().c_str(), "r");
402 const string content = ReadEntireFile(file);
403 fclose(file);
404
405 delete cap;
406 s_captured_streams[fd] = NULL;
407
408 return content;
409}
410// Get the captured stderr of a test as a string.
411static inline string GetCapturedTestStderr() {
412 return GetCapturedTestOutput(STDERR_FILENO);
413}
414
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700415static const std::size_t kLoggingPrefixLength = 9;
416
417// Check if the string is [IWEF](\d{8}|YEARDATE)
Austin Schuh906616c2019-01-21 20:25:11 -0800418static inline bool IsLoggingPrefix(const string& s) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700419 if (s.size() != kLoggingPrefixLength) {
420 return false;
421 }
Austin Schuh906616c2019-01-21 20:25:11 -0800422 if (!strchr("IWEF", s[0])) return false;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700423 for (size_t i = 1; i <= 8; ++i) {
424 if (!isdigit(s[i]) && s[i] != "YEARDATE"[i-1]) return false;
Austin Schuh906616c2019-01-21 20:25:11 -0800425 }
426 return true;
427}
428
429// Convert log output into normalized form.
430//
431// Example:
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700432// I20200102 030405 logging_unittest.cc:345] RAW: vlog -1
433// => IYEARDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
Austin Schuh906616c2019-01-21 20:25:11 -0800434static inline string MungeLine(const string& line) {
Austin Schuh906616c2019-01-21 20:25:11 -0800435 string before, logcode_date, time, thread_lineinfo;
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700436 std::size_t begin_of_logging_prefix = 0;
437 for (; begin_of_logging_prefix + kLoggingPrefixLength < line.size();
438 ++begin_of_logging_prefix) {
439 if (IsLoggingPrefix(
440 line.substr(begin_of_logging_prefix, kLoggingPrefixLength))) {
441 break;
Austin Schuh906616c2019-01-21 20:25:11 -0800442 }
443 }
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700444 if (begin_of_logging_prefix + kLoggingPrefixLength >= line.size()) {
445 return line;
446 } else if (begin_of_logging_prefix > 0) {
447 before = line.substr(0, begin_of_logging_prefix - 1);
448 }
449 std::istringstream iss(line.substr(begin_of_logging_prefix));
450 iss >> logcode_date;
Austin Schuh906616c2019-01-21 20:25:11 -0800451 iss >> time;
452 iss >> thread_lineinfo;
453 CHECK(!thread_lineinfo.empty());
454 if (thread_lineinfo[thread_lineinfo.size() - 1] != ']') {
455 // We found thread ID.
456 string tmp;
457 iss >> tmp;
458 CHECK(!tmp.empty());
459 CHECK_EQ(']', tmp[tmp.size() - 1]);
460 thread_lineinfo = "THREADID " + tmp;
461 }
462 size_t index = thread_lineinfo.find(':');
463 CHECK_NE(string::npos, index);
464 thread_lineinfo = thread_lineinfo.substr(0, index+1) + "LINE]";
465 string rest;
466 std::getline(iss, rest);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700467 return (before + logcode_date[0] + "YEARDATE TIME__ " + thread_lineinfo +
Austin Schuh906616c2019-01-21 20:25:11 -0800468 MungeLine(rest));
469}
470
471static inline void StringReplace(string* str,
472 const string& oldsub,
473 const string& newsub) {
474 size_t pos = str->find(oldsub);
475 if (pos != string::npos) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700476 str->replace(pos, oldsub.size(), newsub);
Austin Schuh906616c2019-01-21 20:25:11 -0800477 }
478}
479
480static inline string Munge(const string& filename) {
481 FILE* fp = fopen(filename.c_str(), "rb");
482 CHECK(fp != NULL) << filename << ": couldn't open";
483 char buf[4096];
484 string result;
485 while (fgets(buf, 4095, fp)) {
486 string line = MungeLine(buf);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700487 const size_t str_size = 256;
488 char null_str[str_size];
489 char ptr_str[str_size];
490 snprintf(null_str, str_size, "%p", static_cast<void*>(NULL));
491 snprintf(ptr_str, str_size, "%p", reinterpret_cast<void*>(PTR_TEST_VALUE));
Austin Schuh906616c2019-01-21 20:25:11 -0800492
493 StringReplace(&line, "__NULLP__", null_str);
494 StringReplace(&line, "__PTRTEST__", ptr_str);
495
496 StringReplace(&line, "__SUCCESS__", StrError(0));
497 StringReplace(&line, "__ENOENT__", StrError(ENOENT));
498 StringReplace(&line, "__EINTR__", StrError(EINTR));
499 StringReplace(&line, "__ENXIO__", StrError(ENXIO));
500 StringReplace(&line, "__ENOEXEC__", StrError(ENOEXEC));
501 result += line + "\n";
502 }
503 fclose(fp);
504 return result;
505}
506
507static inline void WriteToFile(const string& body, const string& file) {
508 FILE* fp = fopen(file.c_str(), "wb");
509 fwrite(body.data(), 1, body.size(), fp);
510 fclose(fp);
511}
512
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700513static inline bool MungeAndDiffTest(const string& golden_filename,
514 CapturedStream* cap) {
515 if (cap == s_captured_streams[STDOUT_FILENO]) {
516 CHECK(cap) << ": did you forget CaptureTestStdout()?";
517 } else {
518 CHECK(cap) << ": did you forget CaptureTestStderr()?";
519 }
Austin Schuh906616c2019-01-21 20:25:11 -0800520
521 cap->StopCapture();
522
523 // Run munge
524 const string captured = Munge(cap->filename());
525 const string golden = Munge(golden_filename);
526 if (captured != golden) {
527 fprintf(stderr,
528 "Test with golden file failed. We'll try to show the diff:\n");
529 string munged_golden = golden_filename + ".munged";
530 WriteToFile(golden, munged_golden);
531 string munged_captured = cap->filename() + ".munged";
532 WriteToFile(captured, munged_captured);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700533#ifdef GLOG_OS_WINDOWS
Austin Schuh906616c2019-01-21 20:25:11 -0800534 string diffcmd("fc " + munged_golden + " " + munged_captured);
535#else
536 string diffcmd("diff -u " + munged_golden + " " + munged_captured);
537#endif
538 if (system(diffcmd.c_str()) != 0) {
539 fprintf(stderr, "diff command was failed.\n");
540 }
541 unlink(munged_golden.c_str());
542 unlink(munged_captured.c_str());
543 return false;
544 }
545 LOG(INFO) << "Diff was successful";
546 return true;
547}
548
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700549static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
550 return MungeAndDiffTest(golden_filename, s_captured_streams[STDERR_FILENO]);
551}
552
553static inline bool MungeAndDiffTestStdout(const string& golden_filename) {
554 return MungeAndDiffTest(golden_filename, s_captured_streams[STDOUT_FILENO]);
555}
556
Austin Schuh906616c2019-01-21 20:25:11 -0800557// Save flags used from logging_unittest.cc.
558#ifndef HAVE_LIB_GFLAGS
559struct FlagSaver {
560 FlagSaver()
561 : v_(FLAGS_v),
562 stderrthreshold_(FLAGS_stderrthreshold),
563 logtostderr_(FLAGS_logtostderr),
564 alsologtostderr_(FLAGS_alsologtostderr) {}
565 ~FlagSaver() {
566 FLAGS_v = v_;
567 FLAGS_stderrthreshold = stderrthreshold_;
568 FLAGS_logtostderr = logtostderr_;
569 FLAGS_alsologtostderr = alsologtostderr_;
570 }
571 int v_;
572 int stderrthreshold_;
573 bool logtostderr_;
574 bool alsologtostderr_;
575};
576#endif
577
578class Thread {
579 public:
580 virtual ~Thread() {}
581
582 void SetJoinable(bool) {}
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700583#if defined(GLOG_OS_WINDOWS) && !defined(GLOG_OS_CYGWIN)
Austin Schuh906616c2019-01-21 20:25:11 -0800584 void Start() {
585 handle_ = CreateThread(NULL,
586 0,
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700587 &Thread::InvokeThreadW,
588 this,
Austin Schuh906616c2019-01-21 20:25:11 -0800589 0,
590 &th_);
591 CHECK(handle_) << "CreateThread";
592 }
593 void Join() {
594 WaitForSingleObject(handle_, INFINITE);
595 }
596#elif defined(HAVE_PTHREAD)
597 void Start() {
598 pthread_create(&th_, NULL, &Thread::InvokeThread, this);
599 }
600 void Join() {
601 pthread_join(th_, NULL);
602 }
603#else
604# error No thread implementation.
605#endif
606
607 protected:
608 virtual void Run() = 0;
609
610 private:
611 static void* InvokeThread(void* self) {
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700612 (static_cast<Thread*>(self))->Run();
Austin Schuh906616c2019-01-21 20:25:11 -0800613 return NULL;
614 }
615
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700616#if defined(GLOG_OS_WINDOWS) && !defined(GLOG_OS_CYGWIN)
617 static DWORD __stdcall InvokeThreadW(LPVOID self) {
618 InvokeThread(self);
619 return 0;
620 }
Austin Schuh906616c2019-01-21 20:25:11 -0800621 HANDLE handle_;
622 DWORD th_;
623#else
624 pthread_t th_;
625#endif
626};
627
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700628static inline void SleepForMilliseconds(unsigned t) {
629#ifndef GLOG_OS_WINDOWS
630# if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
631 const struct timespec req = {0, t * 1000 * 1000};
632 nanosleep(&req, NULL);
633# else
Austin Schuh906616c2019-01-21 20:25:11 -0800634 usleep(t * 1000);
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700635# endif
Austin Schuh906616c2019-01-21 20:25:11 -0800636#else
637 Sleep(t);
638#endif
639}
640
641// Add hook for operator new to ensure there are no memory allocation.
642
643void (*g_new_hook)() = NULL;
644
645_END_GOOGLE_NAMESPACE_
646
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700647void* operator new(size_t size) GOOGLE_GLOG_THROW_BAD_ALLOC {
Austin Schuh906616c2019-01-21 20:25:11 -0800648 if (GOOGLE_NAMESPACE::g_new_hook) {
649 GOOGLE_NAMESPACE::g_new_hook();
650 }
651 return malloc(size);
652}
653
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700654void* operator new[](size_t size) GOOGLE_GLOG_THROW_BAD_ALLOC {
Austin Schuh906616c2019-01-21 20:25:11 -0800655 return ::operator new(size);
656}
657
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700658void operator delete(void* p) throw() {
Austin Schuh906616c2019-01-21 20:25:11 -0800659 free(p);
660}
661
James Kuszmaulba0ac1a2022-08-12 16:29:30 -0700662void operator delete(void* p, size_t) throw() {
663 ::operator delete(p);
664}
665
666void operator delete[](void* p) throw() {
667 ::operator delete(p);
668}
669
670void operator delete[](void* p, size_t) throw() {
Austin Schuh906616c2019-01-21 20:25:11 -0800671 ::operator delete(p);
672}