mirror of
https://github.com/google/googletest.git
synced 2026-06-15 08:26:11 +08:00
Merge 2bbb539f2733440e97c3534ee2d1f700a6b226a0 into 7140cd416cecd7462a8aae488024abeee55598e4
This commit is contained in:
commit
1f6def64cb
@ -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>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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>());
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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_
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user