summaryrefslogtreecommitdiffstats
path: root/base/test
diff options
context:
space:
mode:
Diffstat (limited to 'base/test')
-rw-r--r--base/test/perf_test_suite.h51
-rw-r--r--base/test/run_all_perftests.cc9
-rw-r--r--base/test/run_all_unittests.cc9
-rw-r--r--base/test/test_file_util.h36
-rw-r--r--base/test/test_file_util_linux.cc27
-rw-r--r--base/test/test_file_util_mac.cc36
-rw-r--r--base/test/test_file_util_posix.cc106
-rw-r--r--base/test/test_file_util_win.cc179
-rw-r--r--base/test/test_suite.h237
9 files changed, 690 insertions, 0 deletions
diff --git a/base/test/perf_test_suite.h b/base/test/perf_test_suite.h
new file mode 100644
index 0000000..7393544
--- /dev/null
+++ b/base/test/perf_test_suite.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PERF_TEST_SUITE_H_
+#define BASE_PERF_TEST_SUITE_H_
+
+#include "base/command_line.h"
+#include "base/debug_util.h"
+#include "base/file_path.h"
+#include "base/perftimer.h"
+#include "base/process_util.h"
+#include "base/string_util.h"
+#include "base/test/test_suite.h"
+
+class PerfTestSuite : public TestSuite {
+ public:
+ PerfTestSuite(int argc, char** argv) : TestSuite(argc, argv) {
+ }
+
+ virtual void Initialize() {
+ TestSuite::Initialize();
+
+ // Initialize the perf timer log
+ FilePath log_path;
+ std::wstring log_file =
+ CommandLine::ForCurrentProcess()->GetSwitchValue(L"log-file");
+ if (log_file.empty()) {
+ FilePath exe;
+ PathService::Get(base::FILE_EXE, &exe);
+ log_path = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
+ log_path = log_path.InsertBeforeExtension(FILE_PATH_LITERAL("_perf"));
+ } else {
+ log_path = FilePath::FromWStringHack(log_file);
+ }
+ ASSERT_TRUE(InitPerfLog(log_path));
+
+ // Raise to high priority to have more precise measurements. Since we don't
+ // aim at 1% precision, it is not necessary to run at realtime level.
+ if (!DebugUtil::BeingDebugged())
+ base::RaiseProcessToHighPriority();
+ }
+
+ virtual void Shutdown() {
+ TestSuite::Shutdown();
+
+ FinalizePerfLog();
+ }
+};
+
+#endif // BASE_PERF_TEST_SUITE_H_
diff --git a/base/test/run_all_perftests.cc b/base/test/run_all_perftests.cc
new file mode 100644
index 0000000..6d0a8ee
--- /dev/null
+++ b/base/test/run_all_perftests.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/perf_test_suite.h"
+
+int main(int argc, char** argv) {
+ return PerfTestSuite(argc, argv).Run();
+}
diff --git a/base/test/run_all_unittests.cc b/base/test/run_all_unittests.cc
new file mode 100644
index 0000000..841b353
--- /dev/null
+++ b/base/test/run_all_unittests.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_suite.h"
+
+int main(int argc, char** argv) {
+ return TestSuite(argc, argv).Run();
+}
diff --git a/base/test/test_file_util.h b/base/test/test_file_util.h
new file mode 100644
index 0000000..3d2764e
--- /dev/null
+++ b/base/test/test_file_util.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_FILE_UTIL_H_
+#define BASE_TEST_FILE_UTIL_H_
+
+// File utility functions used only by tests.
+
+#include <string>
+
+class FilePath;
+
+namespace file_util {
+
+// Wrapper over file_util::Delete. On Windows repeatedly invokes Delete in case
+// of failure to workaround Windows file locking semantics. Returns true on
+// success.
+bool DieFileDie(const FilePath& file, bool recurse);
+
+// Clear a specific file from the system cache. After this call, trying
+// to access this file will result in a cold load from the hard drive.
+bool EvictFileFromSystemCache(const FilePath& file);
+
+// Like CopyFileNoCache but recursively copies all files and subdirectories
+// in the given input directory to the output directory. Any files in the
+// destination that already exist will be overwritten.
+//
+// Returns true on success. False means there was some error copying, so the
+// state of the destination is unknown.
+bool CopyRecursiveDirNoCache(const std::wstring& source_dir,
+ const std::wstring& dest_dir);
+
+} // namespace file_util
+
+#endif // BASE_TEST_FILE_UTIL_H_
diff --git a/base/test/test_file_util_linux.cc b/base/test/test_file_util_linux.cc
new file mode 100644
index 0000000..c2911ce
--- /dev/null
+++ b/base/test/test_file_util_linux.cc
@@ -0,0 +1,27 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "base/file_path.h"
+
+namespace file_util {
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+ int fd = open(file.value().c_str(), O_RDONLY);
+ if (fd < 0)
+ return false;
+ if (fdatasync(fd) != 0)
+ return false;
+ if (posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED) != 0)
+ return false;
+ close(fd);
+ return true;
+}
+
+} // namespace file_util
diff --git a/base/test/test_file_util_mac.cc b/base/test/test_file_util_mac.cc
new file mode 100644
index 0000000..316b5c3
--- /dev/null
+++ b/base/test/test_file_util_mac.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <sys/mman.h>
+#include <errno.h>
+#include "base/logging.h"
+#include "base/file_util.h"
+
+namespace file_util {
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+ // There aren't any really direct ways to purge a file from the UBC. From
+ // talking with Amit Singh, the safest is to mmap the file with MAP_FILE (the
+ // default) + MAP_SHARED, then do an msync to invalidate the memory. The next
+ // open should then have to load the file from disk.
+
+ file_util::MemoryMappedFile mapped_file;
+ if (!mapped_file.Initialize(file)) {
+ DLOG(WARNING) << "failed to memory map " << file.value();
+ return false;
+ }
+
+ if (msync(const_cast<uint8*>(mapped_file.data()), mapped_file.length(),
+ MS_INVALIDATE) != 0) {
+ DLOG(WARNING) << "failed to invalidate memory map of " << file.value()
+ << ", errno: " << errno;
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace file_util
diff --git a/base/test/test_file_util_posix.cc b/base/test/test_file_util_posix.cc
new file mode 100644
index 0000000..096f3c6
--- /dev/null
+++ b/base/test/test_file_util_posix.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/string_util.h"
+
+namespace file_util {
+
+bool DieFileDie(const FilePath& file, bool recurse) {
+ // There is no need to workaround Windows problems on POSIX.
+ // Just pass-through.
+ return file_util::Delete(file, recurse);
+}
+
+// Mostly a verbatim copy of CopyDirectory
+bool CopyRecursiveDirNoCache(const std::wstring& source_dir,
+ const std::wstring& dest_dir) {
+ const FilePath from_path(FilePath::FromWStringHack(source_dir));
+ const FilePath to_path(FilePath::FromWStringHack(dest_dir));
+
+ char top_dir[PATH_MAX];
+ if (base::strlcpy(top_dir, from_path.value().c_str(),
+ arraysize(top_dir)) >= arraysize(top_dir)) {
+ return false;
+ }
+
+ // This function does not properly handle destinations within the source
+ FilePath real_to_path = to_path;
+ if (PathExists(real_to_path)) {
+ if (!AbsolutePath(&real_to_path))
+ return false;
+ } else {
+ real_to_path = real_to_path.DirName();
+ if (!AbsolutePath(&real_to_path))
+ return false;
+ }
+ if (real_to_path.value().compare(0, from_path.value().size(),
+ from_path.value()) == 0)
+ return false;
+
+ bool success = true;
+ FileEnumerator::FILE_TYPE traverse_type =
+ static_cast<FileEnumerator::FILE_TYPE>(FileEnumerator::FILES |
+ FileEnumerator::SHOW_SYM_LINKS | FileEnumerator::DIRECTORIES);
+ FileEnumerator traversal(from_path, true, traverse_type);
+
+ // to_path may not exist yet, start the loop with to_path
+ FileEnumerator::FindInfo info;
+ FilePath current = from_path;
+ if (stat(from_path.value().c_str(), &info.stat) < 0) {
+ LOG(ERROR) << "CopyRecursiveDirNoCache() couldn't stat source directory: "
+ << from_path.value() << " errno = " << errno;
+ success = false;
+ }
+
+ while (success && !current.empty()) {
+ // current is the source path, including from_path, so paste
+ // the suffix after from_path onto to_path to create the target_path.
+ std::string suffix(&current.value().c_str()[from_path.value().size()]);
+ // Strip the leading '/' (if any).
+ if (!suffix.empty()) {
+ DCHECK_EQ('/', suffix[0]);
+ suffix.erase(0, 1);
+ }
+ const FilePath target_path = to_path.Append(suffix);
+
+ if (S_ISDIR(info.stat.st_mode)) {
+ if (mkdir(target_path.value().c_str(), info.stat.st_mode & 01777) != 0 &&
+ errno != EEXIST) {
+ LOG(ERROR) << "CopyRecursiveDirNoCache() couldn't create directory: " <<
+ target_path.value() << " errno = " << errno;
+ success = false;
+ }
+ } else if (S_ISREG(info.stat.st_mode)) {
+ if (CopyFile(current, target_path)) {
+ success = EvictFileFromSystemCache(target_path);
+ DCHECK(success);
+ } else {
+ LOG(ERROR) << "CopyRecursiveDirNoCache() couldn't create file: " <<
+ target_path.value();
+ success = false;
+ }
+ } else {
+ LOG(WARNING) << "CopyRecursiveDirNoCache() skipping non-regular file: " <<
+ current.value();
+ }
+
+ current = traversal.Next();
+ traversal.GetFindInfo(&info);
+ }
+
+ return success;
+}
+
+} // namespace file_util
diff --git a/base/test/test_file_util_win.cc b/base/test/test_file_util_win.cc
new file mode 100644
index 0000000..4ebea54
--- /dev/null
+++ b/base/test/test_file_util_win.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include <windows.h>
+
+#include <vector>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/platform_thread.h"
+#include "base/scoped_handle.h"
+
+namespace file_util {
+
+// We could use GetSystemInfo to get the page size, but this serves
+// our purpose fine since 4K is the page size on x86 as well as x64.
+static const ptrdiff_t kPageSize = 4096;
+
+bool DieFileDie(const FilePath& file, bool recurse) {
+ // It turns out that to not induce flakiness a long timeout is needed.
+ const int kTimeoutMs = 10000;
+
+ if (!file_util::PathExists(file))
+ return true;
+
+ // Sometimes Delete fails, so try a few more times. Divide the timeout
+ // into short chunks, so that if a try succeeds, we won't delay the test
+ // for too long.
+ for (int i = 0; i < 25; ++i) {
+ if (file_util::Delete(file, recurse))
+ return true;
+ PlatformThread::Sleep(kTimeoutMs / 25);
+ }
+ return false;
+}
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+ // Request exclusive access to the file and overwrite it with no buffering.
+ ScopedHandle file_handle(
+ CreateFile(file.value().c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL));
+ if (!file_handle)
+ return false;
+
+ // Get some attributes to restore later.
+ BY_HANDLE_FILE_INFORMATION bhi = {0};
+ CHECK(::GetFileInformationByHandle(file_handle, &bhi));
+
+ // Execute in chunks. It could be optimized. We want to do few of these since
+ // these operations will be slow without the cache.
+
+ // Non-buffered reads and writes need to be sector aligned and since sector
+ // sizes typically range from 512-4096 bytes, we just use the page size.
+ // The buffer size is twice the size of a page (minus one) since we need to
+ // get an aligned pointer into the buffer that we can use.
+ char buffer[2 * kPageSize - 1];
+ // Get an aligned pointer into buffer.
+ char* read_write = reinterpret_cast<char*>(
+ reinterpret_cast<ptrdiff_t>(buffer + kPageSize - 1) & ~(kPageSize - 1));
+ DCHECK((reinterpret_cast<int>(read_write) % kPageSize) == 0);
+
+ // If the file size isn't a multiple of kPageSize, we'll need special
+ // processing.
+ bool file_is_page_aligned = true;
+ int total_bytes = 0;
+ DWORD bytes_read, bytes_written;
+ for (;;) {
+ bytes_read = 0;
+ ReadFile(file_handle, read_write, kPageSize, &bytes_read, NULL);
+ if (bytes_read == 0)
+ break;
+
+ if (bytes_read < kPageSize) {
+ // Zero out the remaining part of the buffer.
+ // WriteFile will fail if we provide a buffer size that isn't a
+ // sector multiple, so we'll have to write the entire buffer with
+ // padded zeros and then use SetEndOfFile to truncate the file.
+ ZeroMemory(read_write + bytes_read, kPageSize - bytes_read);
+ file_is_page_aligned = false;
+ }
+
+ // Move back to the position we just read from.
+ // Note that SetFilePointer will also fail if total_bytes isn't sector
+ // aligned, but that shouldn't happen here.
+ DCHECK((total_bytes % kPageSize) == 0);
+ SetFilePointer(file_handle, total_bytes, NULL, FILE_BEGIN);
+ if (!WriteFile(file_handle, read_write, kPageSize, &bytes_written, NULL) ||
+ bytes_written != kPageSize) {
+ DCHECK(false);
+ return false;
+ }
+
+ total_bytes += bytes_read;
+
+ // If this is false, then we just processed the last portion of the file.
+ if (!file_is_page_aligned)
+ break;
+ }
+
+ if (!file_is_page_aligned) {
+ // The size of the file isn't a multiple of the page size, so we'll have
+ // to open the file again, this time without the FILE_FLAG_NO_BUFFERING
+ // flag and use SetEndOfFile to mark EOF.
+ file_handle.Set(NULL);
+ file_handle.Set(CreateFile(file.value().c_str(), GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, 0, NULL));
+ CHECK(SetFilePointer(file_handle, total_bytes, NULL, FILE_BEGIN) !=
+ INVALID_SET_FILE_POINTER);
+ CHECK(::SetEndOfFile(file_handle));
+ }
+
+ // Restore the file attributes.
+ CHECK(::SetFileTime(file_handle, &bhi.ftCreationTime, &bhi.ftLastAccessTime,
+ &bhi.ftLastWriteTime));
+
+ return true;
+}
+
+// Like CopyFileNoCache but recursively copies all files and subdirectories
+// in the given input directory to the output directory.
+bool CopyRecursiveDirNoCache(const std::wstring& source_dir,
+ const std::wstring& dest_dir) {
+ // Try to create the directory if it doesn't already exist.
+ if (!CreateDirectory(dest_dir)) {
+ if (GetLastError() != ERROR_ALREADY_EXISTS)
+ return false;
+ }
+
+ std::vector<std::wstring> files_copied;
+
+ std::wstring src(source_dir);
+ file_util::AppendToPath(&src, L"*");
+
+ WIN32_FIND_DATA fd;
+ HANDLE fh = FindFirstFile(src.c_str(), &fd);
+ if (fh == INVALID_HANDLE_VALUE)
+ return false;
+
+ do {
+ std::wstring cur_file(fd.cFileName);
+ if (cur_file == L"." || cur_file == L"..")
+ continue; // Skip these special entries.
+
+ std::wstring cur_source_path(source_dir);
+ file_util::AppendToPath(&cur_source_path, cur_file);
+
+ std::wstring cur_dest_path(dest_dir);
+ file_util::AppendToPath(&cur_dest_path, cur_file);
+
+ if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ // Recursively copy a subdirectory. We stripped "." and ".." already.
+ if (!CopyRecursiveDirNoCache(cur_source_path, cur_dest_path)) {
+ FindClose(fh);
+ return false;
+ }
+ } else {
+ // Copy the file.
+ if (!::CopyFile(cur_source_path.c_str(), cur_dest_path.c_str(), false)) {
+ FindClose(fh);
+ return false;
+ }
+
+ // We don't check for errors from this function, often, we are copying
+ // files that are in the repository, and they will have read-only set.
+ // This will prevent us from evicting from the cache, but these don't
+ // matter anyway.
+ EvictFileFromSystemCache(FilePath::FromWStringHack(cur_dest_path));
+ }
+ } while (FindNextFile(fh, &fd));
+
+ FindClose(fh);
+ return true;
+}
+
+} // namespace file_util
diff --git a/base/test/test_suite.h b/base/test/test_suite.h
new file mode 100644
index 0000000..1203904
--- /dev/null
+++ b/base/test/test_suite.h
@@ -0,0 +1,237 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_SUITE_H_
+#define BASE_TEST_SUITE_H_
+
+// Defines a basic test suite framework for running gtest based tests. You can
+// instantiate this class in your main function and call its Run method to run
+// any gtest based tests that are linked into your executable.
+
+#include "base/at_exit.h"
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/debug_on_start.h"
+#include "base/debug_util.h"
+#include "base/file_path.h"
+#include "base/i18n/icu_util.h"
+#include "base/logging.h"
+#include "base/multiprocess_test.h"
+#include "base/scoped_nsautorelease_pool.h"
+#include "base/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#if defined(OS_POSIX)
+#include <signal.h>
+#endif
+
+#if defined(OS_LINUX)
+#include <gtk/gtk.h>
+#endif
+
+#if defined(OS_POSIX)
+static void TestSuiteCrashHandler(int signal) {
+ StackTrace().PrintBacktrace();
+ _exit(1);
+}
+#endif // OS_POSIX
+
+#if defined(OS_WIN)
+// Previous unhandled filter. Will be called if not NULL when we intercept an
+// exception.
+__declspec(selectany) LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL;
+
+// Prints the exception call stack.
+// This is the unit tests exception filter.
+inline long WINAPI UnitTestExceptionFilter(EXCEPTION_POINTERS* info) {
+ StackTrace(info).PrintBacktrace();
+ if (g_previous_filter)
+ return g_previous_filter(info);
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+#endif // OS_WIN
+
+// Match function used by the GetTestCount method.
+typedef bool (*TestMatch)(const testing::TestInfo&);
+
+class TestSuite {
+ public:
+ TestSuite(int argc, char** argv) {
+ base::EnableTerminationOnHeapCorruption();
+ CommandLine::Init(argc, argv);
+ testing::InitGoogleTest(&argc, argv);
+#if defined(OS_LINUX)
+ g_thread_init(NULL);
+ gtk_init_check(&argc, &argv);
+#endif
+ // Don't add additional code to this constructor. Instead add it to
+ // Initialize(). See bug 6436.
+ }
+
+ virtual ~TestSuite() {
+ CommandLine::Terminate();
+ }
+
+ // Returns true if a string starts with FLAKY_.
+ static bool IsFlaky(const char* name) {
+ return strncmp(name, "FLAKY_", 6) == 0;
+ }
+
+ // Returns true if the test is marked as flaky.
+ static bool FlakyTest(const testing::TestInfo& test) {
+ return IsFlaky(test.name()) || IsFlaky(test.test_case_name());
+ }
+
+ // Returns true if the test failed and is not marked as flaky.
+ static bool NonFlakyFailures(const testing::TestInfo& test) {
+ return test.should_run() && test.result()->Failed() && !FlakyTest(test);
+ }
+
+ // Returns the number of tests where the match function returns true.
+ int GetTestCount(TestMatch test_match) {
+ testing::UnitTest* instance = testing::UnitTest::GetInstance();
+ int count = 0;
+
+ for (int i = 0; i < instance->total_test_case_count(); ++i) {
+ const testing::TestCase& test_case = *instance->GetTestCase(i);
+ for (int j = 0; j < test_case.total_test_count(); ++j) {
+ if (test_match(*test_case.GetTestInfo(j))) {
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ // Don't add additional code to this method. Instead add it to
+ // Initialize(). See bug 6436.
+ int Run() {
+ base::ScopedNSAutoreleasePool scoped_pool;
+
+ Initialize();
+ std::wstring client_func =
+ CommandLine::ForCurrentProcess()->GetSwitchValue(kRunClientProcess);
+ // Check to see if we are being run as a client process.
+ if (!client_func.empty()) {
+ // Convert our function name to a usable string for GetProcAddress.
+ std::string func_name(client_func.begin(), client_func.end());
+
+ return multi_process_function_list::InvokeChildProcessTest(func_name);
+ }
+ int result = RUN_ALL_TESTS();
+
+ // Reset the result code if only flaky test failed.
+ if (result != 0 && GetTestCount(&TestSuite::NonFlakyFailures) == 0) {
+ result = 0;
+ }
+
+ // Display the number of flaky tests.
+ int flaky_count = GetTestCount(&TestSuite::FlakyTest);
+ if (flaky_count) {
+ printf(" YOU HAVE %d FLAKY %s\n\n", flaky_count,
+ flaky_count == 1 ? "TEST" : "TESTS");
+ }
+
+ // This MUST happen before Shutdown() since Shutdown() tears down
+ // objects (such as NotificationService::current()) that Cocoa
+ // objects use to remove themselves as observers.
+ scoped_pool.Recycle();
+
+ Shutdown();
+
+ return result;
+ }
+
+ protected:
+ // All fatal log messages (e.g. DCHECK failures) imply unit test failures.
+ static void UnitTestAssertHandler(const std::string& str) {
+ FAIL() << str;
+ }
+
+#if defined(OS_WIN)
+ // Disable crash dialogs so that it doesn't gum up the buildbot
+ virtual void SuppressErrorDialogs() {
+ UINT new_flags = SEM_FAILCRITICALERRORS |
+ SEM_NOGPFAULTERRORBOX |
+ SEM_NOOPENFILEERRORBOX;
+
+ // Preserve existing error mode, as discussed at
+ // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx
+ UINT existing_flags = SetErrorMode(new_flags);
+ SetErrorMode(existing_flags | new_flags);
+ }
+#endif
+
+ // Override these for custom initialization and shutdown handling. Use these
+ // instead of putting complex code in your constructor/destructor.
+
+ virtual void Initialize() {
+ // Initialize logging.
+ FilePath exe;
+ PathService::Get(base::FILE_EXE, &exe);
+ FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
+ logging::InitLogging(log_filename.value().c_str(),
+ logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
+ logging::LOCK_LOG_FILE,
+ logging::DELETE_OLD_LOG_FILE);
+ // We want process and thread IDs because we may have multiple processes.
+ // Note: temporarily enabled timestamps in an effort to catch bug 6361.
+ logging::SetLogItems(true, true, true, true);
+
+#if defined(OS_POSIX)
+ // When running in an application, our code typically expects SIGPIPE
+ // to be ignored. Therefore, when testing that same code, it should run
+ // with SIGPIPE ignored as well.
+ struct sigaction action;
+ action.sa_handler = SIG_IGN;
+ action.sa_flags = 0;
+ sigemptyset(&action.sa_mask);
+ CHECK(sigaction(SIGPIPE, &action, NULL) == 0);
+
+ // TODO(phajdan.jr): Catch other crashy signals, like SIGABRT.
+ CHECK(signal(SIGSEGV, &TestSuiteCrashHandler) != SIG_ERR);
+ CHECK(signal(SIGILL, &TestSuiteCrashHandler) != SIG_ERR);
+ CHECK(signal(SIGBUS, &TestSuiteCrashHandler) != SIG_ERR);
+ CHECK(signal(SIGFPE, &TestSuiteCrashHandler) != SIG_ERR);
+#endif // OS_POSIX
+
+#if defined(OS_WIN)
+ // For unit tests we turn on the high resolution timer and disable
+ // base::Time's use of SystemMonitor. Tests create and destroy the message
+ // loop, which causes a crash with SystemMonitor (http://crbug.com/12187).
+ base::Time::EnableHiResClockForTests();
+
+ // In some cases, we do not want to see standard error dialogs.
+ if (!IsDebuggerPresent() &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(L"show-error-dialogs")) {
+ SuppressErrorDialogs();
+#if !defined(PURIFY)
+ // When the code in this file moved around, bug 6436 resurfaced.
+ // As a hack workaround, just #ifdef out this code for Purify builds.
+ logging::SetLogAssertHandler(UnitTestAssertHandler);
+#endif // !defined(PURIFY)
+ // Add stack dumping support on exception on windows. Similar to OS_POSIX
+ // signal() handling above.
+ g_previous_filter = SetUnhandledExceptionFilter(&UnitTestExceptionFilter);
+ }
+#endif // defined(OS_WIN)
+
+ icu_util::Initialize();
+ }
+
+ virtual void Shutdown() {
+ }
+
+ // Make sure that we setup an AtExitManager so Singleton objects will be
+ // destroyed.
+ base::AtExitManager at_exit_manager_;
+};
+
+#endif // BASE_TEST_SUITE_H_