Skip to content

Instantly share code, notes, and snippets.

@zeroomega
Created September 8, 2023 23:35
Show Gist options
  • Save zeroomega/fb24b1d1c4252b852200e15fda29384d to your computer and use it in GitHub Desktop.
Save zeroomega/fb24b1d1c4252b852200e15fda29384d to your computer and use it in GitHub Desktop.
LLVM's patch over GoogleTest v1.14.0
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 089ac987..74a523b6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,27 +1,112 @@
-# Note: CMake support is community-based. The maintainers do not use CMake
-# internally.
+########################################################################
+# Experimental CMake build script for Google Test.
+#
+# Consider this a prototype. It will change drastically. For now,
+# this is only for people on the cutting edge.
+#
+# To run the tests for Google Test itself on Linux, use 'make test' or
+# ctest. You can select which tests to run using 'ctest -R regex'.
+# For more options, run 'ctest --help'.
+########################################################################
+#
+# Project-wide settings
-cmake_minimum_required(VERSION 3.13)
+if(WIN32)
+ add_definitions(-DGTEST_OS_WINDOWS=1)
+endif()
+
+# Google Test requires headers which need _ALL_SOURCE to build on AIX
+if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
+ remove_definitions("-D_XOPEN_SOURCE=700")
+ add_definitions("-D_ALL_SOURCE")
+endif()
+
+if(SUPPORTS_VARIADIC_MACROS_FLAG)
+ add_definitions("-Wno-variadic-macros")
+endif()
+if(SUPPORTS_GNU_ZERO_VARIADIC_MACRO_ARGUMENTS_FLAG)
+ add_definitions("-Wno-gnu-zero-variadic-macro-arguments")
+endif()
+if(CXX_SUPPORTS_COVERED_SWITCH_DEFAULT_FLAG)
+ add_definitions("-Wno-covered-switch-default")
+endif()
+
+set(LLVM_REQUIRES_RTTI 1)
+add_definitions( -DGTEST_HAS_RTTI=0 )
+
+if (HAVE_LIBPTHREAD)
+ list(APPEND LIBS pthread)
+endif()
+
+# Do not build unittest libraries automatically, they will be pulled in
+# by unittests if these are built.
+
+set(BUILDTREE_ONLY BUILDTREE_ONLY)
+set(EXCLUDE_FROM_ALL ON)
+if (LLVM_INSTALL_GTEST)
+ set(EXCLUDE_FROM_ALL OFF)
+ set(BUILDTREE_ONLY "")
+endif ()
+
+add_llvm_library(llvm_gtest
+ googletest/src/gtest-all.cc
+ googlemock/src/gmock-all.cc
+
+ LINK_LIBS
+ ${LIBS}
-project(googletest-distribution)
-set(GOOGLETEST_VERSION 1.14.0)
+ LINK_COMPONENTS
+ Support # Depends on llvm::raw_ostream
-if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX)
- set(CMAKE_CXX_EXTENSIONS OFF)
+ # This is a library meant only for the build tree.
+ ${BUILDTREE_ONLY}
+)
+
+# The googletest and googlemock sources don't presently use the 'override'
+# keyword, which leads to lots of warnings from -Wsuggest-override. Disable
+# that warning here for any targets that link to gtest.
+if(CXX_SUPPORTS_SUGGEST_OVERRIDE_FLAG)
+ add_definitions("-Wno-suggest-override")
+ set_target_properties(llvm_gtest PROPERTIES INTERFACE_COMPILE_OPTIONS "-Wno-suggest-override")
endif()
-enable_testing()
+if (NOT LLVM_ENABLE_THREADS)
+ target_compile_definitions(llvm_gtest PUBLIC GTEST_HAS_PTHREAD=0)
+endif ()
-include(CMakeDependentOption)
-include(GNUInstallDirs)
+target_include_directories(llvm_gtest
+ PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/googletest/include>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/googlemock/include>
+ $<INSTALL_INTERFACE:include/llvm-gtest/>
+ $<INSTALL_INTERFACE:include/llvm-gmock/>
+ PRIVATE googletest googlemock
+ )
-#Note that googlemock target already builds googletest
-option(BUILD_GMOCK "Builds the googlemock subproject" ON)
-option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" ON)
-option(GTEST_HAS_ABSL "Use Abseil and RE2. Requires Abseil and RE2 to be separately added to the build." OFF)
+add_subdirectory(UnitTestMain)
-if(BUILD_GMOCK)
- add_subdirectory( googlemock )
-else()
- add_subdirectory( googletest )
+if (LLVM_INSTALL_GTEST)
+ install(TARGETS llvm_gtest llvm_gtest_main LLVMTestingSupport LLVMTestingAnnotations
+ ARCHIVE DESTINATION "lib${LLVM_LIBDIR_SUFFIX}" COMPONENT llvm_gtest)
+ install(DIRECTORY googletest/include/gtest/ DESTINATION include/llvm-gtest/gtest/ COMPONENT llvm_gtest)
+ install(DIRECTORY googlemock/include/gmock/ DESTINATION include/llvm-gmock/gmock/ COMPONENT llvm_gtest)
endif()
+
+# When LLVM_LINK_LLVM_DYLIB is enabled, libLLVM.so is added to the interface
+# link libraries for gtest and gtest_main. This means that any target, like
+# unittests for example, that links against gtest will be forced to link
+# against libLLVM.so. In some cases we may want to statically unittests if they
+# need access to symbols that are marked private in libLLVM.so. The only
+# way we can make this work is to remove libLLVM.so from the list of interface
+# link libraries for gtest and then make gtest users responsible for explicitly
+# adding libLLVM.so to their targets link libraries if they need it.
+
+function (gtest_remove_dylib_from_link_interface target)
+ get_target_property(interface_libs ${target} INTERFACE_LINK_LIBRARIES)
+ if (interface_libs)
+ list(REMOVE_ITEM interface_libs LLVM)
+ set_target_properties(${target} PROPERTIES INTERFACE_LINK_LIBRARIES "${interface_libs}")
+ endif()
+endfunction()
+
+gtest_remove_dylib_from_link_interface(llvm_gtest)
+gtest_remove_dylib_from_link_interface(llvm_gtest_main)
diff --git a/UnitTestMain/CMakeLists.txt b/UnitTestMain/CMakeLists.txt
new file mode 100644
index 00000000..729ea7e3
--- /dev/null
+++ b/UnitTestMain/CMakeLists.txt
@@ -0,0 +1,16 @@
+set(BUILDTREE_ONLY BUILDTREE_ONLY)
+if (LLVM_INSTALL_GTEST)
+ set(BUILDTREE_ONLY "")
+endif ()
+
+add_llvm_library(llvm_gtest_main
+ TestMain.cpp
+
+ LINK_LIBS
+ llvm_gtest
+
+ LINK_COMPONENTS
+ Support # Depends on llvm::cl
+
+ ${BUILDTREE_ONLY}
+ )
diff --git a/UnitTestMain/TestMain.cpp b/UnitTestMain/TestMain.cpp
new file mode 100644
index 00000000..35ba72ba
--- /dev/null
+++ b/UnitTestMain/TestMain.cpp
@@ -0,0 +1,56 @@
+//===--- utils/unittest/UnitTestMain/TestMain.cpp - unittest driver -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Signals.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <stdlib.h>
+
+#if defined(_WIN32)
+# include <windows.h>
+# if defined(_MSC_VER)
+# include <crtdbg.h>
+# endif
+#endif
+
+const char *TestMainArgv0;
+
+int main(int argc, char **argv) {
+ // Skip setting up signal handlers for tests that need to test things without
+ // them configured.
+ if (!getenv("LLVM_PROGRAM_TEST_NO_STACKTRACE_HANDLER")) {
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0],
+ true /* Disable crash reporting */);
+ }
+
+ // Initialize both gmock and gtest.
+ testing::InitGoogleMock(&argc, argv);
+
+ llvm::cl::ParseCommandLineOptions(argc, argv);
+
+ // Make it easy for a test to re-execute itself by saving argv[0].
+ TestMainArgv0 = argv[0];
+
+# if defined(_WIN32)
+ // Disable all of the possible ways Windows conspires to make automated
+ // testing impossible.
+ ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+# if defined(_MSC_VER)
+ ::_set_error_mode(_OUT_TO_STDERR);
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+# endif
+# endif
+
+ return RUN_ALL_TESTS();
+}
diff --git a/LICENSE b/googlemock/LICENSE.txt
similarity index 100%
rename from LICENSE
rename to googlemock/LICENSE.txt
diff --git a/googlemock/README.LLVM b/googlemock/README.LLVM
new file mode 100644
index 00000000..48ac7766
--- /dev/null
+++ b/googlemock/README.LLVM
@@ -0,0 +1,19 @@
+LLVM notes
+----------
+
+This directory contains the 'googlemock' component of Google Test 1.14.0, with
+all elements removed except for the actual source code, to minimize the
+addition to the LLVM distribution.
+
+Cleaned up as follows:
+
+# Remove all the unnecessary files and directories
+$ rm -f CMakeLists.txt configure* Makefile* CHANGES CONTRIBUTORS README README.md .gitignore
+$ rm -rf build-aux make msvc scripts test docs
+$ rm -f src/gmock_main.cc
+
+# Put the license in the consistent place for LLVM.
+$ mv LICENSE LICENSE.TXT
+
+Modified as follows:
+* Support for std::begin/std::end in gmock-matchers.h
diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h
index 0f677137..a9e7cd19 100644
--- a/googlemock/include/gmock/gmock-matchers.h
+++ b/googlemock/include/gmock/gmock-matchers.h
@@ -2356,12 +2356,20 @@ class BeginEndDistanceIsMatcher {
template <typename Container>
class Impl : public MatcherInterface<Container> {
public:
- typedef internal::StlContainerView<GTEST_REMOVE_REFERENCE_AND_CONST_(
- Container)>
- ContainerView;
+ typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
+ typedef internal::StlContainerView<RawContainer> View;
+ typedef typename View::type StlContainer;
+ typedef typename View::const_reference StlContainerReference;
+ typedef decltype(std::begin(
+ std::declval<StlContainerReference>())) StlContainerConstIterator;
typedef typename std::iterator_traits<
- typename ContainerView::type::const_iterator>::difference_type
- DistanceType;
+ StlContainerConstIterator>::difference_type DistanceType;
+ // typedef internal::StlContainerView<GTEST_REMOVE_REFERENCE_AND_CONST_(
+ // Container)>
+ // ContainerView;
+ // typedef typename std::iterator_traits<
+ // typename ContainerView::type::const_iterator>::difference_type
+ // DistanceType;
explicit Impl(const DistanceMatcher& distance_matcher)
: distance_matcher_(MatcherCast<DistanceType>(distance_matcher)) {}
@@ -3370,7 +3378,11 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
typedef internal::StlContainerView<RawContainer> View;
typedef typename View::type StlContainer;
typedef typename View::const_reference StlContainerReference;
- typedef typename StlContainer::value_type Element;
+ typedef decltype(std::begin(
+ std::declval<StlContainerReference>())) StlContainerConstIterator;
+ typedef typename std::remove_reference<
+ decltype(*std::declval<StlContainerConstIterator &>())>::type Element;
+ //typedef typename StlContainer::value_type Element;
// Constructs the matcher from a sequence of element values or
// element matchers.
@@ -3427,7 +3439,7 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
// explanations[i] is the explanation of the element at index i.
::std::vector<std::string> explanations(count());
StlContainerReference stl_container = View::ConstReference(container);
- auto it = stl_container.begin();
+ StlContainerConstIterator it = stl_container.begin();
size_t exam_pos = 0;
bool mismatch_found = false; // Have we found a mismatched element yet?
@@ -3616,7 +3628,11 @@ class UnorderedElementsAreMatcherImpl
typedef internal::StlContainerView<RawContainer> View;
typedef typename View::type StlContainer;
typedef typename View::const_reference StlContainerReference;
- typedef typename StlContainer::value_type Element;
+ typedef decltype(std::begin(
+ std::declval<StlContainerReference>())) StlContainerConstIterator;
+ typedef typename std::remove_reference<
+ decltype(*std::declval<StlContainerConstIterator &>())>::type Element;
+ //typedef typename StlContainer::value_type Element;
template <typename InputIter>
UnorderedElementsAreMatcherImpl(UnorderedMatcherRequire::Flags matcher_flags,
@@ -3704,8 +3720,15 @@ class UnorderedElementsAreMatcher {
template <typename Container>
operator Matcher<Container>() const {
typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
- typedef typename internal::StlContainerView<RawContainer>::type View;
- typedef typename View::value_type Element;
+
+ typedef internal::StlContainerView<RawContainer> View;
+ typedef typename View::const_reference StlContainerReference;
+ typedef decltype(std::begin(
+ std::declval<StlContainerReference>())) StlContainerConstIterator;
+ typedef typename std::remove_reference<
+ decltype(*std::declval<StlContainerConstIterator &>())>::type Element;
+ // typedef typename internal::StlContainerView<RawContainer>::type View;
+ // typedef typename View::value_type Element;
typedef ::std::vector<Matcher<const Element&>> MatcherVec;
MatcherVec matchers;
matchers.reserve(::std::tuple_size<MatcherTuple>::value);
@@ -3735,8 +3758,14 @@ class ElementsAreMatcher {
"use UnorderedElementsAre with hash tables");
typedef GTEST_REMOVE_REFERENCE_AND_CONST_(Container) RawContainer;
- typedef typename internal::StlContainerView<RawContainer>::type View;
- typedef typename View::value_type Element;
+ typedef internal::StlContainerView<RawContainer> View;
+ typedef typename View::const_reference StlContainerReference;
+ typedef decltype(std::begin(
+ std::declval<StlContainerReference>())) StlContainerConstIterator;
+ typedef typename std::remove_reference<
+ decltype(*std::declval<StlContainerConstIterator &>())>::type Element;
+ // typedef typename internal::StlContainerView<RawContainer>::type View;
+ // typedef typename View::value_type Element;
typedef ::std::vector<Matcher<const Element&>> MatcherVec;
MatcherVec matchers;
matchers.reserve(::std::tuple_size<MatcherTuple>::value);
diff --git a/googletest/LICENSE.txt b/googletest/LICENSE.txt
new file mode 100644
index 00000000..1941a11f
--- /dev/null
+++ b/googletest/LICENSE.txt
@@ -0,0 +1,28 @@
+Copyright 2008, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/googletest/README.LLVM b/googletest/README.LLVM
new file mode 100644
index 00000000..7a8ae859
--- /dev/null
+++ b/googletest/README.LLVM
@@ -0,0 +1,21 @@
+LLVM notes
+----------
+
+This directory contains Google Test 1.14.0,
+revision `f8d7d77c06936315286eb55f8de22cd23c188571`, with all elements removed
+except for the actual source code, to minimize the addition to the LLVM
+distribution.
+
+Cleaned up as follows:
+
+# Remove all the unnecessary files and directories
+$ rm -f CMakeLists.txt configure* Makefile* CHANGES CONTRIBUTORS README README.md .gitignore
+$ rm -rf build-aux cmake codegear m4 make msvc samples scripts test xcode docs
+$ rm -f src/gtest_main.cc
+
+# Put the license in the consistent place for LLVM.
+$ mv LICENSE LICENSE.TXT
+
+Modified as follows:
+* Added raw_os_ostream support to include/gtest/internal/custom/gtest-printers.h.
+* Added StringRef support to include/gtest/internal/custom/gtest-printers.h.
diff --git a/googletest/include/gtest/gtest-message.h b/googletest/include/gtest/gtest-message.h
index 59b805e4..833e227a 100644
--- a/googletest/include/gtest/gtest-message.h
+++ b/googletest/include/gtest/gtest-message.h
@@ -145,7 +145,7 @@ class GTEST_API_ Message {
// overloads of << defined in the global namespace and those
// visible via Koenig lookup are both exposed in this function.
using ::operator<<;
- *ss_ << val;
+ *ss_ << llvm_gtest::printable(val);
return *this;
}
@@ -183,7 +183,7 @@ class GTEST_API_ Message {
if (pointer == nullptr) {
*ss_ << "(null)";
} else {
- *ss_ << pointer;
+ *ss_ << llvm_gtest::printable(pointer);
}
return *this;
}
diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h
index d1766e64..39841923 100644
--- a/googletest/include/gtest/gtest-printers.h
+++ b/googletest/include/gtest/gtest-printers.h
@@ -222,7 +222,7 @@ struct StreamPrinter {
-> decltype((void)(*os << value)) {
// Call streaming operator found by ADL, possibly with implicit conversions
// of the arguments.
- *os << value;
+ *os << ::llvm_gtest::printable(value);
}
};
diff --git a/googletest/include/gtest/internal/custom/gtest-port.h b/googletest/include/gtest/internal/custom/gtest-port.h
index db02881c..57d16fca 100644
--- a/googletest/include/gtest/internal/custom/gtest-port.h
+++ b/googletest/include/gtest/internal/custom/gtest-port.h
@@ -34,4 +34,5 @@
#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+#include "gtest/internal/custom/raw-ostream.h"
#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
diff --git a/googletest/include/gtest/internal/custom/gtest-printers.h b/googletest/include/gtest/internal/custom/gtest-printers.h
index b9495d83..06f85f89 100644
--- a/googletest/include/gtest/internal/custom/gtest-printers.h
+++ b/googletest/include/gtest/internal/custom/gtest-printers.h
@@ -39,4 +39,43 @@
#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+#if !GTEST_NO_LLVM_SUPPORT
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include <ostream>
+// Printing of llvm String types.
+// gtest sees these as containers of char (they have nested iterator types),
+// so their operator<< is never considered unless we provide PrintTo().
+// PrintStringTo provides quotes and escaping, at the cost of a copy.
+namespace llvm {
+inline void PrintTo(llvm::StringRef S, std::ostream *OS) {
+ *OS << ::testing::PrintToString(S.str());
+}
+// We need both SmallString<N> and SmallVectorImpl<char> overloads:
+// - the SmallString<N> template is needed as overload resolution will
+// instantiate generic PrintTo<T> rather than do derived-to-base conversion
+// - but SmallVectorImpl<char> is sometimes the actual static type, in code
+// that erases the small size
+template <unsigned N>
+inline void PrintTo(const SmallString<N> &S, std::ostream *OS) {
+ *OS << ::testing::PrintToString(std::string(S.data(), S.size()));
+}
+inline void PrintTo(const SmallVectorImpl<char> &S, std::ostream *OS) {
+ *OS << ::testing::PrintToString(std::string(S.data(), S.size()));
+}
+
+// DenseMap's entries inherit from std::pair, and should act like pairs.
+// However gTest's provided `PrintTo(pair<K,V>)` template won't deduce K and V
+// because of the needed derived-to-base conversion.
+namespace detail {
+template <typename K, typename V>
+inline void PrintTo(const DenseMapPair<K, V> &Pair, std::ostream *OS) {
+ *OS << ::testing::PrintToString(static_cast<const std::pair<K, V> &>(Pair));
+}
+} // namespace detail
+
+} // namespace llvm
+#endif // !GTEST_NO_LLVM_SUPPORT
+
#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
diff --git a/googletest/include/gtest/internal/custom/raw-ostream.h b/googletest/include/gtest/internal/custom/raw-ostream.h
new file mode 100644
index 00000000..76dcdee4
--- /dev/null
+++ b/googletest/include/gtest/internal/custom/raw-ostream.h
@@ -0,0 +1,85 @@
+//===-- raw-ostream.h - Support for printing using raw_ostream --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// 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> decltype(auto) printable(const T &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_SUPPORT
+#include "llvm/Support/raw_os_ostream.h"
+#include "llvm/Support/raw_ostream.h"
+#include <optional>
+#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}; }
+};
+
+// std::optional has a template operator<<, which means it will not accept any
+// implicit conversions, so we need to special-case it here.
+template <typename T>
+struct StreamSwitch<std::optional<T>,
+ decltype((void)(std::declval<llvm::raw_ostream &>()
+ << std::declval<std::optional<T>>()))> {
+ static const RawStreamProxy<std::optional<T>>
+ printable(const std::optional<T> &V) {
+ return {V};
+ }
+};
+} // namespace llvm_gtest
+#endif // !GTEST_NO_LLVM_SUPPORT
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_RAW_OSTREAM_H_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment