Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
yangql
googletest
Commits
506340a6
Commit
506340a6
authored
Nov 17, 2014
by
kosak
Browse files
Generate relational matchers (Eq,Lt, etc) with CRTP instead of macro.
parent
d370f85b
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
166 additions
and
93 deletions
+166
-93
include/gmock/gmock-matchers.h
include/gmock/gmock-matchers.h
+164
-91
test/gmock-matchers_test.cc
test/gmock-matchers_test.cc
+2
-2
No files found.
include/gmock/gmock-matchers.h
View file @
506340a6
...
@@ -199,6 +199,31 @@ class StringMatchResultListener : public MatchResultListener {
...
@@ -199,6 +199,31 @@ class StringMatchResultListener : public MatchResultListener {
namespace
internal
{
namespace
internal
{
struct
AnyEq
{
template
<
typename
A
,
typename
B
>
bool
operator
()(
const
A
&
a
,
const
B
&
b
)
const
{
return
a
==
b
;
}
};
struct
AnyNe
{
template
<
typename
A
,
typename
B
>
bool
operator
()(
const
A
&
a
,
const
B
&
b
)
const
{
return
a
!=
b
;
}
};
struct
AnyLt
{
template
<
typename
A
,
typename
B
>
bool
operator
()(
const
A
&
a
,
const
B
&
b
)
const
{
return
a
<
b
;
}
};
struct
AnyGt
{
template
<
typename
A
,
typename
B
>
bool
operator
()(
const
A
&
a
,
const
B
&
b
)
const
{
return
a
>
b
;
}
};
struct
AnyLe
{
template
<
typename
A
,
typename
B
>
bool
operator
()(
const
A
&
a
,
const
B
&
b
)
const
{
return
a
<=
b
;
}
};
struct
AnyGe
{
template
<
typename
A
,
typename
B
>
bool
operator
()(
const
A
&
a
,
const
B
&
b
)
const
{
return
a
>=
b
;
}
};
// A match result listener that ignores the explanation.
// A match result listener that ignores the explanation.
class
DummyMatchResultListener
:
public
MatchResultListener
{
class
DummyMatchResultListener
:
public
MatchResultListener
{
public:
public:
...
@@ -862,55 +887,90 @@ class AnythingMatcher {
...
@@ -862,55 +887,90 @@ class AnythingMatcher {
// used to match an int, a short, a double, etc). Therefore we use
// used to match an int, a short, a double, etc). Therefore we use
// a template type conversion operator in the implementation.
// a template type conversion operator in the implementation.
//
//
// We define this as a macro in order to eliminate duplicated source
// code.
//
// The following template definition assumes that the Rhs parameter is
// The following template definition assumes that the Rhs parameter is
// a "bare" type (i.e. neither 'const T' nor 'T&').
// a "bare" type (i.e. neither 'const T' nor 'T&').
#define GMOCK_IMPLEMENT_COMPARISON_MATCHER_( \
template
<
typename
D
,
typename
Rhs
,
typename
Op
>
name, op, relation, negated_relation) \
class
ComparisonBase
{
template <typename Rhs> class name##Matcher { \
public:
public: \
explicit
ComparisonBase
(
const
Rhs
&
rhs
)
:
rhs_
(
rhs
)
{}
explicit name##Matcher(const Rhs& rhs) : rhs_(rhs) {} \
template
<
typename
Lhs
>
template <typename Lhs> \
operator
Matcher
<
Lhs
>
()
const
{
operator Matcher<Lhs>() const { \
return
MakeMatcher
(
new
Impl
<
Lhs
>
(
rhs_
));
return MakeMatcher(new Impl<Lhs>(rhs_)); \
}
} \
private: \
template <typename Lhs> \
class Impl : public MatcherInterface<Lhs> { \
public: \
explicit Impl(const Rhs& rhs) : rhs_(rhs) {} \
virtual bool MatchAndExplain(\
Lhs lhs, MatchResultListener*
/* listener */
) const { \
return lhs op rhs_; \
} \
virtual void DescribeTo(::std::ostream* os) const { \
*os << relation " "; \
UniversalPrint(rhs_, os); \
} \
virtual void DescribeNegationTo(::std::ostream* os) const { \
*os << negated_relation " "; \
UniversalPrint(rhs_, os); \
} \
private: \
Rhs rhs_; \
GTEST_DISALLOW_ASSIGN_(Impl); \
}; \
Rhs rhs_; \
GTEST_DISALLOW_ASSIGN_(name##Matcher); \
}
// Implements Eq(v), Ge(v), Gt(v), Le(v), Lt(v), and Ne(v)
// respectively.
GMOCK_IMPLEMENT_COMPARISON_MATCHER_
(
Eq
,
==
,
"is equal to"
,
"isn't equal to"
);
GMOCK_IMPLEMENT_COMPARISON_MATCHER_
(
Ge
,
>=
,
"is >="
,
"isn't >="
);
GMOCK_IMPLEMENT_COMPARISON_MATCHER_
(
Gt
,
>
,
"is >"
,
"isn't >"
);
GMOCK_IMPLEMENT_COMPARISON_MATCHER_
(
Le
,
<=
,
"is <="
,
"isn't <="
);
GMOCK_IMPLEMENT_COMPARISON_MATCHER_
(
Lt
,
<
,
"is <"
,
"isn't <"
);
GMOCK_IMPLEMENT_COMPARISON_MATCHER_
(
Ne
,
!=
,
"isn't equal to"
,
"is equal to"
);
#undef GMOCK_IMPLEMENT_COMPARISON_MATCHER_
private:
template
<
typename
Lhs
>
class
Impl
:
public
MatcherInterface
<
Lhs
>
{
public:
explicit
Impl
(
const
Rhs
&
rhs
)
:
rhs_
(
rhs
)
{}
virtual
bool
MatchAndExplain
(
Lhs
lhs
,
MatchResultListener
*
/* listener */
)
const
{
return
Op
()(
lhs
,
rhs_
);
}
virtual
void
DescribeTo
(
::
std
::
ostream
*
os
)
const
{
*
os
<<
D
::
Desc
()
<<
" "
;
UniversalPrint
(
rhs_
,
os
);
}
virtual
void
DescribeNegationTo
(
::
std
::
ostream
*
os
)
const
{
*
os
<<
D
::
NegatedDesc
()
<<
" "
;
UniversalPrint
(
rhs_
,
os
);
}
private:
Rhs
rhs_
;
GTEST_DISALLOW_ASSIGN_
(
Impl
);
};
Rhs
rhs_
;
GTEST_DISALLOW_ASSIGN_
(
ComparisonBase
);
};
template
<
typename
Rhs
>
class
EqMatcher
:
public
ComparisonBase
<
EqMatcher
<
Rhs
>
,
Rhs
,
AnyEq
>
{
public:
explicit
EqMatcher
(
const
Rhs
&
rhs
)
:
ComparisonBase
<
EqMatcher
<
Rhs
>
,
Rhs
,
AnyEq
>
(
rhs
)
{
}
static
const
char
*
Desc
()
{
return
"is equal to"
;
}
static
const
char
*
NegatedDesc
()
{
return
"isn't equal to"
;
}
};
template
<
typename
Rhs
>
class
NeMatcher
:
public
ComparisonBase
<
NeMatcher
<
Rhs
>
,
Rhs
,
AnyNe
>
{
public:
explicit
NeMatcher
(
const
Rhs
&
rhs
)
:
ComparisonBase
<
NeMatcher
<
Rhs
>
,
Rhs
,
AnyNe
>
(
rhs
)
{
}
static
const
char
*
Desc
()
{
return
"isn't equal to"
;
}
static
const
char
*
NegatedDesc
()
{
return
"is equal to"
;
}
};
template
<
typename
Rhs
>
class
LtMatcher
:
public
ComparisonBase
<
LtMatcher
<
Rhs
>
,
Rhs
,
AnyLt
>
{
public:
explicit
LtMatcher
(
const
Rhs
&
rhs
)
:
ComparisonBase
<
LtMatcher
<
Rhs
>
,
Rhs
,
AnyLt
>
(
rhs
)
{
}
static
const
char
*
Desc
()
{
return
"is <"
;
}
static
const
char
*
NegatedDesc
()
{
return
"isn't <"
;
}
};
template
<
typename
Rhs
>
class
GtMatcher
:
public
ComparisonBase
<
GtMatcher
<
Rhs
>
,
Rhs
,
AnyGt
>
{
public:
explicit
GtMatcher
(
const
Rhs
&
rhs
)
:
ComparisonBase
<
GtMatcher
<
Rhs
>
,
Rhs
,
AnyGt
>
(
rhs
)
{
}
static
const
char
*
Desc
()
{
return
"is >"
;
}
static
const
char
*
NegatedDesc
()
{
return
"isn't >"
;
}
};
template
<
typename
Rhs
>
class
LeMatcher
:
public
ComparisonBase
<
LeMatcher
<
Rhs
>
,
Rhs
,
AnyLe
>
{
public:
explicit
LeMatcher
(
const
Rhs
&
rhs
)
:
ComparisonBase
<
LeMatcher
<
Rhs
>
,
Rhs
,
AnyLe
>
(
rhs
)
{
}
static
const
char
*
Desc
()
{
return
"is <="
;
}
static
const
char
*
NegatedDesc
()
{
return
"isn't <="
;
}
};
template
<
typename
Rhs
>
class
GeMatcher
:
public
ComparisonBase
<
GeMatcher
<
Rhs
>
,
Rhs
,
AnyGe
>
{
public:
explicit
GeMatcher
(
const
Rhs
&
rhs
)
:
ComparisonBase
<
GeMatcher
<
Rhs
>
,
Rhs
,
AnyGe
>
(
rhs
)
{
}
static
const
char
*
Desc
()
{
return
"is >="
;
}
static
const
char
*
NegatedDesc
()
{
return
"isn't >="
;
}
};
// Implements the polymorphic IsNull() matcher, which matches any raw or smart
// Implements the polymorphic IsNull() matcher, which matches any raw or smart
// pointer that is NULL.
// pointer that is NULL.
...
@@ -1309,51 +1369,64 @@ class MatchesRegexMatcher {
...
@@ -1309,51 +1369,64 @@ class MatchesRegexMatcher {
// used to match a tuple<int, short>, a tuple<const long&, double>,
// used to match a tuple<int, short>, a tuple<const long&, double>,
// etc). Therefore we use a template type conversion operator in the
// etc). Therefore we use a template type conversion operator in the
// implementation.
// implementation.
//
template
<
typename
D
,
typename
Op
>
// We define this as a macro in order to eliminate duplicated source
class
PairMatchBase
{
// code.
public:
#define GMOCK_IMPLEMENT_COMPARISON2_MATCHER_(name, op, relation) \
template
<
typename
T1
,
typename
T2
>
class name##2Matcher { \
operator
Matcher
<
::
testing
::
tuple
<
T1
,
T2
>
>
()
const
{
public: \
return
MakeMatcher
(
new
Impl
<
::
testing
::
tuple
<
T1
,
T2
>
>
);
template <typename T1, typename T2> \
}
operator Matcher< ::testing::tuple<T1, T2> >() const { \
template
<
typename
T1
,
typename
T2
>
return MakeMatcher(new Impl< ::testing::tuple<T1, T2> >); \
operator
Matcher
<
const
::
testing
::
tuple
<
T1
,
T2
>&>
()
const
{
} \
return
MakeMatcher
(
new
Impl
<
const
::
testing
::
tuple
<
T1
,
T2
>&>
);
template <typename T1, typename T2> \
}
operator Matcher<const ::testing::tuple<T1, T2>&>() const { \
return MakeMatcher(new Impl<const ::testing::tuple<T1, T2>&>); \
private:
} \
static
::
std
::
ostream
&
GetDesc
(
::
std
::
ostream
&
os
)
{
// NOLINT
private: \
return
os
<<
D
::
Desc
();
template <typename Tuple> \
}
class Impl : public MatcherInterface<Tuple> { \
public: \
template
<
typename
Tuple
>
virtual bool MatchAndExplain( \
class
Impl
:
public
MatcherInterface
<
Tuple
>
{
Tuple args, \
public:
MatchResultListener*
/* listener */
) const { \
virtual
bool
MatchAndExplain
(
return ::testing::get<0>(args) op ::testing::get<1>(args); \
Tuple
args
,
} \
MatchResultListener
*
/* listener */
)
const
{
virtual void DescribeTo(::std::ostream* os) const { \
return
Op
()(
::
testing
::
get
<
0
>
(
args
),
::
testing
::
get
<
1
>
(
args
));
*os << "are " relation; \
}
} \
virtual
void
DescribeTo
(
::
std
::
ostream
*
os
)
const
{
virtual void DescribeNegationTo(::std::ostream* os) const { \
*
os
<<
"are "
<<
GetDesc
;
*os << "aren't " relation; \
}
} \
virtual
void
DescribeNegationTo
(
::
std
::
ostream
*
os
)
const
{
}; \
*
os
<<
"aren't "
<<
GetDesc
;
}
}
};
// Implements Eq(), Ge(), Gt(), Le(), Lt(), and Ne() respectively.
};
GMOCK_IMPLEMENT_COMPARISON2_MATCHER_
(
Eq
,
==
,
"an equal pair"
);
GMOCK_IMPLEMENT_COMPARISON2_MATCHER_
(
class
Eq2Matcher
:
public
PairMatchBase
<
Eq2Matcher
,
AnyEq
>
{
Ge
,
>=
,
"a pair where the first >= the second"
);
public:
GMOCK_IMPLEMENT_COMPARISON2_MATCHER_
(
static
const
char
*
Desc
()
{
return
"an equal pair"
;
}
Gt
,
>
,
"a pair where the first > the second"
);
};
GMOCK_IMPLEMENT_COMPARISON2_MATCHER_
(
class
Ne2Matcher
:
public
PairMatchBase
<
Ne2Matcher
,
AnyNe
>
{
Le
,
<=
,
"a pair where the first <= the second"
);
public:
GMOCK_IMPLEMENT_COMPARISON2_MATCHER_
(
static
const
char
*
Desc
()
{
return
"an unequal pair"
;
}
Lt
,
<
,
"a pair where the first < the second"
);
};
GMOCK_IMPLEMENT_COMPARISON2_MATCHER_
(
Ne
,
!=
,
"an unequal pair"
);
class
Lt2Matcher
:
public
PairMatchBase
<
Lt2Matcher
,
AnyLt
>
{
public:
#undef GMOCK_IMPLEMENT_COMPARISON2_MATCHER_
static
const
char
*
Desc
()
{
return
"a pair where the first < the second"
;
}
};
class
Gt2Matcher
:
public
PairMatchBase
<
Gt2Matcher
,
AnyGt
>
{
public:
static
const
char
*
Desc
()
{
return
"a pair where the first > the second"
;
}
};
class
Le2Matcher
:
public
PairMatchBase
<
Le2Matcher
,
AnyLe
>
{
public:
static
const
char
*
Desc
()
{
return
"a pair where the first <= the second"
;
}
};
class
Ge2Matcher
:
public
PairMatchBase
<
Ge2Matcher
,
AnyGe
>
{
public:
static
const
char
*
Desc
()
{
return
"a pair where the first >= the second"
;
}
};
// Implements the Not(...) matcher for a particular argument type T.
// Implements the Not(...) matcher for a particular argument type T.
// We do not nest it inside the NotMatcher class template, as that
// We do not nest it inside the NotMatcher class template, as that
...
...
test/gmock-matchers_test.cc
View file @
506340a6
...
@@ -607,11 +607,11 @@ TEST(MatcherCastTest, FromSameType) {
...
@@ -607,11 +607,11 @@ TEST(MatcherCastTest, FromSameType) {
EXPECT_FALSE
(
m2
.
Matches
(
1
));
EXPECT_FALSE
(
m2
.
Matches
(
1
));
}
}
// Implicitly convertible f
o
rm any type.
// Implicitly convertible fr
o
m any type.
struct
ConvertibleFromAny
{
struct
ConvertibleFromAny
{
ConvertibleFromAny
(
int
a_value
)
:
value
(
a_value
)
{}
ConvertibleFromAny
(
int
a_value
)
:
value
(
a_value
)
{}
template
<
typename
T
>
template
<
typename
T
>
ConvertibleFromAny
(
const
T
&
a_value
)
:
value
(
-
1
)
{
ConvertibleFromAny
(
const
T
&
/*
a_value
*/
)
:
value
(
-
1
)
{
ADD_FAILURE
()
<<
"Conversion constructor called"
;
ADD_FAILURE
()
<<
"Conversion constructor called"
;
}
}
int
value
;
int
value
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment