diff options
author | Abseil Team <absl-team@google.com> | 2022-04-09 01:39:39 (GMT) |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2022-04-09 01:40:07 (GMT) |
commit | a1cc8c55195661a58ad60c3bb062a0b9c302710d (patch) | |
tree | 4a2dc2bc70e5cbcf086e8090796b4675958c518c /googlemock/test/gmock-actions_test.cc | |
parent | 5f467ec04df33024e3c6760fa403b5cd5d8e9ace (diff) | |
download | googletest-a1cc8c55195661a58ad60c3bb062a0b9c302710d.zip googletest-a1cc8c55195661a58ad60c3bb062a0b9c302710d.tar.gz googletest-a1cc8c55195661a58ad60c3bb062a0b9c302710d.tar.bz2 |
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
Diffstat (limited to 'googlemock/test/gmock-actions_test.cc')
-rw-r--r-- | googlemock/test/gmock-actions_test.cc | 338 |
1 files changed, 310 insertions, 28 deletions
diff --git a/googlemock/test/gmock-actions_test.cc b/googlemock/test/gmock-actions_test.cc index 233b60c..7ff5780 100644 --- a/googlemock/test/gmock-actions_test.cc +++ b/googlemock/test/gmock-actions_test.cc @@ -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 |