X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=test%2Fgtest-port_test.cc;h=6ea607bc70d352d64653bf28125a91c32e0b56db;hb=e7a2f0999079de84efe682f827455616ececd93f;hp=1c6e2b09760d1c75c75f4a5b7cc1a4aaa1619b83;hpb=87f45b08a34d8412f14ce5d154692256077bbb8e;p=platform%2Fupstream%2Fgtest.git diff --git a/test/gtest-port_test.cc b/test/gtest-port_test.cc index 1c6e2b0..6ea607b 100755 --- a/test/gtest-port_test.cc +++ b/test/gtest-port_test.cc @@ -61,6 +61,43 @@ using std::pair; namespace testing { namespace internal { +TEST(IsXDigitTest, WorksForNarrowAscii) { + EXPECT_TRUE(IsXDigit('0')); + EXPECT_TRUE(IsXDigit('9')); + EXPECT_TRUE(IsXDigit('A')); + EXPECT_TRUE(IsXDigit('F')); + EXPECT_TRUE(IsXDigit('a')); + EXPECT_TRUE(IsXDigit('f')); + + EXPECT_FALSE(IsXDigit('-')); + EXPECT_FALSE(IsXDigit('g')); + EXPECT_FALSE(IsXDigit('G')); +} + +TEST(IsXDigitTest, ReturnsFalseForNarrowNonAscii) { + EXPECT_FALSE(IsXDigit('\x80')); + EXPECT_FALSE(IsXDigit(static_cast('0' | '\x80'))); +} + +TEST(IsXDigitTest, WorksForWideAscii) { + EXPECT_TRUE(IsXDigit(L'0')); + EXPECT_TRUE(IsXDigit(L'9')); + EXPECT_TRUE(IsXDigit(L'A')); + EXPECT_TRUE(IsXDigit(L'F')); + EXPECT_TRUE(IsXDigit(L'a')); + EXPECT_TRUE(IsXDigit(L'f')); + + EXPECT_FALSE(IsXDigit(L'-')); + EXPECT_FALSE(IsXDigit(L'g')); + EXPECT_FALSE(IsXDigit(L'G')); +} + +TEST(IsXDigitTest, ReturnsFalseForWideNonAscii) { + EXPECT_FALSE(IsXDigit(static_cast(0x80))); + EXPECT_FALSE(IsXDigit(static_cast(L'0' | 0x80))); + EXPECT_FALSE(IsXDigit(static_cast(L'0' | 0x100))); +} + class Base { public: // Copy constructor and assignment operator do exactly what we need, so we @@ -92,7 +129,7 @@ TEST(ImplicitCastTest, CanUseInheritance) { class Castable { public: - Castable(bool* converted) : converted_(converted) {} + explicit Castable(bool* converted) : converted_(converted) {} operator Base() { *converted_ = true; return Base(); @@ -111,7 +148,7 @@ TEST(ImplicitCastTest, CanUseNonConstCastOperator) { class ConstCastable { public: - ConstCastable(bool* converted) : converted_(converted) {} + explicit ConstCastable(bool* converted) : converted_(converted) {} operator Base() const { *converted_ = true; return Base(); @@ -224,7 +261,7 @@ TEST(GtestCheckSyntaxTest, WorksWithSwitch) { GTEST_CHECK_(true); } - switch(0) + switch (0) case 0: GTEST_CHECK_(true) << "Check failed in switch case"; } @@ -267,53 +304,51 @@ TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFileAndLine) { EXPECT_EQ("unknown file", FormatCompilerIndependentFileLocation(NULL, -1)); } -#if GTEST_OS_MAC +#if GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX void* ThreadFunc(void* data) { - pthread_mutex_t* mutex = static_cast(data); - pthread_mutex_lock(mutex); - pthread_mutex_unlock(mutex); + internal::Mutex* mutex = static_cast(data); + mutex->Lock(); + mutex->Unlock(); return NULL; } TEST(GetThreadCountTest, ReturnsCorrectValue) { - EXPECT_EQ(1U, GetThreadCount()); - pthread_mutex_t mutex; - pthread_attr_t attr; + const size_t starting_count = GetThreadCount(); pthread_t thread_id; - // TODO(vladl@google.com): turn mutex into internal::Mutex for automatic - // destruction. - pthread_mutex_init(&mutex, NULL); - pthread_mutex_lock(&mutex); - ASSERT_EQ(0, pthread_attr_init(&attr)); - ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); - - const int status = pthread_create(&thread_id, &attr, &ThreadFunc, &mutex); - ASSERT_EQ(0, pthread_attr_destroy(&attr)); - ASSERT_EQ(0, status); - EXPECT_EQ(2U, GetThreadCount()); - pthread_mutex_unlock(&mutex); + internal::Mutex mutex; + { + internal::MutexLock lock(&mutex); + pthread_attr_t attr; + ASSERT_EQ(0, pthread_attr_init(&attr)); + ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); + + const int status = pthread_create(&thread_id, &attr, &ThreadFunc, &mutex); + ASSERT_EQ(0, pthread_attr_destroy(&attr)); + ASSERT_EQ(0, status); + EXPECT_EQ(starting_count + 1, GetThreadCount()); + } void* dummy; ASSERT_EQ(0, pthread_join(thread_id, &dummy)); - // MacOS X may not immediately report the updated thread count after + // The OS may not immediately report the updated thread count after // joining a thread, causing flakiness in this test. To counter that, we // wait for up to .5 seconds for the OS to report the correct value. for (int i = 0; i < 5; ++i) { - if (GetThreadCount() == 1) + if (GetThreadCount() == starting_count) break; SleepMilliseconds(100); } - EXPECT_EQ(1U, GetThreadCount()); - pthread_mutex_destroy(&mutex); + + EXPECT_EQ(starting_count, GetThreadCount()); } #else TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) { EXPECT_EQ(0U, GetThreadCount()); } -#endif // GTEST_OS_MAC +#endif // GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) { const bool a_false_condition = false; @@ -347,15 +382,17 @@ TEST(GtestCheckDeathTest, LivesSilentlyOnSuccess) { // the platform. The test will produce compiler errors in case of failure. // For simplicity, we only cover the most important platforms here. TEST(RegexEngineSelectionTest, SelectsCorrectRegexEngine) { -#if GTEST_HAS_POSIX_RE +#if !GTEST_USES_PCRE +# if GTEST_HAS_POSIX_RE EXPECT_TRUE(GTEST_USES_POSIX_RE); -#else +# else EXPECT_TRUE(GTEST_USES_SIMPLE_RE); -#endif +# endif +#endif // !GTEST_USES_PCRE } #if GTEST_USES_POSIX_RE @@ -924,7 +961,7 @@ TEST(CaptureTest, CapturesStdoutAndStderr) { TEST(CaptureDeathTest, CannotReenterStdoutCapture) { CaptureStdout(); - EXPECT_DEATH_IF_SUPPORTED(CaptureStdout();, + EXPECT_DEATH_IF_SUPPORTED(CaptureStdout(), "Only one stdout capturer can exist at a time"); GetCapturedStdout(); @@ -963,23 +1000,24 @@ TEST(ThreadLocalTest, ValueDefaultContructorIsNotRequiredForParamVersion) { } TEST(ThreadLocalTest, GetAndPointerReturnSameValue) { - ThreadLocal thread_local; + ThreadLocal thread_local_string; - EXPECT_EQ(thread_local.pointer(), &(thread_local.get())); + EXPECT_EQ(thread_local_string.pointer(), &(thread_local_string.get())); // Verifies the condition still holds after calling set. - thread_local.set("foo"); - EXPECT_EQ(thread_local.pointer(), &(thread_local.get())); + thread_local_string.set("foo"); + EXPECT_EQ(thread_local_string.pointer(), &(thread_local_string.get())); } TEST(ThreadLocalTest, PointerAndConstPointerReturnSameValue) { - ThreadLocal thread_local; - const ThreadLocal& const_thread_local = thread_local; + ThreadLocal thread_local_string; + const ThreadLocal& const_thread_local_string = + thread_local_string; - EXPECT_EQ(thread_local.pointer(), const_thread_local.pointer()); + EXPECT_EQ(thread_local_string.pointer(), const_thread_local_string.pointer()); - thread_local.set("foo"); - EXPECT_EQ(thread_local.pointer(), const_thread_local.pointer()); + thread_local_string.set("foo"); + EXPECT_EQ(thread_local_string.pointer(), const_thread_local_string.pointer()); } #if GTEST_IS_THREADSAFE @@ -1019,11 +1057,13 @@ class AtomicCounterWithMutex { MutexLock lock(mutex_); int temp = value_; { - // Locking a mutex puts up a memory barrier, preventing reads and - // writes to value_ rearranged when observed from other threads. - // - // We cannot use Mutex and MutexLock here or rely on their memory - // barrier functionality as we are testing them here. + // We need to put up a memory barrier to prevent reads and writes to + // value_ rearranged with the call to SleepMilliseconds when observed + // from other threads. +#if GTEST_HAS_PTHREAD + // On POSIX, locking a mutex puts up a memory barrier. We cannot use + // Mutex and MutexLock here or rely on their memory barrier + // functionality as we are testing them here. pthread_mutex_t memory_barrier_mutex; GTEST_CHECK_POSIX_SUCCESS_( pthread_mutex_init(&memory_barrier_mutex, NULL)); @@ -1032,6 +1072,16 @@ class AtomicCounterWithMutex { SleepMilliseconds(random_.Generate(30)); GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&memory_barrier_mutex)); + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&memory_barrier_mutex)); +#elif GTEST_OS_WINDOWS + // On Windows, performing an interlocked access puts up a memory barrier. + volatile LONG dummy = 0; + ::InterlockedIncrement(&dummy); + SleepMilliseconds(random_.Generate(30)); + ::InterlockedIncrement(&dummy); +#else +# error "Memory barrier not implemented on this platform." +#endif // GTEST_HAS_PTHREAD } value_ = temp + 1; } @@ -1083,124 +1133,172 @@ void RunFromThread(void (func)(T), T param) { thread.Join(); } -void RetrieveThreadLocalValue(pair*, String*> param) { +void RetrieveThreadLocalValue( + pair*, std::string*> param) { *param.second = param.first->get(); } TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) { - ThreadLocal thread_local("foo"); - EXPECT_STREQ("foo", thread_local.get().c_str()); + ThreadLocal thread_local_string("foo"); + EXPECT_STREQ("foo", thread_local_string.get().c_str()); - thread_local.set("bar"); - EXPECT_STREQ("bar", thread_local.get().c_str()); + thread_local_string.set("bar"); + EXPECT_STREQ("bar", thread_local_string.get().c_str()); - String result; - RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local, &result)); + std::string result; + RunFromThread(&RetrieveThreadLocalValue, + make_pair(&thread_local_string, &result)); EXPECT_STREQ("foo", result.c_str()); } +// Keeps track of whether of destructors being called on instances of +// DestructorTracker. On Windows, waits for the destructor call reports. +class DestructorCall { + public: + DestructorCall() { + invoked_ = false; +#if GTEST_OS_WINDOWS + wait_event_.Reset(::CreateEvent(NULL, TRUE, FALSE, NULL)); + GTEST_CHECK_(wait_event_.Get() != NULL); +#endif + } + + bool CheckDestroyed() const { +#if GTEST_OS_WINDOWS + if (::WaitForSingleObject(wait_event_.Get(), 1000) != WAIT_OBJECT_0) + return false; +#endif + return invoked_; + } + + void ReportDestroyed() { + invoked_ = true; +#if GTEST_OS_WINDOWS + ::SetEvent(wait_event_.Get()); +#endif + } + + static std::vector& List() { return *list_; } + + static void ResetList() { + for (size_t i = 0; i < list_->size(); ++i) { + delete list_->at(i); + } + list_->clear(); + } + + private: + bool invoked_; +#if GTEST_OS_WINDOWS + AutoHandle wait_event_; +#endif + static std::vector* const list_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DestructorCall); +}; + +std::vector* const DestructorCall::list_ = + new std::vector; + // DestructorTracker keeps track of whether its instances have been // destroyed. -static std::vector g_destroyed; - class DestructorTracker { public: DestructorTracker() : index_(GetNewIndex()) {} DestructorTracker(const DestructorTracker& /* rhs */) : index_(GetNewIndex()) {} ~DestructorTracker() { - // We never access g_destroyed concurrently, so we don't need to - // protect the write operation under a mutex. - g_destroyed[index_] = true; + // We never access DestructorCall::List() concurrently, so we don't need + // to protect this acccess with a mutex. + DestructorCall::List()[index_]->ReportDestroyed(); } private: - static int GetNewIndex() { - g_destroyed.push_back(false); - return g_destroyed.size() - 1; + static size_t GetNewIndex() { + DestructorCall::List().push_back(new DestructorCall); + return DestructorCall::List().size() - 1; } - const int index_; + const size_t index_; + + GTEST_DISALLOW_ASSIGN_(DestructorTracker); }; typedef ThreadLocal* ThreadParam; -void CallThreadLocalGet(ThreadParam thread_local) { - thread_local->get(); +void CallThreadLocalGet(ThreadParam thread_local_param) { + thread_local_param->get(); } // Tests that when a ThreadLocal object dies in a thread, it destroys // the managed object for that thread. TEST(ThreadLocalTest, DestroysManagedObjectForOwnThreadWhenDying) { - g_destroyed.clear(); + DestructorCall::ResetList(); { - // The next line default constructs a DestructorTracker object as - // the default value of objects managed by thread_local. - ThreadLocal thread_local; - ASSERT_EQ(1U, g_destroyed.size()); - ASSERT_FALSE(g_destroyed[0]); + ThreadLocal thread_local_tracker; + ASSERT_EQ(0U, DestructorCall::List().size()); // This creates another DestructorTracker object for the main thread. - thread_local.get(); - ASSERT_EQ(2U, g_destroyed.size()); - ASSERT_FALSE(g_destroyed[0]); - ASSERT_FALSE(g_destroyed[1]); + thread_local_tracker.get(); + ASSERT_EQ(1U, DestructorCall::List().size()); + ASSERT_FALSE(DestructorCall::List()[0]->CheckDestroyed()); } - // Now thread_local has died. It should have destroyed both the - // default value shared by all threads and the value for the main - // thread. - ASSERT_EQ(2U, g_destroyed.size()); - EXPECT_TRUE(g_destroyed[0]); - EXPECT_TRUE(g_destroyed[1]); + // Now thread_local_tracker has died. + ASSERT_EQ(1U, DestructorCall::List().size()); + EXPECT_TRUE(DestructorCall::List()[0]->CheckDestroyed()); - g_destroyed.clear(); + DestructorCall::ResetList(); } // Tests that when a thread exits, the thread-local object for that // thread is destroyed. TEST(ThreadLocalTest, DestroysManagedObjectAtThreadExit) { - g_destroyed.clear(); + DestructorCall::ResetList(); { - // The next line default constructs a DestructorTracker object as - // the default value of objects managed by thread_local. - ThreadLocal thread_local; - ASSERT_EQ(1U, g_destroyed.size()); - ASSERT_FALSE(g_destroyed[0]); + ThreadLocal thread_local_tracker; + ASSERT_EQ(0U, DestructorCall::List().size()); // This creates another DestructorTracker object in the new thread. ThreadWithParam thread( - &CallThreadLocalGet, &thread_local, NULL); + &CallThreadLocalGet, &thread_local_tracker, NULL); thread.Join(); - // Now the new thread has exited. The per-thread object for it - // should have been destroyed. - ASSERT_EQ(2U, g_destroyed.size()); - ASSERT_FALSE(g_destroyed[0]); - ASSERT_TRUE(g_destroyed[1]); + // The thread has exited, and we should have a DestroyedTracker + // instance created for it. But it may not have been destroyed yet. + ASSERT_EQ(1U, DestructorCall::List().size()); } - // Now thread_local has died. The default value should have been - // destroyed too. - ASSERT_EQ(2U, g_destroyed.size()); - EXPECT_TRUE(g_destroyed[0]); - EXPECT_TRUE(g_destroyed[1]); + // The thread has exited and thread_local_tracker has died. + ASSERT_EQ(1U, DestructorCall::List().size()); + EXPECT_TRUE(DestructorCall::List()[0]->CheckDestroyed()); - g_destroyed.clear(); + DestructorCall::ResetList(); } TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) { - ThreadLocal thread_local; - thread_local.set("Foo"); - EXPECT_STREQ("Foo", thread_local.get().c_str()); + ThreadLocal thread_local_string; + thread_local_string.set("Foo"); + EXPECT_STREQ("Foo", thread_local_string.get().c_str()); - String result; - RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local, &result)); - EXPECT_TRUE(result.c_str() == NULL); + std::string result; + RunFromThread(&RetrieveThreadLocalValue, + make_pair(&thread_local_string, &result)); + EXPECT_TRUE(result.empty()); } #endif // GTEST_IS_THREADSAFE +#if GTEST_OS_WINDOWS +TEST(WindowsTypesTest, HANDLEIsVoidStar) { + StaticAssertTypeEq(); +} + +TEST(WindowsTypesTest, CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION) { + StaticAssertTypeEq(); +} +#endif // GTEST_OS_WINDOWS + } // namespace internal } // namespace testing