@ -2879,6 +2879,203 @@ class PairMatcher {
const SecondMatcher second_matcher_ ;
} ;
template < typename T , size_t . . . I >
auto UnpackStructImpl ( const T & t , IndexSequence < I . . . > , int )
- > decltype ( std : : tie ( get < I > ( t ) . . . ) ) {
static_assert ( std : : tuple_size < T > : : value = = sizeof . . . ( I ) ,
" Number of arguments doesn't match the number of fields. " ) ;
return std : : tie ( get < I > ( t ) . . . ) ;
}
# if defined(__cpp_structured_bindings) && __cpp_structured_bindings >= 201606
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 1 > , char ) {
const auto & [ a ] = t ;
return std : : tie ( a ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 2 > , char ) {
const auto & [ a , b ] = t ;
return std : : tie ( a , b ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 3 > , char ) {
const auto & [ a , b , c ] = t ;
return std : : tie ( a , b , c ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 4 > , char ) {
const auto & [ a , b , c , d ] = t ;
return std : : tie ( a , b , c , d ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 5 > , char ) {
const auto & [ a , b , c , d , e ] = t ;
return std : : tie ( a , b , c , d , e ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 6 > , char ) {
const auto & [ a , b , c , d , e , f ] = t ;
return std : : tie ( a , b , c , d , e , f ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 7 > , char ) {
const auto & [ a , b , c , d , e , f , g ] = t ;
return std : : tie ( a , b , c , d , e , f , g ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 8 > , char ) {
const auto & [ a , b , c , d , e , f , g , h ] = t ;
return std : : tie ( a , b , c , d , e , f , g , h ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 9 > , char ) {
const auto & [ a , b , c , d , e , f , g , h , i ] = t ;
return std : : tie ( a , b , c , d , e , f , g , h , i ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 10 > , char ) {
const auto & [ a , b , c , d , e , f , g , h , i , j ] = t ;
return std : : tie ( a , b , c , d , e , f , g , h , i , j ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 11 > , char ) {
const auto & [ a , b , c , d , e , f , g , h , i , j , k ] = t ;
return std : : tie ( a , b , c , d , e , f , g , h , i , j , k ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 12 > , char ) {
const auto & [ a , b , c , d , e , f , g , h , i , j , k , l ] = t ;
return std : : tie ( a , b , c , d , e , f , g , h , i , j , k , l ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 13 > , char ) {
const auto & [ a , b , c , d , e , f , g , h , i , j , k , l , m ] = t ;
return std : : tie ( a , b , c , d , e , f , g , h , i , j , k , l , m ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 14 > , char ) {
const auto & [ a , b , c , d , e , f , g , h , i , j , k , l , m , n ] = t ;
return std : : tie ( a , b , c , d , e , f , g , h , i , j , k , l , m , n ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 15 > , char ) {
const auto & [ a , b , c , d , e , f , g , h , i , j , k , l , m , n , o ] = t ;
return std : : tie ( a , b , c , d , e , f , g , h , i , j , k , l , m , n , o ) ;
}
template < typename T >
auto UnpackStructImpl ( const T & t , MakeIndexSequence < 16 > , char ) {
const auto & [ a , b , c , d , e , f , g , h , i , j , k , l , m , n , o , p ] = t ;
return std : : tie ( a , b , c , d , e , f , g , h , i , j , k , l , m , n , o , p ) ;
}
# endif // defined(__cpp_structured_bindings)
template < size_t I , typename T >
auto UnpackStruct ( const T & t )
- > decltype ( ( UnpackStructImpl ) ( t , MakeIndexSequence < I > { } , 0 ) ) {
return ( UnpackStructImpl ) ( t , MakeIndexSequence < I > { } , 0 ) ;
}
// Helper function to do comma folding in C++11.
// The array ensures left-to-right order of evaluation.
// Usage: VariadicExpand({expr...});
template < typename T , size_t N >
void VariadicExpand ( const T ( & a ) [ N ] ) { }
template < typename Struct , typename StructSize >
class FieldsAreMatcherImpl ;
template < typename Struct , size_t . . . I >
class FieldsAreMatcherImpl < Struct , IndexSequence < I . . . > >
: public MatcherInterface < Struct > {
using UnpackedType =
decltype ( UnpackStruct < sizeof . . . ( I ) > ( std : : declval < const Struct & > ( ) ) ) ;
using MatchersType = std : : tuple <
Matcher < const typename std : : tuple_element < I , UnpackedType > : : type & > . . . > ;
public :
template < typename Inner >
explicit FieldsAreMatcherImpl ( const Inner & matchers )
: matchers_ ( testing : : SafeMatcherCast <
const typename std : : tuple_element < I , UnpackedType > : : type & > (
std : : get < I > ( matchers ) ) . . . ) { }
void DescribeTo ( : : std : : ostream * os ) const override {
const char * separator = " " ;
VariadicExpand (
{ ( * os < < separator < < " has field # " < < I < < " that " ,
std : : get < I > ( matchers_ ) . DescribeTo ( os ) , separator = " , and " ) . . . } ) ;
}
void DescribeNegationTo ( : : std : : ostream * os ) const override {
const char * separator = " " ;
VariadicExpand ( { ( * os < < separator < < " has field # " < < I < < " that " ,
std : : get < I > ( matchers_ ) . DescribeNegationTo ( os ) ,
separator = " , or " ) . . . } ) ;
}
bool MatchAndExplain ( Struct t , MatchResultListener * listener ) const override {
return MatchInternal ( ( UnpackStruct < sizeof . . . ( I ) > ) ( t ) , listener ) ;
}
private :
bool MatchInternal ( UnpackedType tuple , MatchResultListener * listener ) const {
if ( ! listener - > IsInterested ( ) ) {
// If the listener is not interested, we don't need to construct the
// explanation.
bool good = true ;
VariadicExpand ( { good = good & & std : : get < I > ( matchers_ ) . Matches (
std : : get < I > ( tuple ) ) . . . } ) ;
return good ;
}
int failed_pos = - 1 ;
std : : vector < StringMatchResultListener > inner_listener ( sizeof . . . ( I ) ) ;
VariadicExpand (
{ failed_pos = = - 1 & & ! std : : get < I > ( matchers_ ) . MatchAndExplain (
std : : get < I > ( tuple ) , & inner_listener [ I ] )
? failed_pos = I
: 0 . . . } ) ;
if ( failed_pos ! = ~ size_t { } ) {
* listener < < " whose field # " < < failed_pos < < " does not match " ;
PrintIfNotEmpty ( inner_listener [ failed_pos ] . str ( ) , listener - > stream ( ) ) ;
return false ;
}
* listener < < " whose all elements match " ;
const char * separator = " , where " ;
for ( size_t index = 0 ; index < sizeof . . . ( I ) ; + + index ) {
const std : : string str = inner_listener [ index ] . str ( ) ;
if ( ! str . empty ( ) ) {
* listener < < separator < < " field # " < < index < < " is a value " < < str ;
separator = " , and " ;
}
}
return true ;
}
MatchersType matchers_ ;
} ;
template < typename . . . Inner >
class FieldsAreMatcher {
public :
explicit FieldsAreMatcher ( Inner . . . inner ) : matchers_ ( std : : move ( inner ) . . . ) { }
template < typename Struct >
operator Matcher < Struct > ( ) const { // NOLINT
return Matcher < Struct > (
new FieldsAreMatcherImpl < const Struct & , IndexSequenceFor < Inner . . . > > (
matchers_ ) ) ;
}
private :
std : : tuple < Inner . . . > matchers_ ;
} ;
// Implements ElementsAre() and ElementsAreArray().
template < typename Container >
class ElementsAreMatcherImpl : public MatcherInterface < Container > {
@ -4514,6 +4711,19 @@ Pair(FirstMatcher first_matcher, SecondMatcher second_matcher) {
first_matcher , second_matcher ) ;
}
namespace no_adl {
// FieldsAre(matchers...) matches piecewise the fields of compatible structs.
// These include those that support `get<I>(obj)`, and when structured bindings
// are enabled any class that supports them.
// In particular, `std::tuple`, `std::pair`, `std::array` and aggregate types.
template < typename . . . M >
internal : : FieldsAreMatcher < typename std : : decay < M > : : type . . . > FieldsAre (
M & & . . . matchers ) {
return internal : : FieldsAreMatcher < typename std : : decay < M > : : type . . . > (
std : : forward < M > ( matchers ) . . . ) ;
}
} // namespace no_adl
// Returns a predicate that is satisfied by anything that matches the
// given matcher.
template < typename M >
@ -5053,6 +5263,9 @@ PolymorphicMatcher<internal::ExceptionMatcherImpl<Err>> ThrowsMessage(
# define GMOCK_INTERNAL_MATCHER_ARG_USAGE(i, data_unused, arg_unused) \
, gmock_p # # i
// To prevent ADL on certain functions we put them on a separate namespace.
using namespace no_adl ; // NOLINT
} // namespace testing
GTEST_DISABLE_MSC_WARNINGS_POP_ ( ) // 4251 5046