summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2010-02-24 17:19:25 +0000
committerzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2010-02-24 17:19:25 +0000
commit050a520ddf9a34b93a3b41704fa2450d7450783f (patch)
treec91cb1205fb45e4a96889ae478afa66a0559694c
parent6851df92502ee6b9b96f008ae66e676f9565fc46 (diff)
downloadgoogletest-050a520ddf9a34b93a3b41704fa2450d7450783f.tar.gz
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).
git-svn-id: http://googletest.googlecode.com/svn/trunk@376 861a406c-534a-0410-8894-cb66d6ee9925
-rw-r--r--CHANGES21
-rw-r--r--CMakeLists.txt16
-rw-r--r--Makefile.am60
-rw-r--r--configure.ac22
-rw-r--r--include/gtest/internal/gtest-linked_ptr.h2
-rw-r--r--include/gtest/internal/gtest-port.h326
-rw-r--r--msvc/gtest.def1
-rw-r--r--scons/SConscript19
-rw-r--r--scons/SConscript.common1
-rw-r--r--scons/SConstruct.common2
-rwxr-xr-xscripts/gtest-config.in8
-rw-r--r--src/gtest-internal-inl.h5
-rw-r--r--src/gtest-port.cc88
-rw-r--r--src/gtest.cc2
-rw-r--r--test/gtest-death-test_test.cc4
-rw-r--r--test/gtest-port_test.cc223
-rw-r--r--test/gtest_dll_test_.cc5
-rwxr-xr-xtest/gtest_output_test.py8
-rw-r--r--test/gtest_output_test_golden_lin.txt40
-rw-r--r--test/gtest_stress_test.cc44
-rw-r--r--test/gtest_unittest.cc18
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 <pthread.h> 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<String>& GetArgvs();
// Defines synchronization primitives.
+#if GTEST_HAS_PTHREAD
+
+// gtest-port.h guarantees to #include <pthread.h> when GTEST_HAS_PTHREAD is
+// true.
+#include <pthread.h>
+
+// 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<int> 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 <typename T>
+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<T*>(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<T*>(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<int> 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 <typename T>
+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<ThreadWithParam<T>*>(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<String>& 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 <windows.h> // For DWORD.
#endif // GTEST_OS_WINDOWS
-#include <gtest/gtest.h>
+#include <gtest/gtest.h> // NOLINT
#include <gtest/gtest-spi.h>
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 <stdio.h>
+#if GTEST_HAS_PTHREAD
+#include <unistd.h> // For nanosleep().
+#endif // GTEST_HAS_PTHREAD
+
#if GTEST_OS_MAC
-#include <pthread.h>
#include <time.h>
#endif // GTEST_OS_MAC
+#include <utility> // For std::pair and std::make_pair.
+
#include <gtest/gtest.h>
#include <gtest/gtest-spi.h>
@@ -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<pthread_mutex_t*>(data);
+ pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(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<int> t1;
+ EXPECT_EQ(0, t1.get());
+
+ ThreadLocal<void*> t2;
+ EXPECT_TRUE(t2.get() == NULL);
+}
+
+TEST(ThreadLocalTest, SingleParamConstructorInitializesToParam) {
+ ThreadLocal<int> t1(123);
+ EXPECT_EQ(123, t1.get());
+
+ int i = 0;
+ ThreadLocal<int*> t2(&i);
+ EXPECT_EQ(&i, t2.get());
+}
+
+class NoCopyConstructor {
+ public:
+ NoCopyConstructor() {}
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(NoCopyConstructor);
+};
+
+TEST(ThreadLocalTest, ValueCopyConstructorIsNotRequiredForDefaultVersion) {
+ ThreadLocal<NoCopyConstructor> bar;
+ bar.get();
+}
+
+class NoDefaultContructor {
+ public:
+ explicit NoDefaultContructor(const char*) {}
+ NoDefaultContructor(const NoDefaultContructor&) {}
+};
+
+TEST(ThreadLocalTest, ValueDefaultContructorIsNotRequiredForParamVersion) {
+ ThreadLocal<NoDefaultContructor> bar(NoDefaultContructor("foo"));
+ bar.pointer();
+}
+
+TEST(ThreadLocalTest, GetAndPointerReturnSameValue) {
+ ThreadLocal<String> 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<String> thread_local;
+ const ThreadLocal<String>& 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<useconds_t>(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<AtomicCounterWithMutex*, int> 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<pair<AtomicCounterWithMutex*, int> > ThreadType;
+ const int kCycleCount = 20;
+ const int kThreadCount = 7;
+ scoped_ptr<ThreadType> 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 <typename T>
+void RunFromThread(void (func)(T), T param) {
+ ThreadWithParam<T> thread(func, param, NULL);
+ thread.Join();
+}
+
+void RetrieveThreadLocalValue(pair<ThreadLocal<String>*, String*> param) {
+ *param.second = param.first->get();
+}
+
+TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) {
+ ThreadLocal<String> 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 <typename T>
+void CallThreadLocalGet(ThreadLocal<T>* threadLocal) {
+ threadLocal->get();
+}
+
+TEST(ThreadLocalTest, DestroysManagedObjectsNoLaterThanSelf) {
+ CountedDestructor::set_counter(0);
+ {
+ ThreadLocal<CountedDestructor> thread_local;
+ ThreadWithParam<ThreadLocal<CountedDestructor>*> thread(
+ &CallThreadLocalGet<CountedDestructor>, &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<String> 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 <typename T> 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<int>* threads[kThreadCount] = {};
- for (int i = 0; i != kThreadCount; i++) {
- // Creates a thread to run the ManyAsserts() function.
- threads[i] = new ThreadWithParam<int>(&ManyAsserts, i);
-
- // Starts the thread.
- threads[i]->Start();
- }
+ {
+ scoped_ptr<ThreadWithParam<int> > threads[kThreadCount];
+ ThreadStartSemaphore semaphore;
+ for (int i = 0; i != kThreadCount; i++)
+ threads[i].reset(new ThreadWithParam<int>(&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<bool> thread(&FailingThread, is_fatal);
- thread.Start();
+ ThreadWithParam<bool> 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<int*, IntAlias*>();
}
-TEST(ThreadLocalTest, DefaultConstructor) {
- ThreadLocal<int> t1;
- EXPECT_EQ(0, t1.get());
-
- ThreadLocal<void*> t2;
- EXPECT_TRUE(t2.get() == NULL);
-}
-
-TEST(ThreadLocalTest, Init) {
- ThreadLocal<int> t1(123);
- EXPECT_EQ(123, t1.get());
-
- int i = 0;
- ThreadLocal<int*> t2(&i);
- EXPECT_EQ(&i, t2.get());
-}
-
TEST(GetCurrentOsStackTraceExceptTopTest, ReturnsTheStackTrace) {
testing::UnitTest* const unit_test = testing::UnitTest::GetInstance();