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<char>('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<wchar_t>(0x80)));
+ EXPECT_FALSE(IsXDigit(static_cast<wchar_t>(L'0' | 0x80)));
+ EXPECT_FALSE(IsXDigit(static_cast<wchar_t>(L'0' | 0x100)));
+}
+
class Base {
public:
// Copy constructor and assignment operator do exactly what we need, so we
class Castable {
public:
- Castable(bool* converted) : converted_(converted) {}
+ explicit Castable(bool* converted) : converted_(converted) {}
operator Base() {
*converted_ = true;
return Base();
class ConstCastable {
public:
- ConstCastable(bool* converted) : converted_(converted) {}
+ explicit ConstCastable(bool* converted) : converted_(converted) {}
operator Base() const {
*converted_ = true;
return Base();
GTEST_CHECK_(true);
}
- switch(0)
+ switch (0)
case 0:
GTEST_CHECK_(true) << "Check failed in switch case";
}
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<pthread_mutex_t*>(data);
- pthread_mutex_lock(mutex);
- pthread_mutex_unlock(mutex);
+ internal::Mutex* mutex = static_cast<internal::Mutex*>(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;
// 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
TEST(CaptureDeathTest, CannotReenterStdoutCapture) {
CaptureStdout();
- EXPECT_DEATH_IF_SUPPORTED(CaptureStdout();,
+ EXPECT_DEATH_IF_SUPPORTED(CaptureStdout(),
"Only one stdout capturer can exist at a time");
GetCapturedStdout();
}
TEST(ThreadLocalTest, GetAndPointerReturnSameValue) {
- ThreadLocal<String> thread_local;
+ ThreadLocal<std::string> 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<String> thread_local;
- const ThreadLocal<String>& const_thread_local = thread_local;
+ ThreadLocal<std::string> thread_local_string;
+ const ThreadLocal<std::string>& 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
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));
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;
}
thread.Join();
}
-void RetrieveThreadLocalValue(pair<ThreadLocal<String>*, String*> param) {
+void RetrieveThreadLocalValue(
+ pair<ThreadLocal<std::string>*, std::string*> param) {
*param.second = param.first->get();
}
TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) {
- ThreadLocal<String> thread_local("foo");
- EXPECT_STREQ("foo", thread_local.get().c_str());
+ ThreadLocal<std::string> 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<DestructorCall*>& 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<DestructorCall*>* const list_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DestructorCall);
+};
+
+std::vector<DestructorCall*>* const DestructorCall::list_ =
+ new std::vector<DestructorCall*>;
+
// DestructorTracker keeps track of whether its instances have been
// destroyed.
-static std::vector<bool> 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<DestructorTracker>* 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<DestructorTracker> thread_local;
- ASSERT_EQ(1U, g_destroyed.size());
- ASSERT_FALSE(g_destroyed[0]);
+ ThreadLocal<DestructorTracker> 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<DestructorTracker> thread_local;
- ASSERT_EQ(1U, g_destroyed.size());
- ASSERT_FALSE(g_destroyed[0]);
+ ThreadLocal<DestructorTracker> thread_local_tracker;
+ ASSERT_EQ(0U, DestructorCall::List().size());
// This creates another DestructorTracker object in the new thread.
ThreadWithParam<ThreadParam> 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<String> thread_local;
- thread_local.set("Foo");
- EXPECT_STREQ("Foo", thread_local.get().c_str());
+ ThreadLocal<std::string> 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<HANDLE, void*>();
+}
+
+TEST(WindowsTypesTest, CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION) {
+ StaticAssertTypeEq<CRITICAL_SECTION, _RTL_CRITICAL_SECTION>();
+}
+#endif // GTEST_OS_WINDOWS
+
} // namespace internal
} // namespace testing