Makes Google Mock compile much faster and use much less memory; reviewed by Nico Weber. This fixes issue 68.
This commit is contained in:
parent
b3e904227f
commit
ed6c9277bb
|
@ -59,9 +59,6 @@ namespace testing {
|
|||
|
||||
namespace internal {
|
||||
|
||||
template <typename F>
|
||||
class MonomorphicDoDefaultActionImpl;
|
||||
|
||||
template <typename F1, typename F2>
|
||||
class ActionAdaptor;
|
||||
|
||||
|
@ -255,8 +252,7 @@ class ActionInterface {
|
|||
typedef typename internal::Function<F>::Result Result;
|
||||
typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
|
||||
|
||||
ActionInterface() : is_do_default_(false) {}
|
||||
|
||||
ActionInterface() {}
|
||||
virtual ~ActionInterface() {}
|
||||
|
||||
// Performs the action. This method is not const, as in general an
|
||||
|
@ -265,21 +261,7 @@ class ActionInterface {
|
|||
// remember the current element.
|
||||
virtual Result Perform(const ArgumentTuple& args) = 0;
|
||||
|
||||
// Returns true iff this is the DoDefault() action.
|
||||
bool IsDoDefault() const { return is_do_default_; }
|
||||
|
||||
private:
|
||||
template <typename Function>
|
||||
friend class internal::MonomorphicDoDefaultActionImpl;
|
||||
|
||||
// This private constructor is reserved for implementing
|
||||
// DoDefault(), the default action for a given mock function.
|
||||
explicit ActionInterface(bool is_do_default)
|
||||
: is_do_default_(is_do_default) {}
|
||||
|
||||
// True iff this action is DoDefault().
|
||||
const bool is_do_default_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ActionInterface);
|
||||
};
|
||||
|
||||
|
@ -302,7 +284,8 @@ class Action {
|
|||
// STL containers.
|
||||
Action() : impl_(NULL) {}
|
||||
|
||||
// Constructs an Action from its implementation.
|
||||
// Constructs an Action from its implementation. A NULL impl is
|
||||
// used to represent the "do-default" action.
|
||||
explicit Action(ActionInterface<F>* impl) : impl_(impl) {}
|
||||
|
||||
// Copy constructor.
|
||||
|
@ -316,7 +299,7 @@ class Action {
|
|||
explicit Action(const Action<Func>& action);
|
||||
|
||||
// Returns true iff this is the DoDefault() action.
|
||||
bool IsDoDefault() const { return impl_->IsDoDefault(); }
|
||||
bool IsDoDefault() const { return impl_.get() == NULL; }
|
||||
|
||||
// Performs the action. Note that this method is const even though
|
||||
// the corresponding method in ActionInterface is not. The reason
|
||||
|
@ -325,6 +308,13 @@ class Action {
|
|||
// cannot change state. (Think of the difference between a const
|
||||
// pointer and a pointer to const.)
|
||||
Result Perform(const ArgumentTuple& args) const {
|
||||
internal::Assert(
|
||||
!IsDoDefault(), __FILE__, __LINE__,
|
||||
"You are using DoDefault() inside a composite action like "
|
||||
"DoAll() or WithArgs(). This is not supported for technical "
|
||||
"reasons. Please instead spell out the default action, or "
|
||||
"assign the default action to an Action variable and use "
|
||||
"the variable in various places.");
|
||||
return impl_->Perform(args);
|
||||
}
|
||||
|
||||
|
@ -633,42 +623,13 @@ class ReturnRefOfCopyAction {
|
|||
GTEST_DISALLOW_ASSIGN_(ReturnRefOfCopyAction);
|
||||
};
|
||||
|
||||
// Implements the DoDefault() action for a particular function type F.
|
||||
template <typename F>
|
||||
class MonomorphicDoDefaultActionImpl : public ActionInterface<F> {
|
||||
public:
|
||||
typedef typename Function<F>::Result Result;
|
||||
typedef typename Function<F>::ArgumentTuple ArgumentTuple;
|
||||
|
||||
MonomorphicDoDefaultActionImpl() : ActionInterface<F>(true) {}
|
||||
|
||||
// For technical reasons, DoDefault() cannot be used inside a
|
||||
// composite action (e.g. DoAll(...)). It can only be used at the
|
||||
// top level in an EXPECT_CALL(). If this function is called, the
|
||||
// user must be using DoDefault() inside a composite action, and we
|
||||
// have to generate a run-time error.
|
||||
virtual Result Perform(const ArgumentTuple&) {
|
||||
Assert(false, __FILE__, __LINE__,
|
||||
"You are using DoDefault() inside a composite action like "
|
||||
"DoAll() or WithArgs(). This is not supported for technical "
|
||||
"reasons. Please instead spell out the default action, or "
|
||||
"assign the default action to an Action variable and use "
|
||||
"the variable in various places.");
|
||||
return internal::Invalid<Result>();
|
||||
// The above statement will never be reached, but is required in
|
||||
// order for this function to compile.
|
||||
}
|
||||
};
|
||||
|
||||
// Implements the polymorphic DoDefault() action.
|
||||
class DoDefaultAction {
|
||||
public:
|
||||
// This template type conversion operator allows DoDefault() to be
|
||||
// used in any function.
|
||||
template <typename F>
|
||||
operator Action<F>() const {
|
||||
return Action<F>(new MonomorphicDoDefaultActionImpl<F>);
|
||||
}
|
||||
operator Action<F>() const { return Action<F>(NULL); }
|
||||
};
|
||||
|
||||
// Implements the Assign action to set a given pointer referent to a
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
|
||||
// This file was GENERATED by command:
|
||||
// pump.py gmock-generated-function-mockers.h.pump
|
||||
// DO NOT EDIT BY HAND!!!
|
||||
|
||||
// Copyright 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
|
@ -352,7 +354,8 @@ using internal::FunctionMocker;
|
|||
} \
|
||||
::testing::MockSpec<F>& \
|
||||
gmock_##Method() constness { \
|
||||
return GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this).With(); \
|
||||
GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this); \
|
||||
return GMOCK_MOCKER_(0, constness, Method).With(); \
|
||||
} \
|
||||
mutable ::testing::FunctionMocker<F> GMOCK_MOCKER_(0, constness, Method)
|
||||
|
||||
|
@ -367,8 +370,8 @@ using internal::FunctionMocker;
|
|||
} \
|
||||
::testing::MockSpec<F>& \
|
||||
gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1) constness { \
|
||||
return GMOCK_MOCKER_(1, constness, \
|
||||
Method).RegisterOwner(this).With(gmock_a1); \
|
||||
GMOCK_MOCKER_(1, constness, Method).RegisterOwner(this); \
|
||||
return GMOCK_MOCKER_(1, constness, Method).With(gmock_a1); \
|
||||
} \
|
||||
mutable ::testing::FunctionMocker<F> GMOCK_MOCKER_(1, constness, Method)
|
||||
|
||||
|
@ -385,8 +388,8 @@ using internal::FunctionMocker;
|
|||
::testing::MockSpec<F>& \
|
||||
gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \
|
||||
GMOCK_MATCHER_(tn, F, 2) gmock_a2) constness { \
|
||||
return GMOCK_MOCKER_(2, constness, \
|
||||
Method).RegisterOwner(this).With(gmock_a1, gmock_a2); \
|
||||
GMOCK_MOCKER_(2, constness, Method).RegisterOwner(this); \
|
||||
return GMOCK_MOCKER_(2, constness, Method).With(gmock_a1, gmock_a2); \
|
||||
} \
|
||||
mutable ::testing::FunctionMocker<F> GMOCK_MOCKER_(2, constness, Method)
|
||||
|
||||
|
@ -406,8 +409,9 @@ using internal::FunctionMocker;
|
|||
gmock_##Method(GMOCK_MATCHER_(tn, F, 1) gmock_a1, \
|
||||
GMOCK_MATCHER_(tn, F, 2) gmock_a2, \
|
||||
GMOCK_MATCHER_(tn, F, 3) gmock_a3) constness { \
|
||||
return GMOCK_MOCKER_(3, constness, \
|
||||
Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3); \
|
||||
GMOCK_MOCKER_(3, constness, Method).RegisterOwner(this); \
|
||||
return GMOCK_MOCKER_(3, constness, Method).With(gmock_a1, gmock_a2, \
|
||||
gmock_a3); \
|
||||
} \
|
||||
mutable ::testing::FunctionMocker<F> GMOCK_MOCKER_(3, constness, Method)
|
||||
|
||||
|
@ -429,9 +433,9 @@ using internal::FunctionMocker;
|
|||
GMOCK_MATCHER_(tn, F, 2) gmock_a2, \
|
||||
GMOCK_MATCHER_(tn, F, 3) gmock_a3, \
|
||||
GMOCK_MATCHER_(tn, F, 4) gmock_a4) constness { \
|
||||
return GMOCK_MOCKER_(4, constness, \
|
||||
Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \
|
||||
gmock_a4); \
|
||||
GMOCK_MOCKER_(4, constness, Method).RegisterOwner(this); \
|
||||
return GMOCK_MOCKER_(4, constness, Method).With(gmock_a1, gmock_a2, \
|
||||
gmock_a3, gmock_a4); \
|
||||
} \
|
||||
mutable ::testing::FunctionMocker<F> GMOCK_MOCKER_(4, constness, Method)
|
||||
|
||||
|
@ -455,9 +459,9 @@ using internal::FunctionMocker;
|
|||
GMOCK_MATCHER_(tn, F, 3) gmock_a3, \
|
||||
GMOCK_MATCHER_(tn, F, 4) gmock_a4, \
|
||||
GMOCK_MATCHER_(tn, F, 5) gmock_a5) constness { \
|
||||
return GMOCK_MOCKER_(5, constness, \
|
||||
Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \
|
||||
gmock_a4, gmock_a5); \
|
||||
GMOCK_MOCKER_(5, constness, Method).RegisterOwner(this); \
|
||||
return GMOCK_MOCKER_(5, constness, Method).With(gmock_a1, gmock_a2, \
|
||||
gmock_a3, gmock_a4, gmock_a5); \
|
||||
} \
|
||||
mutable ::testing::FunctionMocker<F> GMOCK_MOCKER_(5, constness, Method)
|
||||
|
||||
|
@ -483,9 +487,9 @@ using internal::FunctionMocker;
|
|||
GMOCK_MATCHER_(tn, F, 4) gmock_a4, \
|
||||
GMOCK_MATCHER_(tn, F, 5) gmock_a5, \
|
||||
GMOCK_MATCHER_(tn, F, 6) gmock_a6) constness { \
|
||||
return GMOCK_MOCKER_(6, constness, \
|
||||
Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \
|
||||
gmock_a4, gmock_a5, gmock_a6); \
|
||||
GMOCK_MOCKER_(6, constness, Method).RegisterOwner(this); \
|
||||
return GMOCK_MOCKER_(6, constness, Method).With(gmock_a1, gmock_a2, \
|
||||
gmock_a3, gmock_a4, gmock_a5, gmock_a6); \
|
||||
} \
|
||||
mutable ::testing::FunctionMocker<F> GMOCK_MOCKER_(6, constness, Method)
|
||||
|
||||
|
@ -513,9 +517,9 @@ using internal::FunctionMocker;
|
|||
GMOCK_MATCHER_(tn, F, 5) gmock_a5, \
|
||||
GMOCK_MATCHER_(tn, F, 6) gmock_a6, \
|
||||
GMOCK_MATCHER_(tn, F, 7) gmock_a7) constness { \
|
||||
return GMOCK_MOCKER_(7, constness, \
|
||||
Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \
|
||||
gmock_a4, gmock_a5, gmock_a6, gmock_a7); \
|
||||
GMOCK_MOCKER_(7, constness, Method).RegisterOwner(this); \
|
||||
return GMOCK_MOCKER_(7, constness, Method).With(gmock_a1, gmock_a2, \
|
||||
gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \
|
||||
} \
|
||||
mutable ::testing::FunctionMocker<F> GMOCK_MOCKER_(7, constness, Method)
|
||||
|
||||
|
@ -545,9 +549,9 @@ using internal::FunctionMocker;
|
|||
GMOCK_MATCHER_(tn, F, 6) gmock_a6, \
|
||||
GMOCK_MATCHER_(tn, F, 7) gmock_a7, \
|
||||
GMOCK_MATCHER_(tn, F, 8) gmock_a8) constness { \
|
||||
return GMOCK_MOCKER_(8, constness, \
|
||||
Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \
|
||||
gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \
|
||||
GMOCK_MOCKER_(8, constness, Method).RegisterOwner(this); \
|
||||
return GMOCK_MOCKER_(8, constness, Method).With(gmock_a1, gmock_a2, \
|
||||
gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \
|
||||
} \
|
||||
mutable ::testing::FunctionMocker<F> GMOCK_MOCKER_(8, constness, Method)
|
||||
|
||||
|
@ -580,9 +584,10 @@ using internal::FunctionMocker;
|
|||
GMOCK_MATCHER_(tn, F, 7) gmock_a7, \
|
||||
GMOCK_MATCHER_(tn, F, 8) gmock_a8, \
|
||||
GMOCK_MATCHER_(tn, F, 9) gmock_a9) constness { \
|
||||
return GMOCK_MOCKER_(9, constness, \
|
||||
Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \
|
||||
gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9); \
|
||||
GMOCK_MOCKER_(9, constness, Method).RegisterOwner(this); \
|
||||
return GMOCK_MOCKER_(9, constness, Method).With(gmock_a1, gmock_a2, \
|
||||
gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \
|
||||
gmock_a9); \
|
||||
} \
|
||||
mutable ::testing::FunctionMocker<F> GMOCK_MOCKER_(9, constness, Method)
|
||||
|
||||
|
@ -617,9 +622,9 @@ using internal::FunctionMocker;
|
|||
GMOCK_MATCHER_(tn, F, 8) gmock_a8, \
|
||||
GMOCK_MATCHER_(tn, F, 9) gmock_a9, \
|
||||
GMOCK_MATCHER_(tn, F, 10) gmock_a10) constness { \
|
||||
return GMOCK_MOCKER_(10, constness, \
|
||||
Method).RegisterOwner(this).With(gmock_a1, gmock_a2, gmock_a3, \
|
||||
gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \
|
||||
GMOCK_MOCKER_(10, constness, Method).RegisterOwner(this); \
|
||||
return GMOCK_MOCKER_(10, constness, Method).With(gmock_a1, gmock_a2, \
|
||||
gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \
|
||||
gmock_a10); \
|
||||
} \
|
||||
mutable ::testing::FunctionMocker<F> GMOCK_MOCKER_(10, constness, Method)
|
||||
|
|
|
@ -140,7 +140,8 @@ $var matcher_as = [[$for j, \
|
|||
} \
|
||||
::testing::MockSpec<F>& \
|
||||
gmock_##Method($matcher_as) constness { \
|
||||
return GMOCK_MOCKER_($i, constness, Method).RegisterOwner(this).With($as); \
|
||||
GMOCK_MOCKER_($i, constness, Method).RegisterOwner(this); \
|
||||
return GMOCK_MOCKER_($i, constness, Method).With($as); \
|
||||
} \
|
||||
mutable ::testing::FunctionMocker<F> GMOCK_MOCKER_($i, constness, Method)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -261,8 +261,8 @@ def _IncompleteByReferenceArgumentDiagnoser(msg):
|
|||
r'(.*\n)*?' +
|
||||
_CLANG_NON_GMOCK_FILE_LINE_RE +
|
||||
r'note: in instantiation of member function '
|
||||
r'\'testing::internal::FunctionMocker<.*>::Invoke\' '
|
||||
r'requested here')
|
||||
r'\'testing::internal2::TypeWithoutFormatter<.*>::'
|
||||
r'PrintValue\' requested here')
|
||||
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
|
||||
|
|
|
@ -55,6 +55,15 @@ namespace internal {
|
|||
// mockers, and all expectations.
|
||||
GTEST_DEFINE_STATIC_MUTEX_(g_gmock_mutex);
|
||||
|
||||
// Logs a message including file and line number information.
|
||||
void LogWithLocation(testing::internal::LogSeverity severity,
|
||||
const char* file, int line,
|
||||
const string& message) {
|
||||
::std::ostringstream s;
|
||||
s << file << ":" << line << ": " << message << ::std::endl;
|
||||
Log(severity, s.str(), 0);
|
||||
}
|
||||
|
||||
// Constructs an ExpectationBase object.
|
||||
ExpectationBase::ExpectationBase(const char* a_file,
|
||||
int a_line,
|
||||
|
@ -65,8 +74,12 @@ ExpectationBase::ExpectationBase(const char* a_file,
|
|||
cardinality_specified_(false),
|
||||
cardinality_(Exactly(1)),
|
||||
call_count_(0),
|
||||
retired_(false) {
|
||||
}
|
||||
retired_(false),
|
||||
extra_matcher_specified_(false),
|
||||
repeated_action_specified_(false),
|
||||
retires_on_saturation_(false),
|
||||
last_clause_(kNone),
|
||||
action_count_checked_(false) {}
|
||||
|
||||
// Destructs an ExpectationBase object.
|
||||
ExpectationBase::~ExpectationBase() {}
|
||||
|
@ -132,6 +145,99 @@ void ExpectationBase::FindUnsatisfiedPrerequisites(
|
|||
}
|
||||
}
|
||||
|
||||
// Describes how many times a function call matching this
|
||||
// expectation has occurred.
|
||||
// L >= g_gmock_mutex
|
||||
void ExpectationBase::DescribeCallCountTo(::std::ostream* os) const {
|
||||
g_gmock_mutex.AssertHeld();
|
||||
|
||||
// Describes how many times the function is expected to be called.
|
||||
*os << " Expected: to be ";
|
||||
cardinality().DescribeTo(os);
|
||||
*os << "\n Actual: ";
|
||||
Cardinality::DescribeActualCallCountTo(call_count(), os);
|
||||
|
||||
// Describes the state of the expectation (e.g. is it satisfied?
|
||||
// is it active?).
|
||||
*os << " - " << (IsOverSaturated() ? "over-saturated" :
|
||||
IsSaturated() ? "saturated" :
|
||||
IsSatisfied() ? "satisfied" : "unsatisfied")
|
||||
<< " and "
|
||||
<< (is_retired() ? "retired" : "active");
|
||||
}
|
||||
|
||||
// Checks the action count (i.e. the number of WillOnce() and
|
||||
// WillRepeatedly() clauses) against the cardinality if this hasn't
|
||||
// been done before. Prints a warning if there are too many or too
|
||||
// few actions.
|
||||
// L < mutex_
|
||||
void ExpectationBase::CheckActionCountIfNotDone() const {
|
||||
bool should_check = false;
|
||||
{
|
||||
MutexLock l(&mutex_);
|
||||
if (!action_count_checked_) {
|
||||
action_count_checked_ = true;
|
||||
should_check = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (should_check) {
|
||||
if (!cardinality_specified_) {
|
||||
// The cardinality was inferred - no need to check the action
|
||||
// count against it.
|
||||
return;
|
||||
}
|
||||
|
||||
// The cardinality was explicitly specified.
|
||||
const int action_count = static_cast<int>(untyped_actions_.size());
|
||||
const int upper_bound = cardinality().ConservativeUpperBound();
|
||||
const int lower_bound = cardinality().ConservativeLowerBound();
|
||||
bool too_many; // True if there are too many actions, or false
|
||||
// if there are too few.
|
||||
if (action_count > upper_bound ||
|
||||
(action_count == upper_bound && repeated_action_specified_)) {
|
||||
too_many = true;
|
||||
} else if (0 < action_count && action_count < lower_bound &&
|
||||
!repeated_action_specified_) {
|
||||
too_many = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
::std::stringstream ss;
|
||||
DescribeLocationTo(&ss);
|
||||
ss << "Too " << (too_many ? "many" : "few")
|
||||
<< " actions specified in " << source_text() << "...\n"
|
||||
<< "Expected to be ";
|
||||
cardinality().DescribeTo(&ss);
|
||||
ss << ", but has " << (too_many ? "" : "only ")
|
||||
<< action_count << " WillOnce()"
|
||||
<< (action_count == 1 ? "" : "s");
|
||||
if (repeated_action_specified_) {
|
||||
ss << " and a WillRepeatedly()";
|
||||
}
|
||||
ss << ".";
|
||||
Log(WARNING, ss.str(), -1); // -1 means "don't print stack trace".
|
||||
}
|
||||
}
|
||||
|
||||
// Implements the .Times() clause.
|
||||
void ExpectationBase::UntypedTimes(const Cardinality& a_cardinality) {
|
||||
if (last_clause_ == kTimes) {
|
||||
ExpectSpecProperty(false,
|
||||
".Times() cannot appear "
|
||||
"more than once in an EXPECT_CALL().");
|
||||
} else {
|
||||
ExpectSpecProperty(last_clause_ < kTimes,
|
||||
".Times() cannot appear after "
|
||||
".InSequence(), .WillOnce(), .WillRepeatedly(), "
|
||||
"or .RetiresOnSaturation().");
|
||||
}
|
||||
last_clause_ = kTimes;
|
||||
|
||||
SpecifyCardinality(a_cardinality);
|
||||
}
|
||||
|
||||
// Points to the implicit sequence introduced by a living InSequence
|
||||
// object (if any) in the current thread or NULL.
|
||||
ThreadLocal<Sequence*> g_gmock_implicit_sequence;
|
||||
|
@ -151,6 +257,233 @@ void ReportUninterestingCall(CallReaction reaction, const string& msg) {
|
|||
}
|
||||
}
|
||||
|
||||
UntypedFunctionMockerBase::UntypedFunctionMockerBase()
|
||||
: mock_obj_(NULL), name_("") {}
|
||||
|
||||
UntypedFunctionMockerBase::~UntypedFunctionMockerBase() {}
|
||||
|
||||
// Sets the mock object this mock method belongs to, and registers
|
||||
// this information in the global mock registry. Will be called
|
||||
// whenever an EXPECT_CALL() or ON_CALL() is executed on this mock
|
||||
// method.
|
||||
// L < g_gmock_mutex
|
||||
void UntypedFunctionMockerBase::RegisterOwner(const void* mock_obj) {
|
||||
{
|
||||
MutexLock l(&g_gmock_mutex);
|
||||
mock_obj_ = mock_obj;
|
||||
}
|
||||
Mock::Register(mock_obj, this);
|
||||
}
|
||||
|
||||
// Sets the mock object this mock method belongs to, and sets the name
|
||||
// of the mock function. Will be called upon each invocation of this
|
||||
// mock function.
|
||||
// L < g_gmock_mutex
|
||||
void UntypedFunctionMockerBase::SetOwnerAndName(
|
||||
const void* mock_obj, const char* name) {
|
||||
// We protect name_ under g_gmock_mutex in case this mock function
|
||||
// is called from two threads concurrently.
|
||||
MutexLock l(&g_gmock_mutex);
|
||||
mock_obj_ = mock_obj;
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
// Returns the name of the function being mocked. Must be called
|
||||
// after RegisterOwner() or SetOwnerAndName() has been called.
|
||||
// L < g_gmock_mutex
|
||||
const void* UntypedFunctionMockerBase::MockObject() const {
|
||||
const void* mock_obj;
|
||||
{
|
||||
// We protect mock_obj_ under g_gmock_mutex in case this mock
|
||||
// function is called from two threads concurrently.
|
||||
MutexLock l(&g_gmock_mutex);
|
||||
Assert(mock_obj_ != NULL, __FILE__, __LINE__,
|
||||
"MockObject() must not be called before RegisterOwner() or "
|
||||
"SetOwnerAndName() has been called.");
|
||||
mock_obj = mock_obj_;
|
||||
}
|
||||
return mock_obj;
|
||||
}
|
||||
|
||||
// Returns the name of this mock method. Must be called after
|
||||
// SetOwnerAndName() has been called.
|
||||
// L < g_gmock_mutex
|
||||
const char* UntypedFunctionMockerBase::Name() const {
|
||||
const char* name;
|
||||
{
|
||||
// We protect name_ under g_gmock_mutex in case this mock
|
||||
// function is called from two threads concurrently.
|
||||
MutexLock l(&g_gmock_mutex);
|
||||
Assert(name_ != NULL, __FILE__, __LINE__,
|
||||
"Name() must not be called before SetOwnerAndName() has "
|
||||
"been called.");
|
||||
name = name_;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
// Calculates the result of invoking this mock function with the given
|
||||
// arguments, prints it, and returns it. The caller is responsible
|
||||
// for deleting the result.
|
||||
// L < g_gmock_mutex
|
||||
const UntypedActionResultHolderBase*
|
||||
UntypedFunctionMockerBase::UntypedInvokeWith(const void* const untyped_args) {
|
||||
if (untyped_expectations_.size() == 0) {
|
||||
// No expectation is set on this mock method - we have an
|
||||
// uninteresting call.
|
||||
|
||||
// We must get Google Mock's reaction on uninteresting calls
|
||||
// made on this mock object BEFORE performing the action,
|
||||
// because the action may DELETE the mock object and make the
|
||||
// following expression meaningless.
|
||||
const CallReaction reaction =
|
||||
Mock::GetReactionOnUninterestingCalls(MockObject());
|
||||
|
||||
// True 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 this->UntypedPerformDefaultAction(untyped_args, "");
|
||||
}
|
||||
|
||||
// Warns about the uninteresting call.
|
||||
::std::stringstream ss;
|
||||
this->UntypedDescribeUninterestingCall(untyped_args, &ss);
|
||||
|
||||
// Calculates the function result.
|
||||
const UntypedActionResultHolderBase* const result =
|
||||
this->UntypedPerformDefaultAction(untyped_args, ss.str());
|
||||
|
||||
// Prints the function result.
|
||||
if (result != NULL)
|
||||
result->PrintAsActionResult(&ss);
|
||||
|
||||
ReportUninterestingCall(reaction, ss.str());
|
||||
return result;
|
||||
}
|
||||
|
||||
bool is_excessive = false;
|
||||
::std::stringstream ss;
|
||||
::std::stringstream why;
|
||||
::std::stringstream loc;
|
||||
const void* untyped_action = NULL;
|
||||
|
||||
// The UntypedFindMatchingExpectation() function acquires and
|
||||
// releases g_gmock_mutex.
|
||||
const ExpectationBase* const untyped_expectation =
|
||||
this->UntypedFindMatchingExpectation(
|
||||
untyped_args, &untyped_action, &is_excessive,
|
||||
&ss, &why);
|
||||
const bool found = untyped_expectation != NULL;
|
||||
|
||||
// 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
|
||||
untyped_action == NULL ?
|
||||
this->UntypedPerformDefaultAction(untyped_args, "") :
|
||||
this->UntypedPerformAction(untyped_action, untyped_args);
|
||||
}
|
||||
|
||||
ss << " Function call: " << Name();
|
||||
this->UntypedPrintArgs(untyped_args, &ss);
|
||||
|
||||
// In case the action deletes a piece of the expectation, we
|
||||
// generate the message beforehand.
|
||||
if (found && !is_excessive) {
|
||||
untyped_expectation->DescribeLocationTo(&loc);
|
||||
}
|
||||
|
||||
const UntypedActionResultHolderBase* const result =
|
||||
untyped_action == NULL ?
|
||||
this->UntypedPerformDefaultAction(untyped_args, ss.str()) :
|
||||
this->UntypedPerformAction(untyped_action, untyped_args);
|
||||
if (result != NULL)
|
||||
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, untyped_expectation->file(),
|
||||
untyped_expectation->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;
|
||||
}
|
||||
|
||||
// Returns an Expectation object that references and co-owns exp,
|
||||
// which must be an expectation on this mock function.
|
||||
Expectation UntypedFunctionMockerBase::GetHandleOf(ExpectationBase* exp) {
|
||||
for (UntypedExpectations::const_iterator it =
|
||||
untyped_expectations_.begin();
|
||||
it != untyped_expectations_.end(); ++it) {
|
||||
if (it->get() == exp) {
|
||||
return Expectation(*it);
|
||||
}
|
||||
}
|
||||
|
||||
Assert(false, __FILE__, __LINE__, "Cannot find expectation.");
|
||||
return Expectation();
|
||||
// The above statement is just to make the code compile, and will
|
||||
// never be executed.
|
||||
}
|
||||
|
||||
// Verifies that all expectations on this mock function have been
|
||||
// satisfied. Reports one or more Google Test non-fatal failures
|
||||
// and returns false if not.
|
||||
// L >= g_gmock_mutex
|
||||
bool UntypedFunctionMockerBase::VerifyAndClearExpectationsLocked() {
|
||||
g_gmock_mutex.AssertHeld();
|
||||
bool expectations_met = true;
|
||||
for (UntypedExpectations::const_iterator it =
|
||||
untyped_expectations_.begin();
|
||||
it != untyped_expectations_.end(); ++it) {
|
||||
ExpectationBase* const untyped_expectation = it->get();
|
||||
if (untyped_expectation->IsOverSaturated()) {
|
||||
// There was an upper-bound violation. Since the error was
|
||||
// already reported when it occurred, there is no need to do
|
||||
// anything here.
|
||||
expectations_met = false;
|
||||
} else if (!untyped_expectation->IsSatisfied()) {
|
||||
expectations_met = false;
|
||||
::std::stringstream ss;
|
||||
ss << "Actual function call count doesn't match "
|
||||
<< untyped_expectation->source_text() << "...\n";
|
||||
// No need to show the source file location of the expectation
|
||||
// in the description, as the Expect() call that follows already
|
||||
// takes care of it.
|
||||
untyped_expectation->MaybeDescribeExtraMatcherTo(&ss);
|
||||
untyped_expectation->DescribeCallCountTo(&ss);
|
||||
Expect(false, untyped_expectation->file(),
|
||||
untyped_expectation->line(), ss.str());
|
||||
}
|
||||
}
|
||||
untyped_expectations_.clear();
|
||||
return expectations_met;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Class Mock.
|
||||
|
@ -190,7 +523,6 @@ class MockObjectRegistry {
|
|||
// object alive. Therefore we report any living object as test
|
||||
// failure, unless the user explicitly asked us to ignore it.
|
||||
~MockObjectRegistry() {
|
||||
|
||||
// "using ::std::cout;" doesn't work with Symbian's STLport, where cout is
|
||||
// a macro.
|
||||
|
||||
|
|
|
@ -334,8 +334,7 @@ class MyActionImpl : public ActionInterface<MyFunction> {
|
|||
|
||||
TEST(ActionInterfaceTest, CanBeImplementedByDefiningPerform) {
|
||||
MyActionImpl my_action_impl;
|
||||
|
||||
EXPECT_FALSE(my_action_impl.IsDoDefault());
|
||||
(void)my_action_impl;
|
||||
}
|
||||
|
||||
TEST(ActionInterfaceTest, MakeAction) {
|
||||
|
|
|
@ -103,6 +103,34 @@ using testing::internal::CaptureStdout;
|
|||
using testing::internal::GetCapturedStdout;
|
||||
#endif
|
||||
|
||||
class Incomplete;
|
||||
|
||||
class MockIncomplete {
|
||||
public:
|
||||
// This line verifies that a mock method can take a by-reference
|
||||
// argument of an incomplete type.
|
||||
MOCK_METHOD1(ByRefFunc, void(const Incomplete& x));
|
||||
};
|
||||
|
||||
// Tells Google Mock how to print a value of type Incomplete.
|
||||
void PrintTo(const Incomplete& x, ::std::ostream* os);
|
||||
|
||||
TEST(MockMethodTest, CanInstantiateWithIncompleteArgType) {
|
||||
// Even though this mock class contains a mock method that takes
|
||||
// by-reference an argument whose type is incomplete, we can still
|
||||
// use the mock, as long as Google Mock knows how to print the
|
||||
// argument.
|
||||
MockIncomplete incomplete;
|
||||
EXPECT_CALL(incomplete, ByRefFunc(_))
|
||||
.Times(AnyNumber());
|
||||
}
|
||||
|
||||
// The definition of the printer for the argument type doesn't have to
|
||||
// be visible where the mock is used.
|
||||
void PrintTo(const Incomplete& /* x */, ::std::ostream* os) {
|
||||
*os << "incomplete";
|
||||
}
|
||||
|
||||
class Result {};
|
||||
|
||||
class MockA {
|
||||
|
@ -1327,12 +1355,33 @@ TEST(SequenceTest, Retirement) {
|
|||
TEST(ExpectationTest, ConstrutorsWork) {
|
||||
MockA a;
|
||||
Expectation e1; // Default ctor.
|
||||
Expectation e2 = EXPECT_CALL(a, DoA(1)); // Ctor from EXPECT_CALL.
|
||||
Expectation e3 = e2; // Copy ctor.
|
||||
|
||||
// Ctor from various forms of EXPECT_CALL.
|
||||
Expectation e2 = EXPECT_CALL(a, DoA(2));
|
||||
Expectation e3 = EXPECT_CALL(a, DoA(3)).With(_);
|
||||
{
|
||||
Sequence s;
|
||||
Expectation e4 = EXPECT_CALL(a, DoA(4)).Times(1);
|
||||
Expectation e5 = EXPECT_CALL(a, DoA(5)).InSequence(s);
|
||||
}
|
||||
Expectation e6 = EXPECT_CALL(a, DoA(6)).After(e2);
|
||||
Expectation e7 = EXPECT_CALL(a, DoA(7)).WillOnce(Return());
|
||||
Expectation e8 = EXPECT_CALL(a, DoA(8)).WillRepeatedly(Return());
|
||||
Expectation e9 = EXPECT_CALL(a, DoA(9)).RetiresOnSaturation();
|
||||
|
||||
Expectation e10 = e2; // Copy ctor.
|
||||
|
||||
EXPECT_THAT(e1, Ne(e2));
|
||||
EXPECT_THAT(e2, Eq(e3));
|
||||
a.DoA(1);
|
||||
EXPECT_THAT(e2, Eq(e10));
|
||||
|
||||
a.DoA(2);
|
||||
a.DoA(3);
|
||||
a.DoA(4);
|
||||
a.DoA(5);
|
||||
a.DoA(6);
|
||||
a.DoA(7);
|
||||
a.DoA(8);
|
||||
a.DoA(9);
|
||||
}
|
||||
|
||||
TEST(ExpectationTest, AssignmentWorks) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user