Skip to content

Commit 8306020

Browse files
Abseil Teamderekmauro
Abseil Team
authored andcommitted
Googletest export
Add `Conditional` wrapper to gtest This follows an initial proposal for an 'EqIff` matcher. `Conditional` was considered more precise as an EqIff() matcher may suffer from `Iff` not being universally understood. PiperOrigin-RevId: 383407665
1 parent 977cffc commit 8306020

File tree

4 files changed

+66
-0
lines changed

4 files changed

+66
-0
lines changed

CONTRIBUTORS

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Manuel Klimek <klimek@google.com>
3434
Mario Tanev <radix@google.com>
3535
Mark Paskin
3636
Markus Heule <markus.heule@gmail.com>
37+
Martijn Vels <mvels@google.com>
3738
Matthew Simmons <simmonmt@acm.org>
3839
Mika Raento <mikie@iki.fi>
3940
Mike Bland <mbland@google.com>

docs/reference/matchers.md

+1
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ You can make a matcher from one or more other matchers:
238238
| `AnyOf(m1, m2, ..., mn)` | `argument` matches at least one of the matchers `m1` to `mn`. |
239239
| `AnyOfArray({m0, m1, ..., mn})`, `AnyOfArray(a_container)`, `AnyOfArray(begin, end)`, `AnyOfArray(array)`, or `AnyOfArray(array, count)` | The same as `AnyOf()` except that the matchers come from an initializer list, STL-style container, iterator range, or C-style array. |
240240
| `Not(m)` | `argument` doesn't match matcher `m`. |
241+
| `Conditional(cond, m1, m2)` | Matches matcher `m1` if `cond` evalutes to true, else matches `m2`.|
241242

242243
## Adapters for Matchers
243244

googlemock/include/gmock/gmock-matchers.h

+36
Original file line numberDiff line numberDiff line change
@@ -1405,6 +1405,30 @@ class AnyOfMatcherImpl : public MatcherInterface<const T&> {
14051405
template <typename... Args>
14061406
using AnyOfMatcher = VariadicMatcher<AnyOfMatcherImpl, Args...>;
14071407

1408+
// ConditionalMatcher is the implementation of Conditional(cond, m1, m2)
1409+
template <typename MatcherTrue, typename MatcherFalse>
1410+
class ConditionalMatcher {
1411+
public:
1412+
ConditionalMatcher(bool condition, MatcherTrue matcher_true,
1413+
MatcherFalse matcher_false)
1414+
: condition_(condition),
1415+
matcher_true_(std::move(matcher_true)),
1416+
matcher_false_(std::move(matcher_false)) {}
1417+
1418+
template <typename T>
1419+
operator Matcher<T>() const { // NOLINT(runtime/explicit)
1420+
return condition_ ? SafeMatcherCast<T>(matcher_true_)
1421+
: SafeMatcherCast<T>(matcher_false_);
1422+
}
1423+
1424+
private:
1425+
bool condition_;
1426+
MatcherTrue matcher_true_;
1427+
MatcherFalse matcher_false_;
1428+
1429+
GTEST_DISALLOW_ASSIGN_(ConditionalMatcher);
1430+
};
1431+
14081432
// Wrapper for implementation of Any/AllOfArray().
14091433
template <template <class> class MatcherImpl, typename T>
14101434
class SomeOfArrayMatcher {
@@ -4926,6 +4950,18 @@ Pair(FirstMatcher first_matcher, SecondMatcher second_matcher) {
49264950
}
49274951

49284952
namespace no_adl {
4953+
// Conditional() creates a matcher that conditionally uses either the first or
4954+
// second matcher provided. For example, we could create an `equal if, and only
4955+
// if' matcher using the Conditonal wrapper as follows:
4956+
//
4957+
// EXPECT_THAT(result, Conditional(condition, Eq(expected), Ne(expected)));
4958+
template <typename MatcherTrue, typename MatcherFalse>
4959+
internal::ConditionalMatcher<MatcherTrue, MatcherFalse> Conditional(
4960+
bool condition, MatcherTrue matcher_true, MatcherFalse matcher_false) {
4961+
return internal::ConditionalMatcher<MatcherTrue, MatcherFalse>(
4962+
condition, std::move(matcher_true), std::move(matcher_false));
4963+
}
4964+
49294965
// FieldsAre(matchers...) matches piecewise the fields of compatible structs.
49304966
// These include those that support `get<I>(obj)`, and when structured bindings
49314967
// are enabled any class that supports them.

googlemock/test/gmock-matchers_test.cc

+28
Original file line numberDiff line numberDiff line change
@@ -2772,6 +2772,34 @@ TEST(AnyOfTest, VariadicMatchesWhenAnyMatches) {
27722772
"43", "44", "45", "46", "47", "48", "49", "50"));
27732773
}
27742774

2775+
TEST(ConditionalTest, MatchesFirstIfCondition) {
2776+
Matcher<std::string> eq_red = Eq("red");
2777+
Matcher<std::string> ne_red = Ne("red");
2778+
Matcher<std::string> m = Conditional(true, eq_red, ne_red);
2779+
EXPECT_TRUE(m.Matches("red"));
2780+
EXPECT_FALSE(m.Matches("green"));
2781+
2782+
StringMatchResultListener listener;
2783+
StringMatchResultListener expected;
2784+
EXPECT_FALSE(m.MatchAndExplain("green", &listener));
2785+
EXPECT_FALSE(eq_red.MatchAndExplain("green", &expected));
2786+
EXPECT_THAT(listener.str(), Eq(expected.str()));
2787+
}
2788+
2789+
TEST(ConditionalTest, MatchesSecondIfCondition) {
2790+
Matcher<std::string> eq_red = Eq("red");
2791+
Matcher<std::string> ne_red = Ne("red");
2792+
Matcher<std::string> m = Conditional(false, eq_red, ne_red);
2793+
EXPECT_FALSE(m.Matches("red"));
2794+
EXPECT_TRUE(m.Matches("green"));
2795+
2796+
StringMatchResultListener listener;
2797+
StringMatchResultListener expected;
2798+
EXPECT_FALSE(m.MatchAndExplain("red", &listener));
2799+
EXPECT_FALSE(ne_red.MatchAndExplain("red", &expected));
2800+
EXPECT_THAT(listener.str(), Eq(expected.str()));
2801+
}
2802+
27752803
// Tests the variadic version of the ElementsAreMatcher
27762804
TEST(ElementsAreTest, HugeMatcher) {
27772805
vector<int> test_vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

0 commit comments

Comments
 (0)