Merge pull request #1508 from gennadiycivil/master

merge, again, IsRecursiveContainer
This commit is contained in:
Gennadiy Civil 2018-03-19 13:32:25 -04:00 committed by GitHub
commit dccc2d6754
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 130 additions and 23 deletions

View File

@ -509,17 +509,19 @@ void PrintTo(const T& value, ::std::ostream* os) {
// function pointers so that the `*os << p` in the object pointer overload
// doesn't cause that warning either.
DefaultPrintTo(
WrapPrinterType<
(sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) && !IsRecursiveContainer<T>::value
? kPrintContainer : !is_pointer<T>::value
? kPrintOther
WrapPrinterType <
(sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) &&
!IsRecursiveContainer<T>::value
? kPrintContainer
: !is_pointer<T>::value
? kPrintOther
#if GTEST_LANG_CXX11
: std::is_function<typename std::remove_pointer<T>::type>::value
#else
: !internal::ImplicitlyConvertible<T, const void*>::value
#endif
? kPrintFunctionPointer
: kPrintPointer>(),
: kPrintPointer > (),
value, os);
}

View File

@ -875,8 +875,11 @@ struct IsAProtocolMessage
// a container class by checking the type of IsContainerTest<C>(0).
// The value of the expression is insignificant.
//
// Note that we look for both C::iterator and C::const_iterator. The
// reason is that C++ injects the name of a class as a member of the
// In C++11 mode we check the existence of a const_iterator and that an
// iterator is properly implemented for the container.
//
// For pre-C++11 that we look for both C::iterator and C::const_iterator.
// The reason is that C++ injects the name of a class as a member of the
// class itself (e.g. you can refer to class iterator as either
// 'iterator' or 'iterator::iterator'). If we look for C::iterator
// only, for example, we would mistakenly think that a class named
@ -886,40 +889,94 @@ struct IsAProtocolMessage
// IsContainerTest(typename C::const_iterator*) and
// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++.
typedef int IsContainer;
#if GTEST_LANG_CXX11
template <class C,
class Iterator = decltype(::std::declval<const C&>().begin()),
class = decltype(::std::declval<const C&>().end()),
class = decltype(++::std::declval<Iterator&>()),
class = decltype(*::std::declval<Iterator>()),
class = typename C::const_iterator>
IsContainer IsContainerTest(int /* dummy */) {
return 0;
}
#else
template <class C>
IsContainer IsContainerTest(int /* dummy */,
typename C::iterator* /* it */ = NULL,
typename C::const_iterator* /* const_it */ = NULL) {
return 0;
}
#endif // GTEST_LANG_CXX11
typedef char IsNotContainer;
template <class C>
IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; }
template <typename C, bool =
sizeof(IsContainerTest<C>(0)) == sizeof(IsContainer)
>
// Trait to detect whether a type T is a hash table.
// The heuristic used is that the type contains an inner type `hasher` and does
// not contain an inner type `reverse_iterator`.
// If the container is iterable in reverse, then order might actually matter.
template <typename T>
struct IsHashTable {
private:
template <typename U>
static char test(typename U::hasher*, typename U::reverse_iterator*);
template <typename U>
static int test(typename U::hasher*, ...);
template <typename U>
static char test(...);
public:
static const bool value = sizeof(test<T>(0, 0)) == sizeof(int);
};
template <typename T>
const bool IsHashTable<T>::value;
template<typename T>
struct VoidT {
typedef void value_type;
};
template <typename T, typename = void>
struct HasValueType : false_type {};
template <typename T>
struct HasValueType<T, VoidT<typename T::value_type> > : true_type {
};
template <typename C,
bool = sizeof(IsContainerTest<C>(0)) == sizeof(IsContainer),
bool = HasValueType<C>::value>
struct IsRecursiveContainerImpl;
template <typename C, bool HV>
struct IsRecursiveContainerImpl<C, false, HV> : public false_type {};
// Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to
// obey the same inconsistencies as the IsContainerTest, namely check if
// something is a container is relying on only const_iterator in C++11 and
// is relying on both const_iterator and iterator otherwise
template <typename C>
struct IsRecursiveContainerImpl<C, false> : public false_type {};
struct IsRecursiveContainerImpl<C, true, false> : public false_type {};
template <typename C>
struct IsRecursiveContainerImpl<C, true> {
typedef
typename IteratorTraits<typename C::iterator>::value_type
value_type;
struct IsRecursiveContainerImpl<C, true, true> {
#if GTEST_LANG_CXX11
typedef typename IteratorTraits<typename C::const_iterator>::value_type
value_type;
#else
typedef typename IteratorTraits<typename C::iterator>::value_type value_type;
#endif
typedef is_same<value_type, C> type;
};
// IsRecursiveContainer<Type> is a unary compile-time predicate that
// evaluates whether C is a recursive container type. A recursive container
// evaluates whether C is a recursive container type. A recursive container
// type is a container type whose value_type is equal to the container type
// itself. An example for a recursive container type is
// boost::filesystem::path, whose iterator has a value_type that is equal to
// itself. An example for a recursive container type is
// boost::filesystem::path, whose iterator has a value_type that is equal to
// boost::filesystem::path.
template<typename C>
template <typename C>
struct IsRecursiveContainer : public IsRecursiveContainerImpl<C>::type {};
// EnableIf<condition>::type is void when 'Cond' is true, and
@ -1218,4 +1275,3 @@ 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_

View File

@ -5185,8 +5185,8 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) {
// each TestCase and TestInfo object.
// If shard_tests == true, further filters tests based on sharding
// variables in the environment - see
// https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md .
// Returns the number of tests that should run.
// https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md
// . Returns the number of tests that should run.
int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?
Int32FromEnvOrDie(kTestTotalShards, -1) : -1;

View File

@ -195,7 +195,6 @@ class PathLike {
struct iterator {
typedef PathLike value_type;
};
typedef iterator const_iterator;
PathLike() {}

View File

@ -64,6 +64,9 @@ TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded) {
#include <map>
#include <vector>
#include <ostream>
#if GTEST_LANG_CXX11
#include <unordered_set>
#endif // GTEST_LANG_CXX11
#include "gtest/gtest-spi.h"
#include "src/gtest-internal-inl.h"
@ -258,6 +261,8 @@ using testing::internal::IsContainer;
using testing::internal::IsContainerTest;
using testing::internal::IsNotContainer;
using testing::internal::NativeArray;
using testing::internal::OsStackTraceGetter;
using testing::internal::OsStackTraceGetterInterface;
using testing::internal::ParseInt32Flag;
using testing::internal::RelationToSourceCopy;
using testing::internal::RelationToSourceReference;
@ -274,6 +279,7 @@ using testing::internal::String;
using testing::internal::TestEventListenersAccessor;
using testing::internal::TestResultAccessor;
using testing::internal::UInt32;
using testing::internal::UnitTestImpl;
using testing::internal::WideStringToUtf8;
using testing::internal::edit_distance::CalculateOptimalEdits;
using testing::internal::edit_distance::CreateUnifiedDiff;
@ -7526,6 +7532,50 @@ TEST(IsContainerTestTest, WorksForContainer) {
sizeof(IsContainerTest<std::map<int, double> >(0)));
}
#if GTEST_LANG_CXX11
struct ConstOnlyContainerWithPointerIterator {
using const_iterator = int*;
const_iterator begin() const;
const_iterator end() const;
};
struct ConstOnlyContainerWithClassIterator {
struct const_iterator {
const int& operator*() const;
const_iterator& operator++(/* pre-increment */);
};
const_iterator begin() const;
const_iterator end() const;
};
TEST(IsContainerTestTest, ConstOnlyContainer) {
EXPECT_EQ(sizeof(IsContainer),
sizeof(IsContainerTest<ConstOnlyContainerWithPointerIterator>(0)));
EXPECT_EQ(sizeof(IsContainer),
sizeof(IsContainerTest<ConstOnlyContainerWithClassIterator>(0)));
}
#endif // GTEST_LANG_CXX11
// Tests IsHashTable.
struct AHashTable {
typedef void hasher;
};
struct NotReallyAHashTable {
typedef void hasher;
typedef void reverse_iterator;
};
TEST(IsHashTable, Basic) {
EXPECT_TRUE(testing::internal::IsHashTable<AHashTable>::value);
EXPECT_FALSE(testing::internal::IsHashTable<NotReallyAHashTable>::value);
#if GTEST_LANG_CXX11
EXPECT_FALSE(testing::internal::IsHashTable<std::vector<int>>::value);
EXPECT_TRUE(testing::internal::IsHashTable<std::unordered_set<int>>::value);
#endif // GTEST_LANG_CXX11
#if GTEST_HAS_HASH_SET_
EXPECT_TRUE(testing::internal::IsHashTable<hash_set<int>>::value);
#endif // GTEST_HAS_HASH_SET_
}
// Tests ArrayEq().
TEST(ArrayEqTest, WorksForDegeneratedArrays) {