From 3bef459eac9aa84c579f34249aebc9ff56832054 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Wed, 24 Feb 2010 17:19:25 +0000 Subject: Adds threading support (by Miklos Fazekas, Vlad Losev, and Chandler Carruth); adds wide InitGoogleTest to gtest.def (by Vlad Losev); updates the version number (by Zhanyong Wan); updates the release notes for 1.5.0 (by Vlad Losev); removes scons scripts from the distribution (by Zhanyong Wan); adds the cmake build script to the distribution (by Zhanyong Wan); adds fused source files to the distribution (by Vlad Losev and Chandler Carruth). --- CHANGES | 21 ++ CMakeLists.txt | 16 +- Makefile.am | 60 +++++- configure.ac | 22 +- include/gtest/internal/gtest-linked_ptr.h | 2 +- include/gtest/internal/gtest-port.h | 326 +++++++++++++++++++++++++++--- msvc/gtest.def | 1 + scons/SConscript | 19 +- scons/SConscript.common | 1 + scons/SConstruct.common | 2 + scripts/gtest-config.in | 8 +- src/gtest-internal-inl.h | 5 +- src/gtest-port.cc | 88 ++++++++ src/gtest.cc | 2 +- test/gtest-death-test_test.cc | 4 +- test/gtest-port_test.cc | 223 +++++++++++++++++++- test/gtest_dll_test_.cc | 5 + test/gtest_output_test.py | 8 +- test/gtest_output_test_golden_lin.txt | 40 +++- test/gtest_stress_test.cc | 44 ++-- test/gtest_unittest.cc | 18 -- 21 files changed, 796 insertions(+), 119 deletions(-) diff --git a/CHANGES b/CHANGES index 1858f7f..90a9540 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,24 @@ +Changes for 1.5.0: + + * New feature: Ability to use test assertions in multi-threaded tests + on platforms implementing pthreads. + * New feature: Predicates used inside EXPECT_TRUE() and friends + can now generate custom failure messages. + * New feature: Google Test can now be compiled as a DLL on Windows. + * New feature: The distribution package now includes fused source files. + * New feature: Prints help when encountering unrecognized Google Test flags. + * Experimental feature: CMake build script (requires CMake 2.6.4+). + * double values streamed to an assertion are printed with enough precision + to differentiate any two different values. + * Google Test now works on Solaris. + * Build and test script improvements. + * Bug fixes and implementation clean-ups. + + Potentially breaking changes: + + * Stopped supporting VC++ 7.1 with exceptions disabled. + * Dropped support for 'make install'. + Changes for 1.4.0: * New feature: the event listener API diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d3a402..8cde98c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,9 @@ include_directories( link_directories( ${gtest_BINARY_DIR}/src) +# Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT. +find_package(Threads) + # Defines the compiler/linker flags used to build gtest. You can # tweak these definitions to suit your need. if (MSVC) @@ -39,6 +42,11 @@ if (MSVC) set(cxx_default "${cxx_base} -EHsc -D_HAS_EXCEPTIONS=1") else() set(cxx_base "${CMAKE_CXX_FLAGS}") + + if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available. + set(cxx_base "${cxx_base} -DGTEST_HAS_PTHREAD=1") + endif() + set(cxx_default "${cxx_base} -fexceptions") endif() @@ -53,6 +61,9 @@ function(cxx_library name cxx_flags) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "${cxx_flags}") + if (CMAKE_USE_PTHREADS_INIT) + target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) + endif() endfunction() cxx_library(gtest "${cxx_default}" src/gtest-all.cc) @@ -150,6 +161,7 @@ endfunction() cxx_test(gtest_unittest gtest_main) if (build_all_gtest_tests) + cxx_test(gtest-death-test_test gtest_main) cxx_test(gtest_environment_test gtest) cxx_test(gtest-filepath_test gtest_main) cxx_test(gtest-linked_ptr_test gtest_main) @@ -192,10 +204,6 @@ if (build_all_gtest_tests) cxx_library(gtest_main_no_rtti "${cxx_no_rtti}" src/gtest-all.cc src/gtest_main.cc) - find_package(Threads) # Defines CMAKE_THREAD_LIBS_INIT. - cxx_test_with_flags(gtest-death-test_test "${cxx_default}" - "gtest_main;${CMAKE_THREAD_LIBS_INIT}" test/gtest-death-test_test.cc) - cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}" gtest_main_no_rtti test/gtest_unittest.cc) diff --git a/Makefile.am b/Makefile.am index 7ca3916..72bb71c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,10 +11,6 @@ EXTRA_DIST = \ include/gtest/internal/gtest-type-util.h.pump \ include/gtest/internal/gtest-param-util-generated.h.pump \ make/Makefile \ - run_tests.py \ - scons/SConscript \ - scons/SConstruct \ - scons/SConstruct.common \ scripts/fuse_gtest_files.py \ scripts/gen_gtest_pred_impl.py \ scripts/generate_gtest_def.py \ @@ -28,8 +24,7 @@ EXTRA_DIST += \ src/gtest-internal-inl.h \ src/gtest-port.cc \ src/gtest-test-part.cc \ - src/gtest-typed-test.cc \ - src/gtest.def + src/gtest-typed-test.cc # Sample files that we don't compile. EXTRA_DIST += \ @@ -112,6 +107,10 @@ EXTRA_DIST += \ test/run_tests_util.py \ test/run_tests_util_test.py +# CMake script +EXTRA_DIST += \ + CMakeLists.txt + # MSVC project files EXTRA_DIST += \ msvc/gtest-md.sln \ @@ -123,7 +122,8 @@ EXTRA_DIST += \ msvc/gtest_prod_test-md.vcproj \ msvc/gtest_prod_test.vcproj \ msvc/gtest_unittest-md.vcproj \ - msvc/gtest_unittest.vcproj + msvc/gtest_unittest.vcproj \ + msvc/gtest.def # xcode project files EXTRA_DIST += \ @@ -173,6 +173,14 @@ EXTRA_DIST += $(m4data_DATA) # directories. AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/include +# Modifies compiler and linker flags for pthreads compatibility. +if HAVE_PTHREADS + AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1 + AM_LIBS = @PTHREAD_LIBS@ +else + AM_CXXFLAGS = -DGTEST_HAS_PTHREAD=0 +endif + # Build rules for libraries. lib_LTLIBRARIES = lib/libgtest.la lib/libgtest_main.la @@ -244,6 +252,38 @@ samples_sample10_unittest_LDADD = lib/libgtest.la TESTS += test/gtest_all_test check_PROGRAMS += test/gtest_all_test test_gtest_all_test_SOURCES = test/gtest_all_test.cc -test_gtest_all_test_CXXFLAGS = $(AM_CXXFLAGS) $(PTHREAD_CFLAGS) -test_gtest_all_test_LDADD = $(PTHREAD_LIBS) $(PTHREAD_CFLAGS) \ - lib/libgtest_main.la +test_gtest_all_test_LDADD = lib/libgtest_main.la + +# Tests that fused gtest files compile and work. +TESTS += test/gtest_fused_test +check_PROGRAMS += test/gtest_fused_test +test_gtest_fused_test_SOURCES = fused-src/gtest/gtest-all.cc \ + fused-src/gtest/gtest_main.cc \ + fused-src/gtest/gtest.h \ + samples/sample1.cc samples/sample1_unittest.cc +test_gtest_fused_test_CPPFLAGS = -I"$(srcdir)/fused-src" + +# Build rules for putting fused Google Test files into the distribution +# package. The user can also create those files by manually running +# scripts/fuse_gtest_files.py. +$(srcdir)/fused-src/gtest/gtest-all.cc: fused-gtest-internal + +$(srcdir)/fused-src/gtest/gtest.h: fused-gtest-internal + +fused-gtest-internal: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \ + $(lib_libgtest_la_SOURCES) \ + scripts/fuse_gtest_files.py + mkdir -p "$(srcdir)/fused-src/gtest" + chmod -R u+w "$(srcdir)/fused-src" + rm -f "$(srcdir)/fused-src/gtest/gtest-all.cc" + rm -f "$(srcdir)/fused-src/gtest/gtest.h" + "$(srcdir)/scripts/fuse_gtest_files.py" "$(srcdir)/fused-src" + +$(srcdir)/fused-src/gtest/gtest_main.cc: src/gtest_main.cc + mkdir -p "$(srcdir)/fused-src/gtest" + chmod -R u+w "$(srcdir)/fused-src" + cp -f "$(srcdir)/src/gtest_main.cc" "$(srcdir)/fused-src/gtest" + +maintainer-clean-local: + chmod -R u+w "$(srcdir)/fused-src" + rm -rf "$(srcdir)/fused-src/gtest" diff --git a/configure.ac b/configure.ac index 709b024..1b91237 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ m4_include(m4/acx_pthread.m4) # "[1.0.1]"). It also asumes that there won't be any closing parenthesis # between "AC_INIT(" and the closing ")" including comments and strings. AC_INIT([Google C++ Testing Framework], - [1.4.0], + [1.5.0], [googletestframework@googlegroups.com], [gtest]) @@ -39,8 +39,24 @@ AS_IF([test "$PYTHON" != ":"], [AM_PYTHON_CHECK_VERSION([$PYTHON],[2.3],[:],[PYTHON=":"])]) AM_CONDITIONAL([HAVE_PYTHON],[test "$PYTHON" != ":"]) -# Check for pthreads. -ACX_PTHREAD +# Configure pthreads. +AC_ARG_WITH([pthreads], + [AS_HELP_STRING([--with-pthreads], + [use pthreads (default is yes)])], + [with_pthreads=$withval], + [with_pthreads=check]) + +have_pthreads=no +AS_IF([test "x$with_pthreads" != "xno"], + [ACX_PTHREAD( + [], + [AS_IF([test "x$with_pthreads" != "xcheck"], + [AC_MSG_FAILURE( + [--with-pthreads was specified, but unable to be used])])]) + have_pthreads="$acx_pthread_ok"]) +AM_CONDITIONAL([HAVE_PTHREADS],[test "x$have_pthreads" == "xyes"]) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_LIBS) # TODO(chandlerc@google.com) Check for the necessary system headers. diff --git a/include/gtest/internal/gtest-linked_ptr.h b/include/gtest/internal/gtest-linked_ptr.h index f98af0b..5304bcc 100644 --- a/include/gtest/internal/gtest-linked_ptr.h +++ b/include/gtest/internal/gtest-linked_ptr.h @@ -77,7 +77,7 @@ namespace testing { namespace internal { // Protects copying of all linked_ptr objects. -extern Mutex g_linked_ptr_mutex; +GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); // This is used internally by all instances of linked_ptr<>. It needs to be // a non-template class because different types of linked_ptr<> can refer to diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index c049a00..3894124 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -343,10 +343,14 @@ #endif // GTEST_HAS_RTTI -// Determines whether is available. +// Determines whether Google Test can use the pthreads library. #ifndef GTEST_HAS_PTHREAD -// The user didn't tell us, so we need to figure it out. -#define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_SOLARIS) +// The user didn't tell us explicitly, so we assume pthreads support is +// available on Linux and Mac. +// +// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 +// to your compiler flags. +#define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC) #endif // GTEST_HAS_PTHREAD // Determines whether Google Test can use tr1/tuple. You can define @@ -708,6 +712,27 @@ class GTestLog { inline void LogToStderr() {} inline void FlushInfoLog() { fflush(NULL); } +// INTERNAL IMPLEMENTATION - DO NOT USE. +// +// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition +// is not satisfied. +// Synopsys: +// GTEST_CHECK_(boolean_condition); +// or +// GTEST_CHECK_(boolean_condition) << "Additional message"; +// +// This checks the condition and if the condition is not satisfied +// it prints message about the condition violation, including the +// condition itself, plus additional message streamed into it, if any, +// and then it aborts the program. It aborts the program irrespective of +// whether it is built in the debug mode or not. +#define GTEST_CHECK_(condition) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::IsTrue(condition)) \ + ; \ + else \ + GTEST_LOG_(FATAL) << "Condition " #condition " failed. " + #if GTEST_HAS_STREAM_REDIRECTION_ // Defines the stderr capturer: @@ -736,6 +761,260 @@ const ::std::vector& GetArgvs(); // Defines synchronization primitives. +#if GTEST_HAS_PTHREAD + +// gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is +// true. +#include + +// MutexBase and Mutex implement mutex on pthreads-based platforms. They +// are used in conjunction with class MutexLock: +// +// Mutex mutex; +// ... +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end +// // of the current scope. +// +// MutexBase implements behavior for both statically and dynamically +// allocated mutexes. Do not use the MutexBase type directly. Instead, +// define a static mutex using the GTEST_DEFINE_STATIC_MUTEX_ macro: +// +// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// +// Such mutex may also be forward-declared: +// +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// Do not use MutexBase for dynamic mutexes either. Use the Mutex class +// for them. +class MutexBase { + public: + void Lock(); + void Unlock(); + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld() const; + + // We must be able to initialize objects of MutexBase used as static + // mutexes with initializer lists. This means MutexBase has to be a POD. + // The class members have to be public. + public: + pthread_mutex_t mutex_; + pthread_t owner_; +}; + +// Forward-declares a static mutex. +#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex + +// Defines and statically initializes a static mutex. +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 } + +// The class Mutex supports only mutexes created at runtime. It shares its +// API with MutexBase otherwise. +class Mutex : public MutexBase { + public: + Mutex(); + ~Mutex(); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +// We cannot call it MutexLock directly as the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(MutexBase* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + MutexBase* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Implements thread-local storage on pthreads-based systems. +// +// // Thread 1 +// ThreadLocal tl(100); +// +// // Thread 2 +// tl.set(150); +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // On Thread 1, tl.get() returns original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); +// +// The default ThreadLocal constructor requires T to have a default +// constructor. The single param constructor requires a copy contructor +// from T. A per-thread object managed by a ThreadLocal instance for a +// thread is guaranteed to exist at least until the earliest of the two +// events: (a) the thread terminates or (b) the ThreadLocal object +// managing it is destroyed. +template +class ThreadLocal { + public: + ThreadLocal() + : key_(CreateKey()), + default_(), + instance_creator_func_(DefaultConstructNewInstance) {} + + explicit ThreadLocal(const T& value) + : key_(CreateKey()), + default_(value), + instance_creator_func_(CopyConstructNewInstance) {} + + ~ThreadLocal() { + const int err = pthread_key_delete(key_); + GTEST_CHECK_(err == 0) << "pthread_key_delete failed with error " << err; + } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + static pthread_key_t CreateKey() { + pthread_key_t key; + const int err = pthread_key_create(&key, &DeleteData); + GTEST_CHECK_(err == 0) << "pthread_key_create failed with error " << err; + return key; + } + + T* GetOrCreateValue() const { + T* value = static_cast(pthread_getspecific(key_)); + if (value == NULL) { + value = (*instance_creator_func_)(default_); + const int err = pthread_setspecific(key_, value); + GTEST_CHECK_(err == 0) << "pthread_setspecific failed with error " << err; + } + return value; + } + + static void DeleteData(void* data) { delete static_cast(data); } + + static T* DefaultConstructNewInstance(const T&) { return new T(); } + + // Copy constructs new instance of T from default_. Will not be + // instantiated unless this ThreadLocal is constructed by the single + // parameter constructor. + static T* CopyConstructNewInstance(const T& t) { return new T(t); } + + // A key pthreads uses for looking up per-thread values. + const pthread_key_t key_; + // Contains the value that CopyConstructNewInstance copies from. + const T default_; + // Points to either DefaultConstructNewInstance or CopyConstructNewInstance. + T* (*const instance_creator_func_)(const T& default_); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +// Allows the controller thread pause execution of newly created test +// threads until signalled. Instances of this class must be created and +// destroyed in the controller thread. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. +class ThreadStartSemaphore { + public: + ThreadStartSemaphore(); + ~ThreadStartSemaphore(); + // Signals to all test threads created with this semaphore to start. Must + // be called from the controlling thread. + void Signal(); + // Blocks until the controlling thread signals. Must be called from a test + // thread. + void Wait(); + + private: + // We cannot use Mutex here as this class is intended for testing it. + pthread_mutex_t mutex_; + pthread_cond_t cond_; + bool signalled_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadStartSemaphore); +}; + +// Helper class for testing Google Test's multithreading constructs. +// Use: +// +// void ThreadFunc(int param) { /* Do things with param */ } +// ThreadSemaphore semaphore; +// ... +// // The semaphore parameter is optional; you can supply NULL. +// ThredWithParam thread(&ThreadFunc, 5, &semaphore); +// sem.Signal(); // Allows the thread to start. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. +template +class ThreadWithParam { + public: + typedef void (*UserThreadFunc)(T); + + ThreadWithParam(UserThreadFunc func, T param, ThreadStartSemaphore* semaphore) + : func_(func), + param_(param), + start_semaphore_(semaphore), + finished_(false) { + // func_, param_, and start_semaphore_ must be initialized before + // pthread_create() is called. + const int err = pthread_create(&thread_, 0, ThreadMainStatic, this); + GTEST_CHECK_(err == 0) << "pthread_create failed with error: " + << strerror(err) << "(" << err << ")"; + } + ~ThreadWithParam() { Join(); } + + void Join() { + if (!finished_) { + const int err = pthread_join(thread_, 0); + GTEST_CHECK_(err == 0) << "pthread_join failed with error:" + << strerror(err) << "(" << err << ")"; + finished_ = true; + } + } + + private: + void ThreadMain() { + if (start_semaphore_ != NULL) + start_semaphore_->Wait(); + func_(param_); + } + static void* ThreadMainStatic(void* param) { + static_cast*>(param)->ThreadMain(); + return NULL; // We are not interested in thread exit code. + } + + // User supplied thread function. + const UserThreadFunc func_; + // User supplied parameter to UserThreadFunc. + const T param_; + + // Native thread object. + pthread_t thread_; + // When non-NULL, used to block execution until the controller thread + // signals. + ThreadStartSemaphore* const start_semaphore_; + // true iff UserThreadFunc has not completed yet. + bool finished_; +}; + +#define GTEST_IS_THREADSAFE 1 + +#else // GTEST_HAS_PTHREAD + // A dummy implementation of synchronization primitives (mutex, lock, // and thread-local variable). Necessary for compiling Google Test where // mutex is not supported - using Google Test in multiple threads is not @@ -744,14 +1023,14 @@ const ::std::vector& GetArgvs(); class Mutex { public: Mutex() {} - explicit Mutex(int /*unused*/) {} void AssertHeld() const {} - enum { NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX = 0 }; }; -// We cannot call it MutexLock directly as the ctor declaration would -// conflict with a macro named MutexLock, which is defined on some -// platforms. Hence the typedef trick below. +#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex + class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT @@ -772,14 +1051,16 @@ class ThreadLocal { T value_; }; -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. -size_t GetThreadCount(); - // The above synchronization primitives have dummy implementations. // Therefore Google Test is not thread-safe. #define GTEST_IS_THREADSAFE 0 +#endif // GTEST_HAS_PTHREAD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount(); + // Passing non-POD classes through ellipsis (...) crashes the ARM // compiler and generates a warning in Sun Studio. The Nokia Symbian // and the IBM XL C/C++ compiler try to instantiate a copy constructor @@ -1024,27 +1305,6 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Utilities for command line flags and environment variables. -// INTERNAL IMPLEMENTATION - DO NOT USE. -// -// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition -// is not satisfied. -// Synopsys: -// GTEST_CHECK_(boolean_condition); -// or -// GTEST_CHECK_(boolean_condition) << "Additional message"; -// -// This checks the condition and if the condition is not satisfied -// it prints message about the condition violation, including the -// condition itself, plus additional message streamed into it, if any, -// and then it aborts the program. It aborts the program irrespective of -// whether it is built in the debug mode or not. -#define GTEST_CHECK_(condition) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::IsTrue(condition)) \ - ; \ - else \ - GTEST_LOG_(FATAL) << "Condition " #condition " failed. " - // Macro for referencing flags. #define GTEST_FLAG(name) FLAGS_gtest_##name diff --git a/msvc/gtest.def b/msvc/gtest.def index a5583df..8e16eb6 100644 --- a/msvc/gtest.def +++ b/msvc/gtest.def @@ -75,6 +75,7 @@ EXPORTS ?HasNonfatalFailure@TestResult@testing@@QBE_NXZ ?Init@RE@internal@testing@@AAEXPBD@Z ?InitGoogleTest@testing@@YAXPAHPAPAD@Z + ?InitGoogleTest@testing@@YAXPAHPAPA_W@Z ?IsHRESULTFailure@internal@testing@@YA?AVAssertionResult@2@PBDJ@Z ?IsHRESULTSuccess@internal@testing@@YA?AVAssertionResult@2@PBDJ@Z ?IsTrue@internal@testing@@YA_N_N@Z diff --git a/scons/SConscript b/scons/SConscript index df1392e..1e19df7 100644 --- a/scons/SConscript +++ b/scons/SConscript @@ -128,6 +128,10 @@ env_with_exceptions = EnvCreator.Create(env_warning_ok, EnvCreator.WithExceptions) env_without_rtti = EnvCreator.Create(env_warning_ok, EnvCreator.NoRtti) +env_with_exceptions_and_threads = EnvCreator.Create(env_with_threads, + EnvCreator.WithExceptions) +env_with_exceptions_and_threads['OBJ_SUFFIX'] = '_with_exceptions_and_threads' + ############################################################ # Helpers for creating build targets. @@ -232,7 +236,11 @@ gtest, gtest_main = GtestStaticLibraries(env) gtest_ex, gtest_main_ex = GtestStaticLibraries(env_with_exceptions) gtest_no_rtti, gtest_main_no_rtti = GtestStaticLibraries(env_without_rtti) gtest_use_own_tuple, gtest_main_use_own_tuple = GtestStaticLibraries( - env_use_own_tuple) + env_use_own_tuple) +gtest_with_threads, gtest_main_with_threads = GtestStaticLibraries( + env_with_threads) +gtest_ex_with_threads, gtest_main_ex_with_threads = GtestStaticLibraries( + env_with_exceptions_and_threads) # Install the libraries if needed. if 'LIB_OUTPUT' in env.Dictionary(): @@ -259,7 +267,6 @@ if BUILD_TESTS: additional_sources=['../test/gtest-param-test2_test.cc']) GtestTest(env, 'gtest_color_test_', gtest) GtestTest(env, 'gtest-linked_ptr_test', gtest_main) - GtestTest(env, 'gtest-port_test', gtest_main) GtestTest(env, 'gtest_break_on_failure_unittest_', gtest) GtestTest(env, 'gtest_filter_unittest_', gtest) GtestTest(env, 'gtest_help_test_', gtest_main) @@ -275,10 +282,12 @@ if BUILD_TESTS: ############################################################ # Tests targets using custom environments. GtestTest(env_warning_ok, 'gtest_unittest', gtest_main) - GtestTest(env_with_exceptions, 'gtest_output_test_', gtest_ex) + GtestTest(env_with_exceptions_and_threads, 'gtest_output_test_', + gtest_ex_with_threads) GtestTest(env_with_exceptions, 'gtest_throw_on_failure_ex_test', gtest_ex) - GtestTest(env_with_threads, 'gtest-death-test_test', gtest_main) - GtestTest(env_with_threads, 'gtest_stress_test', gtest) + GtestTest(env_with_threads, 'gtest-death-test_test', gtest_main_with_threads) + GtestTest(env_with_threads, 'gtest-port_test', gtest_main_with_threads) + GtestTest(env_with_threads, 'gtest_stress_test', gtest_with_threads) GtestTest(env_less_optimized, 'gtest_env_var_test_', gtest) GtestTest(env_less_optimized, 'gtest_uninitialized_test_', gtest) GtestTest(env_use_own_tuple, 'gtest-tuple_test', gtest_main_use_own_tuple) diff --git a/scons/SConscript.common b/scons/SConscript.common index 7943e77..adefa58 100644 --- a/scons/SConscript.common +++ b/scons/SConscript.common @@ -119,6 +119,7 @@ class EnvCreator: # selecting on a platform. env.Append(CCFLAGS=['-pthread']) env.Append(LINKFLAGS=['-pthread']) + env.Append(CPPDEFINES='GTEST_HAS_PTHREAD=1') WithThreads = classmethod(WithThreads) def NoRtti(cls, env): diff --git a/scons/SConstruct.common b/scons/SConstruct.common index 59b8864..6b10033 100644 --- a/scons/SConstruct.common +++ b/scons/SConstruct.common @@ -200,7 +200,9 @@ class SConstructHelper: '-Wall', '-Werror', '-Wshadow', + '-DGTEST_HAS_PTHREAD=1' ]) + env.Append(LINKFLAGS=['-pthread']) if optimized: env.Append(CCFLAGS=['-O2'], CPPDEFINES=['NDEBUG', '_NDEBUG']) else: diff --git a/scripts/gtest-config.in b/scripts/gtest-config.in index b82d5a1..9c72638 100755 --- a/scripts/gtest-config.in +++ b/scripts/gtest-config.in @@ -214,7 +214,7 @@ if test "${this_bindir}" = "${this_bindir%${bindir}}"; then # TODO(chandlerc@google.com): This is a dangerous dependency on libtool, we # should work to remove it, and/or remove libtool altogether, replacing it # with direct references to the library and a link path. - gtest_libs="${build_dir}/lib/libgtest.la" + gtest_libs="${build_dir}/lib/libgtest.la @PTHREAD_CFLAGS@ @PTHREAD_LIBS@" gtest_ldflags="" # We provide hooks to include from either the source or build dir, where the @@ -222,15 +222,15 @@ if test "${this_bindir}" = "${this_bindir%${bindir}}"; then # build rules for generated headers and have them automatically be preferred # over provided versions. gtest_cppflags="-I${build_dir}/include -I${src_dir}/include" - gtest_cxxflags="" + gtest_cxxflags="@PTHREAD_CFLAGS@" else # We're using an installed gtest, although it may be staged under some # prefix. Assume (as our own libraries do) that we can resolve the prefix, # and are present in the dynamic link paths. gtest_ldflags="-L${libdir}" - gtest_libs="-l${name}" + gtest_libs="-l${name} @PTHREAD_CFLAGS@ @PTHREAD_LIBS@" gtest_cppflags="-I${includedir}" - gtest_cxxflags="" + gtest_cxxflags="@PTHREAD_CFLAGS@" fi # Do an installation query if requested. diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 596dc55..4142e7a 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -60,7 +60,7 @@ #include // For DWORD. #endif // GTEST_OS_WINDOWS -#include +#include // NOLINT #include namespace testing { @@ -1228,6 +1228,9 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { // TestResult contains some private methods that should be hidden from // Google Test user but are required for testing. This class allow our tests // to access them. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. class TestResultAccessor { public: static void RecordProperty(TestResult* test_result, diff --git a/src/gtest-port.cc b/src/gtest-port.cc index b9504f5..5994fd5 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -75,6 +75,94 @@ const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER +#if GTEST_HAS_PTHREAD + +// ThreadStartSemaphore allows the controller thread to pause execution of +// newly created test threads until signalled. Instances of this class must +// be created and destroyed in the controller thread. +ThreadStartSemaphore::ThreadStartSemaphore() : signalled_(false) { + int err = pthread_mutex_init(&mutex_, NULL); + GTEST_CHECK_(err == 0) << "pthread_mutex_init failed with error " << err; + err = pthread_cond_init(&cond_, NULL); + GTEST_CHECK_(err == 0) << "pthread_cond_init failed with error " << err; + pthread_mutex_lock(&mutex_); +} + +ThreadStartSemaphore::~ThreadStartSemaphore() { + // Every ThreadStartSemaphore object must be signalled. It locks + // internal mutex upon creation and Signal unlocks it. + GTEST_CHECK_(signalled_); + + int err = pthread_mutex_destroy(&mutex_); + GTEST_CHECK_(err == 0) + << "pthread_mutex_destroy failed with error " << err; + err = pthread_cond_destroy(&cond_); + GTEST_CHECK_(err == 0) + << "pthread_cond_destroy failed with error " << err; +} + +// Signals to all test threads to start. Must be called from the +// controlling thread. +void ThreadStartSemaphore::Signal() { + signalled_ = true; + int err = pthread_cond_signal(&cond_); + GTEST_CHECK_(err == 0) + << "pthread_cond_signal failed with error " << err; + err = pthread_mutex_unlock(&mutex_); + GTEST_CHECK_(err == 0) + << "pthread_mutex_unlock failed with error " << err; +} + +// Blocks until the controlling thread signals. Should be called from a +// test thread. +void ThreadStartSemaphore::Wait() { + int err = pthread_mutex_lock(&mutex_); + GTEST_CHECK_(err == 0) << "pthread_mutex_lock failed with error " << err; + + while (!signalled_) { + err = pthread_cond_wait(&cond_, &mutex_); + GTEST_CHECK_(err == 0) + << "pthread_cond_wait failed with error " << err; + } + err = pthread_mutex_unlock(&mutex_); + GTEST_CHECK_(err == 0) + << "pthread_mutex_unlock failed with error " << err; +} + +void MutexBase::Lock() { + const int err = pthread_mutex_lock(&mutex_); + GTEST_CHECK_(err == 0) << "pthread_mutex_lock failed with error " << err; + owner_ = pthread_self(); +} + +void MutexBase::Unlock() { + // We don't protect writing to owner_ here, as it's the caller's + // responsibility to ensure that the current thread holds the mutex when + // this is called. + owner_ = 0; + const int err = pthread_mutex_unlock(&mutex_); + GTEST_CHECK_(err == 0) << "pthread_mutex_unlock failed with error " << err; +} + +// Does nothing if the current thread holds the mutex. Otherwise, crashes +// with high probability. +void MutexBase::AssertHeld() const { + GTEST_CHECK_(owner_ == pthread_self()) + << "Current thread is not holding mutex." << this; +} + +Mutex::Mutex() { + owner_ = 0; + const int err = pthread_mutex_init(&mutex_, NULL); + GTEST_CHECK_(err == 0) << "pthread_mutex_init failed with error " << err; +} + +Mutex::~Mutex() { + const int err = pthread_mutex_destroy(&mutex_); + GTEST_CHECK_(err == 0) << "pthread_mutex_destroy failed with error " << err; +} +#endif // GTEST_HAS_PTHREAD + #if GTEST_OS_MAC // Returns the number of threads running in the process, or 0 to indicate that diff --git a/src/gtest.cc b/src/gtest.cc index fb5bae9..3306f3f 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -342,7 +342,7 @@ void AssertHelper::operator=(const Message& message) const { } // Mutex for linked pointers. -Mutex g_linked_ptr_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX); +GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); // Application pathname gotten in InitGoogleTest. String g_executable_path; diff --git a/test/gtest-death-test_test.cc b/test/gtest-death-test_test.cc index 1c7fa47..127b7ff 100644 --- a/test/gtest-death-test_test.cc +++ b/test/gtest-death-test_test.cc @@ -410,7 +410,7 @@ void SetPthreadFlag() { } // namespace -#if GTEST_HAS_CLONE +#if GTEST_HAS_CLONE && GTEST_HAS_PTHREAD TEST_F(TestForDeathTest, DoesNotExecuteAtforkHooks) { if (!testing::GTEST_FLAG(death_test_use_fork)) { @@ -422,7 +422,7 @@ TEST_F(TestForDeathTest, DoesNotExecuteAtforkHooks) { } } -#endif // GTEST_HAS_CLONE +#endif // GTEST_HAS_CLONE && GTEST_HAS_PTHREAD // Tests that a method of another class can be used in a death test. TEST_F(TestForDeathTest, MethodOfAnotherClass) { diff --git a/test/gtest-port_test.cc b/test/gtest-port_test.cc index 3576c2b..8594aa9 100644 --- a/test/gtest-port_test.cc +++ b/test/gtest-port_test.cc @@ -35,11 +35,16 @@ #include +#if GTEST_HAS_PTHREAD +#include // For nanosleep(). +#endif // GTEST_HAS_PTHREAD + #if GTEST_OS_MAC -#include #include #endif // GTEST_OS_MAC +#include // For std::pair and std::make_pair. + #include #include @@ -52,6 +57,9 @@ #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ +using std::make_pair; +using std::pair; + namespace testing { namespace internal { @@ -94,7 +102,7 @@ TEST(GtestCheckSyntaxTest, WorksWithSwitch) { #if GTEST_OS_MAC void* ThreadFunc(void* data) { - pthread_mutex_t* mutex = reinterpret_cast(data); + pthread_mutex_t* mutex = static_cast(data); pthread_mutex_lock(mutex); pthread_mutex_unlock(mutex); return NULL; @@ -745,5 +753,216 @@ TEST(CaptureDeathTest, CannotReenterStdoutCapture) { #endif // !GTEST_OS_WINDOWS_MOBILE +TEST(ThreadLocalTest, DefaultConstructorInitializesToDefaultValues) { + ThreadLocal t1; + EXPECT_EQ(0, t1.get()); + + ThreadLocal t2; + EXPECT_TRUE(t2.get() == NULL); +} + +TEST(ThreadLocalTest, SingleParamConstructorInitializesToParam) { + ThreadLocal t1(123); + EXPECT_EQ(123, t1.get()); + + int i = 0; + ThreadLocal t2(&i); + EXPECT_EQ(&i, t2.get()); +} + +class NoCopyConstructor { + public: + NoCopyConstructor() {} + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(NoCopyConstructor); +}; + +TEST(ThreadLocalTest, ValueCopyConstructorIsNotRequiredForDefaultVersion) { + ThreadLocal bar; + bar.get(); +} + +class NoDefaultContructor { + public: + explicit NoDefaultContructor(const char*) {} + NoDefaultContructor(const NoDefaultContructor&) {} +}; + +TEST(ThreadLocalTest, ValueDefaultContructorIsNotRequiredForParamVersion) { + ThreadLocal bar(NoDefaultContructor("foo")); + bar.pointer(); +} + +TEST(ThreadLocalTest, GetAndPointerReturnSameValue) { + ThreadLocal thread_local; + + // This is why EXPECT_TRUE is used here rather than EXPECT_EQ because + // we don't care about a particular value of thread_local.pointer() here; + // we only care about pointer and reference referring to the same lvalue. + EXPECT_EQ(thread_local.pointer(), &(thread_local.get())); + + // Verifies the condition still holds after calling set. + thread_local.set("foo"); + EXPECT_EQ(thread_local.pointer(), &(thread_local.get())); +} + +TEST(ThreadLocalTest, PointerAndConstPointerReturnSameValue) { + ThreadLocal thread_local; + const ThreadLocal& const_thread_local = thread_local; + + EXPECT_EQ(thread_local.pointer(), const_thread_local.pointer()); + + thread_local.set("foo"); + EXPECT_EQ(thread_local.pointer(), const_thread_local.pointer()); +} + +#if GTEST_IS_THREADSAFE +TEST(MutexTestDeathTest, AssertHeldShouldAssertWhenNotLocked) { + // AssertHeld() is flaky only in the presence of multiple threads accessing + // the lock. In this case, the test is robust. + EXPECT_DEATH_IF_SUPPORTED({ + Mutex m; + { MutexLock lock(&m); } + m.AssertHeld(); + }, + "Current thread is not holding mutex..+"); +} + +void SleepMilliseconds(int time) { + usleep(static_cast(time * 1000.0)); +} + +class AtomicCounterWithMutex { + public: + explicit AtomicCounterWithMutex(Mutex* mutex) : + value_(0), mutex_(mutex), random_(42) {} + + void Increment() { + MutexLock lock(mutex_); + int temp = value_; + { + // Locking a mutex puts up a memory barrier, preventing reads and + // writes to value_ rearranged when observed from other threads. + // + // We cannot use Mutex and MutexLock here or rely on their memory + // barrier functionality as we are testing them here. + pthread_mutex_t memory_barrier_mutex; + int err = pthread_mutex_init(&memory_barrier_mutex, NULL); + GTEST_CHECK_(err == 0) << "pthread_mutex_init failed with error " << err; + err = pthread_mutex_lock(&memory_barrier_mutex); + GTEST_CHECK_(err == 0) << "pthread_mutex_lock failed with error " << err; + + SleepMilliseconds(random_.Generate(30)); + + err = pthread_mutex_unlock(&memory_barrier_mutex); + GTEST_CHECK_(err == 0) + << "pthread_mutex_unlock failed with error " << err; + } + value_ = temp + 1; + } + int value() const { return value_; } + + private: + volatile int value_; + Mutex* const mutex_; // Protects value_. + Random random_; +}; + +void CountingThreadFunc(pair param) { + for (int i = 0; i < param.second; ++i) + param.first->Increment(); +} + +// Tests that the mutex only lets one thread at a time to lock it. +TEST(MutexTest, OnlyOneThreadCanLockAtATime) { + Mutex mutex; + AtomicCounterWithMutex locked_counter(&mutex); + + typedef ThreadWithParam > ThreadType; + const int kCycleCount = 20; + const int kThreadCount = 7; + scoped_ptr counting_threads[kThreadCount]; + ThreadStartSemaphore semaphore; + // Creates and runs kThreadCount threads that increment locked_counter + // kCycleCount times each. + for (int i = 0; i < kThreadCount; ++i) { + counting_threads[i].reset(new ThreadType(&CountingThreadFunc, + make_pair(&locked_counter, + kCycleCount), + &semaphore)); + } + semaphore.Signal(); // Start the threads. + for (int i = 0; i < kThreadCount; ++i) + counting_threads[i]->Join(); + + // If the mutex lets more than one thread to increment the counter at a + // time, they are likely to encounter a race condition and have some + // increments overwritten, resulting in the lower then expected counter + // value. + EXPECT_EQ(kCycleCount * kThreadCount, locked_counter.value()); +} + +template +void RunFromThread(void (func)(T), T param) { + ThreadWithParam thread(func, param, NULL); + thread.Join(); +} + +void RetrieveThreadLocalValue(pair*, String*> param) { + *param.second = param.first->get(); +} + +TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) { + ThreadLocal thread_local("foo"); + EXPECT_STREQ("foo", thread_local.get().c_str()); + + thread_local.set("bar"); + EXPECT_STREQ("bar", thread_local.get().c_str()); + + String result; + RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local, &result)); + EXPECT_STREQ("foo", result.c_str()); +} + +class CountedDestructor { + public: + ~CountedDestructor() { counter_++; } + static int counter() { return counter_; } + static void set_counter(int value) { counter_ = value; } + + private: + static int counter_; +}; +int CountedDestructor::counter_ = 0; + +template +void CallThreadLocalGet(ThreadLocal* threadLocal) { + threadLocal->get(); +} + +TEST(ThreadLocalTest, DestroysManagedObjectsNoLaterThanSelf) { + CountedDestructor::set_counter(0); + { + ThreadLocal thread_local; + ThreadWithParam*> thread( + &CallThreadLocalGet, &thread_local, NULL); + thread.Join(); + } + // There should be 2 desctuctor calls as ThreadLocal also contains a member + // T - used as a prototype for copy ctr version. + EXPECT_EQ(2, CountedDestructor::counter()); +} + +TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) { + ThreadLocal thread_local; + thread_local.set("Foo"); + EXPECT_STREQ("Foo", thread_local.get().c_str()); + + String result; + RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local, &result)); + EXPECT_TRUE(result.c_str() == NULL); +} +#endif // GTEST_IS_THREADSAFE + } // namespace internal } // namespace testing diff --git a/test/gtest_dll_test_.cc b/test/gtest_dll_test_.cc index c99358a..3fb6181 100644 --- a/test/gtest_dll_test_.cc +++ b/test/gtest_dll_test_.cc @@ -484,6 +484,11 @@ class MyOtherListener : public EmptyTestEventListener {}; int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); + void (*wide_init_google_test)(int*, wchar_t**) = &testing::InitGoogleTest; + + // Ensures the linker doesn't throw away reference to wide InitGoogleTest. + GTEST_CHECK_(wide_init_google_test != NULL); + TestEventListeners& listeners = UnitTest::GetInstance()->listeners(); TestEventListener* listener = new MyListener; diff --git a/test/gtest_output_test.py b/test/gtest_output_test.py index a0aa64f..4374a96 100755 --- a/test/gtest_output_test.py +++ b/test/gtest_output_test.py @@ -238,7 +238,9 @@ SUPPORTS_TYPED_TESTS = 'TypedTest' in test_list SUPPORTS_THREADS = 'ExpectFailureWithThreadsTest' in test_list SUPPORTS_STACK_TRACES = False -CAN_GENERATE_GOLDEN_FILE = SUPPORTS_DEATH_TESTS and SUPPORTS_TYPED_TESTS +CAN_GENERATE_GOLDEN_FILE = (SUPPORTS_DEATH_TESTS and + SUPPORTS_TYPED_TESTS and + SUPPORTS_THREADS) class GTestOutputTest(gtest_test_utils.TestCase): @@ -314,8 +316,8 @@ that does not support all the required features (death tests""") """\nand typed tests). Please check that you are using VC++ 8.0 SP1 or higher as your compiler.""") else: - message += """\nand typed tests). Please generate the golden file -using a binary built with those features enabled.""" + message += """\ntyped tests, and threads). Please generate the +golden file using a binary built with those features enabled.""" sys.stderr.write(message) sys.exit(1) diff --git a/test/gtest_output_test_golden_lin.txt b/test/gtest_output_test_golden_lin.txt index 51bae52..4d67bd6 100644 --- a/test/gtest_output_test_golden_lin.txt +++ b/test/gtest_output_test_golden_lin.txt @@ -7,7 +7,7 @@ Expected: true gtest_output_test_.cc:#: Failure Value of: 3 Expected: 2 -[==========] Running 56 tests from 23 test cases. +[==========] Running 59 tests from 25 test cases. [----------] Global test environment set-up. FooEnvironment::SetUp() called. BarEnvironment::SetUp() called. @@ -506,6 +506,35 @@ Failed Expected non-fatal failure. [ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads +[----------] 2 tests from ExpectFailureWithThreadsTest +[ RUN ] ExpectFailureWithThreadsTest.ExpectFatalFailure +(expecting 2 failures) +gtest_output_test_.cc:#: Failure +Failed +Expected fatal failure. +gtest.cc:#: Failure +Expected: 1 fatal failure + Actual: 0 failures +[ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure +[ RUN ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure +(expecting 2 failures) +gtest_output_test_.cc:#: Failure +Failed +Expected non-fatal failure. +gtest.cc:#: Failure +Expected: 1 non-fatal failure + Actual: 0 failures +[ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure +[----------] 1 test from ScopedFakeTestPartResultReporterTest +[ RUN ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread +(expecting 2 failures) +gtest_output_test_.cc:#: Failure +Failed +Expected fatal failure. +gtest_output_test_.cc:#: Failure +Failed +Expected non-fatal failure. +[ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread [----------] Global test environment tear-down BarEnvironment::TearDown() called. gtest_output_test_.cc:#: Failure @@ -515,9 +544,9 @@ FooEnvironment::TearDown() called. gtest_output_test_.cc:#: Failure Failed Expected fatal failure. -[==========] 56 tests from 23 test cases ran. +[==========] 59 tests from 25 test cases ran. [ PASSED ] 21 tests. -[ FAILED ] 35 tests, listed below: +[ FAILED ] 38 tests, listed below: [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine @@ -553,8 +582,11 @@ Expected fatal failure. [ FAILED ] ExpectFailureTest.ExpectNonFatalFailure [ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads [ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads +[ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure +[ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure +[ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread -35 FAILED TESTS +38 FAILED TESTS  YOU HAVE 1 DISABLED TEST Note: Google Test filter = FatalFailureTest.*:LoggingTest.* diff --git a/test/gtest_stress_test.cc b/test/gtest_stress_test.cc index 75d6268..3cb68de 100644 --- a/test/gtest_stress_test.cc +++ b/test/gtest_stress_test.cc @@ -48,23 +48,17 @@ namespace testing { namespace { +using internal::scoped_ptr; using internal::String; using internal::TestPropertyKeyIs; using internal::Vector; +using internal::ThreadStartSemaphore; +using internal::ThreadWithParam; // In order to run tests in this file, for platforms where Google Test is -// thread safe, implement ThreadWithParam with the following interface: -// -// template class ThreadWithParam { -// public: -// // Creates the thread. The thread should execute thread_func(param) when -// // started by a call to Start(). -// ThreadWithParam(void (*thread_func)(T), T param); -// // Starts the thread. -// void Start(); -// // Waits for the thread to finish. -// void Join(); -// }; +// thread safe, implement ThreadWithParam and ThreadStartSemaphore. See the +// description of their API in gtest-port.h, where they are defined for +// already supported platforms. // How many threads to create? const int kThreadCount = 50; @@ -132,22 +126,17 @@ void CheckTestFailureCount(int expected_failures) { // Tests using SCOPED_TRACE() and Google Test assertions in many threads // concurrently. TEST(StressTest, CanUseScopedTraceAndAssertionsInManyThreads) { - ThreadWithParam* threads[kThreadCount] = {}; - for (int i = 0; i != kThreadCount; i++) { - // Creates a thread to run the ManyAsserts() function. - threads[i] = new ThreadWithParam(&ManyAsserts, i); - - // Starts the thread. - threads[i]->Start(); - } + { + scoped_ptr > threads[kThreadCount]; + ThreadStartSemaphore semaphore; + for (int i = 0; i != kThreadCount; i++) + threads[i].reset(new ThreadWithParam(&ManyAsserts, i, &semaphore)); - // At this point, we have many threads running. + semaphore.Signal(); // Starts all the threads. - for (int i = 0; i != kThreadCount; i++) { - // We block until the thread is done. - threads[i]->Join(); - delete threads[i]; - threads[i] = NULL; + // Blocks until all the threads are done. + for (int i = 0; i != kThreadCount; i++) + threads[i]->Join(); } // Ensures that kThreadCount*kThreadCount failures have been reported. @@ -180,8 +169,7 @@ void FailingThread(bool is_fatal) { } void GenerateFatalFailureInAnotherThread(bool is_fatal) { - ThreadWithParam thread(&FailingThread, is_fatal); - thread.Start(); + ThreadWithParam thread(&FailingThread, is_fatal, NULL); thread.Join(); } diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index 55313e3..071301e 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -174,7 +174,6 @@ using testing::internal::StreamableToString; using testing::internal::String; using testing::internal::TestEventListenersAccessor; using testing::internal::TestResultAccessor; -using testing::internal::ThreadLocal; using testing::internal::UInt32; using testing::internal::Vector; using testing::internal::WideStringToUtf8; @@ -6577,23 +6576,6 @@ TEST(StaticAssertTypeEqTest, CompilesForEqualTypes) { StaticAssertTypeEq(); } -TEST(ThreadLocalTest, DefaultConstructor) { - ThreadLocal t1; - EXPECT_EQ(0, t1.get()); - - ThreadLocal t2; - EXPECT_TRUE(t2.get() == NULL); -} - -TEST(ThreadLocalTest, Init) { - ThreadLocal t1(123); - EXPECT_EQ(123, t1.get()); - - int i = 0; - ThreadLocal t2(&i); - EXPECT_EQ(&i, t2.get()); -} - TEST(GetCurrentOsStackTraceExceptTopTest, ReturnsTheStackTrace) { testing::UnitTest* const unit_test = testing::UnitTest::GetInstance(); -- cgit v0.12