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:
committed by
Copybara-Service
parent
5f467ec04d
commit
a1cc8c5519
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user