Skip to content

Commit

Permalink
googletest: Add universal printer for std::span
Browse files Browse the repository at this point in the history
Fixes google#4318

PiperOrigin-RevId: 560089120
Change-Id: I9d0d098140033520266747a1689e953ee8307c47
  • Loading branch information
dinord authored and copybara-github committed Aug 25, 2023
1 parent 460ae98 commit 8a6feab
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 2 deletions.
27 changes: 25 additions & 2 deletions googletest/include/gtest/gtest-printers.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@
#include "gtest/internal/gtest-internal.h"
#include "gtest/internal/gtest-port.h"

#if GTEST_INTERNAL_HAS_STD_SPAN
#include <span> // NOLINT
#endif // GTEST_INTERNAL_HAS_STD_SPAN

namespace testing {

// Definitions in the internal* namespaces are subject to change without notice.
Expand All @@ -131,13 +135,32 @@ namespace internal {
template <typename T>
void UniversalPrint(const T& value, ::std::ostream* os);

template <typename T>
struct IsStdSpan {
static constexpr bool value = false;
};

#if GTEST_INTERNAL_HAS_STD_SPAN
template <typename E>
struct IsStdSpan<std::span<E>> {
static constexpr bool value = true;
};
#endif // GTEST_INTERNAL_HAS_STD_SPAN

// Used to print an STL-style container when the user doesn't define
// a PrintTo() for it.
//
// NOTE: Since std::span does not have const_iterator until C++23, it would
// fail IsContainerTest before C++23. However, IsContainerTest only uses
// the presence of const_iterator to avoid treating iterators as containers
// because of iterator::iterator. Which means std::span satisfies the *intended*
// condition of IsContainerTest.
struct ContainerPrinter {
template <typename T,
typename = typename std::enable_if<
(sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) &&
!IsRecursiveContainer<T>::value>::type>
((sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) &&
!IsRecursiveContainer<T>::value) ||
IsStdSpan<T>::value>::type>
static void PrintValue(const T& container, std::ostream* os) {
const size_t kMaxCount = 32; // The maximum number of elements to print.
*os << '{';
Expand Down
12 changes: 12 additions & 0 deletions googletest/include/gtest/internal/gtest-port.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@
// or
// UniversalPrinter<absl::optional>
// specializations. Always defined to 0 or 1.
// GTEST_INTERNAL_HAS_STD_SPAN - for enabling UniversalPrinter<std::span>
// specializations. Always defined to 0 or 1
// GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher<std::string_view> or
// Matcher<absl::string_view>
// specializations. Always defined to 0 or 1.
Expand Down Expand Up @@ -2407,6 +2409,16 @@ inline ::std::nullopt_t Nullopt() { return ::std::nullopt; }
#define GTEST_INTERNAL_HAS_OPTIONAL 0
#endif

#ifdef __has_include
#if __has_include(<span>) && GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L
#define GTEST_INTERNAL_HAS_STD_SPAN 1
#endif // __has_include(<span>) && GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L
#endif // __has_include

#ifndef GTEST_INTERNAL_HAS_STD_SPAN
#define GTEST_INTERNAL_HAS_STD_SPAN 0
#endif

#ifdef GTEST_HAS_ABSL
// Always use absl::string_view for Matcher<> specializations if googletest
// is built with absl support.
Expand Down
16 changes: 16 additions & 0 deletions googletest/test/googletest-printers-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,16 @@

#include "gtest/gtest-printers.h"
#include "gtest/gtest.h"
#include "gtest/internal/gtest-port.h"

#ifdef GTEST_HAS_ABSL
#include "absl/strings/str_format.h"
#endif

#if GTEST_INTERNAL_HAS_STD_SPAN
#include <span> // NOLINT
#endif // GTEST_INTERNAL_HAS_STD_SPAN

// Some user-defined types for testing the universal value printer.

// An anonymous enum type.
Expand Down Expand Up @@ -1179,6 +1184,17 @@ TEST(PrintStlContainerTest, Vector) {
EXPECT_EQ("{ 1, 2 }", Print(v));
}

TEST(PrintStlContainerTest, StdSpan) {
#if GTEST_INTERNAL_HAS_STD_SPAN
int a[] = {3, 6, 5};
std::span<int> s = a;

EXPECT_EQ("{ 3, 6, 5 }", Print(s));
#else
GTEST_SKIP() << "Does not have std::span.";
#endif // GTEST_INTERNAL_HAS_STD_SPAN
}

TEST(PrintStlContainerTest, LongSequence) {
const int a[100] = {1, 2, 3};
const vector<int> v(a, a + 100);
Expand Down

0 comments on commit 8a6feab

Please sign in to comment.