diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/gtest-death-test_test.cc | 4 | ||||
-rw-r--r-- | test/gtest-port_test.cc | 223 | ||||
-rw-r--r-- | test/gtest_dll_test_.cc | 5 | ||||
-rwxr-xr-x | test/gtest_output_test.py | 8 | ||||
-rw-r--r-- | test/gtest_output_test_golden_lin.txt | 40 | ||||
-rw-r--r-- | test/gtest_stress_test.cc | 44 | ||||
-rw-r--r-- | test/gtest_unittest.cc | 18 |
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 -[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.* 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(); |