From b5ef9876f39067bc370b816d62bde790a92806ca Mon Sep 17 00:00:00 2001 From: "kosak@google.com" Date: Wed, 12 Mar 2014 21:03:35 +0000 Subject: Standards compliance changes to fix QNX build. git-svn-id: http://googletest.googlecode.com/svn/trunk@678 861a406c-534a-0410-8894-cb66d6ee9925 --- src/gtest-port.cc | 1 + src/gtest-printers.cc | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 0c4df5f..a43f33d 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -53,6 +53,7 @@ #if GTEST_OS_QNX # include +# include # include #endif // GTEST_OS_QNX diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index 29c799a..bb794ee 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -45,6 +45,7 @@ #include "gtest/gtest-printers.h" #include #include +#include #include // NOLINT #include #include "gtest/internal/gtest-port.h" @@ -335,7 +336,7 @@ void PrintTo(const wchar_t* s, ostream* os) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; - PrintCharsAsStringTo(s, wcslen(s), os); + PrintCharsAsStringTo(s, std::wcslen(s), os); } } #endif // wchar_t is native -- cgit v1.2.3 From cd5abba27c7809b68c89bd8d926d03ccae187eef Mon Sep 17 00:00:00 2001 From: "kosak@google.com" Date: Wed, 12 Mar 2014 22:51:07 +0000 Subject: Remove code referencing Google protocol buffers version 1. git-svn-id: http://googletest.googlecode.com/svn/trunk@679 861a406c-534a-0410-8894-cb66d6ee9925 --- test/gtest-printers_test.cc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/gtest-printers_test.cc b/test/gtest-printers_test.cc index d34a85e..9481290 100644 --- a/test/gtest-printers_test.cc +++ b/test/gtest-printers_test.cc @@ -1164,13 +1164,6 @@ TEST(PrintPrintableTypeTest, TemplateInUserNamespace) { #if GTEST_HAS_PROTOBUF_ -// Tests printing a protocol message. -TEST(PrintProtocolMessageTest, PrintsShortDebugString) { - testing::internal::TestMessage msg; - msg.set_member("yes"); - EXPECT_EQ("", Print(msg)); -} - // Tests printing a short proto2 message. TEST(PrintProto2MessageTest, PrintsShortDebugStringWhenItIsShort) { testing::internal::FooMessage msg; -- cgit v1.2.3 From e6d432cb2d1aafd47f205deac6a7c76c321dc4dd Mon Sep 17 00:00:00 2001 From: "kosak@google.com" Date: Wed, 12 Mar 2014 22:55:56 +0000 Subject: Add annotations to suppress ThreadSanitizer failures due to gunit/gmock printer. git-svn-id: http://googletest.googlecode.com/svn/trunk@680 861a406c-534a-0410-8894-cb66d6ee9925 --- include/gtest/internal/gtest-port.h | 12 ++++++++++++ src/gtest-printers.cc | 3 +++ 2 files changed, 15 insertions(+) diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index a117676..eaf1a38 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -926,6 +926,18 @@ using ::std::tuple_size; # define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ #endif // __clang__ +// A function level attribute to disable ThreadSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(thread_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ \ + __attribute__((no_sanitize_thread)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +# endif // __has_feature(thread_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +#endif // __clang__ + namespace testing { class Message; diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc index bb794ee..a2df412 100644 --- a/src/gtest-printers.cc +++ b/src/gtest-printers.cc @@ -59,6 +59,7 @@ using ::std::ostream; // Prints a segment of bytes in the given object. GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, size_t count, ostream* os) { char text[5] = ""; @@ -257,6 +258,7 @@ void PrintTo(wchar_t wc, ostream* os) { template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static void PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; @@ -280,6 +282,7 @@ static void PrintCharsAsStringTo( template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static void UniversalPrintCharArray( const CharType* begin, size_t len, ostream* os) { // The code -- cgit v1.2.3 From d132283f055f07588d82ad43fbf501645cb39c9d Mon Sep 17 00:00:00 2001 From: "kosak@google.com" Date: Mon, 24 Mar 2014 21:58:25 +0000 Subject: Implement threading support for gtest on Windows. Also, stop using localtime(). Instead, use localtime_r() on most systems, localtime_s() on Windows. git-svn-id: http://googletest.googlecode.com/svn/trunk@681 861a406c-534a-0410-8894-cb66d6ee9925 --- include/gtest/internal/gtest-port.h | 405 ++++++++++++++++++++++++++++++------ src/gtest-internal-inl.h | 26 --- src/gtest-port.cc | 391 +++++++++++++++++++++++++++++++++- src/gtest.cc | 26 +-- test/gtest-death-test_test.cc | 68 +++++- test/gtest-port_test.cc | 142 +++++++++---- test/gtest_output_test.py | 4 +- 7 files changed, 911 insertions(+), 151 deletions(-) diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index eaf1a38..7a734a2 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -379,16 +379,23 @@ // Brings in definitions for functions used in the testing::internal::posix // namespace (read, write, close, chdir, isatty, stat). We do not currently // use them on Windows Mobile. -#if !GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS_MOBILE +# include +# include +# endif +// In order to avoid having to include , use forward declaration +// assuming CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION. +// This assumption is verified by +// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION. +struct _RTL_CRITICAL_SECTION; +#else // This assumes that non-Windows OSes provide unistd.h. For OSes where this // is not the case, we need to include headers that provide the functions // mentioned above. # include # include -#elif !GTEST_OS_WINDOWS_MOBILE -# include -# include -#endif +#endif // GTEST_OS_WINDOWS #if GTEST_OS_LINUX_ANDROID // Used to define __ANDROID_API__ matching the target NDK API level. @@ -871,6 +878,9 @@ using ::std::tuple_size; # define GTEST_HAS_SEH 0 # endif +#define GTEST_IS_THREADSAFE \ + (GTEST_OS_WINDOWS || GTEST_HAS_PTHREAD) + #endif // GTEST_HAS_SEH #ifdef _MSC_VER @@ -1340,12 +1350,11 @@ extern ::std::vector g_argvs; #endif // GTEST_HAS_DEATH_TEST // Defines synchronization primitives. - -#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. +#if GTEST_IS_THREADSAFE +# if GTEST_HAS_PTHREAD +// Sleeps for (roughly) n milliseconds. 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. @@ -1353,7 +1362,10 @@ inline void SleepMilliseconds(int n) { }; nanosleep(&time, NULL); } +# endif // GTEST_HAS_PTHREAD +# if 0 // OS detection +# elif GTEST_HAS_PTHREAD // 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. @@ -1397,6 +1409,62 @@ class Notification { GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; +# elif GTEST_OS_WINDOWS + +GTEST_API_ void SleepMilliseconds(int n); + +// Provides leak-safe Windows kernel handle ownership. +// Used in death tests and in threading support. +class GTEST_API_ AutoHandle { + public: + // Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to + // avoid including in this header file. Including is + // undesirable because it defines a lot of symbols and macros that tend to + // conflict with client code. This assumption is verified by + // WindowsTypesTest.HANDLEIsVoidStar. + typedef void* Handle; + AutoHandle(); + explicit AutoHandle(Handle handle); + + ~AutoHandle(); + + Handle Get() const; + void Reset(); + void Reset(Handle handle); + + private: + // Returns true iff the handle is a valid handle object that can be closed. + bool IsCloseable() const; + + Handle handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; + +// 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 GTEST_API_ Notification { + public: + Notification(); + void Notify(); + void WaitForNotification(); + + private: + AutoHandle event_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; +# endif // OS detection + +// On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD +// defined, but we don't want to use MinGW's pthreads implementation, which +// has conformance problems with some versions of the POSIX standard. +# if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW + // As a C-function, ThreadFuncWithCLinkage cannot be templated itself. // Consequently, it cannot select a correct instantiation of ThreadWithParam // in order to call its Run(). Introducing ThreadWithParamBase as a @@ -1434,10 +1502,9 @@ extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { template class ThreadWithParam : public ThreadWithParamBase { public: - typedef void (*UserThreadFunc)(T); + typedef void UserThreadFunc(T); - ThreadWithParam( - UserThreadFunc func, T param, Notification* thread_can_start) + ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) : func_(func), param_(param), thread_can_start_(thread_can_start), @@ -1464,7 +1531,7 @@ class ThreadWithParam : public ThreadWithParamBase { } private: - const UserThreadFunc func_; // User-supplied thread function. + UserThreadFunc* const 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. @@ -1474,26 +1541,255 @@ class ThreadWithParam : public ThreadWithParamBase { GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; +# endif // GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW -// MutexBase and Mutex implement mutex on pthreads-based platforms. They -// are used in conjunction with class MutexLock: +# if 0 // OS detection +# elif GTEST_OS_WINDOWS + +// Mutex implements mutex on Windows platforms. It is used in conjunction +// with class MutexLock: // // Mutex mutex; // ... -// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end -// // of the current scope. -// -// MutexBase implements behavior for both statically and dynamically -// allocated mutexes. Do not use MutexBase directly. Instead, write -// the following to define a static mutex: +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the +// // end of the current scope. // +// A static Mutex *must* be defined or declared using one of the following +// macros: // GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// (A non-static Mutex is defined/declared in the usual way). +class GTEST_API_ Mutex { + public: + enum MutexType { kStatic = 0, kDynamic = 1 }; + // We rely on kStaticMutex being 0 as it is to what the linker initializes + // type_ in static mutexes. critical_section_ will be initialized lazily + // in ThreadSafeLazyInit(). + enum StaticConstructorSelector { kStaticMutex = 0 }; + + // This constructor intentionally does nothing. It relies on type_ being + // statically initialized to 0 (effectively setting it to kStatic) and on + // ThreadSafeLazyInit() to lazily initialize the rest of the members. + explicit Mutex(StaticConstructorSelector /*dummy*/) {} + + Mutex(); + ~Mutex(); + + void Lock(); + + void Unlock(); + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld(); + + private: + // Initializes owner_thread_id_ and critical_section_ in static mutexes. + void ThreadSafeLazyInit(); + + // Per http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx, + // we assume that 0 is an invalid value for thread IDs. + unsigned int owner_thread_id_; + + // For static mutexes, we rely on these members being initialized to zeros + // by the linker. + MutexType type_; + long critical_section_init_phase_; // NOLINT + _RTL_CRITICAL_SECTION* critical_section_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex) + +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + Mutex* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Base class for ValueHolder. Allows a caller to hold and delete a value +// without knowing its type. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Provides a way for a thread to send notifications to a ThreadLocal +// regardless of its parameter type. +class ThreadLocalBase { + public: + // Creates a new ValueHolder object holding a default value passed to + // this ThreadLocal's constructor and returns it. It is the caller's + // responsibility not to call this when the ThreadLocal instance already + // has a value on the current thread. + virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0; + + protected: + ThreadLocalBase() {} + virtual ~ThreadLocalBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocalBase); +}; + +// Maps a thread to a set of ThreadLocals that have values instantiated on that +// thread and notifies them when the thread exits. A ThreadLocal instance is +// expected to persist until all threads it has values on have terminated. +class GTEST_API_ ThreadLocalRegistry { + public: + // Registers thread_local_instance as having value on the current thread. + // Returns a value that can be used to identify the thread from other threads. + static ThreadLocalValueHolderBase* GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance); + + // Invoked when a ThreadLocal instance is destroyed. + static void OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance); +}; + +class GTEST_API_ ThreadWithParamBase { + public: + void Join(); + + protected: + class Runnable { + public: + virtual ~Runnable() {} + virtual void Run() = 0; + }; + + ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start); + virtual ~ThreadWithParamBase(); + + private: + AutoHandle thread_; +}; + +// Helper class for testing Google Test's multi-threading constructs. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void UserThreadFunc(T); + + ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) + : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) { + } + virtual ~ThreadWithParam() {} + + private: + class RunnableImpl : public Runnable { + public: + RunnableImpl(UserThreadFunc* func, T param) + : func_(func), + param_(param) { + } + virtual ~RunnableImpl() {} + virtual void Run() { + func_(param_); + } + + private: + UserThreadFunc* const func_; + const T param_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl); + }; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; + +// Implements thread-local storage on Windows systems. // -// You can forward declare a static mutex like this: +// // Thread 1 +// ThreadLocal tl(100); // 100 is the default value for each thread. // -// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// // Thread 2 +// tl.set(150); // Changes the value for thread 2 only. +// EXPECT_EQ(150, tl.get()); // -// To create a dynamic mutex, just define an object of type Mutex. +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); +// +// The template type argument T must have a public copy constructor. +// In addition, the default ThreadLocal constructor requires T to have +// a public default constructor. +// +// The users of a TheadLocal instance have to make sure that all but one +// threads (including the main one) using that instance have exited before +// destroying it. Otherwise, the per-thread objects managed for them by the +// ThreadLocal instance are not guaranteed to be destroyed on all platforms. +// +// Google Test only uses global ThreadLocal objects. That means they +// will die after main() has returned. Therefore, no per-thread +// object managed by Google Test will be leaked as long as all threads +// using Google Test have exited when main() returns. +template +class ThreadLocal : public ThreadLocalBase { + public: + ThreadLocal() : default_() {} + explicit ThreadLocal(const T& value) : default_(value) {} + + ~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of T. Can be deleted via its base class without the caller + // knowing the type of T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + + T* GetOrCreateValue() const { + return static_cast( + ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer(); + } + + virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const { + return new ValueHolder(default_); + } + + const T default_; // The default value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +# elif GTEST_HAS_PTHREAD + +// MutexBase and Mutex implement mutex on pthreads-based platforms. class MutexBase { public: // Acquires this mutex. @@ -1538,8 +1834,8 @@ class MutexBase { }; // Forward-declares a static mutex. -# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ - extern ::testing::internal::MutexBase mutex +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. // The initialization list here does not explicitly initialize each field, @@ -1547,8 +1843,8 @@ class MutexBase { // particular, the owner_ field (a pthread_t) is not explicitly initialized. // This allows initialization to work whether pthread_t is a scalar or struct. // The flag -Wmissing-field-initializers must not be specified for this to work. -# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ - ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false } +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false } // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. @@ -1566,9 +1862,11 @@ class Mutex : public MutexBase { GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; -// We cannot name this class MutexLock as the ctor declaration would +// We cannot name this class MutexLock because the ctor declaration would // conflict with a macro named MutexLock, which is defined on some -// platforms. Hence the typedef trick below. +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(MutexBase* mutex) @@ -1602,34 +1900,6 @@ extern "C" inline void DeleteThreadLocalValue(void* value_holder) { } // Implements thread-local storage on pthreads-based systems. -// -// // Thread 1 -// ThreadLocal tl(100); // 100 is the default value for each thread. -// -// // Thread 2 -// tl.set(150); // Changes the value for thread 2 only. -// EXPECT_EQ(150, tl.get()); -// -// // Thread 1 -// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. -// tl.set(200); -// EXPECT_EQ(200, tl.get()); -// -// The template type argument T must have a public copy constructor. -// In addition, the default ThreadLocal constructor requires T to have -// a public default constructor. -// -// An object managed for a thread by a ThreadLocal instance is deleted -// when the thread exits. Or, if the ThreadLocal instance dies in -// that thread, when the ThreadLocal dies. It's the user's -// responsibility to ensure that all other threads using a ThreadLocal -// have exited when it dies, or the per-thread objects for those -// threads will not be deleted. -// -// Google Test only uses global ThreadLocal objects. That means they -// will die after main() has returned. Therefore, no per-thread -// object managed by Google Test will be leaked as long as all threads -// using Google Test have exited when main() returns. template class ThreadLocal { public: @@ -1694,9 +1964,9 @@ class ThreadLocal { GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; -# define GTEST_IS_THREADSAFE 1 +# endif // OS detection -#else // GTEST_HAS_PTHREAD +#else // GTEST_IS_THREADSAFE // A dummy implementation of synchronization primitives (mutex, lock, // and thread-local variable). Necessary for compiling Google Test where @@ -1716,6 +1986,11 @@ class Mutex { # define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT @@ -1736,11 +2011,7 @@ class ThreadLocal { T value_; }; -// The above synchronization primitives have dummy implementations. -// Therefore Google Test is not thread-safe. -# define GTEST_IS_THREADSAFE 0 - -#endif // GTEST_HAS_PTHREAD +#endif // GTEST_IS_THREADSAFE // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 35df303..41fadb1 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -968,32 +968,6 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); // platform. GTEST_API_ std::string GetLastErrnoDescription(); -# if GTEST_OS_WINDOWS -// Provides leak-safe Windows kernel handle ownership. -class AutoHandle { - public: - AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} - explicit AutoHandle(HANDLE handle) : handle_(handle) {} - - ~AutoHandle() { Reset(); } - - HANDLE Get() const { return handle_; } - void Reset() { Reset(INVALID_HANDLE_VALUE); } - void Reset(HANDLE handle) { - if (handle != handle_) { - if (handle_ != INVALID_HANDLE_VALUE) - ::CloseHandle(handle_); - handle_ = handle; - } - } - - private: - HANDLE handle_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); -}; -# endif // GTEST_OS_WINDOWS - // Attempts to parse a string into a positive integer pointed to by the // number parameter. Returns true if that is possible. // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use diff --git a/src/gtest-port.cc b/src/gtest-port.cc index a43f33d..0d06d6b 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -36,14 +36,14 @@ #include #include -#if GTEST_OS_WINDOWS_MOBILE -# include // For TerminateProcess() -#elif GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS +# include # include # include +# include // Used in ThreadLocal. #else # include -#endif // GTEST_OS_WINDOWS_MOBILE +#endif // GTEST_OS_WINDOWS #if GTEST_OS_MAC # include @@ -134,6 +134,389 @@ size_t GetThreadCount() { #endif // GTEST_OS_MAC +#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS + +void SleepMilliseconds(int n) { + ::Sleep(n); +} + +AutoHandle::AutoHandle() + : handle_(INVALID_HANDLE_VALUE) {} + +AutoHandle::AutoHandle(Handle handle) + : handle_(handle) {} + +AutoHandle::~AutoHandle() { + Reset(); +} + +AutoHandle::Handle AutoHandle::Get() const { + return handle_; +} + +void AutoHandle::Reset() { + Reset(INVALID_HANDLE_VALUE); +} + +void AutoHandle::Reset(HANDLE handle) { + // Resetting with the same handle we already own is invalid. + if (handle_ != handle) { + if (IsCloseable()) { + ::CloseHandle(handle_); + } + handle_ = handle; + } else { + GTEST_CHECK_(!IsCloseable()) + << "Resetting a valid handle to itself is likely a programmer error " + "and thus not allowed."; + } +} + +bool AutoHandle::IsCloseable() const { + // Different Windows APIs may use either of these values to represent an + // invalid handle. + return handle_ != NULL && handle_ != INVALID_HANDLE_VALUE; +} + +Notification::Notification() + : event_(::CreateEvent(NULL, // Default security attributes. + TRUE, // Do not reset automatically. + FALSE, // Initially unset. + NULL)) { // Anonymous event. + GTEST_CHECK_(event_.Get() != NULL); +} + +void Notification::Notify() { + GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE); +} + +void Notification::WaitForNotification() { + GTEST_CHECK_( + ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0); +} + +Mutex::Mutex() + : type_(kDynamic), + owner_thread_id_(0), + critical_section_init_phase_(0), + critical_section_(new CRITICAL_SECTION) { + ::InitializeCriticalSection(critical_section_); +} + +Mutex::~Mutex() { + // Static mutexes are leaked intentionally. It is not thread-safe to try + // to clean them up. + // TODO(yukawa): Switch to Slim Reader/Writer (SRW) Locks, which requires + // nothing to clean it up but is available only on Vista and later. + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937.aspx + if (type_ == kDynamic) { + ::DeleteCriticalSection(critical_section_); + delete critical_section_; + critical_section_ = NULL; + } +} + +void Mutex::Lock() { + ThreadSafeLazyInit(); + ::EnterCriticalSection(critical_section_); + owner_thread_id_ = ::GetCurrentThreadId(); +} + +void Mutex::Unlock() { + ThreadSafeLazyInit(); + // We don't protect writing to owner_thread_id_ here, as it's the + // caller's responsibility to ensure that the current thread holds the + // mutex when this is called. + owner_thread_id_ = 0; + ::LeaveCriticalSection(critical_section_); +} + +// Does nothing if the current thread holds the mutex. Otherwise, crashes +// with high probability. +void Mutex::AssertHeld() { + ThreadSafeLazyInit(); + GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId()) + << "The current thread is not holding the mutex @" << this; +} + +// Initializes owner_thread_id_ and critical_section_ in static mutexes. +void Mutex::ThreadSafeLazyInit() { + // Dynamic mutexes are initialized in the constructor. + if (type_ == kStatic) { + switch ( + ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) { + case 0: + // If critical_section_init_phase_ was 0 before the exchange, we + // are the first to test it and need to perform the initialization. + owner_thread_id_ = 0; + critical_section_ = new CRITICAL_SECTION; + ::InitializeCriticalSection(critical_section_); + // Updates the critical_section_init_phase_ to 2 to signal + // initialization complete. + GTEST_CHECK_(::InterlockedCompareExchange( + &critical_section_init_phase_, 2L, 1L) == + 1L); + break; + case 1: + // Somebody else is already initializing the mutex; spin until they + // are done. + while (::InterlockedCompareExchange(&critical_section_init_phase_, + 2L, + 2L) != 2L) { + // Possibly yields the rest of the thread's time slice to other + // threads. + ::Sleep(0); + } + break; + + case 2: + break; // The mutex is already initialized and ready for use. + + default: + GTEST_CHECK_(false) + << "Unexpected value of critical_section_init_phase_ " + << "while initializing a static mutex."; + } + } +} + +namespace { + +class ThreadWithParamSupport : public ThreadWithParamBase { + public: + static HANDLE CreateThread(Runnable* runnable, + Notification* thread_can_start) { + ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); + DWORD thread_id; + // TODO(yukawa): Consider to use _beginthreadex instead. + HANDLE thread_handle = ::CreateThread( + NULL, // Default security. + 0, // Default stack size. + &ThreadWithParamSupport::ThreadMain, + param, // Parameter to ThreadMainStatic + 0x0, // Default creation flags. + &thread_id); // Need a valid pointer for the call to work under Win98. + GTEST_CHECK_(thread_handle != NULL) << "CreateThread failed with error " + << ::GetLastError() << "."; + if (thread_handle == NULL) { + delete param; + } + return thread_handle; + } + + private: + struct ThreadMainParam { + ThreadMainParam(Runnable* runnable, Notification* thread_can_start) + : runnable_(runnable), + thread_can_start_(thread_can_start) { + } + scoped_ptr runnable_; + // Does not own. + Notification* thread_can_start_; + }; + + static DWORD WINAPI ThreadMain(void* ptr) { + // Transfers ownership. + scoped_ptr param(static_cast(ptr)); + if (param->thread_can_start_ != NULL) + param->thread_can_start_->WaitForNotification(); + param->runnable_->Run(); + return 0; + } + + // Prohibit instantiation. + ThreadWithParamSupport(); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport); +}; + +} // namespace + +ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable, + Notification* thread_can_start) + : thread_(ThreadWithParamSupport::CreateThread(runnable, + thread_can_start)) { +} + +ThreadWithParamBase::~ThreadWithParamBase() { + Join(); +} + +void ThreadWithParamBase::Join() { + GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0) + << "Failed to join the thread with error " << ::GetLastError() << "."; +} + +// Maps a thread to a set of ThreadIdToThreadLocals that have values +// instantiated on that thread and notifies them when the thread exits. A +// ThreadLocal instance is expected to persist until all threads it has +// values on have terminated. +class ThreadLocalRegistryImpl { + public: + // Registers thread_local_instance as having value on the current thread. + // Returns a value that can be used to identify the thread from other threads. + static ThreadLocalValueHolderBase* GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance) { + DWORD current_thread = ::GetCurrentThreadId(); + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + ThreadIdToThreadLocals::iterator thread_local_pos = + thread_to_thread_locals->find(current_thread); + if (thread_local_pos == thread_to_thread_locals->end()) { + thread_local_pos = thread_to_thread_locals->insert( + std::make_pair(current_thread, ThreadLocalValues())).first; + StartWatcherThreadFor(current_thread); + } + ThreadLocalValues& thread_local_values = thread_local_pos->second; + ThreadLocalValues::iterator value_pos = + thread_local_values.find(thread_local_instance); + if (value_pos == thread_local_values.end()) { + value_pos = + thread_local_values + .insert(std::make_pair( + thread_local_instance, + linked_ptr( + thread_local_instance->NewValueForCurrentThread()))) + .first; + } + return value_pos->second.get(); + } + + static void OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance) { + std::vector > value_holders; + // Clean up the ThreadLocalValues data structure while holding the lock, but + // defer the destruction of the ThreadLocalValueHolderBases. + { + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + for (ThreadIdToThreadLocals::iterator it = + thread_to_thread_locals->begin(); + it != thread_to_thread_locals->end(); + ++it) { + ThreadLocalValues& thread_local_values = it->second; + ThreadLocalValues::iterator value_pos = + thread_local_values.find(thread_local_instance); + if (value_pos != thread_local_values.end()) { + value_holders.push_back(value_pos->second); + thread_local_values.erase(value_pos); + // This 'if' can only be successful at most once, so theoretically we + // could break out of the loop here, but we don't bother doing so. + } + } + } + // Outside the lock, let the destructor for 'value_holders' deallocate the + // ThreadLocalValueHolderBases. + } + + static void OnThreadExit(DWORD thread_id) { + GTEST_CHECK_(thread_id != 0) << ::GetLastError(); + std::vector > value_holders; + // Clean up the ThreadIdToThreadLocals data structure while holding the + // lock, but defer the destruction of the ThreadLocalValueHolderBases. + { + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + ThreadIdToThreadLocals::iterator thread_local_pos = + thread_to_thread_locals->find(thread_id); + if (thread_local_pos != thread_to_thread_locals->end()) { + ThreadLocalValues& thread_local_values = thread_local_pos->second; + for (ThreadLocalValues::iterator value_pos = + thread_local_values.begin(); + value_pos != thread_local_values.end(); + ++value_pos) { + value_holders.push_back(value_pos->second); + } + thread_to_thread_locals->erase(thread_local_pos); + } + } + // Outside the lock, let the destructor for 'value_holders' deallocate the + // ThreadLocalValueHolderBases. + } + + private: + // In a particular thread, maps a ThreadLocal object to its value. + typedef std::map > ThreadLocalValues; + // Stores all ThreadIdToThreadLocals having values in a thread, indexed by + // thread's ID. + typedef std::map ThreadIdToThreadLocals; + + // Holds the thread id and thread handle that we pass from + // StartWatcherThreadFor to WatcherThreadFunc. + typedef std::pair ThreadIdAndHandle; + + static void StartWatcherThreadFor(DWORD thread_id) { + // The returned handle will be kept in thread_map and closed by + // watcher_thread in WatcherThreadFunc. + HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, + FALSE, + thread_id); + GTEST_CHECK_(thread != NULL); + // We need to to pass a valid thread ID pointer into CreateThread for it + // to work correctly under Win98. + DWORD watcher_thread_id; + HANDLE watcher_thread = ::CreateThread( + NULL, // Default security. + 0, // Default stack size + &ThreadLocalRegistryImpl::WatcherThreadFunc, + reinterpret_cast(new ThreadIdAndHandle(thread_id, thread)), + CREATE_SUSPENDED, + &watcher_thread_id); + GTEST_CHECK_(watcher_thread != NULL); + // Give the watcher thread the same priority as ours to avoid being + // blocked by it. + ::SetThreadPriority(watcher_thread, + ::GetThreadPriority(::GetCurrentThread())); + ::ResumeThread(watcher_thread); + ::CloseHandle(watcher_thread); + } + + // Monitors exit from a given thread and notifies those + // ThreadIdToThreadLocals about thread termination. + static DWORD WINAPI WatcherThreadFunc(LPVOID param) { + const ThreadIdAndHandle* tah = + reinterpret_cast(param); + GTEST_CHECK_( + ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0); + OnThreadExit(tah->first); + ::CloseHandle(tah->second); + delete tah; + return 0; + } + + // Returns map of thread local instances. + static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { + mutex_.AssertHeld(); + static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals; + return map; + } + + // Protects access to GetThreadLocalsMapLocked() and its return value. + static Mutex mutex_; + // Protects access to GetThreadMapLocked() and its return value. + static Mutex thread_map_mutex_; +}; + +Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); +Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); + +ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance) { + return ThreadLocalRegistryImpl::GetValueOnCurrentThread( + thread_local_instance); +} + +void ThreadLocalRegistry::OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance) { + ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance); +} + +#endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS + #if GTEST_USES_POSIX_RE // Implements RE. Currently only needed for death tests. diff --git a/src/gtest.cc b/src/gtest.cc index 6de53dd..3aee905 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -3219,27 +3219,23 @@ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { // Converts the given epoch time in milliseconds to a date string in the ISO // 8601 format, without the timezone information. std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { - // Using non-reentrant version as localtime_r is not portable. time_t seconds = static_cast(ms / 1000); + struct tm time_struct; #ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996 - // (function or variable may be unsafe). - const struct tm* const time_struct = localtime(&seconds); // NOLINT -# pragma warning(pop) // Restores the warning state again. + if (localtime_s(&time_struct, &seconds) != 0) + return ""; // Invalid ms value #else - const struct tm* const time_struct = localtime(&seconds); // NOLINT -#endif - if (time_struct == NULL) + if (localtime_r(&seconds, &time_struct) == NULL) return ""; // Invalid ms value +#endif // YYYY-MM-DDThh:mm:ss - return StreamableToString(time_struct->tm_year + 1900) + "-" + - String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" + - String::FormatIntWidth2(time_struct->tm_mday) + "T" + - String::FormatIntWidth2(time_struct->tm_hour) + ":" + - String::FormatIntWidth2(time_struct->tm_min) + ":" + - String::FormatIntWidth2(time_struct->tm_sec); + return StreamableToString(time_struct.tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. diff --git a/test/gtest-death-test_test.cc b/test/gtest-death-test_test.cc index c2d26df..da0b84d 100644 --- a/test/gtest-death-test_test.cc +++ b/test/gtest-death-test_test.cc @@ -699,7 +699,10 @@ TEST_F(TestForDeathTest, ExpectDebugDeathDoesNotAbort) { void AssertDebugDeathHelper(bool* aborted) { *aborted = true; - ASSERT_DEBUG_DEATH(return, "") << "This is expected to fail."; + GTEST_LOG_(INFO) << "Before ASSERT_DEBUG_DEATH"; + ASSERT_DEBUG_DEATH(GTEST_LOG_(INFO) << "In ASSERT_DEBUG_DEATH"; return, "") + << "This is expected to fail."; + GTEST_LOG_(INFO) << "After ASSERT_DEBUG_DEATH"; *aborted = false; } @@ -712,6 +715,69 @@ TEST_F(TestForDeathTest, AssertDebugDeathAborts) { EXPECT_TRUE(aborted); } +TEST_F(TestForDeathTest, AssertDebugDeathAborts2) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts3) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts4) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts5) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts6) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts7) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts8) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts9) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + +TEST_F(TestForDeathTest, AssertDebugDeathAborts10) { + static bool aborted; + aborted = false; + EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); + EXPECT_TRUE(aborted); +} + # endif // _NDEBUG // Tests the *_EXIT family of macros, using a variety of predicates. diff --git a/test/gtest-port_test.cc b/test/gtest-port_test.cc index 43f1f20..370c952 100644 --- a/test/gtest-port_test.cc +++ b/test/gtest-port_test.cc @@ -1062,11 +1062,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)); @@ -1076,6 +1078,15 @@ class AtomicCounterWithMutex { 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; } @@ -1145,27 +1156,76 @@ TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) { 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; + DestructorCall::List().push_back(new DestructorCall); + return DestructorCall::List().size() - 1; } const int index_; + + GTEST_DISALLOW_ASSIGN_(DestructorTracker); }; typedef ThreadLocal* ThreadParam; @@ -1177,63 +1237,63 @@ void CallThreadLocalGet(ThreadParam thread_local_param) { // 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_tracker. ThreadLocal thread_local_tracker; - ASSERT_EQ(1U, g_destroyed.size()); - ASSERT_FALSE(g_destroyed[0]); + ASSERT_EQ(1U, DestructorCall::List().size()); + ASSERT_FALSE(DestructorCall::List()[0]->CheckDestroyed()); // This creates another DestructorTracker object for the main thread. thread_local_tracker.get(); - ASSERT_EQ(2U, g_destroyed.size()); - ASSERT_FALSE(g_destroyed[0]); - ASSERT_FALSE(g_destroyed[1]); + ASSERT_EQ(2U, DestructorCall::List().size()); + ASSERT_FALSE(DestructorCall::List()[0]->CheckDestroyed()); + ASSERT_FALSE(DestructorCall::List()[1]->CheckDestroyed()); } // Now thread_local_tracker 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]); + ASSERT_EQ(2U, DestructorCall::List().size()); + EXPECT_TRUE(DestructorCall::List()[0]->CheckDestroyed()); + EXPECT_TRUE(DestructorCall::List()[1]->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_tracker. ThreadLocal thread_local_tracker; - ASSERT_EQ(1U, g_destroyed.size()); - ASSERT_FALSE(g_destroyed[0]); + ASSERT_EQ(1U, DestructorCall::List().size()); + ASSERT_FALSE(DestructorCall::List()[0]->CheckDestroyed()); // This creates another DestructorTracker object in the new thread. ThreadWithParam thread( &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 another DestroyedTracker + // instance created for it. But it may not have been destroyed yet. + // The instance for the main thread should still persist. + ASSERT_EQ(2U, DestructorCall::List().size()); + ASSERT_FALSE(DestructorCall::List()[0]->CheckDestroyed()); } - // Now thread_local_tracker 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. The default + // value should have been destroyed too. + ASSERT_EQ(2U, DestructorCall::List().size()); + EXPECT_TRUE(DestructorCall::List()[0]->CheckDestroyed()); + EXPECT_TRUE(DestructorCall::List()[1]->CheckDestroyed()); - g_destroyed.clear(); + DestructorCall::ResetList(); } TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) { @@ -1249,5 +1309,15 @@ TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) { #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 diff --git a/test/gtest_output_test.py b/test/gtest_output_test.py index f409e2a..fa1a311 100755 --- a/test/gtest_output_test.py +++ b/test/gtest_output_test.py @@ -252,8 +252,8 @@ SUPPORTS_STACK_TRACES = False CAN_GENERATE_GOLDEN_FILE = (SUPPORTS_DEATH_TESTS and SUPPORTS_TYPED_TESTS and - SUPPORTS_THREADS) - + SUPPORTS_THREADS and + not IS_WINDOWS) class GTestOutputTest(gtest_test_utils.TestCase): def RemoveUnsupportedTests(self, test_output): -- cgit v1.2.3 From e735d74bc537869af877dfc90c171dc140495c11 Mon Sep 17 00:00:00 2001 From: "kosak@google.com" Date: Wed, 2 Apr 2014 20:26:07 +0000 Subject: Export tuple and friends in the ::testing namespace. git-svn-id: http://googletest.googlecode.com/svn/trunk@682 861a406c-534a-0410-8894-cb66d6ee9925 --- .../gtest/internal/gtest-param-util-generated.h | 78 +++++++++++----------- .../internal/gtest-param-util-generated.h.pump | 10 +-- include/gtest/internal/gtest-port.h | 21 +++++- samples/sample8_unittest.cc | 6 +- test/gtest-param-test_test.cc | 6 +- 5 files changed, 70 insertions(+), 51 deletions(-) diff --git a/include/gtest/internal/gtest-param-util-generated.h b/include/gtest/internal/gtest-param-util-generated.h index e805485..6dbaf4b 100644 --- a/include/gtest/internal/gtest-param-util-generated.h +++ b/include/gtest/internal/gtest-param-util-generated.h @@ -40,7 +40,7 @@ // and at most 10 arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited -// by the maximum arity of the implementation of tr1::tuple which is +// by the maximum arity of the implementation of tuple which is // currently set at 10. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ @@ -3157,9 +3157,9 @@ class ValueArray50 { // template class CartesianProductGenerator2 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator2(const ParamGenerator& g1, const ParamGenerator& g2) @@ -3272,9 +3272,9 @@ class CartesianProductGenerator2 template class CartesianProductGenerator3 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator3(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3) @@ -3404,9 +3404,9 @@ class CartesianProductGenerator3 template class CartesianProductGenerator4 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator4(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3555,9 +3555,9 @@ class CartesianProductGenerator4 template class CartesianProductGenerator5 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator5(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3723,10 +3723,10 @@ class CartesianProductGenerator5 template class CartesianProductGenerator6 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator6(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3909,10 +3909,10 @@ class CartesianProductGenerator6 template class CartesianProductGenerator7 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator7(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -4112,10 +4112,10 @@ class CartesianProductGenerator7 template class CartesianProductGenerator8 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator8(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -4334,10 +4334,10 @@ class CartesianProductGenerator8 template class CartesianProductGenerator9 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator9(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -4573,10 +4573,10 @@ class CartesianProductGenerator9 template class CartesianProductGenerator10 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator10(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -4838,8 +4838,8 @@ class CartesianProductHolder2 { CartesianProductHolder2(const Generator1& g1, const Generator2& g2) : g1_(g1), g2_(g2) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator2( static_cast >(g1_), static_cast >(g2_))); @@ -4860,8 +4860,8 @@ CartesianProductHolder3(const Generator1& g1, const Generator2& g2, const Generator3& g3) : g1_(g1), g2_(g2), g3_(g3) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator3( static_cast >(g1_), static_cast >(g2_), @@ -4885,8 +4885,8 @@ CartesianProductHolder4(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator4( static_cast >(g1_), static_cast >(g2_), @@ -4912,8 +4912,8 @@ CartesianProductHolder5(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator5( static_cast >(g1_), static_cast >(g2_), @@ -4943,8 +4943,8 @@ CartesianProductHolder6(const Generator1& g1, const Generator2& g2, : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator6( static_cast >(g1_), static_cast >(g2_), @@ -4976,9 +4976,9 @@ CartesianProductHolder7(const Generator1& g1, const Generator2& g2, : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator7( static_cast >(g1_), static_cast >(g2_), @@ -5014,9 +5014,9 @@ CartesianProductHolder8(const Generator1& g1, const Generator2& g2, g8_(g8) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator8( static_cast >(g1_), static_cast >(g2_), @@ -5055,9 +5055,9 @@ CartesianProductHolder9(const Generator1& g1, const Generator2& g2, g9_(g9) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator9( static_cast >(g1_), @@ -5099,10 +5099,10 @@ CartesianProductHolder10(const Generator1& g1, const Generator2& g2, g9_(g9), g10_(g10) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator10( static_cast >(g1_), diff --git a/include/gtest/internal/gtest-param-util-generated.h.pump b/include/gtest/internal/gtest-param-util-generated.h.pump index 009206f..801a2fc 100644 --- a/include/gtest/internal/gtest-param-util-generated.h.pump +++ b/include/gtest/internal/gtest-param-util-generated.h.pump @@ -39,7 +39,7 @@ $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // and at most $maxtuple arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited -// by the maximum arity of the implementation of tr1::tuple which is +// by the maximum arity of the implementation of tuple which is // currently set at $maxtuple. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ @@ -128,9 +128,9 @@ $range k 2..i template <$for j, [[typename T$j]]> class CartesianProductGenerator$i - : public ParamGeneratorInterface< ::std::tr1::tuple<$for j, [[T$j]]> > { + : public ParamGeneratorInterface< ::testing::tuple<$for j, [[T$j]]> > { public: - typedef ::std::tr1::tuple<$for j, [[T$j]]> ParamType; + typedef ::testing::tuple<$for j, [[T$j]]> ParamType; CartesianProductGenerator$i($for j, [[const ParamGenerator& g$j]]) : $for j, [[g$(j)_(g$j)]] {} @@ -269,8 +269,8 @@ class CartesianProductHolder$i { CartesianProductHolder$i($for j, [[const Generator$j& g$j]]) : $for j, [[g$(j)_(g$j)]] {} template <$for j, [[typename T$j]]> - operator ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >() const { - return ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >( + operator ParamGenerator< ::testing::tuple<$for j, [[T$j]]> >() const { + return ParamGenerator< ::testing::tuple<$for j, [[T$j]]> >( new CartesianProductGenerator$i<$for j, [[T$j]]>( $for j,[[ diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index 7a734a2..7ac4a5d 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -640,8 +640,18 @@ struct _RTL_CRITICAL_SECTION; // To avoid conditional compilation everywhere, we make it // gtest-port.h's responsibility to #include the header implementing -// tr1/tuple. +// tuple. +// TODO(sbenza): Enable this block to start using std::tuple instead of +// std::tr1::tuple. +#if 0 && GTEST_HAS_STD_TUPLE_ +# include +# define GTEST_TUPLE_NAMESPACE_ ::std +#endif + #if GTEST_HAS_TR1_TUPLE +# ifndef GTEST_TUPLE_NAMESPACE_ +# define GTEST_TUPLE_NAMESPACE_ ::std::tr1 +# endif // GTEST_TUPLE_NAMESPACE_ # if GTEST_USE_OWN_TR1_TUPLE # include "gtest/internal/gtest-tuple.h" @@ -952,6 +962,15 @@ namespace testing { class Message; +// Import tuple and friends into the ::testing namespace. +// It is part of our interface, having them in ::testing allows us to change +// their types as needed. +using GTEST_TUPLE_NAMESPACE_::get; +using GTEST_TUPLE_NAMESPACE_::make_tuple; +using GTEST_TUPLE_NAMESPACE_::tuple; +using GTEST_TUPLE_NAMESPACE_::tuple_size; +using GTEST_TUPLE_NAMESPACE_::tuple_element; + namespace internal { // A secret type that Google Test users don't know about. It has no diff --git a/samples/sample8_unittest.cc b/samples/sample8_unittest.cc index 5ad2e2c..7274334 100644 --- a/samples/sample8_unittest.cc +++ b/samples/sample8_unittest.cc @@ -90,7 +90,7 @@ using ::testing::Combine; // PreCalculatedPrimeTable disabled. We do this by defining fixture which will // accept different combinations of parameters for instantiating a // HybridPrimeTable instance. -class PrimeTableTest : public TestWithParam< ::std::tr1::tuple > { +class PrimeTableTest : public TestWithParam< ::testing::tuple > { protected: virtual void SetUp() { // This can be written as @@ -101,8 +101,8 @@ class PrimeTableTest : public TestWithParam< ::std::tr1::tuple > { // // once the Google C++ Style Guide allows use of ::std::tr1::tie. // - bool force_on_the_fly = ::std::tr1::get<0>(GetParam()); - int max_precalculated = ::std::tr1::get<1>(GetParam()); + bool force_on_the_fly = ::testing::get<0>(GetParam()); + int max_precalculated = ::testing::get<1>(GetParam()); table_ = new HybridPrimeTable(force_on_the_fly, max_precalculated); } virtual void TearDown() { diff --git a/test/gtest-param-test_test.cc b/test/gtest-param-test_test.cc index f60cb8a..cc1dc65 100644 --- a/test/gtest-param-test_test.cc +++ b/test/gtest-param-test_test.cc @@ -64,9 +64,9 @@ using ::testing::ValuesIn; # if GTEST_HAS_COMBINE using ::testing::Combine; -using ::std::tr1::get; -using ::std::tr1::make_tuple; -using ::std::tr1::tuple; +using ::testing::get; +using ::testing::make_tuple; +using ::testing::tuple; # endif // GTEST_HAS_COMBINE using ::testing::internal::ParamGenerator; -- cgit v1.2.3 From f0d7f455d0ba1b1da1891c3ee54961a162e8fbc4 Mon Sep 17 00:00:00 2001 From: "billydonahue@google.com" Date: Thu, 15 May 2014 19:42:15 +0000 Subject: Push upstream to SVN. git-svn-id: http://googletest.googlecode.com/svn/trunk@686 861a406c-534a-0410-8894-cb66d6ee9925 --- include/gtest/gtest-printers.h | 22 ++----- include/gtest/gtest.h | 42 +++++++++----- include/gtest/internal/gtest-internal.h | 79 +++++++++++++------------ include/gtest/internal/gtest-port.h | 100 +++++++++++++++++++++----------- src/gtest-filepath.cc | 2 +- src/gtest-port.cc | 9 +-- src/gtest.cc | 43 ++++++-------- test/gtest-death-test_test.cc | 70 ++++++++++------------ test/gtest-printers_test.cc | 7 ++- test/gtest_premature_exit_test.cc | 4 +- test/gtest_unittest.cc | 66 +++++++++++++-------- 11 files changed, 241 insertions(+), 203 deletions(-) diff --git a/include/gtest/gtest-printers.h b/include/gtest/gtest-printers.h index 852d44a..18ee7bc 100644 --- a/include/gtest/gtest-printers.h +++ b/include/gtest/gtest-printers.h @@ -593,10 +593,7 @@ class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4180) // Temporarily disables warning 4180. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) // Note: we deliberately don't call this PrintTo(), as that name // conflicts with ::testing::internal::PrintTo in the body of the @@ -613,9 +610,7 @@ class UniversalPrinter { PrintTo(value, os); } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() }; // UniversalPrintArray(begin, len, os) prints an array of 'len' @@ -667,10 +662,7 @@ class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4180) // Temporarily disables warning 4180. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) static void Print(const T& value, ::std::ostream* os) { // Prints the address of the value. We use reinterpret_cast here @@ -681,9 +673,7 @@ class UniversalPrinter { UniversalPrint(value, os); } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() }; // Prints a value tersely: for a reference type, the referenced value @@ -835,9 +825,9 @@ struct TuplePrefixPrinter { template static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { TuplePrefixPrinter::PrintPrefixTo(t, os); - GTEST_INTENTIONAL_CONST_COND_PUSH_ + GTEST_INTENTIONAL_CONST_COND_PUSH_() if (N > 1) { - GTEST_INTENTIONAL_CONST_COND_POP_ + GTEST_INTENTIONAL_CONST_COND_POP_() *os << ", "; } UniversalPrinter< diff --git a/include/gtest/gtest.h b/include/gtest/gtest.h index 6fa0a39..a19b3db 100644 --- a/include/gtest/gtest.h +++ b/include/gtest/gtest.h @@ -258,8 +258,31 @@ class GTEST_API_ AssertionResult { // Copy constructor. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult(const AssertionResult& other); + + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) + // Used in the EXPECT_TRUE/FALSE(bool_expression). - explicit AssertionResult(bool success) : success_(success) {} + // + // T must be contextually convertible to bool. + // + // The second parameter prevents this overload from being considered if + // the argument is implicitly convertible to AssertionResult. In that case + // we want AssertionResult's copy constructor to be used. + template + explicit AssertionResult( + const T& success, + typename internal::EnableIf< + !internal::ImplicitlyConvertible::value>::type* + /*enabler*/ = NULL) + : success_(success) {} + + GTEST_DISABLE_MSC_WARNINGS_POP_() + + // Assignment operator. + AssertionResult& operator=(AssertionResult other) { + swap(other); + return *this; + } // Returns true iff the assertion succeeded. operator bool() const { return success_; } // NOLINT @@ -300,6 +323,9 @@ class GTEST_API_ AssertionResult { message_->append(a_message.GetString().c_str()); } + // Swap the contents of this AssertionResult with other. + void swap(AssertionResult& other); + // Stores result of the assertion predicate. bool success_; // Stores the message describing the condition in case the expectation @@ -307,8 +333,6 @@ class GTEST_API_ AssertionResult { // Referenced via a pointer to avoid taking too much stack frame space // with test assertions. internal::scoped_ptr< ::std::string> message_; - - GTEST_DISALLOW_ASSIGN_(AssertionResult); }; // Makes a successful assertion result. @@ -1439,19 +1463,11 @@ AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4389) // Temporarily disables warning on - // signed/unsigned mismatch. -#endif - +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4389 /* signed/unsigned mismatch */) if (expected == actual) { return AssertionSuccess(); } - -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif +GTEST_DISABLE_MSC_WARNINGS_POP_() return EqFailure(expected_expression, actual_expression, diff --git a/include/gtest/internal/gtest-internal.h b/include/gtest/internal/gtest-internal.h index f58f65f..ff8f629 100644 --- a/include/gtest/internal/gtest-internal.h +++ b/include/gtest/internal/gtest-internal.h @@ -802,25 +802,20 @@ class ImplicitlyConvertible { // We have to put the 'public' section after the 'private' section, // or MSVC refuses to compile the code. public: - // MSVC warns about implicitly converting from double to int for - // possible loss of data, so we need to temporarily disable the - // warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4244) // Temporarily disables warning 4244. - - static const bool value = - sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; -# pragma warning(pop) // Restores the warning state. -#elif defined(__BORLANDC__) +#if defined(__BORLANDC__) // C++Builder cannot use member overload resolution during template // instantiation. The simplest workaround is to use its C++0x type traits // functions (C++Builder 2009 and above only). static const bool value = __is_convertible(From, To); #else + // MSVC warns about implicitly converting from double to int for + // possible loss of data, so we need to temporarily disable the + // warning. + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4244) static const bool value = sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; -#endif // _MSV_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif // __BORLANDC__ }; template const bool ImplicitlyConvertible::value; @@ -946,11 +941,10 @@ void CopyArray(const T* from, size_t size, U* to) { // The relation between an NativeArray object (see below) and the // native array it represents. -enum RelationToSource { - kReference, // The NativeArray references the native array. - kCopy // The NativeArray makes a copy of the native array and - // owns the copy. -}; +// We use 2 different structs to allow non-copyable types to be used, as long +// as RelationToSourceReference() is passed. +struct RelationToSourceReference {}; +struct RelationToSourceCopy {}; // Adapts a native array to a read-only STL-style container. Instead // of the complete STL container concept, this adaptor only implements @@ -968,22 +962,23 @@ class NativeArray { typedef Element* iterator; typedef const Element* const_iterator; - // Constructs from a native array. - NativeArray(const Element* array, size_t count, RelationToSource relation) { - Init(array, count, relation); + // Constructs from a native array. References the source. + NativeArray(const Element* array, size_t count, RelationToSourceReference) { + InitRef(array, count); + } + + // Constructs from a native array. Copies the source. + NativeArray(const Element* array, size_t count, RelationToSourceCopy) { + InitCopy(array, count); } // Copy constructor. NativeArray(const NativeArray& rhs) { - Init(rhs.array_, rhs.size_, rhs.relation_to_source_); + (this->*rhs.clone_)(rhs.array_, rhs.size_); } ~NativeArray() { - // Ensures that the user doesn't instantiate NativeArray with a - // const or reference type. - static_cast(StaticAssertTypeEqHelper()); - if (relation_to_source_ == kCopy) + if (clone_ != &NativeArray::InitRef) delete[] array_; } @@ -997,23 +992,30 @@ class NativeArray { } private: - // Initializes this object; makes a copy of the input array if - // 'relation' is kCopy. - void Init(const Element* array, size_t a_size, RelationToSource relation) { - if (relation == kReference) { - array_ = array; - } else { - Element* const copy = new Element[a_size]; - CopyArray(array, a_size, copy); - array_ = copy; - } + enum { + kCheckTypeIsNotConstOrAReference = StaticAssertTypeEqHelper< + Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value, + }; + + // Initializes this object with a copy of the input. + void InitCopy(const Element* array, size_t a_size) { + Element* const copy = new Element[a_size]; + CopyArray(array, a_size, copy); + array_ = copy; size_ = a_size; - relation_to_source_ = relation; + clone_ = &NativeArray::InitCopy; + } + + // Initializes this object with a reference of the input. + void InitRef(const Element* array, size_t a_size) { + array_ = array; + size_ = a_size; + clone_ = &NativeArray::InitRef; } const Element* array_; size_t size_; - RelationToSource relation_to_source_; + void (NativeArray::*clone_)(const Element*, size_t); GTEST_DISALLOW_ASSIGN_(NativeArray); }; @@ -1156,3 +1158,4 @@ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ + diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index 7ac4a5d..efb479d 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -136,6 +136,8 @@ // GTEST_OS_WINDOWS_DESKTOP - Windows Desktop // GTEST_OS_WINDOWS_MINGW - MinGW // GTEST_OS_WINDOWS_MOBILE - Windows Mobile +// GTEST_OS_WINDOWS_PHONE - Windows Phone +// GTEST_OS_WINDOWS_RT - Windows Store App/WinRT // GTEST_OS_ZOS - z/OS // // Among the platforms, Cygwin, Linux, Max OS X, and Windows have the @@ -269,6 +271,7 @@ # include #endif +#include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT @@ -299,6 +302,19 @@ # define GTEST_OS_WINDOWS_MOBILE 1 # elif defined(__MINGW__) || defined(__MINGW32__) # define GTEST_OS_WINDOWS_MINGW 1 +# elif defined(WINAPI_FAMILY) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define GTEST_OS_WINDOWS_DESKTOP 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) +# define GTEST_OS_WINDOWS_PHONE 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +# define GTEST_OS_WINDOWS_RT 1 +# else + // WINAPI_FAMILY defined but no known partition matched. + // Default to desktop. +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif # else # define GTEST_OS_WINDOWS_DESKTOP 1 # endif // _WIN32_WCE @@ -331,6 +347,23 @@ # define GTEST_OS_QNX 1 #endif // __CYGWIN__ +// Macros for disabling Microsoft Visual C++ warnings. +// +// GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385) +// /* code that triggers warnings C4800 and C4385 */ +// GTEST_DISABLE_MSC_WARNINGS_POP_() +#if _MSC_VER >= 1500 +# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ + __pragma(warning(push)) \ + __pragma(warning(disable: warnings)) +# define GTEST_DISABLE_MSC_WARNINGS_POP_() \ + __pragma(warning(pop)) +#else +// Older versions of MSVC don't have __pragma. +# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) +# define GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + #ifndef GTEST_LANG_CXX11 // gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when // -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a @@ -641,20 +674,20 @@ struct _RTL_CRITICAL_SECTION; // To avoid conditional compilation everywhere, we make it // gtest-port.h's responsibility to #include the header implementing // tuple. -// TODO(sbenza): Enable this block to start using std::tuple instead of -// std::tr1::tuple. -#if 0 && GTEST_HAS_STD_TUPLE_ -# include +#if GTEST_HAS_STD_TUPLE_ +# include // IWYU pragma: export # define GTEST_TUPLE_NAMESPACE_ ::std -#endif +#endif // GTEST_HAS_STD_TUPLE_ +// We include tr1::tuple even if std::tuple is available to define printers for +// them. #if GTEST_HAS_TR1_TUPLE # ifndef GTEST_TUPLE_NAMESPACE_ # define GTEST_TUPLE_NAMESPACE_ ::std::tr1 # endif // GTEST_TUPLE_NAMESPACE_ # if GTEST_USE_OWN_TR1_TUPLE -# include "gtest/internal/gtest-tuple.h" +# include "gtest/internal/gtest-tuple.h" // IWYU pragma: export // NOLINT # elif GTEST_ENV_HAS_STD_TUPLE_ # include // C++11 puts its tuple into the ::std namespace rather than @@ -685,7 +718,7 @@ using ::std::tuple_size; // This prevents , which defines // BOOST_HAS_TR1_TUPLE, from being #included by Boost's . # define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED -# include +# include // IWYU pragma: export // NOLINT # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) // GCC 4.0+ implements tr1/tuple in the header. This does @@ -708,7 +741,7 @@ using ::std::tuple_size; # else // If the compiler is not GCC 4.0+, we assume the user is using a // spec-conforming TR1 implementation. -# include // NOLINT +# include // IWYU pragma: export // NOLINT # endif // GTEST_USE_OWN_TR1_TUPLE #endif // GTEST_HAS_TR1_TUPLE @@ -742,7 +775,8 @@ using ::std::tuple_size; #ifndef GTEST_HAS_STREAM_REDIRECTION // By default, we assume that stream redirection is supported on all // platforms except known mobile ones. -# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || \ + GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT # define GTEST_HAS_STREAM_REDIRECTION 0 # else # define GTEST_HAS_STREAM_REDIRECTION 1 @@ -859,20 +893,14 @@ using ::std::tuple_size; // constant. In some contexts this warning is false positive and needs to be // suppressed. Use the following two macros in such cases: // -// GTEST_INTENTIONAL_CONST_COND_PUSH_ +// GTEST_INTENTIONAL_CONST_COND_PUSH_() // while (true) { -// GTEST_INTENTIONAL_CONST_COND_POP_ +// GTEST_INTENTIONAL_CONST_COND_POP_() // } -#if defined(_MSC_VER) -# define GTEST_INTENTIONAL_CONST_COND_PUSH_ \ - __pragma(warning(push)) \ - __pragma(warning(disable: 4127)) -# define GTEST_INTENTIONAL_CONST_COND_POP_ \ - __pragma(warning(pop)) -#else -# define GTEST_INTENTIONAL_CONST_COND_PUSH_ -# define GTEST_INTENTIONAL_CONST_COND_POP_ -#endif +# define GTEST_INTENTIONAL_CONST_COND_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127) +# define GTEST_INTENTIONAL_CONST_COND_POP_() \ + GTEST_DISABLE_MSC_WARNINGS_POP_() // Determine whether the compiler supports Microsoft's Structured Exception // Handling. This is supported by several Windows compilers but generally @@ -962,6 +990,7 @@ namespace testing { class Message; +#if defined(GTEST_TUPLE_NAMESPACE_) // Import tuple and friends into the ::testing namespace. // It is part of our interface, having them in ::testing allows us to change // their types as needed. @@ -970,6 +999,7 @@ using GTEST_TUPLE_NAMESPACE_::make_tuple; using GTEST_TUPLE_NAMESPACE_::tuple; using GTEST_TUPLE_NAMESPACE_::tuple_size; using GTEST_TUPLE_NAMESPACE_::tuple_element; +#endif // defined(GTEST_TUPLE_NAMESPACE_) namespace internal { @@ -1049,7 +1079,9 @@ template struct StaticAssertTypeEqHelper; template -struct StaticAssertTypeEqHelper {}; +struct StaticAssertTypeEqHelper { + enum { value = true }; +}; // Evaluates to the number of elements in 'array'. #define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0])) @@ -1101,6 +1133,11 @@ class scoped_ptr { } } + friend void swap(scoped_ptr& a, scoped_ptr& b) { + using std::swap; + swap(a.ptr_, b.ptr_); + } + private: T* ptr_; @@ -1312,9 +1349,9 @@ inline To DownCast_(From* f) { // so we only accept pointers // for compile-time type checking, and has no overhead in an // optimized build at run-time, as it will be optimized away // completely. - GTEST_INTENTIONAL_CONST_COND_PUSH_ + GTEST_INTENTIONAL_CONST_COND_PUSH_() if (false) { - GTEST_INTENTIONAL_CONST_COND_POP_ + GTEST_INTENTIONAL_CONST_COND_POP_() const To to = NULL; ::testing::internal::ImplicitCast_(to); } @@ -2203,11 +2240,7 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } // Functions deprecated by MSVC 8.0. -#ifdef _MSC_VER -// Temporarily disable warning 4996 (deprecated function). -# pragma warning(push) -# pragma warning(disable:4996) -#endif +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* deprecated function */) inline const char* StrNCpy(char* dest, const char* src, size_t n) { return strncpy(dest, src, n); @@ -2217,7 +2250,7 @@ inline const char* StrNCpy(char* dest, const char* src, size_t n) { // StrError() aren't needed on Windows CE at this time and thus not // defined there. -#if !GTEST_OS_WINDOWS_MOBILE +#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT inline int ChDir(const char* dir) { return chdir(dir); } #endif inline FILE* FOpen(const char* path, const char* mode) { @@ -2241,7 +2274,7 @@ inline int Close(int fd) { return close(fd); } inline const char* StrError(int errnum) { return strerror(errnum); } #endif inline const char* GetEnv(const char* name) { -#if GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE | GTEST_OS_WINDOWS_RT // We are on Windows CE, which has no environment variables. return NULL; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) @@ -2254,9 +2287,7 @@ inline const char* GetEnv(const char* name) { #endif } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif +GTEST_DISABLE_MSC_WARNINGS_POP_() #if GTEST_OS_WINDOWS_MOBILE // Windows CE has no C library. The abort() function is used in @@ -2396,3 +2427,4 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index d221cfd..219875c 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -97,7 +97,7 @@ static bool IsPathSeparator(char c) { // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { -#if GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT // Windows CE doesn't have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 0d06d6b..39e70bb 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -886,10 +886,7 @@ GTestLog::~GTestLog() { } // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4996) -#endif // _MSC_VER +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) #if GTEST_HAS_STREAM_REDIRECTION @@ -1008,9 +1005,7 @@ std::string CapturedStream::ReadEntireFile(FILE* file) { return content; } -# ifdef _MSC_VER -# pragma warning(pop) -# endif // _MSC_VER +GTEST_DISABLE_MSC_WARNINGS_POP_() static CapturedStream* g_captured_stderr = NULL; static CapturedStream* g_captured_stdout = NULL; diff --git a/src/gtest.cc b/src/gtest.cc index 3aee905..408e6f2 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -802,21 +802,13 @@ TimeInMillis GetTimeInMillis() { #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; -# ifdef _MSC_VER - // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. // TODO(kenton@google.com): Use GetTickCount()? Or use // SystemTimeToFileTime() -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996. - _ftime64(&now); -# pragma warning(pop) // Restores the warning state. -# else - + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) _ftime64(&now); - -# endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ @@ -956,6 +948,13 @@ AssertionResult::AssertionResult(const AssertionResult& other) static_cast< ::std::string*>(NULL)) { } +// Swaps two AssertionResults. +void AssertionResult::swap(AssertionResult& other) { + using std::swap; + swap(success_, other.success_); + swap(message_, other.message_); +} + // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); @@ -2554,7 +2553,8 @@ enum GTestColor { COLOR_YELLOW }; -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // Returns the character attribute for the given color. WORD GetColorAttribute(GTestColor color) { @@ -2622,7 +2622,8 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || \ + GTEST_OS_IOS || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT const bool use_color = false; #else static const bool in_color_mode = @@ -2637,7 +2638,8 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { return; } -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. @@ -3808,7 +3810,7 @@ void UnitTest::AddTestPartResult( // with another testing framework) and specify the former on the // command line for debugging. if (GTEST_FLAG(break_on_failure)) { -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // Using DebugBreak on Windows allows gtest to still break into a debugger // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. @@ -3886,7 +3888,7 @@ int UnitTest::Run() { // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected. if (impl()->catch_exceptions() || in_death_test_child_process) { -# if !GTEST_OS_WINDOWS_MOBILE +# if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); @@ -3989,17 +3991,10 @@ namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4355) // Temporarily disables warning 4355 - // (using this in initializer). - default_global_test_part_result_reporter_(this), - default_per_thread_test_part_result_reporter_(this), -# pragma warning(pop) // Restores the warning state again. -#else + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */) default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( diff --git a/test/gtest-death-test_test.cc b/test/gtest-death-test_test.cc index da0b84d..b25bc22 100644 --- a/test/gtest-death-test_test.cc +++ b/test/gtest-death-test_test.cc @@ -326,12 +326,9 @@ TEST_F(TestForDeathTest, EmbeddedNulInMessage) { // Tests that death test macros expand to code which interacts well with switch // statements. TEST_F(TestForDeathTest, SwitchStatement) { -// Microsoft compiler usually complains about switch statements without -// case labels. We suppress that warning for this test. -# ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4065) -# endif // _MSC_VER + // Microsoft compiler usually complains about switch statements without + // case labels. We suppress that warning for this test. + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4065) switch (0) default: @@ -341,9 +338,7 @@ TEST_F(TestForDeathTest, SwitchStatement) { case 0: EXPECT_DEATH(_exit(1), "") << "exit in switch case"; -# ifdef _MSC_VER -# pragma warning(pop) -# endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() } // Tests that a static member function can be used in a "fast" style @@ -1304,7 +1299,27 @@ TEST(ConditionalDeathMacrosDeathTest, ExpectsDeathWhenDeathTestsAvailable) { EXPECT_FATAL_FAILURE(ASSERT_DEATH_IF_SUPPORTED(;, ""), ""); } -#else +TEST(InDeathTestChildDeathTest, ReportsDeathTestCorrectlyInFastStyle) { + testing::GTEST_FLAG(death_test_style) = "fast"; + EXPECT_FALSE(InDeathTestChild()); + EXPECT_DEATH({ + fprintf(stderr, InDeathTestChild() ? "Inside" : "Outside"); + fflush(stderr); + _exit(1); + }, "Inside"); +} + +TEST(InDeathTestChildDeathTest, ReportsDeathTestCorrectlyInThreadSafeStyle) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; + EXPECT_FALSE(InDeathTestChild()); + EXPECT_DEATH({ + fprintf(stderr, InDeathTestChild() ? "Inside" : "Outside"); + fflush(stderr); + _exit(1); + }, "Inside"); +} + +#else // !GTEST_HAS_DEATH_TEST follows using testing::internal::CaptureStderr; using testing::internal::GetCapturedStderr; @@ -1354,27 +1369,7 @@ TEST(ConditionalDeathMacrosTest, AssertDeatDoesNotReturnhIfUnsupported) { EXPECT_EQ(1, n); } -TEST(InDeathTestChildDeathTest, ReportsDeathTestCorrectlyInFastStyle) { - testing::GTEST_FLAG(death_test_style) = "fast"; - EXPECT_FALSE(InDeathTestChild()); - EXPECT_DEATH({ - fprintf(stderr, InDeathTestChild() ? "Inside" : "Outside"); - fflush(stderr); - _exit(1); - }, "Inside"); -} - -TEST(InDeathTestChildDeathTest, ReportsDeathTestCorrectlyInThreadSafeStyle) { - testing::GTEST_FLAG(death_test_style) = "threadsafe"; - EXPECT_FALSE(InDeathTestChild()); - EXPECT_DEATH({ - fprintf(stderr, InDeathTestChild() ? "Inside" : "Outside"); - fflush(stderr); - _exit(1); - }, "Inside"); -} - -#endif // GTEST_HAS_DEATH_TEST +#endif // !GTEST_HAS_DEATH_TEST // Tests that the death test macros expand to code which may or may not // be followed by operator<<, and that in either case the complete text @@ -1405,12 +1400,9 @@ TEST(ConditionalDeathMacrosSyntaxDeathTest, SingleStatement) { // Tests that conditional death test macros expand to code which interacts // well with switch statements. TEST(ConditionalDeathMacrosSyntaxDeathTest, SwitchStatement) { -// Microsoft compiler usually complains about switch statements without -// case labels. We suppress that warning for this test. -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4065) -#endif // _MSC_VER + // Microsoft compiler usually complains about switch statements without + // case labels. We suppress that warning for this test. + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4065) switch (0) default: @@ -1421,9 +1413,7 @@ TEST(ConditionalDeathMacrosSyntaxDeathTest, SwitchStatement) { case 0: EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << "exit in switch case"; -#ifdef _MSC_VER -# pragma warning(pop) -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() } // Tests that a test case whose name ends with "DeathTest" works fine diff --git a/test/gtest-printers_test.cc b/test/gtest-printers_test.cc index 9481290..7b07fd1 100644 --- a/test/gtest-printers_test.cc +++ b/test/gtest-printers_test.cc @@ -202,12 +202,12 @@ using ::testing::internal::FormatForComparisonFailureMessage; using ::testing::internal::ImplicitCast_; using ::testing::internal::NativeArray; using ::testing::internal::RE; +using ::testing::internal::RelationToSourceReference; using ::testing::internal::Strings; using ::testing::internal::UniversalPrint; using ::testing::internal::UniversalPrinter; using ::testing::internal::UniversalTersePrint; using ::testing::internal::UniversalTersePrintTupleFieldsToStrings; -using ::testing::internal::kReference; using ::testing::internal::string; // The hash_* classes are not part of the C++ standard. STLport @@ -946,13 +946,13 @@ TEST(PrintStlContainerTest, NestedContainer) { TEST(PrintStlContainerTest, OneDimensionalNativeArray) { const int a[3] = { 1, 2, 3 }; - NativeArray b(a, 3, kReference); + NativeArray b(a, 3, RelationToSourceReference()); EXPECT_EQ("{ 1, 2, 3 }", Print(b)); } TEST(PrintStlContainerTest, TwoDimensionalNativeArray) { const int a[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; - NativeArray b(a, 2, kReference); + NativeArray b(a, 2, RelationToSourceReference()); EXPECT_EQ("{ { 1, 2, 3 }, { 4, 5, 6 } }", Print(b)); } @@ -1648,3 +1648,4 @@ TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsTersely) { } // namespace gtest_printers_test } // namespace testing + diff --git a/test/gtest_premature_exit_test.cc b/test/gtest_premature_exit_test.cc index fcfc623..c1ed968 100644 --- a/test/gtest_premature_exit_test.cc +++ b/test/gtest_premature_exit_test.cc @@ -100,9 +100,9 @@ TEST_F(PrematureExitDeathTest, FileExistsDuringExecutionOfDeathTest) { // Tests that TEST_PREMATURE_EXIT_FILE is set where it's expected to // be set. TEST_F(PrematureExitTest, TestPrematureExitFileEnvVarIsSet) { - GTEST_INTENTIONAL_CONST_COND_PUSH_ + GTEST_INTENTIONAL_CONST_COND_PUSH_() if (kTestPrematureExitFileEnvVarShouldBeSet) { - GTEST_INTENTIONAL_CONST_COND_POP_ + GTEST_INTENTIONAL_CONST_COND_POP_() const char* const filepath = GetEnv("TEST_PREMATURE_EXIT_FILE"); ASSERT_TRUE(filepath != NULL); ASSERT_NE(*filepath, '\0'); diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index 0cab07d..6cccd01 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -233,7 +233,6 @@ using testing::TestProperty; using testing::TestResult; using testing::TimeInMillis; using testing::UnitTest; -using testing::kMaxStackTraceDepth; using testing::internal::AddReference; using testing::internal::AlwaysFalse; using testing::internal::AlwaysTrue; @@ -267,6 +266,8 @@ using testing::internal::IsContainerTest; using testing::internal::IsNotContainer; using testing::internal::NativeArray; using testing::internal::ParseInt32Flag; +using testing::internal::RelationToSourceCopy; +using testing::internal::RelationToSourceReference; using testing::internal::RemoveConst; using testing::internal::RemoveReference; using testing::internal::ShouldRunTestOnShard; @@ -281,11 +282,10 @@ using testing::internal::TestEventListenersAccessor; using testing::internal::TestResultAccessor; using testing::internal::UInt32; using testing::internal::WideStringToUtf8; -using testing::internal::kCopy; using testing::internal::kMaxRandomSeed; -using testing::internal::kReference; using testing::internal::kTestTypeIdInGoogleTest; using testing::internal::scoped_ptr; +using testing::kMaxStackTraceDepth; #if GTEST_HAS_STREAM_REDIRECTION using testing::internal::CaptureStdout; @@ -417,19 +417,11 @@ class FormatEpochTimeInMillisAsIso8601Test : public Test { private: virtual void SetUp() { saved_tz_ = NULL; -#if _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996 - // (function or variable may be unsafe - // for getenv, function is deprecated for - // strdup). - if (getenv("TZ")) - saved_tz_ = strdup(getenv("TZ")); -# pragma warning(pop) // Restores the warning state again. -#else + + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* getenv, strdup: deprecated */) if (getenv("TZ")) saved_tz_ = strdup(getenv("TZ")); -#endif + GTEST_DISABLE_MSC_WARNINGS_POP_() // Set up the time zone for FormatEpochTimeInMillisAsIso8601 to use. We // cannot use the local time zone because the function's output depends @@ -453,11 +445,9 @@ class FormatEpochTimeInMillisAsIso8601Test : public Test { const std::string env_var = std::string("TZ=") + (time_zone ? time_zone : ""); _putenv(env_var.c_str()); -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996 - // (function is deprecated). + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* deprecated function */) tzset(); -# pragma warning(pop) // Restores the warning state again. + GTEST_DISABLE_MSC_WARNINGS_POP_() #else if (time_zone) { setenv(("TZ"), time_zone, 1); @@ -5026,6 +5016,31 @@ TEST(AssertionResultTest, CanStreamOstreamManipulators) { EXPECT_STREQ("Data\n\\0Will be visible", r.message()); } +// The next test uses explicit conversion operators -- a C++11 feature. +#if GTEST_LANG_CXX11 + +TEST(AssertionResultTest, ConstructibleFromContextuallyConvertibleToBool) { + struct ExplicitlyConvertibleToBool { + explicit operator bool() const { return value; } + bool value; + }; + ExplicitlyConvertibleToBool v1 = {false}; + ExplicitlyConvertibleToBool v2 = {true}; + EXPECT_FALSE(v1); + EXPECT_TRUE(v2); +} + +#endif // GTEST_LANG_CXX11 + +struct ConvertibleToAssertionResult { + operator AssertionResult() const { return AssertionResult(true); } +}; + +TEST(AssertionResultTest, ConstructibleFromImplicitlyConvertible) { + ConvertibleToAssertionResult obj; + EXPECT_TRUE(obj); +} + // Tests streaming a user type whose definition and operator << are // both in the global namespace. class Base { @@ -7327,7 +7342,7 @@ TEST(CopyArrayTest, WorksForTwoDimensionalArrays) { TEST(NativeArrayTest, ConstructorFromArrayWorks) { const int a[3] = { 0, 1, 2 }; - NativeArray na(a, 3, kReference); + NativeArray na(a, 3, RelationToSourceReference()); EXPECT_EQ(3U, na.size()); EXPECT_EQ(a, na.begin()); } @@ -7337,7 +7352,7 @@ TEST(NativeArrayTest, CreatesAndDeletesCopyOfArrayWhenAskedTo) { Array* a = new Array[1]; (*a)[0] = 0; (*a)[1] = 1; - NativeArray na(*a, 2, kCopy); + NativeArray na(*a, 2, RelationToSourceCopy()); EXPECT_NE(*a, na.begin()); delete[] a; EXPECT_EQ(0, na.begin()[0]); @@ -7357,7 +7372,7 @@ TEST(NativeArrayTest, TypeMembersAreCorrect) { TEST(NativeArrayTest, MethodsWork) { const int a[3] = { 0, 1, 2 }; - NativeArray na(a, 3, kCopy); + NativeArray na(a, 3, RelationToSourceCopy()); ASSERT_EQ(3U, na.size()); EXPECT_EQ(3, na.end() - na.begin()); @@ -7372,18 +7387,18 @@ TEST(NativeArrayTest, MethodsWork) { EXPECT_TRUE(na == na); - NativeArray na2(a, 3, kReference); + NativeArray na2(a, 3, RelationToSourceReference()); EXPECT_TRUE(na == na2); const int b1[3] = { 0, 1, 1 }; const int b2[4] = { 0, 1, 2, 3 }; - EXPECT_FALSE(na == NativeArray(b1, 3, kReference)); - EXPECT_FALSE(na == NativeArray(b2, 4, kCopy)); + EXPECT_FALSE(na == NativeArray(b1, 3, RelationToSourceReference())); + EXPECT_FALSE(na == NativeArray(b2, 4, RelationToSourceCopy())); } TEST(NativeArrayTest, WorksForTwoDimensionalArray) { const char a[2][3] = { "hi", "lo" }; - NativeArray na(a, 2, kReference); + NativeArray na(a, 2, RelationToSourceReference()); ASSERT_EQ(2U, na.size()); EXPECT_EQ(a, na.begin()); } @@ -7413,3 +7428,4 @@ TEST(SkipPrefixTest, DoesNotSkipWhenPrefixDoesNotMatch) { EXPECT_FALSE(SkipPrefix("world!", &p)); EXPECT_EQ(str, p); } + -- cgit v1.2.3 From 041a4cefa9db0af77307eca5183c8a7c86d44dba Mon Sep 17 00:00:00 2001 From: "kosak@google.com" Date: Tue, 17 Jun 2014 23:16:37 +0000 Subject: Disable asan instrumentation for StackGrowsDown(). git-svn-id: http://googletest.googlecode.com/svn/trunk@688 861a406c-534a-0410-8894-cb66d6ee9925 --- src/gtest-death-test.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index a6023fc..69fe7c1 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -985,6 +985,8 @@ void StackLowerThanAddress(const void* ptr, bool* result) { *result = (&dummy < ptr); } +// Make sure AddressSanitizer does not tamper with the stack here. +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ bool StackGrowsDown() { int dummy; bool result; -- cgit v1.2.3 From 2f9c469cd2ac136ca4b496b8682a316ce6bf466d Mon Sep 17 00:00:00 2001 From: "kosak@google.com" Date: Wed, 18 Jun 2014 00:22:42 +0000 Subject: Reduce the number of occurrences of gendered pronouns in gtest. git-svn-id: http://googletest.googlecode.com/svn/trunk@689 861a406c-534a-0410-8894-cb66d6ee9925 --- include/gtest/gtest.h | 22 +++++++++++----------- src/gtest-death-test.cc | 6 +++--- src/gtest-internal-inl.h | 2 +- src/gtest-port.cc | 6 +++--- src/gtest-test-part.cc | 6 +++--- src/gtest.cc | 8 ++++---- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/include/gtest/gtest.h b/include/gtest/gtest.h index a19b3db..38ca3e9 100644 --- a/include/gtest/gtest.h +++ b/include/gtest/gtest.h @@ -70,14 +70,14 @@ // class ::string, which has the same interface as ::std::string, but // has a different implementation. // -// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that +// You can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that // ::string is available AND is a distinct type to ::std::string, or // define it to 0 to indicate otherwise. // -// If the user's ::std::string and ::string are the same class due to -// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. +// If ::std::string and ::string are the same class on your platform +// due to aliasing, you should define GTEST_HAS_GLOBAL_STRING to 0. // -// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined +// If you do not define GTEST_HAS_GLOBAL_STRING, it is defined // heuristically. namespace testing { @@ -455,17 +455,17 @@ class GTEST_API_ Test { // Uses a GTestFlagSaver to save and restore all Google Test flags. const internal::GTestFlagSaver* const gtest_flag_saver_; - // Often a user mis-spells SetUp() as Setup() and spends a long time + // Often a user misspells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of // the following method is solely for catching such an error at // compile time: // // - The return type is deliberately chosen to be not void, so it - // will be a conflict if a user declares void Setup() in his test - // fixture. + // will be a conflict if void Setup() is declared in the user's + // test fixture. // // - This method is private, so it will be another compiler error - // if a user calls it from his test fixture. + // if the method is called from the user's test fixture. // // DO NOT OVERRIDE THIS FUNCTION. // @@ -948,7 +948,7 @@ class GTEST_API_ TestCase { }; // An Environment object is capable of setting up and tearing down an -// environment. The user should subclass this to define his own +// environment. You should subclass this to define your own // environment(s). // // An Environment object does the set-up and tear-down in virtual @@ -2231,8 +2231,8 @@ bool StaticAssertTypeEq() { // The convention is to end the test case name with "Test". For // example, a test case for the Foo class can be named FooTest. // -// The user should put his test code between braces after using this -// macro. Example: +// Test code should appear between braces after an invocation of +// this macro. Example: // // TEST(FooTest, InitializesCorrectly) { // Foo foo; diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc index 69fe7c1..a0a8c7b 100644 --- a/src/gtest-death-test.cc +++ b/src/gtest-death-test.cc @@ -68,9 +68,9 @@ // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. +// included, or there will be a compiler error. This trick exists to +// prevent the accidental inclusion of gtest-internal-inl.h in the +// user's code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 41fadb1..0ac7a10 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -40,7 +40,7 @@ // GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is // part of Google Test's implementation; otherwise it's undefined. #if !GTEST_IMPLEMENTATION_ -// A user is trying to include this from his code - just say no. +// If this file is included from the user's code, just say no. # error "gtest-internal-inl.h is part of Google Test's internal implementation." # error "It must not be included except by Google Test itself." #endif // GTEST_IMPLEMENTATION_ diff --git a/src/gtest-port.cc b/src/gtest-port.cc index 39e70bb..b032745 100644 --- a/src/gtest-port.cc +++ b/src/gtest-port.cc @@ -64,9 +64,9 @@ // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. +// included, or there will be a compiler error. This trick exists to +// prevent the accidental inclusion of gtest-internal-inl.h in the +// user's code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index c60eef3..fb0e354 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -35,9 +35,9 @@ // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. +// included, or there will be a compiler error. This trick exists to +// prevent the accidental inclusion of gtest-internal-inl.h in the +// user's code. #define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ diff --git a/src/gtest.cc b/src/gtest.cc index 408e6f2..ca3596e 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -1962,8 +1962,8 @@ bool Test::HasSameFixtureClass() { const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { - // The user mixed TEST and TEST_F in this test case - we'll tell - // him/her how to fix it. + // Both TEST and TEST_F appear in same test case, which is incorrect. + // Tell the user how to fix this. // Gets the name of the TEST and the name of the TEST_F. Note // that first_is_TEST and this_is_TEST cannot both be true, as @@ -1983,8 +1983,8 @@ bool Test::HasSameFixtureClass() { << "want to change the TEST to TEST_F or move it to another test\n" << "case."; } else { - // The user defined two fixture classes with the same name in - // two namespaces - we'll tell him/her how to fix it. + // Two fixture classes with the same name appear in two different + // namespaces, which is not allowed. Tell the user how to fix this. ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " -- cgit v1.2.3 From 0476e154db5fab1721c2a0f32abf4aa773679b52 Mon Sep 17 00:00:00 2001 From: "kosak@google.com" Date: Wed, 18 Jun 2014 21:31:01 +0000 Subject: Additional changes, to add support for Windows Phone and Windows RT git-svn-id: http://googletest.googlecode.com/svn/trunk@690 861a406c-534a-0410-8894-cb66d6ee9925 --- include/gtest/internal/gtest-port.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index efb479d..f376dfa 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -917,7 +917,9 @@ using ::std::tuple_size; # endif #define GTEST_IS_THREADSAFE \ - (GTEST_OS_WINDOWS || GTEST_HAS_PTHREAD) + (0 \ + || (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) \ + || GTEST_HAS_PTHREAD) #endif // GTEST_HAS_SEH @@ -1465,7 +1467,7 @@ class Notification { GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; -# elif GTEST_OS_WINDOWS +# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT GTEST_API_ void SleepMilliseconds(int n); @@ -1600,7 +1602,7 @@ class ThreadWithParam : public ThreadWithParamBase { # endif // GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW # if 0 // OS detection -# elif GTEST_OS_WINDOWS +# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // Mutex implements mutex on Windows platforms. It is used in conjunction // with class MutexLock: -- cgit v1.2.3 From d9abf3b04db54a8081365ab131aeb0943b5aab36 Mon Sep 17 00:00:00 2001 From: "kosak@google.com" Date: Mon, 28 Jul 2014 21:54:50 +0000 Subject: Expand equality failure messages with a by-line diff. git-svn-id: http://googletest.googlecode.com/svn/trunk@691 861a406c-534a-0410-8894-cb66d6ee9925 --- include/gtest/internal/gtest-internal.h | 32 ++++ src/gtest.cc | 285 ++++++++++++++++++++++++++++++++ test/gtest_output_test_.cc | 5 + test/gtest_output_test_golden_lin.txt | 22 ++- test/gtest_unittest.cc | 94 +++++++++++ 5 files changed, 433 insertions(+), 5 deletions(-) diff --git a/include/gtest/internal/gtest-internal.h b/include/gtest/internal/gtest-internal.h index ff8f629..21a0f56 100644 --- a/include/gtest/internal/gtest-internal.h +++ b/include/gtest/internal/gtest-internal.h @@ -56,6 +56,8 @@ #include #include #include +#include +#include #include "gtest/gtest-message.h" #include "gtest/internal/gtest-string.h" @@ -171,6 +173,36 @@ class GTEST_API_ ScopedTrace { // c'tor and d'tor. Therefore it doesn't // need to be used otherwise. +namespace edit_distance { +// Returns the optimal edits to go from 'left' to 'right'. +// All edits cost the same, with replace having lower priority than +// add/remove. +// Simple implementation of the Wagner–Fischer algorithm. +// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm +enum EditType { kMatch, kAdd, kRemove, kReplace }; +GTEST_API_ std::vector CalculateOptimalEdits( + const std::vector& left, const std::vector& right); + +// Same as above, but the input is represented as strings. +GTEST_API_ std::vector CalculateOptimalEdits( + const std::vector& left, + const std::vector& right); + +// Create a diff of the input strings in Unified diff format. +GTEST_API_ std::string CreateUnifiedDiff(const std::vector& left, + const std::vector& right, + size_t context = 2); + +} // namespace edit_distance + +// Calculate the diff between 'left' and 'right' and return it in unified diff +// format. +// If not null, stores in 'total_line_count' the total number of lines found +// in left + right. +GTEST_API_ std::string DiffStrings(const std::string& left, + const std::string& right, + size_t* total_line_count); + // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // diff --git a/src/gtest.cc b/src/gtest.cc index ca3596e..e4f3df3 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include // NOLINT #include #include @@ -80,6 +82,7 @@ #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. # include // NOLINT +# undef min #elif GTEST_OS_WINDOWS // We are on Windows proper. @@ -102,6 +105,7 @@ // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT +# undef min #else @@ -981,6 +985,276 @@ AssertionResult AssertionFailure(const Message& message) { namespace internal { +namespace edit_distance { +std::vector CalculateOptimalEdits(const std::vector& left, + const std::vector& right) { + std::vector > costs( + left.size() + 1, std::vector(right.size() + 1)); + std::vector > best_move( + left.size() + 1, std::vector(right.size() + 1)); + + // Populate for empty right. + for (size_t l_i = 0; l_i < costs.size(); ++l_i) { + costs[l_i][0] = static_cast(l_i); + best_move[l_i][0] = kRemove; + } + // Populate for empty left. + for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) { + costs[0][r_i] = static_cast(r_i); + best_move[0][r_i] = kAdd; + } + + for (size_t l_i = 0; l_i < left.size(); ++l_i) { + for (size_t r_i = 0; r_i < right.size(); ++r_i) { + if (left[l_i] == right[r_i]) { + // Found a match. Consume it. + costs[l_i + 1][r_i + 1] = costs[l_i][r_i]; + best_move[l_i + 1][r_i + 1] = kMatch; + continue; + } + + const double add = costs[l_i + 1][r_i]; + const double remove = costs[l_i][r_i + 1]; + const double replace = costs[l_i][r_i]; + if (add < remove && add < replace) { + costs[l_i + 1][r_i + 1] = add + 1; + best_move[l_i + 1][r_i + 1] = kAdd; + } else if (remove < add && remove < replace) { + costs[l_i + 1][r_i + 1] = remove + 1; + best_move[l_i + 1][r_i + 1] = kRemove; + } else { + // We make replace a little more expensive than add/remove to lower + // their priority. + costs[l_i + 1][r_i + 1] = replace + 1.00001; + best_move[l_i + 1][r_i + 1] = kReplace; + } + } + } + + // Reconstruct the best path. We do it in reverse order. + std::vector best_path; + for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) { + EditType move = best_move[l_i][r_i]; + best_path.push_back(move); + l_i -= move != kAdd; + r_i -= move != kRemove; + } + std::reverse(best_path.begin(), best_path.end()); + return best_path; +} + +namespace { + +// Helper class to convert string into ids with deduplication. +class InternalStrings { + public: + size_t GetId(const std::string& str) { + IdMap::iterator it = ids_.find(str); + if (it != ids_.end()) return it->second; + size_t id = ids_.size(); + return ids_[str] = id; + } + + private: + typedef std::map IdMap; + IdMap ids_; +}; + +} // namespace + +std::vector CalculateOptimalEdits( + const std::vector& left, + const std::vector& right) { + std::vector left_ids, right_ids; + { + InternalStrings intern_table; + for (size_t i = 0; i < left.size(); ++i) { + left_ids.push_back(intern_table.GetId(left[i])); + } + for (size_t i = 0; i < right.size(); ++i) { + right_ids.push_back(intern_table.GetId(right[i])); + } + } + return CalculateOptimalEdits(left_ids, right_ids); +} + +namespace { + +// Helper class that holds the state for one hunk and prints it out to the +// stream. +// It reorders adds/removes when possible to group all removes before all +// adds. It also adds the hunk header before printint into the stream. +class Hunk { + public: + Hunk(size_t left_start, size_t right_start) + : left_start_(left_start), + right_start_(right_start), + adds_(), + removes_(), + common_() {} + + void PushLine(char edit, const char* line) { + switch (edit) { + case ' ': + ++common_; + FlushEdits(); + hunk_.push_back(std::make_pair(' ', line)); + break; + case '-': + ++removes_; + hunk_removes_.push_back(std::make_pair('-', line)); + break; + case '+': + ++adds_; + hunk_adds_.push_back(std::make_pair('+', line)); + break; + } + } + + void PrintTo(std::ostream* os) { + PrintHeader(os); + FlushEdits(); + for (std::list >::const_iterator it = + hunk_.begin(); + it != hunk_.end(); ++it) { + *os << it->first << it->second << "\n"; + } + } + + bool has_edits() const { return adds_ || removes_; } + + private: + void FlushEdits() { + hunk_.splice(hunk_.end(), hunk_removes_); + hunk_.splice(hunk_.end(), hunk_adds_); + } + + // Print a unified diff header for one hunk. + // The format is + // "@@ -, +, @@" + // where the left/right parts are ommitted if unnecessary. + void PrintHeader(std::ostream* ss) const { + *ss << "@@ "; + if (removes_) { + *ss << "-" << left_start_ << "," << (removes_ + common_); + } + if (removes_ && adds_) { + *ss << " "; + } + if (adds_) { + *ss << "+" << right_start_ << "," << (adds_ + common_); + } + *ss << " @@\n"; + } + + size_t left_start_, right_start_; + size_t adds_, removes_, common_; + std::list > hunk_, hunk_adds_, hunk_removes_; +}; + +} // namespace + +// Create a list of diff hunks in Unified diff format. +// Each hunk has a header generated by PrintHeader above plus a body with +// lines prefixed with ' ' for no change, '-' for deletion and '+' for +// addition. +// 'context' represents the desired unchanged prefix/suffix around the diff. +// If two hunks are close enough that their contexts overlap, then they are +// joined into one hunk. +std::string CreateUnifiedDiff(const std::vector& left, + const std::vector& right, + size_t context) { + const std::vector edits = CalculateOptimalEdits(left, right); + + size_t l_i = 0, r_i = 0, edit_i = 0; + std::stringstream ss; + while (edit_i < edits.size()) { + // Find first edit. + while (edit_i < edits.size() && edits[edit_i] == kMatch) { + ++l_i; + ++r_i; + ++edit_i; + } + + // Find the first line to include in the hunk. + const size_t prefix_context = std::min(l_i, context); + Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1); + for (size_t i = prefix_context; i > 0; --i) { + hunk.PushLine(' ', left[l_i - i].c_str()); + } + + // Iterate the edits until we found enough suffix for the hunk or the input + // is over. + size_t n_suffix = 0; + for (; edit_i < edits.size(); ++edit_i) { + if (n_suffix >= context) { + // Continue only if the next hunk is very close. + std::vector::const_iterator it = edits.begin() + edit_i; + while (it != edits.end() && *it == kMatch) ++it; + if (it == edits.end() || (it - edits.begin()) - edit_i >= context) { + // There is no next edit or it is too far away. + break; + } + } + + EditType edit = edits[edit_i]; + // Reset count when a non match is found. + n_suffix = edit == kMatch ? n_suffix + 1 : 0; + + if (edit == kMatch || edit == kRemove || edit == kReplace) { + hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str()); + } + if (edit == kAdd || edit == kReplace) { + hunk.PushLine('+', right[r_i].c_str()); + } + + // Advance indices, depending on edit type. + l_i += edit != kAdd; + r_i += edit != kRemove; + } + + if (!hunk.has_edits()) { + // We are done. We don't want this hunk. + break; + } + + hunk.PrintTo(&ss); + } + return ss.str(); +} + +} // namespace edit_distance + +namespace { + +// The string representation of the values received in EqFailure() are already +// escaped. Split them on escaped '\n' boundaries. Leave all other escaped +// characters the same. +std::vector SplitEscapedString(const std::string& str) { + std::vector lines; + size_t start = 0, end = str.size(); + if (end > 2 && str[0] == '"' && str[end - 1] == '"') { + ++start; + --end; + } + bool escaped = false; + for (size_t i = start; i + 1 < end; ++i) { + if (escaped) { + escaped = false; + if (str[i] == 'n') { + lines.push_back(str.substr(start, i - start - 1)); + start = i + 1; + } + } else { + escaped = str[i] == '\\'; + } + } + lines.push_back(str.substr(start, end - start)); + return lines; +} + +} // namespace + // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // @@ -1015,6 +1289,17 @@ AssertionResult EqFailure(const char* expected_expression, msg << "\nWhich is: " << expected_value; } + if (!expected_value.empty() && !actual_value.empty()) { + const std::vector expected_lines = + SplitEscapedString(expected_value); + const std::vector actual_lines = + SplitEscapedString(actual_value); + if (expected_lines.size() > 1 || actual_lines.size() > 1) { + msg << "\nWith diff:\n" + << edit_distance::CreateUnifiedDiff(expected_lines, actual_lines); + } + } + return AssertionFailure() << msg; } diff --git a/test/gtest_output_test_.cc b/test/gtest_output_test_.cc index 07ab633..5361d8d 100644 --- a/test/gtest_output_test_.cc +++ b/test/gtest_output_test_.cc @@ -113,6 +113,11 @@ TEST(NonfatalFailureTest, EscapesStringOperands) { EXPECT_EQ(golden, actual); } +TEST(NonfatalFailureTest, DiffForLongStrings) { + std::string golden_str(kGoldenString, sizeof(kGoldenString) - 1); + EXPECT_EQ(golden_str, "Line 2"); +} + // Tests catching a fatal failure in a subroutine. TEST(FatalFailureTest, FatalFailureInSubroutine) { printf("(expecting a failure that x should be 1)\n"); diff --git a/test/gtest_output_test_golden_lin.txt b/test/gtest_output_test_golden_lin.txt index 960eedc..da54170 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 63 tests from 28 test cases. +[==========] Running 64 tests from 28 test cases. [----------] Global test environment set-up. FooEnvironment::SetUp() called. BarEnvironment::SetUp() called. @@ -31,7 +31,7 @@ BarEnvironment::SetUp() called. [ OK ] PassingTest.PassingTest1 [ RUN ] PassingTest.PassingTest2 [ OK ] PassingTest.PassingTest2 -[----------] 1 test from NonfatalFailureTest +[----------] 2 tests from NonfatalFailureTest [ RUN ] NonfatalFailureTest.EscapesStringOperands gtest_output_test_.cc:#: Failure Value of: actual @@ -44,6 +44,17 @@ Value of: actual Expected: golden Which is: "\"Line" [ FAILED ] NonfatalFailureTest.EscapesStringOperands +[ RUN ] NonfatalFailureTest.DiffForLongStrings +gtest_output_test_.cc:#: Failure +Value of: "Line 2" +Expected: golden_str +Which is: "\"Line\0 1\"\nLine 2" +With diff: +@@ -1,2 @@ +-\"Line\0 1\" + Line 2 + +[ FAILED ] NonfatalFailureTest.DiffForLongStrings [----------] 3 tests from FatalFailureTest [ RUN ] FatalFailureTest.FatalFailureInSubroutine (expecting a failure that x should be 1) @@ -599,10 +610,11 @@ FooEnvironment::TearDown() called. gtest_output_test_.cc:#: Failure Failed Expected fatal failure. -[==========] 63 tests from 28 test cases ran. +[==========] 64 tests from 28 test cases ran. [ PASSED ] 21 tests. -[ FAILED ] 42 tests, listed below: +[ FAILED ] 43 tests, listed below: [ FAILED ] NonfatalFailureTest.EscapesStringOperands +[ FAILED ] NonfatalFailureTest.DiffForLongStrings [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine [ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine @@ -645,7 +657,7 @@ Expected fatal failure. [ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread [ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2 -42 FAILED TESTS +43 FAILED TESTS  YOU HAVE 1 DISABLED TEST Note: Google Test filter = FatalFailureTest.*:LoggingTest.* diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index 6cccd01..42638ce 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -282,6 +282,9 @@ using testing::internal::TestEventListenersAccessor; using testing::internal::TestResultAccessor; using testing::internal::UInt32; using testing::internal::WideStringToUtf8; +using testing::internal::edit_distance::CalculateOptimalEdits; +using testing::internal::edit_distance::CreateUnifiedDiff; +using testing::internal::edit_distance::EditType; using testing::internal::kMaxRandomSeed; using testing::internal::kTestTypeIdInGoogleTest; using testing::internal::scoped_ptr; @@ -3431,6 +3434,79 @@ TEST_F(NoFatalFailureTest, MessageIsStreamable) { // Tests non-string assertions. +std::string EditsToString(const std::vector& edits) { + std::string out; + for (size_t i = 0; i < edits.size(); ++i) { + static const char kEdits[] = " +-/"; + out.append(1, kEdits[edits[i]]); + } + return out; +} + +std::vector CharsToIndices(const std::string& str) { + std::vector out; + for (size_t i = 0; i < str.size(); ++i) { + out.push_back(str[i]); + } + return out; +} + +std::vector CharsToLines(const std::string& str) { + std::vector out; + for (size_t i = 0; i < str.size(); ++i) { + out.push_back(str.substr(i, 1)); + } + return out; +} + +TEST(EditDistance, TestCases) { + struct Case { + int line; + const char* left; + const char* right; + const char* expected_edits; + const char* expected_diff; + }; + static const Case kCases[] = { + // No change. + {__LINE__, "A", "A", " ", ""}, + {__LINE__, "ABCDE", "ABCDE", " ", ""}, + // Simple adds. + {__LINE__, "X", "XA", " +", "@@ +1,2 @@\n X\n+A\n"}, + {__LINE__, "X", "XABCD", " ++++", "@@ +1,5 @@\n X\n+A\n+B\n+C\n+D\n"}, + // Simple removes. + {__LINE__, "XA", "X", " -", "@@ -1,2 @@\n X\n-A\n"}, + {__LINE__, "XABCD", "X", " ----", "@@ -1,5 @@\n X\n-A\n-B\n-C\n-D\n"}, + // Simple replaces. + {__LINE__, "A", "a", "/", "@@ -1,1 +1,1 @@\n-A\n+a\n"}, + {__LINE__, "ABCD", "abcd", "////", + "@@ -1,4 +1,4 @@\n-A\n-B\n-C\n-D\n+a\n+b\n+c\n+d\n"}, + // Path finding. + {__LINE__, "ABCDEFGH", "ABXEGH1", " -/ - +", + "@@ -1,8 +1,7 @@\n A\n B\n-C\n-D\n+X\n E\n-F\n G\n H\n+1\n"}, + {__LINE__, "AAAABCCCC", "ABABCDCDC", "- / + / ", + "@@ -1,9 +1,9 @@\n-A\n A\n-A\n+B\n A\n B\n C\n+D\n C\n-C\n+D\n C\n"}, + {__LINE__, "ABCDE", "BCDCD", "- +/", + "@@ -1,5 +1,5 @@\n-A\n B\n C\n D\n-E\n+C\n+D\n"}, + {__LINE__, "ABCDEFGHIJKL", "BCDCDEFGJKLJK", "- ++ -- ++", + "@@ -1,4 +1,5 @@\n-A\n B\n+C\n+D\n C\n D\n" + "@@ -6,7 +7,7 @@\n F\n G\n-H\n-I\n J\n K\n L\n+J\n+K\n"}, + {}}; + for (const Case* c = kCases; c->left; ++c) { + EXPECT_TRUE(c->expected_edits == + EditsToString(CalculateOptimalEdits(CharsToIndices(c->left), + CharsToIndices(c->right)))) + << "Left <" << c->left << "> Right <" << c->right << "> Edits <" + << EditsToString(CalculateOptimalEdits( + CharsToIndices(c->left), CharsToIndices(c->right))) << ">"; + EXPECT_TRUE(c->expected_diff == CreateUnifiedDiff(CharsToLines(c->left), + CharsToLines(c->right))) + << "Left <" << c->left << "> Right <" << c->right << "> Diff <" + << CreateUnifiedDiff(CharsToLines(c->left), CharsToLines(c->right)) + << ">"; + } +} + // Tests EqFailure(), used for implementing *EQ* assertions. TEST(AssertionTest, EqFailure) { const std::string foo_val("5"), bar_val("6"); @@ -3481,6 +3557,24 @@ TEST(AssertionTest, EqFailure) { msg5.c_str()); } +TEST(AssertionTest, EqFailureWithDiff) { + const std::string left( + "1\\n2XXX\\n3\\n5\\n6\\n7\\n8\\n9\\n10\\n11\\n12XXX\\n13\\n14\\n15"); + const std::string right( + "1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\\n11\\n12\\n13\\n14"); + const std::string msg1( + EqFailure("left", "right", left, right, false).failure_message()); + EXPECT_STREQ( + "Value of: right\n" + " Actual: 1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\\n11\\n12\\n13\\n14\n" + "Expected: left\n" + "Which is: " + "1\\n2XXX\\n3\\n5\\n6\\n7\\n8\\n9\\n10\\n11\\n12XXX\\n13\\n14\\n15\n" + "With diff:\n@@ -1,5 +1,6 @@\n 1\n-2XXX\n+2\n 3\n+4\n 5\n 6\n" + "@@ -7,8 +8,6 @@\n 8\n 9\n-10\n 11\n-12XXX\n+12\n 13\n 14\n-15\n", + msg1.c_str()); +} + // Tests AppendUserMessage(), used for implementing the *EQ* macros. TEST(AssertionTest, AppendUserMessage) { const std::string foo("foo"); -- cgit v1.2.3 From 4650552ff637bb44ecf7784060091cbed3252211 Mon Sep 17 00:00:00 2001 From: "kosak@google.com" Date: Tue, 29 Jul 2014 00:30:10 +0000 Subject: Mock out GetCurrentDir in NaCl. git-svn-id: http://googletest.googlecode.com/svn/trunk@692 861a406c-534a-0410-8894-cb66d6ee9925 --- src/gtest-filepath.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/gtest-filepath.cc b/src/gtest-filepath.cc index 219875c..0292dc1 100644 --- a/src/gtest-filepath.cc +++ b/src/gtest-filepath.cc @@ -106,7 +106,14 @@ FilePath FilePath::GetCurrentDir() { return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); + char* result = getcwd(cwd, sizeof(cwd)); +# if GTEST_OS_NACL + // getcwd will likely fail in NaCl due to the sandbox, so return something + // reasonable. The user may have provided a shim implementation for getcwd, + // however, so fallback only when failure is detected. + return FilePath(result == NULL ? kCurrentDirectoryString : cwd); +# endif // GTEST_OS_NACL + return FilePath(result == NULL ? "" : cwd); #endif // GTEST_OS_WINDOWS_MOBILE } -- cgit v1.2.3