summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2010-03-04 22:15:53 +0000
committerzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2010-03-04 22:15:53 +0000
commitf6fb532f0825024feda89c863e33a51b6ff377f5 (patch)
tree9a7a9aac24a5946d5bca4e04ec681ecd38b6199c
parent2b608176ebb3ae26cd536dbb5809d6941affec33 (diff)
downloadgtest-f6fb532f0825024feda89c863e33a51b6ff377f5.tar.gz
gtest-f6fb532f0825024feda89c863e33a51b6ff377f5.tar.bz2
gtest-f6fb532f0825024feda89c863e33a51b6ff377f5.tar.xz
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).
git-svn-id: http://googletest.googlecode.com/svn/trunk@386 861a406c-534a-0410-8894-cb66d6ee9925
-rw-r--r--include/gtest/internal/gtest-port.h183
-rw-r--r--include/gtest/internal/gtest-string.h13
-rw-r--r--samples/sample7_unittest.cc12
-rw-r--r--samples/sample8_unittest.cc12
-rw-r--r--src/gtest-death-test.cc2
-rw-r--r--test/gtest-port_test.cc50
-rw-r--r--test/gtest-typed-test_test.cc12
-rwxr-xr-xtest/gtest_output_test.py4
-rw-r--r--test/gtest_output_test_.cc162
-rw-r--r--test/gtest_output_test_golden_lin.txt40
-rw-r--r--test/gtest_stress_test.cc17
-rw-r--r--test/gtest_unittest.cc31
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 <vector> // 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<String>& 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<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
// true.
#include <pthread.h>
@@ -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<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>
-class ThreadWithParam {
+class ThreadWithParam : public ThreadWithParamBase<T> {
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<T>(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<ThreadWithParam<T>*>(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<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, &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
// 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
-[==========] 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<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.