diff options
author | Aaron Jacobs <jacobsa@google.com> | 2022-05-26 14:24:44 (GMT) |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2022-05-26 14:25:17 (GMT) |
commit | 56246cdb94de94f7f43c9df59635db92c41d4064 (patch) | |
tree | 2ea59c6f23a8134b95845e23db16b5680d8da65f /googlemock/include/gmock | |
parent | cf942a5d69b0b59a69d17d8151890ca94ed57e07 (diff) | |
download | googletest-56246cdb94de94f7f43c9df59635db92c41d4064.zip googletest-56246cdb94de94f7f43c9df59635db92c41d4064.tar.gz googletest-56246cdb94de94f7f43c9df59635db92c41d4064.tar.bz2 |
gmock-spec-builders: move a method to the header.
In order to make the diff more readable in an upcoming commit that requires the
method to be templated on the action's result type.
PiperOrigin-RevId: 451157029
Change-Id: I57beb7544efccd0459efb3a1f039ea45cd7c7602
Diffstat (limited to 'googlemock/include/gmock')
-rw-r--r-- | googlemock/include/gmock/gmock-spec-builders.h | 137 |
1 files changed, 134 insertions, 3 deletions
diff --git a/googlemock/include/gmock/gmock-spec-builders.h b/googlemock/include/gmock/gmock-spec-builders.h index 835e518..60636f0 100644 --- a/googlemock/include/gmock/gmock-spec-builders.h +++ b/googlemock/include/gmock/gmock-spec-builders.h @@ -1463,6 +1463,10 @@ class ActionResultHolder<void> : public UntypedActionResultHolderBase { ActionResultHolder& operator=(const ActionResultHolder&) = delete; }; +// Reports an uninteresting call (whose description is in msg) in the +// manner specified by 'reaction'. +void ReportUninterestingCall(CallReaction reaction, const std::string& msg); + template <typename F> class FunctionMocker; @@ -1788,9 +1792,136 @@ class FunctionMocker<R(Args...)> final : public UntypedFunctionMockerBase { } }; // class FunctionMocker -// Reports an uninteresting call (whose description is in msg) in the -// manner specified by 'reaction'. -void ReportUninterestingCall(CallReaction reaction, const std::string& msg); +// 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) + GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { + // See the definition of untyped_expectations_ for why access to it + // is unprotected here. + if (untyped_expectations_.size() == 0) { + // No expectation is set on this mock method - we have an + // uninteresting call. + + // We must get Google Mock's reaction on uninteresting calls + // made on this mock object BEFORE performing the action, + // because the action may DELETE the mock object and make the + // following expression meaningless. + const CallReaction reaction = + Mock::GetReactionOnUninterestingCalls(MockObject()); + + // True if and only if we need to print this call's arguments and return + // value. This definition must be kept in sync with + // the behavior of ReportUninterestingCall(). + const bool need_to_report_uninteresting_call = + // If the user allows this uninteresting call, we print it + // only when they want informational messages. + reaction == kAllow ? LogIsVisible(kInfo) : + // If the user wants this to be a warning, we print + // it only when they want to see warnings. + reaction == kWarn + ? LogIsVisible(kWarning) + : + // Otherwise, the user wants this to be an error, and we + // should always print detailed information in the error. + true; + + if (!need_to_report_uninteresting_call) { + // Perform the action without printing the call information. + return this->UntypedPerformDefaultAction( + untyped_args, "Function call: " + std::string(Name())); + } + + // Warns about the uninteresting call. + ::std::stringstream ss; + this->UntypedDescribeUninterestingCall(untyped_args, &ss); + + // Calculates the function result. + UntypedActionResultHolderBase* const result = + this->UntypedPerformDefaultAction(untyped_args, ss.str()); + + // Prints the function result. + if (result != nullptr) result->PrintAsActionResult(&ss); + + ReportUninterestingCall(reaction, ss.str()); + return result; + } + + bool is_excessive = false; + ::std::stringstream ss; + ::std::stringstream why; + ::std::stringstream loc; + const void* untyped_action = nullptr; + + // The UntypedFindMatchingExpectation() function acquires and + // releases g_gmock_mutex. + + const ExpectationBase* const untyped_expectation = + this->UntypedFindMatchingExpectation(untyped_args, &untyped_action, + &is_excessive, &ss, &why); + const bool found = untyped_expectation != nullptr; + + // True if and only if we need to print the call's arguments + // and return value. + // This definition must be kept in sync with the uses of Expect() + // and Log() in this function. + const bool need_to_report_call = + !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); + } + + ss << " Function call: " << Name(); + this->UntypedPrintArgs(untyped_args, &ss); + + // In case the action deletes a piece of the expectation, we + // generate the message beforehand. + if (found && !is_excessive) { + 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 = [&] { + ss << "\n" << why.str(); + + if (!found) { + // No expectation matches this call - reports a failure. + Expect(false, nullptr, -1, ss.str()); + } else if (is_excessive) { + // We had an upper-bound violation and the failure message is in ss. + Expect(false, untyped_expectation->file(), untyped_expectation->line(), + ss.str()); + } else { + // We had an expected call and the matching expectation is + // 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; +} } // namespace internal |