2 #error You must not include this file twice.
15 #include <sys/types.h>
20 #include "base/commandlineflags.h"
26 DEFINE_string(test_tmpdir, "/tmp", "Dir we use for temp files");
27 DEFINE_string(test_srcdir, ".",
28 "Source-dir root, needed to find glog_unittest_flagfile");
29 DEFINE_int32(benchmark_iters, 100000000, "Number of iterations per benchmark");
31 _START_GOOGLE_NAMESPACE_
33 extern void (*g_logging_fail_func)();
35 // The following is some bare-bones testing infrastructure
37 #define EXPECT_TRUE(cond) \
40 fprintf(stderr, "Check failed: %s\n", #cond); \
45 #define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
47 #define EXPECT_OP(op, val1, val2) \
49 if (!((val1) op (val2))) { \
50 fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
55 #define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)
56 #define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)
57 #define EXPECT_GT(val1, val2) EXPECT_OP(>, val1, val2)
58 #define EXPECT_LT(val1, val2) EXPECT_OP(<, val1, val2)
60 #define EXPECT_NAN(arg) \
63 fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
68 #define EXPECT_INF(arg) \
71 fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
76 #define EXPECT_DOUBLE_EQ(val1, val2) \
78 if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) { \
79 fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
84 #define EXPECT_STREQ(val1, val2) \
86 if (strcmp((val1), (val2)) != 0) { \
87 fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
92 static bool g_called_abort;
93 static jmp_buf g_jmp_buf;
94 static void CalledAbort() {
95 g_called_abort = true;
96 longjmp(g_jmp_buf, 1);
99 #define ASSERT_DEATH(fn, msg) \
101 g_called_abort = false; \
102 /* in logging.cc */ \
103 void (*original_logging_fail_func)() = g_logging_fail_func; \
104 g_logging_fail_func = &CalledAbort; \
105 if (!setjmp(g_jmp_buf)) fn; \
106 /* set back to their default */ \
107 g_logging_fail_func = original_logging_fail_func; \
108 if (!g_called_abort) { \
109 fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
115 #define ASSERT_DEBUG_DEATH(fn, msg)
117 #define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)
120 vector<void (*)()> g_testlist; // the tests to run
123 struct Test_##a##_##b { \
124 Test_##a##_##b() { g_testlist.push_back(&Run); } \
125 static void Run() { FlagSaver fs; RunTest(); } \
126 static void RunTest(); \
128 static Test_##a##_##b g_test_##a##_##b; \
129 void Test_##a##_##b::RunTest()
132 static int RUN_ALL_TESTS() {
133 vector<void (*)()>::const_iterator it;
134 for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {
137 fprintf(stderr, "Passed %d tests\n\nPASS\n", (int)g_testlist.size());
143 #define BENCHMARK(n) static BenchmarkRegisterer __benchmark_ ## n (#n, &n);
145 map<string, void (*)(int)> g_benchlist; // the benchmarks to run
147 class BenchmarkRegisterer {
149 BenchmarkRegisterer(const char* name, void (*function)(int iters)) {
150 EXPECT_TRUE(g_benchlist.insert(std::make_pair(name, function)).second);
154 static void RunSpecifiedBenchmarks() {
155 int iter_cnt = FLAGS_benchmark_iters;
156 puts("Benchmark\tTime(ns)\tIterations");
157 for (map<string, void (*)(int)>::const_iterator iter = g_benchlist.begin();
158 iter != g_benchlist.end();
160 clock_t start = clock();
161 iter->second(iter_cnt);
163 ((double)clock() - start) / CLOCKS_PER_SEC * 1000*1000*1000;
164 printf("%s\t%8.2lf\t%10d\n",
165 iter->first.c_str(), elapsed_ns / iter_cnt, iter_cnt);
170 // ----------------------------------------------------------------------
171 // Golden file functions
172 // ----------------------------------------------------------------------
174 class CapturedStream {
176 CapturedStream(int fd, const string & filename) :
179 filename_(filename) {
184 if (uncaptured_fd_ != -1) {
185 CHECK(close(uncaptured_fd_) != -1);
189 // Start redirecting output to a file
191 // Keep original stream for later
192 CHECK(uncaptured_fd_ == -1) << ", Stream " << fd_ << " already captured!";
193 uncaptured_fd_ = dup(fd_);
194 CHECK(uncaptured_fd_ != -1);
196 // Open file to save stream to
197 int cap_fd = open(filename_.c_str(),
198 O_CREAT | O_TRUNC | O_WRONLY,
202 // Send stdout/stderr to this file
204 CHECK(dup2(cap_fd, fd_) != -1);
205 CHECK(close(cap_fd) != -1);
208 // Remove output redirection
210 // Restore original stream
211 if (uncaptured_fd_ != -1) {
213 CHECK(dup2(uncaptured_fd_, fd_) != -1);
217 const string & filename() const { return filename_; }
220 int fd_; // file descriptor being captured
221 int uncaptured_fd_; // where the stream was originally being sent to
222 string filename_; // file where stream is being saved
224 static CapturedStream * s_captured_streams[STDERR_FILENO+1];
225 // Redirect a file descriptor to a file.
226 // fd - Should be STDOUT_FILENO or STDERR_FILENO
227 // filename - File where output should be stored
228 static void CaptureTestOutput(int fd, const string & filename) {
229 CHECK((fd == STDOUT_FILENO) || (fd == STDERR_FILENO));
230 CHECK(s_captured_streams[fd] == NULL);
231 s_captured_streams[fd] = new CapturedStream(fd, filename);
233 static void CaptureTestStderr() {
234 CaptureTestOutput(STDERR_FILENO, FLAGS_test_tmpdir + "/captured.err");
236 // Return the size (in bytes) of a file
237 static size_t GetFileSize(FILE * file) {
238 fseek(file, 0, SEEK_END);
239 return static_cast<size_t>(ftell(file));
241 // Read the entire content of a file as a string
242 static string ReadEntireFile(FILE * file) {
243 const size_t file_size = GetFileSize(file);
244 char * const buffer = new char[file_size];
246 size_t bytes_last_read = 0; // # of bytes read in the last fread()
247 size_t bytes_read = 0; // # of bytes read so far
249 fseek(file, 0, SEEK_SET);
251 // Keep reading the file until we cannot read further or the
252 // pre-determined file size is reached.
254 bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
255 bytes_read += bytes_last_read;
256 } while (bytes_last_read > 0 && bytes_read < file_size);
258 const string content = string(buffer, buffer+bytes_read);
263 // Get the captured stdout (when fd is STDOUT_FILENO) or stderr (when
264 // fd is STDERR_FILENO) as a string
265 static string GetCapturedTestOutput(int fd) {
266 CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
267 CapturedStream * const cap = s_captured_streams[fd];
269 << ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
271 // Make sure everything is flushed.
274 // Read the captured file.
275 FILE * const file = fopen(cap->filename().c_str(), "r");
276 const string content = ReadEntireFile(file);
280 s_captured_streams[fd] = NULL;
284 // Get the captured stderr of a test as a string.
285 static string GetCapturedTestStderr() {
286 return GetCapturedTestOutput(STDERR_FILENO);
289 // Check if the string is [IWEF](\d{4}|DATE)
290 static bool IsLoggingPrefix(const string& s) {
291 if (s.size() != 5) return false;
292 if (!strchr("IWEF", s[0])) return false;
293 for (int i = 1; i <= 4; ++i) {
294 if (!isdigit(s[i]) && s[i] != "DATE"[i-1]) return false;
299 // Convert log output into normalized form.
302 // I0102 030405 logging_unittest.cc:345] RAW: vlog -1
303 // => IDATE TIME__ logging_unittest.cc:LINE] RAW: vlog -1
304 static string MungeLine(const string& line) {
305 std::istringstream iss(line);
306 string before, logcode_date, time, thread_lineinfo;
308 while (!IsLoggingPrefix(logcode_date)) {
309 before += " " + logcode_date;
311 // We cannot find the header of log output.
316 if (!before.empty()) before += " ";
318 CHECK_EQ(6, time.size());
319 iss >> thread_lineinfo;
320 CHECK(!thread_lineinfo.empty());
321 if (thread_lineinfo[thread_lineinfo.size() - 1] != ']') {
322 // We found thread ID.
326 CHECK_EQ(']', tmp[tmp.size() - 1]);
327 thread_lineinfo = "THREADID " + tmp;
329 size_t index = thread_lineinfo.find(':');
330 CHECK_NE(string::npos, index);
331 thread_lineinfo = thread_lineinfo.substr(0, index+1) + "LINE]";
333 std::getline(iss, rest);
334 return (before + logcode_date[0] + "DATE TIME__ " + thread_lineinfo +
338 static void StringReplace(string* str,
339 const string& oldsub,
340 const string& newsub) {
341 size_t pos = str->find(oldsub);
342 if (pos != string::npos) {
343 str->replace(pos, oldsub.size(), newsub.c_str());
347 static string Munge(const string& filename) {
348 FILE* fp = fopen(filename.c_str(), "rb");
349 CHECK(fp != NULL) << filename << ": couldn't open";
352 while (fgets(buf, 4095, fp)) {
353 string line = MungeLine(buf);
355 sprintf(null_str, "%p", NULL);
356 StringReplace(&line, "__NULLP__", null_str);
358 char errmsg_buf[100];
359 posix_strerror_r(0, errmsg_buf, sizeof(errmsg_buf));
360 if (*errmsg_buf == '\0') {
361 // MacOSX 10.4 and FreeBSD return empty string for errno=0.
362 // In such case, the we need to remove an extra space.
363 StringReplace(&line, "__SUCCESS__ ", "");
365 StringReplace(&line, "__SUCCESS__", errmsg_buf);
367 StringReplace(&line, "__ENOENT__", strerror(ENOENT));
368 StringReplace(&line, "__EINTR__", strerror(EINTR));
369 StringReplace(&line, "__ENXIO__", strerror(ENXIO));
370 StringReplace(&line, "__ENOEXEC__", strerror(ENOEXEC));
371 result += line + "\n";
377 static void WriteToFile(const string& body, const string& file) {
378 FILE* fp = fopen(file.c_str(), "wb");
379 fwrite(body.data(), 1, body.size(), fp);
383 static bool MungeAndDiffTestStderr(const string& golden_filename) {
384 CapturedStream* cap = s_captured_streams[STDERR_FILENO];
385 CHECK(cap) << ": did you forget CaptureTestStderr()?";
390 const string captured = Munge(cap->filename());
391 const string golden = Munge(golden_filename);
392 if (captured != golden) {
394 "Test with golden file failed. We'll try to show the diff:\n");
395 string munged_golden = golden_filename + ".munged";
396 WriteToFile(golden, munged_golden);
397 string munged_captured = cap->filename() + ".munged";
398 WriteToFile(captured, munged_captured);
399 string diffcmd("diff -u " + munged_golden + " " + munged_captured);
400 if (system(diffcmd.c_str()) != 0) {
401 fprintf(stderr, "diff command was failed.\n");
403 unlink(munged_golden.c_str());
404 unlink(munged_captured.c_str());
407 LOG(INFO) << "Diff was successful";
411 // Save flags used from logging_unittest.cc.
412 #ifndef HAVE_LIB_GFLAGS
416 stderrthreshold_(FLAGS_stderrthreshold),
417 logtostderr_(FLAGS_logtostderr),
418 alsologtostderr_(FLAGS_alsologtostderr) {}
421 FLAGS_stderrthreshold = stderrthreshold_;
422 FLAGS_logtostderr = logtostderr_;
423 FLAGS_alsologtostderr = alsologtostderr_;
426 int stderrthreshold_;
428 bool alsologtostderr_;
432 // TODO(hamaji): Make it portable.
435 void SetJoinable(bool joinable) {}
437 pthread_create(&th_, NULL, &Thread::InvokeThread, this);
440 pthread_join(th_, NULL);
444 virtual void Run() = 0;
447 static void* InvokeThread(void* self) {
448 ((Thread*)self)->Run();
455 // TODO(hamaji): Make it portable.
456 static void SleepForMilliseconds(int t) {
460 // Add hook for operator new to ensure there are no memory allocation.
462 void (*g_new_hook)() = NULL;
464 _END_GOOGLE_NAMESPACE_
466 void* operator new(size_t size) {
467 if (GOOGLE_NAMESPACE::g_new_hook) {
468 GOOGLE_NAMESPACE::g_new_hook();
473 void* operator new[](size_t size) {
474 return ::operator new(size);
477 void operator delete(void* p) {
481 void operator delete[](void* p) {
482 ::operator delete(p);