diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index f88ac80d..af3483f7 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -59,9 +59,6 @@ namespace testing { namespace internal { -template -class MonomorphicDoDefaultActionImpl; - template class ActionAdaptor; @@ -255,8 +252,7 @@ class ActionInterface { typedef typename internal::Function::Result Result; typedef typename internal::Function::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 - 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* impl) : impl_(impl) {} // Copy constructor. @@ -316,7 +299,7 @@ class Action { explicit Action(const Action& 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 -class MonomorphicDoDefaultActionImpl : public ActionInterface { - public: - typedef typename Function::Result Result; - typedef typename Function::ArgumentTuple ArgumentTuple; - - MonomorphicDoDefaultActionImpl() : ActionInterface(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(); - // 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 - operator Action() const { - return Action(new MonomorphicDoDefaultActionImpl); - } + operator Action() const { return Action(NULL); } }; // Implements the Assign action to set a given pointer referent to a diff --git a/include/gmock/gmock-generated-function-mockers.h b/include/gmock/gmock-generated-function-mockers.h index 7b334e42..509d46cb 100644 --- a/include/gmock/gmock-generated-function-mockers.h +++ b/include/gmock/gmock-generated-function-mockers.h @@ -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& \ 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 GMOCK_MOCKER_(0, constness, Method) @@ -367,8 +370,8 @@ using internal::FunctionMocker; } \ ::testing::MockSpec& \ 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 GMOCK_MOCKER_(1, constness, Method) @@ -385,8 +388,8 @@ using internal::FunctionMocker; ::testing::MockSpec& \ 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 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 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 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 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 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 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 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 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 GMOCK_MOCKER_(10, constness, Method) diff --git a/include/gmock/gmock-generated-function-mockers.h.pump b/include/gmock/gmock-generated-function-mockers.h.pump index 50b369bb..4f82d622 100644 --- a/include/gmock/gmock-generated-function-mockers.h.pump +++ b/include/gmock/gmock-generated-function-mockers.h.pump @@ -140,7 +140,8 @@ $var matcher_as = [[$for j, \ } \ ::testing::MockSpec& \ 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 GMOCK_MOCKER_($i, constness, Method) diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h index 4f0b0725..9e185085 100644 --- a/include/gmock/gmock-spec-builders.h +++ b/include/gmock/gmock-spec-builders.h @@ -113,53 +113,190 @@ template class FunctionMockerBase; // calls to ensure the integrity of the mock objects' states. GTEST_DECLARE_STATIC_MUTEX_(g_gmock_mutex); +// Untyped base class for ActionResultHolder. +class UntypedActionResultHolderBase; + // Abstract base class of FunctionMockerBase. This is the // type-agnostic part of the function mocker interface. Its pure // virtual methods are implemented by FunctionMockerBase. class UntypedFunctionMockerBase { public: - virtual ~UntypedFunctionMockerBase() {} + UntypedFunctionMockerBase(); + virtual ~UntypedFunctionMockerBase(); // 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 - virtual bool VerifyAndClearExpectationsLocked() = 0; + bool VerifyAndClearExpectationsLocked(); // Clears the ON_CALL()s set on this mock function. // L >= g_gmock_mutex virtual void ClearDefaultActionsLocked() = 0; + + // In all of the following Untyped* functions, it's the caller's + // responsibility to guarantee the correctness of the arguments' + // types. + + // Performs the default action with the given arguments and returns + // the action's result. The call description string will be used in + // the error message to describe the call in the case the default + // action fails. + // L = * + virtual UntypedActionResultHolderBase* UntypedPerformDefaultAction( + const void* untyped_args, + const string& call_description) const = 0; + + // Performs the given action with the given arguments and returns + // the action's result. + // L = * + virtual UntypedActionResultHolderBase* UntypedPerformAction( + const void* untyped_action, + const void* untyped_args) const = 0; + + // Writes a message that the call is uninteresting (i.e. neither + // explicitly expected nor explicitly unexpected) to the given + // ostream. + // L < g_gmock_mutex + virtual void UntypedDescribeUninterestingCall(const void* untyped_args, + ::std::ostream* os) const = 0; + + // Returns the expectation that matches the given function arguments + // (or NULL is there's no match); when a match is found, + // untyped_action is set to point to the action that should be + // performed (or NULL if the action is "do default"), and + // is_excessive is modified to indicate whether the call exceeds the + // expected number. + // L < g_gmock_mutex + virtual const ExpectationBase* UntypedFindMatchingExpectation( + const void* untyped_args, + const void** untyped_action, bool* is_excessive, + ::std::ostream* what, ::std::ostream* why) = 0; + + // Prints the given function arguments to the ostream. + virtual void UntypedPrintArgs(const void* untyped_args, + ::std::ostream* os) const = 0; + + // 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. + // TODO(wan@google.com): rename to SetAndRegisterOwner(). + // L < g_gmock_mutex + void RegisterOwner(const void* mock_obj); + + // 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 SetOwnerAndName(const void* mock_obj, const char* name); + + // Returns the mock object this mock method belongs to. Must be + // called after RegisterOwner() or SetOwnerAndName() has been + // called. + // L < g_gmock_mutex + const void* MockObject() const; + + // Returns the name of this mock method. Must be called after + // SetOwnerAndName() has been called. + // L < g_gmock_mutex + const char* Name() const; + + // Returns the result of invoking this mock function with the given + // arguments. This function can be safely called from multiple + // threads concurrently. The caller is responsible for deleting the + // result. + // L < g_gmock_mutex + const UntypedActionResultHolderBase* UntypedInvokeWith( + const void* untyped_args); + + protected: + typedef std::vector UntypedOnCallSpecs; + + typedef std::vector > + UntypedExpectations; + + // Returns an Expectation object that references and co-owns exp, + // which must be an expectation on this mock function. + Expectation GetHandleOf(ExpectationBase* exp); + + // Address of the mock object this mock method belongs to. Only + // valid after this mock method has been called or + // ON_CALL/EXPECT_CALL has been invoked on it. + const void* mock_obj_; // Protected by g_gmock_mutex. + + // Name of the function being mocked. Only valid after this mock + // method has been called. + const char* name_; // Protected by g_gmock_mutex. + + // All default action specs for this function mocker. + UntypedOnCallSpecs untyped_on_call_specs_; + + // All expectations for this function mocker. + UntypedExpectations untyped_expectations_; }; // class UntypedFunctionMockerBase -// This template class implements a default action spec (i.e. an -// ON_CALL() statement). -template -class DefaultActionSpec { +// Untyped base class for OnCallSpec. +class UntypedOnCallSpecBase { public: - typedef typename Function::ArgumentTuple ArgumentTuple; - typedef typename Function::ArgumentMatcherTuple ArgumentMatcherTuple; - - // Constructs a DefaultActionSpec object from the information inside - // the parenthesis of an ON_CALL() statement. - DefaultActionSpec(const char* a_file, int a_line, - const ArgumentMatcherTuple& matchers) - : file_(a_file), - line_(a_line), - matchers_(matchers), - // By default, extra_matcher_ should match anything. However, - // we cannot initialize it with _ as that triggers a compiler - // bug in Symbian's C++ compiler (cannot decide between two - // overloaded constructors of Matcher). - extra_matcher_(A()), - last_clause_(kNone) { - } + // The arguments are the location of the ON_CALL() statement. + UntypedOnCallSpecBase(const char* a_file, int a_line) + : file_(a_file), line_(a_line), last_clause_(kNone) {} // Where in the source file was the default action spec defined? const char* file() const { return file_; } int line() const { return line_; } + protected: + // Gives each clause in the ON_CALL() statement a name. + enum Clause { + // Do not change the order of the enum members! The run-time + // syntax checking relies on it. + kNone, + kWith, + kWillByDefault, + }; + + // Asserts that the ON_CALL() statement has a certain property. + void AssertSpecProperty(bool property, const string& failure_message) const { + Assert(property, file_, line_, failure_message); + } + + // Expects that the ON_CALL() statement has a certain property. + void ExpectSpecProperty(bool property, const string& failure_message) const { + Expect(property, file_, line_, failure_message); + } + + const char* file_; + int line_; + + // The last clause in the ON_CALL() statement as seen so far. + // Initially kNone and changes as the statement is parsed. + Clause last_clause_; +}; // class UntypedOnCallSpecBase + +// This template class implements an ON_CALL spec. +template +class OnCallSpec : public UntypedOnCallSpecBase { + public: + typedef typename Function::ArgumentTuple ArgumentTuple; + typedef typename Function::ArgumentMatcherTuple ArgumentMatcherTuple; + + // Constructs an OnCallSpec object from the information inside + // the parenthesis of an ON_CALL() statement. + OnCallSpec(const char* a_file, int a_line, + const ArgumentMatcherTuple& matchers) + : UntypedOnCallSpecBase(a_file, a_line), + matchers_(matchers), + // By default, extra_matcher_ should match anything. However, + // we cannot initialize it with _ as that triggers a compiler + // bug in Symbian's C++ compiler (cannot decide between two + // overloaded constructors of Matcher). + extra_matcher_(A()) { + } + // Implements the .With() clause. - DefaultActionSpec& With(const Matcher& m) { + OnCallSpec& With(const Matcher& m) { // Makes sure this is called at most once. ExpectSpecProperty(last_clause_ < kWith, ".With() cannot appear " @@ -171,7 +308,7 @@ class DefaultActionSpec { } // Implements the .WillByDefault() clause. - DefaultActionSpec& WillByDefault(const Action& action) { + OnCallSpec& WillByDefault(const Action& action) { ExpectSpecProperty(last_clause_ < kWillByDefault, ".WillByDefault() must appear " "exactly once in an ON_CALL()."); @@ -197,25 +334,6 @@ class DefaultActionSpec { } private: - // Gives each clause in the ON_CALL() statement a name. - enum Clause { - // Do not change the order of the enum members! The run-time - // syntax checking relies on it. - kNone, - kWith, - kWillByDefault, - }; - - // Asserts that the ON_CALL() statement has a certain property. - void AssertSpecProperty(bool property, const string& failure_message) const { - Assert(property, file_, line_, failure_message); - } - - // Expects that the ON_CALL() statement has a certain property. - void ExpectSpecProperty(bool property, const string& failure_message) const { - Expect(property, file_, line_, failure_message); - } - // The information in statement // // ON_CALL(mock_object, Method(matchers)) @@ -229,16 +347,10 @@ class DefaultActionSpec { // matchers => matchers_ // multi-argument-matcher => extra_matcher_ // action => action_ - const char* file_; - int line_; ArgumentMatcherTuple matchers_; Matcher extra_matcher_; Action action_; - - // The last clause in the ON_CALL() statement as seen so far. - // Initially kNone and changes as the statement is parsed. - Clause last_clause_; -}; // class DefaultActionSpec +}; // class OnCallSpec // Possible reactions on uninteresting calls. TODO(wan@google.com): // rename the enum values to the kFoo style. @@ -269,6 +381,8 @@ class Mock { // verification was successful. static bool VerifyAndClear(void* mock_obj); private: + friend class internal::UntypedFunctionMockerBase; + // Needed for a function mocker to register itself (so that we know // how to clear a mock object). template @@ -389,6 +503,7 @@ class Expectation { friend class ExpectationSet; friend class Sequence; friend class ::testing::internal::ExpectationBase; + friend class ::testing::internal::UntypedFunctionMockerBase; template friend class ::testing::internal::FunctionMockerBase; @@ -581,10 +696,15 @@ class ExpectationBase { // Describes how many times a function call matching this // expectation has occurred. // L >= g_gmock_mutex - virtual void DescribeCallCountTo(::std::ostream* os) const = 0; + void DescribeCallCountTo(::std::ostream* os) const; + + // If this mock method has an extra matcher (i.e. .With(matcher)), + // describes it to the ostream. + virtual void MaybeDescribeExtraMatcherTo(::std::ostream* os) = 0; protected: friend class ::testing::Expectation; + friend class UntypedFunctionMockerBase; enum Clause { // Don't change the order of the enum members! @@ -598,6 +718,8 @@ class ExpectationBase { kRetiresOnSaturation, }; + typedef std::vector UntypedActions; + // Returns an Expectation object that references and co-owns this // expectation. virtual Expectation GetHandle() = 0; @@ -690,13 +812,22 @@ class ExpectationBase { call_count_++; } - private: + // 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 CheckActionCountIfNotDone() const; + friend class ::testing::Sequence; friend class ::testing::internal::ExpectationTester; template friend class TypedExpectation; + // Implements the .Times() clause. + void UntypedTimes(const Cardinality& a_cardinality); + // This group of fields are part of the spec and won't change after // an EXPECT_CALL() statement finishes. const char* file_; // The file that contains the expectation. @@ -717,6 +848,13 @@ class ExpectationBase { // and can change as the mock function is called. int call_count_; // How many times this expectation has been invoked. bool retired_; // True iff this expectation has retired. + UntypedActions untyped_actions_; + bool extra_matcher_specified_; + bool repeated_action_specified_; // True if a WillRepeatedly() was specified. + bool retires_on_saturation_; + Clause last_clause_; + mutable bool action_count_checked_; // Under mutex_. + mutable Mutex mutex_; // Protects action_count_checked_. GTEST_DISALLOW_ASSIGN_(ExpectationBase); }; // class ExpectationBase @@ -735,22 +873,21 @@ class TypedExpectation : public ExpectationBase { : ExpectationBase(a_file, a_line, a_source_text), owner_(owner), matchers_(m), - extra_matcher_specified_(false), // By default, extra_matcher_ should match anything. However, // we cannot initialize it with _ as that triggers a compiler // bug in Symbian's C++ compiler (cannot decide between two // overloaded constructors of Matcher). extra_matcher_(A()), - repeated_action_specified_(false), - repeated_action_(DoDefault()), - retires_on_saturation_(false), - last_clause_(kNone), - action_count_checked_(false) {} + repeated_action_(DoDefault()) {} 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(); + for (UntypedActions::const_iterator it = untyped_actions_.begin(); + it != untyped_actions_.end(); ++it) { + delete static_cast*>(*it); + } } // Implements the .With() clause. @@ -773,19 +910,7 @@ class TypedExpectation : public ExpectationBase { // Implements the .Times() clause. TypedExpectation& Times(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; - - ExpectationBase::SpecifyCardinality(a_cardinality); + ExpectationBase::UntypedTimes(a_cardinality); return *this; } @@ -859,9 +984,9 @@ class TypedExpectation : public ExpectationBase { ".WillRepeatedly() or .RetiresOnSaturation()."); last_clause_ = kWillOnce; - actions_.push_back(action); + untyped_actions_.push_back(new Action(action)); if (!cardinality_specified()) { - set_cardinality(Exactly(static_cast(actions_.size()))); + set_cardinality(Exactly(static_cast(untyped_actions_.size()))); } return *this; } @@ -882,7 +1007,7 @@ class TypedExpectation : public ExpectationBase { repeated_action_ = action; if (!cardinality_specified()) { - set_cardinality(AtLeast(static_cast(actions_.size()))); + set_cardinality(AtLeast(static_cast(untyped_actions_.size()))); } // Now that no more action clauses can be specified, we check @@ -916,38 +1041,12 @@ class TypedExpectation : public ExpectationBase { return extra_matcher_; } - // Returns the sequence of actions specified by the .WillOnce() clause. - const std::vector >& actions() const { return actions_; } - // Returns the action specified by the .WillRepeatedly() clause. const Action& repeated_action() const { return repeated_action_; } - // Returns true iff the .RetiresOnSaturation() clause was specified. - bool retires_on_saturation() const { return retires_on_saturation_; } - - // Describes how many times a function call matching this - // expectation has occurred (implements - // ExpectationBase::DescribeCallCountTo()). - // L >= g_gmock_mutex - virtual void 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"); - } - - void MaybeDescribeExtraMatcherTo(::std::ostream* os) { + // If this mock method has an extra matcher (i.e. .With(matcher)), + // describes it to the ostream. + virtual void MaybeDescribeExtraMatcherTo(::std::ostream* os) { if (extra_matcher_specified_) { *os << " Expected args: "; extra_matcher_.DescribeTo(os); @@ -1044,7 +1143,7 @@ class TypedExpectation : public ExpectationBase { "call_count() is <= 0 when GetCurrentAction() is " "called - this should never happen."); - const int action_count = static_cast(actions().size()); + const int action_count = static_cast(untyped_actions_.size()); if (action_count > 0 && !repeated_action_specified_ && count > action_count) { // If there is at least one WillOnce() and no WillRepeatedly(), @@ -1059,7 +1158,9 @@ class TypedExpectation : public ExpectationBase { Log(WARNING, ss.str(), 1); } - return count <= action_count ? actions()[count - 1] : repeated_action(); + return count <= action_count ? + *static_cast*>(untyped_actions_[count - 1]) : + repeated_action(); } // Given the arguments of a mock function call, if the call will @@ -1067,12 +1168,13 @@ class TypedExpectation : public ExpectationBase { // otherwise, returns the next action in this expectation. Also // describes *what* happened to 'what', and explains *why* Google // Mock does it to 'why'. This method is not const as it calls - // IncrementCallCount(). + // IncrementCallCount(). A return value of NULL means the default + // action. // L >= g_gmock_mutex - Action GetActionForArguments(const FunctionMockerBase* mocker, - const ArgumentTuple& args, - ::std::ostream* what, - ::std::ostream* why) { + const Action* GetActionForArguments(const FunctionMockerBase* mocker, + const ArgumentTuple& args, + ::std::ostream* what, + ::std::ostream* why) { g_gmock_mutex.AssertHeld(); if (IsSaturated()) { // We have an excessive call. @@ -1081,92 +1183,30 @@ class TypedExpectation : public ExpectationBase { mocker->DescribeDefaultActionTo(args, what); DescribeCallCountTo(why); - // TODO(wan): allow the user to control whether unexpected calls - // should fail immediately or continue using a flag - // --gmock_unexpected_calls_are_fatal. - return DoDefault(); + // TODO(wan@google.com): allow the user to control whether + // unexpected calls should fail immediately or continue using a + // flag --gmock_unexpected_calls_are_fatal. + return NULL; } IncrementCallCount(); RetireAllPreRequisites(); - if (retires_on_saturation() && IsSaturated()) { + if (retires_on_saturation_ && IsSaturated()) { Retire(); } // Must be done after IncrementCount()! *what << "Mock function call matches " << source_text() <<"...\n"; - return GetCurrentAction(mocker, args); - } - - // 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 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(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". - } + return &(GetCurrentAction(mocker, args)); } // All the fields below won't change once the EXPECT_CALL() // statement finishes. FunctionMockerBase* const owner_; ArgumentMatcherTuple matchers_; - bool extra_matcher_specified_; Matcher extra_matcher_; - std::vector > actions_; - bool repeated_action_specified_; // True if a WillRepeatedly() was specified. Action repeated_action_; - bool retires_on_saturation_; - Clause last_clause_; - mutable bool action_count_checked_; // Under mutex_. - mutable Mutex mutex_; // Protects action_count_checked_. GTEST_DISALLOW_COPY_AND_ASSIGN_(TypedExpectation); }; // class TypedExpectation @@ -1181,6 +1221,11 @@ class TypedExpectation : public ExpectationBase { // template. To workaround this compiler bug, we define MockSpec in // ::testing::internal and import it into ::testing. +// Logs a message including file and line number information. +void LogWithLocation(testing::internal::LogSeverity severity, + const char* file, int line, + const string& message); + template class MockSpec { public: @@ -1195,11 +1240,11 @@ class MockSpec { // Adds a new default action spec to the function mocker and returns // the newly created spec. - internal::DefaultActionSpec& InternalDefaultActionSetAt( + internal::OnCallSpec& InternalDefaultActionSetAt( const char* file, int line, const char* obj, const char* call) { LogWithLocation(internal::INFO, file, line, string("ON_CALL(") + obj + ", " + call + ") invoked"); - return function_mocker_->AddNewDefaultActionSpec(file, line, matchers_); + return function_mocker_->AddNewOnCallSpec(file, line, matchers_); } // Adds a new expectation spec to the function mocker and returns @@ -1220,15 +1265,6 @@ class MockSpec { matchers_ = matchers; } - // 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); - } - // The function mocker that owns this spec. internal::FunctionMockerBase* const function_mocker_; // The argument matchers specified in the spec. @@ -1253,42 +1289,58 @@ class MockSpec { // 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. +// non-void-returning mock functions. + +// Untyped base class for ActionResultHolder. +class UntypedActionResultHolderBase { + public: + virtual ~UntypedActionResultHolderBase() {} + + // Prints the held value as an action's result to os. + virtual void PrintAsActionResult(::std::ostream* os) const = 0; +}; + +// This generic definition is used when T is not void. template -class ActionResultHolder { +class ActionResultHolder : public UntypedActionResultHolderBase { public: explicit ActionResultHolder(T a_value) : value_(a_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_; } + // Returns the held value and deletes this object. + T GetValueAndDelete() const { + T retval(value_); + delete this; + return retval; + } // Prints the held value as an action's result to os. - void PrintAsActionResult(::std::ostream* os) const { + virtual void PrintAsActionResult(::std::ostream* os) const { *os << "\n Returns: "; // T may be a reference type, so we don't use UniversalPrint(). UniversalPrinter::Print(value_, os); } // Performs the given mock function's default action and returns the - // result in a ActionResultHolder. - template - static ActionResultHolder PerformDefaultAction( - const FunctionMockerBase* func_mocker, - const Arguments& args, + // result in a new-ed ActionResultHolder. + template + static ActionResultHolder* PerformDefaultAction( + const FunctionMockerBase* func_mocker, + const typename Function::ArgumentTuple& args, const string& call_description) { - return ActionResultHolder( + return new ActionResultHolder( func_mocker->PerformDefaultAction(args, call_description)); } - // Performs the given action and returns the result in a + // Performs the given action and returns the result in a new-ed // ActionResultHolder. - template - static ActionResultHolder PerformAction(const Action& action, - const Arguments& args) { - return ActionResultHolder(action.Perform(args)); + template + static ActionResultHolder* + PerformAction(const Action& action, + const typename Function::ArgumentTuple& args) { + return new ActionResultHolder(action.Perform(args)); } private: @@ -1300,26 +1352,29 @@ class ActionResultHolder { // Specialization for T = void. template <> -class ActionResultHolder { +class ActionResultHolder : public UntypedActionResultHolderBase { public: - ActionResultHolder() {} - void value() const {} - void PrintAsActionResult(::std::ostream* /* os */) const {} + void GetValueAndDelete() const { delete this; } - template - static ActionResultHolder PerformDefaultAction( - const FunctionMockerBase* func_mocker, - const Arguments& args, + virtual void PrintAsActionResult(::std::ostream* /* os */) const {} + + // Performs the given mock function's default action and returns NULL; + template + static ActionResultHolder* PerformDefaultAction( + const FunctionMockerBase* func_mocker, + const typename Function::ArgumentTuple& args, const string& call_description) { func_mocker->PerformDefaultAction(args, call_description); - return ActionResultHolder(); + return NULL; } - template - static ActionResultHolder PerformAction(const Action& action, - const Arguments& args) { + // Performs the given action and returns NULL. + template + static ActionResultHolder* PerformAction( + const Action& action, + const typename Function::ArgumentTuple& args) { action.Perform(args); - return ActionResultHolder(); + return NULL; } }; @@ -1333,7 +1388,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { typedef typename Function::ArgumentTuple ArgumentTuple; typedef typename Function::ArgumentMatcherTuple ArgumentMatcherTuple; - FunctionMockerBase() : mock_obj_(NULL), name_(""), current_spec_(this) {} + FunctionMockerBase() : current_spec_(this) {} // The destructor verifies that all expectations on this mock // function have been satisfied. If not, it will report Google Test @@ -1343,19 +1398,20 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { MutexLock l(&g_gmock_mutex); VerifyAndClearExpectationsLocked(); Mock::UnregisterLocked(this); + ClearDefaultActionsLocked(); } // Returns the ON_CALL spec that matches this mock function with the // given arguments; returns NULL if no matching ON_CALL is found. // L = * - const DefaultActionSpec* FindDefaultActionSpec( + const OnCallSpec* FindOnCallSpec( const ArgumentTuple& args) const { - for (typename std::vector >::const_reverse_iterator it - = default_actions_.rbegin(); - it != default_actions_.rend(); ++it) { - const DefaultActionSpec& spec = *it; - if (spec.Matches(args)) - return &spec; + for (UntypedOnCallSpecs::const_reverse_iterator it + = untyped_on_call_specs_.rbegin(); + it != untyped_on_call_specs_.rend(); ++it) { + const OnCallSpec* spec = static_cast*>(*it); + if (spec->Matches(args)) + return spec; } return NULL; @@ -1368,7 +1424,8 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // L = * Result PerformDefaultAction(const ArgumentTuple& args, const string& call_description) const { - const DefaultActionSpec* const spec = FindDefaultActionSpec(args); + const OnCallSpec* const spec = + this->FindOnCallSpec(args); if (spec != NULL) { return spec->GetAction().Perform(args); } @@ -1378,91 +1435,70 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { return DefaultValue::Get(); } - // Registers this function mocker and the mock object owning it; - // returns a reference to the function mocker object. This is only - // called by the ON_CALL() and EXPECT_CALL() macros. - // L < g_gmock_mutex - FunctionMocker& RegisterOwner(const void* mock_obj) { - { - MutexLock l(&g_gmock_mutex); - mock_obj_ = mock_obj; - } - Mock::Register(mock_obj, this); - return *::testing::internal::DownCast_*>(this); + // Performs the default action with the given arguments and returns + // the action's result. The call description string will be used in + // the error message to describe the call in the case the default + // action fails. The caller is responsible for deleting the result. + // L = * + virtual UntypedActionResultHolderBase* UntypedPerformDefaultAction( + const void* untyped_args, // must point to an ArgumentTuple + const string& call_description) const { + const ArgumentTuple& args = + *static_cast(untyped_args); + return ResultHolder::PerformDefaultAction(this, args, call_description); } - // The following two functions are from UntypedFunctionMockerBase. + // Performs the given action with the given arguments and returns + // the action's result. The caller is responsible for deleting the + // result. + // L = * + virtual UntypedActionResultHolderBase* UntypedPerformAction( + const void* untyped_action, const void* untyped_args) const { + // Make a copy of the action before performing it, in case the + // action deletes the mock object (and thus deletes itself). + const Action action = *static_cast*>(untyped_action); + const ArgumentTuple& args = + *static_cast(untyped_args); + return ResultHolder::PerformAction(action, args); + } - // 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 - virtual bool VerifyAndClearExpectationsLocked(); - - // Clears the ON_CALL()s set on this mock function. + // Implements UntypedFunctionMockerBase::ClearDefaultActionsLocked(): + // clears the ON_CALL()s set on this mock function. // L >= g_gmock_mutex virtual void ClearDefaultActionsLocked() { g_gmock_mutex.AssertHeld(); - default_actions_.clear(); - } - - // Sets the name of the function being mocked. Will be called upon - // each invocation of this mock function. - // L < g_gmock_mutex - void 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 address of the mock object this method belongs to. - // Must be called after SetOwnerAndName() has been called. - // L < g_gmock_mutex - const void* 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); - mock_obj = mock_obj_; + for (UntypedOnCallSpecs::const_iterator it = + untyped_on_call_specs_.begin(); + it != untyped_on_call_specs_.end(); ++it) { + delete static_cast*>(*it); } - return mock_obj; - } - - // Returns the name of the function being mocked. Must be called - // after SetOwnerAndName() has been called. - // L < g_gmock_mutex - const char* 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); - name = name_; - } - return name; + untyped_on_call_specs_.clear(); } protected: template friend class MockSpec; + typedef ActionResultHolder ResultHolder; + // Returns the result of invoking this mock function with the given // arguments. This function can be safely called from multiple // threads concurrently. // L < g_gmock_mutex - Result InvokeWith(const ArgumentTuple& args); + Result InvokeWith(const ArgumentTuple& args) { + return static_cast( + this->UntypedInvokeWith(&args))->GetValueAndDelete(); + } // Adds and returns a default action spec for this mock function. // L < g_gmock_mutex - DefaultActionSpec& AddNewDefaultActionSpec( + OnCallSpec& AddNewOnCallSpec( const char* file, int line, const ArgumentMatcherTuple& m) { Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line); - default_actions_.push_back(DefaultActionSpec(file, line, m)); - return default_actions_.back(); + OnCallSpec* const on_call_spec = new OnCallSpec(file, line, m); + untyped_on_call_specs_.push_back(on_call_spec); + return *on_call_spec; } // Adds and returns an expectation spec for this mock function. @@ -1473,14 +1509,15 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { const string& source_text, const ArgumentMatcherTuple& m) { Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line); - const linked_ptr > expectation( - new TypedExpectation(this, file, line, source_text, m)); - expectations_.push_back(expectation); + TypedExpectation* const expectation = + new TypedExpectation(this, file, line, source_text, m); + const linked_ptr untyped_expectation(expectation); + untyped_expectations_.push_back(untyped_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(expectation)); + implicit_sequence->AddExpectation(Expectation(untyped_expectation)); } return *expectation; @@ -1493,33 +1530,14 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { private: template friend class TypedExpectation; - typedef std::vector > > - TypedExpectations; - - // Returns an Expectation object that references and co-owns exp, - // which must be an expectation on this mock function. - Expectation GetHandleOf(TypedExpectation* exp) { - for (typename TypedExpectations::const_iterator it = expectations_.begin(); - it != 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. - } - - // Some utilities needed for implementing InvokeWith(). + // Some utilities needed for implementing UntypedInvokeWith(). // Describes what default action will be performed for the given // arguments. // L = * void DescribeDefaultActionTo(const ArgumentTuple& args, ::std::ostream* os) const { - const DefaultActionSpec* const spec = FindDefaultActionSpec(args); + const OnCallSpec* const spec = FindOnCallSpec(args); if (spec == NULL) { *os << (internal::type_equals::value ? @@ -1535,14 +1553,23 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // explicitly expected nor explicitly unexpected) to the given // ostream. // L < g_gmock_mutex - void DescribeUninterestingCall(const ArgumentTuple& args, - ::std::ostream* os) const { + virtual void UntypedDescribeUninterestingCall(const void* untyped_args, + ::std::ostream* os) const { + const ArgumentTuple& args = + *static_cast(untyped_args); *os << "Uninteresting mock function call - "; DescribeDefaultActionTo(args, os); *os << " Function call: " << Name(); UniversalPrint(args, os); } + // Returns the expectation that matches the given function arguments + // (or NULL is there's no match); when a match is found, + // untyped_action is set to point to the action that should be + // performed (or NULL if the action is "do default"), and + // is_excessive is modified to indicate whether the call exceeds the + // expected number. + // // Critical section: We must find the matching expectation and the // corresponding action that needs to be taken in an ATOMIC // transaction. Otherwise another thread may call this mock @@ -1553,23 +1580,36 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // action does (it can invoke an arbitrary user function or even a // mock function) and excessive locking could cause a dead lock. // L < g_gmock_mutex - bool FindMatchingExpectationAndAction( - const ArgumentTuple& args, TypedExpectation** exp, Action* action, - bool* is_excessive, ::std::ostream* what, ::std::ostream* why) { + virtual const ExpectationBase* UntypedFindMatchingExpectation( + const void* untyped_args, + const void** untyped_action, bool* is_excessive, + ::std::ostream* what, ::std::ostream* why) { + const ArgumentTuple& args = + *static_cast(untyped_args); MutexLock l(&g_gmock_mutex); - *exp = this->FindMatchingExpectationLocked(args); - if (*exp == NULL) { // A match wasn't found. - *action = DoDefault(); + TypedExpectation* exp = this->FindMatchingExpectationLocked(args); + if (exp == NULL) { // A match wasn't found. this->FormatUnexpectedCallMessageLocked(args, what, why); - return false; + return NULL; } // This line must be done before calling GetActionForArguments(), // which will increment the call count for *exp and thus affect // its saturation status. - *is_excessive = (*exp)->IsSaturated(); - *action = (*exp)->GetActionForArguments(this, args, what, why); - return true; + *is_excessive = exp->IsSaturated(); + const Action* action = exp->GetActionForArguments(this, args, what, why); + if (action != NULL && action->IsDoDefault()) + action = NULL; // Normalize "do default" to NULL. + *untyped_action = action; + return exp; + } + + // Prints the given function arguments to the ostream. + virtual void UntypedPrintArgs(const void* untyped_args, + ::std::ostream* os) const { + const ArgumentTuple& args = + *static_cast(untyped_args); + UniversalPrint(args, os); } // Returns the expectation that matches the arguments, or NULL if no @@ -1578,10 +1618,11 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { TypedExpectation* FindMatchingExpectationLocked( const ArgumentTuple& args) const { g_gmock_mutex.AssertHeld(); - for (typename TypedExpectations::const_reverse_iterator it = - expectations_.rbegin(); - it != expectations_.rend(); ++it) { - TypedExpectation* const exp = it->get(); + for (typename UntypedExpectations::const_reverse_iterator it = + untyped_expectations_.rbegin(); + it != untyped_expectations_.rend(); ++it) { + TypedExpectation* const exp = + static_cast*>(it->get()); if (exp->ShouldHandleArguments(args)) { return exp; } @@ -1606,41 +1647,29 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { void PrintTriedExpectationsLocked(const ArgumentTuple& args, ::std::ostream* why) const { g_gmock_mutex.AssertHeld(); - const int count = static_cast(expectations_.size()); + const int count = static_cast(untyped_expectations_.size()); *why << "Google Mock tried the following " << count << " " << (count == 1 ? "expectation, but it didn't match" : "expectations, but none matched") << ":\n"; for (int i = 0; i < count; i++) { + TypedExpectation* const expectation = + static_cast*>(untyped_expectations_[i].get()); *why << "\n"; - expectations_[i]->DescribeLocationTo(why); + expectation->DescribeLocationTo(why); if (count > 1) { *why << "tried expectation #" << i << ": "; } - *why << expectations_[i]->source_text() << "...\n"; - expectations_[i]->ExplainMatchResultTo(args, why); - expectations_[i]->DescribeCallCountTo(why); + *why << expectation->source_text() << "...\n"; + expectation->ExplainMatchResultTo(args, why); + expectation->DescribeCallCountTo(why); } } - // Address of the mock object this mock method belongs to. Only - // valid after this mock method has been called or - // ON_CALL/EXPECT_CALL has been invoked on it. - const void* mock_obj_; // Protected by g_gmock_mutex. - - // Name of the function being mocked. Only valid after this mock - // method has been called. - const char* name_; // Protected by g_gmock_mutex. - // The current spec (either default action spec or expectation spec) // being described on this function mocker. MockSpec current_spec_; - // All default action specs for this function mocker. - std::vector > default_actions_; - // All expectations for this function mocker. - TypedExpectations expectations_; - // There is no generally useful and implementable semantics of // copying a mock object, so copying a mock is usually a user error. // Thus we disallow copying function mockers. If the user really @@ -1666,144 +1695,11 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // satisfied. Reports one or more Google Test non-fatal failures and // returns false if not. // L >= g_gmock_mutex -template -bool FunctionMockerBase::VerifyAndClearExpectationsLocked() { - g_gmock_mutex.AssertHeld(); - bool expectations_met = true; - for (typename TypedExpectations::const_iterator it = expectations_.begin(); - it != expectations_.end(); ++it) { - TypedExpectation* const exp = it->get(); - - if (exp->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 (!exp->IsSatisfied()) { - expectations_met = false; - ::std::stringstream ss; - ss << "Actual function call count doesn't match " - << exp->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. - exp->MaybeDescribeExtraMatcherTo(&ss); - exp->DescribeCallCountTo(&ss); - Expect(false, exp->file(), exp->line(), ss.str()); - } - } - expectations_.clear(); - return expectations_met; -} // Reports an uninteresting call (whose description is in msg) in the // manner specified by 'reaction'. void ReportUninterestingCall(CallReaction reaction, const string& msg); -// Calculates the result of invoking this mock function with the given -// arguments, prints it, and returns it. -// L < g_gmock_mutex -template -typename Function::Result FunctionMockerBase::InvokeWith( - const typename Function::ArgumentTuple& args) { - typedef ActionResultHolder ResultHolder; - - if (expectations_.size() == 0) { - // No expectation is set on this mock method - we have an - // uninteresting call. - - // We must get Google Mock's reaction on uninteresting calls - // made on this mock object BEFORE performing the action, - // because the action may DELETE the mock object and make the - // following expression meaningless. - const CallReaction reaction = - Mock::GetReactionOnUninterestingCalls(MockObject()); - - // True iff we need to print this call's arguments and return - // value. This definition must be kept in sync with - // the behavior of ReportUninterestingCall(). - const bool need_to_report_uninteresting_call = - // If the user allows this uninteresting call, we print it - // only when he wants informational messages. - reaction == ALLOW ? LogIsVisible(INFO) : - // If the user wants this to be a warning, we print it only - // when he wants to see warnings. - reaction == WARN ? LogIsVisible(WARNING) : - // Otherwise, the user wants this to be an error, and we - // should always print detailed information in the error. - true; - - if (!need_to_report_uninteresting_call) { - // Perform the action without printing the call information. - return PerformDefaultAction(args, ""); - } - - // Warns about the uninteresting call. - ::std::stringstream ss; - DescribeUninterestingCall(args, &ss); - - // Calculates the function result. - const ResultHolder result = - ResultHolder::PerformDefaultAction(this, args, ss.str()); - - // Prints the function result. - result.PrintAsActionResult(&ss); - - ReportUninterestingCall(reaction, ss.str()); - return result.value(); - } - - bool is_excessive = false; - ::std::stringstream ss; - ::std::stringstream why; - ::std::stringstream loc; - Action action; - TypedExpectation* exp; - - // The FindMatchingExpectationAndAction() function acquires and - // releases g_gmock_mutex. - const bool found = FindMatchingExpectationAndAction( - args, &exp, &action, &is_excessive, &ss, &why); - - // True iff we need to print the call's arguments and return value. - // This definition must be kept in sync with the uses of Expect() - // and Log() in this function. - const bool need_to_report_call = !found || is_excessive || LogIsVisible(INFO); - if (!need_to_report_call) { - // Perform the action without printing the call information. - return action.IsDoDefault() ? PerformDefaultAction(args, "") : - action.Perform(args); - } - - ss << " Function call: " << Name(); - UniversalPrint(args, &ss); - - // In case the action deletes a piece of the expectation, we - // generate the message beforehand. - if (found && !is_excessive) { - exp->DescribeLocationTo(&loc); - } - - const ResultHolder result = action.IsDoDefault() ? - ResultHolder::PerformDefaultAction(this, args, ss.str()) : - ResultHolder::PerformAction(action, args); - result.PrintAsActionResult(&ss); - ss << "\n" << why.str(); - - if (!found) { - // No expectation matches this call - reports a failure. - Expect(false, NULL, -1, ss.str()); - } else if (is_excessive) { - // We had an upper-bound violation and the failure message is in ss. - Expect(false, exp->file(), exp->line(), ss.str()); - } else { - // We had an expected call and the matching expectation is - // described in ss. - Log(INFO, loc.str() + ss.str(), 2); - } - return result.value(); -} - } // namespace internal // The style guide prohibits "using" statements in a namespace scope diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py index f7932b5e..ab923efb 100755 --- a/scripts/gmock_doctor.py +++ b/scripts/gmock_doctor.py @@ -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 diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc index 0d40d9cd..a99caef2 100644 --- a/src/gmock-spec-builders.cc +++ b/src/gmock-spec-builders.cc @@ -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(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 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. diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index e12402b9..b3f8d52b 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -334,8 +334,7 @@ class MyActionImpl : public ActionInterface { TEST(ActionInterfaceTest, CanBeImplementedByDefiningPerform) { MyActionImpl my_action_impl; - - EXPECT_FALSE(my_action_impl.IsDoDefault()); + (void)my_action_impl; } TEST(ActionInterfaceTest, MakeAction) { diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index 737bcfff..aea5228b 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -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) {