Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
googletest
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
googletest
Commits
fb25d539
Commit
fb25d539
authored
Jul 28, 2013
by
zhanyong.wan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adds matchers UnorderedElementsAre[Array]() (by Billy Donahue); pulls in
gtest r660.
parent
2989703e
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1664 additions
and
605 deletions
+1664
-605
CHANGES
CHANGES
+2
-1
gmock-generated-matchers.h
include/gmock/gmock-generated-matchers.h
+382
-446
gmock-generated-matchers.h.pump
include/gmock/gmock-generated-matchers.h.pump
+45
-112
gmock-matchers.h
include/gmock/gmock-matchers.h
+433
-39
gmock-matchers.cc
src/gmock-matchers.cc
+361
-0
gmock-generated-matchers_test.cc
test/gmock-generated-matchers_test.cc
+6
-5
gmock-matchers_test.cc
test/gmock-matchers_test.cc
+435
-2
No files found.
CHANGES
View file @
fb25d539
...
...
@@ -2,7 +2,8 @@ Changes for 1.7.0:
* All new improvements in Google Test 1.7.0.
* New feature: matchers DoubleNear(), FloatNear(),
NanSensitiveDoubleNear(), NanSensitiveFloatNear(), WhenSorted(),
NanSensitiveDoubleNear(), NanSensitiveFloatNear(),
UnorderedElementsAre(), UnorderedElementsAreArray(), WhenSorted(),
WhenSortedBy(), IsEmpty(), and SizeIs().
* Improvement: Google Mock can now be built as a DLL.
* Improvement: when compiled by a C++11 compiler, matchers AllOf()
...
...
include/gmock/gmock-generated-matchers.h
View file @
fb25d539
...
...
@@ -306,374 +306,6 @@ class ArgsMatcher {
GTEST_DISALLOW_ASSIGN_
(
ArgsMatcher
);
};
// Implements ElementsAre() of 1-10 arguments. The use of DecayArray in
// the implementation allows ElementsAre() to accept string literals, whose
// inferred type is const char[N] while we want to treat them as const char*.
template
<
typename
T1
>
class
ElementsAreMatcher1
{
public
:
explicit
ElementsAreMatcher1
(
const
T1
&
e1
)
:
e1_
(
e1
)
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
::
value_type
Element
;
// Nokia's Symbian Compiler has a nasty bug where the object put
// in a one-element local array is not destructed when the array
// goes out of scope. This leads to obvious badness as we've
// added the linked_ptr in it to our other linked_ptrs list.
// Hence we implement ElementsAreMatcher1 specially to avoid using
// a local array.
const
Matcher
<
const
Element
&>
matcher
=
MatcherCast
<
const
Element
&>
(
e1_
);
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
&
matcher
,
&
matcher
+
1
));
}
private
:
const
typename
DecayArray
<
T1
>::
type
e1_
;
GTEST_DISALLOW_ASSIGN_
(
ElementsAreMatcher1
);
};
template
<
typename
T1
,
typename
T2
>
class
ElementsAreMatcher2
{
public
:
ElementsAreMatcher2
(
const
T1
&
e1
,
const
T2
&
e2
)
:
e1_
(
e1
),
e2_
(
e2
)
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
::
value_type
Element
;
const
Matcher
<
const
Element
&>
matchers
[]
=
{
MatcherCast
<
const
Element
&>
(
e1_
),
MatcherCast
<
const
Element
&>
(
e2_
),
};
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
matchers
,
matchers
+
2
));
}
private
:
const
typename
DecayArray
<
T1
>::
type
e1_
;
const
typename
DecayArray
<
T2
>::
type
e2_
;
GTEST_DISALLOW_ASSIGN_
(
ElementsAreMatcher2
);
};
template
<
typename
T1
,
typename
T2
,
typename
T3
>
class
ElementsAreMatcher3
{
public
:
ElementsAreMatcher3
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
)
:
e1_
(
e1
),
e2_
(
e2
),
e3_
(
e3
)
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
::
value_type
Element
;
const
Matcher
<
const
Element
&>
matchers
[]
=
{
MatcherCast
<
const
Element
&>
(
e1_
),
MatcherCast
<
const
Element
&>
(
e2_
),
MatcherCast
<
const
Element
&>
(
e3_
),
};
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
matchers
,
matchers
+
3
));
}
private
:
const
typename
DecayArray
<
T1
>::
type
e1_
;
const
typename
DecayArray
<
T2
>::
type
e2_
;
const
typename
DecayArray
<
T3
>::
type
e3_
;
GTEST_DISALLOW_ASSIGN_
(
ElementsAreMatcher3
);
};
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
>
class
ElementsAreMatcher4
{
public
:
ElementsAreMatcher4
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
)
:
e1_
(
e1
),
e2_
(
e2
),
e3_
(
e3
),
e4_
(
e4
)
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
::
value_type
Element
;
const
Matcher
<
const
Element
&>
matchers
[]
=
{
MatcherCast
<
const
Element
&>
(
e1_
),
MatcherCast
<
const
Element
&>
(
e2_
),
MatcherCast
<
const
Element
&>
(
e3_
),
MatcherCast
<
const
Element
&>
(
e4_
),
};
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
matchers
,
matchers
+
4
));
}
private
:
const
typename
DecayArray
<
T1
>::
type
e1_
;
const
typename
DecayArray
<
T2
>::
type
e2_
;
const
typename
DecayArray
<
T3
>::
type
e3_
;
const
typename
DecayArray
<
T4
>::
type
e4_
;
GTEST_DISALLOW_ASSIGN_
(
ElementsAreMatcher4
);
};
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
>
class
ElementsAreMatcher5
{
public
:
ElementsAreMatcher5
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
)
:
e1_
(
e1
),
e2_
(
e2
),
e3_
(
e3
),
e4_
(
e4
),
e5_
(
e5
)
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
::
value_type
Element
;
const
Matcher
<
const
Element
&>
matchers
[]
=
{
MatcherCast
<
const
Element
&>
(
e1_
),
MatcherCast
<
const
Element
&>
(
e2_
),
MatcherCast
<
const
Element
&>
(
e3_
),
MatcherCast
<
const
Element
&>
(
e4_
),
MatcherCast
<
const
Element
&>
(
e5_
),
};
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
matchers
,
matchers
+
5
));
}
private
:
const
typename
DecayArray
<
T1
>::
type
e1_
;
const
typename
DecayArray
<
T2
>::
type
e2_
;
const
typename
DecayArray
<
T3
>::
type
e3_
;
const
typename
DecayArray
<
T4
>::
type
e4_
;
const
typename
DecayArray
<
T5
>::
type
e5_
;
GTEST_DISALLOW_ASSIGN_
(
ElementsAreMatcher5
);
};
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
>
class
ElementsAreMatcher6
{
public
:
ElementsAreMatcher6
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
)
:
e1_
(
e1
),
e2_
(
e2
),
e3_
(
e3
),
e4_
(
e4
),
e5_
(
e5
),
e6_
(
e6
)
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
::
value_type
Element
;
const
Matcher
<
const
Element
&>
matchers
[]
=
{
MatcherCast
<
const
Element
&>
(
e1_
),
MatcherCast
<
const
Element
&>
(
e2_
),
MatcherCast
<
const
Element
&>
(
e3_
),
MatcherCast
<
const
Element
&>
(
e4_
),
MatcherCast
<
const
Element
&>
(
e5_
),
MatcherCast
<
const
Element
&>
(
e6_
),
};
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
matchers
,
matchers
+
6
));
}
private
:
const
typename
DecayArray
<
T1
>::
type
e1_
;
const
typename
DecayArray
<
T2
>::
type
e2_
;
const
typename
DecayArray
<
T3
>::
type
e3_
;
const
typename
DecayArray
<
T4
>::
type
e4_
;
const
typename
DecayArray
<
T5
>::
type
e5_
;
const
typename
DecayArray
<
T6
>::
type
e6_
;
GTEST_DISALLOW_ASSIGN_
(
ElementsAreMatcher6
);
};
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
,
typename
T7
>
class
ElementsAreMatcher7
{
public
:
ElementsAreMatcher7
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
,
const
T7
&
e7
)
:
e1_
(
e1
),
e2_
(
e2
),
e3_
(
e3
),
e4_
(
e4
),
e5_
(
e5
),
e6_
(
e6
),
e7_
(
e7
)
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
::
value_type
Element
;
const
Matcher
<
const
Element
&>
matchers
[]
=
{
MatcherCast
<
const
Element
&>
(
e1_
),
MatcherCast
<
const
Element
&>
(
e2_
),
MatcherCast
<
const
Element
&>
(
e3_
),
MatcherCast
<
const
Element
&>
(
e4_
),
MatcherCast
<
const
Element
&>
(
e5_
),
MatcherCast
<
const
Element
&>
(
e6_
),
MatcherCast
<
const
Element
&>
(
e7_
),
};
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
matchers
,
matchers
+
7
));
}
private
:
const
typename
DecayArray
<
T1
>::
type
e1_
;
const
typename
DecayArray
<
T2
>::
type
e2_
;
const
typename
DecayArray
<
T3
>::
type
e3_
;
const
typename
DecayArray
<
T4
>::
type
e4_
;
const
typename
DecayArray
<
T5
>::
type
e5_
;
const
typename
DecayArray
<
T6
>::
type
e6_
;
const
typename
DecayArray
<
T7
>::
type
e7_
;
GTEST_DISALLOW_ASSIGN_
(
ElementsAreMatcher7
);
};
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
,
typename
T7
,
typename
T8
>
class
ElementsAreMatcher8
{
public
:
ElementsAreMatcher8
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
,
const
T7
&
e7
,
const
T8
&
e8
)
:
e1_
(
e1
),
e2_
(
e2
),
e3_
(
e3
),
e4_
(
e4
),
e5_
(
e5
),
e6_
(
e6
),
e7_
(
e7
),
e8_
(
e8
)
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
::
value_type
Element
;
const
Matcher
<
const
Element
&>
matchers
[]
=
{
MatcherCast
<
const
Element
&>
(
e1_
),
MatcherCast
<
const
Element
&>
(
e2_
),
MatcherCast
<
const
Element
&>
(
e3_
),
MatcherCast
<
const
Element
&>
(
e4_
),
MatcherCast
<
const
Element
&>
(
e5_
),
MatcherCast
<
const
Element
&>
(
e6_
),
MatcherCast
<
const
Element
&>
(
e7_
),
MatcherCast
<
const
Element
&>
(
e8_
),
};
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
matchers
,
matchers
+
8
));
}
private
:
const
typename
DecayArray
<
T1
>::
type
e1_
;
const
typename
DecayArray
<
T2
>::
type
e2_
;
const
typename
DecayArray
<
T3
>::
type
e3_
;
const
typename
DecayArray
<
T4
>::
type
e4_
;
const
typename
DecayArray
<
T5
>::
type
e5_
;
const
typename
DecayArray
<
T6
>::
type
e6_
;
const
typename
DecayArray
<
T7
>::
type
e7_
;
const
typename
DecayArray
<
T8
>::
type
e8_
;
GTEST_DISALLOW_ASSIGN_
(
ElementsAreMatcher8
);
};
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
,
typename
T7
,
typename
T8
,
typename
T9
>
class
ElementsAreMatcher9
{
public
:
ElementsAreMatcher9
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
,
const
T7
&
e7
,
const
T8
&
e8
,
const
T9
&
e9
)
:
e1_
(
e1
),
e2_
(
e2
),
e3_
(
e3
),
e4_
(
e4
),
e5_
(
e5
),
e6_
(
e6
),
e7_
(
e7
),
e8_
(
e8
),
e9_
(
e9
)
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
::
value_type
Element
;
const
Matcher
<
const
Element
&>
matchers
[]
=
{
MatcherCast
<
const
Element
&>
(
e1_
),
MatcherCast
<
const
Element
&>
(
e2_
),
MatcherCast
<
const
Element
&>
(
e3_
),
MatcherCast
<
const
Element
&>
(
e4_
),
MatcherCast
<
const
Element
&>
(
e5_
),
MatcherCast
<
const
Element
&>
(
e6_
),
MatcherCast
<
const
Element
&>
(
e7_
),
MatcherCast
<
const
Element
&>
(
e8_
),
MatcherCast
<
const
Element
&>
(
e9_
),
};
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
matchers
,
matchers
+
9
));
}
private
:
const
typename
DecayArray
<
T1
>::
type
e1_
;
const
typename
DecayArray
<
T2
>::
type
e2_
;
const
typename
DecayArray
<
T3
>::
type
e3_
;
const
typename
DecayArray
<
T4
>::
type
e4_
;
const
typename
DecayArray
<
T5
>::
type
e5_
;
const
typename
DecayArray
<
T6
>::
type
e6_
;
const
typename
DecayArray
<
T7
>::
type
e7_
;
const
typename
DecayArray
<
T8
>::
type
e8_
;
const
typename
DecayArray
<
T9
>::
type
e9_
;
GTEST_DISALLOW_ASSIGN_
(
ElementsAreMatcher9
);
};
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
,
typename
T7
,
typename
T8
,
typename
T9
,
typename
T10
>
class
ElementsAreMatcher10
{
public
:
ElementsAreMatcher10
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
,
const
T7
&
e7
,
const
T8
&
e8
,
const
T9
&
e9
,
const
T10
&
e10
)
:
e1_
(
e1
),
e2_
(
e2
),
e3_
(
e3
),
e4_
(
e4
),
e5_
(
e5
),
e6_
(
e6
),
e7_
(
e7
),
e8_
(
e8
),
e9_
(
e9
),
e10_
(
e10
)
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
::
value_type
Element
;
const
Matcher
<
const
Element
&>
matchers
[]
=
{
MatcherCast
<
const
Element
&>
(
e1_
),
MatcherCast
<
const
Element
&>
(
e2_
),
MatcherCast
<
const
Element
&>
(
e3_
),
MatcherCast
<
const
Element
&>
(
e4_
),
MatcherCast
<
const
Element
&>
(
e5_
),
MatcherCast
<
const
Element
&>
(
e6_
),
MatcherCast
<
const
Element
&>
(
e7_
),
MatcherCast
<
const
Element
&>
(
e8_
),
MatcherCast
<
const
Element
&>
(
e9_
),
MatcherCast
<
const
Element
&>
(
e10_
),
};
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
matchers
,
matchers
+
10
));
}
private
:
const
typename
DecayArray
<
T1
>::
type
e1_
;
const
typename
DecayArray
<
T2
>::
type
e2_
;
const
typename
DecayArray
<
T3
>::
type
e3_
;
const
typename
DecayArray
<
T4
>::
type
e4_
;
const
typename
DecayArray
<
T5
>::
type
e5_
;
const
typename
DecayArray
<
T6
>::
type
e6_
;
const
typename
DecayArray
<
T7
>::
type
e7_
;
const
typename
DecayArray
<
T8
>::
type
e8_
;
const
typename
DecayArray
<
T9
>::
type
e9_
;
const
typename
DecayArray
<
T10
>::
type
e10_
;
GTEST_DISALLOW_ASSIGN_
(
ElementsAreMatcher10
);
};
// A set of metafunctions for computing the result type of AllOf.
// AllOf(m1, ..., mN) returns
// AllOfResultN<decltype(m1), ..., decltype(mN)>::type.
...
...
@@ -930,144 +562,448 @@ Args(const InnerMatcher& matcher) {
k9
,
k10
>
(
matcher
);
}
// ElementsAre(e
0, e1, ...,
e_n) matches an STL-style container with
//
(n + 1)
elements, where the i-th element in the container must
// ElementsAre(e
_1, e_2, ...
e_n) matches an STL-style container with
//
n
elements, where the i-th element in the container must
// match the i-th argument in the list. Each argument of
// ElementsAre() can be either a value or a matcher. We support up to
// 10 arguments.
//
// The use of DecayArray in the implementation allows ElementsAre()
// to accept string literals, whose type is const char[N], but we
// want to treat them as const char*.
//
// NOTE: Since ElementsAre() cares about the order of the elements, it
// must not be used with containers whose elements's order is
// undefined (e.g. hash_map).
inline
internal
::
ElementsAreMatcher0
ElementsAre
()
{
return
internal
::
ElementsAreMatcher0
();
inline
internal
::
ElementsAreMatcher
<
std
::
tr1
::
tuple
<>
>
ElementsAre
()
{
typedef
std
::
tr1
::
tuple
<>
Args
;
return
internal
::
ElementsAreMatcher
<
Args
>
(
Args
());
}
template
<
typename
T1
>
inline
internal
::
ElementsAreMatcher1
<
T1
>
ElementsAre
(
const
T1
&
e1
)
{
return
internal
::
ElementsAreMatcher1
<
T1
>
(
e1
);
inline
internal
::
ElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
>
>
ElementsAre
(
const
T1
&
e1
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
>
Args
;
return
internal
::
ElementsAreMatcher
<
Args
>
(
Args
(
e1
));
}
template
<
typename
T1
,
typename
T2
>
inline
internal
::
ElementsAreMatcher2
<
T1
,
T2
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
)
{
return
internal
::
ElementsAreMatcher2
<
T1
,
T2
>
(
e1
,
e2
);
inline
internal
::
ElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
>
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
>
Args
;
return
internal
::
ElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
>
inline
internal
::
ElementsAreMatcher3
<
T1
,
T2
,
T3
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
)
{
return
internal
::
ElementsAreMatcher3
<
T1
,
T2
,
T3
>
(
e1
,
e2
,
e3
);
inline
internal
::
ElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
>
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
>
Args
;
return
internal
::
ElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
>
inline
internal
::
ElementsAreMatcher4
<
T1
,
T2
,
T3
,
T4
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
)
{
return
internal
::
ElementsAreMatcher4
<
T1
,
T2
,
T3
,
T4
>
(
e1
,
e2
,
e3
,
e4
);
inline
internal
::
ElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
>
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
>
Args
;
return
internal
::
ElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
>
inline
internal
::
ElementsAreMatcher5
<
T1
,
T2
,
T3
,
T4
,
T5
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
inline
internal
::
ElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
>
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
)
{
return
internal
::
ElementsAreMatcher5
<
T1
,
T2
,
T3
,
T4
,
T5
>
(
e1
,
e2
,
e3
,
e4
,
e5
);
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
>
Args
;
return
internal
::
ElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
,
e5
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
>
inline
internal
::
ElementsAreMatcher6
<
T1
,
T2
,
T3
,
T4
,
T5
,
T6
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
inline
internal
::
ElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
>
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
)
{
return
internal
::
ElementsAreMatcher6
<
T1
,
T2
,
T3
,
T4
,
T5
,
T6
>
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
);
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
>
Args
;
return
internal
::
ElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
,
typename
T7
>
inline
internal
::
ElementsAreMatcher7
<
T1
,
T2
,
T3
,
T4
,
T5
,
T6
,
T7
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
inline
internal
::
ElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
>
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
,
const
T7
&
e7
)
{
return
internal
::
ElementsAreMatcher7
<
T1
,
T2
,
T3
,
T4
,
T5
,
T6
,
T7
>
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
,
e7
);
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
>
Args
;
return
internal
::
ElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
,
e7
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
,
typename
T7
,
typename
T8
>
inline
internal
::
ElementsAreMatcher8
<
T1
,
T2
,
T3
,
T4
,
T5
,
T6
,
T7
,
T8
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
inline
internal
::
ElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
,
typename
internal
::
DecayArray
<
T8
>::
type
>
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
,
const
T7
&
e7
,
const
T8
&
e8
)
{
return
internal
::
ElementsAreMatcher8
<
T1
,
T2
,
T3
,
T4
,
T5
,
T6
,
T7
,
T8
>
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
,
e7
,
e8
);
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
,
typename
internal
::
DecayArray
<
T8
>::
type
>
Args
;
return
internal
::
ElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
,
e7
,
e8
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
,
typename
T7
,
typename
T8
,
typename
T9
>
inline
internal
::
ElementsAreMatcher9
<
T1
,
T2
,
T3
,
T4
,
T5
,
T6
,
T7
,
T8
,
T9
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
inline
internal
::
ElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
,
typename
internal
::
DecayArray
<
T8
>::
type
,
typename
internal
::
DecayArray
<
T9
>::
type
>
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
,
const
T7
&
e7
,
const
T8
&
e8
,
const
T9
&
e9
)
{
return
internal
::
ElementsAreMatcher9
<
T1
,
T2
,
T3
,
T4
,
T5
,
T6
,
T7
,
T8
,
T9
>
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
,
e7
,
e8
,
e9
);
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
,
typename
internal
::
DecayArray
<
T8
>::
type
,
typename
internal
::
DecayArray
<
T9
>::
type
>
Args
;
return
internal
::
ElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
,
e7
,
e8
,
e9
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
,
typename
T7
,
typename
T8
,
typename
T9
,
typename
T10
>
inline
internal
::
ElementsAreMatcher10
<
T1
,
T2
,
T3
,
T4
,
T5
,
T6
,
T7
,
T8
,
T9
,
T10
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
inline
internal
::
ElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
,
typename
internal
::
DecayArray
<
T8
>::
type
,
typename
internal
::
DecayArray
<
T9
>::
type
,
typename
internal
::
DecayArray
<
T10
>::
type
>
>
ElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
,
const
T7
&
e7
,
const
T8
&
e8
,
const
T9
&
e9
,
const
T10
&
e10
)
{
return
internal
::
ElementsAreMatcher10
<
T1
,
T2
,
T3
,
T4
,
T5
,
T6
,
T7
,
T8
,
T9
,
T10
>
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
,
e7
,
e8
,
e9
,
e10
);
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
,
typename
internal
::
DecayArray
<
T8
>::
type
,
typename
internal
::
DecayArray
<
T9
>::
type
,
typename
internal
::
DecayArray
<
T10
>::
type
>
Args
;
return
internal
::
ElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
,
e7
,
e8
,
e9
,
e10
));
}
// ElementsAreArray(array)
// ElementsAreArray(pointer, count)
// ElementsAreArray(vector)
// ElementsAreArray(first, last)
//
// The ElementsAreArray() functions are like ElementsAre(...), except that
// they are given a sequence of matchers or values rather than taking each
// element as a function argument. The sequence can be specified as a
// C-style array, a pointer and count, a vector, or an STL iterator range.
//
// * The array form infers the size of 'array', which must be of a
// statically-sized C-style array type.
//
// * The (pointer, count) form can take either a statically-sized C-style
// array or a pointer to a dynamically created array. It does not take
// ownership of the pointer.
//
// * The vector form can take a std::vector either of values or of matchers.
//
// * The (first, last) form can take any STL iterator range.
//
// All forms of ElementsAreArray() make a copy of the input sequence.
template
<
typename
T
>
inline
internal
::
ElementsAreArrayMatcher
<
T
>
ElementsAreArray
(
const
T
*
first
,
size_t
count
)
{
return
internal
::
ElementsAreArrayMatcher
<
T
>
(
first
,
first
+
count
);
// UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension
// that matches n elements in any order. We support up to n=10 arguments.
inline
internal
::
UnorderedElementsAreMatcher
<
std
::
tr1
::
tuple
<>
>
UnorderedElementsAre
()
{
typedef
std
::
tr1
::
tuple
<>
Args
;
return
internal
::
UnorderedElementsAreMatcher
<
Args
>
(
Args
());
}
template
<
typename
T
,
size_t
N
>
inline
internal
::
ElementsAreArrayMatcher
<
T
>
ElementsAreArray
(
const
T
(
&
array
)[
N
])
{
return
internal
::
ElementsAreArrayMatcher
<
T
>
(
array
,
array
+
N
);
template
<
typename
T1
>
inline
internal
::
UnorderedElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
>
>
UnorderedElementsAre
(
const
T1
&
e1
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
>
Args
;
return
internal
::
UnorderedElementsAreMatcher
<
Args
>
(
Args
(
e1
));
}
template
<
typename
T
,
typename
A
>
inline
internal
::
ElementsAreArrayMatcher
<
T
>
ElementsAreArray
(
const
std
::
vector
<
T
,
A
>&
vec
)
{
return
internal
::
ElementsAreArrayMatcher
<
T
>
(
vec
.
begin
(),
vec
.
end
());
template
<
typename
T1
,
typename
T2
>
inline
internal
::
UnorderedElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
>
>
UnorderedElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
>
Args
;
return
internal
::
UnorderedElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
));
}
template
<
typename
Iter
>
inline
internal
::
ElementsAreArrayMatcher
<
typename
std
::
iterator_traits
<
Iter
>::
value_type
>
ElementsAreArray
(
Iter
first
,
Iter
last
)
{
typedef
typename
std
::
iterator_traits
<
Iter
>::
value_type
T
;
return
internal
::
ElementsAreArrayMatcher
<
T
>
(
first
,
last
);
template
<
typename
T1
,
typename
T2
,
typename
T3
>
inline
internal
::
UnorderedElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
>
>
UnorderedElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
>
Args
;
return
internal
::
UnorderedElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
>
inline
internal
::
UnorderedElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
>
>
UnorderedElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
>
Args
;
return
internal
::
UnorderedElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
>
inline
internal
::
UnorderedElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
>
>
UnorderedElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
>
Args
;
return
internal
::
UnorderedElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
,
e5
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
>
inline
internal
::
UnorderedElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
>
>
UnorderedElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
>
Args
;
return
internal
::
UnorderedElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
,
typename
T7
>
inline
internal
::
UnorderedElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
>
>
UnorderedElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
,
const
T7
&
e7
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
>
Args
;
return
internal
::
UnorderedElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
,
e7
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
,
typename
T7
,
typename
T8
>
inline
internal
::
UnorderedElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
,
typename
internal
::
DecayArray
<
T8
>::
type
>
>
UnorderedElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
,
const
T7
&
e7
,
const
T8
&
e8
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
,
typename
internal
::
DecayArray
<
T8
>::
type
>
Args
;
return
internal
::
UnorderedElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
,
e7
,
e8
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
,
typename
T7
,
typename
T8
,
typename
T9
>
inline
internal
::
UnorderedElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
,
typename
internal
::
DecayArray
<
T8
>::
type
,
typename
internal
::
DecayArray
<
T9
>::
type
>
>
UnorderedElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
,
const
T7
&
e7
,
const
T8
&
e8
,
const
T9
&
e9
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
,
typename
internal
::
DecayArray
<
T8
>::
type
,
typename
internal
::
DecayArray
<
T9
>::
type
>
Args
;
return
internal
::
UnorderedElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
,
e7
,
e8
,
e9
));
}
template
<
typename
T1
,
typename
T2
,
typename
T3
,
typename
T4
,
typename
T5
,
typename
T6
,
typename
T7
,
typename
T8
,
typename
T9
,
typename
T10
>
inline
internal
::
UnorderedElementsAreMatcher
<
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
,
typename
internal
::
DecayArray
<
T8
>::
type
,
typename
internal
::
DecayArray
<
T9
>::
type
,
typename
internal
::
DecayArray
<
T10
>::
type
>
>
UnorderedElementsAre
(
const
T1
&
e1
,
const
T2
&
e2
,
const
T3
&
e3
,
const
T4
&
e4
,
const
T5
&
e5
,
const
T6
&
e6
,
const
T7
&
e7
,
const
T8
&
e8
,
const
T9
&
e9
,
const
T10
&
e10
)
{
typedef
std
::
tr1
::
tuple
<
typename
internal
::
DecayArray
<
T1
>::
type
,
typename
internal
::
DecayArray
<
T2
>::
type
,
typename
internal
::
DecayArray
<
T3
>::
type
,
typename
internal
::
DecayArray
<
T4
>::
type
,
typename
internal
::
DecayArray
<
T5
>::
type
,
typename
internal
::
DecayArray
<
T6
>::
type
,
typename
internal
::
DecayArray
<
T7
>::
type
,
typename
internal
::
DecayArray
<
T8
>::
type
,
typename
internal
::
DecayArray
<
T9
>::
type
,
typename
internal
::
DecayArray
<
T10
>::
type
>
Args
;
return
internal
::
UnorderedElementsAreMatcher
<
Args
>
(
Args
(
e1
,
e2
,
e3
,
e4
,
e5
,
e6
,
e7
,
e8
,
e9
,
e10
));
}
// AllOf(m1, m2, ..., mk) matches any value that matches all of the given
// sub-matchers. AllOf is called fully qualified to prevent ADL from firing.
...
...
include/gmock/gmock-generated-matchers.h.pump
View file @
fb25d539
...
...
@@ -187,66 +187,6 @@ class ArgsMatcher {
GTEST_DISALLOW_ASSIGN_
(
ArgsMatcher
);
};
// Implements ElementsAre() of 1-$n arguments. The use of DecayArray in
// the implementation allows ElementsAre() to accept string literals, whose
// inferred type is const char[N] while we want to treat them as const char*.
$
range
i
1.
.
n
$
for
i
[[
$
range
j
1.
.
i
template
<
$
for
j
,
[[
typename
T
$
j
]]
>
class
ElementsAreMatcher
$
i
{
public
:
$
if
i
==
1
[[
explicit
]]
ElementsAreMatcher
$
i
(
$
for
j
,
[[
const
T
$
j
&
e
$
j
]])
$
if
i
>
0
[[
:
]]
$
for
j
,
[[
e
$
j
[[]]
_
(
e
$
j
)]]
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
::
value_type
Element
;
$
if
i
==
1
[[
// Nokia's Symbian Compiler has a nasty bug where the object put
// in a one-element local array is not destructed when the array
// goes out of scope. This leads to obvious badness as we've
// added the linked_ptr in it to our other linked_ptrs list.
// Hence we implement ElementsAreMatcher1 specially to avoid using
// a local array.
const
Matcher
<
const
Element
&>
matcher
=
MatcherCast
<
const
Element
&>
(
e1_
);
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
&
matcher
,
&
matcher
+
1
));
]]
$
else
[[
const
Matcher
<
const
Element
&>
matchers
[]
=
{
$
for
j
[[
MatcherCast
<
const
Element
&>
(
e
$
j
[[]]
_
),
]]
};
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
matchers
,
matchers
+
$
i
));
]]
}
private
:
$
for
j
[[
const
typename
DecayArray
<
T
$
j
>::
type
e
$
j
[[]]
_
;
]]
GTEST_DISALLOW_ASSIGN_
(
ElementsAreMatcher
$
i
);
};
]]
// A set of metafunctions for computing the result type of AllOf.
// AllOf(m1, ..., mN) returns
// AllOfResultN<decltype(m1), ..., decltype(mN)>::type.
...
...
@@ -324,79 +264,72 @@ Args(const InnerMatcher& matcher) {
]]
// ElementsAre(e
0, e1, ...,
e_n) matches an STL-style container with
//
(n + 1)
elements, where the i-th element in the container must
// ElementsAre(e
_1, e_2, ...
e_n) matches an STL-style container with
//
n
elements, where the i-th element in the container must
// match the i-th argument in the list. Each argument of
// ElementsAre() can be either a value or a matcher. We support up to
// $n arguments.
//
// The use of DecayArray in the implementation allows ElementsAre()
// to accept string literals, whose type is const char[N], but we
// want to treat them as const char*.
//
// NOTE: Since ElementsAre() cares about the order of the elements, it
// must not be used with containers whose elements's order is
// undefined (e.g. hash_map).
inline
internal
::
ElementsAreMatcher0
ElementsAre
()
{
return
internal
::
ElementsAreMatcher0
();
}
$
range
i
1.
.
n
$
range
i
0.
.
n
$
for
i
[[
$
range
j
1.
.
i
$
if
i
>
0
[[
template
<
$
for
j
,
[[
typename
T
$
j
]]
>
inline
internal
::
ElementsAreMatcher
$
i
<
$
for
j
,
[[
T
$
j
]]
>
ElementsAre
(
$
for
j
,
[[
const
T
$
j
&
e
$
j
]])
{
return
internal
::
ElementsAreMatcher
$
i
<
$
for
j
,
[[
T
$
j
]]
>
(
$
for
j
,
[[
e
$
j
]]);
]]
inline
internal
::
ElementsAreMatcher
<
std
::
tr1
::
tuple
<
$
for
j
,
[[
typename
internal
::
DecayArray
<
T
$
j
[[]]
>::
type
]]
>
>
ElementsAre
(
$
for
j
,
[[
const
T
$
j
&
e
$
j
]])
{
typedef
std
::
tr1
::
tuple
<
$
for
j
,
[[
typename
internal
::
DecayArray
<
T
$
j
[[]]
>::
type
]]
>
Args
;
return
internal
::
ElementsAreMatcher
<
Args
>
(
Args
(
$
for
j
,
[[
e
$
j
]]));
}
]]
// ElementsAreArray(array)
// ElementsAreArray(pointer, count)
// ElementsAreArray(vector)
// ElementsAreArray(first, last)
//
// The ElementsAreArray() functions are like ElementsAre(...), except that
// they are given a sequence of matchers or values rather than taking each
// element as a function argument. The sequence can be specified as a
// C-style array, a pointer and count, a vector, or an STL iterator range.
//
// * The array form infers the size of 'array', which must be of a
// statically-sized C-style array type.
//
// * The (pointer, count) form can take either a statically-sized C-style
// array or a pointer to a dynamically created array. It does not take
// ownership of the pointer.
//
// * The vector form can take a std::vector either of values or of matchers.
//
// * The (first, last) form can take any STL iterator range.
//
// All forms of ElementsAreArray() make a copy of the input sequence.
template
<
typename
T
>
inline
internal
::
ElementsAreArrayMatcher
<
T
>
ElementsAreArray
(
const
T
*
first
,
size_t
count
)
{
return
internal
::
ElementsAreArrayMatcher
<
T
>
(
first
,
first
+
count
);
}
// UnorderedElementsAre(e_1, e_2, ..., e_n) is an ElementsAre extension
// that matches n elements in any order. We support up to n=$n arguments.
template
<
typename
T
,
size_t
N
>
inline
internal
::
ElementsAreArrayMatcher
<
T
>
ElementsAreArray
(
const
T
(
&
array
)[
N
])
{
return
internal
::
ElementsAreArrayMatcher
<
T
>
(
array
,
array
+
N
);
}
$
range
i
0.
.
n
$
for
i
[[
template
<
typename
T
,
typename
A
>
inline
internal
::
ElementsAreArrayMatcher
<
T
>
ElementsAreArray
(
const
std
::
vector
<
T
,
A
>&
vec
)
{
return
internal
::
ElementsAreArrayMatcher
<
T
>
(
vec
.
begin
(),
vec
.
end
());
}
$
range
j
1.
.
i
$
if
i
>
0
[[
template
<
typename
Iter
>
inline
internal
::
ElementsAreArrayMatcher
<
typename
std
::
iterator_traits
<
Iter
>::
value_type
>
ElementsAreArray
(
Iter
first
,
Iter
last
)
{
typedef
typename
std
::
iterator_traits
<
Iter
>::
value_type
T
;
return
internal
::
ElementsAreArrayMatcher
<
T
>
(
first
,
last
);
template
<
$
for
j
,
[[
typename
T
$
j
]]
>
]]
inline
internal
::
UnorderedElementsAreMatcher
<
std
::
tr1
::
tuple
<
$
for
j
,
[[
typename
internal
::
DecayArray
<
T
$
j
[[]]
>::
type
]]
>
>
UnorderedElementsAre
(
$
for
j
,
[[
const
T
$
j
&
e
$
j
]])
{
typedef
std
::
tr1
::
tuple
<
$
for
j
,
[[
typename
internal
::
DecayArray
<
T
$
j
[[]]
>::
type
]]
>
Args
;
return
internal
::
UnorderedElementsAreMatcher
<
Args
>
(
Args
(
$
for
j
,
[[
e
$
j
]]));
}
]]
// AllOf(m1, m2, ..., mk) matches any value that matches all of the given
// sub-matchers. AllOf is called fully qualified to prevent ADL from firing.
...
...
include/gmock/gmock-matchers.h
View file @
fb25d539
...
...
@@ -40,6 +40,7 @@
#include <math.h>
#include <algorithm>
#include <iterator>
#include <limits>
#include <ostream> // NOLINT
#include <sstream>
...
...
@@ -106,12 +107,36 @@ class MatchResultListener {
inline
MatchResultListener
::~
MatchResultListener
()
{
}
// An instance of a subclass of this knows how to describe itself as a
// matcher.
class
MatcherDescriberInterface
{
public
:
virtual
~
MatcherDescriberInterface
()
{}
// Describes this matcher to an ostream. The function should print
// a verb phrase that describes the property a value matching this
// matcher should have. The subject of the verb phrase is the value
// being matched. For example, the DescribeTo() method of the Gt(7)
// matcher prints "is greater than 7".
virtual
void
DescribeTo
(
::
std
::
ostream
*
os
)
const
=
0
;
// Describes the negation of this matcher to an ostream. For
// example, if the description of this matcher is "is greater than
// 7", the negated description could be "is not greater than 7".
// You are not required to override this when implementing
// MatcherInterface, but it is highly advised so that your matcher
// can produce good error messages.
virtual
void
DescribeNegationTo
(
::
std
::
ostream
*
os
)
const
{
*
os
<<
"not ("
;
DescribeTo
(
os
);
*
os
<<
")"
;
}
};
// The implementation of a matcher.
template
<
typename
T
>
class
MatcherInterface
{
class
MatcherInterface
:
public
MatcherDescriberInterface
{
public
:
virtual
~
MatcherInterface
()
{}
// Returns true iff the matcher matches x; also explains the match
// result to 'listener' if necessary (see the next paragraph), in
// the form of a non-restrictive relative clause ("which ...",
...
...
@@ -145,24 +170,9 @@ class MatcherInterface {
// listener->stream() may be NULL.
virtual
bool
MatchAndExplain
(
T
x
,
MatchResultListener
*
listener
)
const
=
0
;
// Describes this matcher to an ostream. The function should print
// a verb phrase that describes the property a value matching this
// matcher should have. The subject of the verb phrase is the value
// being matched. For example, the DescribeTo() method of the Gt(7)
// matcher prints "is greater than 7".
virtual
void
DescribeTo
(
::
std
::
ostream
*
os
)
const
=
0
;
// Describes the negation of this matcher to an ostream. For
// example, if the description of this matcher is "is greater than
// 7", the negated description could be "is not greater than 7".
// You are not required to override this when implementing
// MatcherInterface, but it is highly advised so that your matcher
// can produce good error messages.
virtual
void
DescribeNegationTo
(
::
std
::
ostream
*
os
)
const
{
*
os
<<
"not ("
;
DescribeTo
(
os
);
*
os
<<
")"
;
}
// Inherits these methods from MatcherDescriberInterface:
// virtual void DescribeTo(::std::ostream* os) const = 0;
// virtual void DescribeNegationTo(::std::ostream* os) const;
};
namespace
internal
{
...
...
@@ -234,6 +244,13 @@ class MatcherBase {
MatchAndExplain
(
x
,
&
listener
);
}
// Returns the describer for this matcher object; retains ownership
// of the describer, which is only guaranteed to be alive when
// this matcher object is alive.
const
MatcherDescriberInterface
*
GetDescriber
()
const
{
return
impl_
.
get
();
}
protected
:
MatcherBase
()
{}
...
...
@@ -626,7 +643,7 @@ namespace internal {
// If the explanation is not empty, prints it to the ostream.
inline
void
PrintIfNotEmpty
(
const
internal
::
string
&
explanation
,
std
::
ostream
*
os
)
{
::
std
::
ostream
*
os
)
{
if
(
explanation
!=
""
&&
os
!=
NULL
)
{
*
os
<<
", "
<<
explanation
;
}
...
...
@@ -770,6 +787,46 @@ void ExplainMatchFailureTupleTo(const MatcherTuple& matchers,
matchers
,
values
,
os
);
}
// TransformTupleValues and its helper.
//
// TransformTupleValuesHelper hides the internal machinery that
// TransformTupleValues uses to implement a tuple traversal.
template
<
typename
Tuple
,
typename
Func
,
typename
OutIter
>
class
TransformTupleValuesHelper
{
private
:
typedef
typename
::
std
::
tr1
::
tuple_size
<
Tuple
>
TupleSize
;
public
:
// For each member of tuple 't', taken in order, evaluates '*out++ = f(t)'.
// Returns the final value of 'out' in case the caller needs it.
static
OutIter
Run
(
Func
f
,
const
Tuple
&
t
,
OutIter
out
)
{
return
IterateOverTuple
<
Tuple
,
TupleSize
::
value
>
()(
f
,
t
,
out
);
}
private
:
template
<
typename
Tup
,
size_t
kRemainingSize
>
struct
IterateOverTuple
{
OutIter
operator
()
(
Func
f
,
const
Tup
&
t
,
OutIter
out
)
const
{
*
out
++
=
f
(
::
std
::
tr1
::
get
<
TupleSize
::
value
-
kRemainingSize
>
(
t
));
return
IterateOverTuple
<
Tup
,
kRemainingSize
-
1
>
()(
f
,
t
,
out
);
}
};
template
<
typename
Tup
>
struct
IterateOverTuple
<
Tup
,
0
>
{
OutIter
operator
()
(
Func
/* f */
,
const
Tup
&
/* t */
,
OutIter
out
)
const
{
return
out
;
}
};
};
// Successively invokes 'f(element)' on each element of the tuple 't',
// appending each result to the 'out' iterator. Returns the final value
// of 'out'.
template
<
typename
Tuple
,
typename
Func
,
typename
OutIter
>
OutIter
TransformTupleValues
(
Func
f
,
const
Tuple
&
t
,
OutIter
out
)
{
return
TransformTupleValuesHelper
<
Tuple
,
Func
,
OutIter
>::
Run
(
f
,
t
,
out
);
}
// Implements A<T>().
template
<
typename
T
>
class
AnyMatcherImpl
:
public
MatcherInterface
<
T
>
{
...
...
@@ -2343,9 +2400,10 @@ class WhenSortedByMatcher {
virtual
bool
MatchAndExplain
(
LhsContainer
lhs
,
MatchResultListener
*
listener
)
const
{
LhsStlContainerReference
lhs_stl_container
=
LhsView
::
ConstReference
(
lhs
);
std
::
vector
<
LhsValue
>
sorted_container
(
lhs_stl_container
.
begin
(),
lhs_stl_container
.
end
());
std
::
sort
(
sorted_container
.
begin
(),
sorted_container
.
end
(),
comparator_
);
::
std
::
vector
<
LhsValue
>
sorted_container
(
lhs_stl_container
.
begin
(),
lhs_stl_container
.
end
());
::
std
::
sort
(
sorted_container
.
begin
(),
sorted_container
.
end
(),
comparator_
);
if
(
!
listener
->
IsInterested
())
{
// If the listener is not interested, we do not need to
...
...
@@ -2366,7 +2424,7 @@ class WhenSortedByMatcher {
private
:
const
Comparator
comparator_
;
const
Matcher
<
const
std
::
vector
<
LhsValue
>&>
matcher_
;
const
Matcher
<
const
::
std
::
vector
<
LhsValue
>&>
matcher_
;
GTEST_DISALLOW_COPY_AND_ASSIGN_
(
Impl
);
};
...
...
@@ -2416,7 +2474,7 @@ class PointwiseMatcher {
// reference, as they may be expensive to copy. We must use tuple
// instead of pair here, as a pair cannot hold references (C++ 98,
// 20.2.2 [lib.pairs]).
typedef
std
::
tr1
::
tuple
<
const
LhsValue
&
,
const
RhsValue
&>
InnerMatcherArg
;
typedef
::
std
::
tr1
::
tuple
<
const
LhsValue
&
,
const
RhsValue
&>
InnerMatcherArg
;
Impl
(
const
TupleMatcher
&
tuple_matcher
,
const
RhsStlContainer
&
rhs
)
// mono_tuple_matcher_ holds a monomorphic version of the tuple matcher.
...
...
@@ -2860,7 +2918,7 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
// there's no need to explain anything as Google Mock already
// prints the empty container. Otherwise we just need to show
// how many elements there actually are.
if
(
actual_count
!=
0
)
{
if
(
actual_count
!=
0
&&
listener
->
IsInterested
()
)
{
*
listener
<<
"which has "
<<
Elements
(
actual_count
);
}
return
false
;
...
...
@@ -2868,7 +2926,7 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
typename
StlContainer
::
const_iterator
it
=
stl_container
.
begin
();
// explanations[i] is the explanation of the element at index i.
std
::
vector
<
internal
::
string
>
explanations
(
count
());
::
std
::
vector
<
internal
::
string
>
explanations
(
count
());
for
(
size_t
i
=
0
;
i
!=
count
();
++
it
,
++
i
)
{
StringMatchResultListener
s
;
if
(
matchers_
[
i
].
MatchAndExplain
(
*
it
,
&
s
))
{
...
...
@@ -2905,26 +2963,280 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
}
size_t
count
()
const
{
return
matchers_
.
size
();
}
std
::
vector
<
Matcher
<
const
Element
&>
>
matchers_
;
::
std
::
vector
<
Matcher
<
const
Element
&>
>
matchers_
;
GTEST_DISALLOW_ASSIGN_
(
ElementsAreMatcherImpl
);
};
// Implements ElementsAre() of 0 arguments.
class
ElementsAreMatcher0
{
// Connectivity matrix of (elements X matchers), in element-major order.
// Initially, there are no edges.
// Use NextGraph() to iterate over all possible edge configurations.
// Use Randomize() to generate a random edge configuration.
class
GTEST_API_
MatchMatrix
{
public
:
MatchMatrix
(
size_t
num_elements
,
size_t
num_matchers
)
:
num_elements_
(
num_elements
),
num_matchers_
(
num_matchers
),
matched_
(
num_elements_
*
num_matchers_
,
0
)
{
}
size_t
LhsSize
()
const
{
return
num_elements_
;
}
size_t
RhsSize
()
const
{
return
num_matchers_
;
}
bool
HasEdge
(
size_t
ilhs
,
size_t
irhs
)
const
{
return
matched_
[
SpaceIndex
(
ilhs
,
irhs
)]
==
1
;
}
void
SetEdge
(
size_t
ilhs
,
size_t
irhs
,
bool
b
)
{
matched_
[
SpaceIndex
(
ilhs
,
irhs
)]
=
b
?
1
:
0
;
}
// Treating the connectivity matrix as a (LhsSize()*RhsSize())-bit number,
// adds 1 to that number; returns false if incrementing the graph left it
// empty.
bool
NextGraph
();
void
Randomize
();
string
DebugString
()
const
;
private
:
size_t
SpaceIndex
(
size_t
ilhs
,
size_t
irhs
)
const
{
return
ilhs
*
num_matchers_
+
irhs
;
}
size_t
num_elements_
;
size_t
num_matchers_
;
// Each element is a char interpreted as bool. They are stored as a
// flattened array in lhs-major order, use 'SpaceIndex()' to translate
// a (ilhs, irhs) matrix coordinate into an offset.
::
std
::
vector
<
char
>
matched_
;
};
typedef
::
std
::
pair
<
size_t
,
size_t
>
ElementMatcherPair
;
typedef
::
std
::
vector
<
ElementMatcherPair
>
ElementMatcherPairs
;
// Returns a maximum bipartite matching for the specified graph 'g'.
// The matching is represented as a vector of {element, matcher} pairs.
GTEST_API_
ElementMatcherPairs
FindMaxBipartiteMatching
(
const
MatchMatrix
&
g
);
GTEST_API_
bool
FindPairing
(
const
MatchMatrix
&
matrix
,
MatchResultListener
*
listener
);
// Untyped base class for implementing UnorderedElementsAre. By
// putting logic that's not specific to the element type here, we
// reduce binary bloat and increase compilation speed.
class
GTEST_API_
UnorderedElementsAreMatcherImplBase
{
protected
:
// A vector of matcher describers, one for each element matcher.
// Does not own the describers (and thus can be used only when the
// element matchers are alive).
typedef
::
std
::
vector
<
const
MatcherDescriberInterface
*>
MatcherDescriberVec
;
// Describes this UnorderedElementsAre matcher.
void
DescribeToImpl
(
::
std
::
ostream
*
os
)
const
;
// Describes the negation of this UnorderedElementsAre matcher.
void
DescribeNegationToImpl
(
::
std
::
ostream
*
os
)
const
;
bool
VerifyAllElementsAndMatchersAreMatched
(
const
::
std
::
vector
<
string
>&
element_printouts
,
const
MatchMatrix
&
matrix
,
MatchResultListener
*
listener
)
const
;
MatcherDescriberVec
&
matcher_describers
()
{
return
matcher_describers_
;
}
static
Message
Elements
(
size_t
n
)
{
return
Message
()
<<
n
<<
" element"
<<
(
n
==
1
?
""
:
"s"
);
}
private
:
MatcherDescriberVec
matcher_describers_
;
GTEST_DISALLOW_ASSIGN_
(
UnorderedElementsAreMatcherImplBase
);
};
// Implements unordered ElementsAre and unordered ElementsAreArray.
template
<
typename
Container
>
class
UnorderedElementsAreMatcherImpl
:
public
MatcherInterface
<
Container
>
,
public
UnorderedElementsAreMatcherImplBase
{
public
:
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
internal
::
StlContainerView
<
RawContainer
>
View
;
typedef
typename
View
::
type
StlContainer
;
typedef
typename
View
::
const_reference
StlContainerReference
;
typedef
typename
StlContainer
::
const_iterator
StlContainerConstIterator
;
typedef
typename
StlContainer
::
value_type
Element
;
// Constructs the matcher from a sequence of element values or
// element matchers.
template
<
typename
InputIter
>
UnorderedElementsAreMatcherImpl
(
InputIter
first
,
InputIter
last
)
{
for
(;
first
!=
last
;
++
first
)
{
matchers_
.
push_back
(
MatcherCast
<
const
Element
&>
(
*
first
));
matcher_describers
().
push_back
(
matchers_
.
back
().
GetDescriber
());
}
}
// Describes what this matcher does.
virtual
void
DescribeTo
(
::
std
::
ostream
*
os
)
const
{
return
UnorderedElementsAreMatcherImplBase
::
DescribeToImpl
(
os
);
}
// Describes what the negation of this matcher does.
virtual
void
DescribeNegationTo
(
::
std
::
ostream
*
os
)
const
{
return
UnorderedElementsAreMatcherImplBase
::
DescribeNegationToImpl
(
os
);
}
virtual
bool
MatchAndExplain
(
Container
container
,
MatchResultListener
*
listener
)
const
{
StlContainerReference
stl_container
=
View
::
ConstReference
(
container
);
size_t
actual_count
=
stl_container
.
size
();
if
(
actual_count
==
0
&&
matchers_
.
empty
())
{
return
true
;
}
if
(
actual_count
!=
matchers_
.
size
())
{
// The element count doesn't match. If the container is empty,
// there's no need to explain anything as Google Mock already
// prints the empty container. Otherwise we just need to show
// how many elements there actually are.
if
(
actual_count
!=
0
&&
listener
->
IsInterested
())
{
*
listener
<<
"which has "
<<
Elements
(
actual_count
);
}
return
false
;
}
::
std
::
vector
<
string
>
element_printouts
;
MatchMatrix
matrix
=
AnalyzeElements
(
stl_container
.
begin
(),
stl_container
.
end
(),
&
element_printouts
,
listener
);
return
VerifyAllElementsAndMatchersAreMatched
(
element_printouts
,
matrix
,
listener
)
&&
FindPairing
(
matrix
,
listener
);
}
private
:
typedef
::
std
::
vector
<
Matcher
<
const
Element
&>
>
MatcherVec
;
template
<
typename
ElementIter
>
MatchMatrix
AnalyzeElements
(
ElementIter
elem_first
,
ElementIter
elem_last
,
::
std
::
vector
<
string
>*
element_printouts
,
MatchResultListener
*
listener
)
const
{
::
std
::
vector
<
char
>
did_match
;
size_t
num_elements
=
0
;
for
(;
elem_first
!=
elem_last
;
++
num_elements
,
++
elem_first
)
{
if
(
listener
->
IsInterested
())
{
element_printouts
->
push_back
(
PrintToString
(
*
elem_first
));
}
for
(
size_t
irhs
=
0
;
irhs
!=
matchers_
.
size
();
++
irhs
)
{
did_match
.
push_back
(
Matches
(
matchers_
[
irhs
])(
*
elem_first
));
}
}
MatchMatrix
matrix
(
num_elements
,
matchers_
.
size
());
::
std
::
vector
<
char
>::
const_iterator
did_match_iter
=
did_match
.
begin
();
for
(
size_t
ilhs
=
0
;
ilhs
!=
num_elements
;
++
ilhs
)
{
for
(
size_t
irhs
=
0
;
irhs
!=
matchers_
.
size
();
++
irhs
)
{
matrix
.
SetEdge
(
ilhs
,
irhs
,
*
did_match_iter
++
!=
0
);
}
}
return
matrix
;
}
MatcherVec
matchers_
;
GTEST_DISALLOW_ASSIGN_
(
UnorderedElementsAreMatcherImpl
);
};
// Functor for use in TransformTuple.
// Performs MatcherCast<Target> on an input argument of any type.
template
<
typename
Target
>
struct
CastAndAppendTransform
{
template
<
typename
Arg
>
Matcher
<
Target
>
operator
()(
const
Arg
&
a
)
const
{
return
MatcherCast
<
Target
>
(
a
);
}
};
// Implements UnorderedElementsAre.
template
<
typename
MatcherTuple
>
class
UnorderedElementsAreMatcher
{
public
:
ElementsAreMatcher0
()
{}
explicit
UnorderedElementsAreMatcher
(
const
MatcherTuple
&
args
)
:
matchers_
(
args
)
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
::
value_type
Element
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
View
;
typedef
typename
View
::
value_type
Element
;
typedef
::
std
::
vector
<
Matcher
<
const
Element
&>
>
MatcherVec
;
MatcherVec
matchers
;
matchers
.
reserve
(
::
std
::
tr1
::
tuple_size
<
MatcherTuple
>::
value
);
TransformTupleValues
(
CastAndAppendTransform
<
const
Element
&>
(),
matchers_
,
::
std
::
back_inserter
(
matchers
));
return
MakeMatcher
(
new
UnorderedElementsAreMatcherImpl
<
Container
>
(
matchers
.
begin
(),
matchers
.
end
()));
}
private
:
const
MatcherTuple
matchers_
;
GTEST_DISALLOW_ASSIGN_
(
UnorderedElementsAreMatcher
);
};
const
Matcher
<
const
Element
&>*
const
matchers
=
NULL
;
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
matchers
,
matchers
));
// Implements ElementsAre.
template
<
typename
MatcherTuple
>
class
ElementsAreMatcher
{
public
:
explicit
ElementsAreMatcher
(
const
MatcherTuple
&
args
)
:
matchers_
(
args
)
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
typedef
GTEST_REMOVE_REFERENCE_AND_CONST_
(
Container
)
RawContainer
;
typedef
typename
internal
::
StlContainerView
<
RawContainer
>::
type
View
;
typedef
typename
View
::
value_type
Element
;
typedef
::
std
::
vector
<
Matcher
<
const
Element
&>
>
MatcherVec
;
MatcherVec
matchers
;
matchers
.
reserve
(
::
std
::
tr1
::
tuple_size
<
MatcherTuple
>::
value
);
TransformTupleValues
(
CastAndAppendTransform
<
const
Element
&>
(),
matchers_
,
::
std
::
back_inserter
(
matchers
));
return
MakeMatcher
(
new
ElementsAreMatcherImpl
<
Container
>
(
matchers
.
begin
(),
matchers
.
end
()));
}
private
:
const
MatcherTuple
matchers_
;
GTEST_DISALLOW_ASSIGN_
(
ElementsAreMatcher
);
};
// Implements UnorderedElementsAreArray().
template
<
typename
T
>
class
UnorderedElementsAreArrayMatcher
{
public
:
UnorderedElementsAreArrayMatcher
()
{}
template
<
typename
Iter
>
UnorderedElementsAreArrayMatcher
(
Iter
first
,
Iter
last
)
:
matchers_
(
first
,
last
)
{}
template
<
typename
Container
>
operator
Matcher
<
Container
>
()
const
{
return
MakeMatcher
(
new
UnorderedElementsAreMatcherImpl
<
Container
>
(
matchers_
.
begin
(),
matchers_
.
end
()));
}
private
:
::
std
::
vector
<
T
>
matchers_
;
GTEST_DISALLOW_ASSIGN_
(
UnorderedElementsAreArrayMatcher
);
};
// Implements ElementsAreArray().
...
...
@@ -2941,7 +3253,7 @@ class ElementsAreArrayMatcher {
}
private
:
const
std
::
vector
<
T
>
matchers_
;
const
::
std
::
vector
<
T
>
matchers_
;
GTEST_DISALLOW_ASSIGN_
(
ElementsAreArrayMatcher
);
};
...
...
@@ -2957,6 +3269,88 @@ GTEST_API_ string FormatMatcherDescription(bool negation,
}
// namespace internal
// ElementsAreArray(first, last)
// ElementsAreArray(pointer, count)
// ElementsAreArray(array)
// ElementsAreArray(vector)
//
// The ElementsAreArray() functions are like ElementsAre(...), except that
// they are given a homogeneous sequence rather than taking each element as
// a function argument. The sequence can be specified as an array, a
// pointer and count, a vector, or an STL iterator range. In each of these
// cases, the underlying sequence can be either a sequence of values or a
// sequence of matchers.
//
// * ElementsAreArray(array) deduces the size of the array.
//
// * ElementsAreArray(pointer, count) form takes a pointer and count.
//
// * ElementsAreArray(vector) takes a std::vector.
//
// * ElementsAreArray(first, last) takes any iterator range.
//
// All forms of ElementsAreArray() make a copy of the input matcher sequence.
template
<
typename
Iter
>
inline
internal
::
ElementsAreArrayMatcher
<
typename
::
std
::
iterator_traits
<
Iter
>::
value_type
>
ElementsAreArray
(
Iter
first
,
Iter
last
)
{
typedef
typename
::
std
::
iterator_traits
<
Iter
>::
value_type
T
;
return
internal
::
ElementsAreArrayMatcher
<
T
>
(
first
,
last
);
}
template
<
typename
T
>
inline
internal
::
ElementsAreArrayMatcher
<
T
>
ElementsAreArray
(
const
T
*
pointer
,
size_t
count
)
{
return
ElementsAreArray
(
pointer
,
pointer
+
count
);
}
template
<
typename
T
,
size_t
N
>
inline
internal
::
ElementsAreArrayMatcher
<
T
>
ElementsAreArray
(
const
T
(
&
array
)[
N
])
{
return
ElementsAreArray
(
array
,
N
);
}
template
<
typename
T
,
typename
A
>
inline
internal
::
ElementsAreArrayMatcher
<
T
>
ElementsAreArray
(
const
::
std
::
vector
<
T
,
A
>&
vec
)
{
return
ElementsAreArray
(
vec
.
begin
(),
vec
.
end
());
}
// UnorderedElementsAreArray(first, last)
// UnorderedElementsAreArray(pointer, count)
// UnorderedElementsAreArray(array)
// UnorderedElementsAreArray(vector)
//
// The UnorderedElementsAreArray() functions are like
// ElementsAreArray(...), but allow matching the elements in any order.
template
<
typename
Iter
>
inline
internal
::
UnorderedElementsAreArrayMatcher
<
typename
::
std
::
iterator_traits
<
Iter
>::
value_type
>
UnorderedElementsAreArray
(
Iter
first
,
Iter
last
)
{
typedef
typename
::
std
::
iterator_traits
<
Iter
>::
value_type
T
;
return
internal
::
UnorderedElementsAreArrayMatcher
<
T
>
(
first
,
last
);
}
template
<
typename
T
>
inline
internal
::
UnorderedElementsAreArrayMatcher
<
T
>
UnorderedElementsAreArray
(
const
T
*
pointer
,
size_t
count
)
{
return
UnorderedElementsAreArray
(
pointer
,
pointer
+
count
);
}
template
<
typename
T
,
size_t
N
>
inline
internal
::
UnorderedElementsAreArrayMatcher
<
T
>
UnorderedElementsAreArray
(
const
T
(
&
array
)[
N
])
{
return
UnorderedElementsAreArray
(
array
,
N
);
}
template
<
typename
T
,
typename
A
>
inline
internal
::
UnorderedElementsAreArrayMatcher
<
T
>
UnorderedElementsAreArray
(
const
::
std
::
vector
<
T
,
A
>&
vec
)
{
return
UnorderedElementsAreArray
(
vec
.
begin
(),
vec
.
end
());
}
// _ is a matcher that matches anything of any type.
//
// This definition is fine as:
...
...
src/gmock-matchers.cc
View file @
fb25d539
...
...
@@ -133,5 +133,366 @@ GTEST_API_ string FormatMatcherDescription(bool negation,
return
negation
?
"not ("
+
result
+
")"
:
result
;
}
// FindMaxBipartiteMatching and its helper class.
//
// Uses the well-known Ford-Fulkerson max flow method to find a maximum
// bipartite matching. Flow is considered to be from left to right.
// There is an implicit source node that is connected to all of the left
// nodes, and an implicit sink node that is connected to all of the
// right nodes. All edges have unit capacity.
//
// Neither the flow graph nor the residual flow graph are represented
// explicitly. Instead, they are implied by the information in 'graph' and
// a vector<int> called 'left_' whose elements are initialized to the
// value kUnused. This represents the initial state of the algorithm,
// where the flow graph is empty, and the residual flow graph has the
// following edges:
// - An edge from source to each left_ node
// - An edge from each right_ node to sink
// - An edge from each left_ node to each right_ node, if the
// corresponding edge exists in 'graph'.
//
// When the TryAugment() method adds a flow, it sets left_[l] = r for some
// nodes l and r. This induces the following changes:
// - The edges (source, l), (l, r), and (r, sink) are added to the
// flow graph.
// - The same three edges are removed from the residual flow graph.
// - The reverse edges (l, source), (r, l), and (sink, r) are added
// to the residual flow graph, which is a directional graph
// representing unused flow capacity.
//
// When the method augments a flow (moving left_[l] from some r1 to some
// other r2), this can be thought of as "undoing" the above steps with
// respect to r1 and "redoing" them with respect to r2.
//
// It bears repeating that the flow graph and residual flow graph are
// never represented explicitly, but can be derived by looking at the
// information in 'graph' and in left_.
//
// As an optimization, there is a second vector<int> called right_ which
// does not provide any new information. Instead, it enables more
// efficient queries about edges entering or leaving the right-side nodes
// of the flow or residual flow graphs. The following invariants are
// maintained:
//
// left[l] == kUnused or right[left[l]] == l
// right[r] == kUnused or left[right[r]] == r
//
// . [ source ] .
// . ||| .
// . ||| .
// . ||\--> left[0]=1 ---\ right[0]=-1 ----\ .
// . || | | .
// . |\---> left[1]=-1 \--> right[1]=0 ---\| .
// . | || .
// . \----> left[2]=2 ------> right[2]=2 --\|| .
// . ||| .
// . elements matchers vvv .
// . [ sink ] .
//
// See Also:
// [1] Cormen, et al (2001). "Section 26.2: The Ford–Fulkerson method".
// "Introduction to Algorithms (Second ed.)", pp. 651–664.
// [2] "Ford–Fulkerson algorithm", Wikipedia,
// 'http://en.wikipedia.org/wiki/Ford%E2%80%93Fulkerson_algorithm'
class
MaxBipartiteMatchState
{
public
:
explicit
MaxBipartiteMatchState
(
const
MatchMatrix
&
graph
)
:
graph_
(
&
graph
),
left_
(
graph_
->
LhsSize
(),
kUnused
),
right_
(
graph_
->
RhsSize
(),
kUnused
)
{
}
// Returns the edges of a maximal match, each in the form {left, right}.
ElementMatcherPairs
Compute
()
{
// 'seen' is used for path finding { 0: unseen, 1: seen }.
::
std
::
vector
<
char
>
seen
;
// Searches the residual flow graph for a path from each left node to
// the sink in the residual flow graph, and if one is found, add flow
// to the graph. It's okay to search through the left nodes once. The
// edge from the implicit source node to each previously-visited left
// node will have flow if that left node has any path to the sink
// whatsoever. Subsequent augmentations can only add flow to the
// network, and cannot take away that previous flow unit from the source.
// Since the source-to-left edge can only carry one flow unit (or,
// each element can be matched to only one matcher), there is no need
// to visit the left nodes more than once looking for augmented paths.
// The flow is known to be possible or impossible by looking at the
// node once.
for
(
size_t
ilhs
=
0
;
ilhs
<
graph_
->
LhsSize
();
++
ilhs
)
{
// Reset the path-marking vector and try to find a path from
// source to sink starting at the left_[ilhs] node.
GTEST_CHECK_
(
left_
[
ilhs
]
==
kUnused
)
<<
"ilhs: "
<<
ilhs
<<
", left_[ilhs]: "
<<
left_
[
ilhs
];
// 'seen' initialized to 'graph_->RhsSize()' copies of 0.
seen
.
assign
(
graph_
->
RhsSize
(),
0
);
TryAugment
(
ilhs
,
&
seen
);
}
ElementMatcherPairs
result
;
for
(
size_t
ilhs
=
0
;
ilhs
<
left_
.
size
();
++
ilhs
)
{
size_t
irhs
=
left_
[
ilhs
];
if
(
irhs
==
kUnused
)
continue
;
result
.
push_back
(
ElementMatcherPair
(
ilhs
,
irhs
));
}
return
result
;
}
private
:
static
const
size_t
kUnused
=
static_cast
<
size_t
>
(
-
1
);
// Perform a depth-first search from left node ilhs to the sink. If a
// path is found, flow is added to the network by linking the left and
// right vector elements corresponding each segment of the path.
// Returns true if a path to sink was found, which means that a unit of
// flow was added to the network. The 'seen' vector elements correspond
// to right nodes and are marked to eliminate cycles from the search.
//
// Left nodes will only be explored at most once because they
// are accessible from at most one right node in the residual flow
// graph.
//
// Note that left_[ilhs] is the only element of left_ that TryAugment will
// potentially transition from kUnused to another value. Any other
// left_ element holding kUnused before TryAugment will be holding it
// when TryAugment returns.
//
bool
TryAugment
(
size_t
ilhs
,
::
std
::
vector
<
char
>*
seen
)
{
for
(
size_t
irhs
=
0
;
irhs
<
graph_
->
RhsSize
();
++
irhs
)
{
if
((
*
seen
)[
irhs
])
continue
;
if
(
!
graph_
->
HasEdge
(
ilhs
,
irhs
))
continue
;
// There's an available edge from ilhs to irhs.
(
*
seen
)[
irhs
]
=
1
;
// Next a search is performed to determine whether
// this edge is a dead end or leads to the sink.
//
// right_[irhs] == kUnused means that there is residual flow from
// right node irhs to the sink, so we can use that to finish this
// flow path and return success.
//
// Otherwise there is residual flow to some ilhs. We push flow
// along that path and call ourselves recursively to see if this
// ultimately leads to sink.
if
(
right_
[
irhs
]
==
kUnused
||
TryAugment
(
right_
[
irhs
],
seen
))
{
// Add flow from left_[ilhs] to right_[irhs].
left_
[
ilhs
]
=
irhs
;
right_
[
irhs
]
=
ilhs
;
return
true
;
}
}
return
false
;
}
const
MatchMatrix
*
graph_
;
// not owned
// Each element of the left_ vector represents a left hand side node
// (i.e. an element) and each element of right_ is a right hand side
// node (i.e. a matcher). The values in the left_ vector indicate
// outflow from that node to a node on the the right_ side. The values
// in the right_ indicate inflow, and specify which left_ node is
// feeding that right_ node, if any. For example, left_[3] == 1 means
// there's a flow from element #3 to matcher #1. Such a flow would also
// be redundantly represented in the right_ vector as right_[1] == 3.
// Elements of left_ and right_ are either kUnused or mutually
// referent. Mutually referent means that left_[right_[i]] = i and
// right_[left_[i]] = i.
::
std
::
vector
<
size_t
>
left_
;
::
std
::
vector
<
size_t
>
right_
;
GTEST_DISALLOW_ASSIGN_
(
MaxBipartiteMatchState
);
};
const
size_t
MaxBipartiteMatchState
::
kUnused
;
GTEST_API_
ElementMatcherPairs
FindMaxBipartiteMatching
(
const
MatchMatrix
&
g
)
{
return
MaxBipartiteMatchState
(
g
).
Compute
();
}
static
void
LogElementMatcherPairVec
(
const
ElementMatcherPairs
&
pairs
,
::
std
::
ostream
*
stream
)
{
typedef
ElementMatcherPairs
::
const_iterator
Iter
;
::
std
::
ostream
&
os
=
*
stream
;
os
<<
"{"
;
const
char
*
sep
=
""
;
for
(
Iter
it
=
pairs
.
begin
();
it
!=
pairs
.
end
();
++
it
)
{
os
<<
sep
<<
"
\n
("
<<
"element #"
<<
it
->
first
<<
", "
<<
"matcher #"
<<
it
->
second
<<
")"
;
sep
=
","
;
}
os
<<
"
\n
}"
;
}
// Tries to find a pairing, and explains the result.
GTEST_API_
bool
FindPairing
(
const
MatchMatrix
&
matrix
,
MatchResultListener
*
listener
)
{
ElementMatcherPairs
matches
=
FindMaxBipartiteMatching
(
matrix
);
size_t
max_flow
=
matches
.
size
();
bool
result
=
(
max_flow
==
matrix
.
RhsSize
());
if
(
!
result
)
{
if
(
listener
->
IsInterested
())
{
*
listener
<<
"where no permutation of the elements can "
"satisfy all matchers, and the closest match is "
<<
max_flow
<<
" of "
<<
matrix
.
RhsSize
()
<<
" matchers with the pairings:
\n
"
;
LogElementMatcherPairVec
(
matches
,
listener
->
stream
());
}
return
false
;
}
if
(
matches
.
size
()
>
1
)
{
if
(
listener
->
IsInterested
())
{
const
char
*
sep
=
"where:
\n
"
;
for
(
size_t
mi
=
0
;
mi
<
matches
.
size
();
++
mi
)
{
*
listener
<<
sep
<<
" - element #"
<<
matches
[
mi
].
first
<<
" is matched by matcher #"
<<
matches
[
mi
].
second
;
sep
=
",
\n
"
;
}
}
}
return
true
;
}
bool
MatchMatrix
::
NextGraph
()
{
for
(
size_t
ilhs
=
0
;
ilhs
<
LhsSize
();
++
ilhs
)
{
for
(
size_t
irhs
=
0
;
irhs
<
RhsSize
();
++
irhs
)
{
char
&
b
=
matched_
[
SpaceIndex
(
ilhs
,
irhs
)];
if
(
!
b
)
{
b
=
1
;
return
true
;
}
b
=
0
;
}
}
return
false
;
}
void
MatchMatrix
::
Randomize
()
{
for
(
size_t
ilhs
=
0
;
ilhs
<
LhsSize
();
++
ilhs
)
{
for
(
size_t
irhs
=
0
;
irhs
<
RhsSize
();
++
irhs
)
{
char
&
b
=
matched_
[
SpaceIndex
(
ilhs
,
irhs
)];
b
=
static_cast
<
char
>
(
rand
()
&
1
);
// NOLINT
}
}
}
string
MatchMatrix
::
DebugString
()
const
{
::
std
::
stringstream
ss
;
const
char
*
sep
=
""
;
for
(
size_t
i
=
0
;
i
<
LhsSize
();
++
i
)
{
ss
<<
sep
;
for
(
size_t
j
=
0
;
j
<
RhsSize
();
++
j
)
{
ss
<<
HasEdge
(
i
,
j
);
}
sep
=
";"
;
}
return
ss
.
str
();
}
void
UnorderedElementsAreMatcherImplBase
::
DescribeToImpl
(
::
std
::
ostream
*
os
)
const
{
if
(
matcher_describers_
.
empty
())
{
*
os
<<
"is empty"
;
return
;
}
if
(
matcher_describers_
.
size
()
==
1
)
{
*
os
<<
"has "
<<
Elements
(
1
)
<<
" and that element "
;
matcher_describers_
[
0
]
->
DescribeTo
(
os
);
return
;
}
*
os
<<
"has "
<<
Elements
(
matcher_describers_
.
size
())
<<
" and there exists some permutation of elements such that:
\n
"
;
const
char
*
sep
=
""
;
for
(
size_t
i
=
0
;
i
!=
matcher_describers_
.
size
();
++
i
)
{
*
os
<<
sep
<<
" - element #"
<<
i
<<
" "
;
matcher_describers_
[
i
]
->
DescribeTo
(
os
);
sep
=
", and
\n
"
;
}
}
void
UnorderedElementsAreMatcherImplBase
::
DescribeNegationToImpl
(
::
std
::
ostream
*
os
)
const
{
if
(
matcher_describers_
.
empty
())
{
*
os
<<
"isn't empty"
;
return
;
}
if
(
matcher_describers_
.
size
()
==
1
)
{
*
os
<<
"doesn't have "
<<
Elements
(
1
)
<<
", or has "
<<
Elements
(
1
)
<<
" that "
;
matcher_describers_
[
0
]
->
DescribeNegationTo
(
os
);
return
;
}
*
os
<<
"doesn't have "
<<
Elements
(
matcher_describers_
.
size
())
<<
", or there exists no permutation of elements such that:
\n
"
;
const
char
*
sep
=
""
;
for
(
size_t
i
=
0
;
i
!=
matcher_describers_
.
size
();
++
i
)
{
*
os
<<
sep
<<
" - element #"
<<
i
<<
" "
;
matcher_describers_
[
i
]
->
DescribeTo
(
os
);
sep
=
", and
\n
"
;
}
}
// Checks that all matchers match at least one element, and that all
// elements match at least one matcher. This enables faster matching
// and better error reporting.
// Returns false, writing an explanation to 'listener', if and only
// if the success criteria are not met.
bool
UnorderedElementsAreMatcherImplBase
::
VerifyAllElementsAndMatchersAreMatched
(
const
::
std
::
vector
<
string
>&
element_printouts
,
const
MatchMatrix
&
matrix
,
MatchResultListener
*
listener
)
const
{
bool
result
=
true
;
::
std
::
vector
<
char
>
element_matched
(
matrix
.
LhsSize
(),
0
);
::
std
::
vector
<
char
>
matcher_matched
(
matrix
.
RhsSize
(),
0
);
for
(
size_t
ilhs
=
0
;
ilhs
<
matrix
.
LhsSize
();
ilhs
++
)
{
for
(
size_t
irhs
=
0
;
irhs
<
matrix
.
RhsSize
();
irhs
++
)
{
char
matched
=
matrix
.
HasEdge
(
ilhs
,
irhs
);
element_matched
[
ilhs
]
|=
matched
;
matcher_matched
[
irhs
]
|=
matched
;
}
}
{
const
char
*
sep
=
"where the following matchers don't match any elements:
\n
"
;
for
(
size_t
mi
=
0
;
mi
<
matcher_matched
.
size
();
++
mi
)
{
if
(
matcher_matched
[
mi
])
continue
;
result
=
false
;
if
(
listener
->
IsInterested
())
{
*
listener
<<
sep
<<
"matcher #"
<<
mi
<<
": "
;
matcher_describers_
[
mi
]
->
DescribeTo
(
listener
->
stream
());
sep
=
",
\n
"
;
}
}
}
{
const
char
*
sep
=
"where the following elements don't match any matchers:
\n
"
;
const
char
*
outer_sep
=
""
;
if
(
!
result
)
{
outer_sep
=
"
\n
and "
;
}
for
(
size_t
ei
=
0
;
ei
<
element_matched
.
size
();
++
ei
)
{
if
(
element_matched
[
ei
])
continue
;
result
=
false
;
if
(
listener
->
IsInterested
())
{
*
listener
<<
outer_sep
<<
sep
<<
"element #"
<<
ei
<<
": "
<<
element_printouts
[
ei
];
sep
=
",
\n
"
;
outer_sep
=
""
;
}
}
}
return
result
;
}
}
// namespace internal
}
// namespace testing
test/gmock-generated-matchers_test.cc
View file @
fb25d539
...
...
@@ -80,6 +80,9 @@ using testing::Value;
using
testing
::
internal
::
ElementsAreArrayMatcher
;
using
testing
::
internal
::
string
;
// Evaluates to the number of elements in 'array'.
#define GMOCK_ARRAY_SIZE_(a) (sizeof(a) / sizeof(a[0]))
// Returns the description of the given matcher.
template
<
typename
T
>
string
Describe
(
const
Matcher
<
T
>&
m
)
{
...
...
@@ -284,9 +287,6 @@ Matcher<int> GreaterThan(int n) {
// Tests for ElementsAre().
// Evaluates to the number of elements in 'array'.
#define GMOCK_ARRAY_SIZE_(array) (sizeof(array)/sizeof(array[0]))
TEST
(
ElementsAreTest
,
CanDescribeExpectingNoElement
)
{
Matcher
<
const
vector
<
int
>&>
m
=
ElementsAre
();
EXPECT_EQ
(
"is empty"
,
Describe
(
m
));
...
...
@@ -563,8 +563,8 @@ TEST(ElementsAreTest, MakesCopyOfArguments) {
int
x
=
1
;
int
y
=
2
;
// This should make a copy of x and y.
::
testing
::
internal
::
ElementsAreMatcher
2
<
int
,
int
>
polymorphic_matcher
=
ElementsAre
(
x
,
y
);
::
testing
::
internal
::
ElementsAreMatcher
<
std
::
tr1
::
tuple
<
int
,
int
>
>
polymorphic_matcher
=
ElementsAre
(
x
,
y
);
// Changing x and y now shouldn't affect the meaning of the above matcher.
x
=
y
=
0
;
const
int
array1
[]
=
{
1
,
2
};
...
...
@@ -573,6 +573,7 @@ TEST(ElementsAreTest, MakesCopyOfArguments) {
EXPECT_THAT
(
array2
,
Not
(
polymorphic_matcher
));
}
// Tests for ElementsAreArray(). Since ElementsAreArray() shares most
// of the implementation with ElementsAre(), we don't test it as
// thoroughly here.
...
...
test/gmock-matchers_test.cc
View file @
fb25d539
...
...
@@ -37,6 +37,7 @@
#include "gmock/gmock-more-matchers.h"
#include <string.h>
#include <time.h>
#include <deque>
#include <functional>
#include <iostream>
...
...
@@ -134,11 +135,14 @@ using testing::WhenSorted;
using
testing
::
WhenSortedBy
;
using
testing
::
_
;
using
testing
::
internal
::
DummyMatchResultListener
;
using
testing
::
internal
::
ElementMatcherPair
;
using
testing
::
internal
::
ElementMatcherPairs
;
using
testing
::
internal
::
ExplainMatchFailureTupleTo
;
using
testing
::
internal
::
FloatingEqMatcher
;
using
testing
::
internal
::
FormatMatcherDescription
;
using
testing
::
internal
::
IsReadableTypeName
;
using
testing
::
internal
::
JoinAsTuple
;
using
testing
::
internal
::
MatchMatrix
;
using
testing
::
internal
::
RE
;
using
testing
::
internal
::
StreamMatchResultListener
;
using
testing
::
internal
::
StringMatchResultListener
;
...
...
@@ -147,6 +151,9 @@ using testing::internal::linked_ptr;
using
testing
::
internal
::
scoped_ptr
;
using
testing
::
internal
::
string
;
// Evaluates to the number of elements in 'array'.
#define GMOCK_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0]))
// For testing ExplainMatchResultTo().
class
GreaterThanMatcher
:
public
MatcherInterface
<
int
>
{
public
:
...
...
@@ -4429,13 +4436,439 @@ TEST(WhenSortedTest, WorksForStreamlike) {
}
TEST
(
WhenSortedTest
,
WorksForVectorConstRefMatcherOnStreamlike
)
{
const
int
a
[
5
]
=
{
2
,
1
,
4
,
5
,
3
};
Streamlike
<
int
>
s
(
a
,
a
+
5
);
const
int
a
[]
=
{
2
,
1
,
4
,
5
,
3
};
Streamlike
<
int
>
s
(
a
,
a
+
GMOCK_ARRAY_SIZE_
(
a
)
);
Matcher
<
const
std
::
vector
<
int
>&>
vector_match
=
ElementsAre
(
1
,
2
,
3
,
4
,
5
);
EXPECT_THAT
(
s
,
WhenSorted
(
vector_match
));
EXPECT_THAT
(
s
,
Not
(
WhenSorted
(
ElementsAre
(
2
,
1
,
4
,
5
,
3
))));
}
// Tests for UnorderedElementsAreArray()
TEST
(
UnorderedElementsAreArrayTest
,
SucceedsWhenExpected
)
{
const
int
a
[]
=
{
0
,
1
,
2
,
3
,
4
};
std
::
vector
<
int
>
s
(
a
,
a
+
GMOCK_ARRAY_SIZE_
(
a
));
do
{
StringMatchResultListener
listener
;
EXPECT_TRUE
(
ExplainMatchResult
(
UnorderedElementsAreArray
(
a
),
s
,
&
listener
))
<<
listener
.
str
();
}
while
(
std
::
next_permutation
(
s
.
begin
(),
s
.
end
()));
}
TEST
(
UnorderedElementsAreArrayTest
,
VectorBool
)
{
const
bool
a
[]
=
{
0
,
1
,
0
,
1
,
1
};
const
bool
b
[]
=
{
1
,
0
,
1
,
1
,
0
};
std
::
vector
<
bool
>
expected
(
a
,
a
+
GMOCK_ARRAY_SIZE_
(
a
));
std
::
vector
<
bool
>
actual
(
b
,
b
+
GMOCK_ARRAY_SIZE_
(
b
));
StringMatchResultListener
listener
;
EXPECT_TRUE
(
ExplainMatchResult
(
UnorderedElementsAreArray
(
expected
),
actual
,
&
listener
))
<<
listener
.
str
();
}
class
UnorderedElementsAreTest
:
public
testing
::
Test
{
protected
:
typedef
std
::
vector
<
int
>
IntVec
;
};
TEST_F
(
UnorderedElementsAreTest
,
SucceedsWhenExpected
)
{
const
int
a
[]
=
{
1
,
2
,
3
};
std
::
vector
<
int
>
s
(
a
,
a
+
GMOCK_ARRAY_SIZE_
(
a
));
do
{
StringMatchResultListener
listener
;
EXPECT_TRUE
(
ExplainMatchResult
(
UnorderedElementsAre
(
1
,
2
,
3
),
s
,
&
listener
))
<<
listener
.
str
();
}
while
(
std
::
next_permutation
(
s
.
begin
(),
s
.
end
()));
}
TEST_F
(
UnorderedElementsAreTest
,
FailsWhenAnElementMatchesNoMatcher
)
{
const
int
a
[]
=
{
1
,
2
,
3
};
std
::
vector
<
int
>
s
(
a
,
a
+
GMOCK_ARRAY_SIZE_
(
a
));
std
::
vector
<
Matcher
<
int
>
>
mv
;
mv
.
push_back
(
1
);
mv
.
push_back
(
2
);
mv
.
push_back
(
2
);
// The element with value '3' matches nothing: fail fast.
StringMatchResultListener
listener
;
EXPECT_FALSE
(
ExplainMatchResult
(
UnorderedElementsAreArray
(
mv
),
s
,
&
listener
))
<<
listener
.
str
();
}
// One naive implementation of the matcher runs in O(N!) time, which is too
// slow for many real-world inputs. This test shows that our matcher can match
// 100 inputs very quickly (a few milliseconds). An O(100!) is 10^158
// iterations and obviously effectively incomputable.
// [ RUN ] UnorderedElementsAreTest.Performance
// [ OK ] UnorderedElementsAreTest.Performance (4 ms)
TEST_F
(
UnorderedElementsAreTest
,
Performance
)
{
std
::
vector
<
int
>
s
;
std
::
vector
<
Matcher
<
int
>
>
mv
;
for
(
int
i
=
0
;
i
<
100
;
++
i
)
{
s
.
push_back
(
i
);
mv
.
push_back
(
_
);
}
mv
[
50
]
=
Eq
(
0
);
StringMatchResultListener
listener
;
EXPECT_TRUE
(
ExplainMatchResult
(
UnorderedElementsAreArray
(
mv
),
s
,
&
listener
))
<<
listener
.
str
();
}
// Another variant of 'Performance' with similar expectations.
// [ RUN ] UnorderedElementsAreTest.PerformanceHalfStrict
// [ OK ] UnorderedElementsAreTest.PerformanceHalfStrict (4 ms)
TEST_F
(
UnorderedElementsAreTest
,
PerformanceHalfStrict
)
{
std
::
vector
<
int
>
s
;
std
::
vector
<
Matcher
<
int
>
>
mv
;
for
(
int
i
=
0
;
i
<
100
;
++
i
)
{
s
.
push_back
(
i
);
if
(
i
&
1
)
{
mv
.
push_back
(
_
);
}
else
{
mv
.
push_back
(
i
);
}
}
StringMatchResultListener
listener
;
EXPECT_TRUE
(
ExplainMatchResult
(
UnorderedElementsAreArray
(
mv
),
s
,
&
listener
))
<<
listener
.
str
();
}
TEST_F
(
UnorderedElementsAreTest
,
FailMessageCountWrong
)
{
std
::
vector
<
int
>
v
;
v
.
push_back
(
4
);
StringMatchResultListener
listener
;
EXPECT_FALSE
(
ExplainMatchResult
(
UnorderedElementsAre
(
1
,
2
,
3
),
v
,
&
listener
))
<<
listener
.
str
();
EXPECT_THAT
(
listener
.
str
(),
Eq
(
"which has 1 element"
));
}
TEST_F
(
UnorderedElementsAreTest
,
FailMessageCountWrongZero
)
{
std
::
vector
<
int
>
v
;
StringMatchResultListener
listener
;
EXPECT_FALSE
(
ExplainMatchResult
(
UnorderedElementsAre
(
1
,
2
,
3
),
v
,
&
listener
))
<<
listener
.
str
();
EXPECT_THAT
(
listener
.
str
(),
Eq
(
""
));
}
TEST_F
(
UnorderedElementsAreTest
,
FailMessageUnmatchedMatchers
)
{
std
::
vector
<
int
>
v
;
v
.
push_back
(
1
);
v
.
push_back
(
1
);
StringMatchResultListener
listener
;
EXPECT_FALSE
(
ExplainMatchResult
(
UnorderedElementsAre
(
1
,
2
),
v
,
&
listener
))
<<
listener
.
str
();
EXPECT_THAT
(
listener
.
str
(),
Eq
(
"where the following matchers don't match any elements:
\n
"
"matcher #1: is equal to 2"
));
}
TEST_F
(
UnorderedElementsAreTest
,
FailMessageUnmatchedElements
)
{
std
::
vector
<
int
>
v
;
v
.
push_back
(
1
);
v
.
push_back
(
2
);
StringMatchResultListener
listener
;
EXPECT_FALSE
(
ExplainMatchResult
(
UnorderedElementsAre
(
1
,
1
),
v
,
&
listener
))
<<
listener
.
str
();
EXPECT_THAT
(
listener
.
str
(),
Eq
(
"where the following elements don't match any matchers:
\n
"
"element #1: 2"
));
}
TEST_F
(
UnorderedElementsAreTest
,
FailMessageUnmatchedMatcherAndElement
)
{
std
::
vector
<
int
>
v
;
v
.
push_back
(
2
);
v
.
push_back
(
3
);
StringMatchResultListener
listener
;
EXPECT_FALSE
(
ExplainMatchResult
(
UnorderedElementsAre
(
1
,
2
),
v
,
&
listener
))
<<
listener
.
str
();
EXPECT_THAT
(
listener
.
str
(),
Eq
(
"where"
" the following matchers don't match any elements:
\n
"
"matcher #0: is equal to 1
\n
"
"and"
" where"
" the following elements don't match any matchers:
\n
"
"element #1: 3"
));
}
// Test helper for formatting element, matcher index pairs in expectations.
static
string
EMString
(
int
element
,
int
matcher
)
{
stringstream
ss
;
ss
<<
"(element #"
<<
element
<<
", matcher #"
<<
matcher
<<
")"
;
return
ss
.
str
();
}
TEST_F
(
UnorderedElementsAreTest
,
FailMessageImperfectMatchOnly
)
{
// A situation where all elements and matchers have a match
// associated with them, but the max matching is not perfect.
std
::
vector
<
string
>
v
;
v
.
push_back
(
"a"
);
v
.
push_back
(
"b"
);
v
.
push_back
(
"c"
);
StringMatchResultListener
listener
;
EXPECT_FALSE
(
ExplainMatchResult
(
UnorderedElementsAre
(
"a"
,
"a"
,
AnyOf
(
"b"
,
"c"
)),
v
,
&
listener
))
<<
listener
.
str
();
string
prefix
=
"where no permutation of the elements can satisfy all matchers, "
"and the closest match is 2 of 3 matchers with the "
"pairings:
\n
"
;
// We have to be a bit loose here, because there are 4 valid max matches.
EXPECT_THAT
(
listener
.
str
(),
AnyOf
(
prefix
+
"{
\n
"
+
EMString
(
0
,
0
)
+
",
\n
"
+
EMString
(
1
,
2
)
+
"
\n
}"
,
prefix
+
"{
\n
"
+
EMString
(
0
,
1
)
+
",
\n
"
+
EMString
(
1
,
2
)
+
"
\n
}"
,
prefix
+
"{
\n
"
+
EMString
(
0
,
0
)
+
",
\n
"
+
EMString
(
2
,
2
)
+
"
\n
}"
,
prefix
+
"{
\n
"
+
EMString
(
0
,
1
)
+
",
\n
"
+
EMString
(
2
,
2
)
+
"
\n
}"
));
}
TEST_F
(
UnorderedElementsAreTest
,
Describe
)
{
EXPECT_THAT
(
Describe
<
IntVec
>
(
UnorderedElementsAre
()),
Eq
(
"is empty"
));
EXPECT_THAT
(
Describe
<
IntVec
>
(
UnorderedElementsAre
(
345
)),
Eq
(
"has 1 element and that element is equal to 345"
));
EXPECT_THAT
(
Describe
<
IntVec
>
(
UnorderedElementsAre
(
111
,
222
,
333
)),
Eq
(
"has 3 elements and there exists some permutation "
"of elements such that:
\n
"
" - element #0 is equal to 111, and
\n
"
" - element #1 is equal to 222, and
\n
"
" - element #2 is equal to 333"
));
}
TEST_F
(
UnorderedElementsAreTest
,
DescribeNegation
)
{
EXPECT_THAT
(
DescribeNegation
<
IntVec
>
(
UnorderedElementsAre
()),
Eq
(
"isn't empty"
));
EXPECT_THAT
(
DescribeNegation
<
IntVec
>
(
UnorderedElementsAre
(
345
)),
Eq
(
"doesn't have 1 element, or has 1 element that isn't equal to 345"
));
EXPECT_THAT
(
DescribeNegation
<
IntVec
>
(
UnorderedElementsAre
(
123
,
234
,
345
)),
Eq
(
"doesn't have 3 elements, or there exists no permutation "
"of elements such that:
\n
"
" - element #0 is equal to 123, and
\n
"
" - element #1 is equal to 234, and
\n
"
" - element #2 is equal to 345"
));
}
namespace
{
// Used as a check on the more complex max flow method used in the
// real testing::internal::FindMaxBipartiteMatching. This method is
// compatible but runs in worst-case factorial time, so we only
// use it in testing for small problem sizes.
template
<
typename
Graph
>
class
BacktrackingMaxBPMState
{
public
:
// Does not take ownership of 'g'.
explicit
BacktrackingMaxBPMState
(
const
Graph
*
g
)
:
graph_
(
g
)
{
}
ElementMatcherPairs
Compute
()
{
if
(
graph_
->
LhsSize
()
==
0
||
graph_
->
RhsSize
()
==
0
)
{
return
best_so_far_
;
}
lhs_used_
.
assign
(
graph_
->
LhsSize
(),
kUnused
);
rhs_used_
.
assign
(
graph_
->
RhsSize
(),
kUnused
);
for
(
size_t
irhs
=
0
;
irhs
<
graph_
->
RhsSize
();
++
irhs
)
{
matches_
.
clear
();
RecurseInto
(
irhs
);
if
(
best_so_far_
.
size
()
==
graph_
->
RhsSize
())
break
;
}
return
best_so_far_
;
}
private
:
static
const
size_t
kUnused
=
static_cast
<
size_t
>
(
-
1
);
void
PushMatch
(
size_t
lhs
,
size_t
rhs
)
{
matches_
.
push_back
(
ElementMatcherPair
(
lhs
,
rhs
));
lhs_used_
[
lhs
]
=
rhs
;
rhs_used_
[
rhs
]
=
lhs
;
if
(
matches_
.
size
()
>
best_so_far_
.
size
())
{
best_so_far_
=
matches_
;
}
}
void
PopMatch
()
{
const
ElementMatcherPair
&
back
=
matches_
.
back
();
lhs_used_
[
back
.
first
]
=
kUnused
;
rhs_used_
[
back
.
second
]
=
kUnused
;
matches_
.
pop_back
();
}
bool
RecurseInto
(
size_t
irhs
)
{
if
(
rhs_used_
[
irhs
]
!=
kUnused
)
{
return
true
;
}
for
(
size_t
ilhs
=
0
;
ilhs
<
graph_
->
LhsSize
();
++
ilhs
)
{
if
(
lhs_used_
[
ilhs
]
!=
kUnused
)
{
continue
;
}
if
(
!
graph_
->
HasEdge
(
ilhs
,
irhs
))
{
continue
;
}
PushMatch
(
ilhs
,
irhs
);
if
(
best_so_far_
.
size
()
==
graph_
->
RhsSize
())
{
return
false
;
}
for
(
size_t
mi
=
irhs
+
1
;
mi
<
graph_
->
RhsSize
();
++
mi
)
{
if
(
!
RecurseInto
(
mi
))
return
false
;
}
PopMatch
();
}
return
true
;
}
const
Graph
*
graph_
;
// not owned
std
::
vector
<
size_t
>
lhs_used_
;
std
::
vector
<
size_t
>
rhs_used_
;
ElementMatcherPairs
matches_
;
ElementMatcherPairs
best_so_far_
;
};
template
<
typename
Graph
>
const
size_t
BacktrackingMaxBPMState
<
Graph
>::
kUnused
;
}
// namespace
// Implement a simple backtracking algorithm to determine if it is possible
// to find one element per matcher, without reusing elements.
template
<
typename
Graph
>
ElementMatcherPairs
FindBacktrackingMaxBPM
(
const
Graph
&
g
)
{
return
BacktrackingMaxBPMState
<
Graph
>
(
&
g
).
Compute
();
}
class
BacktrackingBPMTest
:
public
::
testing
::
Test
{
};
// Tests the MaxBipartiteMatching algorithm with square matrices.
// The single int param is the # of nodes on each of the left and right sides.
class
BipartiteTest
:
public
::
testing
::
TestWithParam
<
int
>
{
};
// Verify all match graphs up to some moderate number of edges.
TEST_P
(
BipartiteTest
,
Exhaustive
)
{
int
nodes
=
GetParam
();
MatchMatrix
graph
(
nodes
,
nodes
);
do
{
ElementMatcherPairs
matches
=
internal
::
FindMaxBipartiteMatching
(
graph
);
EXPECT_EQ
(
FindBacktrackingMaxBPM
(
graph
).
size
(),
matches
.
size
())
<<
"graph: "
<<
graph
.
DebugString
();
// Check that all elements of matches are in the graph.
// Check that elements of first and second are unique.
std
::
vector
<
bool
>
seen_element
(
graph
.
LhsSize
());
std
::
vector
<
bool
>
seen_matcher
(
graph
.
RhsSize
());
SCOPED_TRACE
(
PrintToString
(
matches
));
for
(
size_t
i
=
0
;
i
<
matches
.
size
();
++
i
)
{
size_t
ilhs
=
matches
[
i
].
first
;
size_t
irhs
=
matches
[
i
].
second
;
EXPECT_TRUE
(
graph
.
HasEdge
(
ilhs
,
irhs
));
EXPECT_FALSE
(
seen_element
[
ilhs
]);
EXPECT_FALSE
(
seen_matcher
[
irhs
]);
seen_element
[
ilhs
]
=
true
;
seen_matcher
[
irhs
]
=
true
;
}
}
while
(
graph
.
NextGraph
());
}
INSTANTIATE_TEST_CASE_P
(
AllGraphs
,
BipartiteTest
,
::
testing
::
Range
(
0
,
5
));
// Parameterized by a pair interpreted as (LhsSize, RhsSize).
class
BipartiteNonSquareTest
:
public
::
testing
::
TestWithParam
<
std
::
pair
<
size_t
,
size_t
>
>
{
};
TEST_F
(
BipartiteNonSquareTest
,
SimpleBacktracking
)
{
// .......
// 0:-----\ :
// 1:---\ | :
// 2:---\ | :
// 3:-\ | | :
// :.......:
// 0 1 2
MatchMatrix
g
(
4
,
3
);
static
const
int
kEdges
[][
2
]
=
{
{
0
,
2
},
{
1
,
1
},
{
2
,
1
},
{
3
,
0
}
};
for
(
size_t
i
=
0
;
i
<
GMOCK_ARRAY_SIZE_
(
kEdges
);
++
i
)
{
g
.
SetEdge
(
kEdges
[
i
][
0
],
kEdges
[
i
][
1
],
true
);
}
EXPECT_THAT
(
FindBacktrackingMaxBPM
(
g
),
ElementsAre
(
Pair
(
3
,
0
),
Pair
(
AnyOf
(
1
,
2
),
1
),
Pair
(
0
,
2
)))
<<
g
.
DebugString
();
}
// Verify a few nonsquare matrices.
TEST_P
(
BipartiteNonSquareTest
,
Exhaustive
)
{
size_t
nlhs
=
GetParam
().
first
;
size_t
nrhs
=
GetParam
().
second
;
MatchMatrix
graph
(
nlhs
,
nrhs
);
do
{
EXPECT_EQ
(
FindBacktrackingMaxBPM
(
graph
).
size
(),
internal
::
FindMaxBipartiteMatching
(
graph
).
size
())
<<
"graph: "
<<
graph
.
DebugString
()
<<
"
\n
backtracking: "
<<
PrintToString
(
FindBacktrackingMaxBPM
(
graph
))
<<
"
\n
max flow: "
<<
PrintToString
(
internal
::
FindMaxBipartiteMatching
(
graph
));
}
while
(
graph
.
NextGraph
());
}
INSTANTIATE_TEST_CASE_P
(
AllGraphs
,
BipartiteNonSquareTest
,
testing
::
Values
(
std
::
make_pair
(
1
,
2
),
std
::
make_pair
(
2
,
1
),
std
::
make_pair
(
3
,
2
),
std
::
make_pair
(
2
,
3
),
std
::
make_pair
(
4
,
1
),
std
::
make_pair
(
1
,
4
),
std
::
make_pair
(
4
,
3
),
std
::
make_pair
(
3
,
4
)));
class
BipartiteRandomTest
:
public
::
testing
::
TestWithParam
<
std
::
pair
<
int
,
int
>
>
{
};
// Verifies a large sample of larger graphs.
TEST_P
(
BipartiteRandomTest
,
LargerNets
)
{
int
nodes
=
GetParam
().
first
;
int
iters
=
GetParam
().
second
;
MatchMatrix
graph
(
nodes
,
nodes
);
testing
::
internal
::
Int32
seed
=
GTEST_FLAG
(
random_seed
);
if
(
seed
==
0
)
{
seed
=
static_cast
<
testing
::
internal
::
Int32
>
(
time
(
NULL
));
}
for
(;
iters
>
0
;
--
iters
,
++
seed
)
{
srand
(
static_cast
<
int
>
(
seed
));
graph
.
Randomize
();
EXPECT_EQ
(
FindBacktrackingMaxBPM
(
graph
).
size
(),
internal
::
FindMaxBipartiteMatching
(
graph
).
size
())
<<
" graph: "
<<
graph
.
DebugString
()
<<
"
\n
To reproduce the failure, rerun the test with the flag"
" --"
<<
GTEST_FLAG_PREFIX_
<<
"random_seed="
<<
seed
;
}
}
// Test argument is a std::pair<int, int> representing (nodes, iters).
INSTANTIATE_TEST_CASE_P
(
Samples
,
BipartiteRandomTest
,
testing
::
Values
(
std
::
make_pair
(
5
,
10000
),
std
::
make_pair
(
6
,
5000
),
std
::
make_pair
(
7
,
2000
),
std
::
make_pair
(
8
,
500
),
std
::
make_pair
(
9
,
100
)));
// Tests IsReadableTypeName().
TEST
(
IsReadableTypeNameTest
,
ReturnsTrueForShortNames
)
{
...
...
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