diff --git a/googlemock/include/gmock/gmock-spec-builders.h b/googlemock/include/gmock/gmock-spec-builders.h index 60636f0c..fd12a067 100644 --- a/googlemock/include/gmock/gmock-spec-builders.h +++ b/googlemock/include/gmock/gmock-spec-builders.h @@ -132,9 +132,6 @@ class NaggyMockImpl; // calls to ensure the integrity of the mock objects' states. GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_gmock_mutex); -// Untyped base class for ActionResultHolder. -class UntypedActionResultHolderBase; - // Abstract base class of FunctionMocker. This is the // type-agnostic part of the function mocker interface. Its pure // virtual methods are implemented by FunctionMocker. @@ -157,20 +154,6 @@ class GTEST_API_ UntypedFunctionMockerBase { // responsibility to guarantee the correctness of the arguments' // types. - // Performs the default action with the given arguments and returns - // the action's result. The call description string will be used in - // the error message to describe the call in the case the default - // action fails. - // L = * - virtual UntypedActionResultHolderBase* UntypedPerformDefaultAction( - void* untyped_args, const std::string& call_description) const = 0; - - // Performs the given action with the given arguments and returns - // the action's result. - // L = * - virtual UntypedActionResultHolderBase* UntypedPerformAction( - const void* untyped_action, void* untyped_args) const = 0; - // Writes a message that the call is uninteresting (i.e. neither // explicitly expected nor explicitly unexpected) to the given // ostream. @@ -214,13 +197,6 @@ class GTEST_API_ UntypedFunctionMockerBase { // SetOwnerAndName() has been called. const char* Name() const GTEST_LOCK_EXCLUDED_(g_gmock_mutex); - // Returns the result of invoking this mock function with the given - // arguments. This function can be safely called from multiple - // threads concurrently. The caller is responsible for deleting the - // result. - UntypedActionResultHolderBase* UntypedInvokeWith(void* untyped_args) - GTEST_LOCK_EXCLUDED_(g_gmock_mutex); - protected: typedef std::vector UntypedOnCallSpecs; @@ -1368,104 +1344,28 @@ class ReferenceOrValueWrapper { T* value_ptr_; }; -// C++ treats the void type specially. For example, you cannot define -// a void-typed variable or pass a void value to a function. -// ActionResultHolder holds a value of type T, where T must be a -// copyable type or void (T doesn't need to be default-constructable). -// It hides the syntactic difference between void and other types, and -// is used to unify the code for invoking both void-returning and -// non-void-returning mock functions. - -// Untyped base class for ActionResultHolder. -class UntypedActionResultHolderBase { - public: - virtual ~UntypedActionResultHolderBase() {} - - // Prints the held value as an action's result to os. - virtual void PrintAsActionResult(::std::ostream* os) const = 0; -}; - -// This generic definition is used when T is not void. +// Prints the held value as an action's result to os. template -class ActionResultHolder : public UntypedActionResultHolderBase { - public: - // Returns the held value. Must not be called more than once. - T Unwrap() { return result_.Unwrap(); } - - // Prints the held value as an action's result to os. - void PrintAsActionResult(::std::ostream* os) const override { - *os << "\n Returns: "; - // T may be a reference type, so we don't use UniversalPrint(). - UniversalPrinter::Print(result_.Peek(), os); - } - - // Performs the given mock function's default action and returns the - // result in a new-ed ActionResultHolder. - template - static ActionResultHolder* PerformDefaultAction( - const FunctionMocker* func_mocker, - typename Function::ArgumentTuple&& args, - const std::string& call_description) { - return new ActionResultHolder(Wrapper( - func_mocker->PerformDefaultAction(std::move(args), call_description))); - } - - // Performs the given action and returns the result in a new-ed - // ActionResultHolder. - template - static ActionResultHolder* PerformAction( - const Action& action, typename Function::ArgumentTuple&& args) { - return new ActionResultHolder(Wrapper(action.Perform(std::move(args)))); - } - - private: - typedef ReferenceOrValueWrapper Wrapper; - - explicit ActionResultHolder(Wrapper result) : result_(std::move(result)) {} - - Wrapper result_; - - ActionResultHolder(const ActionResultHolder&) = delete; - ActionResultHolder& operator=(const ActionResultHolder&) = delete; -}; - -// Specialization for T = void. -template <> -class ActionResultHolder : public UntypedActionResultHolderBase { - public: - void Unwrap() {} - - void PrintAsActionResult(::std::ostream* /* os */) const override {} - - // Performs the given mock function's default action and returns ownership - // of an empty ActionResultHolder*. - template - static ActionResultHolder* PerformDefaultAction( - const FunctionMocker* func_mocker, - typename Function::ArgumentTuple&& args, - const std::string& call_description) { - func_mocker->PerformDefaultAction(std::move(args), call_description); - return new ActionResultHolder; - } - - // Performs the given action and returns ownership of an empty - // ActionResultHolder*. - template - static ActionResultHolder* PerformAction( - const Action& action, typename Function::ArgumentTuple&& args) { - action.Perform(std::move(args)); - return new ActionResultHolder; - } - - private: - ActionResultHolder() {} - ActionResultHolder(const ActionResultHolder&) = delete; - ActionResultHolder& operator=(const ActionResultHolder&) = delete; -}; +void PrintAsActionResult(const T& result, std::ostream& os) { + os << "\n Returns: "; + // T may be a reference type, so we don't use UniversalPrint(). + UniversalPrinter::Print(result, &os); +} // Reports an uninteresting call (whose description is in msg) in the // manner specified by 'reaction'. -void ReportUninterestingCall(CallReaction reaction, const std::string& msg); +GTEST_API_ void ReportUninterestingCall(CallReaction reaction, + const std::string& msg); + +// A generic RAII type that runs a user-provided function in its destructor. +class Cleanup final { + public: + explicit Cleanup(std::function f) : f_(std::move(f)) {} + ~Cleanup() { f_(); } + + private: + std::function f_; +}; template class FunctionMocker; @@ -1547,32 +1447,6 @@ class FunctionMocker final : public UntypedFunctionMockerBase { return DefaultValue::Get(); } - // Performs the default action with the given arguments and returns - // the action's result. The call description string will be used in - // the error message to describe the call in the case the default - // action fails. The caller is responsible for deleting the result. - // L = * - UntypedActionResultHolderBase* UntypedPerformDefaultAction( - void* untyped_args, // must point to an ArgumentTuple - const std::string& call_description) const override { - ArgumentTuple* args = static_cast(untyped_args); - return ResultHolder::PerformDefaultAction(this, std::move(*args), - call_description); - } - - // Performs the given action with the given arguments and returns - // the action's result. The caller is responsible for deleting the - // result. - // L = * - UntypedActionResultHolderBase* UntypedPerformAction( - const void* untyped_action, void* untyped_args) const override { - // Make a copy of the action before performing it, in case the - // action deletes the mock object (and thus deletes itself). - const Action action = *static_cast*>(untyped_action); - ArgumentTuple* args = static_cast(untyped_args); - return ResultHolder::PerformAction(action, std::move(*args)); - } - // Implements UntypedFunctionMockerBase::ClearDefaultActionsLocked(): // clears the ON_CALL()s set on this mock function. void ClearDefaultActionsLocked() override @@ -1604,10 +1478,7 @@ class FunctionMocker final : public UntypedFunctionMockerBase { // arguments. This function can be safely called from multiple // threads concurrently. Result Invoke(Args... args) GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { - ArgumentTuple tuple(std::forward(args)...); - std::unique_ptr holder(DownCast_( - this->UntypedInvokeWith(static_cast(&tuple)))); - return holder->Unwrap(); + return InvokeWith(ArgumentTuple(std::forward(args)...)); } MockSpec With(Matcher... m) { @@ -1618,8 +1489,6 @@ class FunctionMocker final : public UntypedFunctionMockerBase { template friend class MockSpec; - typedef ActionResultHolder ResultHolder; - // Adds and returns a default action spec for this mock function. OnCallSpec& AddNewOnCallSpec(const char* file, int line, const ArgumentMatcherTuple& m) @@ -1790,13 +1659,73 @@ class FunctionMocker final : public UntypedFunctionMockerBase { expectation->DescribeCallCountTo(why); } } + + // Performs the given action (or the default if it's null) with the given + // arguments and returns the action's result. + // L = * + R PerformAction(const void* untyped_action, ArgumentTuple&& args, + const std::string& call_description) const { + if (untyped_action == nullptr) { + return PerformDefaultAction(std::move(args), call_description); + } + + // Make a copy of the action before performing it, in case the + // action deletes the mock object (and thus deletes itself). + const Action action = *static_cast*>(untyped_action); + return action.Perform(std::move(args)); + } + + // Is it possible to store an object of the supplied type in a local variable + // for the sake of printing it, then return it on to the caller? + template + using can_print_result = internal::conjunction< + // void can't be stored as an object (and we also don't need to print it). + internal::negation>, + // Non-moveable types can't be returned on to the user, so there's no way + // for us to intercept and print them. + std::is_move_constructible>; + + // Perform the supplied action, printing the result to os. + template ::value, int>::type = 0> + R PerformActionAndPrintResult(const void* const untyped_action, + ArgumentTuple&& args, + const std::string& call_description, + std::ostream& os) { + R result = PerformAction(untyped_action, std::move(args), call_description); + + PrintAsActionResult(result, os); + return std::forward(result); + } + + // Disable warnings about an unused parameter (due to SFINAE choosing an + // overload that doesn't use it). + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4100); + + // An overload for when it's not possible to print the result. In this case we + // simply perform the action. + template >::value, int>::type = 0> + R PerformActionAndPrintResult(const void* const untyped_action, + ArgumentTuple&& args, + const std::string& call_description, + std::ostream& os) { + return PerformAction(untyped_action, std::move(args), call_description); + } + + GTEST_DISABLE_MSC_WARNINGS_POP_(); + + // Returns the result of invoking this mock function with the given + // arguments. This function can be safely called from multiple + // threads concurrently. + R InvokeWith(ArgumentTuple&& args) GTEST_LOCK_EXCLUDED_(g_gmock_mutex); }; // class FunctionMocker // Calculates the result of invoking this mock function with the given -// arguments, prints it, and returns it. The caller is responsible -// for deleting the result. -inline UntypedActionResultHolderBase* -UntypedFunctionMockerBase::UntypedInvokeWith(void* const untyped_args) +// arguments, prints it, and returns it. +template +R FunctionMocker::InvokeWith(ArgumentTuple&& args) GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { // See the definition of untyped_expectations_ for why access to it // is unprotected here. @@ -1829,23 +1758,23 @@ UntypedFunctionMockerBase::UntypedInvokeWith(void* const untyped_args) if (!need_to_report_uninteresting_call) { // Perform the action without printing the call information. - return this->UntypedPerformDefaultAction( - untyped_args, "Function call: " + std::string(Name())); + return this->PerformDefaultAction( + std::move(args), "Function call: " + std::string(Name())); } // Warns about the uninteresting call. ::std::stringstream ss; - this->UntypedDescribeUninterestingCall(untyped_args, &ss); + this->UntypedDescribeUninterestingCall(&args, &ss); - // Calculates the function result. - UntypedActionResultHolderBase* const result = - this->UntypedPerformDefaultAction(untyped_args, ss.str()); + // Perform the action, print the result, and then report the uninteresting + // call. + // + // We use RAII to do the latter in case R is void or a non-moveable type. In + // either case we can't assign it to a local variable. + const Cleanup report_uninteresting_call( + [&] { ReportUninterestingCall(reaction, ss.str()); }); - // Prints the function result. - if (result != nullptr) result->PrintAsActionResult(&ss); - - ReportUninterestingCall(reaction, ss.str()); - return result; + return PerformActionAndPrintResult(nullptr, std::move(args), ss.str(), ss); } bool is_excessive = false; @@ -1858,7 +1787,7 @@ UntypedFunctionMockerBase::UntypedInvokeWith(void* const untyped_args) // releases g_gmock_mutex. const ExpectationBase* const untyped_expectation = - this->UntypedFindMatchingExpectation(untyped_args, &untyped_action, + this->UntypedFindMatchingExpectation(&args, &untyped_action, &is_excessive, &ss, &why); const bool found = untyped_expectation != nullptr; @@ -1870,13 +1799,11 @@ UntypedFunctionMockerBase::UntypedInvokeWith(void* const untyped_args) !found || is_excessive || LogIsVisible(kInfo); if (!need_to_report_call) { // Perform the action without printing the call information. - return untyped_action == nullptr - ? this->UntypedPerformDefaultAction(untyped_args, "") - : this->UntypedPerformAction(untyped_action, untyped_args); + return PerformAction(untyped_action, std::move(args), ""); } ss << " Function call: " << Name(); - this->UntypedPrintArgs(untyped_args, &ss); + this->UntypedPrintArgs(&args, &ss); // In case the action deletes a piece of the expectation, we // generate the message beforehand. @@ -1884,14 +1811,12 @@ UntypedFunctionMockerBase::UntypedInvokeWith(void* const untyped_args) untyped_expectation->DescribeLocationTo(&loc); } - UntypedActionResultHolderBase* result = nullptr; - - auto perform_action = [&] { - return untyped_action == nullptr - ? this->UntypedPerformDefaultAction(untyped_args, ss.str()) - : this->UntypedPerformAction(untyped_action, untyped_args); - }; - auto handle_failures = [&] { + // Perform the action, print the result, and then fail or log in whatever way + // is appropriate. + // + // We use RAII to do the latter in case R is void or a non-moveable type. In + // either case we can't assign it to a local variable. + const Cleanup handle_failures([&] { ss << "\n" << why.str(); if (!found) { @@ -1906,21 +1831,10 @@ UntypedFunctionMockerBase::UntypedInvokeWith(void* const untyped_args) // described in ss. Log(kInfo, loc.str() + ss.str(), 2); } - }; -#if GTEST_HAS_EXCEPTIONS - try { - result = perform_action(); - } catch (...) { - handle_failures(); - throw; - } -#else - result = perform_action(); -#endif + }); - if (result != nullptr) result->PrintAsActionResult(&ss); - handle_failures(); - return result; + return PerformActionAndPrintResult(untyped_action, std::move(args), ss.str(), + ss); } } // namespace internal diff --git a/googlemock/test/gmock-spec-builders_test.cc b/googlemock/test/gmock-spec-builders_test.cc index d32fb420..122d5b94 100644 --- a/googlemock/test/gmock-spec-builders_test.cc +++ b/googlemock/test/gmock-spec-builders_test.cc @@ -37,6 +37,7 @@ #include // NOLINT #include #include +#include #include "gmock/gmock.h" #include "gmock/internal/gmock-port.h" @@ -45,63 +46,19 @@ #include "gtest/internal/gtest-port.h" namespace testing { -namespace internal { - -// Helper class for testing the Expectation class template. -class ExpectationTester { - public: - // Sets the call count of the given expectation to the given number. - void SetCallCount(int n, ExpectationBase* exp) { exp->call_count_ = n; } -}; - -} // namespace internal -} // namespace testing - namespace { -using testing::_; -using testing::AnyNumber; -using testing::AtLeast; -using testing::AtMost; -using testing::Between; -using testing::Cardinality; -using testing::CardinalityInterface; -using testing::Const; -using testing::ContainsRegex; -using testing::DoAll; -using testing::DoDefault; -using testing::Eq; -using testing::Expectation; -using testing::ExpectationSet; -using testing::Gt; -using testing::IgnoreResult; -using testing::InSequence; -using testing::Invoke; -using testing::InvokeWithoutArgs; -using testing::IsNotSubstring; -using testing::IsSubstring; -using testing::Lt; -using testing::Message; -using testing::Mock; -using testing::NaggyMock; -using testing::Ne; -using testing::Return; -using testing::SaveArg; -using testing::Sequence; -using testing::SetArgPointee; -using testing::internal::ExpectationTester; -using testing::internal::FormatFileLocation; -using testing::internal::kAllow; -using testing::internal::kErrorVerbosity; -using testing::internal::kFail; -using testing::internal::kInfoVerbosity; -using testing::internal::kWarn; -using testing::internal::kWarningVerbosity; +using ::testing::internal::FormatFileLocation; +using ::testing::internal::kAllow; +using ::testing::internal::kErrorVerbosity; +using ::testing::internal::kFail; +using ::testing::internal::kInfoVerbosity; +using ::testing::internal::kWarn; +using ::testing::internal::kWarningVerbosity; #if GTEST_HAS_STREAM_REDIRECTION -using testing::HasSubstr; -using testing::internal::CaptureStdout; -using testing::internal::GetCapturedStdout; +using ::testing::internal::CaptureStdout; +using ::testing::internal::GetCapturedStdout; #endif class Incomplete; @@ -846,6 +803,50 @@ TEST(ExpectCallTest, InfersCardinality1WhenThereIsWillRepeatedly) { "to be called at least once"); } +#if defined(__cplusplus) && __cplusplus >= 201703L + +// It should be possible to return a non-moveable type from a mock action in +// C++17 and above, where it's guaranteed that such a type can be initialized +// from a prvalue returned from a function. +TEST(ExpectCallTest, NonMoveableType) { + // Define a non-moveable result type. + struct Result { + explicit Result(int x_in) : x(x_in) {} + Result(Result&&) = delete; + + int x; + }; + + static_assert(!std::is_move_constructible_v); + static_assert(!std::is_copy_constructible_v); + + static_assert(!std::is_move_assignable_v); + static_assert(!std::is_copy_assignable_v); + + // We should be able to use a callable that returns that result as both a + // OnceAction and an Action, whether the callable ignores arguments or not. + const auto return_17 = [] { return Result(17); }; + + static_cast(OnceAction{return_17}); + static_cast(Action{return_17}); + + static_cast(OnceAction{return_17}); + static_cast(Action{return_17}); + + // It should be possible to return the result end to end through an + // EXPECT_CALL statement, with both WillOnce and WillRepeatedly. + MockFunction mock; + EXPECT_CALL(mock, Call) // + .WillOnce(return_17) // + .WillRepeatedly(return_17); + + EXPECT_EQ(17, mock.AsStdFunction()().x); + EXPECT_EQ(17, mock.AsStdFunction()().x); + EXPECT_EQ(17, mock.AsStdFunction()().x); +} + +#endif // C++17 and above + // Tests that the n-th action is taken for the n-th matching // invocation. TEST(ExpectCallTest, NthMatchTakesNthAction) { @@ -2596,6 +2597,7 @@ TEST(ParameterlessExpectationsTest, } } // namespace +} // namespace testing // Allows the user to define their own main and then invoke gmock_main // from it. This might be necessary on some platforms which require