diff options
author | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2010-03-04 22:15:53 (GMT) |
---|---|---|
committer | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2010-03-04 22:15:53 (GMT) |
commit | 12a92c26fc0e0de81f687dbe739a6aa24f37f9dd (patch) | |
tree | 9a7a9aac24a5946d5bca4e04ec681ecd38b6199c /test | |
parent | 0928f00c6b995af037b787b710fde509267ad624 (diff) | |
download | googletest-12a92c26fc0e0de81f687dbe739a6aa24f37f9dd.zip googletest-12a92c26fc0e0de81f687dbe739a6aa24f37f9dd.tar.gz googletest-12a92c26fc0e0de81f687dbe739a6aa24f37f9dd.tar.bz2 |
Renames ThreadStartSempahore to Notificaton (by Vlad Losev); adds threading tests for SCOPED_TRACE() (by Vlad Losev); replaces native pthread calls with gtest's threading constructs (by Vlad Losev); fixes flakiness in CountedDestructor (by Vlad Losev); minor MSVC 7.1 clean-up (by Zhanyong Wan).
Diffstat (limited to 'test')
-rw-r--r-- | test/gtest-port_test.cc | 50 | ||||
-rw-r--r-- | test/gtest-typed-test_test.cc | 12 | ||||
-rwxr-xr-x | test/gtest_output_test.py | 4 | ||||
-rw-r--r-- | test/gtest_output_test_.cc | 162 | ||||
-rw-r--r-- | test/gtest_output_test_golden_lin.txt | 40 | ||||
-rw-r--r-- | test/gtest_stress_test.cc | 17 | ||||
-rw-r--r-- | test/gtest_unittest.cc | 31 |
7 files changed, 239 insertions, 77 deletions
diff --git a/test/gtest-port_test.cc b/test/gtest-port_test.cc index 357a99e..1588bd4 100644 --- a/test/gtest-port_test.cc +++ b/test/gtest-port_test.cc @@ -803,7 +803,7 @@ TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) { { MutexLock lock(&m); } m.AssertHeld(); }, - "The current thread is not holding the mutex @.+"); + "thread .*hold"); } TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) { @@ -859,16 +859,16 @@ TEST(MutexTest, OnlyOneThreadCanLockAtATime) { const int kCycleCount = 20; const int kThreadCount = 7; scoped_ptr<ThreadType> counting_threads[kThreadCount]; - ThreadStartSemaphore semaphore; + Notification threads_can_start; // 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)); + &threads_can_start)); } - semaphore.Signal(); // Starts the threads. + threads_can_start.Notify(); for (int i = 0; i < kThreadCount; ++i) counting_threads[i]->Join(); @@ -901,16 +901,29 @@ TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) { EXPECT_STREQ("foo", result.c_str()); } -class CountedDestructor { +// DestructorTracker keeps track of whether the class instances have been +// destroyed. The static synchronization mutex has to be defined outside +// of the class, due to syntax of its definition. +static GTEST_DEFINE_STATIC_MUTEX_(destructor_tracker_mutex); + +static std::vector<bool> g_destroyed; + +class DestructorTracker { public: - ~CountedDestructor() { counter_++; } - static int counter() { return counter_; } - static void set_counter(int value) { counter_ = value; } + DestructorTracker() : index_(GetNewIndex()) {} + ~DestructorTracker() { + MutexLock lock(&destructor_tracker_mutex); + g_destroyed[index_] = true; + } private: - static int counter_; + static int GetNewIndex() { + MutexLock lock(&destructor_tracker_mutex); + g_destroyed.push_back(false); + return g_destroyed.size() - 1; + } + const int index_; }; -int CountedDestructor::counter_ = 0; template <typename T> void CallThreadLocalGet(ThreadLocal<T>* threadLocal) { @@ -918,16 +931,19 @@ void CallThreadLocalGet(ThreadLocal<T>* threadLocal) { } TEST(ThreadLocalTest, DestroysManagedObjectsNoLaterThanSelf) { - CountedDestructor::set_counter(0); + g_destroyed.clear(); { - ThreadLocal<CountedDestructor> thread_local; - ThreadWithParam<ThreadLocal<CountedDestructor>*> thread( - &CallThreadLocalGet<CountedDestructor>, &thread_local, NULL); + ThreadLocal<DestructorTracker> thread_local; + ThreadWithParam<ThreadLocal<DestructorTracker>*> thread( + &CallThreadLocalGet<DestructorTracker>, &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()); + // Verifies that all DestructorTracker objects there were have been + // destroyed. + for (size_t i = 0; i < g_destroyed.size(); ++i) + EXPECT_TRUE(g_destroyed[i]) << "at index " << i; + + g_destroyed.clear(); } TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) { diff --git a/test/gtest-typed-test_test.cc b/test/gtest-typed-test_test.cc index 4b6e971..f2c3972 100644 --- a/test/gtest-typed-test_test.cc +++ b/test/gtest-typed-test_test.cc @@ -349,12 +349,12 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, NumericTest, NumericTypes); #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P) -// Google Test doesn't support type-parameterized tests on some platforms -// and compilers, such as MSVC 7.1. If we use conditional compilation to -// compile out all code referring to the gtest_main library, MSVC linker -// will not link that library at all and consequently complain about -// missing entry point defined in that library (fatal error LNK1561: -// entry point must be defined). This dummy test keeps gtest_main linked in. +// Google Test may not support type-parameterized tests with some +// compilers. If we use conditional compilation to compile out all +// code referring to the gtest_main library, MSVC linker will not link +// that library at all and consequently complain about missing entry +// point defined in that library (fatal error LNK1561: entry point +// must be defined). This dummy test keeps gtest_main linked in. TEST(DummyTest, TypedTestsAreNotSupportedOnThisPlatform) {} #endif // #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P) diff --git a/test/gtest_output_test.py b/test/gtest_output_test.py index 125970a..192030a 100755 --- a/test/gtest_output_test.py +++ b/test/gtest_output_test.py @@ -282,7 +282,7 @@ class GTestOutputTest(gtest_test_utils.TestCase): normalized_golden = RemoveTypeInfoDetails(golden) if CAN_GENERATE_GOLDEN_FILE: - self.assert_(normalized_golden == normalized_actual) + self.assertEqual(normalized_golden, normalized_actual) else: normalized_actual = RemoveTestCounts(normalized_actual) normalized_golden = RemoveTestCounts(self.RemoveUnsupportedTests( @@ -299,7 +299,7 @@ class GTestOutputTest(gtest_test_utils.TestCase): '_gtest_output_test_normalized_golden.txt'), 'wb').write( normalized_golden) - self.assert_(normalized_golden == normalized_actual) + self.assertEqual(normalized_golden, normalized_actual) if __name__ == '__main__': diff --git a/test/gtest_output_test_.cc b/test/gtest_output_test_.cc index 6d75602..273e8e9 100644 --- a/test/gtest_output_test_.cc +++ b/test/gtest_output_test_.cc @@ -46,15 +46,17 @@ #include <stdlib.h> -#if GTEST_HAS_PTHREAD -#include <pthread.h> -#endif // GTEST_HAS_PTHREAD - +#if GTEST_IS_THREADSAFE using testing::ScopedFakeTestPartResultReporter; using testing::TestPartResultArray; +using testing::internal::Notification; +using testing::internal::ThreadWithParam; +#endif + namespace posix = ::testing::internal::posix; using testing::internal::String; +using testing::internal::scoped_ptr; // Tests catching fatal failures. @@ -214,6 +216,83 @@ TEST(SCOPED_TRACETest, CanBeRepeated) { << "trace point A, B, and D."; } +#if GTEST_IS_THREADSAFE +// Tests that SCOPED_TRACE()s can be used concurrently from multiple +// threads. Namely, an assertion should be affected by +// SCOPED_TRACE()s in its own thread only. + +// Here's the sequence of actions that happen in the test: +// +// Thread A (main) | Thread B (spawned) +// ===============================|================================ +// spawns thread B | +// -------------------------------+-------------------------------- +// waits for n1 | SCOPED_TRACE("Trace B"); +// | generates failure #1 +// | notifies n1 +// -------------------------------+-------------------------------- +// SCOPED_TRACE("Trace A"); | waits for n2 +// generates failure #2 | +// notifies n2 | +// -------------------------------|-------------------------------- +// waits for n3 | generates failure #3 +// | trace B dies +// | generates failure #4 +// | notifies n3 +// -------------------------------|-------------------------------- +// generates failure #5 | finishes +// trace A dies | +// generates failure #6 | +// -------------------------------|-------------------------------- +// waits for thread B to finish | + +struct CheckPoints { + Notification n1; + Notification n2; + Notification n3; +}; + +static void ThreadWithScopedTrace(CheckPoints* check_points) { + { + SCOPED_TRACE("Trace B"); + ADD_FAILURE() + << "Expected failure #1 (in thread B, only trace B alive)."; + check_points->n1.Notify(); + check_points->n2.WaitForNotification(); + + ADD_FAILURE() + << "Expected failure #3 (in thread B, trace A & B both alive)."; + } // Trace B dies here. + ADD_FAILURE() + << "Expected failure #4 (in thread B, only trace A alive)."; + check_points->n3.Notify(); +} + +TEST(SCOPED_TRACETest, WorksConcurrently) { + printf("(expecting 6 failures)\n"); + + CheckPoints check_points; + ThreadWithParam<CheckPoints*> thread(&ThreadWithScopedTrace, + &check_points, + NULL); + check_points.n1.WaitForNotification(); + + { + SCOPED_TRACE("Trace A"); + ADD_FAILURE() + << "Expected failure #2 (in thread A, trace A & B both alive)."; + check_points.n2.Notify(); + check_points.n3.WaitForNotification(); + + ADD_FAILURE() + << "Expected failure #5 (in thread A, only trace A alive)."; + } // Trace A dies here. + ADD_FAILURE() + << "Expected failure #6 (in thread A, no trace alive)."; + thread.Join(); +} +#endif // GTEST_IS_THREADSAFE + TEST(DisabledTestsWarningTest, DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning) { // This test body is intentionally empty. Its sole purpose is for @@ -479,6 +558,63 @@ TEST_F(ExceptionInTearDownTest, ExceptionInTearDown) { #endif // GTEST_OS_WINDOWS +#if GTEST_IS_THREADSAFE + +// A unary function that may die. +void DieIf(bool should_die) { + GTEST_CHECK_(!should_die) << " - death inside DieIf()."; +} + +// Tests running death tests in a multi-threaded context. + +// Used for coordination between the main and the spawn thread. +struct SpawnThreadNotifications { + SpawnThreadNotifications() {} + + Notification spawn_thread_started; + Notification spawn_thread_ok_to_terminate; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(SpawnThreadNotifications); +}; + +// The function to be executed in the thread spawn by the +// MultipleThreads test (below). +static void ThreadRoutine(SpawnThreadNotifications* notifications) { + // Signals the main thread that this thread has started. + notifications->spawn_thread_started.Notify(); + + // Waits for permission to finish from the main thread. + notifications->spawn_thread_ok_to_terminate.WaitForNotification(); +} + +// This is a death-test test, but it's not named with a DeathTest +// suffix. It starts threads which might interfere with later +// death tests, so it must run after all other death tests. +class DeathTestAndMultiThreadsTest : public testing::Test { + protected: + // Starts a thread and waits for it to begin. + virtual void SetUp() { + thread_.reset(new ThreadWithParam<SpawnThreadNotifications*>( + &ThreadRoutine, ¬ifications_, NULL)); + notifications_.spawn_thread_started.WaitForNotification(); + } + // Tells the thread to finish, and reaps it. + // Depending on the version of the thread library in use, + // a manager thread might still be left running that will interfere + // with later death tests. This is unfortunate, but this class + // cleans up after itself as best it can. + virtual void TearDown() { + notifications_.spawn_thread_ok_to_terminate.Notify(); + } + + private: + SpawnThreadNotifications notifications_; + scoped_ptr<ThreadWithParam<SpawnThreadNotifications*> > thread_; +}; + +#endif // GTEST_IS_THREADSAFE + // The MixedUpTestCaseTest test case verifies that Google Test will fail a // test if it uses a different fixture class than what other tests in // the same test case use. It deliberately contains two fixture @@ -849,23 +985,13 @@ TEST_F(ExpectFailureTest, ExpectNonFatalFailure) { "failure."); } -#if GTEST_IS_THREADSAFE && GTEST_HAS_PTHREAD +#if GTEST_IS_THREADSAFE class ExpectFailureWithThreadsTest : public ExpectFailureTest { protected: static void AddFailureInOtherThread(FailureMode failure) { - pthread_t tid; - pthread_create(&tid, - NULL, - ExpectFailureWithThreadsTest::FailureThread, - &failure); - pthread_join(tid, NULL); - } - private: - static void* FailureThread(void* attr) { - FailureMode* failure = static_cast<FailureMode*>(attr); - AddFailure(*failure); - return NULL; + ThreadWithParam<FailureMode> thread(&AddFailure, failure, NULL); + thread.Join(); } }; @@ -901,7 +1027,7 @@ TEST_F(ScopedFakeTestPartResultReporterTest, InterceptOnlyCurrentThread) { EXPECT_EQ(0, results.size()) << "This shouldn't fail."; } -#endif // GTEST_IS_THREADSAFE && GTEST_HAS_PTHREAD +#endif // GTEST_IS_THREADSAFE TEST_F(ExpectFailureTest, ExpectFatalFailureOnAllThreads) { // Expected fatal failure, but succeeds. diff --git a/test/gtest_output_test_golden_lin.txt b/test/gtest_output_test_golden_lin.txt index 4d67bd6..ec60437 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 59 tests from 25 test cases. +[0;32m[==========] [mRunning 60 tests from 25 test cases. [0;32m[----------] [mGlobal test environment set-up. FooEnvironment::SetUp() called. BarEnvironment::SetUp() called. @@ -65,7 +65,7 @@ i == 3 gtest_output_test_.cc:#: Failure Expected: (3) >= (a[i]), actual: 3 vs 6 [0;31m[ FAILED ] [mLoggingTest.InterleavingLoggingAndAssertions -[0;32m[----------] [m5 tests from SCOPED_TRACETest +[0;32m[----------] [m6 tests from SCOPED_TRACETest [0;32m[ RUN ] [mSCOPED_TRACETest.ObeysScopes (expected to fail) gtest_output_test_.cc:#: Failure @@ -148,6 +148,35 @@ gtest_output_test_.cc:#: D gtest_output_test_.cc:#: B gtest_output_test_.cc:#: A [0;31m[ FAILED ] [mSCOPED_TRACETest.CanBeRepeated +[0;32m[ RUN ] [mSCOPED_TRACETest.WorksConcurrently +(expecting 6 failures) +gtest_output_test_.cc:#: Failure +Failed +Expected failure #1 (in thread B, only trace B alive). +Google Test trace: +gtest_output_test_.cc:#: Trace B +gtest_output_test_.cc:#: Failure +Failed +Expected failure #2 (in thread A, trace A & B both alive). +Google Test trace: +gtest_output_test_.cc:#: Trace A +gtest_output_test_.cc:#: Failure +Failed +Expected failure #3 (in thread B, trace A & B both alive). +Google Test trace: +gtest_output_test_.cc:#: Trace B +gtest_output_test_.cc:#: Failure +Failed +Expected failure #4 (in thread B, only trace A alive). +gtest_output_test_.cc:#: Failure +Failed +Expected failure #5 (in thread A, only trace A alive). +Google Test trace: +gtest_output_test_.cc:#: Trace A +gtest_output_test_.cc:#: Failure +Failed +Expected failure #6 (in thread A, no trace alive). +[0;31m[ FAILED ] [mSCOPED_TRACETest.WorksConcurrently [0;32m[----------] [m1 test from NonFatalFailureInFixtureConstructorTest [0;32m[ RUN ] [mNonFatalFailureInFixtureConstructorTest.FailureInConstructor (expecting 5 failures) @@ -544,9 +573,9 @@ FooEnvironment::TearDown() called. gtest_output_test_.cc:#: Failure Failed Expected fatal failure. -[0;32m[==========] [m59 tests from 25 test cases ran. +[0;32m[==========] [m60 tests from 25 test cases ran. [0;32m[ PASSED ] [m21 tests. -[0;31m[ FAILED ] [m38 tests, listed below: +[0;31m[ FAILED ] [m39 tests, listed below: [0;31m[ FAILED ] [mFatalFailureTest.FatalFailureInSubroutine [0;31m[ FAILED ] [mFatalFailureTest.FatalFailureInNestedSubroutine [0;31m[ FAILED ] [mFatalFailureTest.NonfatalFailureInSubroutine @@ -556,6 +585,7 @@ Expected fatal failure. [0;31m[ FAILED ] [mSCOPED_TRACETest.WorksInSubroutine [0;31m[ FAILED ] [mSCOPED_TRACETest.CanBeNested [0;31m[ FAILED ] [mSCOPED_TRACETest.CanBeRepeated +[0;31m[ FAILED ] [mSCOPED_TRACETest.WorksConcurrently [0;31m[ FAILED ] [mNonFatalFailureInFixtureConstructorTest.FailureInConstructor [0;31m[ FAILED ] [mFatalFailureInFixtureConstructorTest.FailureInConstructor [0;31m[ FAILED ] [mNonFatalFailureInSetUpTest.FailureInSetUp @@ -586,7 +616,7 @@ Expected fatal failure. [0;31m[ FAILED ] [mExpectFailureWithThreadsTest.ExpectNonFatalFailure [0;31m[ FAILED ] [mScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread -38 FAILED TESTS +39 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 01f4fc6..f5af78c 100644 --- a/test/gtest_stress_test.cc +++ b/test/gtest_stress_test.cc @@ -49,16 +49,15 @@ namespace testing { namespace { -using internal::scoped_ptr; +using internal::Notification; using internal::String; using internal::TestPropertyKeyIs; -using internal::ThreadStartSemaphore; using internal::ThreadWithParam; +using internal::scoped_ptr; // In order to run tests in this file, for platforms where Google Test is -// thread safe, implement ThreadWithParam and ThreadStartSemaphore. See the -// description of their API in gtest-port.h, where they are defined for -// already supported platforms. +// thread safe, implement ThreadWithParam. See the description of its API +// in gtest-port.h, where it is defined for already supported platforms. // How many threads to create? const int kThreadCount = 50; @@ -129,11 +128,13 @@ void CheckTestFailureCount(int expected_failures) { TEST(StressTest, CanUseScopedTraceAndAssertionsInManyThreads) { { scoped_ptr<ThreadWithParam<int> > threads[kThreadCount]; - ThreadStartSemaphore semaphore; + Notification threads_can_start; for (int i = 0; i != kThreadCount; i++) - threads[i].reset(new ThreadWithParam<int>(&ManyAsserts, i, &semaphore)); + threads[i].reset(new ThreadWithParam<int>(&ManyAsserts, + i, + &threads_can_start)); - semaphore.Signal(); // Starts all the threads. + threads_can_start.Notify(); // Blocks until all the threads are done. for (int i = 0; i != kThreadCount; i++) diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index bc190e1..d5a6f30 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -71,10 +71,6 @@ TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded) { #include <stdlib.h> #include <time.h> -#if GTEST_HAS_PTHREAD -#include <pthread.h> -#endif // GTEST_HAS_PTHREAD - #include <map> namespace testing { @@ -191,6 +187,10 @@ using testing::internal::CaptureStdout; using testing::internal::GetCapturedStdout; #endif // GTEST_HAS_STREAM_REDIRECTION_ +#if GTEST_IS_THREADSAFE +using testing::internal::ThreadWithParam; +#endif + class TestingVector : public std::vector<int> { }; @@ -1283,25 +1283,14 @@ TEST_F(ScopedFakeTestPartResultReporterTest, DeprecatedConstructor) { EXPECT_EQ(1, results.size()); } -#if GTEST_IS_THREADSAFE && GTEST_HAS_PTHREAD +#if GTEST_IS_THREADSAFE class ScopedFakeTestPartResultReporterWithThreadsTest : public ScopedFakeTestPartResultReporterTest { protected: static void AddFailureInOtherThread(FailureMode failure) { - pthread_t tid; - pthread_create(&tid, - NULL, - ScopedFakeTestPartResultReporterWithThreadsTest:: - FailureThread, - &failure); - pthread_join(tid, NULL); - } - private: - static void* FailureThread(void* attr) { - FailureMode* failure = static_cast<FailureMode*>(attr); - AddFailure(*failure); - return NULL; + ThreadWithParam<FailureMode> thread(&AddFailure, failure, NULL); + thread.Join(); } }; @@ -1324,7 +1313,7 @@ TEST_F(ScopedFakeTestPartResultReporterWithThreadsTest, EXPECT_TRUE(results.GetTestPartResult(3).fatally_failed()); } -#endif // GTEST_IS_THREADSAFE && GTEST_HAS_PTHREAD +#endif // GTEST_IS_THREADSAFE // Tests EXPECT_FATAL_FAILURE{,ON_ALL_THREADS}. Makes sure that they // work even if the failure is generated in a called function rather than @@ -1435,7 +1424,7 @@ TEST_F(ExpectNonfatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma) { }, ""); } -#if GTEST_IS_THREADSAFE && GTEST_HAS_PTHREAD +#if GTEST_IS_THREADSAFE typedef ScopedFakeTestPartResultReporterWithThreadsTest ExpectFailureWithThreadsTest; @@ -1450,7 +1439,7 @@ TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailureOnAllThreads) { AddFailureInOtherThread(NONFATAL_FAILURE), "Expected non-fatal failure."); } -#endif // GTEST_IS_THREADSAFE && GTEST_HAS_PTHREAD +#endif // GTEST_IS_THREADSAFE // Tests the TestProperty class. |