mirror of
https://github.com/google/googletest.git
synced 2025-01-15 00:47:54 +08:00
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).
This commit is contained in:
parent
dd280cfa8d
commit
3bef459eac
21
CHANGES
21
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
|
||||
|
@ -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)
|
||||
|
||||
|
60
Makefile.am
60
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"
|
||||
|
22
configure.ac
22
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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -7,7 +7,7 @@ Expected: true
|
||||
gtest_output_test_.cc:#: Failure
|
||||
Value of: 3
|
||||
Expected: 2
|
||||
[0;32m[==========] [mRunning 56 tests from 23 test cases.
|
||||
[0;32m[==========] [mRunning 59 tests from 25 test cases.
|
||||
[0;32m[----------] [mGlobal test environment set-up.
|
||||
FooEnvironment::SetUp() called.
|
||||
BarEnvironment::SetUp() called.
|
||||
@ -506,6 +506,35 @@ Failed
|
||||
Expected non-fatal failure.
|
||||
|
||||
[0;31m[ FAILED ] [mExpectFailureTest.ExpectNonFatalFailureOnAllThreads
|
||||
[0;32m[----------] [m2 tests from ExpectFailureWithThreadsTest
|
||||
[0;32m[ RUN ] [mExpectFailureWithThreadsTest.ExpectFatalFailure
|
||||
(expecting 2 failures)
|
||||
gtest_output_test_.cc:#: Failure
|
||||
Failed
|
||||
Expected fatal failure.
|
||||
gtest.cc:#: Failure
|
||||
Expected: 1 fatal failure
|
||||
Actual: 0 failures
|
||||
[0;31m[ FAILED ] [mExpectFailureWithThreadsTest.ExpectFatalFailure
|
||||
[0;32m[ RUN ] [mExpectFailureWithThreadsTest.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
|
||||
[0;31m[ FAILED ] [mExpectFailureWithThreadsTest.ExpectNonFatalFailure
|
||||
[0;32m[----------] [m1 test from ScopedFakeTestPartResultReporterTest
|
||||
[0;32m[ RUN ] [mScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread
|
||||
(expecting 2 failures)
|
||||
gtest_output_test_.cc:#: Failure
|
||||
Failed
|
||||
Expected fatal failure.
|
||||
gtest_output_test_.cc:#: Failure
|
||||
Failed
|
||||
Expected non-fatal failure.
|
||||
[0;31m[ FAILED ] [mScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread
|
||||
[0;32m[----------] [mGlobal 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.
|
||||
[0;32m[==========] [m56 tests from 23 test cases ran.
|
||||
[0;32m[==========] [m59 tests from 25 test cases ran.
|
||||
[0;32m[ PASSED ] [m21 tests.
|
||||
[0;31m[ FAILED ] [m35 tests, listed below:
|
||||
[0;31m[ FAILED ] [m38 tests, listed below:
|
||||
[0;31m[ FAILED ] [mFatalFailureTest.FatalFailureInSubroutine
|
||||
[0;31m[ FAILED ] [mFatalFailureTest.FatalFailureInNestedSubroutine
|
||||
[0;31m[ FAILED ] [mFatalFailureTest.NonfatalFailureInSubroutine
|
||||
@ -553,8 +582,11 @@ Expected fatal failure.
|
||||
[0;31m[ FAILED ] [mExpectFailureTest.ExpectNonFatalFailure
|
||||
[0;31m[ FAILED ] [mExpectFailureTest.ExpectFatalFailureOnAllThreads
|
||||
[0;31m[ FAILED ] [mExpectFailureTest.ExpectNonFatalFailureOnAllThreads
|
||||
[0;31m[ FAILED ] [mExpectFailureWithThreadsTest.ExpectFatalFailure
|
||||
[0;31m[ FAILED ] [mExpectFailureWithThreadsTest.ExpectNonFatalFailure
|
||||
[0;31m[ FAILED ] [mScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread
|
||||
|
||||
35 FAILED TESTS
|
||||
38 FAILED TESTS
|
||||
[0;33m YOU HAVE 1 DISABLED TEST
|
||||
|
||||
[mNote: Google Test filter = FatalFailureTest.*:LoggingTest.*
|
||||
|
@ -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);
|
||||
{
|
||||
scoped_ptr<ThreadWithParam<int> > threads[kThreadCount];
|
||||
ThreadStartSemaphore semaphore;
|
||||
for (int i = 0; i != kThreadCount; i++)
|
||||
threads[i].reset(new ThreadWithParam<int>(&ManyAsserts, i, &semaphore));
|
||||
|
||||
// Starts the thread.
|
||||
threads[i]->Start();
|
||||
}
|
||||
semaphore.Signal(); // Starts all the threads.
|
||||
|
||||
// At this point, we have many threads running.
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user