Add support for move-only and &&-qualified actions in WillOnce.

This provides a type-safe way for an action to express that it wants to be
called only once, or to capture move-only objects. It is a generalization of
the type system-evading hack in ByMove, with the improvement that it works for
_any_ action (including user-defined ones), and correctly expresses that the
action can only be used with WillOnce. I'll make existing actions benefit in a
future commit.

PiperOrigin-RevId: 440496139
Change-Id: I4145d191cca5655995ef41360bb126c123cb41d3
This commit is contained in:
Abseil Team
2022-04-08 18:39:39 -07:00
committed by Copybara-Service
parent 5f467ec04d
commit a1cc8c5519
4 changed files with 584 additions and 35 deletions

View File

@@ -55,37 +55,170 @@
#include "gtest/gtest-spi.h"
#include "gtest/gtest.h"
namespace testing {
namespace {
using ::testing::_;
using ::testing::Action;
using ::testing::ActionInterface;
using ::testing::Assign;
using ::testing::ByMove;
using ::testing::ByRef;
using ::testing::DefaultValue;
using ::testing::DoAll;
using ::testing::DoDefault;
using ::testing::IgnoreResult;
using ::testing::Invoke;
using ::testing::InvokeWithoutArgs;
using ::testing::MakePolymorphicAction;
using ::testing::PolymorphicAction;
using ::testing::Return;
using ::testing::ReturnNew;
using ::testing::ReturnNull;
using ::testing::ReturnRef;
using ::testing::ReturnRefOfCopy;
using ::testing::ReturnRoundRobin;
using ::testing::SetArgPointee;
using ::testing::SetArgumentPointee;
using ::testing::Unused;
using ::testing::WithArgs;
using ::testing::internal::BuiltInDefaultValue;
#if !GTEST_OS_WINDOWS_MOBILE
using ::testing::SetErrnoAndReturn;
#endif
TEST(TypeTraits, Negation) {
// Direct use with std types.
static_assert(std::is_base_of<std::false_type,
internal::negation<std::true_type>>::value,
"");
static_assert(std::is_base_of<std::true_type,
internal::negation<std::false_type>>::value,
"");
// With other types that fit the requirement of a value member that is
// convertible to bool.
static_assert(std::is_base_of<
std::true_type,
internal::negation<std::integral_constant<int, 0>>>::value,
"");
static_assert(std::is_base_of<
std::false_type,
internal::negation<std::integral_constant<int, 1>>>::value,
"");
static_assert(std::is_base_of<
std::false_type,
internal::negation<std::integral_constant<int, -1>>>::value,
"");
}
// Weird false/true types that aren't actually bool constants (but should still
// be legal according to [meta.logical] because `bool(T::value)` is valid), are
// distinct from std::false_type and std::true_type, and are distinct from other
// instantiations of the same template.
//
// These let us check finicky details mandated by the standard like
// "std::conjunction should evaluate to a type that inherits from the first
// false-y input".
template <int>
struct MyFalse : std::integral_constant<int, 0> {};
template <int>
struct MyTrue : std::integral_constant<int, -1> {};
TEST(TypeTraits, Conjunction) {
// Base case: always true.
static_assert(std::is_base_of<std::true_type, internal::conjunction<>>::value,
"");
// One predicate: inherits from that predicate, regardless of value.
static_assert(
std::is_base_of<MyFalse<0>, internal::conjunction<MyFalse<0>>>::value,
"");
static_assert(
std::is_base_of<MyTrue<0>, internal::conjunction<MyTrue<0>>>::value, "");
// Multiple predicates, with at least one false: inherits from that one.
static_assert(
std::is_base_of<MyFalse<1>, internal::conjunction<MyTrue<0>, MyFalse<1>,
MyTrue<2>>>::value,
"");
static_assert(
std::is_base_of<MyFalse<1>, internal::conjunction<MyTrue<0>, MyFalse<1>,
MyFalse<2>>>::value,
"");
// Short circuiting: in the case above, additional predicates need not even
// define a value member.
struct Empty {};
static_assert(
std::is_base_of<MyFalse<1>, internal::conjunction<MyTrue<0>, MyFalse<1>,
Empty>>::value,
"");
// All predicates true: inherits from the last.
static_assert(
std::is_base_of<MyTrue<2>, internal::conjunction<MyTrue<0>, MyTrue<1>,
MyTrue<2>>>::value,
"");
}
TEST(TypeTraits, Disjunction) {
// Base case: always false.
static_assert(
std::is_base_of<std::false_type, internal::disjunction<>>::value, "");
// One predicate: inherits from that predicate, regardless of value.
static_assert(
std::is_base_of<MyFalse<0>, internal::disjunction<MyFalse<0>>>::value,
"");
static_assert(
std::is_base_of<MyTrue<0>, internal::disjunction<MyTrue<0>>>::value, "");
// Multiple predicates, with at least one true: inherits from that one.
static_assert(
std::is_base_of<MyTrue<1>, internal::disjunction<MyFalse<0>, MyTrue<1>,
MyFalse<2>>>::value,
"");
static_assert(
std::is_base_of<MyTrue<1>, internal::disjunction<MyFalse<0>, MyTrue<1>,
MyTrue<2>>>::value,
"");
// Short circuiting: in the case above, additional predicates need not even
// define a value member.
struct Empty {};
static_assert(
std::is_base_of<MyTrue<1>, internal::disjunction<MyFalse<0>, MyTrue<1>,
Empty>>::value,
"");
// All predicates false: inherits from the last.
static_assert(
std::is_base_of<MyFalse<2>, internal::disjunction<MyFalse<0>, MyFalse<1>,
MyFalse<2>>>::value,
"");
}
TEST(TypeTraits, IsInvocableRV) {
struct C {
int operator()() const { return 0; }
void operator()(int) & {}
std::string operator()(int) && { return ""; };
};
// The first overload is callable for const and non-const rvalues and lvalues.
// It can be used to obtain an int, void, or anything int is convertible too.
static_assert(internal::is_callable_r<int, C>::value, "");
static_assert(internal::is_callable_r<int, C&>::value, "");
static_assert(internal::is_callable_r<int, const C>::value, "");
static_assert(internal::is_callable_r<int, const C&>::value, "");
static_assert(internal::is_callable_r<void, C>::value, "");
static_assert(internal::is_callable_r<char, C>::value, "");
// It's possible to provide an int. If it's given to an lvalue, the result is
// void. Otherwise it is std::string (which is also treated as allowed for a
// void result type).
static_assert(internal::is_callable_r<void, C&, int>::value, "");
static_assert(!internal::is_callable_r<int, C&, int>::value, "");
static_assert(!internal::is_callable_r<std::string, C&, int>::value, "");
static_assert(!internal::is_callable_r<void, const C&, int>::value, "");
static_assert(internal::is_callable_r<std::string, C, int>::value, "");
static_assert(internal::is_callable_r<void, C, int>::value, "");
static_assert(!internal::is_callable_r<int, C, int>::value, "");
// It's not possible to provide other arguments.
static_assert(!internal::is_callable_r<void, C, std::string>::value, "");
static_assert(!internal::is_callable_r<void, C, int, int>::value, "");
// Nothing should choke when we try to call other arguments besides directly
// callable objects, but they should not show up as callable.
static_assert(!internal::is_callable_r<void, int>::value, "");
static_assert(!internal::is_callable_r<void, void (C::*)()>::value, "");
static_assert(!internal::is_callable_r<void, void (C::*)(), C*>::value, "");
}
// Tests that BuiltInDefaultValue<T*>::Get() returns NULL.
TEST(BuiltInDefaultValueTest, IsNullForPointerTypes) {
@@ -1428,6 +1561,154 @@ TEST(MockMethodTest, CanTakeMoveOnlyValue) {
EXPECT_EQ(42, *saved);
}
// It should be possible to use callables with an &&-qualified call operator
// with WillOnce, since they will be called only once. This allows actions to
// contain and manipulate move-only types.
TEST(MockMethodTest, ActionHasRvalueRefQualifiedCallOperator) {
struct Return17 {
int operator()() && { return 17; }
};
// Action is directly compatible with mocked function type.
{
MockFunction<int()> mock;
EXPECT_CALL(mock, Call).WillOnce(Return17());
EXPECT_EQ(17, mock.AsStdFunction()());
}
// Action doesn't want mocked function arguments.
{
MockFunction<int(int)> mock;
EXPECT_CALL(mock, Call).WillOnce(Return17());
EXPECT_EQ(17, mock.AsStdFunction()(0));
}
}
// Edge case: if an action has both a const-qualified and an &&-qualified call
// operator, there should be no "ambiguous call" errors. The &&-qualified
// operator should be used by WillOnce (since it doesn't need to retain the
// action beyond one call), and the const-qualified one by WillRepeatedly.
TEST(MockMethodTest, ActionHasMultipleCallOperators) {
struct ReturnInt {
int operator()() && { return 17; }
int operator()() const& { return 19; }
};
// Directly compatible with mocked function type.
{
MockFunction<int()> mock;
EXPECT_CALL(mock, Call).WillOnce(ReturnInt()).WillRepeatedly(ReturnInt());
EXPECT_EQ(17, mock.AsStdFunction()());
EXPECT_EQ(19, mock.AsStdFunction()());
EXPECT_EQ(19, mock.AsStdFunction()());
}
// Ignores function arguments.
{
MockFunction<int(int)> mock;
EXPECT_CALL(mock, Call).WillOnce(ReturnInt()).WillRepeatedly(ReturnInt());
EXPECT_EQ(17, mock.AsStdFunction()(0));
EXPECT_EQ(19, mock.AsStdFunction()(0));
EXPECT_EQ(19, mock.AsStdFunction()(0));
}
}
// WillOnce should have no problem coping with a move-only action, whether it is
// &&-qualified or not.
TEST(MockMethodTest, MoveOnlyAction) {
// &&-qualified
{
struct Return17 {
Return17() = default;
Return17(Return17&&) = default;
Return17(const Return17&) = delete;
Return17 operator=(const Return17&) = delete;
int operator()() && { return 17; }
};
MockFunction<int()> mock;
EXPECT_CALL(mock, Call).WillOnce(Return17());
EXPECT_EQ(17, mock.AsStdFunction()());
}
// Not &&-qualified
{
struct Return17 {
Return17() = default;
Return17(Return17&&) = default;
Return17(const Return17&) = delete;
Return17 operator=(const Return17&) = delete;
int operator()() const { return 17; }
};
MockFunction<int()> mock;
EXPECT_CALL(mock, Call).WillOnce(Return17());
EXPECT_EQ(17, mock.AsStdFunction()());
}
}
// It should be possible to use an action that returns a value with a mock
// function that doesn't, both through WillOnce and WillRepeatedly.
TEST(MockMethodTest, ActionReturnsIgnoredValue) {
struct ReturnInt {
int operator()() const { return 0; }
};
MockFunction<void()> mock;
EXPECT_CALL(mock, Call).WillOnce(ReturnInt()).WillRepeatedly(ReturnInt());
mock.AsStdFunction()();
mock.AsStdFunction()();
}
// Despite the fanciness around move-only actions and so on, it should still be
// possible to hand an lvalue reference to a copyable action to WillOnce.
TEST(MockMethodTest, WillOnceCanAcceptLvalueReference) {
MockFunction<int()> mock;
const auto action = [] { return 17; };
EXPECT_CALL(mock, Call).WillOnce(action);
EXPECT_EQ(17, mock.AsStdFunction()());
}
// A callable that doesn't use SFINAE to restrict its call operator's overload
// set, but is still picky about which arguments it will accept.
struct StaticAssertSingleArgument {
template <typename... Args>
static constexpr bool CheckArgs() {
static_assert(sizeof...(Args) == 1, "");
return true;
}
template <typename... Args, bool = CheckArgs<Args...>()>
int operator()(Args...) const {
return 17;
}
};
// WillOnce and WillRepeatedly should both work fine with naïve implementations
// of actions that don't use SFINAE to limit the overload set for their call
// operator. If they are compatible with the actual mocked signature, we
// shouldn't probe them with no arguments and trip a static_assert.
TEST(MockMethodTest, ActionSwallowsAllArguments) {
MockFunction<int(int)> mock;
EXPECT_CALL(mock, Call)
.WillOnce(StaticAssertSingleArgument{})
.WillRepeatedly(StaticAssertSingleArgument{});
EXPECT_EQ(17, mock.AsStdFunction()(0));
EXPECT_EQ(17, mock.AsStdFunction()(0));
}
// Tests for std::function based action.
int Add(int val, int& ref, int* ptr) { // NOLINT
@@ -1552,7 +1833,8 @@ TEST(ActionMacro, LargeArity) {
14, 15, 16, 17, 18, 19)));
}
} // Unnamed namespace
} // namespace
} // namespace testing
#ifdef _MSC_VER
#if _MSC_VER == 1900