aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzhanyong.wan <zhanyong.wan@8415998a-534a-0410-bf83-d39667b30386>2009-05-29 19:50:06 +0000
committerzhanyong.wan <zhanyong.wan@8415998a-534a-0410-bf83-d39667b30386>2009-05-29 19:50:06 +0000
commit9413f2ff615ae1b933580576183d316c4cb6376c (patch)
treee5ef88b0191fa3296a34c793a17a16427a041fdf
parent16cf473930c01cd7a1a51dff65f22c541fbad5b8 (diff)
downloadgoogletest-9413f2ff615ae1b933580576183d316c4cb6376c.tar.gz
googletest-9413f2ff615ae1b933580576183d316c4cb6376c.tar.bz2
googletest-9413f2ff615ae1b933580576183d316c4cb6376c.zip
Avoids unnecessary printing of call into to internal buffers;
Made the universal value printer safer when printing char[]; Removed duplicated code in InvokeWith; Improved gmock_doctor.py.
-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
-rwxr-xr-xscripts/gmock_doctor.py93
-rw-r--r--src/gmock-internal-utils.cc27
-rw-r--r--src/gmock-printers.cc5
-rw-r--r--src/gmock-spec-builders.cc4
-rw-r--r--test/gmock-internal-utils_test.cc28
-rw-r--r--test/gmock-printers_test.cc54
-rw-r--r--test/gmock-spec-builders_test.cc47
10 files changed, 396 insertions, 281 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
diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py
index 907089e9..1980977c 100755
--- a/scripts/gmock_doctor.py
+++ b/scripts/gmock_doctor.py
@@ -36,7 +36,7 @@ __author__ = 'wan@google.com (Zhanyong Wan)'
import re
import sys
-_VERSION = '1.0.0'
+_VERSION = '1.0.1'
_COMMON_GMOCK_SYMBOLS = [
# Matchers
@@ -46,8 +46,12 @@ _COMMON_GMOCK_SYMBOLS = [
'AllOf',
'An',
'AnyOf',
+ 'ContainerEq',
+ 'Contains',
'ContainsRegex',
'DoubleEq',
+ 'ElementsAre',
+ 'ElementsAreArray',
'EndsWith',
'Eq',
'Field',
@@ -60,6 +64,8 @@ _COMMON_GMOCK_SYMBOLS = [
'Lt',
'MatcherCast',
'MatchesRegex',
+ 'NanSensitiveDoubleEq',
+ 'NanSensitiveFloatEq',
'Ne',
'Not',
'NotNull',
@@ -67,6 +73,8 @@ _COMMON_GMOCK_SYMBOLS = [
'PointeeIsInitializedProto',
'Property',
'Ref',
+ 'ResultOf',
+ 'SafeMatcherCast',
'StartsWith',
'StrCaseEq',
'StrCaseNe',
@@ -76,7 +84,9 @@ _COMMON_GMOCK_SYMBOLS = [
'TypedEq',
# Actions
+ 'Assign',
'ByRef',
+ 'DeleteArg',
'DoAll',
'DoDefault',
'IgnoreResult',
@@ -84,11 +94,18 @@ _COMMON_GMOCK_SYMBOLS = [
'InvokeArgument',
'InvokeWithoutArgs',
'Return',
+ 'ReturnNew',
'ReturnNull',
'ReturnRef',
+ 'SaveArg',
+ 'SetArgReferee',
'SetArgumentPointee',
'SetArrayArgument',
+ 'SetErrnoAndReturn',
+ 'Throw',
+ 'WithArg',
'WithArgs',
+ 'WithoutArgs',
# Cardinalities
'AnyNumber',
@@ -106,6 +123,9 @@ _COMMON_GMOCK_SYMBOLS = [
'Mock',
]
+# Regex for matching source file path and line number in gcc's errors.
+_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):\s+'
+
def _FindAllMatches(regex, s):
"""Generates all matches of regex in string s."""
@@ -128,6 +148,7 @@ def _GenericDiagnoser(short_name, long_name, regex, diagnosis, msg):
(short name of disease, long name of disease, diagnosis).
"""
+ diagnosis = '%(file)s:%(line)s:' + diagnosis
for m in _FindAllMatches(regex, msg):
yield (short_name, long_name, diagnosis % m.groupdict())
@@ -136,9 +157,9 @@ def _NeedToReturnReferenceDiagnoser(msg):
"""Diagnoses the NRR disease, given the error messages by gcc."""
regex = (r'In member function \'testing::internal::ReturnAction<R>.*\n'
- r'(?P<file>.*):(?P<line>\d+):\s+instantiated from here\n'
+ + _FILE_LINE_RE + r'instantiated from here\n'
r'.*gmock-actions\.h.*error: creating array with negative size')
- diagnosis = """%(file)s:%(line)s:
+ diagnosis = """
You are using an Return() action in a function that returns a reference.
Please use ReturnRef() instead."""
return _GenericDiagnoser('NRR', 'Need to Return Reference',
@@ -148,11 +169,11 @@ Please use ReturnRef() instead."""
def _NeedToReturnSomethingDiagnoser(msg):
"""Diagnoses the NRS disease, given the error messages by gcc."""
- regex = (r'(?P<file>.*):(?P<line>\d+):\s+'
+ regex = (_FILE_LINE_RE +
r'(instantiated from here\n.'
r'*gmock-actions\.h.*error: void value not ignored)'
r'|(error: control reaches end of non-void function)')
- diagnosis = """%(file)s:%(line)s:
+ diagnosis = """
You are using an action that returns void, but it needs to return
*something*. Please tell it *what* to return. Perhaps you can use
the pattern DoAll(some_action, Return(some_value))?"""
@@ -163,10 +184,10 @@ the pattern DoAll(some_action, Return(some_value))?"""
def _NeedToReturnNothingDiagnoser(msg):
"""Diagnoses the NRN disease, given the error messages by gcc."""
- regex = (r'(?P<file>.*):(?P<line>\d+):\s+instantiated from here\n'
+ regex = (_FILE_LINE_RE + r'instantiated from here\n'
r'.*gmock-actions\.h.*error: return-statement with a value, '
r'in function returning \'void\'')
- diagnosis = """%(file)s:%(line)s:
+ diagnosis = """
You are using an action that returns *something*, but it needs to return
void. Please use a void-returning action instead.
@@ -179,10 +200,10 @@ to re-arrange the order of actions in a DoAll(), if you are using one?"""
def _IncompleteByReferenceArgumentDiagnoser(msg):
"""Diagnoses the IBRA disease, given the error messages by gcc."""
- regex = (r'(?P<file>.*):(?P<line>\d+):\s+instantiated from here\n'
+ regex = (_FILE_LINE_RE + r'instantiated from here\n'
r'.*gmock-printers\.h.*error: invalid application of '
r'\'sizeof\' to incomplete type \'(?P<type>.*)\'')
- diagnosis = """%(file)s:%(line)s:
+ diagnosis = """
In order to mock this function, Google Mock needs to see the definition
of type "%(type)s" - declaration alone is not enough. Either #include
the header that defines it, or change the argument to be passed
@@ -194,9 +215,9 @@ by pointer."""
def _OverloadedFunctionMatcherDiagnoser(msg):
"""Diagnoses the OFM disease, given the error messages by gcc."""
- regex = (r'(?P<file>.*):(?P<line>\d+): error: no matching function for '
+ regex = (_FILE_LINE_RE + r'error: no matching function for '
r'call to \'Truly\(<unresolved overloaded function type>\)')
- diagnosis = """%(file)s:%(line)s:
+ diagnosis = """
The argument you gave to Truly() is an overloaded function. Please tell
gcc which overloaded version you want to use.
@@ -211,10 +232,9 @@ you should write
def _OverloadedFunctionActionDiagnoser(msg):
"""Diagnoses the OFA disease, given the error messages by gcc."""
- regex = (r'(?P<file>.*):(?P<line>\d+): error: '
- r'no matching function for call to \'Invoke\('
+ regex = (_FILE_LINE_RE + r'error: no matching function for call to \'Invoke\('
r'<unresolved overloaded function type>')
- diagnosis = """%(file)s:%(line)s:
+ diagnosis = """
You are passing an overloaded function to Invoke(). Please tell gcc
which overloaded version you want to use.
@@ -229,10 +249,10 @@ you should write something like
def _OverloadedMethodActionDiagnoser1(msg):
"""Diagnoses the OMA disease, given the error messages by gcc."""
- regex = (r'(?P<file>.*):(?P<line>\d+): error: '
+ regex = (_FILE_LINE_RE + r'error: '
r'.*no matching function for call to \'Invoke\(.*, '
r'unresolved overloaded function type>')
- diagnosis = """%(file)s:%(line)s:
+ diagnosis = """
The second argument you gave to Invoke() is an overloaded method. Please
tell gcc which overloaded version you want to use.
@@ -250,10 +270,10 @@ you should write something like
def _MockObjectPointerDiagnoser(msg):
"""Diagnoses the MOP disease, given the error messages by gcc."""
- regex = (r'(?P<file>.*):(?P<line>\d+): error: request for member '
+ regex = (_FILE_LINE_RE + r'error: request for member '
r'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', '
r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'')
- diagnosis = """%(file)s:%(line)s:
+ diagnosis = """
The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*,
not a *pointer* to it. Please write '*(%(mock_object)s)' instead of
'%(mock_object)s' as your first argument.
@@ -279,9 +299,9 @@ you should use the EXPECT_CALL like this:
def _OverloadedMethodActionDiagnoser2(msg):
"""Diagnoses the OMA disease, given the error messages by gcc."""
- regex = (r'(?P<file>.*):(?P<line>\d+): error: no matching function for '
+ regex = (_FILE_LINE_RE + r'error: no matching function for '
r'call to \'Invoke\(.+, <unresolved overloaded function type>\)')
- diagnosis = """%(file)s:%(line)s:
+ diagnosis = """
The second argument you gave to Invoke() is an overloaded method. Please
tell gcc which overloaded version you want to use.
@@ -299,9 +319,9 @@ you should write something like
def _NeedToUseSymbolDiagnoser(msg):
"""Diagnoses the NUS disease, given the error messages by gcc."""
- regex = (r'(?P<file>.*):(?P<line>\d+): error: \'(?P<symbol>.+)\' '
+ regex = (_FILE_LINE_RE + r'error: \'(?P<symbol>.+)\' '
r'(was not declared in this scope|has not been declared)')
- diagnosis = """%(file)s:%(line)s:
+ diagnosis = """
'%(symbol)s' is defined by Google Mock in the testing namespace.
Did you forget to write
using testing::%(symbol)s;
@@ -315,11 +335,10 @@ Did you forget to write
def _NeedToUseReturnNullDiagnoser(msg):
"""Diagnoses the NRNULL disease, given the error messages by gcc."""
- regex = (r'(?P<file>.*):(?P<line>\d+):\s+instantiated from here\n'
+ regex = (_FILE_LINE_RE + r'instantiated from here\n'
r'.*gmock-actions\.h.*error: invalid conversion from '
r'\'long int\' to \'(?P<type>.+\*)')
-
- diagnosis = """%(file)s:%(line)s:
+ diagnosis = """
You are probably calling Return(NULL) and the compiler isn't sure how to turn
NULL into a %(type)s*. Use ReturnNull() instead.
Note: the line number may be off; please fix all instances of Return(NULL)."""
@@ -330,13 +349,11 @@ Note: the line number may be off; please fix all instances of Return(NULL)."""
def _WrongMockMethodMacroDiagnoser(msg):
"""Diagnoses the WMM disease, given the error messages by gcc."""
- regex = (r'(?P<file>.*):(?P<line>\d+):\s+'
+ regex = (_FILE_LINE_RE +
r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n'
r'.*\n'
- r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>'
- )
-
- diagnosis = """%(file)s:%(line)s:
+ r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>')
+ diagnosis = """
You are using MOCK_METHOD%(wrong_args)s to define a mock method that has
%(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s,
MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead."""
@@ -344,6 +361,21 @@ MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead."""
regex, diagnosis, msg)
+def _WrongParenPositionDiagnoser(msg):
+ """Diagnoses the WPP disease, given the error messages by gcc."""
+
+ regex = (_FILE_LINE_RE +
+ r'error:.*testing::internal::MockSpec<.* has no member named \''
+ r'(?P<method>\w+)\'')
+ diagnosis = """
+The closing parenthesis of ON_CALL or EXPECT_CALL should be *before*
+".%(method)s". For example, you should write:
+ EXPECT_CALL(my_mock, Foo(_)).%(method)s(...);
+instead of:
+ EXPECT_CALL(my_mock, Foo(_).%(method)s(...));"""
+ return _GenericDiagnoser('WPP', 'Wrong parenthesis position',
+ regex, diagnosis, msg)
+
_DIAGNOSERS = [
_IncompleteByReferenceArgumentDiagnoser,
@@ -358,6 +390,7 @@ _DIAGNOSERS = [
_OverloadedMethodActionDiagnoser1,
_OverloadedMethodActionDiagnoser2,
_WrongMockMethodMacroDiagnoser,
+ _WrongParenPositionDiagnoser,
]
diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc
index 735abce5..ce17d715 100644
--- a/src/gmock-internal-utils.cc
+++ b/src/gmock-internal-utils.cc
@@ -101,6 +101,22 @@ FailureReporterInterface* GetFailureReporter() {
// Protects global resources (stdout in particular) used by Log().
static Mutex g_log_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX);
+// Returns true iff a log with the given severity is visible according
+// to the --gmock_verbose flag.
+bool LogIsVisible(LogSeverity severity) {
+ if (GMOCK_FLAG(verbose) == kInfoVerbosity) {
+ // Always show the log if --gmock_verbose=info.
+ return true;
+ } else if (GMOCK_FLAG(verbose) == kErrorVerbosity) {
+ // Always hide it if --gmock_verbose=error.
+ return false;
+ } else {
+ // If --gmock_verbose is neither "info" nor "error", we treat it
+ // as "warning" (its default value).
+ return severity == WARNING;
+ }
+}
+
// 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
@@ -110,17 +126,8 @@ static Mutex g_log_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX);
// conservative.
void Log(LogSeverity severity, const string& message,
int stack_frames_to_skip) {
- if (GMOCK_FLAG(verbose) == kErrorVerbosity) {
- // The user is not interested in logs.
+ if (!LogIsVisible(severity))
return;
- } else if (GMOCK_FLAG(verbose) != kInfoVerbosity) {
- // The user is interested in warnings but not informational logs.
- // Note that invalid values of GMOCK_FLAG(verbose) are treated as
- // "warning", which is the default value of the flag.
- if (severity == INFO) {
- return;
- }
- }
// Ensures that logs from different threads don't interleave.
MutexLock l(&g_log_mutex);
diff --git a/src/gmock-printers.cc b/src/gmock-printers.cc
index e6d4001a..922a7b2d 100644
--- a/src/gmock-printers.cc
+++ b/src/gmock-printers.cc
@@ -242,6 +242,11 @@ static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) {
*os << "\"";
}
+// Prints a (const) char array of 'len' elements, starting at address 'begin'.
+void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
+ PrintCharsAsStringTo(begin, len, os);
+}
+
// Prints the given array of wide characters to the ostream.
// The array starts at *begin, the length is len, it may include L'\0'
// characters and may not be null-terminated.
diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc
index 65a74b81..465e4d63 100644
--- a/src/gmock-spec-builders.cc
+++ b/src/gmock-spec-builders.cc
@@ -139,10 +139,10 @@ ThreadLocal<Sequence*> g_gmock_implicit_sequence;
void ReportUninterestingCall(CallReaction reaction, const string& msg) {
switch (reaction) {
case ALLOW:
- Log(INFO, msg, 4);
+ Log(INFO, msg, 3);
break;
case WARN:
- Log(WARNING, msg, 4);
+ Log(WARNING, msg, 3);
break;
default: // FAIL
Expect(false, NULL, -1, msg);
diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc
index 5e4dc030..7886f6d3 100644
--- a/test/gmock-internal-utils_test.cc
+++ b/test/gmock-internal-utils_test.cc
@@ -494,6 +494,34 @@ TEST(ExpectTest, FailsNonfatallyOnFalse) {
}, "Expectation failed");
}
+// Tests LogIsVisible().
+
+class LogIsVisibleTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() { original_verbose_ = GMOCK_FLAG(verbose); }
+ virtual void TearDown() { GMOCK_FLAG(verbose) = original_verbose_; }
+
+ string original_verbose_;
+};
+
+TEST_F(LogIsVisibleTest, AlwaysReturnsTrueIfVerbosityIsInfo) {
+ GMOCK_FLAG(verbose) = kInfoVerbosity;
+ EXPECT_TRUE(LogIsVisible(INFO));
+ EXPECT_TRUE(LogIsVisible(WARNING));
+}
+
+TEST_F(LogIsVisibleTest, AlwaysReturnsFalseIfVerbosityIsError) {
+ GMOCK_FLAG(verbose) = kErrorVerbosity;
+ EXPECT_FALSE(LogIsVisible(INFO));
+ EXPECT_FALSE(LogIsVisible(WARNING));
+}
+
+TEST_F(LogIsVisibleTest, WorksWhenVerbosityIsWarning) {
+ GMOCK_FLAG(verbose) = kWarningVerbosity;
+ EXPECT_FALSE(LogIsVisible(INFO));
+ EXPECT_TRUE(LogIsVisible(WARNING));
+}
+
// TODO(wan@google.com): find a way to re-enable these tests.
#if 0
diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc
index 29a0db84..f03be292 100644
--- a/test/gmock-printers_test.cc
+++ b/test/gmock-printers_test.cc
@@ -485,75 +485,58 @@ TEST(PrintPointerTest, MemberFunctionPointer) {
// Tests printing C arrays.
-// One-dimensional array.
-
-void ArrayHelper1(int (&a)[5]) { // NOLINT
- EXPECT_EQ("{ 1, 2, 3, 4, 5 }", Print(a));
+// The difference between this and Print() is that it ensures that the
+// argument is a reference to an array.
+template <typename T, size_t N>
+string PrintArrayHelper(T (&a)[N]) {
+ return Print(a);
}
+// One-dimensional array.
TEST(PrintArrayTest, OneDimensionalArray) {
int a[5] = { 1, 2, 3, 4, 5 };
- ArrayHelper1(a);
+ EXPECT_EQ("{ 1, 2, 3, 4, 5 }", PrintArrayHelper(a));
}
// Two-dimensional array.
-
-void ArrayHelper2(int (&a)[2][5]) { // NOLINT
- EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", Print(a));
-}
-
TEST(PrintArrayTest, TwoDimensionalArray) {
int a[2][5] = {
{ 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 0 }
};
- ArrayHelper2(a);
+ EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", PrintArrayHelper(a));
}
// Array of const elements.
-
-void ArrayHelper3(const bool (&a)[1]) { // NOLINT
- EXPECT_EQ("{ false }", Print(a));
-}
-
TEST(PrintArrayTest, ConstArray) {
const bool a[1] = { false };
- ArrayHelper3(a);
+ EXPECT_EQ("{ false }", PrintArrayHelper(a));
}
// Char array.
-
-void ArrayHelper4(char (&a)[3]) { // NOLINT
- EXPECT_EQ(PrintPointer(a) + " pointing to \"Hi\"", Print(a));
-}
-
TEST(PrintArrayTest, CharArray) {
- char a[3] = "Hi";
- ArrayHelper4(a);
+ // Array a contains '\0' in the middle and doesn't end with '\0'.
+ char a[3] = { 'H', '\0', 'i' };
+ EXPECT_EQ("\"H\\0i\"", PrintArrayHelper(a));
}
// Const char array.
-
-void ArrayHelper5(const char (&a)[3]) { // NOLINT
- EXPECT_EQ(Print(a), PrintPointer(a) + " pointing to \"Hi\"");
-}
-
TEST(PrintArrayTest, ConstCharArray) {
- const char a[3] = "Hi";
- ArrayHelper5(a);
+ const char a[4] = "\0Hi";
+ EXPECT_EQ("\"\\0Hi\\0\"", PrintArrayHelper(a));
}
// Array of objects.
TEST(PrintArrayTest, ObjectArray) {
string a[3] = { "Hi", "Hello", "Ni hao" };
- EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", Print(a));
+ EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", PrintArrayHelper(a));
}
// Array with many elements.
TEST(PrintArrayTest, BigArray) {
int a[100] = { 1, 2, 3 };
EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }",
- Print(a));
+ PrintArrayHelper(a));
}
// Tests printing ::string and ::std::string.
@@ -995,6 +978,11 @@ TEST(PrintToStringTest, WorksForReference) {
UniversalPrinter<const int&>::PrintToString(n));
}
+TEST(PrintToStringTest, WorksForArray) {
+ int n[3] = { 1, 2, 3 };
+ EXPECT_EQ("{ 1, 2, 3 }", UniversalPrinter<int[3]>::PrintToString(n));
+}
+
TEST(UniversalTersePrintTest, WorksForNonReference) {
::std::stringstream ss;
UniversalTersePrint(123, &ss);
diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc
index e8c39028..4711899d 100644
--- a/test/gmock-spec-builders_test.cc
+++ b/test/gmock-spec-builders_test.cc
@@ -1612,6 +1612,53 @@ TEST_F(GMockVerboseFlagTest, InvalidFlagIsTreatedAsWarning) {
#endif // 0
+// A helper class that generates a failure when printed. We use it to
+// ensure that Google Mock doesn't print a value (even to an internal
+// buffer) when it is not supposed to do so.
+class PrintMeNot {};
+
+void PrintTo(PrintMeNot /* dummy */, ::std::ostream* /* os */) {
+ ADD_FAILURE() << "Google Mock is printing a value that shouldn't be "
+ << "printed even to an internal buffer.";
+}
+
+class LogTestHelper {
+ public:
+ MOCK_METHOD1(Foo, PrintMeNot(PrintMeNot));
+};
+
+class GMockLogTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() { original_verbose_ = GMOCK_FLAG(verbose); }
+ virtual void TearDown() { GMOCK_FLAG(verbose) = original_verbose_; }
+
+ LogTestHelper helper_;
+ string original_verbose_;
+};
+
+TEST_F(GMockLogTest, DoesNotPrintGoodCallInternallyIfVerbosityIsWarning) {
+ GMOCK_FLAG(verbose) = kWarningVerbosity;
+ EXPECT_CALL(helper_, Foo(_))
+ .WillOnce(Return(PrintMeNot()));
+ helper_.Foo(PrintMeNot()); // This is an expected call.
+}
+
+TEST_F(GMockLogTest, DoesNotPrintGoodCallInternallyIfVerbosityIsError) {
+ GMOCK_FLAG(verbose) = kErrorVerbosity;
+ EXPECT_CALL(helper_, Foo(_))
+ .WillOnce(Return(PrintMeNot()));
+ helper_.Foo(PrintMeNot()); // This is an expected call.
+}
+
+TEST_F(GMockLogTest, DoesNotPrintWarningInternallyIfVerbosityIsError) {
+ GMOCK_FLAG(verbose) = kErrorVerbosity;
+ ON_CALL(helper_, Foo(_))
+ .WillByDefault(Return(PrintMeNot()));
+ helper_.Foo(PrintMeNot()); // This should generate a warning.
+}
+
+// Tests Mock::AllowLeak().
+
TEST(AllowLeakTest, AllowsLeakingUnusedMockObject) {
MockA* a = new MockA;
Mock::AllowLeak(a);