Skip to content

Commit

Permalink
Googletest export
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Abseil Team authored and derekmauro committed Jul 7, 2021
1 parent 977cffc commit 8306020
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 0 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS
Expand Up @@ -34,6 +34,7 @@ Manuel Klimek <klimek@google.com>
Mario Tanev <radix@google.com>
Mark Paskin
Markus Heule <markus.heule@gmail.com>
Martijn Vels <mvels@google.com>
Matthew Simmons <simmonmt@acm.org>
Mika Raento <mikie@iki.fi>
Mike Bland <mbland@google.com>
Expand Down
1 change: 1 addition & 0 deletions docs/reference/matchers.md
Expand Up @@ -238,6 +238,7 @@ You can make a matcher from one or more other matchers:
| `AnyOf(m1, m2, ..., mn)` | `argument` matches at least one of the matchers `m1` to `mn`. |
| `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. |
| `Not(m)` | `argument` doesn't match matcher `m`. |
| `Conditional(cond, m1, m2)` | Matches matcher `m1` if `cond` evalutes to true, else matches `m2`.|

## Adapters for Matchers

Expand Down
36 changes: 36 additions & 0 deletions googlemock/include/gmock/gmock-matchers.h
Expand Up @@ -1405,6 +1405,30 @@ class AnyOfMatcherImpl : public MatcherInterface<const T&> {
template <typename... Args>
using AnyOfMatcher = VariadicMatcher<AnyOfMatcherImpl, Args...>;

// ConditionalMatcher is the implementation of Conditional(cond, m1, m2)
template <typename MatcherTrue, typename MatcherFalse>
class ConditionalMatcher {
public:
ConditionalMatcher(bool condition, MatcherTrue matcher_true,
MatcherFalse matcher_false)
: condition_(condition),
matcher_true_(std::move(matcher_true)),
matcher_false_(std::move(matcher_false)) {}

template <typename T>
operator Matcher<T>() const { // NOLINT(runtime/explicit)
return condition_ ? SafeMatcherCast<T>(matcher_true_)
: SafeMatcherCast<T>(matcher_false_);
}

private:
bool condition_;
MatcherTrue matcher_true_;
MatcherFalse matcher_false_;

GTEST_DISALLOW_ASSIGN_(ConditionalMatcher);
};

// Wrapper for implementation of Any/AllOfArray().
template <template <class> class MatcherImpl, typename T>
class SomeOfArrayMatcher {
Expand Down Expand Up @@ -4926,6 +4950,18 @@ Pair(FirstMatcher first_matcher, SecondMatcher second_matcher) {
}

namespace no_adl {
// Conditional() creates a matcher that conditionally uses either the first or
// second matcher provided. For example, we could create an `equal if, and only
// if' matcher using the Conditonal wrapper as follows:
//
// EXPECT_THAT(result, Conditional(condition, Eq(expected), Ne(expected)));
template <typename MatcherTrue, typename MatcherFalse>
internal::ConditionalMatcher<MatcherTrue, MatcherFalse> Conditional(
bool condition, MatcherTrue matcher_true, MatcherFalse matcher_false) {
return internal::ConditionalMatcher<MatcherTrue, MatcherFalse>(
condition, std::move(matcher_true), std::move(matcher_false));
}

// FieldsAre(matchers...) matches piecewise the fields of compatible structs.
// These include those that support `get<I>(obj)`, and when structured bindings
// are enabled any class that supports them.
Expand Down
28 changes: 28 additions & 0 deletions googlemock/test/gmock-matchers_test.cc
Expand Up @@ -2772,6 +2772,34 @@ TEST(AnyOfTest, VariadicMatchesWhenAnyMatches) {
"43", "44", "45", "46", "47", "48", "49", "50"));
}

TEST(ConditionalTest, MatchesFirstIfCondition) {
Matcher<std::string> eq_red = Eq("red");
Matcher<std::string> ne_red = Ne("red");
Matcher<std::string> m = Conditional(true, eq_red, ne_red);
EXPECT_TRUE(m.Matches("red"));
EXPECT_FALSE(m.Matches("green"));

StringMatchResultListener listener;
StringMatchResultListener expected;
EXPECT_FALSE(m.MatchAndExplain("green", &listener));
EXPECT_FALSE(eq_red.MatchAndExplain("green", &expected));
EXPECT_THAT(listener.str(), Eq(expected.str()));
}

TEST(ConditionalTest, MatchesSecondIfCondition) {
Matcher<std::string> eq_red = Eq("red");
Matcher<std::string> ne_red = Ne("red");
Matcher<std::string> m = Conditional(false, eq_red, ne_red);
EXPECT_FALSE(m.Matches("red"));
EXPECT_TRUE(m.Matches("green"));

StringMatchResultListener listener;
StringMatchResultListener expected;
EXPECT_FALSE(m.MatchAndExplain("red", &listener));
EXPECT_FALSE(ne_red.MatchAndExplain("red", &expected));
EXPECT_THAT(listener.str(), Eq(expected.str()));
}

// Tests the variadic version of the ElementsAreMatcher
TEST(ElementsAreTest, HugeMatcher) {
vector<int> test_vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
Expand Down

0 comments on commit 8306020

Please sign in to comment.