Merge 2bbb539f2733440e97c3534ee2d1f700a6b226a0 into 7140cd416cecd7462a8aae488024abeee55598e4

This commit is contained in:
Ben Dunkin 2026-06-05 05:43:07 +00:00 committed by GitHub
commit 1f6def64cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 440 additions and 42 deletions

View File

@ -4581,9 +4581,9 @@ inline auto ElementsAreArray(const T (&array)[N])
}
template <typename Container>
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<Container>::ConstReference(container);
return ElementsAreArray(view.begin(), view.end());
}
template <typename T>
@ -4628,9 +4628,10 @@ inline internal::UnorderedElementsAreArrayMatcher<T> UnorderedElementsAreArray(
template <typename Container>
inline internal::UnorderedElementsAreArrayMatcher<
typename Container::value_type>
typename internal::RangeTraits<Container>::value_type>
UnorderedElementsAreArray(const Container& container) {
return UnorderedElementsAreArray(container.begin(), container.end());
auto view = internal::StlContainerView<Container>::ConstReference(container);
return UnorderedElementsAreArray(view.begin(), view.end());
}
template <typename T>
@ -5326,9 +5327,10 @@ inline internal::UnorderedElementsAreArrayMatcher<T> IsSupersetOf(
template <typename Container>
inline internal::UnorderedElementsAreArrayMatcher<
typename Container::value_type>
typename internal::RangeTraits<Container>::value_type>
IsSupersetOf(const Container& container) {
return IsSupersetOf(container.begin(), container.end());
auto view = internal::StlContainerView<Container>::ConstReference(container);
return IsSupersetOf(view.begin(), view.end());
}
template <typename T>
@ -5383,9 +5385,10 @@ inline internal::UnorderedElementsAreArrayMatcher<T> IsSubsetOf(
template <typename Container>
inline internal::UnorderedElementsAreArrayMatcher<
typename Container::value_type>
typename internal::RangeTraits<Container>::value_type>
IsSubsetOf(const Container& container) {
return IsSubsetOf(container.begin(), container.end());
auto view = internal::StlContainerView<Container>::ConstReference(container);
return IsSubsetOf(view.begin(), view.end());
}
template <typename T>

View File

@ -60,17 +60,20 @@ namespace internal {
// Implements the polymorphic IsEmpty matcher, which
// can be used as a Matcher<T> 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 <typename MatcheeContainerType>
bool MatchAndExplain(const MatcheeContainerType& c,
MatchResultListener* listener) const {
if (c.empty()) {
auto view = StlContainerView<MatcheeContainerType>::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;
}

View File

@ -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<type>::value)
// LosslessArithmeticConvertibleImpl<kFromKind, From, kToKind, To>::value
@ -326,8 +326,7 @@ inline T Invalid() {
void GetValueType(const void*);
template <class T>
typename std::iterator_traits<
decltype(std::begin(std::declval<T&>()))>::value_type
std::remove_reference_t<decltype(*iterator_help::Begin(std::declval<T&>()))>
GetValueType(T*);
template <class T, class = void>
@ -360,15 +359,25 @@ struct RangeTraits<T, std::conditional_t<true, void, typename T::value_type>> {
template <class RawContainer>
class [[nodiscard]] StlContainerView {
public:
typedef RawContainer type;
typedef const type& const_reference;
typedef internal::ContainerWrapper<GTEST_REMOVE_REFERENCE_AND_CONST_(
RawContainer)>
type;
// ContainerWrapper<T> 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<RawContainer>::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<Element[N]> {
// This specialization is used when RawContainer is a native array
// represented as a (pointer, size) tuple.
template <typename ElementPointer, typename Size>
class [[nodiscard]] StlContainerView< ::std::tuple<ElementPointer, Size> > {
class [[nodiscard]] StlContainerView<::std::tuple<ElementPointer, Size>> {
public:
typedef typename std::remove_const<
typename std::pointer_traits<ElementPointer>::element_type>::type
@ -430,7 +439,7 @@ struct RemoveConstFromKey {
// Partially specialized to remove constness from std::pair<const K, V>.
template <typename K, typename V>
struct RemoveConstFromKey<std::pair<const K, V> > {
struct RemoveConstFromKey<std::pair<const K, V>> {
typedef std::pair<K, V> type;
};
@ -447,11 +456,10 @@ auto ApplyImpl(F&& f, Tuple&& args, std::index_sequence<Idx...>)
// Apply the function to a tuple of arguments.
template <typename F, typename Tuple>
auto Apply(F&& f, Tuple&& args)
-> decltype(ApplyImpl(
std::forward<F>(f), std::forward<Tuple>(args),
std::make_index_sequence<std::tuple_size<
typename std::remove_reference<Tuple>::type>::value>())) {
auto Apply(F&& f, Tuple&& args) -> decltype(ApplyImpl(
std::forward<F>(f), std::forward<Tuple>(args),
std::make_index_sequence<std::tuple_size<
typename std::remove_reference<Tuple>::type>::value>())) {
return ApplyImpl(std::forward<F>(f), std::forward<Tuple>(args),
std::make_index_sequence<std::tuple_size<
typename std::remove_reference<Tuple>::type>::value>());

View File

@ -582,18 +582,19 @@ TEST(OnCallTest, LogsAnythingArgument) {
// Tests StlContainerView.
TEST(StlContainerViewTest, WorksForStlContainer) {
StaticAssertTypeEq<std::vector<int>,
StaticAssertTypeEq<internal::ContainerWrapper<std::vector<int>>,
StlContainerView<std::vector<int>>::type>();
StaticAssertTypeEq<const std::vector<double>&,
StaticAssertTypeEq<const internal::ContainerWrapper<std::vector<double>>,
StlContainerView<std::vector<double>>::const_reference>();
typedef std::vector<char> Chars;
using Chars = std::vector<char>;
using Adaptor = internal::ContainerWrapper<Chars>;
Chars v1;
const Chars& v2(StlContainerView<Chars>::ConstReference(v1));
EXPECT_EQ(&v1, &v2);
const Adaptor& v2(StlContainerView<Chars>::ConstReference(v1));
EXPECT_EQ(v1.begin(), v2.begin());
v1.push_back('a');
Chars v3 = StlContainerView<Chars>::Copy(v1);
Adaptor v3 = StlContainerView<Chars>::Copy(v1);
EXPECT_THAT(v3, Eq(v3));
}

View File

@ -45,8 +45,8 @@
#include <vector>
#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<int>(), 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<int>(), ElementsAre(1, 2, 3, 4)));
EXPECT_THAT(numbers,
WhenSortedBy(less<int>(), ElementsAreArray(sorted_numbers)));
EXPECT_THAT(numbers, Not(WhenSortedBy(less<int>(), ElementsAre(1, 3, 2, 4))));
}
TEST(WhenSortedByTest, CanDescribeSelf) {
const Matcher<vector<int>> m = WhenSortedBy(less<int>(), 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<int> d;
d.push_back(2);
@ -1457,6 +1472,12 @@ TEST(BeginEndDistanceIsTest, WorksWithNonStdList) {
EXPECT_THAT(s, BeginEndDistanceIs(5));
}
TEST(BeginEndDistanceIsTest, WorksWithPseudoContainers) {
std::vector<int> a = {1, 2, 3, 4, 5};
pseudo_container::PseudoContainer s(a);
EXPECT_THAT(s, BeginEndDistanceIs(5));
}
TEST(BeginEndDistanceIsTest, CanDescribeSelf) {
Matcher<vector<int>> 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<int> a = {1, 2, 3, 4, 5};
pseudo_container::PseudoContainer actual(a);
vector<int> 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<int> a = {1, 2, 3, 4, 5};
pseudo_container::PseudoContainer expected(a);
std::vector<int> actual1 = {1, 2, 3};
EXPECT_THAT(actual1, Not(IsSupersetOf(expected)));
std::vector<int> 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<int> a = {1, 2};
pseudo_container::PseudoContainer actual(a);
vector<int> 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<int> a = {1, 2};
pseudo_container::PseudoContainer expected(a);
vector<int> 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<int> 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<int> 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<int> 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<int> a = {1, 2, 3};
pseudo_container::PseudoContainer lhs(a);
vector<int> 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<int> a = {1, 2, 3};
pseudo_container::PseudoContainer rhs(a);
vector<int> 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<bool> 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<int> 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<int> 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<int> 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<int> 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<int> source_a = {1, 2, 3, 4, 5};
std::vector<int> 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<int> 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<int> 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<const int (&)[5]> m = ContainsSubsequence(1, 3, 4);
EXPECT_EQ(

View File

@ -41,8 +41,8 @@
#include <vector>
#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<int> 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<int> a1 = {1, 2, 3};
std::vector<int> a2 = {1, 2, 3};
std::vector<int> 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<const int(&)[2]> m = Contains(2).Times(3);
Matcher<const int (&)[2]> m = Contains(2).Times(3);
EXPECT_EQ(
"whose element #1 matches but whose match quantity of 1 does not match",
Explain(m, a));

View File

@ -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<int>& 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<int> 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_

View File

@ -114,7 +114,7 @@ template <typename T>
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<Bits>(1) << (kBitCount - 1);
// The mask for the fraction bits.
static const Bits kFractionBitMask = ~static_cast<Bits>(0) >>
(kExponentBitCount + 1);
static const Bits kFractionBitMask =
~static_cast<Bits>(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 <typename T>
auto BeginImpl(T& container, int) -> decltype(container.begin()) {
return container.begin();
}
template <typename T>
auto BeginImpl(T& container, float) -> decltype(begin(container)) {
return begin(container);
}
template <typename T>
auto Begin(T& container) -> decltype(BeginImpl(container, 0)) {
return BeginImpl(container, 0);
}
template <typename T>
auto Begin(const T& container) -> decltype(BeginImpl(container, 0)) {
return BeginImpl(container, 0);
}
template <typename T>
auto EndImpl(T& container, int) -> decltype(container.end()) {
return container.end();
}
template <typename T>
auto EndImpl(T& container, float) -> decltype(end(container)) {
return end(container);
}
template <typename T>
auto End(T& container) -> decltype(EndImpl(container, 0)) {
return EndImpl(container, 0);
}
template <typename T>
auto End(const T& container) -> decltype(EndImpl(container, 0)) {
return EndImpl(container, 0);
}
template <typename T>
auto SizeImpl(T& container, int) -> decltype(container.size()) {
return container.size();
}
template <typename T>
auto SizeImpl(T& container, float) {
return std::distance(iterator_help::Begin(container),
iterator_help::End(container));
}
template <typename T>
auto Size(T& container) -> decltype(SizeImpl(container, 0)) {
return SizeImpl(container, 0);
}
template <typename T>
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 <typename Container>
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<const WrappedType>())));
using iterator = decltype(iterator_help::Begin(std::declval<WrappedType>()));
using const_iterator =
decltype(iterator_help::Begin(std::declval<const WrappedType>()));
// 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<Container>::value, "Type must not be const");
static_assert(!std::is_reference<Container>::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 <size_t>
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