aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-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
7 files changed, 285 insertions, 57 deletions
diff --git a/test/gtest-death-test_test.cc b/test/gtest-death-test_test.cc
index 1c7fa474..127b7ffc 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 3576c2b8..8594aa97 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 c99358aa..3fb61812 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 a0aa64fd..4374a96e 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 51bae52d..4d67bd62 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 75d6268e..3cb68de8 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 55313e36..071301ea 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();