Skip to content

Commit 5126f71

Browse files
jacobsacopybara-github
authored andcommitted
gmock-actions: add support for move-only values to Return.
`Return(x)` can now be used directly with `WillOnce` (the only place it makes sense in the type system), without using `ByMove`. PiperOrigin-RevId: 448380066 Change-Id: Ia71cc60ccbc3b99720662731a2d309735a5ce7c8
1 parent 8a011b8 commit 5126f71

File tree

2 files changed

+83
-29
lines changed

2 files changed

+83
-29
lines changed

googlemock/include/gmock/gmock-actions.h

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,17 @@ class ReturnAction final {
878878
public:
879879
explicit ReturnAction(R value) : value_(std::move(value)) {}
880880

881+
template <typename U, typename... Args,
882+
typename = typename std::enable_if<conjunction<
883+
// See the requirements documented on Return.
884+
negation<std::is_same<void, U>>, //
885+
negation<std::is_reference<U>>, //
886+
std::is_convertible<R, U>, //
887+
std::is_move_constructible<U>>::value>::type>
888+
operator OnceAction<U(Args...)>() && { // NOLINT
889+
return Impl<U>(std::move(value_));
890+
}
891+
881892
template <typename U, typename... Args,
882893
typename = typename std::enable_if<conjunction<
883894
// See the requirements documented on Return.
@@ -894,9 +905,17 @@ class ReturnAction final {
894905
template <typename U>
895906
class Impl final {
896907
public:
908+
// The constructor used when the return value is allowed to move from the
909+
// input value (i.e. we are converting to OnceAction).
910+
explicit Impl(R&& input_value)
911+
: state_(new State(std::move(input_value))) {}
912+
913+
// The constructor used when the return value is not allowed to move from
914+
// the input value (i.e. we are converting to Action).
897915
explicit Impl(const R& input_value) : state_(new State(input_value)) {}
898916

899-
U operator()() const { return state_->value; }
917+
U operator()() && { return std::move(state_->value); }
918+
U operator()() const& { return state_->value; }
900919

901920
private:
902921
// We put our state on the heap so that the compiler-generated copy/move
@@ -923,6 +942,18 @@ class ReturnAction final {
923942
// explicit constructor from R.
924943
value(ImplicitCast_<U>(internal::as_const(input_value))) {}
925944

945+
// As above, but for the case where we're moving from the ReturnAction
946+
// object because it's being used as a OnceAction.
947+
explicit State(R&& input_value_in)
948+
: input_value(std::move(input_value_in)),
949+
// For the same reason as above we make an implicit conversion to U
950+
// before initializing the value.
951+
//
952+
// Unlike above we provide the input value as an rvalue to the
953+
// implicit conversion because this is a OnceAction: it's fine if it
954+
// wants to consume the input value.
955+
value(ImplicitCast_<U>(std::move(input_value))) {}
956+
926957
// A copy of the value originally provided by the user. We retain this in
927958
// addition to the value of the mock function's result type below in case
928959
// the latter is a reference-like type. See the std::string_view example
@@ -1740,18 +1771,19 @@ internal::WithArgsAction<typename std::decay<InnerAction>::type> WithoutArgs(
17401771

17411772
// Creates an action that returns a value.
17421773
//
1743-
// R must be copy-constructible. The returned type can be used as an
1744-
// Action<U(Args...)> for any type U where all of the following are true:
1774+
// The returned type can be used with a mock function returning a non-void,
1775+
// non-reference type U as follows:
17451776
//
1746-
// * U is not void.
1747-
// * U is not a reference type. (Use ReturnRef instead.)
1748-
// * U is copy-constructible.
1749-
// * const R& is convertible to U.
1777+
// * If R is convertible to U and U is move-constructible, then the action can
1778+
// be used with WillOnce.
17501779
//
1751-
// The Action<U(Args)...> object contains the R value from which the U return
1752-
// value is constructed (a copy of the argument to Return). This means that the
1753-
// R value will survive at least until the mock object's expectations are
1754-
// cleared or the mock object is destroyed, meaning that U can be a
1780+
// * If const R& is convertible to U and U is copy-constructible, then the
1781+
// action can be used with both WillOnce and WillRepeatedly.
1782+
//
1783+
// The mock expectation contains the R value from which the U return value is
1784+
// constructed (a move/copy of the argument to Return). This means that the R
1785+
// value will survive at least until the mock object's expectations are cleared
1786+
// or the mock object is destroyed, meaning that U can safely be a
17551787
// reference-like type such as std::string_view:
17561788
//
17571789
// // The mock function returns a view of a copy of the string fed to
@@ -1794,6 +1826,8 @@ inline internal::ReturnRefOfCopyAction<R> ReturnRefOfCopy(const R& x) {
17941826
return internal::ReturnRefOfCopyAction<R>(x);
17951827
}
17961828

1829+
// DEPRECATED: use Return(x) directly with WillOnce.
1830+
//
17971831
// Modifies the parent action (a Return() action) to perform a move of the
17981832
// argument instead of a copy.
17991833
// Return(ByMove()) actions can only be executed once and will assert this

googlemock/test/gmock-actions_test.cc

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include "gmock/gmock-actions.h"
4848

4949
#include <algorithm>
50+
#include <functional>
5051
#include <iterator>
5152
#include <memory>
5253
#include <string>
@@ -709,6 +710,24 @@ TEST(ReturnTest, PrefersConversionOperator) {
709710
EXPECT_THAT(mock.AsStdFunction()(), Field(&Out::x, 19));
710711
}
711712

713+
// It should be possible to use Return(R) with a mock function result type U
714+
// that is convertible from const R& but *not* R (such as
715+
// std::reference_wrapper). This should work for both WillOnce and
716+
// WillRepeatedly.
717+
TEST(ReturnTest, ConversionRequiresConstLvalueReference) {
718+
using R = int;
719+
using U = std::reference_wrapper<const int>;
720+
721+
static_assert(std::is_convertible<const R&, U>::value, "");
722+
static_assert(!std::is_convertible<R, U>::value, "");
723+
724+
MockFunction<U()> mock;
725+
EXPECT_CALL(mock, Call).WillOnce(Return(17)).WillRepeatedly(Return(19));
726+
727+
EXPECT_EQ(17, mock.AsStdFunction()());
728+
EXPECT_EQ(19, mock.AsStdFunction()());
729+
}
730+
712731
// Return(x) should not be usable with a mock function result type that's
713732
// implicitly convertible from decltype(x) but requires a non-const lvalue
714733
// reference to the input. It doesn't make sense for the conversion operator to
@@ -731,32 +750,33 @@ TEST(ReturnTest, ConversionRequiresMutableLvalueReference) {
731750

732751
// It shouldn't be possible to use the result of Return(std::string) in a
733752
// context where an S is needed.
753+
//
754+
// Here too we disable the assertion for MSVC, since its incorrect
755+
// implementation of is_convertible causes our SFINAE to be wrong.
734756
using RA = decltype(Return(std::string()));
735757

736758
static_assert(!std::is_convertible<RA, Action<S()>>::value, "");
759+
#ifndef _MSC_VER
737760
static_assert(!std::is_convertible<RA, OnceAction<S()>>::value, "");
761+
#endif
738762
}
739763

740-
// Return(x) should not be usable with a mock function result type that's
741-
// implicitly convertible from decltype(x) but requires an rvalue reference to
742-
// the input. We don't yet support handing over the value for consumption.
743-
TEST(ReturnTest, ConversionRequiresRvalueReference) {
744-
// Set up a type that is implicitly convertible from std::string&& and
745-
// `const std::string&&`, but not `const std::string&`.
746-
struct S {
747-
S(std::string&&) {} // NOLINT
748-
S(const std::string&&) {} // NOLINT
749-
};
750-
751-
static_assert(std::is_convertible<std::string, S>::value, "");
752-
static_assert(!std::is_convertible<const std::string&, S>::value, "");
764+
TEST(ReturnTest, MoveOnlyResultType) {
765+
// Return should support move-only result types when used with WillOnce.
766+
{
767+
MockFunction<std::unique_ptr<int>()> mock;
768+
EXPECT_CALL(mock, Call)
769+
// NOLINTNEXTLINE
770+
.WillOnce(Return(std::unique_ptr<int>(new int(17))));
753771

754-
// It shouldn't be possible to use the result of Return(std::string) in a
755-
// context where an S is needed.
756-
using RA = decltype(Return(std::string()));
772+
EXPECT_THAT(mock.AsStdFunction()(), Pointee(17));
773+
}
757774

758-
static_assert(!std::is_convertible<RA, Action<S()>>::value, "");
759-
static_assert(!std::is_convertible<RA, OnceAction<S()>>::value, "");
775+
// The result of Return should not be convertible to Action (so it can't be
776+
// used with WillRepeatedly).
777+
static_assert(!std::is_convertible<decltype(Return(std::unique_ptr<int>())),
778+
Action<std::unique_ptr<int>()>>::value,
779+
"");
760780
}
761781

762782
// Tests that Return(v) is covaraint.

0 commit comments

Comments
 (0)