diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index bdd8084d5..8d4590116 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -4581,9 +4581,9 @@ inline auto ElementsAreArray(const T (&array)[N]) } template -inline auto ElementsAreArray(const Container& container) - -> decltype(ElementsAreArray(container.begin(), container.end())) { - return ElementsAreArray(container.begin(), container.end()); +inline auto ElementsAreArray(const Container& container) { + auto view = internal::StlContainerView::ConstReference(container); + return ElementsAreArray(view.begin(), view.end()); } template @@ -4628,9 +4628,10 @@ inline internal::UnorderedElementsAreArrayMatcher UnorderedElementsAreArray( template inline internal::UnorderedElementsAreArrayMatcher< - typename Container::value_type> + typename internal::RangeTraits::value_type> UnorderedElementsAreArray(const Container& container) { - return UnorderedElementsAreArray(container.begin(), container.end()); + auto view = internal::StlContainerView::ConstReference(container); + return UnorderedElementsAreArray(view.begin(), view.end()); } template @@ -5326,9 +5327,10 @@ inline internal::UnorderedElementsAreArrayMatcher IsSupersetOf( template inline internal::UnorderedElementsAreArrayMatcher< - typename Container::value_type> + typename internal::RangeTraits::value_type> IsSupersetOf(const Container& container) { - return IsSupersetOf(container.begin(), container.end()); + auto view = internal::StlContainerView::ConstReference(container); + return IsSupersetOf(view.begin(), view.end()); } template @@ -5383,9 +5385,10 @@ inline internal::UnorderedElementsAreArrayMatcher IsSubsetOf( template inline internal::UnorderedElementsAreArrayMatcher< - typename Container::value_type> + typename internal::RangeTraits::value_type> IsSubsetOf(const Container& container) { - return IsSubsetOf(container.begin(), container.end()); + auto view = internal::StlContainerView::ConstReference(container); + return IsSubsetOf(view.begin(), view.end()); } template diff --git a/googlemock/include/gmock/gmock-more-matchers.h b/googlemock/include/gmock/gmock-more-matchers.h index 39aad4c1a..a29bec10b 100644 --- a/googlemock/include/gmock/gmock-more-matchers.h +++ b/googlemock/include/gmock/gmock-more-matchers.h @@ -60,17 +60,20 @@ namespace internal { // Implements the polymorphic IsEmpty matcher, which // can be used as a Matcher as long as T is either a container that defines -// empty() and size() (e.g. std::vector or std::string), or a C-style string. +// size() (e.g. std::vector or std::string), can calculate size using the +// difference of iterators (e.g std::distance), or a C-style string. class [[nodiscard]] IsEmptyMatcher { public: - // Matches anything that defines empty() and size(). + // Matches anything that defines size(). template bool MatchAndExplain(const MatcheeContainerType& c, MatchResultListener* listener) const { - if (c.empty()) { + auto view = StlContainerView::ConstReference(c); + const size_t size = view.size(); + if (size == 0) { return true; } - *listener << "whose size is " << c.size(); + *listener << "whose size is " << size; return false; } diff --git a/googlemock/include/gmock/internal/gmock-internal-utils.h b/googlemock/include/gmock/internal/gmock-internal-utils.h index 258397a4f..8399193dc 100644 --- a/googlemock/include/gmock/internal/gmock-internal-utils.h +++ b/googlemock/include/gmock/internal/gmock-internal-utils.h @@ -168,8 +168,8 @@ GMOCK_DECLARE_KIND_(long double, kFloatingPoint); #undef GMOCK_DECLARE_KIND_ // Evaluates to the kind of 'type'. -#define GMOCK_KIND_OF_(type) \ - static_cast< ::testing::internal::TypeKind>( \ +#define GMOCK_KIND_OF_(type) \ + static_cast<::testing::internal::TypeKind>( \ ::testing::internal::KindOf::value) // LosslessArithmeticConvertibleImpl::value @@ -326,8 +326,7 @@ inline T Invalid() { void GetValueType(const void*); template -typename std::iterator_traits< - decltype(std::begin(std::declval()))>::value_type +std::remove_reference_t()))> GetValueType(T*); template @@ -360,15 +359,25 @@ struct RangeTraits> { template class [[nodiscard]] StlContainerView { public: - typedef RawContainer type; - typedef const type& const_reference; + typedef internal::ContainerWrapper + type; + // ContainerWrapper can represent a type either by value or by reference + // (selected by a constructor argument), so 'const type' can be used to + // reference a const wrapper. We cannot 'typedef const type& const_reference' + // here, as that would mean ConstReference() has to return a reference to a + // local variable. + typedef const type const_reference; + typedef typename type::value_type RawElement; static const_reference ConstReference(const RawContainer& container) { static_assert(!std::is_const::value, "RawContainer type must not be const"); - return container; + return type(&container, RelationToSourceReference()); + } + static type Copy(const RawContainer& container) { + return type(&container, RelationToSourceCopy()); } - static type Copy(const RawContainer& container) { return container; } }; // This specialization is used when RawContainer is a native array type. @@ -397,7 +406,7 @@ class [[nodiscard]] StlContainerView { // This specialization is used when RawContainer is a native array // represented as a (pointer, size) tuple. template -class [[nodiscard]] StlContainerView< ::std::tuple > { +class [[nodiscard]] StlContainerView<::std::tuple> { public: typedef typename std::remove_const< typename std::pointer_traits::element_type>::type @@ -430,7 +439,7 @@ struct RemoveConstFromKey { // Partially specialized to remove constness from std::pair. template -struct RemoveConstFromKey > { +struct RemoveConstFromKey> { typedef std::pair type; }; @@ -447,11 +456,10 @@ auto ApplyImpl(F&& f, Tuple&& args, std::index_sequence) // Apply the function to a tuple of arguments. template -auto Apply(F&& f, Tuple&& args) - -> decltype(ApplyImpl( - std::forward(f), std::forward(args), - std::make_index_sequence::type>::value>())) { +auto Apply(F&& f, Tuple&& args) -> decltype(ApplyImpl( + std::forward(f), std::forward(args), + std::make_index_sequence::type>::value>())) { return ApplyImpl(std::forward(f), std::forward(args), std::make_index_sequence::type>::value>()); diff --git a/googlemock/test/gmock-internal-utils_test.cc b/googlemock/test/gmock-internal-utils_test.cc index 7cffd18a3..684d9663a 100644 --- a/googlemock/test/gmock-internal-utils_test.cc +++ b/googlemock/test/gmock-internal-utils_test.cc @@ -582,18 +582,19 @@ TEST(OnCallTest, LogsAnythingArgument) { // Tests StlContainerView. TEST(StlContainerViewTest, WorksForStlContainer) { - StaticAssertTypeEq, + StaticAssertTypeEq>, StlContainerView>::type>(); - StaticAssertTypeEq&, + StaticAssertTypeEq>, StlContainerView>::const_reference>(); - typedef std::vector Chars; + using Chars = std::vector; + using Adaptor = internal::ContainerWrapper; Chars v1; - const Chars& v2(StlContainerView::ConstReference(v1)); - EXPECT_EQ(&v1, &v2); + const Adaptor& v2(StlContainerView::ConstReference(v1)); + EXPECT_EQ(v1.begin(), v2.begin()); v1.push_back('a'); - Chars v3 = StlContainerView::Copy(v1); + Adaptor v3 = StlContainerView::Copy(v1); EXPECT_THAT(v3, Eq(v3)); } diff --git a/googlemock/test/gmock-matchers-containers_test.cc b/googlemock/test/gmock-matchers-containers_test.cc index 697509f71..ba5aa6dcd 100644 --- a/googlemock/test/gmock-matchers-containers_test.cc +++ b/googlemock/test/gmock-matchers-containers_test.cc @@ -45,8 +45,8 @@ #include #include "gmock/gmock.h" -#include "test/gmock-matchers_test.h" #include "gtest/gtest.h" +#include "test/gmock-matchers_test.h" // Silence warning C4244: 'initializing': conversion from 'int' to 'short', // possible loss of data and C4100, unreferenced local parameter @@ -1256,6 +1256,15 @@ TEST(WhenSortedByTest, WorksForNativeArray) { EXPECT_THAT(numbers, Not(WhenSortedBy(less(), ElementsAre(1, 3, 2, 4)))); } +TEST(WhenSortedByTest, WorksForPseudoContainer) { + pseudo_container::PseudoContainer numbers({1, 3, 2, 4}); + pseudo_container::PseudoContainer sorted_numbers({1, 2, 3, 4}); + EXPECT_THAT(numbers, WhenSortedBy(less(), ElementsAre(1, 2, 3, 4))); + EXPECT_THAT(numbers, + WhenSortedBy(less(), ElementsAreArray(sorted_numbers))); + EXPECT_THAT(numbers, Not(WhenSortedBy(less(), ElementsAre(1, 3, 2, 4)))); +} + TEST(WhenSortedByTest, CanDescribeSelf) { const Matcher> m = WhenSortedBy(less(), ElementsAre(1, 2)); EXPECT_EQ( @@ -1335,6 +1344,12 @@ TEST(WhenSortedTest, WorksForPolymorphicMatcher) { EXPECT_THAT(d, Not(WhenSorted(ElementsAre(2, 1)))); } +TEST(WhenSortedTest, WorksForPseudoContainer) { + pseudo_container::PseudoContainer d({2, 1}); + EXPECT_THAT(d, WhenSorted(ElementsAre(1, 2))); + EXPECT_THAT(d, Not(WhenSorted(ElementsAre(2, 1)))); +} + TEST(WhenSortedTest, WorksForVectorConstRefMatcher) { std::deque d; d.push_back(2); @@ -1457,6 +1472,12 @@ TEST(BeginEndDistanceIsTest, WorksWithNonStdList) { EXPECT_THAT(s, BeginEndDistanceIs(5)); } +TEST(BeginEndDistanceIsTest, WorksWithPseudoContainers) { + std::vector a = {1, 2, 3, 4, 5}; + pseudo_container::PseudoContainer s(a); + EXPECT_THAT(s, BeginEndDistanceIs(5)); +} + TEST(BeginEndDistanceIsTest, CanDescribeSelf) { Matcher> m = BeginEndDistanceIs(2); EXPECT_EQ("distance between begin() and end() is equal to 2", Describe(m)); @@ -1572,6 +1593,31 @@ TEST(IsSupersetOfTest, WorksForStreamlike) { EXPECT_THAT(s, Not(IsSupersetOf(expected))); } +TEST(IsSupersetOfTest, WorksForPseudoContainer) { + std::vector a = {1, 2, 3, 4, 5}; + pseudo_container::PseudoContainer actual(a); + + vector expected; + expected.push_back(1); + expected.push_back(2); + expected.push_back(5); + EXPECT_THAT(actual, IsSupersetOf(expected)); + + expected.push_back(0); + EXPECT_THAT(actual, Not(IsSupersetOf(expected))); +} + +TEST(IsSupersetOfTest, TakesPseudoContainer) { + std::vector a = {1, 2, 3, 4, 5}; + pseudo_container::PseudoContainer expected(a); + + std::vector actual1 = {1, 2, 3}; + EXPECT_THAT(actual1, Not(IsSupersetOf(expected))); + + std::vector actual2 = {1, 2, 3, 4, 5, 6}; + EXPECT_THAT(actual2, IsSupersetOf(expected)); +} + TEST(IsSupersetOfTest, TakesStlContainer) { const int actual[] = {3, 1, 2}; @@ -1698,6 +1744,30 @@ TEST(IsSubsetOfTest, WorksForStreamlike) { EXPECT_THAT(s, IsSubsetOf(expected)); } +TEST(IsSubsetOfTest, WorksWithPseudoContainer) { + std::vector a = {1, 2}; + pseudo_container::PseudoContainer actual(a); + + vector expected; + expected.push_back(1); + EXPECT_THAT(actual, Not(IsSubsetOf(expected))); + expected.push_back(2); + expected.push_back(5); + EXPECT_THAT(actual, IsSubsetOf(expected)); +} + +TEST(IsSubsetOfTest, TakesPseudoContainer) { + std::vector a = {1, 2}; + pseudo_container::PseudoContainer expected(a); + + vector actual; + actual.push_back(1); + EXPECT_THAT(actual, IsSubsetOf(expected)); + actual.push_back(2); + actual.push_back(5); + EXPECT_THAT(actual, Not(IsSubsetOf(expected))); +} + TEST(IsSubsetOfTest, TakesStlContainer) { const int actual[] = {3, 1, 2}; @@ -2163,6 +2233,36 @@ TEST(UnorderedElementsAreArrayTest, WorksForStreamlike) { EXPECT_THAT(s, Not(UnorderedElementsAreArray(expected))); } +TEST(UnorderedElementsAreArrayTest, WorksForPseudoContainer) { + pseudo_container::PseudoContainer actual({2, 1, 4, 5, 3}); + + ::std::vector expected; + expected.push_back(1); + expected.push_back(2); + expected.push_back(3); + expected.push_back(4); + expected.push_back(5); + EXPECT_THAT(actual, UnorderedElementsAreArray(expected)); + + expected.push_back(6); + EXPECT_THAT(actual, Not(UnorderedElementsAreArray(expected))); +} + +TEST(UnorderedElementsAreArrayTest, TakesPseudoContainer) { + pseudo_container::PseudoContainer expected({2, 1, 4, 5, 3}); + + ::std::vector actual; + actual.push_back(1); + actual.push_back(2); + actual.push_back(3); + actual.push_back(4); + actual.push_back(5); + EXPECT_THAT(actual, UnorderedElementsAreArray(expected)); + + actual.push_back(6); + EXPECT_THAT(actual, Not(UnorderedElementsAreArray(expected))); +} + TEST(UnorderedElementsAreArrayTest, TakesStlContainer) { const int actual[] = {3, 1, 2}; @@ -2262,6 +2362,13 @@ TEST_F(UnorderedElementsAreTest, WorksForStreamlike) { EXPECT_THAT(s, Not(UnorderedElementsAre(2, 2, 3, 4, 5))); } +TEST_F(UnorderedElementsAreTest, WorksForPseudoContainer) { + pseudo_container::PseudoContainer s({2, 1, 4, 5, 3}); + + EXPECT_THAT(s, UnorderedElementsAre(1, 2, 3, 4, 5)); + EXPECT_THAT(s, Not(UnorderedElementsAre(2, 2, 3, 4, 5))); +} + TEST_F(UnorderedElementsAreTest, WorksWithMoveOnly) { ContainerHelper helper; EXPECT_CALL(helper, Call(UnorderedElementsAre(Pointee(1), Pointee(2)))); @@ -2530,6 +2637,14 @@ TEST(EachTest, WorksWithMoveOnly) { helper.Call(MakeUniquePtrs({1, 2})); } +TEST(EachTest, WorksWithPseudoContainers) { + std::vector a = {1, 2, 3}; + pseudo_container::PseudoContainer pa(a); + + EXPECT_THAT(pa, Each(Gt(0))); + EXPECT_THAT(pa, Not(Each(Gt(1)))); +} + // For testing Pointwise(). class IsHalfOfMatcher { public: @@ -2609,6 +2724,30 @@ TEST(PointwiseTest, WorksForRhsNativeArray) { EXPECT_THAT(lhs, Not(Pointwise(Lt(), rhs))); } +TEST(PointwiseTest, WorksForLhsPseudoContainer) { + std::vector a = {1, 2, 3}; + pseudo_container::PseudoContainer lhs(a); + + vector rhs; + rhs.push_back(2); + rhs.push_back(4); + rhs.push_back(6); + EXPECT_THAT(lhs, Pointwise(Lt(), rhs)); + EXPECT_THAT(lhs, Not(Pointwise(Gt(), rhs))); +} + +TEST(PointwiseTest, WorksForRhsPseudoContainer) { + std::vector a = {1, 2, 3}; + pseudo_container::PseudoContainer rhs(a); + + vector lhs; + lhs.push_back(2); + lhs.push_back(4); + lhs.push_back(6); + EXPECT_THAT(lhs, Pointwise(Gt(), rhs)); + EXPECT_THAT(lhs, Not(Pointwise(Lt(), rhs))); +} + // Test is effective only with sanitizers. TEST(PointwiseTest, WorksForVectorOfBool) { vector rhs(3, false); @@ -2737,6 +2876,26 @@ TEST(UnorderedPointwiseTest, WorksForRhsNativeArray) { EXPECT_THAT(lhs, Not(UnorderedPointwise(Lt(), rhs))); } +TEST(UnorderedPointwiseTest, WorksForLhsPseudoContainer) { + pseudo_container::PseudoContainer lhs({1, 2, 3}); + vector rhs; + rhs.push_back(4); + rhs.push_back(6); + rhs.push_back(2); + EXPECT_THAT(lhs, UnorderedPointwise(Lt(), rhs)); + EXPECT_THAT(lhs, Not(UnorderedPointwise(Gt(), rhs))); +} + +TEST(UnorderedPointwiseTest, WorksForRhsPseudoContainer) { + pseudo_container::PseudoContainer rhs({1, 2, 3}); + vector lhs; + lhs.push_back(4); + lhs.push_back(2); + lhs.push_back(6); + EXPECT_THAT(lhs, UnorderedPointwise(Gt(), rhs)); + EXPECT_THAT(lhs, Not(UnorderedPointwise(Lt(), rhs))); +} + TEST(UnorderedPointwiseTest, WorksForRhsInitializerList) { const vector lhs{2, 4, 6}; EXPECT_THAT(lhs, UnorderedPointwise(Gt(), {5, 1, 3})); @@ -3134,6 +3293,14 @@ TEST(ElementsAreTest, AcceptsStringLiteral) { EXPECT_THAT(array, Not(ElementsAre("hi", "one", "too"))); } +TEST(ElementsAreTest, WorksWithPseudoContainer) { + std::vector array = {0, 1, 2}; + pseudo_container::PseudoContainer pseudoArray(array); + EXPECT_THAT(pseudoArray, ElementsAre(0, 1, _)); + EXPECT_THAT(pseudoArray, Not(ElementsAre(1, _, _))); + EXPECT_THAT(pseudoArray, Not(ElementsAre(0, _))); +} + // Declared here with the size unknown. Defined AFTER the following test. extern const char kHi[]; @@ -3305,6 +3472,22 @@ TEST(ElementsAreArrayTest, SourceLifeSpan) { EXPECT_THAT(test_vector, Not(matcher_maker)); } +TEST(ElementsAreArrayTest, WorksWithPseudoContainers) { + std::vector source_a = {1, 2, 3, 4, 5}; + std::vector source_b = {1, 2, 4, 6, 3}; + + pseudo_container::PseudoContainer test_container(source_a); + pseudo_container::PseudoContainer not_expected_container(source_b); + + EXPECT_THAT(source_a, ElementsAreArray(test_container)); + EXPECT_THAT(source_a, Not(ElementsAreArray(not_expected_container))); + + EXPECT_THAT(test_container, ElementsAreArray(source_a)); + EXPECT_THAT(test_container, Not(ElementsAreArray(source_b))); + + EXPECT_THAT(test_container, ElementsAreArray(test_container)); + EXPECT_THAT(test_container, Not(ElementsAreArray(not_expected_container))); +} // Tests Contains(). INSTANTIATE_GTEST_MATCHER_TEST_P(ContainsTest); @@ -3439,6 +3622,13 @@ TEST(ContainsTest, WorksForTwoDimensionalNativeArray) { EXPECT_THAT(a, Contains(Not(Contains(5)))); } +TEST(ContainsTest, WorksForPseudoContainer) { + std::vector a = {1, 2, 3}; + pseudo_container::PseudoContainer pa(a); + EXPECT_THAT(pa, Contains(Gt(2))); + EXPECT_THAT(pa, Contains(Not(Gt(4)))); +} + // Tests ContainsSubsequence(). TEST(ContainsSubsequenceTest, WorksForNativeArray) { @@ -3475,6 +3665,13 @@ TEST(ContainsSubsequenceTest, WorksForEmptySmallSizedSubsequences) { EXPECT_THAT(a, Not(ContainsSubsequence(Lt(2), Lt(2)))); } +TEST(ContainsSubsequenceTest, WorksForPseudoContainer) { + std::vector a = {1, 2, 3, 4, 5}; + pseudo_container::PseudoContainer pa(a); + EXPECT_THAT(pa, ContainsSubsequence(1, 3, 4)); + EXPECT_THAT(pa, Not(ContainsSubsequence(1, 3, 2))); +} + TEST(ContainsSubsequenceTest, DescribesItselfCorrectly) { Matcher m = ContainsSubsequence(1, 3, 4); EXPECT_EQ( diff --git a/googlemock/test/gmock-matchers-misc_test.cc b/googlemock/test/gmock-matchers-misc_test.cc index 0161169f2..7fbce0afa 100644 --- a/googlemock/test/gmock-matchers-misc_test.cc +++ b/googlemock/test/gmock-matchers-misc_test.cc @@ -41,8 +41,8 @@ #include #include "gmock/gmock.h" -#include "test/gmock-matchers_test.h" #include "gtest/gtest.h" +#include "test/gmock-matchers_test.h" // Silence warning C4244: 'initializing': conversion from 'int' to 'short', // possible loss of data and C4100, unreferenced local parameter @@ -173,6 +173,17 @@ TEST(IsEmptyTest, WorksWithMoveOnly) { helper.Call({}); } +TEST(IsEmptyTest, WorksWithPseudoContainer) { + vector container; + pseudo_container::PseudoContainer empty_container(container); + + container.push_back(0); + pseudo_container::PseudoContainer not_empty_container(container); + + EXPECT_THAT(empty_container, IsEmpty()); + EXPECT_THAT(not_empty_container, Not(IsEmpty())); +} + TEST(IsTrueTest, IsTrueIsFalse) { EXPECT_THAT(true, IsTrue()); EXPECT_THAT(false, IsFalse()); @@ -403,6 +414,19 @@ TEST(ContainerEqExtraTest, CopiesNativeArrayParameter) { EXPECT_THAT(a1, m); } +TEST(ContainerEqExtraTest, WorksWithPseudoContainers) { + std::vector a1 = {1, 2, 3}; + std::vector a2 = {1, 2, 3}; + std::vector b = {1, 2, 4}; + + pseudo_container::PseudoContainer pa1(a1); + pseudo_container::PseudoContainer pa2(a2); + pseudo_container::PseudoContainer pb(b); + + EXPECT_THAT(pa1, ContainerEq(pa2)); + EXPECT_THAT(pa1, Not(ContainerEq(pb))); +} + namespace { // Used as a check on the more complex max flow method used in the @@ -1468,7 +1492,7 @@ TEST(ContainsTimes, ListMatchesWhenElementQuantityMatches) { TEST_P(ContainsTimesP, ExplainsMatchResultCorrectly) { const int a[2] = {1, 2}; - Matcher m = Contains(2).Times(3); + Matcher m = Contains(2).Times(3); EXPECT_EQ( "whose element #1 matches but whose match quantity of 1 does not match", Explain(m, a)); diff --git a/googlemock/test/gmock-matchers_test.h b/googlemock/test/gmock-matchers_test.h index 56956076d..a201dc27e 100644 --- a/googlemock/test/gmock-matchers_test.h +++ b/googlemock/test/gmock-matchers_test.h @@ -189,4 +189,32 @@ std::string Explain(const MatcherType& m, const Value& x) { } // namespace gmock_matchers_test } // namespace testing +namespace pseudo_container { + +class PseudoContainer { + public: + PseudoContainer(const std::vector& elements) : elements(elements) {} + + PseudoContainer(const PseudoContainer& other) = default; + + const int* Start() const { return elements.data(); } + const int* End() const { return elements.data() + elements.size(); } + + bool operator==(const PseudoContainer& other) const { + return elements == other.elements; + } + + private: + std::vector elements; +}; + +inline const int* begin(const PseudoContainer& container) { + return container.Start(); +} +inline const int* end(const PseudoContainer& container) { + return container.End(); +} + +} // namespace pseudo_container + #endif // GOOGLEMOCK_TEST_GMOCK_MATCHERS_TEST_H_ diff --git a/googletest/include/gtest/internal/gtest-internal.h b/googletest/include/gtest/internal/gtest-internal.h index 7096355d5..695b71a6f 100644 --- a/googletest/include/gtest/internal/gtest-internal.h +++ b/googletest/include/gtest/internal/gtest-internal.h @@ -114,7 +114,7 @@ template namespace internal { -struct TraceInfo; // Information about a trace point. +struct TraceInfo; // Information about a trace point. class [[nodiscard]] TestInfoImpl; // Opaque implementation of TestInfo class [[nodiscard]] UnitTestImpl; // Opaque implementation of UnitTest @@ -265,8 +265,8 @@ class [[nodiscard]] FloatingPoint { static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); // The mask for the fraction bits. - static const Bits kFractionBitMask = ~static_cast(0) >> - (kExponentBitCount + 1); + static const Bits kFractionBitMask = + ~static_cast(0) >> (kExponentBitCount + 1); // The mask for the exponent bits. static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); @@ -1125,6 +1125,141 @@ class [[nodiscard]] NativeArray { void (NativeArray::*clone_)(const Element*, size_t); }; +// This is a separate namespace so that std::begin and std::end are not brought +// in to the whole ::testing::internal namespace +namespace iterator_help { +using std::begin; +using std::end; + +template +auto BeginImpl(T& container, int) -> decltype(container.begin()) { + return container.begin(); +} + +template +auto BeginImpl(T& container, float) -> decltype(begin(container)) { + return begin(container); +} + +template +auto Begin(T& container) -> decltype(BeginImpl(container, 0)) { + return BeginImpl(container, 0); +} + +template +auto Begin(const T& container) -> decltype(BeginImpl(container, 0)) { + return BeginImpl(container, 0); +} + +template +auto EndImpl(T& container, int) -> decltype(container.end()) { + return container.end(); +} + +template +auto EndImpl(T& container, float) -> decltype(end(container)) { + return end(container); +} + +template +auto End(T& container) -> decltype(EndImpl(container, 0)) { + return EndImpl(container, 0); +} + +template +auto End(const T& container) -> decltype(EndImpl(container, 0)) { + return EndImpl(container, 0); +} + +template +auto SizeImpl(T& container, int) -> decltype(container.size()) { + return container.size(); +} + +template +auto SizeImpl(T& container, float) { + return std::distance(iterator_help::Begin(container), + iterator_help::End(container)); +} + +template +auto Size(T& container) -> decltype(SizeImpl(container, 0)) { + return SizeImpl(container, 0); +} + +template +auto Size(const T& container) -> decltype(SizeImpl(container, 0)) { + return SizeImpl(container, 0); +} + +} // namespace iterator_help + +// Adapts a type to a read-only STL-style container. Instead of the complete STL +// container concept, this adaptor only implements members useful for Google +// Mock's container matchers. New members should be added as needed. We support +// types that we can get an iterator from using ::begin()/::end() or +// begin()/end() member functions, a size using std::distance on the type's +// iterators or a size() member function, and support operator==. +template +class [[nodiscard]] ContainerWrapper { + public: + using WrappedType = GTEST_REMOVE_REFERENCE_AND_CONST_(Container); + + // STL-style container typedefs. + using value_type = GTEST_REMOVE_REFERENCE_AND_CONST_( + decltype(*iterator_help::Begin(std::declval()))); + using iterator = decltype(iterator_help::Begin(std::declval())); + using const_iterator = + decltype(iterator_help::Begin(std::declval())); + + // Constructs from a native array. References the source. + ContainerWrapper(const Container* container, RelationToSourceReference) { + InitRef(container); + } + + // Constructs from a native array. Copies the source. + ContainerWrapper(const Container* container, RelationToSourceCopy) { + InitCopy(container); + } + + // Copy constructor. + ContainerWrapper(const ContainerWrapper& rhs) { + (this->*rhs.clone_)(rhs.container_); + } + + ~ContainerWrapper() { + if (clone_ != &ContainerWrapper::InitRef) delete container_; + } + + // STL-style container methods. + size_t size() const { return iterator_help::Size(*container_); } + const_iterator begin() const { return iterator_help::Begin(*container_); } + const_iterator end() const { return iterator_help::End(*container_); } + bool operator==(const ContainerWrapper& rhs) const { + return *container_ == *rhs.container_; + } + + private: + static_assert(!std::is_const::value, "Type must not be const"); + static_assert(!std::is_reference::value, + "Type must not be a reference"); + + // Initializes this object with a copy of the input. + void InitCopy(const Container* container) { + container_ = new Container(*container); + clone_ = &ContainerWrapper::InitCopy; + } + + // Initializes this object with a reference of the input. + void InitRef(const Container* container) { + container_ = container; + clone_ = &ContainerWrapper::InitRef; + } + + const Container* container_; + void (ContainerWrapper::*clone_)(const Container*); +}; + template struct Ignore { Ignore(...); // NOLINT @@ -1334,8 +1469,7 @@ class [[nodiscard]] NeverThrown { #else // GTEST_HAS_RTTI -#define GTEST_EXCEPTION_TYPE_(e) \ - std::string { "an std::exception-derived error" } +#define GTEST_EXCEPTION_TYPE_(e) std::string{"an std::exception-derived error"} #endif // GTEST_HAS_RTTI