mirror of
https://github.com/google/googletest.git
synced 2025-03-20 10:53:47 +00:00
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.
This commit is contained in:
parent
16cf473930
commit
9413f2ff61
@ -580,22 +580,11 @@ class UniversalPrinter {
|
|||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
};
|
};
|
||||||
|
|
||||||
// Implements printing an array type T[N].
|
// UniversalPrintArray(begin, len, os) prints an array of 'len'
|
||||||
template <typename T, size_t N>
|
// elements, starting at address 'begin'.
|
||||||
class UniversalPrinter<T[N]> {
|
template <typename T>
|
||||||
public:
|
void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
|
||||||
// Prints the given array, omitting some elements when there are too
|
if (len == 0) {
|
||||||
// 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 << "{}";
|
*os << "{}";
|
||||||
} else {
|
} else {
|
||||||
*os << "{ ";
|
*os << "{ ";
|
||||||
@ -604,24 +593,42 @@ class UniversalPrinter<T[N]> {
|
|||||||
// If the array has more than kThreshold elements, we'll have to
|
// If the array has more than kThreshold elements, we'll have to
|
||||||
// omit some details by printing only the first and the last
|
// omit some details by printing only the first and the last
|
||||||
// kChunkSize elements.
|
// kChunkSize elements.
|
||||||
// TODO(wan): let the user control the threshold using a flag.
|
// TODO(wan@google.com): let the user control the threshold using a flag.
|
||||||
if (N <= kThreshold) {
|
if (len <= kThreshold) {
|
||||||
PrintRawArrayTo(a, N, os);
|
PrintRawArrayTo(begin, len, os);
|
||||||
} else {
|
} else {
|
||||||
PrintRawArrayTo(a, kChunkSize, os);
|
PrintRawArrayTo(begin, kChunkSize, os);
|
||||||
*os << ", ..., ";
|
*os << ", ..., ";
|
||||||
PrintRawArrayTo(a + N - kChunkSize, kChunkSize, os);
|
PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
|
||||||
}
|
}
|
||||||
*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]> {
|
||||||
|
public:
|
||||||
|
// Prints the given array, omitting some elements when there are too
|
||||||
|
// many.
|
||||||
|
static void Print(const T (&a)[N], ::std::ostream* os) {
|
||||||
|
UniversalPrintArray(a, N, os);
|
||||||
|
}
|
||||||
|
|
||||||
// A convenient wrapper for Print() that returns the print-out as a
|
// A convenient wrapper for Print() that returns the print-out as a
|
||||||
// string.
|
// string.
|
||||||
static string PrintToString(const T (&a)[N]) {
|
static string PrintToString(const T (&a)[N]) {
|
||||||
::std::stringstream ss;
|
return UniversalPrintArrayToString(a, N);
|
||||||
Print(a, &ss);
|
|
||||||
return ss.str();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -93,10 +93,6 @@ class ExpectationTester;
|
|||||||
template <typename F>
|
template <typename F>
|
||||||
class FunctionMockerBase;
|
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
|
// Protects the mock object registry (in class Mock), all function
|
||||||
// mockers, and all expectations.
|
// mockers, and all expectations.
|
||||||
//
|
//
|
||||||
@ -269,9 +265,6 @@ class Mock {
|
|||||||
template <typename F>
|
template <typename F>
|
||||||
friend class internal::FunctionMockerBase;
|
friend class internal::FunctionMockerBase;
|
||||||
|
|
||||||
template <typename R, typename Args>
|
|
||||||
friend class internal::InvokeWithHelper;
|
|
||||||
|
|
||||||
template <typename M>
|
template <typename M>
|
||||||
friend class NiceMock;
|
friend class NiceMock;
|
||||||
|
|
||||||
@ -763,9 +756,6 @@ class Expectation : public ExpectationBase {
|
|||||||
template <typename Function>
|
template <typename Function>
|
||||||
friend class FunctionMockerBase;
|
friend class FunctionMockerBase;
|
||||||
|
|
||||||
template <typename R, typename Function>
|
|
||||||
friend class InvokeWithHelper;
|
|
||||||
|
|
||||||
// The following methods will be called only after the EXPECT_CALL()
|
// The following methods will be called only after the EXPECT_CALL()
|
||||||
// statement finishes and when the current thread holds
|
// statement finishes and when the current thread holds
|
||||||
// g_gmock_mutex.
|
// g_gmock_mutex.
|
||||||
@ -1042,6 +1032,78 @@ class MockSpec {
|
|||||||
#pragma warning(disable:4355) // Temporarily disables warning 4355.
|
#pragma warning(disable:4355) // Temporarily disables warning 4355.
|
||||||
#endif // _MSV_VER
|
#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.
|
// 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
|
// We put the methods in this class instead of its child to avoid code
|
||||||
// bloat.
|
// bloat.
|
||||||
@ -1167,16 +1229,11 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
|
|||||||
template <typename Function>
|
template <typename Function>
|
||||||
friend class MockSpec;
|
friend class MockSpec;
|
||||||
|
|
||||||
template <typename R, typename Function>
|
|
||||||
friend class InvokeWithHelper;
|
|
||||||
|
|
||||||
// Returns the result of invoking this mock function with the given
|
// Returns the result of invoking this mock function with the given
|
||||||
// arguments. This function can be safely called from multiple
|
// arguments. This function can be safely called from multiple
|
||||||
// threads concurrently.
|
// threads concurrently.
|
||||||
// L < g_gmock_mutex
|
// L < g_gmock_mutex
|
||||||
Result InvokeWith(const ArgumentTuple& args) {
|
Result InvokeWith(const ArgumentTuple& args);
|
||||||
return InvokeWithHelper<Result, F>::InvokeAndPrintResult(this, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adds and returns a default action spec for this mock function.
|
// Adds and returns a default action spec for this mock function.
|
||||||
// L < g_gmock_mutex
|
// L < g_gmock_mutex
|
||||||
@ -1417,55 +1474,57 @@ bool FunctionMockerBase<F>::VerifyAndClearExpectationsLocked() {
|
|||||||
// manner specified by 'reaction'.
|
// manner specified by 'reaction'.
|
||||||
void ReportUninterestingCall(CallReaction reaction, const string& msg);
|
void ReportUninterestingCall(CallReaction reaction, const string& msg);
|
||||||
|
|
||||||
// When an uninteresting or unexpected mock function is called, we
|
// Calculates the result of invoking this mock function with the given
|
||||||
// want to print its return value to assist the user debugging. Since
|
// arguments, prints it, and returns it.
|
||||||
// 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
|
// L < g_gmock_mutex
|
||||||
static Result InvokeAndPrintResult(
|
template <typename F>
|
||||||
FunctionMockerBase<F>* mocker,
|
typename Function<F>::Result FunctionMockerBase<F>::InvokeWith(
|
||||||
const ArgumentTuple& args) {
|
const typename Function<F>::ArgumentTuple& args) {
|
||||||
if (mocker->expectations_.size() == 0) {
|
typedef ActionResultHolder<Result> ResultHolder;
|
||||||
|
|
||||||
|
if (expectations_.size() == 0) {
|
||||||
// No expectation is set on this mock method - we have an
|
// No expectation is set on this mock method - we have an
|
||||||
// uninteresting call.
|
// 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, "");
|
||||||
|
}
|
||||||
|
|
||||||
// Warns about the uninteresting call.
|
// Warns about the uninteresting call.
|
||||||
::std::stringstream ss;
|
::std::stringstream ss;
|
||||||
mocker->DescribeUninterestingCall(args, &ss);
|
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.
|
// Calculates the function result.
|
||||||
Result result = mocker->PerformDefaultAction(args, ss.str());
|
const ResultHolder result =
|
||||||
|
ResultHolder::PerformDefaultAction(this, args, ss.str());
|
||||||
|
|
||||||
// Prints the function result.
|
// Prints the function result.
|
||||||
ss << "\n Returns: ";
|
result.PrintAsActionResult(&ss);
|
||||||
UniversalPrinter<Result>::Print(result, &ss);
|
|
||||||
ReportUninterestingCall(reaction, ss.str());
|
|
||||||
|
|
||||||
return result;
|
ReportUninterestingCall(reaction, ss.str());
|
||||||
|
return result.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_excessive = false;
|
bool is_excessive = false;
|
||||||
@ -1477,110 +1536,47 @@ class InvokeWithHelper {
|
|||||||
|
|
||||||
// The FindMatchingExpectationAndAction() function acquires and
|
// The FindMatchingExpectationAndAction() function acquires and
|
||||||
// releases g_gmock_mutex.
|
// releases g_gmock_mutex.
|
||||||
const bool found = mocker->FindMatchingExpectationAndAction(
|
const bool found = FindMatchingExpectationAndAction(
|
||||||
args, &exp, &action, &is_excessive, &ss, &why);
|
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) {
|
// True iff we need to print the call's arguments and return value.
|
||||||
if (is_excessive) {
|
// This definition must be kept in sync with the uses of Expect()
|
||||||
// We had an upper-bound violation and the failure message is in ss.
|
// and Log() in this function.
|
||||||
Expect(false, exp->file(), exp->line(), ss.str());
|
const bool need_to_report_call = !found || is_excessive || LogIsVisible(INFO);
|
||||||
} else {
|
if (!need_to_report_call) {
|
||||||
// We had an expected call and the matching expectation is
|
// Perform the action without printing the call information.
|
||||||
// described in ss.
|
return action.IsDoDefault() ? PerformDefaultAction(args, "") :
|
||||||
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.
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
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);
|
action.Perform(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found) {
|
ss << " Function call: " << Name();
|
||||||
// A matching expectation and corresponding action were found.
|
UniversalPrinter<ArgumentTuple>::Print(args, &ss);
|
||||||
if (is_excessive) {
|
|
||||||
|
// 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.
|
// We had an upper-bound violation and the failure message is in ss.
|
||||||
Expect(false, exp->file(), exp->line(), ss.str());
|
Expect(false, exp->file(), exp->line(), ss.str());
|
||||||
} else {
|
} else {
|
||||||
// We had an expected call and the matching expectation is
|
// We had an expected call and the matching expectation is
|
||||||
// described in ss.
|
// described in ss.
|
||||||
Log(INFO, loc.str() + ss.str(), 3);
|
Log(INFO, loc.str() + ss.str(), 2);
|
||||||
}
|
}
|
||||||
} else {
|
return result.value();
|
||||||
// No matching expectation was found - reports an error.
|
|
||||||
Expect(false, NULL, -1, ss.str());
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}; // class InvokeWithHelper<void, F>
|
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
|
@ -438,6 +438,10 @@ const char kWarningVerbosity[] = "warning";
|
|||||||
// No logs are printed.
|
// No logs are printed.
|
||||||
const char kErrorVerbosity[] = "error";
|
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
|
// Prints the given message to stdout iff 'severity' >= the level
|
||||||
// specified by the --gmock_verbose flag. If stack_frames_to_skip >=
|
// specified by the --gmock_verbose flag. If stack_frames_to_skip >=
|
||||||
// 0, also prints the stack trace excluding the top
|
// 0, also prints the stack trace excluding the top
|
||||||
|
@ -36,7 +36,7 @@ __author__ = 'wan@google.com (Zhanyong Wan)'
|
|||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
_VERSION = '1.0.0'
|
_VERSION = '1.0.1'
|
||||||
|
|
||||||
_COMMON_GMOCK_SYMBOLS = [
|
_COMMON_GMOCK_SYMBOLS = [
|
||||||
# Matchers
|
# Matchers
|
||||||
@ -46,8 +46,12 @@ _COMMON_GMOCK_SYMBOLS = [
|
|||||||
'AllOf',
|
'AllOf',
|
||||||
'An',
|
'An',
|
||||||
'AnyOf',
|
'AnyOf',
|
||||||
|
'ContainerEq',
|
||||||
|
'Contains',
|
||||||
'ContainsRegex',
|
'ContainsRegex',
|
||||||
'DoubleEq',
|
'DoubleEq',
|
||||||
|
'ElementsAre',
|
||||||
|
'ElementsAreArray',
|
||||||
'EndsWith',
|
'EndsWith',
|
||||||
'Eq',
|
'Eq',
|
||||||
'Field',
|
'Field',
|
||||||
@ -60,6 +64,8 @@ _COMMON_GMOCK_SYMBOLS = [
|
|||||||
'Lt',
|
'Lt',
|
||||||
'MatcherCast',
|
'MatcherCast',
|
||||||
'MatchesRegex',
|
'MatchesRegex',
|
||||||
|
'NanSensitiveDoubleEq',
|
||||||
|
'NanSensitiveFloatEq',
|
||||||
'Ne',
|
'Ne',
|
||||||
'Not',
|
'Not',
|
||||||
'NotNull',
|
'NotNull',
|
||||||
@ -67,6 +73,8 @@ _COMMON_GMOCK_SYMBOLS = [
|
|||||||
'PointeeIsInitializedProto',
|
'PointeeIsInitializedProto',
|
||||||
'Property',
|
'Property',
|
||||||
'Ref',
|
'Ref',
|
||||||
|
'ResultOf',
|
||||||
|
'SafeMatcherCast',
|
||||||
'StartsWith',
|
'StartsWith',
|
||||||
'StrCaseEq',
|
'StrCaseEq',
|
||||||
'StrCaseNe',
|
'StrCaseNe',
|
||||||
@ -76,7 +84,9 @@ _COMMON_GMOCK_SYMBOLS = [
|
|||||||
'TypedEq',
|
'TypedEq',
|
||||||
|
|
||||||
# Actions
|
# Actions
|
||||||
|
'Assign',
|
||||||
'ByRef',
|
'ByRef',
|
||||||
|
'DeleteArg',
|
||||||
'DoAll',
|
'DoAll',
|
||||||
'DoDefault',
|
'DoDefault',
|
||||||
'IgnoreResult',
|
'IgnoreResult',
|
||||||
@ -84,11 +94,18 @@ _COMMON_GMOCK_SYMBOLS = [
|
|||||||
'InvokeArgument',
|
'InvokeArgument',
|
||||||
'InvokeWithoutArgs',
|
'InvokeWithoutArgs',
|
||||||
'Return',
|
'Return',
|
||||||
|
'ReturnNew',
|
||||||
'ReturnNull',
|
'ReturnNull',
|
||||||
'ReturnRef',
|
'ReturnRef',
|
||||||
|
'SaveArg',
|
||||||
|
'SetArgReferee',
|
||||||
'SetArgumentPointee',
|
'SetArgumentPointee',
|
||||||
'SetArrayArgument',
|
'SetArrayArgument',
|
||||||
|
'SetErrnoAndReturn',
|
||||||
|
'Throw',
|
||||||
|
'WithArg',
|
||||||
'WithArgs',
|
'WithArgs',
|
||||||
|
'WithoutArgs',
|
||||||
|
|
||||||
# Cardinalities
|
# Cardinalities
|
||||||
'AnyNumber',
|
'AnyNumber',
|
||||||
@ -106,6 +123,9 @@ _COMMON_GMOCK_SYMBOLS = [
|
|||||||
'Mock',
|
'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):
|
def _FindAllMatches(regex, s):
|
||||||
"""Generates all matches of regex in string 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).
|
(short name of disease, long name of disease, diagnosis).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
diagnosis = '%(file)s:%(line)s:' + diagnosis
|
||||||
for m in _FindAllMatches(regex, msg):
|
for m in _FindAllMatches(regex, msg):
|
||||||
yield (short_name, long_name, diagnosis % m.groupdict())
|
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."""
|
"""Diagnoses the NRR disease, given the error messages by gcc."""
|
||||||
|
|
||||||
regex = (r'In member function \'testing::internal::ReturnAction<R>.*\n'
|
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')
|
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.
|
You are using an Return() action in a function that returns a reference.
|
||||||
Please use ReturnRef() instead."""
|
Please use ReturnRef() instead."""
|
||||||
return _GenericDiagnoser('NRR', 'Need to Return Reference',
|
return _GenericDiagnoser('NRR', 'Need to Return Reference',
|
||||||
@ -148,11 +169,11 @@ Please use ReturnRef() instead."""
|
|||||||
def _NeedToReturnSomethingDiagnoser(msg):
|
def _NeedToReturnSomethingDiagnoser(msg):
|
||||||
"""Diagnoses the NRS disease, given the error messages by gcc."""
|
"""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'(instantiated from here\n.'
|
||||||
r'*gmock-actions\.h.*error: void value not ignored)'
|
r'*gmock-actions\.h.*error: void value not ignored)'
|
||||||
r'|(error: control reaches end of non-void function)')
|
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
|
You are using an action that returns void, but it needs to return
|
||||||
*something*. Please tell it *what* to return. Perhaps you can use
|
*something*. Please tell it *what* to return. Perhaps you can use
|
||||||
the pattern DoAll(some_action, Return(some_value))?"""
|
the pattern DoAll(some_action, Return(some_value))?"""
|
||||||
@ -163,10 +184,10 @@ the pattern DoAll(some_action, Return(some_value))?"""
|
|||||||
def _NeedToReturnNothingDiagnoser(msg):
|
def _NeedToReturnNothingDiagnoser(msg):
|
||||||
"""Diagnoses the NRN disease, given the error messages by gcc."""
|
"""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'.*gmock-actions\.h.*error: return-statement with a value, '
|
||||||
r'in function returning \'void\'')
|
r'in function returning \'void\'')
|
||||||
diagnosis = """%(file)s:%(line)s:
|
diagnosis = """
|
||||||
You are using an action that returns *something*, but it needs to return
|
You are using an action that returns *something*, but it needs to return
|
||||||
void. Please use a void-returning action instead.
|
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):
|
def _IncompleteByReferenceArgumentDiagnoser(msg):
|
||||||
"""Diagnoses the IBRA disease, given the error messages by gcc."""
|
"""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'.*gmock-printers\.h.*error: invalid application of '
|
||||||
r'\'sizeof\' to incomplete type \'(?P<type>.*)\'')
|
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
|
In order to mock this function, Google Mock needs to see the definition
|
||||||
of type "%(type)s" - declaration alone is not enough. Either #include
|
of type "%(type)s" - declaration alone is not enough. Either #include
|
||||||
the header that defines it, or change the argument to be passed
|
the header that defines it, or change the argument to be passed
|
||||||
@ -194,9 +215,9 @@ by pointer."""
|
|||||||
def _OverloadedFunctionMatcherDiagnoser(msg):
|
def _OverloadedFunctionMatcherDiagnoser(msg):
|
||||||
"""Diagnoses the OFM disease, given the error messages by gcc."""
|
"""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>\)')
|
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
|
The argument you gave to Truly() is an overloaded function. Please tell
|
||||||
gcc which overloaded version you want to use.
|
gcc which overloaded version you want to use.
|
||||||
|
|
||||||
@ -211,10 +232,9 @@ you should write
|
|||||||
def _OverloadedFunctionActionDiagnoser(msg):
|
def _OverloadedFunctionActionDiagnoser(msg):
|
||||||
"""Diagnoses the OFA disease, given the error messages by gcc."""
|
"""Diagnoses the OFA disease, given the error messages by gcc."""
|
||||||
|
|
||||||
regex = (r'(?P<file>.*):(?P<line>\d+): error: '
|
regex = (_FILE_LINE_RE + r'error: no matching function for call to \'Invoke\('
|
||||||
r'no matching function for call to \'Invoke\('
|
|
||||||
r'<unresolved overloaded function type>')
|
r'<unresolved overloaded function type>')
|
||||||
diagnosis = """%(file)s:%(line)s:
|
diagnosis = """
|
||||||
You are passing an overloaded function to Invoke(). Please tell gcc
|
You are passing an overloaded function to Invoke(). Please tell gcc
|
||||||
which overloaded version you want to use.
|
which overloaded version you want to use.
|
||||||
|
|
||||||
@ -229,10 +249,10 @@ you should write something like
|
|||||||
def _OverloadedMethodActionDiagnoser1(msg):
|
def _OverloadedMethodActionDiagnoser1(msg):
|
||||||
"""Diagnoses the OMA disease, given the error messages by gcc."""
|
"""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'.*no matching function for call to \'Invoke\(.*, '
|
||||||
r'unresolved overloaded function type>')
|
r'unresolved overloaded function type>')
|
||||||
diagnosis = """%(file)s:%(line)s:
|
diagnosis = """
|
||||||
The second argument you gave to Invoke() is an overloaded method. Please
|
The second argument you gave to Invoke() is an overloaded method. Please
|
||||||
tell gcc which overloaded version you want to use.
|
tell gcc which overloaded version you want to use.
|
||||||
|
|
||||||
@ -250,10 +270,10 @@ you should write something like
|
|||||||
def _MockObjectPointerDiagnoser(msg):
|
def _MockObjectPointerDiagnoser(msg):
|
||||||
"""Diagnoses the MOP disease, given the error messages by gcc."""
|
"""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'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', '
|
||||||
r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'')
|
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*,
|
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
|
not a *pointer* to it. Please write '*(%(mock_object)s)' instead of
|
||||||
'%(mock_object)s' as your first argument.
|
'%(mock_object)s' as your first argument.
|
||||||
@ -279,9 +299,9 @@ you should use the EXPECT_CALL like this:
|
|||||||
def _OverloadedMethodActionDiagnoser2(msg):
|
def _OverloadedMethodActionDiagnoser2(msg):
|
||||||
"""Diagnoses the OMA disease, given the error messages by gcc."""
|
"""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>\)')
|
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
|
The second argument you gave to Invoke() is an overloaded method. Please
|
||||||
tell gcc which overloaded version you want to use.
|
tell gcc which overloaded version you want to use.
|
||||||
|
|
||||||
@ -299,9 +319,9 @@ you should write something like
|
|||||||
def _NeedToUseSymbolDiagnoser(msg):
|
def _NeedToUseSymbolDiagnoser(msg):
|
||||||
"""Diagnoses the NUS disease, given the error messages by gcc."""
|
"""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)')
|
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.
|
'%(symbol)s' is defined by Google Mock in the testing namespace.
|
||||||
Did you forget to write
|
Did you forget to write
|
||||||
using testing::%(symbol)s;
|
using testing::%(symbol)s;
|
||||||
@ -315,11 +335,10 @@ Did you forget to write
|
|||||||
def _NeedToUseReturnNullDiagnoser(msg):
|
def _NeedToUseReturnNullDiagnoser(msg):
|
||||||
"""Diagnoses the NRNULL disease, given the error messages by gcc."""
|
"""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'.*gmock-actions\.h.*error: invalid conversion from '
|
||||||
r'\'long int\' to \'(?P<type>.+\*)')
|
r'\'long int\' to \'(?P<type>.+\*)')
|
||||||
|
diagnosis = """
|
||||||
diagnosis = """%(file)s:%(line)s:
|
|
||||||
You are probably calling Return(NULL) and the compiler isn't sure how to turn
|
You are probably calling Return(NULL) and the compiler isn't sure how to turn
|
||||||
NULL into a %(type)s*. Use ReturnNull() instead.
|
NULL into a %(type)s*. Use ReturnNull() instead.
|
||||||
Note: the line number may be off; please fix all instances of Return(NULL)."""
|
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):
|
def _WrongMockMethodMacroDiagnoser(msg):
|
||||||
"""Diagnoses the WMM disease, given the error messages by gcc."""
|
"""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'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n'
|
||||||
r'.*\n'
|
r'.*\n'
|
||||||
r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>'
|
r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>')
|
||||||
)
|
diagnosis = """
|
||||||
|
|
||||||
diagnosis = """%(file)s:%(line)s:
|
|
||||||
You are using MOCK_METHOD%(wrong_args)s to define a mock method that has
|
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,
|
%(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."""
|
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)
|
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 = [
|
_DIAGNOSERS = [
|
||||||
_IncompleteByReferenceArgumentDiagnoser,
|
_IncompleteByReferenceArgumentDiagnoser,
|
||||||
@ -358,6 +390,7 @@ _DIAGNOSERS = [
|
|||||||
_OverloadedMethodActionDiagnoser1,
|
_OverloadedMethodActionDiagnoser1,
|
||||||
_OverloadedMethodActionDiagnoser2,
|
_OverloadedMethodActionDiagnoser2,
|
||||||
_WrongMockMethodMacroDiagnoser,
|
_WrongMockMethodMacroDiagnoser,
|
||||||
|
_WrongParenPositionDiagnoser,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,6 +101,22 @@ FailureReporterInterface* GetFailureReporter() {
|
|||||||
// Protects global resources (stdout in particular) used by Log().
|
// Protects global resources (stdout in particular) used by Log().
|
||||||
static Mutex g_log_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX);
|
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
|
// Prints the given message to stdout iff 'severity' >= the level
|
||||||
// specified by the --gmock_verbose flag. If stack_frames_to_skip >=
|
// specified by the --gmock_verbose flag. If stack_frames_to_skip >=
|
||||||
// 0, also prints the stack trace excluding the top
|
// 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.
|
// conservative.
|
||||||
void Log(LogSeverity severity, const string& message,
|
void Log(LogSeverity severity, const string& message,
|
||||||
int stack_frames_to_skip) {
|
int stack_frames_to_skip) {
|
||||||
if (GMOCK_FLAG(verbose) == kErrorVerbosity) {
|
if (!LogIsVisible(severity))
|
||||||
// The user is not interested in logs.
|
|
||||||
return;
|
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.
|
// Ensures that logs from different threads don't interleave.
|
||||||
MutexLock l(&g_log_mutex);
|
MutexLock l(&g_log_mutex);
|
||||||
|
@ -242,6 +242,11 @@ static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) {
|
|||||||
*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.
|
// Prints the given array of wide characters to the ostream.
|
||||||
// The array starts at *begin, the length is len, it may include L'\0'
|
// The array starts at *begin, the length is len, it may include L'\0'
|
||||||
// characters and may not be null-terminated.
|
// characters and may not be null-terminated.
|
||||||
|
@ -139,10 +139,10 @@ ThreadLocal<Sequence*> g_gmock_implicit_sequence;
|
|||||||
void ReportUninterestingCall(CallReaction reaction, const string& msg) {
|
void ReportUninterestingCall(CallReaction reaction, const string& msg) {
|
||||||
switch (reaction) {
|
switch (reaction) {
|
||||||
case ALLOW:
|
case ALLOW:
|
||||||
Log(INFO, msg, 4);
|
Log(INFO, msg, 3);
|
||||||
break;
|
break;
|
||||||
case WARN:
|
case WARN:
|
||||||
Log(WARNING, msg, 4);
|
Log(WARNING, msg, 3);
|
||||||
break;
|
break;
|
||||||
default: // FAIL
|
default: // FAIL
|
||||||
Expect(false, NULL, -1, msg);
|
Expect(false, NULL, -1, msg);
|
||||||
|
@ -494,6 +494,34 @@ TEST(ExpectTest, FailsNonfatallyOnFalse) {
|
|||||||
}, "Expectation failed");
|
}, "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.
|
// TODO(wan@google.com): find a way to re-enable these tests.
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
|
@ -485,75 +485,58 @@ TEST(PrintPointerTest, MemberFunctionPointer) {
|
|||||||
|
|
||||||
// Tests printing C arrays.
|
// Tests printing C arrays.
|
||||||
|
|
||||||
// One-dimensional array.
|
// The difference between this and Print() is that it ensures that the
|
||||||
|
// argument is a reference to an array.
|
||||||
void ArrayHelper1(int (&a)[5]) { // NOLINT
|
template <typename T, size_t N>
|
||||||
EXPECT_EQ("{ 1, 2, 3, 4, 5 }", Print(a));
|
string PrintArrayHelper(T (&a)[N]) {
|
||||||
|
return Print(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// One-dimensional array.
|
||||||
TEST(PrintArrayTest, OneDimensionalArray) {
|
TEST(PrintArrayTest, OneDimensionalArray) {
|
||||||
int a[5] = { 1, 2, 3, 4, 5 };
|
int a[5] = { 1, 2, 3, 4, 5 };
|
||||||
ArrayHelper1(a);
|
EXPECT_EQ("{ 1, 2, 3, 4, 5 }", PrintArrayHelper(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Two-dimensional array.
|
// 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) {
|
TEST(PrintArrayTest, TwoDimensionalArray) {
|
||||||
int a[2][5] = {
|
int a[2][5] = {
|
||||||
{ 1, 2, 3, 4, 5 },
|
{ 1, 2, 3, 4, 5 },
|
||||||
{ 6, 7, 8, 9, 0 }
|
{ 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.
|
// Array of const elements.
|
||||||
|
|
||||||
void ArrayHelper3(const bool (&a)[1]) { // NOLINT
|
|
||||||
EXPECT_EQ("{ false }", Print(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(PrintArrayTest, ConstArray) {
|
TEST(PrintArrayTest, ConstArray) {
|
||||||
const bool a[1] = { false };
|
const bool a[1] = { false };
|
||||||
ArrayHelper3(a);
|
EXPECT_EQ("{ false }", PrintArrayHelper(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Char array.
|
// Char array.
|
||||||
|
|
||||||
void ArrayHelper4(char (&a)[3]) { // NOLINT
|
|
||||||
EXPECT_EQ(PrintPointer(a) + " pointing to \"Hi\"", Print(a));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(PrintArrayTest, CharArray) {
|
TEST(PrintArrayTest, CharArray) {
|
||||||
char a[3] = "Hi";
|
// Array a contains '\0' in the middle and doesn't end with '\0'.
|
||||||
ArrayHelper4(a);
|
char a[3] = { 'H', '\0', 'i' };
|
||||||
|
EXPECT_EQ("\"H\\0i\"", PrintArrayHelper(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Const char array.
|
// Const char array.
|
||||||
|
|
||||||
void ArrayHelper5(const char (&a)[3]) { // NOLINT
|
|
||||||
EXPECT_EQ(Print(a), PrintPointer(a) + " pointing to \"Hi\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(PrintArrayTest, ConstCharArray) {
|
TEST(PrintArrayTest, ConstCharArray) {
|
||||||
const char a[3] = "Hi";
|
const char a[4] = "\0Hi";
|
||||||
ArrayHelper5(a);
|
EXPECT_EQ("\"\\0Hi\\0\"", PrintArrayHelper(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Array of objects.
|
// Array of objects.
|
||||||
TEST(PrintArrayTest, ObjectArray) {
|
TEST(PrintArrayTest, ObjectArray) {
|
||||||
string a[3] = { "Hi", "Hello", "Ni hao" };
|
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.
|
// Array with many elements.
|
||||||
TEST(PrintArrayTest, BigArray) {
|
TEST(PrintArrayTest, BigArray) {
|
||||||
int a[100] = { 1, 2, 3 };
|
int a[100] = { 1, 2, 3 };
|
||||||
EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }",
|
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.
|
// Tests printing ::string and ::std::string.
|
||||||
@ -995,6 +978,11 @@ TEST(PrintToStringTest, WorksForReference) {
|
|||||||
UniversalPrinter<const int&>::PrintToString(n));
|
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) {
|
TEST(UniversalTersePrintTest, WorksForNonReference) {
|
||||||
::std::stringstream ss;
|
::std::stringstream ss;
|
||||||
UniversalTersePrint(123, &ss);
|
UniversalTersePrint(123, &ss);
|
||||||
|
@ -1612,6 +1612,53 @@ TEST_F(GMockVerboseFlagTest, InvalidFlagIsTreatedAsWarning) {
|
|||||||
|
|
||||||
#endif // 0
|
#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) {
|
TEST(AllowLeakTest, AllowsLeakingUnusedMockObject) {
|
||||||
MockA* a = new MockA;
|
MockA* a = new MockA;
|
||||||
Mock::AllowLeak(a);
|
Mock::AllowLeak(a);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user