aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/gmock/gmock-printers.h67
-rw-r--r--include/gmock/gmock-spec-builders.h348
-rw-r--r--include/gmock/internal/gmock-internal-utils.h4
3 files changed, 213 insertions, 206 deletions
diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h
index 99002434..e233ef3e 100644
--- a/include/gmock/gmock-printers.h
+++ b/include/gmock/gmock-printers.h
@@ -580,6 +580,41 @@ class UniversalPrinter {
#endif // _MSC_VER
};
+// UniversalPrintArray(begin, len, os) prints an array of 'len'
+// elements, starting at address 'begin'.
+template <typename T>
+void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
+ if (len == 0) {
+ *os << "{}";
+ } else {
+ *os << "{ ";
+ const size_t kThreshold = 18;
+ const size_t kChunkSize = 8;
+ // If the array has more than kThreshold elements, we'll have to
+ // omit some details by printing only the first and the last
+ // kChunkSize elements.
+ // TODO(wan@google.com): let the user control the threshold using a flag.
+ if (len <= kThreshold) {
+ PrintRawArrayTo(begin, len, os);
+ } else {
+ PrintRawArrayTo(begin, kChunkSize, os);
+ *os << ", ..., ";
+ PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
+ }
+ *os << " }";
+ }
+}
+// This overload prints a (const) char array compactly.
+void UniversalPrintArray(const char* begin, size_t len, ::std::ostream* os);
+
+// Prints an array of 'len' elements, starting at address 'begin', to a string.
+template <typename T>
+string UniversalPrintArrayToString(const T* begin, size_t len) {
+ ::std::stringstream ss;
+ UniversalPrintArray(begin, len, &ss);
+ return ss.str();
+}
+
// Implements printing an array type T[N].
template <typename T, size_t N>
class UniversalPrinter<T[N]> {
@@ -587,41 +622,13 @@ class UniversalPrinter<T[N]> {
// Prints the given array, omitting some elements when there are too
// many.
static void Print(const T (&a)[N], ::std::ostream* os) {
- // Prints a char array as a C string. Note that we compare 'const
- // T' with 'const char' instead of comparing T with char, in case
- // that T is already a const type.
- if (internal::type_equals<const T, const char>::value) {
- UniversalPrinter<const T*>::Print(a, os);
- return;
- }
-
- if (N == 0) {
- *os << "{}";
- } else {
- *os << "{ ";
- const size_t kThreshold = 18;
- const size_t kChunkSize = 8;
- // If the array has more than kThreshold elements, we'll have to
- // omit some details by printing only the first and the last
- // kChunkSize elements.
- // TODO(wan): let the user control the threshold using a flag.
- if (N <= kThreshold) {
- PrintRawArrayTo(a, N, os);
- } else {
- PrintRawArrayTo(a, kChunkSize, os);
- *os << ", ..., ";
- PrintRawArrayTo(a + N - kChunkSize, kChunkSize, os);
- }
- *os << " }";
- }
+ UniversalPrintArray(a, N, os);
}
// A convenient wrapper for Print() that returns the print-out as a
// string.
static string PrintToString(const T (&a)[N]) {
- ::std::stringstream ss;
- Print(a, &ss);
- return ss.str();
+ return UniversalPrintArrayToString(a, N);
}
};
diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h
index cc48bc0b..d4578ac7 100644
--- a/include/gmock/gmock-spec-builders.h
+++ b/include/gmock/gmock-spec-builders.h
@@ -93,10 +93,6 @@ class ExpectationTester;
template <typename F>
class FunctionMockerBase;
-// Helper class for implementing FunctionMockerBase<F>::InvokeWith().
-template <typename Result, typename F>
-class InvokeWithHelper;
-
// Protects the mock object registry (in class Mock), all function
// mockers, and all expectations.
//
@@ -269,9 +265,6 @@ class Mock {
template <typename F>
friend class internal::FunctionMockerBase;
- template <typename R, typename Args>
- friend class internal::InvokeWithHelper;
-
template <typename M>
friend class NiceMock;
@@ -763,9 +756,6 @@ class Expectation : public ExpectationBase {
template <typename Function>
friend class FunctionMockerBase;
- template <typename R, typename Function>
- friend class InvokeWithHelper;
-
// The following methods will be called only after the EXPECT_CALL()
// statement finishes and when the current thread holds
// g_gmock_mutex.
@@ -1042,6 +1032,78 @@ class MockSpec {
#pragma warning(disable:4355) // Temporarily disables warning 4355.
#endif // _MSV_VER
+// C++ treats the void type specially. For example, you cannot define
+// a void-typed variable or pass a void value to a function.
+// ActionResultHolder<T> 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. This generic definition is used
+// when T is not void.
+template <typename T>
+class ActionResultHolder {
+ public:
+ explicit ActionResultHolder(T value) : value_(value) {}
+
+ // The compiler-generated copy constructor and assignment operator
+ // are exactly what we need, so we don't need to define them.
+
+ T value() const { return value_; }
+
+ // Prints the held value as an action's result to os.
+ void PrintAsActionResult(::std::ostream* os) const {
+ *os << "\n Returns: ";
+ UniversalPrinter<T>::Print(value_, os);
+ }
+
+ // Performs the given mock function's default action and returns the
+ // result in a ActionResultHolder.
+ template <typename Function, typename Arguments>
+ static ActionResultHolder PerformDefaultAction(
+ const FunctionMockerBase<Function>* func_mocker,
+ const Arguments& args,
+ const string& call_description) {
+ return ActionResultHolder(
+ func_mocker->PerformDefaultAction(args, call_description));
+ }
+
+ // Performs the given action and returns the result in a
+ // ActionResultHolder.
+ template <typename Function, typename Arguments>
+ static ActionResultHolder PerformAction(const Action<Function>& action,
+ const Arguments& args) {
+ return ActionResultHolder(action.Perform(args));
+ }
+
+ private:
+ T value_;
+};
+
+// Specialization for T = void.
+template <>
+class ActionResultHolder<void> {
+ public:
+ ActionResultHolder() {}
+ void value() const {}
+ void PrintAsActionResult(::std::ostream* /* os */) const {}
+
+ template <typename Function, typename Arguments>
+ static ActionResultHolder PerformDefaultAction(
+ const FunctionMockerBase<Function>* func_mocker,
+ const Arguments& args,
+ const string& call_description) {
+ func_mocker->PerformDefaultAction(args, call_description);
+ return ActionResultHolder();
+ }
+
+ template <typename Function, typename Arguments>
+ static ActionResultHolder PerformAction(const Action<Function>& action,
+ const Arguments& args) {
+ action.Perform(args);
+ return ActionResultHolder();
+ }
+};
+
// The base of the function mocker class for the given function type.
// We put the methods in this class instead of its child to avoid code
// bloat.
@@ -1167,16 +1229,11 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
template <typename Function>
friend class MockSpec;
- template <typename R, typename Function>
- friend class InvokeWithHelper;
-
// Returns the result of invoking this mock function with the given
// arguments. This function can be safely called from multiple
// threads concurrently.
// L < g_gmock_mutex
- Result InvokeWith(const ArgumentTuple& args) {
- return InvokeWithHelper<Result, F>::InvokeAndPrintResult(this, args);
- }
+ Result InvokeWith(const ArgumentTuple& args);
// Adds and returns a default action spec for this mock function.
// L < g_gmock_mutex
@@ -1417,170 +1474,109 @@ bool FunctionMockerBase<F>::VerifyAndClearExpectationsLocked() {
// manner specified by 'reaction'.
void ReportUninterestingCall(CallReaction reaction, const string& msg);
-// When an uninteresting or unexpected mock function is called, we
-// want to print its return value to assist the user debugging. Since
-// there's nothing to print when the function returns void, we need to
-// specialize the logic of FunctionMockerBase<F>::InvokeWith() for
-// void return values.
-//
-// C++ doesn't allow us to specialize a member function template
-// unless we also specialize its enclosing class, so we had to let
-// InvokeWith() delegate its work to a helper class InvokeWithHelper,
-// which can then be specialized.
-//
-// Note that InvokeWithHelper must be a class template (as opposed to
-// a function template), as only class templates can be partially
-// specialized.
-template <typename Result, typename F>
-class InvokeWithHelper {
- public:
- typedef typename Function<F>::ArgumentTuple ArgumentTuple;
-
- // Calculates the result of invoking the function mocked by mocker
- // with the given arguments, prints it, and returns it.
- // L < g_gmock_mutex
- static Result InvokeAndPrintResult(
- FunctionMockerBase<F>* mocker,
- const ArgumentTuple& args) {
- if (mocker->expectations_.size() == 0) {
- // No expectation is set on this mock method - we have an
- // uninteresting call.
-
- // Warns about the uninteresting call.
- ::std::stringstream ss;
- mocker->DescribeUninterestingCall(args, &ss);
-
- // 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(mocker->MockObject());
-
- // Calculates the function result.
- Result result = mocker->PerformDefaultAction(args, ss.str());
-
- // Prints the function result.
- ss << "\n Returns: ";
- UniversalPrinter<Result>::Print(result, &ss);
- ReportUninterestingCall(reaction, ss.str());
-
- return result;
- }
-
- bool is_excessive = false;
- ::std::stringstream ss;
- ::std::stringstream why;
- ::std::stringstream loc;
- Action<F> action;
- Expectation<F>* exp;
-
- // The FindMatchingExpectationAndAction() function acquires and
- // releases g_gmock_mutex.
- const bool found = mocker->FindMatchingExpectationAndAction(
- args, &exp, &action, &is_excessive, &ss, &why);
- ss << " Function call: " << mocker->Name();
- UniversalPrinter<ArgumentTuple>::Print(args, &ss);
- // In case the action deletes a piece of the expectation, we
- // generate the message beforehand.
- if (found && !is_excessive) {
- exp->DescribeLocationTo(&loc);
- }
- Result result = action.IsDoDefault() ?
- mocker->PerformDefaultAction(args, ss.str())
- : action.Perform(args);
- ss << "\n Returns: ";
- UniversalPrinter<Result>::Print(result, &ss);
- ss << "\n" << why.str();
-
- if (found) {
- if (is_excessive) {
- // We had an upper-bound violation and the failure message is in ss.
- Expect(false, exp->file(), exp->line(), ss.str());
- } else {
- // We had an expected call and the matching expectation is
- // described in ss.
- Log(INFO, loc.str() + ss.str(), 3);
- }
- } else {
- // No expectation matches this call - reports a failure.
- Expect(false, NULL, -1, ss.str());
- }
- return result;
- }
-}; // class InvokeWithHelper
-
-// This specialization helps to implement
-// FunctionMockerBase<F>::InvokeWith() for void-returning functions.
+// Calculates the result of invoking this mock function with the given
+// arguments, prints it, and returns it.
+// L < g_gmock_mutex
template <typename F>
-class InvokeWithHelper<void, F> {
- public:
- typedef typename Function<F>::ArgumentTuple ArgumentTuple;
-
- // Invokes the function mocked by mocker with the given arguments.
- // L < g_gmock_mutex
- static void InvokeAndPrintResult(FunctionMockerBase<F>* mocker,
- const ArgumentTuple& args) {
- const int count = static_cast<int>(mocker->expectations_.size());
- if (count == 0) {
- // No expectation is set on this mock method - we have an
- // uninteresting call.
- ::std::stringstream ss;
- mocker->DescribeUninterestingCall(args, &ss);
-
- // 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(mocker->MockObject());
-
- mocker->PerformDefaultAction(args, ss.str());
- ReportUninterestingCall(reaction, ss.str());
- return;
+typename Function<F>::Result FunctionMockerBase<F>::InvokeWith(
+ const typename Function<F>::ArgumentTuple& args) {
+ typedef ActionResultHolder<Result> ResultHolder;
+
+ if (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 iff 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 he wants informational messages.
+ reaction == ALLOW ? LogIsVisible(INFO) :
+ // If the user wants this to be a warning, we print it only
+ // when he wants to see warnings.
+ reaction == WARN ? LogIsVisible(WARNING) :
+ // 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 PerformDefaultAction(args, "");
}
- bool is_excessive = false;
+ // Warns about the uninteresting call.
::std::stringstream ss;
- ::std::stringstream why;
- ::std::stringstream loc;
- Action<F> action;
- Expectation<F>* exp;
-
- // The FindMatchingExpectationAndAction() function acquires and
- // releases g_gmock_mutex.
- const bool found = mocker->FindMatchingExpectationAndAction(
- args, &exp, &action, &is_excessive, &ss, &why);
- ss << " Function call: " << mocker->Name();
- UniversalPrinter<ArgumentTuple>::Print(args, &ss);
- ss << "\n" << why.str();
- // In case the action deletes a piece of the expectation, we
- // generate the message beforehand.
- if (found && !is_excessive) {
- exp->DescribeLocationTo(&loc);
- }
- if (action.IsDoDefault()) {
- mocker->PerformDefaultAction(args, ss.str());
- } else {
- action.Perform(args);
- }
-
- if (found) {
- // A matching expectation and corresponding action were found.
- if (is_excessive) {
- // We had an upper-bound violation and the failure message is in ss.
- Expect(false, exp->file(), exp->line(), ss.str());
- } else {
- // We had an expected call and the matching expectation is
- // described in ss.
- Log(INFO, loc.str() + ss.str(), 3);
- }
- } else {
- // No matching expectation was found - reports an error.
- Expect(false, NULL, -1, ss.str());
- }
- }
-}; // class InvokeWithHelper<void, F>
+ DescribeUninterestingCall(args, &ss);
+
+ // Calculates the function result.
+ const ResultHolder result =
+ ResultHolder::PerformDefaultAction(this, args, ss.str());
+
+ // Prints the function result.
+ result.PrintAsActionResult(&ss);
+
+ ReportUninterestingCall(reaction, ss.str());
+ return result.value();
+ }
+
+ bool is_excessive = false;
+ ::std::stringstream ss;
+ ::std::stringstream why;
+ ::std::stringstream loc;
+ Action<F> action;
+ Expectation<F>* exp;
+
+ // The FindMatchingExpectationAndAction() function acquires and
+ // releases g_gmock_mutex.
+ const bool found = FindMatchingExpectationAndAction(
+ args, &exp, &action, &is_excessive, &ss, &why);
+
+ // True iff 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(INFO);
+ if (!need_to_report_call) {
+ // Perform the action without printing the call information.
+ return action.IsDoDefault() ? PerformDefaultAction(args, "") :
+ action.Perform(args);
+ }
+
+ ss << " Function call: " << Name();
+ UniversalPrinter<ArgumentTuple>::Print(args, &ss);
+
+ // In case the action deletes a piece of the expectation, we
+ // generate the message beforehand.
+ if (found && !is_excessive) {
+ exp->DescribeLocationTo(&loc);
+ }
+
+ const ResultHolder result = action.IsDoDefault() ?
+ ResultHolder::PerformDefaultAction(this, args, ss.str()) :
+ ResultHolder::PerformAction(action, args);
+ result.PrintAsActionResult(&ss);
+ ss << "\n" << why.str();
+
+ if (!found) {
+ // No expectation matches this call - reports a failure.
+ Expect(false, NULL, -1, ss.str());
+ } else if (is_excessive) {
+ // We had an upper-bound violation and the failure message is in ss.
+ Expect(false, exp->file(), exp->line(), ss.str());
+ } else {
+ // We had an expected call and the matching expectation is
+ // described in ss.
+ Log(INFO, loc.str() + ss.str(), 2);
+ }
+ return result.value();
+}
} // namespace internal
diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h
index b02682f8..b5e38db3 100644
--- a/include/gmock/internal/gmock-internal-utils.h
+++ b/include/gmock/internal/gmock-internal-utils.h
@@ -438,6 +438,10 @@ const char kWarningVerbosity[] = "warning";
// No logs are printed.
const char kErrorVerbosity[] = "error";
+// Returns true iff a log with the given severity is visible according
+// to the --gmock_verbose flag.
+bool LogIsVisible(LogSeverity severity);
+
// Prints the given message to stdout iff 'severity' >= the level
// specified by the --gmock_verbose flag. If stack_frames_to_skip >=
// 0, also prints the stack trace excluding the top