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:
zhanyong.wan
2010-02-24 17:19:25 +00:00
parent dd280cfa8d
commit 3bef459eac
21 changed files with 796 additions and 119 deletions

View File

@@ -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) {

View File

@@ -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

View File

@@ -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;

View File

@@ -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)

View File

@@ -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.*

View File

@@ -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();
}

View File

@@ -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();