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

This commit is contained in:
zhanyong.wan 2010-03-04 22:15:53 +00:00
parent 0928f00c6b
commit 12a92c26fc
12 changed files with 359 additions and 179 deletions

View File

@ -463,13 +463,10 @@
#include <vector> // NOLINT #include <vector> // NOLINT
#endif #endif
// Determines whether to support value-parameterized tests. // We don't support MSVC 7.1 with exceptions disabled now. Therefore
// all the compilers we care about are adequate for supporting
#if defined(__GNUC__) || (_MSC_VER >= 1400) // value-parameterized tests.
// TODO(vladl@google.com): get the implementation rid of vector and list
// to compile on MSVC 7.1.
#define GTEST_HAS_PARAM_TEST 1 #define GTEST_HAS_PARAM_TEST 1
#endif // defined(__GNUC__) || (_MSC_VER >= 1400)
// Determines whether to support type-driven tests. // Determines whether to support type-driven tests.
@ -774,6 +771,97 @@ const ::std::vector<String>& GetArgvs();
#if GTEST_HAS_PTHREAD #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<T> from
// ThreadWithParamBase<T> 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<int> 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 <typename T>
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 <pthread.h> when GTEST_HAS_PTHREAD is // gtest-port.h guarantees to #include <pthread.h> when GTEST_HAS_PTHREAD is
// true. // true.
#include <pthread.h> #include <pthread.h>
@ -936,99 +1024,32 @@ class ThreadLocal {
GTEST_DISALLOW_COPY_AND_ASSIGN_(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. // 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<int> 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 <typename T> template <typename T>
class ThreadWithParam { class ThreadWithParam : public ThreadWithParamBase<T> {
public: public:
typedef void (*UserThreadFunc)(T); ThreadWithParam(void (*func)(T), T param, Notification* thread_can_start)
: ThreadWithParamBase<T>(func, param, thread_can_start) {
ThreadWithParam(UserThreadFunc func, T param, ThreadStartSemaphore* semaphore)
: func_(func),
param_(param),
start_semaphore_(semaphore),
finished_(false) {
// The thread can be created only after all fields except thread_ // The thread can be created only after all fields except thread_
// have been initialized. // have been initialized.
GTEST_CHECK_POSIX_SUCCESS_( GTEST_CHECK_POSIX_SUCCESS_(
pthread_create(&thread_, 0, ThreadMainStatic, this)); pthread_create(&thread_, 0, ThreadMainStatic, this));
} }
~ThreadWithParam() { Join(); } virtual ~ThreadWithParam() { this->Join(); }
void Join() { virtual void JoinUnderlyingThread() {
if (!finished_) {
GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0));
finished_ = true;
}
} }
private: private:
void ThreadMain() {
if (start_semaphore_ != NULL)
start_semaphore_->Wait();
func_(param_);
}
static void* ThreadMainStatic(void* thread_with_param) { static void* ThreadMainStatic(void* thread_with_param) {
static_cast<ThreadWithParam<T>*>(thread_with_param)->ThreadMain(); static_cast<ThreadWithParam<T>*>(thread_with_param)->ThreadMain();
return NULL; // We are not interested in the thread exit code. 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. pthread_t thread_; // The native thread object.
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
}; };
#define GTEST_IS_THREADSAFE 1 #define GTEST_IS_THREADSAFE 1

View File

@ -51,14 +51,13 @@ namespace internal {
// String - a UTF-8 string class. // String - a UTF-8 string class.
// //
// We cannot use std::string as Microsoft's STL implementation in // For historic reasons, we don't use std::string.
// 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.
// //
// Also, String is different from std::string in that it can represent // TODO(wan@google.com): replace this class with std::string or
// both NULL and the empty string, while std::string cannot represent // implement it in terms of the latter.
// NULL. //
// 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 // NULL and the empty string are considered different. NULL is less
// than anything (including the empty string) except itself. // than anything (including the empty string) except itself.

View File

@ -121,12 +121,12 @@ INSTANTIATE_TEST_CASE_P(
#else #else
// Google Test doesn't support value-parameterized tests on some platforms // Google Test may not support value-parameterized tests with some
// and compilers, such as MSVC 7.1. If we use conditional compilation to // compilers. If we use conditional compilation to compile out all
// compile out all code referring to the gtest_main library, MSVC linker // code referring to the gtest_main library, MSVC linker will not link
// will not link that library at all and consequently complain about // that library at all and consequently complain about missing entry
// missing entry point defined in that library (fatal error LNK1561: // point defined in that library (fatal error LNK1561: entry point
// entry point must be defined). This dummy test keeps gtest_main linked in. // must be defined). This dummy test keeps gtest_main linked in.
TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {} TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
#endif // GTEST_HAS_PARAM_TEST #endif // GTEST_HAS_PARAM_TEST

View File

@ -162,12 +162,12 @@ INSTANTIATE_TEST_CASE_P(MeaningfulTestParameters,
#else #else
// Google Test doesn't support Combine() on some platforms and compilers, // Google Test may not support Combine() with some compilers. If we
// such as MSVC 7.1. If we use conditional compilation to compile out // use conditional compilation to compile out all code referring to
// all code referring to the gtest_main library, MSVC linker will not // the gtest_main library, MSVC linker will not link that library at
// link that library at all and consequently complain about missing entry // all and consequently complain about missing entry point defined in
// point defined in that library (fatal error LNK1561: entry point must // that library (fatal error LNK1561: entry point must be
// be defined). This dummy test keeps gtest_main linked in. // defined). This dummy test keeps gtest_main linked in.
TEST(DummyTest, CombineIsNotSupportedOnThisPlatform) {} TEST(DummyTest, CombineIsNotSupportedOnThisPlatform) {}
#endif // GTEST_HAS_COMBINE #endif // GTEST_HAS_COMBINE

View File

@ -1037,8 +1037,6 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
// Splits a given string on a given delimiter, populating a given // Splits a given string on a given delimiter, populating a given
// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have // vector with the fields. GTEST_HAS_DEATH_TEST implies that we have
// ::std::string, so we can use it here. // ::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, static void SplitString(const ::std::string& str, char delimiter,
::std::vector< ::std::string>* dest) { ::std::vector< ::std::string>* dest) {
::std::vector< ::std::string> parsed; ::std::vector< ::std::string> parsed;

View File

@ -803,7 +803,7 @@ TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) {
{ MutexLock lock(&m); } { MutexLock lock(&m); }
m.AssertHeld(); m.AssertHeld();
}, },
"The current thread is not holding the mutex @.+"); "thread .*hold");
} }
TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) { TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) {
@ -859,16 +859,16 @@ TEST(MutexTest, OnlyOneThreadCanLockAtATime) {
const int kCycleCount = 20; const int kCycleCount = 20;
const int kThreadCount = 7; const int kThreadCount = 7;
scoped_ptr<ThreadType> counting_threads[kThreadCount]; scoped_ptr<ThreadType> counting_threads[kThreadCount];
ThreadStartSemaphore semaphore; Notification threads_can_start;
// Creates and runs kThreadCount threads that increment locked_counter // Creates and runs kThreadCount threads that increment locked_counter
// kCycleCount times each. // kCycleCount times each.
for (int i = 0; i < kThreadCount; ++i) { for (int i = 0; i < kThreadCount; ++i) {
counting_threads[i].reset(new ThreadType(&CountingThreadFunc, counting_threads[i].reset(new ThreadType(&CountingThreadFunc,
make_pair(&locked_counter, make_pair(&locked_counter,
kCycleCount), kCycleCount),
&semaphore)); &threads_can_start));
} }
semaphore.Signal(); // Starts the threads. threads_can_start.Notify();
for (int i = 0; i < kThreadCount; ++i) for (int i = 0; i < kThreadCount; ++i)
counting_threads[i]->Join(); counting_threads[i]->Join();
@ -901,16 +901,29 @@ TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) {
EXPECT_STREQ("foo", result.c_str()); 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: public:
~CountedDestructor() { counter_++; } DestructorTracker() : index_(GetNewIndex()) {}
static int counter() { return counter_; } ~DestructorTracker() {
static void set_counter(int value) { counter_ = value; } MutexLock lock(&destructor_tracker_mutex);
g_destroyed[index_] = true;
}
private: 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> template <typename T>
void CallThreadLocalGet(ThreadLocal<T>* threadLocal) { void CallThreadLocalGet(ThreadLocal<T>* threadLocal) {
@ -918,16 +931,19 @@ void CallThreadLocalGet(ThreadLocal<T>* threadLocal) {
} }
TEST(ThreadLocalTest, DestroysManagedObjectsNoLaterThanSelf) { TEST(ThreadLocalTest, DestroysManagedObjectsNoLaterThanSelf) {
CountedDestructor::set_counter(0); g_destroyed.clear();
{ {
ThreadLocal<CountedDestructor> thread_local; ThreadLocal<DestructorTracker> thread_local;
ThreadWithParam<ThreadLocal<CountedDestructor>*> thread( ThreadWithParam<ThreadLocal<DestructorTracker>*> thread(
&CallThreadLocalGet<CountedDestructor>, &thread_local, NULL); &CallThreadLocalGet<DestructorTracker>, &thread_local, NULL);
thread.Join(); thread.Join();
} }
// There should be 2 desctuctor calls as ThreadLocal also contains a member // Verifies that all DestructorTracker objects there were have been
// T - used as a prototype for copy ctr version. // destroyed.
EXPECT_EQ(2, CountedDestructor::counter()); for (size_t i = 0; i < g_destroyed.size(); ++i)
EXPECT_TRUE(g_destroyed[i]) << "at index " << i;
g_destroyed.clear();
} }
TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) { TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) {

View File

@ -349,12 +349,12 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, NumericTest, NumericTypes);
#if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P) #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P)
// Google Test doesn't support type-parameterized tests on some platforms // Google Test may not support type-parameterized tests with some
// and compilers, such as MSVC 7.1. If we use conditional compilation to // compilers. If we use conditional compilation to compile out all
// compile out all code referring to the gtest_main library, MSVC linker // code referring to the gtest_main library, MSVC linker will not link
// will not link that library at all and consequently complain about // that library at all and consequently complain about missing entry
// missing entry point defined in that library (fatal error LNK1561: // point defined in that library (fatal error LNK1561: entry point
// entry point must be defined). This dummy test keeps gtest_main linked in. // must be defined). This dummy test keeps gtest_main linked in.
TEST(DummyTest, TypedTestsAreNotSupportedOnThisPlatform) {} TEST(DummyTest, TypedTestsAreNotSupportedOnThisPlatform) {}
#endif // #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P) #endif // #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P)

View File

@ -282,7 +282,7 @@ class GTestOutputTest(gtest_test_utils.TestCase):
normalized_golden = RemoveTypeInfoDetails(golden) normalized_golden = RemoveTypeInfoDetails(golden)
if CAN_GENERATE_GOLDEN_FILE: if CAN_GENERATE_GOLDEN_FILE:
self.assert_(normalized_golden == normalized_actual) self.assertEqual(normalized_golden, normalized_actual)
else: else:
normalized_actual = RemoveTestCounts(normalized_actual) normalized_actual = RemoveTestCounts(normalized_actual)
normalized_golden = RemoveTestCounts(self.RemoveUnsupportedTests( normalized_golden = RemoveTestCounts(self.RemoveUnsupportedTests(
@ -299,7 +299,7 @@ class GTestOutputTest(gtest_test_utils.TestCase):
'_gtest_output_test_normalized_golden.txt'), 'wb').write( '_gtest_output_test_normalized_golden.txt'), 'wb').write(
normalized_golden) normalized_golden)
self.assert_(normalized_golden == normalized_actual) self.assertEqual(normalized_golden, normalized_actual)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -46,15 +46,17 @@
#include <stdlib.h> #include <stdlib.h>
#if GTEST_HAS_PTHREAD #if GTEST_IS_THREADSAFE
#include <pthread.h>
#endif // GTEST_HAS_PTHREAD
using testing::ScopedFakeTestPartResultReporter; using testing::ScopedFakeTestPartResultReporter;
using testing::TestPartResultArray; using testing::TestPartResultArray;
using testing::internal::Notification;
using testing::internal::ThreadWithParam;
#endif
namespace posix = ::testing::internal::posix; namespace posix = ::testing::internal::posix;
using testing::internal::String; using testing::internal::String;
using testing::internal::scoped_ptr;
// Tests catching fatal failures. // Tests catching fatal failures.
@ -214,6 +216,83 @@ TEST(SCOPED_TRACETest, CanBeRepeated) {
<< "trace point A, B, and D."; << "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, TEST(DisabledTestsWarningTest,
DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning) { DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning) {
// This test body is intentionally empty. Its sole purpose is for // This test body is intentionally empty. Its sole purpose is for
@ -479,6 +558,63 @@ TEST_F(ExceptionInTearDownTest, ExceptionInTearDown) {
#endif // GTEST_OS_WINDOWS #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, &notifications_, 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 // The MixedUpTestCaseTest test case verifies that Google Test will fail a
// test if it uses a different fixture class than what other tests in // test if it uses a different fixture class than what other tests in
// the same test case use. It deliberately contains two fixture // the same test case use. It deliberately contains two fixture
@ -849,23 +985,13 @@ TEST_F(ExpectFailureTest, ExpectNonFatalFailure) {
"failure."); "failure.");
} }
#if GTEST_IS_THREADSAFE && GTEST_HAS_PTHREAD #if GTEST_IS_THREADSAFE
class ExpectFailureWithThreadsTest : public ExpectFailureTest { class ExpectFailureWithThreadsTest : public ExpectFailureTest {
protected: protected:
static void AddFailureInOtherThread(FailureMode failure) { static void AddFailureInOtherThread(FailureMode failure) {
pthread_t tid; ThreadWithParam<FailureMode> thread(&AddFailure, failure, NULL);
pthread_create(&tid, thread.Join();
NULL,
ExpectFailureWithThreadsTest::FailureThread,
&failure);
pthread_join(tid, NULL);
}
private:
static void* FailureThread(void* attr) {
FailureMode* failure = static_cast<FailureMode*>(attr);
AddFailure(*failure);
return NULL;
} }
}; };
@ -901,7 +1027,7 @@ TEST_F(ScopedFakeTestPartResultReporterTest, InterceptOnlyCurrentThread) {
EXPECT_EQ(0, results.size()) << "This shouldn't fail."; EXPECT_EQ(0, results.size()) << "This shouldn't fail.";
} }
#endif // GTEST_IS_THREADSAFE && GTEST_HAS_PTHREAD #endif // GTEST_IS_THREADSAFE
TEST_F(ExpectFailureTest, ExpectFatalFailureOnAllThreads) { TEST_F(ExpectFailureTest, ExpectFatalFailureOnAllThreads) {
// Expected fatal failure, but succeeds. // Expected fatal failure, but succeeds.

View File

@ -7,7 +7,7 @@ Expected: true
gtest_output_test_.cc:#: Failure gtest_output_test_.cc:#: Failure
Value of: 3 Value of: 3
Expected: 2 Expected: 2
[==========] Running 59 tests from 25 test cases. [==========] Running 60 tests from 25 test cases.
[----------] Global test environment set-up. [----------] Global test environment set-up.
FooEnvironment::SetUp() called. FooEnvironment::SetUp() called.
BarEnvironment::SetUp() called. BarEnvironment::SetUp() called.
@ -65,7 +65,7 @@ i == 3
gtest_output_test_.cc:#: Failure gtest_output_test_.cc:#: Failure
Expected: (3) >= (a[i]), actual: 3 vs 6 Expected: (3) >= (a[i]), actual: 3 vs 6
[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions [ FAILED ] LoggingTest.InterleavingLoggingAndAssertions
[----------] 5 tests from SCOPED_TRACETest [----------] 6 tests from SCOPED_TRACETest
[ RUN ] SCOPED_TRACETest.ObeysScopes [ RUN ] SCOPED_TRACETest.ObeysScopes
(expected to fail) (expected to fail)
gtest_output_test_.cc:#: Failure gtest_output_test_.cc:#: Failure
@ -148,6 +148,35 @@ gtest_output_test_.cc:#: D
gtest_output_test_.cc:#: B gtest_output_test_.cc:#: B
gtest_output_test_.cc:#: A gtest_output_test_.cc:#: A
[ FAILED ] SCOPED_TRACETest.CanBeRepeated [ 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 [----------] 1 test from NonFatalFailureInFixtureConstructorTest
[ RUN ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor [ RUN ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor
(expecting 5 failures) (expecting 5 failures)
@ -544,9 +573,9 @@ FooEnvironment::TearDown() called.
gtest_output_test_.cc:#: Failure gtest_output_test_.cc:#: Failure
Failed Failed
Expected fatal failure. Expected fatal failure.
[==========] 59 tests from 25 test cases ran. [==========] 60 tests from 25 test cases ran.
[ PASSED ] 21 tests. [ PASSED ] 21 tests.
[ FAILED ] 38 tests, listed below: [ FAILED ] 39 tests, listed below:
[ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ FAILED ] FatalFailureTest.FatalFailureInSubroutine
[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine
[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine
@ -556,6 +585,7 @@ Expected fatal failure.
[ FAILED ] SCOPED_TRACETest.WorksInSubroutine [ FAILED ] SCOPED_TRACETest.WorksInSubroutine
[ FAILED ] SCOPED_TRACETest.CanBeNested [ FAILED ] SCOPED_TRACETest.CanBeNested
[ FAILED ] SCOPED_TRACETest.CanBeRepeated [ FAILED ] SCOPED_TRACETest.CanBeRepeated
[ FAILED ] SCOPED_TRACETest.WorksConcurrently
[ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor [ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor
[ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor [ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor
[ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp [ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp
@ -586,7 +616,7 @@ Expected fatal failure.
[ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure [ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure
[ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread [ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread
38 FAILED TESTS 39 FAILED TESTS
 YOU HAVE 1 DISABLED TEST  YOU HAVE 1 DISABLED TEST
Note: Google Test filter = FatalFailureTest.*:LoggingTest.* Note: Google Test filter = FatalFailureTest.*:LoggingTest.*

View File

@ -49,16 +49,15 @@
namespace testing { namespace testing {
namespace { namespace {
using internal::scoped_ptr; using internal::Notification;
using internal::String; using internal::String;
using internal::TestPropertyKeyIs; using internal::TestPropertyKeyIs;
using internal::ThreadStartSemaphore;
using internal::ThreadWithParam; using internal::ThreadWithParam;
using internal::scoped_ptr;
// In order to run tests in this file, for platforms where Google Test is // In order to run tests in this file, for platforms where Google Test is
// thread safe, implement ThreadWithParam and ThreadStartSemaphore. See the // thread safe, implement ThreadWithParam. See the description of its API
// description of their API in gtest-port.h, where they are defined for // in gtest-port.h, where it is defined for already supported platforms.
// already supported platforms.
// How many threads to create? // How many threads to create?
const int kThreadCount = 50; const int kThreadCount = 50;
@ -129,11 +128,13 @@ void CheckTestFailureCount(int expected_failures) {
TEST(StressTest, CanUseScopedTraceAndAssertionsInManyThreads) { TEST(StressTest, CanUseScopedTraceAndAssertionsInManyThreads) {
{ {
scoped_ptr<ThreadWithParam<int> > threads[kThreadCount]; scoped_ptr<ThreadWithParam<int> > threads[kThreadCount];
ThreadStartSemaphore semaphore; Notification threads_can_start;
for (int i = 0; i != kThreadCount; i++) 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. // Blocks until all the threads are done.
for (int i = 0; i != kThreadCount; i++) for (int i = 0; i != kThreadCount; i++)

View File

@ -71,10 +71,6 @@ TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded) {
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#if GTEST_HAS_PTHREAD
#include <pthread.h>
#endif // GTEST_HAS_PTHREAD
#include <map> #include <map>
namespace testing { namespace testing {
@ -191,6 +187,10 @@ using testing::internal::CaptureStdout;
using testing::internal::GetCapturedStdout; using testing::internal::GetCapturedStdout;
#endif // GTEST_HAS_STREAM_REDIRECTION_ #endif // GTEST_HAS_STREAM_REDIRECTION_
#if GTEST_IS_THREADSAFE
using testing::internal::ThreadWithParam;
#endif
class TestingVector : public std::vector<int> { class TestingVector : public std::vector<int> {
}; };
@ -1283,25 +1283,14 @@ TEST_F(ScopedFakeTestPartResultReporterTest, DeprecatedConstructor) {
EXPECT_EQ(1, results.size()); EXPECT_EQ(1, results.size());
} }
#if GTEST_IS_THREADSAFE && GTEST_HAS_PTHREAD #if GTEST_IS_THREADSAFE
class ScopedFakeTestPartResultReporterWithThreadsTest class ScopedFakeTestPartResultReporterWithThreadsTest
: public ScopedFakeTestPartResultReporterTest { : public ScopedFakeTestPartResultReporterTest {
protected: protected:
static void AddFailureInOtherThread(FailureMode failure) { static void AddFailureInOtherThread(FailureMode failure) {
pthread_t tid; ThreadWithParam<FailureMode> thread(&AddFailure, failure, NULL);
pthread_create(&tid, thread.Join();
NULL,
ScopedFakeTestPartResultReporterWithThreadsTest::
FailureThread,
&failure);
pthread_join(tid, NULL);
}
private:
static void* FailureThread(void* attr) {
FailureMode* failure = static_cast<FailureMode*>(attr);
AddFailure(*failure);
return NULL;
} }
}; };
@ -1324,7 +1313,7 @@ TEST_F(ScopedFakeTestPartResultReporterWithThreadsTest,
EXPECT_TRUE(results.GetTestPartResult(3).fatally_failed()); 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 // Tests EXPECT_FATAL_FAILURE{,ON_ALL_THREADS}. Makes sure that they
// work even if the failure is generated in a called function rather than // 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 typedef ScopedFakeTestPartResultReporterWithThreadsTest
ExpectFailureWithThreadsTest; ExpectFailureWithThreadsTest;
@ -1450,7 +1439,7 @@ TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailureOnAllThreads) {
AddFailureInOtherThread(NONFATAL_FAILURE), "Expected non-fatal failure."); AddFailureInOtherThread(NONFATAL_FAILURE), "Expected non-fatal failure.");
} }
#endif // GTEST_IS_THREADSAFE && GTEST_HAS_PTHREAD #endif // GTEST_IS_THREADSAFE
// Tests the TestProperty class. // Tests the TestProperty class.