summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzhanyong.wan <zhanyong.wan@8415998a-534a-0410-bf83-d39667b30386>2009-07-01 19:04:51 +0000
committerzhanyong.wan <zhanyong.wan@8415998a-534a-0410-bf83-d39667b30386>2009-07-01 19:04:51 +0000
commit6564a60f4e2a97f1e24878b5f9701ecb822849b3 (patch)
treed5f7c699eab323243a6ac854e1d1fb77cc22cf0b
parent427f193dc0b7a580e78c6170a86087ac02afecf5 (diff)
downloadgooglemock-6564a60f4e2a97f1e24878b5f9701ecb822849b3.tar.gz
Implements Expectation, ExpectationSet, and After for specifying expectation orders.
git-svn-id: http://googlemock.googlecode.com/svn/trunk@179 8415998a-534a-0410-bf83-d39667b30386
-rw-r--r--include/gmock/gmock-spec-builders.h350
-rw-r--r--src/gmock-spec-builders.cc34
-rw-r--r--test/gmock-spec-builders_test.cc322
3 files changed, 606 insertions, 100 deletions
diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h
index a22bcd1..0748d9d 100644
--- a/include/gmock/gmock-spec-builders.h
+++ b/include/gmock/gmock-spec-builders.h
@@ -49,13 +49,13 @@
// .With(multi-argument-matchers)
// .Times(cardinality)
// .InSequence(sequences)
+// .After(expectations)
// .WillOnce(action)
// .WillRepeatedly(action)
// .RetiresOnSaturation();
//
-// where all clauses are optional, .InSequence() and .WillOnce() can
-// appear any number of times, and .Times() can be omitted only if
-// .WillOnce() or .WillRepeatedly() is present.
+// where all clauses are optional, and .InSequence()/.After()/
+// .WillOnce() can appear any number of times.
#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
#define GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
@@ -76,22 +76,30 @@
namespace testing {
+// An abstract handle of an expectation.
+class Expectation;
+
+// A set of expectation handles.
+class ExpectationSet;
+
// Anything inside the 'internal' namespace IS INTERNAL IMPLEMENTATION
// and MUST NOT BE USED IN USER CODE!!!
namespace internal {
-template <typename F>
-class FunctionMocker;
+// Implements a mock function.
+template <typename F> class FunctionMocker;
// Base class for expectations.
class ExpectationBase;
+// Implements an expectation.
+template <typename F> class TypedExpectation;
+
// Helper class for testing the Expectation class template.
class ExpectationTester;
// Base class for function mockers.
-template <typename F>
-class FunctionMockerBase;
+template <typename F> class FunctionMockerBase;
// Protects the mock object registry (in class Mock), all function
// mockers, and all expectations.
@@ -232,7 +240,8 @@ class DefaultActionSpec {
Clause last_clause_;
}; // class DefaultActionSpec
-// Possible reactions on uninteresting calls.
+// Possible reactions on uninteresting calls. TODO(wan@google.com):
+// rename the enum values to the kFoo style.
enum CallReaction {
ALLOW,
WARN,
@@ -327,31 +336,166 @@ class Mock {
static void UnregisterLocked(internal::UntypedFunctionMockerBase* mocker);
}; // class Mock
+// An abstract handle of an expectation. Useful in the .After()
+// clause of EXPECT_CALL() for setting the (partial) order of
+// expectations. The syntax:
+//
+// Expectation e1 = EXPECT_CALL(...)...;
+// EXPECT_CALL(...).After(e1)...;
+//
+// sets two expectations where the latter can only be matched after
+// the former has been satisfied.
+//
+// Notes:
+// - This class is copyable and has value semantics.
+// - Constness is shallow: a const Expectation object itself cannot
+// be modified, but the mutable methods of the ExpectationBase
+// object it references can be called via expectation_base().
+class Expectation {
+ public:
+ // Constructs a null object that doesn't reference any expectation.
+ Expectation() {}
+
+ // This single-argument ctor must not be explicit, in order to support the
+ // Expectation e = EXPECT_CALL(...);
+ // syntax.
+ //
+ // A TypedExpectation object stores its pre-requisites as
+ // Expectation objects, and needs to call the non-const Retire()
+ // method on the ExpectationBase objects they reference. Therefore
+ // Expectation must receive a *non-const* reference to the
+ // ExpectationBase object.
+ Expectation(internal::ExpectationBase& exp); // NOLINT
+
+ // The compiler-generated copy ctor and operator= work exactly as
+ // intended, so we don't need to define our own.
+
+ // Returns true iff rhs references the same expectation as this object does.
+ bool operator==(const Expectation& rhs) const {
+ return expectation_base_ == rhs.expectation_base_;
+ }
+
+ bool operator!=(const Expectation& rhs) const { return !(*this == rhs); }
+
+ private:
+ friend class ExpectationSet;
+ friend class Sequence;
+ friend class ::testing::internal::ExpectationBase;
+
+ template <typename F>
+ friend class ::testing::internal::FunctionMockerBase;
+
+ template <typename F>
+ friend class ::testing::internal::TypedExpectation;
+
+ // This comparator is needed for putting Expectation objects into a set.
+ class Less {
+ public:
+ bool operator()(const Expectation& lhs, const Expectation& rhs) const {
+ return lhs.expectation_base_.get() < rhs.expectation_base_.get();
+ }
+ };
+
+ typedef ::std::set<Expectation, Less> Set;
+
+ Expectation(
+ const internal::linked_ptr<internal::ExpectationBase>& expectation_base) :
+ expectation_base_(expectation_base) {}
+
+ // Returns the expectation this object references.
+ const internal::linked_ptr<internal::ExpectationBase>&
+ expectation_base() const {
+ return expectation_base_;
+ }
+
+ // A linked_ptr that co-owns the expectation this handle references.
+ internal::linked_ptr<internal::ExpectationBase> expectation_base_;
+};
+
+// A set of expectation handles. Useful in the .After() clause of
+// EXPECT_CALL() for setting the (partial) order of expectations. The
+// syntax:
+//
+// ExpectationSet es;
+// es += EXPECT_CALL(...)...;
+// es += EXPECT_CALL(...)...;
+// EXPECT_CALL(...).After(es)...;
+//
+// sets three expectations where the last one can only be matched
+// after the first two have both been satisfied.
+//
+// This class is copyable and has value semantics.
+class ExpectationSet {
+ public:
+ // A bidirectional iterator that can read a const element in the set.
+ typedef Expectation::Set::const_iterator const_iterator;
+
+ // An object stored in the set. This is an alias of Expectation.
+ typedef Expectation::Set::value_type value_type;
+
+ // Constructs an empty set.
+ ExpectationSet() {}
+
+ // This single-argument ctor must not be explicit, in order to support the
+ // ExpectationSet es = EXPECT_CALL(...);
+ // syntax.
+ ExpectationSet(internal::ExpectationBase& exp) { // NOLINT
+ *this += Expectation(exp);
+ }
+
+ // This single-argument ctor implements implicit conversion from
+ // Expectation and thus must not be explicit. This allows either an
+ // Expectation or an ExpectationSet to be used in .After().
+ ExpectationSet(const Expectation& e) { // NOLINT
+ *this += e;
+ }
+
+ // The compiler-generator ctor and operator= works exactly as
+ // intended, so we don't need to define our own.
+
+ // Returns true iff rhs contains the same set of Expectation objects
+ // as this does.
+ bool operator==(const ExpectationSet& rhs) const {
+ return expectations_ == rhs.expectations_;
+ }
+
+ bool operator!=(const ExpectationSet& rhs) const { return !(*this == rhs); }
+
+ // Implements the syntax
+ // expectation_set += EXPECT_CALL(...);
+ ExpectationSet& operator+=(const Expectation& e) {
+ expectations_.insert(e);
+ return *this;
+ }
+
+ int size() const { return static_cast<int>(expectations_.size()); }
+
+ const_iterator begin() const { return expectations_.begin(); }
+ const_iterator end() const { return expectations_.end(); }
+
+ private:
+ Expectation::Set expectations_;
+};
+
+
// Sequence objects are used by a user to specify the relative order
// in which the expectations should match. They are copyable (we rely
// on the compiler-defined copy constructor and assignment operator).
class Sequence {
public:
// Constructs an empty sequence.
- Sequence()
- : last_expectation_(
- new internal::linked_ptr<internal::ExpectationBase>(NULL)) {}
+ Sequence() : last_expectation_(new Expectation) {}
// Adds an expectation to this sequence. The caller must ensure
// that no other thread is accessing this Sequence object.
- void AddExpectation(
- const internal::linked_ptr<internal::ExpectationBase>& expectation) const;
+ void AddExpectation(const Expectation& expectation) const;
+
private:
- // The last expectation in this sequence. We use a nested
- // linked_ptr here because:
- // - Sequence objects are copyable, and we want the copies to act
- // as aliases. The outer linked_ptr allows the copies to co-own
- // and share the same state.
- // - An Expectation object is co-owned (via linked_ptr) by its
- // FunctionMocker and its successors (other Expectation objects).
- // Hence the inner linked_ptr.
- internal::linked_ptr<internal::linked_ptr<internal::ExpectationBase> >
- last_expectation_;
+ // The last expectation in this sequence. We use a linked_ptr here
+ // because Sequence objects are copyable and we want the copies to
+ // be aliases. The linked_ptr allows the copies to co-own and share
+ // the same Expectation object.
+ internal::linked_ptr<Expectation> last_expectation_;
}; // class Sequence
// An object of this type causes all EXPECT_CALL() statements
@@ -431,9 +575,7 @@ class ExpectationBase {
// L >= g_gmock_mutex
virtual void DescribeCallCountTo(::std::ostream* os) const = 0;
protected:
- typedef std::set<linked_ptr<ExpectationBase>,
- LinkedPtrLessThan<ExpectationBase> >
- ExpectationBaseSet;
+ friend class ::testing::Expectation;
enum Clause {
// Don't change the order of the enum members!
@@ -441,11 +583,16 @@ class ExpectationBase {
kWith,
kTimes,
kInSequence,
+ kAfter,
kWillOnce,
kWillRepeatedly,
kRetiresOnSaturation,
};
+ // Returns an Expectation object that references and co-owns this
+ // expectation.
+ virtual Expectation GetHandle() = 0;
+
// Asserts that the EXPECT_CALL() statement has the given property.
void AssertSpecProperty(bool property, const string& failure_message) const {
Assert(property, file_, line_, failure_message);
@@ -518,7 +665,7 @@ class ExpectationBase {
// Adds unsatisfied pre-requisites of this expectation to 'result'.
// L >= g_gmock_mutex
- void FindUnsatisfiedPrerequisites(ExpectationBaseSet* result) const;
+ void FindUnsatisfiedPrerequisites(ExpectationSet* result) const;
// Returns the number this expectation has been invoked.
// L >= g_gmock_mutex
@@ -539,7 +686,7 @@ class ExpectationBase {
friend class ::testing::internal::ExpectationTester;
template <typename Function>
- friend class Expectation;
+ friend class TypedExpectation;
// This group of fields are part of the spec and won't change after
// an EXPECT_CALL() statement finishes.
@@ -548,11 +695,13 @@ class ExpectationBase {
// True iff the cardinality is specified explicitly.
bool cardinality_specified_;
Cardinality cardinality_; // The cardinality of the expectation.
- // The immediate pre-requisites of this expectation. We use
- // linked_ptr in the set because we want an Expectation object to be
- // co-owned by its FunctionMocker and its successors. This allows
- // multiple mock objects to be deleted at different times.
- ExpectationBaseSet immediate_prerequisites_;
+ // The immediate pre-requisites (i.e. expectations that must be
+ // satisfied before this expectation can be matched) of this
+ // expectation. We use linked_ptr in the set because we want an
+ // Expectation object to be co-owned by its FunctionMocker and its
+ // successors. This allows multiple mock objects to be deleted at
+ // different times.
+ ExpectationSet immediate_prerequisites_;
// This group of fields are the current state of the expectation,
// and can change as the mock function is called.
@@ -562,14 +711,14 @@ class ExpectationBase {
// Impements an expectation for the given function type.
template <typename F>
-class Expectation : public ExpectationBase {
+class TypedExpectation : public ExpectationBase {
public:
typedef typename Function<F>::ArgumentTuple ArgumentTuple;
typedef typename Function<F>::ArgumentMatcherTuple ArgumentMatcherTuple;
typedef typename Function<F>::Result Result;
- Expectation(FunctionMockerBase<F>* owner, const char* file, int line,
- const ArgumentMatcherTuple& m)
+ TypedExpectation(FunctionMockerBase<F>* owner, const char* file, int line,
+ const ArgumentMatcherTuple& m)
: ExpectationBase(file, line),
owner_(owner),
matchers_(m),
@@ -584,14 +733,14 @@ class Expectation : public ExpectationBase {
last_clause_(kNone),
action_count_checked_(false) {}
- virtual ~Expectation() {
+ virtual ~TypedExpectation() {
// Check the validity of the action count if it hasn't been done
// yet (for example, if the expectation was never used).
CheckActionCountIfNotDone();
}
// Implements the .With() clause.
- Expectation& With(const Matcher<const ArgumentTuple&>& m) {
+ TypedExpectation& With(const Matcher<const ArgumentTuple&>& m) {
if (last_clause_ == kWith) {
ExpectSpecProperty(false,
".With() cannot appear "
@@ -608,7 +757,7 @@ class Expectation : public ExpectationBase {
}
// Implements the .Times() clause.
- Expectation& Times(const Cardinality& cardinality) {
+ TypedExpectation& Times(const Cardinality& cardinality) {
if (last_clause_ ==kTimes) {
ExpectSpecProperty(false,
".Times() cannot appear "
@@ -626,40 +775,70 @@ class Expectation : public ExpectationBase {
}
// Implements the .Times() clause.
- Expectation& Times(int n) {
+ TypedExpectation& Times(int n) {
return Times(Exactly(n));
}
// Implements the .InSequence() clause.
- Expectation& InSequence(const Sequence& s) {
+ TypedExpectation& InSequence(const Sequence& s) {
ExpectSpecProperty(last_clause_ <= kInSequence,
- ".InSequence() cannot appear after .WillOnce(),"
- " .WillRepeatedly(), or "
+ ".InSequence() cannot appear after .After(),"
+ " .WillOnce(), .WillRepeatedly(), or "
".RetiresOnSaturation().");
last_clause_ = kInSequence;
- s.AddExpectation(owner_->GetLinkedExpectationBase(this));
+ s.AddExpectation(GetHandle());
return *this;
}
- Expectation& InSequence(const Sequence& s1, const Sequence& s2) {
+ TypedExpectation& InSequence(const Sequence& s1, const Sequence& s2) {
return InSequence(s1).InSequence(s2);
}
- Expectation& InSequence(const Sequence& s1, const Sequence& s2,
- const Sequence& s3) {
+ TypedExpectation& InSequence(const Sequence& s1, const Sequence& s2,
+ const Sequence& s3) {
return InSequence(s1, s2).InSequence(s3);
}
- Expectation& InSequence(const Sequence& s1, const Sequence& s2,
- const Sequence& s3, const Sequence& s4) {
+ TypedExpectation& InSequence(const Sequence& s1, const Sequence& s2,
+ const Sequence& s3, const Sequence& s4) {
return InSequence(s1, s2, s3).InSequence(s4);
}
- Expectation& InSequence(const Sequence& s1, const Sequence& s2,
- const Sequence& s3, const Sequence& s4,
- const Sequence& s5) {
+ TypedExpectation& InSequence(const Sequence& s1, const Sequence& s2,
+ const Sequence& s3, const Sequence& s4,
+ const Sequence& s5) {
return InSequence(s1, s2, s3, s4).InSequence(s5);
}
+ // Implements that .After() clause.
+ TypedExpectation& After(const ExpectationSet& s) {
+ ExpectSpecProperty(last_clause_ <= kAfter,
+ ".After() cannot appear after .WillOnce(),"
+ " .WillRepeatedly(), or "
+ ".RetiresOnSaturation().");
+ last_clause_ = kAfter;
+
+ for (ExpectationSet::const_iterator it = s.begin(); it != s.end(); ++it) {
+ immediate_prerequisites_ += *it;
+ }
+ return *this;
+ }
+ TypedExpectation& After(const ExpectationSet& s1, const ExpectationSet& s2) {
+ return After(s1).After(s2);
+ }
+ TypedExpectation& After(const ExpectationSet& s1, const ExpectationSet& s2,
+ const ExpectationSet& s3) {
+ return After(s1, s2).After(s3);
+ }
+ TypedExpectation& After(const ExpectationSet& s1, const ExpectationSet& s2,
+ const ExpectationSet& s3, const ExpectationSet& s4) {
+ return After(s1, s2, s3).After(s4);
+ }
+ TypedExpectation& After(const ExpectationSet& s1, const ExpectationSet& s2,
+ const ExpectationSet& s3, const ExpectationSet& s4,
+ const ExpectationSet& s5) {
+ return After(s1, s2, s3, s4).After(s5);
+ }
+
// Implements the .WillOnce() clause.
- Expectation& WillOnce(const Action<F>& action) {
+ TypedExpectation& WillOnce(const Action<F>& action) {
ExpectSpecProperty(last_clause_ <= kWillOnce,
".WillOnce() cannot appear after "
".WillRepeatedly() or .RetiresOnSaturation().");
@@ -673,7 +852,7 @@ class Expectation : public ExpectationBase {
}
// Implements the .WillRepeatedly() clause.
- Expectation& WillRepeatedly(const Action<F>& action) {
+ TypedExpectation& WillRepeatedly(const Action<F>& action) {
if (last_clause_ == kWillRepeatedly) {
ExpectSpecProperty(false,
".WillRepeatedly() cannot appear "
@@ -698,7 +877,7 @@ class Expectation : public ExpectationBase {
}
// Implements the .RetiresOnSaturation() clause.
- Expectation& RetiresOnSaturation() {
+ TypedExpectation& RetiresOnSaturation() {
ExpectSpecProperty(last_clause_ < kRetiresOnSaturation,
".RetiresOnSaturation() cannot appear "
"more than once.");
@@ -756,6 +935,12 @@ class Expectation : public ExpectationBase {
template <typename Function>
friend class FunctionMockerBase;
+ // Returns an Expectation object that references and co-owns this
+ // expectation.
+ virtual Expectation GetHandle() {
+ return owner_->GetHandleOf(this);
+ }
+
// The following methods will be called only after the EXPECT_CALL()
// statement finishes and when the current thread holds
// g_gmock_mutex.
@@ -807,12 +992,12 @@ class Expectation : public ExpectationBase {
*os << " Expected: all pre-requisites are satisfied\n"
<< " Actual: the following immediate pre-requisites "
<< "are not satisfied:\n";
- ExpectationBaseSet unsatisfied_prereqs;
+ ExpectationSet unsatisfied_prereqs;
FindUnsatisfiedPrerequisites(&unsatisfied_prereqs);
int i = 0;
- for (ExpectationBaseSet::const_iterator it = unsatisfied_prereqs.begin();
+ for (ExpectationSet::const_iterator it = unsatisfied_prereqs.begin();
it != unsatisfied_prereqs.end(); ++it) {
- (*it)->DescribeLocationTo(os);
+ it->expectation_base()->DescribeLocationTo(os);
*os << "pre-requisite #" << i++ << "\n";
}
*os << " (end of pre-requisites)\n";
@@ -957,7 +1142,7 @@ class Expectation : public ExpectationBase {
Clause last_clause_;
mutable bool action_count_checked_; // Under mutex_.
mutable Mutex mutex_; // Protects action_count_checked_.
-}; // class Expectation
+}; // class TypedExpectation
// A MockSpec object is used by ON_CALL() or EXPECT_CALL() for
// specifying the default behavior of, or expectation on, a mock
@@ -992,7 +1177,7 @@ class MockSpec {
// Adds a new expectation spec to the function mocker and returns
// the newly created spec.
- internal::Expectation<F>& InternalExpectedAt(
+ internal::TypedExpectation<F>& InternalExpectedAt(
const char* file, int line, const char* obj, const char* call) {
LogWithLocation(internal::INFO, file, line,
string("EXPECT_CALL(") + obj + ", " + call + ") invoked");
@@ -1247,18 +1432,18 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
// Adds and returns an expectation spec for this mock function.
// L < g_gmock_mutex
- Expectation<F>& AddNewExpectation(
+ TypedExpectation<F>& AddNewExpectation(
const char* file, int line,
const ArgumentMatcherTuple& m) {
Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line);
- const linked_ptr<Expectation<F> > expectation(
- new Expectation<F>(this, file, line, m));
+ const linked_ptr<TypedExpectation<F> > expectation(
+ new TypedExpectation<F>(this, file, line, m));
expectations_.push_back(expectation);
// Adds this expectation into the implicit sequence if there is one.
Sequence* const implicit_sequence = g_gmock_implicit_sequence.get();
if (implicit_sequence != NULL) {
- implicit_sequence->AddExpectation(expectation);
+ implicit_sequence->AddExpectation(Expectation(expectation));
}
return *expectation;
@@ -1268,22 +1453,23 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
// being described on this function mocker.
MockSpec<F>& current_spec() { return current_spec_; }
private:
- template <typename Func> friend class Expectation;
+ template <typename Func> friend class TypedExpectation;
- typedef std::vector<internal::linked_ptr<Expectation<F> > > Expectations;
+ typedef std::vector<internal::linked_ptr<TypedExpectation<F> > >
+ TypedExpectations;
- // Gets the internal::linked_ptr<ExpectationBase> object that co-owns 'exp'.
- internal::linked_ptr<ExpectationBase> GetLinkedExpectationBase(
- Expectation<F>* exp) {
- for (typename Expectations::const_iterator it = expectations_.begin();
+ // Returns an Expectation object that references and co-owns exp,
+ // which must be an expectation on this mock function.
+ Expectation GetHandleOf(TypedExpectation<F>* exp) {
+ for (typename TypedExpectations::const_iterator it = expectations_.begin();
it != expectations_.end(); ++it) {
if (it->get() == exp) {
- return *it;
+ return Expectation(*it);
}
}
Assert(false, __FILE__, __LINE__, "Cannot find expectation.");
- return internal::linked_ptr<ExpectationBase>(NULL);
+ return Expectation();
// The above statement is just to make the code compile, and will
// never be executed.
}
@@ -1330,7 +1516,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
// mock function) and excessive locking could cause a dead lock.
// L < g_gmock_mutex
bool FindMatchingExpectationAndAction(
- const ArgumentTuple& args, Expectation<F>** exp, Action<F>* action,
+ const ArgumentTuple& args, TypedExpectation<F>** exp, Action<F>* action,
bool* is_excessive, ::std::ostream* what, ::std::ostream* why) {
MutexLock l(&g_gmock_mutex);
*exp = this->FindMatchingExpectationLocked(args);
@@ -1351,13 +1537,13 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
// Returns the expectation that matches the arguments, or NULL if no
// expectation matches them.
// L >= g_gmock_mutex
- Expectation<F>* FindMatchingExpectationLocked(
+ TypedExpectation<F>* FindMatchingExpectationLocked(
const ArgumentTuple& args) const {
g_gmock_mutex.AssertHeld();
- for (typename Expectations::const_reverse_iterator it =
+ for (typename TypedExpectations::const_reverse_iterator it =
expectations_.rbegin();
it != expectations_.rend(); ++it) {
- Expectation<F>* const exp = it->get();
+ TypedExpectation<F>* const exp = it->get();
if (exp->ShouldHandleArguments(args)) {
return exp;
}
@@ -1415,7 +1601,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
// All default action specs for this function mocker.
std::vector<DefaultActionSpec<F> > default_actions_;
// All expectations for this function mocker.
- Expectations expectations_;
+ TypedExpectations expectations_;
// There is no generally useful and implementable semantics of
// copying a mock object, so copying a mock is usually a user error.
@@ -1446,9 +1632,9 @@ template <typename F>
bool FunctionMockerBase<F>::VerifyAndClearExpectationsLocked() {
g_gmock_mutex.AssertHeld();
bool expectations_met = true;
- for (typename Expectations::const_iterator it = expectations_.begin();
+ for (typename TypedExpectations::const_iterator it = expectations_.begin();
it != expectations_.end(); ++it) {
- Expectation<F>* const exp = it->get();
+ TypedExpectation<F>* const exp = it->get();
if (exp->IsOverSaturated()) {
// There was an upper-bound violation. Since the error was
@@ -1532,7 +1718,7 @@ typename Function<F>::Result FunctionMockerBase<F>::InvokeWith(
::std::stringstream why;
::std::stringstream loc;
Action<F> action;
- Expectation<F>* exp;
+ TypedExpectation<F>* exp;
// The FindMatchingExpectationAndAction() function acquires and
// releases g_gmock_mutex.
@@ -1605,6 +1791,10 @@ using internal::MockSpec;
template <typename T>
inline const T& Const(const T& x) { return x; }
+// Constructs an Expectation object that references and co-owns exp.
+inline Expectation::Expectation(internal::ExpectationBase& exp) // NOLINT
+ : expectation_base_(exp.GetHandle().expectation_base()) {}
+
} // namespace testing
// A separate macro is required to avoid compile errors when the name
diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc
index 465e4d6..00d1691 100644
--- a/src/gmock-spec-builders.cc
+++ b/src/gmock-spec-builders.cc
@@ -82,11 +82,9 @@ void ExpectationBase::RetireAllPreRequisites() {
return;
}
- for (ExpectationBaseSet::const_iterator it =
- immediate_prerequisites_.begin();
- it != immediate_prerequisites_.end();
- ++it) {
- ExpectationBase* const prerequisite = (*it).get();
+ for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin();
+ it != immediate_prerequisites_.end(); ++it) {
+ ExpectationBase* const prerequisite = it->expectation_base().get();
if (!prerequisite->is_retired()) {
prerequisite->RetireAllPreRequisites();
prerequisite->Retire();
@@ -99,10 +97,10 @@ void ExpectationBase::RetireAllPreRequisites() {
// L >= g_gmock_mutex
bool ExpectationBase::AllPrerequisitesAreSatisfied() const {
g_gmock_mutex.AssertHeld();
- for (ExpectationBaseSet::const_iterator it = immediate_prerequisites_.begin();
+ for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin();
it != immediate_prerequisites_.end(); ++it) {
- if (!(*it)->IsSatisfied() ||
- !(*it)->AllPrerequisitesAreSatisfied())
+ if (!(it->expectation_base()->IsSatisfied()) ||
+ !(it->expectation_base()->AllPrerequisitesAreSatisfied()))
return false;
}
return true;
@@ -111,21 +109,21 @@ bool ExpectationBase::AllPrerequisitesAreSatisfied() const {
// Adds unsatisfied pre-requisites of this expectation to 'result'.
// L >= g_gmock_mutex
void ExpectationBase::FindUnsatisfiedPrerequisites(
- ExpectationBaseSet* result) const {
+ ExpectationSet* result) const {
g_gmock_mutex.AssertHeld();
- for (ExpectationBaseSet::const_iterator it = immediate_prerequisites_.begin();
+ for (ExpectationSet::const_iterator it = immediate_prerequisites_.begin();
it != immediate_prerequisites_.end(); ++it) {
- if ((*it)->IsSatisfied()) {
+ if (it->expectation_base()->IsSatisfied()) {
// If *it is satisfied and has a call count of 0, some of its
// pre-requisites may not be satisfied yet.
- if ((*it)->call_count_ == 0) {
- (*it)->FindUnsatisfiedPrerequisites(result);
+ if (it->expectation_base()->call_count_ == 0) {
+ it->expectation_base()->FindUnsatisfiedPrerequisites(result);
}
} else {
// Now that we know *it is unsatisfied, we are not so interested
// in whether its pre-requisites are satisfied. Therefore we
// don't recursively call FindUnsatisfiedPrerequisites() here.
- result->insert(*it);
+ *result += *it;
}
}
}
@@ -421,11 +419,11 @@ void Mock::ClearDefaultActionsLocked(void* mock_obj) {
}
// Adds an expectation to a sequence.
-void Sequence::AddExpectation(
- const internal::linked_ptr<internal::ExpectationBase>& expectation) const {
+void Sequence::AddExpectation(const Expectation& expectation) const {
if (*last_expectation_ != expectation) {
- if (*last_expectation_ != NULL) {
- expectation->immediate_prerequisites_.insert(*last_expectation_);
+ if (last_expectation_->expectation_base() != NULL) {
+ expectation.expectation_base()->immediate_prerequisites_
+ += *last_expectation_;
}
*last_expectation_ = expectation;
}
diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc
index 614e4ab..f6c3141 100644
--- a/test/gmock-spec-builders_test.cc
+++ b/test/gmock-spec-builders_test.cc
@@ -71,6 +71,9 @@ using testing::CardinalityInterface;
using testing::Const;
using testing::DoAll;
using testing::DoDefault;
+using testing::Eq;
+using testing::Expectation;
+using testing::ExpectationSet;
using testing::GMOCK_FLAG(verbose);
using testing::Gt;
using testing::InSequence;
@@ -80,13 +83,13 @@ using testing::IsSubstring;
using testing::Lt;
using testing::Message;
using testing::Mock;
+using testing::Ne;
using testing::Return;
using testing::Sequence;
using testing::internal::g_gmock_mutex;
using testing::internal::kErrorVerbosity;
using testing::internal::kInfoVerbosity;
using testing::internal::kWarningVerbosity;
-using testing::internal::Expectation;
using testing::internal::ExpectationTester;
using testing::internal::string;
@@ -345,7 +348,22 @@ TEST(ExpectCallSyntaxTest, InSequenceCanAppearMultipleTimes) {
a.DoA(1);
}
-TEST(ExpectCallSyntaxTest, InSequenceMustBeBeforeWill) {
+TEST(ExpectCallSyntaxTest, InSequenceMustBeBeforeAfter) {
+ MockA a;
+ Sequence s;
+
+ Expectation e = EXPECT_CALL(a, DoA(1))
+ .Times(AnyNumber());
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_CALL(a, DoA(2))
+ .After(e)
+ .InSequence(s);
+ }, ".InSequence() cannot appear after ");
+
+ a.DoA(2);
+}
+
+TEST(ExpectCallSyntaxTest, InSequenceMustBeBeforeWillOnce) {
MockA a;
Sequence s;
@@ -358,6 +376,20 @@ TEST(ExpectCallSyntaxTest, InSequenceMustBeBeforeWill) {
a.DoA(1);
}
+TEST(ExpectCallSyntaxTest, AfterMustBeBeforeWillOnce) {
+ MockA a;
+
+ Expectation e = EXPECT_CALL(a, DoA(1));
+ EXPECT_NONFATAL_FAILURE({
+ EXPECT_CALL(a, DoA(2))
+ .WillOnce(Return())
+ .After(e);
+ }, ".After() cannot appear after ");
+
+ a.DoA(1);
+ a.DoA(2);
+}
+
TEST(ExpectCallSyntaxTest, WillIsOptional) {
MockA a;
@@ -1248,6 +1280,292 @@ TEST(SequenceTest, Retirement) {
a.DoA(1);
}
+// Tests Expectation.
+
+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.
+
+ EXPECT_THAT(e1, Ne(e2));
+ EXPECT_THAT(e2, Eq(e3));
+ a.DoA(1);
+}
+
+TEST(ExpectationTest, AssignmentWorks) {
+ MockA a;
+ Expectation e1;
+ Expectation e2 = EXPECT_CALL(a, DoA(1));
+
+ EXPECT_THAT(e1, Ne(e2));
+
+ e1 = e2;
+ EXPECT_THAT(e1, Eq(e2));
+
+ a.DoA(1);
+}
+
+// Tests ExpectationSet.
+
+TEST(ExpectationSetTest, MemberTypesAreCorrect) {
+ ::testing::StaticAssertTypeEq<Expectation, ExpectationSet::value_type>();
+}
+
+TEST(ExpectationSetTest, ConstructorsWork) {
+ MockA a;
+
+ Expectation e1;
+ const Expectation e2;
+ ExpectationSet es1; // Default ctor.
+ ExpectationSet es2 = EXPECT_CALL(a, DoA(1)); // Ctor from EXPECT_CALL.
+ ExpectationSet es3 = e1; // Ctor from Expectation.
+ ExpectationSet es4(e1); // Ctor from Expectation; alternative syntax.
+ ExpectationSet es5 = e2; // Ctor from const Expectation.
+ ExpectationSet es6(e2); // Ctor from const Expectation; alternative syntax.
+ ExpectationSet es7 = es2; // Copy ctor.
+
+ EXPECT_EQ(0, es1.size());
+ EXPECT_EQ(1, es2.size());
+ EXPECT_EQ(1, es3.size());
+ EXPECT_EQ(1, es4.size());
+ EXPECT_EQ(1, es5.size());
+ EXPECT_EQ(1, es6.size());
+ EXPECT_EQ(1, es7.size());
+
+ EXPECT_THAT(es3, Ne(es2));
+ EXPECT_THAT(es4, Eq(es3));
+ EXPECT_THAT(es5, Eq(es4));
+ EXPECT_THAT(es6, Eq(es5));
+ EXPECT_THAT(es7, Eq(es2));
+ a.DoA(1);
+}
+
+TEST(ExpectationSetTest, AssignmentWorks) {
+ ExpectationSet es1;
+ ExpectationSet es2 = Expectation();
+
+ es1 = es2;
+ EXPECT_EQ(1, es1.size());
+ EXPECT_THAT(*(es1.begin()), Eq(Expectation()));
+ EXPECT_THAT(es1, Eq(es2));
+}
+
+TEST(ExpectationSetTest, InsertionWorks) {
+ ExpectationSet es1;
+ Expectation e1;
+ es1 += e1;
+ EXPECT_EQ(1, es1.size());
+ EXPECT_THAT(*(es1.begin()), Eq(e1));
+
+ MockA a;
+ Expectation e2 = EXPECT_CALL(a, DoA(1));
+ es1 += e2;
+ EXPECT_EQ(2, es1.size());
+
+ ExpectationSet::const_iterator it1 = es1.begin();
+ ExpectationSet::const_iterator it2 = it1;
+ ++it2;
+ EXPECT_TRUE(*it1 == e1 || *it2 == e1); // e1 must be in the set.
+ EXPECT_TRUE(*it1 == e2 || *it2 == e2); // e2 must be in the set too.
+ a.DoA(1);
+}
+
+TEST(ExpectationSetTest, SizeWorks) {
+ ExpectationSet es;
+ EXPECT_EQ(0, es.size());
+
+ es += Expectation();
+ EXPECT_EQ(1, es.size());
+
+ MockA a;
+ es += EXPECT_CALL(a, DoA(1));
+ EXPECT_EQ(2, es.size());
+
+ a.DoA(1);
+}
+
+TEST(ExpectationSetTest, IsEnumerable) {
+ ExpectationSet es;
+ EXPECT_THAT(es.begin(), Eq(es.end()));
+
+ es += Expectation();
+ ExpectationSet::const_iterator it = es.begin();
+ EXPECT_THAT(it, Ne(es.end()));
+ EXPECT_THAT(*it, Eq(Expectation()));
+ ++it;
+ EXPECT_THAT(it, Eq(es.end()));
+}
+
+// Tests the .After() clause.
+
+TEST(AfterTest, SucceedsWhenPartialOrderIsSatisfied) {
+ MockA a;
+ ExpectationSet es;
+ es += EXPECT_CALL(a, DoA(1));
+ es += EXPECT_CALL(a, DoA(2));
+ EXPECT_CALL(a, DoA(3))
+ .After(es);
+
+ a.DoA(1);
+ a.DoA(2);
+ a.DoA(3);
+}
+
+TEST(AfterTest, SucceedsWhenTotalOrderIsSatisfied) {
+ MockA a;
+ MockB b;
+ // The following also verifies that const Expectation objects work
+ // too. Do not remove the const modifiers.
+ const Expectation e1 = EXPECT_CALL(a, DoA(1));
+ const Expectation e2 = EXPECT_CALL(b, DoB())
+ .Times(2)
+ .After(e1);
+ EXPECT_CALL(a, DoA(2)).After(e2);
+
+ a.DoA(1);
+ b.DoB();
+ b.DoB();
+ a.DoA(2);
+}
+
+// Calls must be in strict order when specified so.
+TEST(AfterTest, CallsMustBeInStrictOrderWhenSpecifiedSo) {
+ MockA a;
+ MockB b;
+ Expectation e1 = EXPECT_CALL(a, DoA(1));
+ Expectation e2 = EXPECT_CALL(b, DoB())
+ .Times(2)
+ .After(e1);
+ EXPECT_CALL(a, ReturnResult(2))
+ .After(e2)
+ .WillOnce(Return(Result()));
+
+ a.DoA(1);
+ // If a call to ReturnResult() violates the specified order, no
+ // matching expectation will be found, and thus the default action
+ // will be done. Since the return type of ReturnResult() is not a
+ // built-in type, gmock won't know what to return and will thus
+ // abort the program. Therefore a death test can tell us whether
+ // gmock catches the order violation correctly.
+ //
+ // gtest and gmock print messages to stdout, which isn't captured by
+ // death tests. Therefore we have to match with an empty regular
+ // expression in all the EXPECT_DEATH()s.
+ EXPECT_DEATH(a.ReturnResult(2), "");
+
+ b.DoB();
+ EXPECT_DEATH(a.ReturnResult(2), "");
+
+ b.DoB();
+ a.ReturnResult(2);
+}
+
+// Calls must satisfy the partial order when specified so.
+TEST(AfterTest, CallsMustSatisfyPartialOrderWhenSpecifiedSo) {
+ MockA a;
+ Expectation e = EXPECT_CALL(a, DoA(1));
+ const ExpectationSet es = EXPECT_CALL(a, DoA(2));
+ EXPECT_CALL(a, ReturnResult(3))
+ .After(e, es)
+ .WillOnce(Return(Result()));
+
+ EXPECT_DEATH(a.ReturnResult(3), "");
+
+ a.DoA(2);
+ EXPECT_DEATH(a.ReturnResult(3), "");
+
+ a.DoA(1);
+ a.ReturnResult(3);
+}
+
+// .After() can be combined with .InSequence().
+TEST(AfterTest, CanBeUsedWithInSequence) {
+ MockA a;
+ Sequence s;
+ Expectation e = EXPECT_CALL(a, DoA(1));
+ EXPECT_CALL(a, DoA(2)).InSequence(s);
+ EXPECT_CALL(a, ReturnResult(3))
+ .InSequence(s).After(e)
+ .WillOnce(Return(Result()));
+
+ a.DoA(1);
+ EXPECT_DEATH(a.ReturnResult(3), "");
+
+ a.DoA(2);
+ a.ReturnResult(3);
+}
+
+// .After() can be called multiple times.
+TEST(AfterTest, CanBeCalledManyTimes) {
+ MockA a;
+ Expectation e1 = EXPECT_CALL(a, DoA(1));
+ Expectation e2 = EXPECT_CALL(a, DoA(2));
+ Expectation e3 = EXPECT_CALL(a, DoA(3));
+ EXPECT_CALL(a, DoA(4))
+ .After(e1)
+ .After(e2)
+ .After(e3);
+
+ a.DoA(3);
+ a.DoA(1);
+ a.DoA(2);
+ a.DoA(4);
+}
+
+// .After() accepts up to 5 arguments.
+TEST(AfterTest, AcceptsUpToFiveArguments) {
+ MockA a;
+ Expectation e1 = EXPECT_CALL(a, DoA(1));
+ Expectation e2 = EXPECT_CALL(a, DoA(2));
+ Expectation e3 = EXPECT_CALL(a, DoA(3));
+ ExpectationSet es1 = EXPECT_CALL(a, DoA(4));
+ ExpectationSet es2 = EXPECT_CALL(a, DoA(5));
+ EXPECT_CALL(a, DoA(6))
+ .After(e1, e2, e3, es1, es2);
+
+ a.DoA(5);
+ a.DoA(2);
+ a.DoA(4);
+ a.DoA(1);
+ a.DoA(3);
+ a.DoA(6);
+}
+
+// .After() allows input to contain duplicated Expectations.
+TEST(AfterTest, AcceptsDuplicatedInput) {
+ MockA a;
+ Expectation e1 = EXPECT_CALL(a, DoA(1));
+ Expectation e2 = EXPECT_CALL(a, DoA(2));
+ ExpectationSet es;
+ es += e1;
+ es += e2;
+ EXPECT_CALL(a, ReturnResult(3))
+ .After(e1, e2, es, e1)
+ .WillOnce(Return(Result()));
+
+ a.DoA(1);
+ EXPECT_DEATH(a.ReturnResult(3), "");
+
+ a.DoA(2);
+ a.ReturnResult(3);
+}
+
+// An Expectation added to an ExpectationSet after it has been used in
+// an .After() has no effect.
+TEST(AfterTest, ChangesToExpectationSetHaveNoEffectAfterwards) {
+ MockA a;
+ ExpectationSet es1 = EXPECT_CALL(a, DoA(1));
+ Expectation e2 = EXPECT_CALL(a, DoA(2));
+ EXPECT_CALL(a, DoA(3))
+ .After(es1);
+ es1 += e2;
+
+ a.DoA(1);
+ a.DoA(3);
+ a.DoA(2);
+}
+
// Tests that Google Mock correctly handles calls to mock functions
// after a mock object owning one of their pre-requisites has died.