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:
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user