summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2010-03-04 22:15:53 (GMT)
committerzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2010-03-04 22:15:53 (GMT)
commit12a92c26fc0e0de81f687dbe739a6aa24f37f9dd (patch)
tree9a7a9aac24a5946d5bca4e04ec681ecd38b6199c /test
parent0928f00c6b995af037b787b710fde509267ad624 (diff)
downloadgoogletest-12a92c26fc0e0de81f687dbe739a6aa24f37f9dd.zip
googletest-12a92c26fc0e0de81f687dbe739a6aa24f37f9dd.tar.gz
googletest-12a92c26fc0e0de81f687dbe739a6aa24f37f9dd.tar.bz2
Renames ThreadStartSempahore to Notificaton (by Vlad Losev); adds threading tests for SCOPED_TRACE() (by Vlad Losev); replaces native pthread calls with gtest's threading constructs (by Vlad Losev); fixes flakiness in CountedDestructor (by Vlad Losev); minor MSVC 7.1 clean-up (by Zhanyong Wan).
Diffstat (limited to 'test')
-rw-r--r--test/gtest-port_test.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
7 files changed, 239 insertions, 77 deletions
diff --git a/test/gtest-port_test.cc b/test/gtest-port_test.cc
index 357a99e..1588bd4 100644
--- a/test/gtest-port_test.cc
+++ b/test/gtest-port_test.cc
@@ -803,7 +803,7 @@ TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) {
{ MutexLock lock(&m); }
m.AssertHeld();
},
- "The current thread is not holding the mutex @.+");
+ "thread .*hold");
}
TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) {
@@ -859,16 +859,16 @@ TEST(MutexTest, OnlyOneThreadCanLockAtATime) {
const int kCycleCount = 20;
const int kThreadCount = 7;
scoped_ptr<ThreadType> counting_threads[kThreadCount];
- ThreadStartSemaphore semaphore;
+ Notification threads_can_start;
// Creates and runs kThreadCount threads that increment locked_counter
// kCycleCount times each.
for (int i = 0; i < kThreadCount; ++i) {
counting_threads[i].reset(new ThreadType(&CountingThreadFunc,
make_pair(&locked_counter,
kCycleCount),
- &semaphore));
+ &threads_can_start));
}
- semaphore.Signal(); // Starts the threads.
+ threads_can_start.Notify();
for (int i = 0; i < kThreadCount; ++i)
counting_threads[i]->Join();
@@ -901,16 +901,29 @@ TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) {
EXPECT_STREQ("foo", result.c_str());
}
-class CountedDestructor {
+// DestructorTracker keeps track of whether the class instances have been
+// destroyed. The static synchronization mutex has to be defined outside
+// of the class, due to syntax of its definition.
+static GTEST_DEFINE_STATIC_MUTEX_(destructor_tracker_mutex);
+
+static std::vector<bool> g_destroyed;
+
+class DestructorTracker {
public:
- ~CountedDestructor() { counter_++; }
- static int counter() { return counter_; }
- static void set_counter(int value) { counter_ = value; }
+ DestructorTracker() : index_(GetNewIndex()) {}
+ ~DestructorTracker() {
+ MutexLock lock(&destructor_tracker_mutex);
+ g_destroyed[index_] = true;
+ }
private:
- static int counter_;
+ static int GetNewIndex() {
+ MutexLock lock(&destructor_tracker_mutex);
+ g_destroyed.push_back(false);
+ return g_destroyed.size() - 1;
+ }
+ const int index_;
};
-int CountedDestructor::counter_ = 0;
template <typename T>
void CallThreadLocalGet(ThreadLocal<T>* threadLocal) {
@@ -918,16 +931,19 @@ void CallThreadLocalGet(ThreadLocal<T>* threadLocal) {
}
TEST(ThreadLocalTest, DestroysManagedObjectsNoLaterThanSelf) {
- CountedDestructor::set_counter(0);
+ g_destroyed.clear();
{
- ThreadLocal<CountedDestructor> thread_local;
- ThreadWithParam<ThreadLocal<CountedDestructor>*> thread(
- &CallThreadLocalGet<CountedDestructor>, &thread_local, NULL);
+ ThreadLocal<DestructorTracker> thread_local;
+ ThreadWithParam<ThreadLocal<DestructorTracker>*> thread(
+ &CallThreadLocalGet<DestructorTracker>, &thread_local, NULL);
thread.Join();
}
- // There should be 2 desctuctor calls as ThreadLocal also contains a member
- // T - used as a prototype for copy ctr version.
- EXPECT_EQ(2, CountedDestructor::counter());
+ // Verifies that all DestructorTracker objects there were have been
+ // destroyed.
+ for (size_t i = 0; i < g_destroyed.size(); ++i)
+ EXPECT_TRUE(g_destroyed[i]) << "at index " << i;
+
+ g_destroyed.clear();
}
TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) {
diff --git a/test/gtest-typed-test_test.cc b/test/gtest-typed-test_test.cc
index 4b6e971..f2c3972 100644
--- a/test/gtest-typed-test_test.cc
+++ b/test/gtest-typed-test_test.cc
@@ -349,12 +349,12 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, NumericTest, NumericTypes);
#if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P)
-// Google Test doesn't support type-parameterized tests on some platforms
-// and compilers, such as MSVC 7.1. If we use conditional compilation to
-// compile out all code referring to the gtest_main library, MSVC linker
-// will not link that library at all and consequently complain about
-// missing entry point defined in that library (fatal error LNK1561:
-// entry point must be defined). This dummy test keeps gtest_main linked in.
+// Google Test may not support type-parameterized tests with some
+// compilers. If we use conditional compilation to compile out all
+// code referring to the gtest_main library, MSVC linker will not link
+// that library at all and consequently complain about missing entry
+// point defined in that library (fatal error LNK1561: entry point
+// must be defined). This dummy test keeps gtest_main linked in.
TEST(DummyTest, TypedTestsAreNotSupportedOnThisPlatform) {}
#endif // #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P)
diff --git a/test/gtest_output_test.py b/test/gtest_output_test.py
index 125970a..192030a 100755
--- a/test/gtest_output_test.py
+++ b/test/gtest_output_test.py
@@ -282,7 +282,7 @@ class GTestOutputTest(gtest_test_utils.TestCase):
normalized_golden = RemoveTypeInfoDetails(golden)
if CAN_GENERATE_GOLDEN_FILE:
- self.assert_(normalized_golden == normalized_actual)
+ self.assertEqual(normalized_golden, normalized_actual)
else:
normalized_actual = RemoveTestCounts(normalized_actual)
normalized_golden = RemoveTestCounts(self.RemoveUnsupportedTests(
@@ -299,7 +299,7 @@ class GTestOutputTest(gtest_test_utils.TestCase):
'_gtest_output_test_normalized_golden.txt'), 'wb').write(
normalized_golden)
- self.assert_(normalized_golden == normalized_actual)
+ self.assertEqual(normalized_golden, normalized_actual)
if __name__ == '__main__':
diff --git a/test/gtest_output_test_.cc b/test/gtest_output_test_.cc
index 6d75602..273e8e9 100644
--- a/test/gtest_output_test_.cc
+++ b/test/gtest_output_test_.cc
@@ -46,15 +46,17 @@
#include <stdlib.h>
-#if GTEST_HAS_PTHREAD
-#include <pthread.h>
-#endif // GTEST_HAS_PTHREAD
-
+#if GTEST_IS_THREADSAFE
using testing::ScopedFakeTestPartResultReporter;
using testing::TestPartResultArray;
+using testing::internal::Notification;
+using testing::internal::ThreadWithParam;
+#endif
+
namespace posix = ::testing::internal::posix;
using testing::internal::String;
+using testing::internal::scoped_ptr;
// Tests catching fatal failures.
@@ -214,6 +216,83 @@ TEST(SCOPED_TRACETest, CanBeRepeated) {
<< "trace point A, B, and D.";
}
+#if GTEST_IS_THREADSAFE
+// Tests that SCOPED_TRACE()s can be used concurrently from multiple
+// threads. Namely, an assertion should be affected by
+// SCOPED_TRACE()s in its own thread only.
+
+// Here's the sequence of actions that happen in the test:
+//
+// Thread A (main) | Thread B (spawned)
+// ===============================|================================
+// spawns thread B |
+// -------------------------------+--------------------------------
+// waits for n1 | SCOPED_TRACE("Trace B");
+// | generates failure #1
+// | notifies n1
+// -------------------------------+--------------------------------
+// SCOPED_TRACE("Trace A"); | waits for n2
+// generates failure #2 |
+// notifies n2 |
+// -------------------------------|--------------------------------
+// waits for n3 | generates failure #3
+// | trace B dies
+// | generates failure #4
+// | notifies n3
+// -------------------------------|--------------------------------
+// generates failure #5 | finishes
+// trace A dies |
+// generates failure #6 |
+// -------------------------------|--------------------------------
+// waits for thread B to finish |
+
+struct CheckPoints {
+ Notification n1;
+ Notification n2;
+ Notification n3;
+};
+
+static void ThreadWithScopedTrace(CheckPoints* check_points) {
+ {
+ SCOPED_TRACE("Trace B");
+ ADD_FAILURE()
+ << "Expected failure #1 (in thread B, only trace B alive).";
+ check_points->n1.Notify();
+ check_points->n2.WaitForNotification();
+
+ ADD_FAILURE()
+ << "Expected failure #3 (in thread B, trace A & B both alive).";
+ } // Trace B dies here.
+ ADD_FAILURE()
+ << "Expected failure #4 (in thread B, only trace A alive).";
+ check_points->n3.Notify();
+}
+
+TEST(SCOPED_TRACETest, WorksConcurrently) {
+ printf("(expecting 6 failures)\n");
+
+ CheckPoints check_points;
+ ThreadWithParam<CheckPoints*> thread(&ThreadWithScopedTrace,
+ &check_points,
+ NULL);
+ check_points.n1.WaitForNotification();
+
+ {
+ SCOPED_TRACE("Trace A");
+ ADD_FAILURE()
+ << "Expected failure #2 (in thread A, trace A & B both alive).";
+ check_points.n2.Notify();
+ check_points.n3.WaitForNotification();
+
+ ADD_FAILURE()
+ << "Expected failure #5 (in thread A, only trace A alive).";
+ } // Trace A dies here.
+ ADD_FAILURE()
+ << "Expected failure #6 (in thread A, no trace alive).";
+ thread.Join();
+}
+#endif // GTEST_IS_THREADSAFE
+
TEST(DisabledTestsWarningTest,
DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning) {
// This test body is intentionally empty. Its sole purpose is for
@@ -479,6 +558,63 @@ TEST_F(ExceptionInTearDownTest, ExceptionInTearDown) {
#endif // GTEST_OS_WINDOWS
+#if GTEST_IS_THREADSAFE
+
+// A unary function that may die.
+void DieIf(bool should_die) {
+ GTEST_CHECK_(!should_die) << " - death inside DieIf().";
+}
+
+// Tests running death tests in a multi-threaded context.
+
+// Used for coordination between the main and the spawn thread.
+struct SpawnThreadNotifications {
+ SpawnThreadNotifications() {}
+
+ Notification spawn_thread_started;
+ Notification spawn_thread_ok_to_terminate;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SpawnThreadNotifications);
+};
+
+// The function to be executed in the thread spawn by the
+// MultipleThreads test (below).
+static void ThreadRoutine(SpawnThreadNotifications* notifications) {
+ // Signals the main thread that this thread has started.
+ notifications->spawn_thread_started.Notify();
+
+ // Waits for permission to finish from the main thread.
+ notifications->spawn_thread_ok_to_terminate.WaitForNotification();
+}
+
+// This is a death-test test, but it's not named with a DeathTest
+// suffix. It starts threads which might interfere with later
+// death tests, so it must run after all other death tests.
+class DeathTestAndMultiThreadsTest : public testing::Test {
+ protected:
+ // Starts a thread and waits for it to begin.
+ virtual void SetUp() {
+ thread_.reset(new ThreadWithParam<SpawnThreadNotifications*>(
+ &ThreadRoutine, &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.