From 12a92c26fc0e0de81f687dbe739a6aa24f37f9dd Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 4 Mar 2010 22:15:53 +0000 Subject: 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). --- include/gtest/internal/gtest-port.h | 183 +++++++++++++++++++--------------- include/gtest/internal/gtest-string.h | 13 ++- samples/sample7_unittest.cc | 12 +-- samples/sample8_unittest.cc | 12 +-- src/gtest-death-test.cc | 2 - test/gtest-port_test.cc | 50 ++++++---- test/gtest-typed-test_test.cc | 12 +-- test/gtest_output_test.py | 4 +- test/gtest_output_test_.cc | 162 ++++++++++++++++++++++++++---- test/gtest_output_test_golden_lin.txt | 40 +++++++- test/gtest_stress_test.cc | 17 ++-- test/gtest_unittest.cc | 31 ++---- 12 files changed, 359 insertions(+), 179 deletions(-) diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index 6910c7b..b1b9203 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -463,13 +463,10 @@ #include // NOLINT #endif -// Determines whether to support value-parameterized tests. - -#if defined(__GNUC__) || (_MSC_VER >= 1400) -// TODO(vladl@google.com): get the implementation rid of vector and list -// to compile on MSVC 7.1. +// We don't support MSVC 7.1 with exceptions disabled now. Therefore +// all the compilers we care about are adequate for supporting +// value-parameterized tests. #define GTEST_HAS_PARAM_TEST 1 -#endif // defined(__GNUC__) || (_MSC_VER >= 1400) // Determines whether to support type-driven tests. @@ -774,6 +771,97 @@ const ::std::vector& GetArgvs(); #if GTEST_HAS_PTHREAD +// Sleeps for (roughly) n milli-seconds. This function is only for +// testing Google Test's own constructs. Don't use it in user tests, +// either directly or indirectly. +inline void SleepMilliseconds(int n) { + const timespec time = { + 0, // 0 seconds. + n * 1000L * 1000L, // And n ms. + }; + nanosleep(&time, NULL); +} + +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class Notification { + public: + Notification() : notified_(false) {} + + // Notifies all threads created with this notification to start. Must + // be called from the controller thread. + void Notify() { notified_ = true; } + + // Blocks until the controller thread notifies. Must be called from a test + // thread. + void WaitForNotification() { + while(!notified_) { + SleepMilliseconds(10); + } + } + + private: + volatile bool notified_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; + +// Helper class for testing Google Test's multi-threading constructs. +// To use it, derive a class template ThreadWithParam from +// ThreadWithParamBase and implement thread creation and startup in +// the constructor and joining the thread in JoinUnderlyingThread(). +// Then you can write: +// +// void ThreadFunc(int param) { /* Do things with param */ } +// Notification thread_can_start; +// ... +// // The thread_can_start parameter is optional; you can supply NULL. +// ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); +// thread_can_start.Notify(); +// +// These classes are only for testing Google Test's own constructs. Do +// not use them in user tests, either directly or indirectly. +template +class ThreadWithParamBase { + public: + typedef void (*UserThreadFunc)(T); + + ThreadWithParamBase( + UserThreadFunc func, T param, Notification* thread_can_start) + : func_(func), + param_(param), + thread_can_start_(thread_can_start), + finished_(false) {} + virtual ~ThreadWithParamBase() {} + + void Join() { + if (!finished_) { + JoinUnderlyingThread(); + finished_ = true; + } + } + + virtual void JoinUnderlyingThread() = 0; + + void ThreadMain() { + if (thread_can_start_ != NULL) + thread_can_start_->WaitForNotification(); + func_(param_); + } + + protected: + const UserThreadFunc func_; // User-supplied thread function. + const T param_; // User-supplied parameter to the thread function. + // When non-NULL, used to block execution until the controller thread + // notifies. + Notification* const thread_can_start_; + bool finished_; // true iff we know that the thread function has finished. +}; + // gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is // true. #include @@ -936,99 +1024,32 @@ class ThreadLocal { GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; -// Sleeps for (roughly) n milli-seconds. This function is only for -// testing Google Test's own constructs. Don't use it in user tests, -// either directly or indirectly. -inline void SleepMilliseconds(int n) { - const timespec time = { - 0, // 0 seconds. - n * 1000L * 1000L, // And n ms. - }; - nanosleep(&time, NULL); -} - -// Allows a controller thread to pause execution of newly created -// threads until signalled. Instances of this class must be created -// and destroyed in the controller thread. -// -// This class is only for testing Google Test's own constructs. Do not -// use it in user tests, either directly or indirectly. -class ThreadStartSemaphore { - public: - ThreadStartSemaphore() : signalled_(false) {} - - // Signals to all threads created with this semaphore to start. Must - // be called from the controller thread. - void Signal() { signalled_ = true; } - - // Blocks until the controller thread signals. Must be called from a test - // thread. - void Wait() { - while(!signalled_) { - SleepMilliseconds(10); - } - } - - private: - volatile bool signalled_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadStartSemaphore); -}; - // Helper class for testing Google Test's multi-threading constructs. -// Use: -// -// void ThreadFunc(int param) { /* Do things with param */ } -// ThreadStartSemaphore semaphore; -// ... -// // The semaphore parameter is optional; you can supply NULL. -// ThreadWithParam thread(&ThreadFunc, 5, &semaphore); -// semaphore.Signal(); // Allows the thread to start. -// -// This class is only for testing Google Test's own constructs. Do not -// use it in user tests, either directly or indirectly. template -class ThreadWithParam { +class ThreadWithParam : public ThreadWithParamBase { public: - typedef void (*UserThreadFunc)(T); - - ThreadWithParam(UserThreadFunc func, T param, ThreadStartSemaphore* semaphore) - : func_(func), - param_(param), - start_semaphore_(semaphore), - finished_(false) { + ThreadWithParam(void (*func)(T), T param, Notification* thread_can_start) + : ThreadWithParamBase(func, param, thread_can_start) { // The thread can be created only after all fields except thread_ // have been initialized. GTEST_CHECK_POSIX_SUCCESS_( pthread_create(&thread_, 0, ThreadMainStatic, this)); } - ~ThreadWithParam() { Join(); } + virtual ~ThreadWithParam() { this->Join(); } - void Join() { - if (!finished_) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); - finished_ = true; - } + virtual void JoinUnderlyingThread() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); } private: - void ThreadMain() { - if (start_semaphore_ != NULL) - start_semaphore_->Wait(); - func_(param_); - } static void* ThreadMainStatic(void* thread_with_param) { static_cast*>(thread_with_param)->ThreadMain(); return NULL; // We are not interested in the thread exit code. } - const UserThreadFunc func_; // User-supplied thread function. - const T param_; // User-supplied parameter to the thread function. - // When non-NULL, used to block execution until the controller thread - // signals. - ThreadStartSemaphore* const start_semaphore_; - bool finished_; // Has the thread function finished? pthread_t thread_; // The native thread object. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; #define GTEST_IS_THREADSAFE 1 diff --git a/include/gtest/internal/gtest-string.h b/include/gtest/internal/gtest-string.h index 6f9ba05..280645e 100644 --- a/include/gtest/internal/gtest-string.h +++ b/include/gtest/internal/gtest-string.h @@ -51,14 +51,13 @@ namespace internal { // String - a UTF-8 string class. // -// We cannot use std::string as Microsoft's STL implementation in -// Visual C++ 7.1 has problems when exception is disabled. There is a -// hack to work around this, but we've seen cases where the hack fails -// to work. +// For historic reasons, we don't use std::string. // -// Also, String is different from std::string in that it can represent -// both NULL and the empty string, while std::string cannot represent -// NULL. +// TODO(wan@google.com): replace this class with std::string or +// implement it in terms of the latter. +// +// Note that String can represent both NULL and the empty string, +// while std::string cannot represent NULL. // // NULL and the empty string are considered different. NULL is less // than anything (including the empty string) except itself. diff --git a/samples/sample7_unittest.cc b/samples/sample7_unittest.cc index b5d507a..f455282 100644 --- a/samples/sample7_unittest.cc +++ b/samples/sample7_unittest.cc @@ -121,12 +121,12 @@ INSTANTIATE_TEST_CASE_P( #else -// Google Test doesn't support value-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 value-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, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {} #endif // GTEST_HAS_PARAM_TEST diff --git a/samples/sample8_unittest.cc b/samples/sample8_unittest.cc index d76136a..ccf61d9 100644 --- a/samples/sample8_unittest.cc +++ b/samples/sample8_unittest.cc @@ -162,12 +162,12 @@ INSTANTIATE_TEST_CASE_P(MeaningfulTestParameters, #else -// Google Test doesn't support Combine() 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 Combine() 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, CombineIsNotSupportedOnThisPlatform) {} #endif // GTEST_HAS_COMBINE diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 5f2fbbc..3b73b01 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -1037,8 +1037,6 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, // Splits a given string on a given delimiter, populating a given // vector with the fields. GTEST_HAS_DEATH_TEST implies that we have // ::std::string, so we can use it here. -// TODO(vladl@google.com): Get rid of std::vector to be able to build on -// Visual C++ 7.1 with exceptions disabled. static void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest) { ::std::vector< ::std::string> parsed; 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 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 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 void CallThreadLocalGet(ThreadLocal* threadLocal) { @@ -918,16 +931,19 @@ void CallThreadLocalGet(ThreadLocal* threadLocal) { } TEST(ThreadLocalTest, DestroysManagedObjectsNoLaterThanSelf) { - CountedDestructor::set_counter(0); + g_destroyed.clear(); { - ThreadLocal thread_local; - ThreadWithParam*> thread( - &CallThreadLocalGet, &thread_local, NULL); + ThreadLocal thread_local; + ThreadWithParam*> thread( + &CallThreadLocalGet, &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 -#if GTEST_HAS_PTHREAD -#include -#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 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( + &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 > 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(attr); - AddFailure(*failure); - return NULL; + ThreadWithParam 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 -[==========] Running 59 tests from 25 test cases. +[==========] Running 60 tests from 25 test cases. [----------] Global 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 [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions -[----------] 5 tests from SCOPED_TRACETest +[----------] 6 tests from SCOPED_TRACETest [ RUN ] SCOPED_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 [ FAILED ] SCOPED_TRACETest.CanBeRepeated +[ RUN ] SCOPED_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). +[ FAILED ] SCOPED_TRACETest.WorksConcurrently [----------] 1 test from NonFatalFailureInFixtureConstructorTest [ RUN ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor (expecting 5 failures) @@ -544,9 +573,9 @@ FooEnvironment::TearDown() called. gtest_output_test_.cc:#: Failure Failed Expected fatal failure. -[==========] 59 tests from 25 test cases ran. +[==========] 60 tests from 25 test cases ran. [ PASSED ] 21 tests. -[ FAILED ] 38 tests, listed below: +[ FAILED ] 39 tests, listed below: [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine @@ -556,6 +585,7 @@ Expected fatal failure. [ FAILED ] SCOPED_TRACETest.WorksInSubroutine [ FAILED ] SCOPED_TRACETest.CanBeNested [ FAILED ] SCOPED_TRACETest.CanBeRepeated +[ FAILED ] SCOPED_TRACETest.WorksConcurrently [ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor [ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor [ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp @@ -586,7 +616,7 @@ Expected fatal failure. [ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure [ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread -38 FAILED TESTS +39 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 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 > threads[kThreadCount]; - ThreadStartSemaphore semaphore; + Notification threads_can_start; for (int i = 0; i != kThreadCount; i++) - threads[i].reset(new ThreadWithParam(&ManyAsserts, i, &semaphore)); + threads[i].reset(new ThreadWithParam(&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 #include -#if GTEST_HAS_PTHREAD -#include -#endif // GTEST_HAS_PTHREAD - #include 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 { }; @@ -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(attr); - AddFailure(*failure); - return NULL; + ThreadWithParam 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. -- cgit v0.12