summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/advanced.md12
-rw-r--r--docs/gmock_cook_book.md4
-rw-r--r--googlemock/include/gmock/gmock-matchers.h39
-rw-r--r--googlemock/test/gmock-matchers-comparisons_test.cc60
-rw-r--r--googlemock/test/gmock-matchers-misc_test.cc19
5 files changed, 111 insertions, 23 deletions
diff --git a/docs/advanced.md b/docs/advanced.md
index 7e998cc..d4b44d5 100644
--- a/docs/advanced.md
+++ b/docs/advanced.md
@@ -416,7 +416,7 @@ corruption, security holes, or worse. Hence it is vitally important to test that
such assertion statements work as expected.
Since these precondition checks cause the processes to die, we call such tests
-_death tests_. More generally, any test that checks that a program terminates
+*death tests*. More generally, any test that checks that a program terminates
(except by throwing an exception) in an expected fashion is also a death test.
Note that if a piece of code throws an exception, we don't consider it "death"
@@ -462,6 +462,12 @@ verifies that:
exit with exit code 0, and
* calling `KillProcess()` kills the process with signal `SIGKILL`.
+{: .callout .warning}
+Warning: If your death test contains mocks and is expecting a specific exit
+code, then you must allow the mock objects to be leaked via `Mock::AllowLeak`.
+This is because the mock leak detector will exit with its own error code if it
+detects a leak.
+
The test function body may contain other assertions and statements as well, if
necessary.
@@ -727,7 +733,7 @@ Some tips on using `SCOPED_TRACE`:
### Propagating Fatal Failures
A common pitfall when using `ASSERT_*` and `FAIL*` is not understanding that
-when they fail they only abort the _current function_, not the entire test. For
+when they fail they only abort the *current function*, not the entire test. For
example, the following test will segfault:
```c++
@@ -2382,7 +2388,7 @@ IMPORTANT: The exact format of the JSON document is subject to change.
#### Detecting Test Premature Exit
-Google Test implements the _premature-exit-file_ protocol for test runners to
+Google Test implements the *premature-exit-file* protocol for test runners to
catch any kind of unexpected exits of test programs. Upon start, Google Test
creates the file which will be automatically deleted after all work has been
finished. Then, the test runner can check if this file exists. In case the file
diff --git a/docs/gmock_cook_book.md b/docs/gmock_cook_book.md
index 948abe9..633dbc3 100644
--- a/docs/gmock_cook_book.md
+++ b/docs/gmock_cook_book.md
@@ -936,8 +936,8 @@ casts a matcher `m` to type `Matcher<T>`. To ensure safety, gMock checks that
floating-point numbers), the conversion from `T` to `U` is not lossy (in
other words, any value representable by `T` can also be represented by `U`);
and
-3. When `U` is a reference, `T` must also be a reference (as the underlying
- matcher may be interested in the address of the `U` value).
+3. When `U` is a non-const reference, `T` must also be a reference (as the
+ underlying matcher may be interested in the address of the `U` value).
The code won't compile if any of these conditions isn't met.
diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h
index 8f82b27..e979544 100644
--- a/googlemock/include/gmock/gmock-matchers.h
+++ b/googlemock/include/gmock/gmock-matchers.h
@@ -408,13 +408,22 @@ class MatcherCastImpl<T, Matcher<U>> {
}
private:
- class Impl : public MatcherInterface<T> {
+ // If it's possible to implicitly convert a `const T&` to U, then `Impl` can
+ // take that as input to avoid a copy. Otherwise, such as when `T` is a
+ // non-const reference type or a type explicitly constructible only from a
+ // non-const reference, then `Impl` must use `T` as-is (potentially copying).
+ using ImplArgT =
+ typename std::conditional<std::is_convertible<const T&, const U&>::value,
+ const T&, T>::type;
+
+ class Impl : public MatcherInterface<ImplArgT> {
public:
explicit Impl(const Matcher<U>& source_matcher)
: source_matcher_(source_matcher) {}
// We delegate the matching logic to the source matcher.
- bool MatchAndExplain(T x, MatchResultListener* listener) const override {
+ bool MatchAndExplain(ImplArgT x,
+ MatchResultListener* listener) const override {
using FromType = typename std::remove_cv<typename std::remove_pointer<
typename std::remove_reference<T>::type>::type>::type;
using ToType = typename std::remove_cv<typename std::remove_pointer<
@@ -431,9 +440,8 @@ class MatcherCastImpl<T, Matcher<U>> {
// Do the cast to `U` explicitly if necessary.
// Otherwise, let implicit conversions do the trick.
- using CastType =
- typename std::conditional<std::is_convertible<T&, const U&>::value,
- T&, U>::type;
+ using CastType = typename std::conditional<
+ std::is_convertible<ImplArgT&, const U&>::value, ImplArgT&, U>::type;
return source_matcher_.MatchAndExplain(static_cast<CastType>(x),
listener);
@@ -528,18 +536,16 @@ inline Matcher<T> SafeMatcherCast(const M& polymorphic_matcher_or_value) {
// safely convert a Matcher<U> to a Matcher<T> (i.e. Matcher is
// contravariant): just keep a copy of the original Matcher<U>, convert the
// argument from type T to U, and then pass it to the underlying Matcher<U>.
-// The only exception is when U is a reference and T is not, as the
+// The only exception is when U is a non-const reference and T is not, as the
// underlying Matcher<U> may be interested in the argument's address, which
-// is not preserved in the conversion from T to U.
+// cannot be preserved in the conversion from T to U (since a copy of the input
+// T argument would be required to provide a non-const reference U).
template <typename T, typename U>
inline Matcher<T> SafeMatcherCast(const Matcher<U>& matcher) {
// Enforce that T can be implicitly converted to U.
static_assert(std::is_convertible<const T&, const U&>::value,
- "T must be implicitly convertible to U");
- // Enforce that we are not converting a non-reference type T to a reference
- // type U.
- static_assert(std::is_reference<T>::value || !std::is_reference<U>::value,
- "cannot convert non reference arg to reference");
+ "T must be implicitly convertible to U (and T must be a "
+ "non-const reference if U is a non-const reference)");
// In case both T and U are arithmetic types, enforce that the
// conversion is not lossy.
typedef GTEST_REMOVE_REFERENCE_AND_CONST_(T) RawT;
@@ -2275,6 +2281,9 @@ class ResultOfMatcher {
class Impl : public MatcherInterface<T> {
using ResultType = decltype(CallableTraits<Callable>::template Invoke<T>(
std::declval<CallableStorageType>(), std::declval<T>()));
+ using InnerType = std::conditional_t<
+ std::is_lvalue_reference<ResultType>::value,
+ const typename std::remove_reference<ResultType>::type&, ResultType>;
public:
template <typename M>
@@ -2282,7 +2291,7 @@ class ResultOfMatcher {
const CallableStorageType& callable, const M& matcher)
: result_description_(result_description),
callable_(callable),
- matcher_(MatcherCast<ResultType>(matcher)) {}
+ matcher_(MatcherCast<InnerType>(matcher)) {}
void DescribeTo(::std::ostream* os) const override {
if (result_description_.empty()) {
@@ -2312,7 +2321,7 @@ class ResultOfMatcher {
// takes a non-const reference as argument.
// Also, specifying template argument explicitly is needed because T could
// be a non-const reference (e.g. Matcher<Uncopyable&>).
- ResultType result =
+ InnerType result =
CallableTraits<Callable>::template Invoke<T>(callable_, obj);
return MatchPrintAndExplain(result, matcher_, listener);
}
@@ -2325,7 +2334,7 @@ class ResultOfMatcher {
// use stateful callables with ResultOf(), which doesn't guarantee
// how many times the callable will be invoked.
mutable CallableStorageType callable_;
- const Matcher<ResultType> matcher_;
+ const Matcher<InnerType> matcher_;
}; // class Impl
const std::string result_description_;
diff --git a/googlemock/test/gmock-matchers-comparisons_test.cc b/googlemock/test/gmock-matchers-comparisons_test.cc
index a324c4c..a331aec 100644
--- a/googlemock/test/gmock-matchers-comparisons_test.cc
+++ b/googlemock/test/gmock-matchers-comparisons_test.cc
@@ -411,9 +411,27 @@ class IntValue {
int value_;
};
+// For testing casting matchers between compatible types. This is similar to
+// IntValue, but takes a non-const reference to the value, showing MatcherCast
+// works with such types (and doesn't, for example, use a const ref internally).
+class MutableIntView {
+ public:
+ // An int& can be statically (although not implicitly) cast to a
+ // MutableIntView.
+ explicit MutableIntView(int& a_value) : value_(a_value) {}
+
+ int& value() const { return value_; }
+
+ private:
+ int& value_;
+};
+
// For testing casting matchers between compatible types.
bool IsPositiveIntValue(const IntValue& foo) { return foo.value() > 0; }
+// For testing casting matchers between compatible types.
+bool IsPositiveMutableIntView(MutableIntView foo) { return foo.value() > 0; }
+
// Tests that MatcherCast<T>(m) works when m is a Matcher<U> where T
// can be statically converted to U.
TEST(MatcherCastTest, FromCompatibleType) {
@@ -429,14 +447,34 @@ TEST(MatcherCastTest, FromCompatibleType) {
// predicate.
EXPECT_TRUE(m4.Matches(1));
EXPECT_FALSE(m4.Matches(0));
+
+ Matcher<MutableIntView> m5 = Truly(IsPositiveMutableIntView);
+ Matcher<int> m6 = MatcherCast<int>(m5);
+ // In the following, the arguments 1 and 0 are statically converted to
+ // MutableIntView objects, and then tested by the IsPositiveMutableIntView()
+ // predicate.
+ EXPECT_TRUE(m6.Matches(1));
+ EXPECT_FALSE(m6.Matches(0));
}
// Tests that MatcherCast<T>(m) works when m is a Matcher<const T&>.
TEST(MatcherCastTest, FromConstReferenceToNonReference) {
- Matcher<const int&> m1 = Eq(0);
+ int n = 0;
+ Matcher<const int&> m1 = Ref(n);
Matcher<int> m2 = MatcherCast<int>(m1);
- EXPECT_TRUE(m2.Matches(0));
- EXPECT_FALSE(m2.Matches(1));
+ int n1 = 0;
+ EXPECT_TRUE(m2.Matches(n));
+ EXPECT_FALSE(m2.Matches(n1));
+}
+
+// Tests that MatcherCast<T&>(m) works when m is a Matcher<const T&>.
+TEST(MatcherCastTest, FromConstReferenceToReference) {
+ int n = 0;
+ Matcher<const int&> m1 = Ref(n);
+ Matcher<int&> m2 = MatcherCast<int&>(m1);
+ int n1 = 0;
+ EXPECT_TRUE(m2.Matches(n));
+ EXPECT_FALSE(m2.Matches(n1));
}
// Tests that MatcherCast<T>(m) works when m is a Matcher<T&>.
@@ -445,6 +483,12 @@ TEST(MatcherCastTest, FromReferenceToNonReference) {
Matcher<int> m2 = MatcherCast<int>(m1);
EXPECT_TRUE(m2.Matches(0));
EXPECT_FALSE(m2.Matches(1));
+
+ // Of course, reference identity isn't preserved since a copy is required.
+ int n = 0;
+ Matcher<int&> m3 = Ref(n);
+ Matcher<int> m4 = MatcherCast<int>(m3);
+ EXPECT_FALSE(m4.Matches(n));
}
// Tests that MatcherCast<const T&>(m) works when m is a Matcher<T>.
@@ -649,6 +693,16 @@ TEST(SafeMatcherCastTest, FromBaseClass) {
EXPECT_FALSE(m4.Matches(d2));
}
+// Tests that SafeMatcherCast<T>(m) works when m is a Matcher<const T&>.
+TEST(SafeMatcherCastTest, FromConstReferenceToNonReference) {
+ int n = 0;
+ Matcher<const int&> m1 = Ref(n);
+ Matcher<int> m2 = SafeMatcherCast<int>(m1);
+ int n1 = 0;
+ EXPECT_TRUE(m2.Matches(n));
+ EXPECT_FALSE(m2.Matches(n1));
+}
+
// Tests that SafeMatcherCast<T&>(m) works when m is a Matcher<const T&>.
TEST(SafeMatcherCastTest, FromConstReferenceToReference) {
int n = 0;
diff --git a/googlemock/test/gmock-matchers-misc_test.cc b/googlemock/test/gmock-matchers-misc_test.cc
index ac976dd..de8b76c 100644
--- a/googlemock/test/gmock-matchers-misc_test.cc
+++ b/googlemock/test/gmock-matchers-misc_test.cc
@@ -32,6 +32,7 @@
// This file tests some commonly used argument matchers.
#include <array>
+#include <cstdint>
#include <memory>
#include <ostream>
#include <string>
@@ -747,6 +748,24 @@ TYPED_TEST(OptionalTest, DoesNotMatchNullopt) {
EXPECT_FALSE(m.Matches(empty));
}
+TYPED_TEST(OptionalTest, ComposesWithMonomorphicMatchersTakingReferences) {
+ const Matcher<const int&> eq1 = Eq(1);
+ const Matcher<const int&> eq2 = Eq(2);
+ TypeParam opt(1);
+ EXPECT_THAT(opt, Optional(eq1));
+ EXPECT_THAT(opt, Optional(Not(eq2)));
+ EXPECT_THAT(opt, Optional(AllOf(eq1, Not(eq2))));
+}
+
+TYPED_TEST(OptionalTest, ComposesWithMonomorphicMatchersRequiringConversion) {
+ const Matcher<int64_t> eq1 = Eq(1);
+ const Matcher<int64_t> eq2 = Eq(2);
+ TypeParam opt(1);
+ EXPECT_THAT(opt, Optional(eq1));
+ EXPECT_THAT(opt, Optional(Not(eq2)));
+ EXPECT_THAT(opt, Optional(AllOf(eq1, Not(eq2))));
+}
+
template <typename T>
class MoveOnlyOptionalTest : public testing::Test {};