git-subtree-dir: third_party/glog git-subtree-split: 9ef754a3023e6fd10f20fe53dfca96dd898182e3
		
			
				
	
	
		
			611 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			611 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (c) 2009, Google Inc.
 | |
| // All rights reserved.
 | |
| //
 | |
| // Redistribution and use in source and binary forms, with or without
 | |
| // modification, are permitted provided that the following conditions are
 | |
| // met:
 | |
| //
 | |
| //     * Redistributions of source code must retain the above copyright
 | |
| // notice, this list of conditions and the following disclaimer.
 | |
| //     * Redistributions in binary form must reproduce the above
 | |
| // copyright notice, this list of conditions and the following disclaimer
 | |
| // in the documentation and/or other materials provided with the
 | |
| // distribution.
 | |
| //     * Neither the name of Google Inc. nor the names of its
 | |
| // contributors may be used to endorse or promote products derived from
 | |
| // this software without specific prior written permission.
 | |
| //
 | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
| //
 | |
| // Author: Shinichiro Hamaji
 | |
| //   (based on googletest: http://code.google.com/p/googletest/)
 | |
| 
 | |
| #ifdef GOOGLETEST_H__
 | |
| #error You must not include this file twice.
 | |
| #endif
 | |
| #define GOOGLETEST_H__
 | |
| 
 | |
| #include "utilities.h"
 | |
| 
 | |
| #include <ctype.h>
 | |
| #include <setjmp.h>
 | |
| #include <time.h>
 | |
| 
 | |
| #include <map>
 | |
| #include <sstream>
 | |
| #include <string>
 | |
| #include <vector>
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <fcntl.h>
 | |
| #ifdef HAVE_UNISTD_H
 | |
| # include <unistd.h>
 | |
| #endif
 | |
| 
 | |
| #include "base/commandlineflags.h"
 | |
| 
 | |
| using std::map;
 | |
| using std::string;
 | |
| using std::vector;
 | |
| 
 | |
| _START_GOOGLE_NAMESPACE_
 | |
| 
 | |
| extern GOOGLE_GLOG_DLL_DECL void (*g_logging_fail_func)();
 | |
| 
 | |
| _END_GOOGLE_NAMESPACE_
 | |
| 
 | |
| #undef GOOGLE_GLOG_DLL_DECL
 | |
| #define GOOGLE_GLOG_DLL_DECL
 | |
| 
 | |
| static inline string GetTempDir() {
 | |
| #ifndef OS_WINDOWS
 | |
|   return "/tmp";
 | |
| #else
 | |
|   char tmp[MAX_PATH];
 | |
|   GetTempPathA(MAX_PATH, tmp);
 | |
|   return tmp;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #if defined(OS_WINDOWS) && defined(_MSC_VER) && !defined(TEST_SRC_DIR)
 | |
| // The test will run in glog/vsproject/<project name>
 | |
| // (e.g., glog/vsproject/logging_unittest).
 | |
| static const char TEST_SRC_DIR[] = "../..";
 | |
| #elif !defined(TEST_SRC_DIR)
 | |
| # warning TEST_SRC_DIR should be defined in config.h
 | |
| static const char TEST_SRC_DIR[] = ".";
 | |
| #endif
 | |
| 
 | |
| static const uint32_t PTR_TEST_VALUE = 0x12345678;
 | |
| 
 | |
| DEFINE_string(test_tmpdir, GetTempDir(), "Dir we use for temp files");
 | |
| DEFINE_string(test_srcdir, TEST_SRC_DIR,
 | |
|               "Source-dir root, needed to find glog_unittest_flagfile");
 | |
| DEFINE_bool(run_benchmark, false, "If true, run benchmarks");
 | |
| #ifdef NDEBUG
 | |
| DEFINE_int32(benchmark_iters, 100000000, "Number of iterations per benchmark");
 | |
| #else
 | |
| DEFINE_int32(benchmark_iters, 100000, "Number of iterations per benchmark");
 | |
| #endif
 | |
| 
 | |
| #ifdef HAVE_LIB_GTEST
 | |
| # include <gtest/gtest.h>
 | |
| // Use our ASSERT_DEATH implementation.
 | |
| # undef ASSERT_DEATH
 | |
| # undef ASSERT_DEBUG_DEATH
 | |
| using testing::InitGoogleTest;
 | |
| #else
 | |
| 
 | |
| _START_GOOGLE_NAMESPACE_
 | |
| 
 | |
| void InitGoogleTest(int*, char**);
 | |
| 
 | |
| void InitGoogleTest(int*, char**) {}
 | |
| 
 | |
| // The following is some bare-bones testing infrastructure
 | |
| 
 | |
| #define EXPECT_TRUE(cond)                               \
 | |
|   do {                                                  \
 | |
|     if (!(cond)) {                                      \
 | |
|       fprintf(stderr, "Check failed: %s\n", #cond);     \
 | |
|       exit(1);                                          \
 | |
|     }                                                   \
 | |
|   } while (0)
 | |
| 
 | |
| #define EXPECT_FALSE(cond)  EXPECT_TRUE(!(cond))
 | |
| 
 | |
| #define EXPECT_OP(op, val1, val2)                                       \
 | |
|   do {                                                                  \
 | |
|     if (!((val1) op (val2))) {                                          \
 | |
|       fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2);   \
 | |
|       exit(1);                                                          \
 | |
|     }                                                                   \
 | |
|   } while (0)
 | |
| 
 | |
| #define EXPECT_EQ(val1, val2)  EXPECT_OP(==, val1, val2)
 | |
| #define EXPECT_NE(val1, val2)  EXPECT_OP(!=, val1, val2)
 | |
| #define EXPECT_GT(val1, val2)  EXPECT_OP(>, val1, val2)
 | |
| #define EXPECT_LT(val1, val2)  EXPECT_OP(<, val1, val2)
 | |
| 
 | |
| #define EXPECT_NAN(arg)                                         \
 | |
|   do {                                                          \
 | |
|     if (!isnan(arg)) {                                          \
 | |
|       fprintf(stderr, "Check failed: isnan(%s)\n", #arg);       \
 | |
|       exit(1);                                                  \
 | |
|     }                                                           \
 | |
|   } while (0)
 | |
| 
 | |
| #define EXPECT_INF(arg)                                         \
 | |
|   do {                                                          \
 | |
|     if (!isinf(arg)) {                                          \
 | |
|       fprintf(stderr, "Check failed: isinf(%s)\n", #arg);       \
 | |
|       exit(1);                                                  \
 | |
|     }                                                           \
 | |
|   } while (0)
 | |
| 
 | |
| #define EXPECT_DOUBLE_EQ(val1, val2)                                    \
 | |
|   do {                                                                  \
 | |
|     if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) {         \
 | |
|       fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2);        \
 | |
|       exit(1);                                                          \
 | |
|     }                                                                   \
 | |
|   } while (0)
 | |
| 
 | |
| #define EXPECT_STREQ(val1, val2)                                        \
 | |
|   do {                                                                  \
 | |
|     if (strcmp((val1), (val2)) != 0) {                                  \
 | |
|       fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2);   \
 | |
|       exit(1);                                                          \
 | |
|     }                                                                   \
 | |
|   } while (0)
 | |
| 
 | |
| vector<void (*)()> g_testlist;  // the tests to run
 | |
| 
 | |
| #define TEST(a, b)                                      \
 | |
|   struct Test_##a##_##b {                               \
 | |
|     Test_##a##_##b() { g_testlist.push_back(&Run); }    \
 | |
|     static void Run() { FlagSaver fs; RunTest(); }      \
 | |
|     static void RunTest();                              \
 | |
|   };                                                    \
 | |
|   static Test_##a##_##b g_test_##a##_##b;               \
 | |
|   void Test_##a##_##b::RunTest()
 | |
| 
 | |
| 
 | |
| static inline int RUN_ALL_TESTS() {
 | |
|   vector<void (*)()>::const_iterator it;
 | |
|   for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {
 | |
|     (*it)();
 | |
|   }
 | |
|   fprintf(stderr, "Passed %d tests\n\nPASS\n", (int)g_testlist.size());
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| _END_GOOGLE_NAMESPACE_
 | |
| 
 | |
| #endif  // ! HAVE_LIB_GTEST
 | |
| 
 | |
| _START_GOOGLE_NAMESPACE_
 | |
| 
 | |
| static bool g_called_abort;
 | |
| static jmp_buf g_jmp_buf;
 | |
| static inline void CalledAbort() {
 | |
|   g_called_abort = true;
 | |
|   longjmp(g_jmp_buf, 1);
 | |
| }
 | |
| 
 | |
| #ifdef OS_WINDOWS
 | |
| // TODO(hamaji): Death test somehow doesn't work in Windows.
 | |
| #define ASSERT_DEATH(fn, msg)
 | |
| #else
 | |
| #define ASSERT_DEATH(fn, msg)                                           \
 | |
|   do {                                                                  \
 | |
|     g_called_abort = false;                                             \
 | |
|     /* in logging.cc */                                                 \
 | |
|     void (*original_logging_fail_func)() = g_logging_fail_func;         \
 | |
|     g_logging_fail_func = &CalledAbort;                                 \
 | |
|     if (!setjmp(g_jmp_buf)) fn;                                         \
 | |
|     /* set back to their default */                                     \
 | |
|     g_logging_fail_func = original_logging_fail_func;                   \
 | |
|     if (!g_called_abort) {                                              \
 | |
|       fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn);      \
 | |
|       exit(1);                                                          \
 | |
|     }                                                                   \
 | |
|   } while (0)
 | |
| #endif
 | |
| 
 | |
| #ifdef NDEBUG
 | |
| #define ASSERT_DEBUG_DEATH(fn, msg)
 | |
| #else
 | |
| #define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)
 | |
| #endif  // NDEBUG
 | |
| 
 | |
| // Benchmark tools.
 | |
| 
 | |
| #define BENCHMARK(n) static BenchmarkRegisterer __benchmark_ ## n (#n, &n);
 | |
| 
 | |
| map<string, void (*)(int)> g_benchlist;  // the benchmarks to run
 | |
| 
 | |
| class BenchmarkRegisterer {
 | |
|  public:
 | |
|   BenchmarkRegisterer(const char* name, void (*function)(int iters)) {
 | |
|     EXPECT_TRUE(g_benchlist.insert(std::make_pair(name, function)).second);
 | |
|   }
 | |
| };
 | |
| 
 | |
| static inline void RunSpecifiedBenchmarks() {
 | |
|   if (!FLAGS_run_benchmark) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   int iter_cnt = FLAGS_benchmark_iters;
 | |
|   puts("Benchmark\tTime(ns)\tIterations");
 | |
|   for (map<string, void (*)(int)>::const_iterator iter = g_benchlist.begin();
 | |
|        iter != g_benchlist.end();
 | |
|        ++iter) {
 | |
|     clock_t start = clock();
 | |
|     iter->second(iter_cnt);
 | |
|     double elapsed_ns =
 | |
|         ((double)clock() - start) / CLOCKS_PER_SEC * 1000*1000*1000;
 | |
|     printf("%s\t%8.2lf\t%10d\n",
 | |
|            iter->first.c_str(), elapsed_ns / iter_cnt, iter_cnt);
 | |
|   }
 | |
|   puts("");
 | |
| }
 | |
| 
 | |
| // ----------------------------------------------------------------------
 | |
| // Golden file functions
 | |
| // ----------------------------------------------------------------------
 | |
| 
 | |
| class CapturedStream {
 | |
|  public:
 | |
|   CapturedStream(int fd, const string & filename) :
 | |
|     fd_(fd),
 | |
|     uncaptured_fd_(-1),
 | |
|     filename_(filename) {
 | |
|     Capture();
 | |
|   }
 | |
| 
 | |
|   ~CapturedStream() {
 | |
|     if (uncaptured_fd_ != -1) {
 | |
|       CHECK(close(uncaptured_fd_) != -1);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Start redirecting output to a file
 | |
|   void Capture() {
 | |
|     // Keep original stream for later
 | |
|     CHECK(uncaptured_fd_ == -1) << ", Stream " << fd_ << " already captured!";
 | |
|     uncaptured_fd_ = dup(fd_);
 | |
|     CHECK(uncaptured_fd_ != -1);
 | |
| 
 | |
|     // Open file to save stream to
 | |
|     int cap_fd = open(filename_.c_str(),
 | |
|                       O_CREAT | O_TRUNC | O_WRONLY,
 | |
|                       S_IRUSR | S_IWUSR);
 | |
|     CHECK(cap_fd != -1);
 | |
| 
 | |
|     // Send stdout/stderr to this file
 | |
|     fflush(NULL);
 | |
|     CHECK(dup2(cap_fd, fd_) != -1);
 | |
|     CHECK(close(cap_fd) != -1);
 | |
|   }
 | |
| 
 | |
|   // Remove output redirection
 | |
|   void StopCapture() {
 | |
|     // Restore original stream
 | |
|     if (uncaptured_fd_ != -1) {
 | |
|       fflush(NULL);
 | |
|       CHECK(dup2(uncaptured_fd_, fd_) != -1);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   const string & filename() const { return filename_; }
 | |
| 
 | |
|  private:
 | |
|   int fd_;             // file descriptor being captured
 | |
|   int uncaptured_fd_;  // where the stream was originally being sent to
 | |
|   string filename_;    // file where stream is being saved
 | |
| };
 | |
| static CapturedStream * s_captured_streams[STDERR_FILENO+1];
 | |
| // Redirect a file descriptor to a file.
 | |
| //   fd       - Should be STDOUT_FILENO or STDERR_FILENO
 | |
| //   filename - File where output should be stored
 | |
| static inline void CaptureTestOutput(int fd, const string & filename) {
 | |
|   CHECK((fd == STDOUT_FILENO) || (fd == STDERR_FILENO));
 | |
|   CHECK(s_captured_streams[fd] == NULL);
 | |
|   s_captured_streams[fd] = new CapturedStream(fd, filename);
 | |
| }
 | |
| static inline void CaptureTestStderr() {
 | |
|   CaptureTestOutput(STDERR_FILENO, FLAGS_test_tmpdir + "/captured.err");
 | |
| }
 | |
| // Return the size (in bytes) of a file
 | |
| static inline size_t GetFileSize(FILE * file) {
 | |
|   fseek(file, 0, SEEK_END);
 | |
|   return static_cast<size_t>(ftell(file));
 | |
| }
 | |
| // Read the entire content of a file as a string
 | |
| static inline string ReadEntireFile(FILE * file) {
 | |
|   const size_t file_size = GetFileSize(file);
 | |
|   char * const buffer = new char[file_size];
 | |
| 
 | |
|   size_t bytes_last_read = 0;  // # of bytes read in the last fread()
 | |
|   size_t bytes_read = 0;       // # of bytes read so far
 | |
| 
 | |
|   fseek(file, 0, SEEK_SET);
 | |
| 
 | |
|   // Keep reading the file until we cannot read further or the
 | |
|   // pre-determined file size is reached.
 | |
|   do {
 | |
|     bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
 | |
|     bytes_read += bytes_last_read;
 | |
|   } while (bytes_last_read > 0 && bytes_read < file_size);
 | |
| 
 | |
|   const string content = string(buffer, buffer+bytes_read);
 | |
|   delete[] buffer;
 | |
| 
 | |
|   return content;
 | |
| }
 | |
| // Get the captured stdout (when fd is STDOUT_FILENO) or stderr (when
 | |
| // fd is STDERR_FILENO) as a string
 | |
| static inline string GetCapturedTestOutput(int fd) {
 | |
|   CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
 | |
|   CapturedStream * const cap = s_captured_streams[fd];
 | |
|   CHECK(cap)
 | |
|     << ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
 | |
| 
 | |
|   // Make sure everything is flushed.
 | |
|   cap->StopCapture();
 | |
| 
 | |
|   // Read the captured file.
 | |
|   FILE * const file = fopen(cap->filename().c_str(), "r");
 | |
|   const string content = ReadEntireFile(file);
 | |
|   fclose(file);
 | |
| 
 | |
|   delete cap;
 | |
|   s_captured_streams[fd] = NULL;
 | |
| 
 | |
|   return content;
 | |
| }
 | |
| // Get the captured stderr of a test as a string.
 | |
| static inline string GetCapturedTestStderr() {
 | |
|   return GetCapturedTestOutput(STDERR_FILENO);
 | |
| }
 | |
| 
 | |
| // Check if the string is [IWEF](\d{8}|YEARDATE)
 | |
| static inline bool IsLoggingPrefix(const string& s) {
 | |
|   if (s.size() != 9) return false;
 | |
|   if (!strchr("IWEF", s[0])) return false;
 | |
|   for (int i = 1; i <= 8; ++i) {
 | |
|     if (!isdigit(s[i]) && s[i] != "YEARDATE"[i-1]) return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Convert log output into normalized form.
 | |
| //
 | |
| // Example:
 | |
| //     I20200102 030405 logging_unittest.cc:345] RAW: vlog -1
 | |
| //  => IYEARDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
 | |
| static inline string MungeLine(const string& line) {
 | |
|   std::istringstream iss(line);
 | |
|   string before, logcode_date, time, thread_lineinfo;
 | |
|   iss >> logcode_date;
 | |
|   while (!IsLoggingPrefix(logcode_date)) {
 | |
|     before += " " + logcode_date;
 | |
|     if (!(iss >> logcode_date)) {
 | |
|       // We cannot find the header of log output.
 | |
|       return before;
 | |
|     }
 | |
|   }
 | |
|   if (!before.empty()) before += " ";
 | |
|   iss >> time;
 | |
|   iss >> thread_lineinfo;
 | |
|   CHECK(!thread_lineinfo.empty());
 | |
|   if (thread_lineinfo[thread_lineinfo.size() - 1] != ']') {
 | |
|     // We found thread ID.
 | |
|     string tmp;
 | |
|     iss >> tmp;
 | |
|     CHECK(!tmp.empty());
 | |
|     CHECK_EQ(']', tmp[tmp.size() - 1]);
 | |
|     thread_lineinfo = "THREADID " + tmp;
 | |
|   }
 | |
|   size_t index = thread_lineinfo.find(':');
 | |
|   CHECK_NE(string::npos, index);
 | |
|   thread_lineinfo = thread_lineinfo.substr(0, index+1) + "LINE]";
 | |
|   string rest;
 | |
|   std::getline(iss, rest);
 | |
|   return (before + logcode_date[0] + "YEARDATE TIME__ " + thread_lineinfo +
 | |
|           MungeLine(rest));
 | |
| }
 | |
| 
 | |
| static inline void StringReplace(string* str,
 | |
|                           const string& oldsub,
 | |
|                           const string& newsub) {
 | |
|   size_t pos = str->find(oldsub);
 | |
|   if (pos != string::npos) {
 | |
|     str->replace(pos, oldsub.size(), newsub.c_str());
 | |
|   }
 | |
| }
 | |
| 
 | |
| static inline string Munge(const string& filename) {
 | |
|   FILE* fp = fopen(filename.c_str(), "rb");
 | |
|   CHECK(fp != NULL) << filename << ": couldn't open";
 | |
|   char buf[4096];
 | |
|   string result;
 | |
|   while (fgets(buf, 4095, fp)) {
 | |
|     string line = MungeLine(buf);
 | |
|     char null_str[256];
 | |
|     char ptr_str[256];
 | |
|     sprintf(null_str, "%p", static_cast<void*>(NULL));
 | |
|     sprintf(ptr_str, "%p", reinterpret_cast<void*>(PTR_TEST_VALUE));
 | |
| 
 | |
|     StringReplace(&line, "__NULLP__", null_str);
 | |
|     StringReplace(&line, "__PTRTEST__", ptr_str);
 | |
| 
 | |
|     StringReplace(&line, "__SUCCESS__", StrError(0));
 | |
|     StringReplace(&line, "__ENOENT__", StrError(ENOENT));
 | |
|     StringReplace(&line, "__EINTR__", StrError(EINTR));
 | |
|     StringReplace(&line, "__ENXIO__", StrError(ENXIO));
 | |
|     StringReplace(&line, "__ENOEXEC__", StrError(ENOEXEC));
 | |
|     result += line + "\n";
 | |
|   }
 | |
|   fclose(fp);
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| static inline void WriteToFile(const string& body, const string& file) {
 | |
|   FILE* fp = fopen(file.c_str(), "wb");
 | |
|   fwrite(body.data(), 1, body.size(), fp);
 | |
|   fclose(fp);
 | |
| }
 | |
| 
 | |
| static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
 | |
|   CapturedStream* cap = s_captured_streams[STDERR_FILENO];
 | |
|   CHECK(cap) << ": did you forget CaptureTestStderr()?";
 | |
| 
 | |
|   cap->StopCapture();
 | |
| 
 | |
|   // Run munge
 | |
|   const string captured = Munge(cap->filename());
 | |
|   const string golden = Munge(golden_filename);
 | |
|   if (captured != golden) {
 | |
|     fprintf(stderr,
 | |
|             "Test with golden file failed. We'll try to show the diff:\n");
 | |
|     string munged_golden = golden_filename + ".munged";
 | |
|     WriteToFile(golden, munged_golden);
 | |
|     string munged_captured = cap->filename() + ".munged";
 | |
|     WriteToFile(captured, munged_captured);
 | |
| #ifdef OS_WINDOWS
 | |
|     string diffcmd("fc " + munged_golden + " " + munged_captured);
 | |
| #else
 | |
|     string diffcmd("diff -u " + munged_golden + " " + munged_captured);
 | |
| #endif
 | |
|     if (system(diffcmd.c_str()) != 0) {
 | |
|       fprintf(stderr, "diff command was failed.\n");
 | |
|     }
 | |
|     unlink(munged_golden.c_str());
 | |
|     unlink(munged_captured.c_str());
 | |
|     return false;
 | |
|   }
 | |
|   LOG(INFO) << "Diff was successful";
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Save flags used from logging_unittest.cc.
 | |
| #ifndef HAVE_LIB_GFLAGS
 | |
| struct FlagSaver {
 | |
|   FlagSaver()
 | |
|       : v_(FLAGS_v),
 | |
|         stderrthreshold_(FLAGS_stderrthreshold),
 | |
|         logtostderr_(FLAGS_logtostderr),
 | |
|         alsologtostderr_(FLAGS_alsologtostderr) {}
 | |
|   ~FlagSaver() {
 | |
|     FLAGS_v = v_;
 | |
|     FLAGS_stderrthreshold = stderrthreshold_;
 | |
|     FLAGS_logtostderr = logtostderr_;
 | |
|     FLAGS_alsologtostderr = alsologtostderr_;
 | |
|   }
 | |
|   int v_;
 | |
|   int stderrthreshold_;
 | |
|   bool logtostderr_;
 | |
|   bool alsologtostderr_;
 | |
| };
 | |
| #endif
 | |
| 
 | |
| class Thread {
 | |
|  public:
 | |
|   virtual ~Thread() {}
 | |
| 
 | |
|   void SetJoinable(bool) {}
 | |
| #if defined(OS_WINDOWS) && !defined(OS_CYGWIN)
 | |
|   void Start() {
 | |
|     handle_ = CreateThread(NULL,
 | |
|                            0,
 | |
|                            (LPTHREAD_START_ROUTINE)&Thread::InvokeThread,
 | |
|                            (LPVOID)this,
 | |
|                            0,
 | |
|                            &th_);
 | |
|     CHECK(handle_) << "CreateThread";
 | |
|   }
 | |
|   void Join() {
 | |
|     WaitForSingleObject(handle_, INFINITE);
 | |
|   }
 | |
| #elif defined(HAVE_PTHREAD)
 | |
|   void Start() {
 | |
|     pthread_create(&th_, NULL, &Thread::InvokeThread, this);
 | |
|   }
 | |
|   void Join() {
 | |
|     pthread_join(th_, NULL);
 | |
|   }
 | |
| #else
 | |
| # error No thread implementation.
 | |
| #endif
 | |
| 
 | |
|  protected:
 | |
|   virtual void Run() = 0;
 | |
| 
 | |
|  private:
 | |
|   static void* InvokeThread(void* self) {
 | |
|     ((Thread*)self)->Run();
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
| #if defined(OS_WINDOWS) && !defined(OS_CYGWIN)
 | |
|   HANDLE handle_;
 | |
|   DWORD th_;
 | |
| #else
 | |
|   pthread_t th_;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| static inline void SleepForMilliseconds(int t) {
 | |
| #ifndef OS_WINDOWS
 | |
| # if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
 | |
|   const struct timespec req = {0, t * 1000 * 1000};
 | |
|   nanosleep(&req, NULL);
 | |
| # else
 | |
|   usleep(t * 1000);
 | |
| # endif
 | |
| #else
 | |
|   Sleep(t);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| // Add hook for operator new to ensure there are no memory allocation.
 | |
| 
 | |
| void (*g_new_hook)() = NULL;
 | |
| 
 | |
| _END_GOOGLE_NAMESPACE_
 | |
| 
 | |
| void* operator new(size_t size) {
 | |
|   if (GOOGLE_NAMESPACE::g_new_hook) {
 | |
|     GOOGLE_NAMESPACE::g_new_hook();
 | |
|   }
 | |
|   return malloc(size);
 | |
| }
 | |
| 
 | |
| void* operator new[](size_t size) {
 | |
|   return ::operator new(size);
 | |
| }
 | |
| 
 | |
| void operator delete(void* p) {
 | |
|   free(p);
 | |
| }
 | |
| 
 | |
| void operator delete[](void* p) {
 | |
|   ::operator delete(p);
 | |
| }
 |