diff options
author | Sam McCall <sam.mccall@gmail.com> | 2018-02-12 10:20:09 +0000 |
---|---|---|
committer | Sam McCall <sam.mccall@gmail.com> | 2018-02-12 10:20:09 +0000 |
commit | 4d4c57240a75bc23e21de906c4fae160baebe275 (patch) | |
tree | dab79bb691fa50d4569d90cb7a79eceadaae1e37 /utils/unittest | |
parent | 289fcee6332d0878c17d1b299493dadd0f302d31 (diff) |
[gtest] Support raw_ostream printing functions more comprehensively.
Summary:
These are functions like operator<<(raw_ostream&, Foo).
Previously these were only supported for messages. In the assertion
EXPECT_EQ(A, B) << C;
the local modifications would explicitly try to use raw_ostream printing for C.
However A and B would look for a std::ostream printing function, and often fall
back to gtest's default "168 byte object <00 01 FE 42 ...>".
This patch pulls out the raw_ostream support into a new header under `custom/`.
I changed the mechanism: instead of a convertible stream, we wrap the printed
value in a proxy object to allow it to be sent to a std::ostream.
I think the new way is clearer.
I also changed the policy: we prefer raw_ostream printers over std::ostream
ones. This is because the fallback printers are defined using std::ostream,
while all the raw_ostream printers should be "good".
Reviewers: ilya-biryukov, chandlerc
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D43091
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@324876 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils/unittest')
3 files changed, 79 insertions, 41 deletions
diff --git a/utils/unittest/googletest/include/gtest/gtest-message.h b/utils/unittest/googletest/include/gtest/gtest-message.h index 47ed669a9b1..30cb5ed6993 100644 --- a/utils/unittest/googletest/include/gtest/gtest-message.h +++ b/utils/unittest/googletest/include/gtest/gtest-message.h @@ -49,36 +49,7 @@ #include <limits> #include "gtest/internal/gtest-port.h" - -#if !GTEST_NO_LLVM_RAW_OSTREAM -#include "llvm/Support/raw_os_ostream.h" - -// LLVM INTERNAL CHANGE: To allow operator<< to work with both -// std::ostreams and LLVM's raw_ostreams, we define a special -// std::ostream with an implicit conversion to raw_ostream& and stream -// to that. This causes the compiler to prefer std::ostream overloads -// but still find raw_ostream& overloads. -namespace llvm { -class convertible_fwd_ostream : public std::ostream { - raw_os_ostream ros_; - -public: - convertible_fwd_ostream(std::ostream& os) - : std::ostream(os.rdbuf()), ros_(*this) {} - operator raw_ostream&() { return ros_; } -}; -} -template <typename T> -inline void GTestStreamToHelper(std::ostream& os, const T& val) { - llvm::convertible_fwd_ostream cos(os); - cos << val; -} -#else -template <typename T> -inline void GTestStreamToHelper(std::ostream& os, const T& val) { - os << val; -} -#endif +#include "gtest/internal/custom/raw-ostream.h" // Ensures that there is at least one operator<< in the global namespace. // See Message& operator<<(...) below for why. @@ -157,12 +128,8 @@ class GTEST_API_ Message { // from the global namespace. With this using declaration, // overloads of << defined in the global namespace and those // visible via Koenig lookup are both exposed in this function. -#if GTEST_NO_LLVM_RAW_OSTREAM using ::operator <<; - *ss_ << val; -#else - ::GTestStreamToHelper(*ss_, val); -#endif + *ss_ << llvm_gtest::printable(val); return *this; } @@ -184,11 +151,7 @@ class GTEST_API_ Message { if (pointer == NULL) { *ss_ << "(null)"; } else { -#if GTEST_NO_LLVM_RAW_OSTREAM - *ss_ << pointer; -#else - ::GTestStreamToHelper(*ss_, pointer); -#endif + *ss_ << llvm_gtest::printable(pointer); } return *this; } diff --git a/utils/unittest/googletest/include/gtest/gtest-printers.h b/utils/unittest/googletest/include/gtest/gtest-printers.h index 8a33164cb38..be793bbb151 100644 --- a/utils/unittest/googletest/include/gtest/gtest-printers.h +++ b/utils/unittest/googletest/include/gtest/gtest-printers.h @@ -102,6 +102,7 @@ #include <vector> #include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-internal.h" +#include "gtest/internal/custom/raw-ostream.h" #if GTEST_HAS_STD_TUPLE_ # include <tuple> @@ -246,7 +247,7 @@ void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { // impossible to define #1 (e.g. when foo is ::std, defining // anything in it is undefined behavior unless you are a compiler // vendor.). - *os << value; + *os << ::llvm_gtest::printable(value); } } // namespace testing_internal diff --git a/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h b/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h new file mode 100644 index 00000000000..fd993db1602 --- /dev/null +++ b/utils/unittest/googletest/include/gtest/internal/custom/raw-ostream.h @@ -0,0 +1,74 @@ +//===-- raw-ostream.h - Support for printing using raw_ostream --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This file is not part of gtest, but extends it to support LLVM libraries. +// This is not a public API for testing - it's a detail of LLVM's gtest. +// +// gtest allows providing printers for custom types by defining operator<<. +// In LLVM, operator<< usually takes llvm:raw_ostream& instead of std::ostream&. +// +// This file defines a template printable(V), which returns a version of V that +// can be streamed into a std::ostream. +// +// This interface is chosen so that in the default case (printable(V) is V), +// the main gtest code calls operator<<(OS, V) itself. gtest-printers carefully +// controls the lookup to enable fallback printing (see testing::internal2). +//===----------------------------------------------------------------------===// + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_RAW_OSTREAM_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_RAW_OSTREAM_H_ + +namespace llvm_gtest { +// StreamSwitch is a trait that tells us how to stream a T into a std::ostream. +// By default, we just stream the T directly. We'll specialize this later. +template <typename T, typename Enable = void> struct StreamSwitch { + static const T& printable(const T& V) { return V; } +}; + +// printable() returns a version of its argument that can be streamed into a +// std::ostream. This may be the argument itself, or some other representation. +template <typename T> +auto printable(const T &V) -> decltype(StreamSwitch<T>::printable(V)) { + // We delegate to the trait, to allow partial specialization. + return StreamSwitch<T>::printable(V); +} +} // namespace llvm_gtest + +// If raw_ostream support is enabled, we specialize for types with operator<< +// that takes a raw_ostream. +#if !GTEST_NO_LLVM_RAW_OSTREAM +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/raw_os_ostream.h" +#include <ostream> +namespace llvm_gtest { + +// The printable() of a raw_ostream-enabled type T is a RawStreamProxy<T>. +// It uses raw_os_ostream to write the wrapped value to a std::ostream. +template <typename T> +struct RawStreamProxy { + const T& V; + friend std::ostream &operator<<(std::ostream &S, const RawStreamProxy<T> &V) { + llvm::raw_os_ostream OS(S); + OS << V.V; + return S; + } +}; + +// We enable raw_ostream treatment if `(raw_ostream&) << (const T&)` is valid. +// We don't want implicit conversions on the RHS (e.g. to bool!), so "consume" +// the possible conversion by passing something convertible to const T& instead. +template <typename T> struct ConvertibleTo { operator T(); }; +template <typename T> +struct StreamSwitch<T, decltype((void)(std::declval<llvm::raw_ostream &>() + << ConvertibleTo<const T &>()))> { + static const RawStreamProxy<T> printable(const T &V) { return {V}; } +}; +} // namespace llvm_gtest +#endif // !GTEST_NO_LLVM_RAW_OSTREAM + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_RAW_OSTREAM_H_ |