|
|
|
@ -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.
|
|
|
|
|
|
|
|
|
|