From 1c8eb1c059d6727d9fcf45864dc6efa3d844e184 Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Thu, 9 Apr 2009 07:29:58 +0000 Subject: [PATCH] Adds actions ReturnNew(...) and DeleteArg(), by Jason Hsueh. --- include/gmock/gmock-generated-actions.h | 341 +++++++++++++++++++ include/gmock/gmock-generated-actions.h.pump | 69 ++++ test/gmock-generated-actions_test.cc | 103 ++++++ 3 files changed, 513 insertions(+) diff --git a/include/gmock/gmock-generated-actions.h b/include/gmock/gmock-generated-actions.h index e3f3dc27..26308bf4 100644 --- a/include/gmock/gmock-generated-actions.h +++ b/include/gmock/gmock-generated-actions.h @@ -2320,6 +2320,240 @@ ACTION_P(SetArg0Referee, value) { arg0 = value; } +// ReturnNewAction creates and returns a new instance of an object each time +// it is performed. It is overloaded to work with constructors that take +// different numbers of arguments. +// Returns a new instance of T using a nullary constructor with the given +// arguments. +template +class ReturnNewAction0 { + public: + ReturnNewAction0() {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(); + } + private: +}; + +// Returns a new instance of T using a unary constructor with the given +// arguments. +template +class ReturnNewAction1 { + public: + explicit ReturnNewAction1(A1 a1) : arg1_(a1) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_); + } + private: + const A1 arg1_; +}; + +// Returns a new instance of T using a binary constructor with the given +// arguments. +template +class ReturnNewAction2 { + public: + ReturnNewAction2(A1 a1, A2 a2) : arg1_(a1), arg2_(a2) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_); + } + private: + const A1 arg1_; + const A2 arg2_; +}; + +// Returns a new instance of T using a ternary constructor with the given +// arguments. +template +class ReturnNewAction3 { + public: + ReturnNewAction3(A1 a1, A2 a2, A3 a3) : arg1_(a1), arg2_(a2), arg3_(a3) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; +}; + +// Returns a new instance of T using a 4-ary constructor with the given +// arguments. +template +class ReturnNewAction4 { + public: + ReturnNewAction4(A1 a1, A2 a2, A3 a3, A4 a4) : arg1_(a1), arg2_(a2), + arg3_(a3), arg4_(a4) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; +}; + +// Returns a new instance of T using a 5-ary constructor with the given +// arguments. +template +class ReturnNewAction5 { + public: + ReturnNewAction5(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : arg1_(a1), arg2_(a2), + arg3_(a3), arg4_(a4), arg5_(a5) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_, arg5_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; +}; + +// Returns a new instance of T using a 6-ary constructor with the given +// arguments. +template +class ReturnNewAction6 { + public: + ReturnNewAction6(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : arg1_(a1), + arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), arg6_(a6) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; +}; + +// Returns a new instance of T using a 7-ary constructor with the given +// arguments. +template +class ReturnNewAction7 { + public: + ReturnNewAction7(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, + A7 a7) : arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), + arg6_(a6), arg7_(a7) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; + const A7 arg7_; +}; + +// Returns a new instance of T using a 8-ary constructor with the given +// arguments. +template +class ReturnNewAction8 { + public: + ReturnNewAction8(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, + A8 a8) : arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), + arg6_(a6), arg7_(a7), arg8_(a8) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; + const A7 arg7_; + const A8 arg8_; +}; + +// Returns a new instance of T using a 9-ary constructor with the given +// arguments. +template +class ReturnNewAction9 { + public: + ReturnNewAction9(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, + A9 a9) : arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), + arg6_(a6), arg7_(a7), arg8_(a8), arg9_(a9) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_, arg9_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; + const A7 arg7_; + const A8 arg8_; + const A9 arg9_; +}; + +// Returns a new instance of T using a 10-ary constructor with the given +// arguments. +template +class ReturnNewAction10 { + public: + ReturnNewAction10(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, + A9 a9, A10 a10) : arg1_(a1), arg2_(a2), arg3_(a3), arg4_(a4), arg5_(a5), + arg6_(a6), arg7_(a7), arg8_(a8), arg9_(a9), arg10_(a10) {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_, arg7_, arg8_, arg9_, + arg10_); + } + private: + const A1 arg1_; + const A2 arg2_; + const A3 arg3_; + const A4 arg4_; + const A5 arg5_; + const A6 arg6_; + const A7 arg7_; + const A8 arg8_; + const A9 arg9_; + const A10 arg10_; +}; + +// Deletes the object pointed to by argument #0. +ACTION(DeleteArg0) { delete arg0; } + } // namespace internal // Action SaveArg(pointer) saves the k-th (0-based) argument of the @@ -2338,6 +2572,113 @@ SetArgReferee(const Value& value) { return WithArg(internal::SetArg0Referee(value)); } +// Various overloads for ReturnNew(). +// +// The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new +// instance of type T, constructed on the heap with constructor arguments +// a1, a2, ..., and a_k. The caller assumes ownership of the returned value. +template +inline PolymorphicAction > +ReturnNew() { + return MakePolymorphicAction( + internal::ReturnNewAction0()); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1) { + return MakePolymorphicAction( + internal::ReturnNewAction1(a1)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2) { + return MakePolymorphicAction( + internal::ReturnNewAction2(a1, a2)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3) { + return MakePolymorphicAction( + internal::ReturnNewAction3(a1, a2, a3)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4) { + return MakePolymorphicAction( + internal::ReturnNewAction4(a1, a2, a3, a4)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) { + return MakePolymorphicAction( + internal::ReturnNewAction5(a1, a2, a3, a4, a5)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) { + return MakePolymorphicAction( + internal::ReturnNewAction6(a1, a2, a3, a4, a5, + a6)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) { + return MakePolymorphicAction( + internal::ReturnNewAction7(a1, a2, a3, a4, + a5, a6, a7)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) { + return MakePolymorphicAction( + internal::ReturnNewAction8(a1, a2, a3, + a4, a5, a6, a7, a8)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) { + return MakePolymorphicAction( + internal::ReturnNewAction9(a1, a2, + a3, a4, a5, a6, a7, a8, a9)); +} + +template +inline PolymorphicAction > +ReturnNew(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, + A10 a10) { + return MakePolymorphicAction( + internal::ReturnNewAction10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)); +} + +// Action DeleteArg() deletes the k-th (0-based) argument of the mock +// function. +template +inline internal::WithArgsAction +DeleteArg() { + return WithArg(internal::DeleteArg0()); +} + // Action Throw(exception) can be used in a mock function of any type // to throw the given exception. Any copyable value can be thrown. #if GTEST_HAS_EXCEPTIONS diff --git a/include/gmock/gmock-generated-actions.h.pump b/include/gmock/gmock-generated-actions.h.pump index 67359e64..942be2e5 100644 --- a/include/gmock/gmock-generated-actions.h.pump +++ b/include/gmock/gmock-generated-actions.h.pump @@ -806,6 +806,45 @@ ACTION_P(SetArg0Referee, value) { arg0 = value; } +// ReturnNewAction creates and returns a new instance of an object each time +// it is performed. It is overloaded to work with constructors that take +// different numbers of arguments. +$range i 0..n +$for i [[ +$var arity = [[ $if i==0 [[nullary]] + $elif i==1 [[unary]] + $elif i==2 [[binary]] + $elif i==3 [[ternary]] + $else [[$i-ary]]]] +$range j 1..i +$var typename_As = [[$for j [[, typename A$j]]]] +$var args_ = [[$for j, [[arg$j[[]]_]]]] + +// Returns a new instance of T using a $arity constructor with the given +// arguments. +template +class ReturnNewAction$i { + public: + $if i==1 [[explicit ]]ReturnNewAction$i($for j, [[A$j a$j]])$if i>0 [[ : ]] +$for j, [[arg$j[[]]_(a$j)]] {} + + template + Result Perform(const ArgumentTuple& /* args */) { + return new T($args_); + } + private: +$for j [[ + + const A$j arg$j[[]]_; +]] + +}; + +]] + +// Deletes the object pointed to by argument #0. +ACTION(DeleteArg0) { delete arg0; } + } // namespace internal // Action SaveArg(pointer) saves the k-th (0-based) argument of the @@ -824,6 +863,36 @@ SetArgReferee(const Value& value) { return WithArg(internal::SetArg0Referee(value)); } +// Various overloads for ReturnNew(). +// +// The ReturnNew(a1, a2, ..., a_k) action returns a pointer to a new +// instance of type T, constructed on the heap with constructor arguments +// a1, a2, ..., and a_k. The caller assumes ownership of the returned value. +$range i 0..n +$for i [[ +$range j 1..i +$var typename_As = [[$for j [[, typename A$j]]]] +$var As = [[$for j [[, A$j]]]] +$var Aas = [[$for j, [[A$j a$j]]]] +$var as = [[$for j, [[a$j]]]] + +template +inline PolymorphicAction > +ReturnNew($Aas) { + return MakePolymorphicAction( + internal::ReturnNewAction$i($as)); +} + +]] + +// Action DeleteArg() deletes the k-th (0-based) argument of the mock +// function. +template +inline internal::WithArgsAction +DeleteArg() { + return WithArg(internal::DeleteArg0()); +} + // Action Throw(exception) can be used in a mock function of any type // to throw the given exception. Any copyable value can be thrown. #if GTEST_HAS_EXCEPTIONS diff --git a/test/gmock-generated-actions_test.cc b/test/gmock-generated-actions_test.cc index dd25a123..922efca9 100644 --- a/test/gmock-generated-actions_test.cc +++ b/test/gmock-generated-actions_test.cc @@ -53,10 +53,12 @@ using testing::_; using testing::Action; using testing::ActionInterface; using testing::ByRef; +using testing::DeleteArg; using testing::DoAll; using testing::Invoke; using testing::InvokeArgument; using testing::Return; +using testing::ReturnNew; using testing::SaveArg; using testing::SetArgReferee; using testing::SetArgumentPointee; @@ -1371,6 +1373,107 @@ TEST(SetArgRefereeActionTest, WorksWithExtraArguments) { EXPECT_EQ('a', value); } +class NullaryConstructorClass { + public: + NullaryConstructorClass() : value_(123) {} + int value_; +}; + +// Tests using ReturnNew() with a nullary constructor. +TEST(ReturnNewTest, NoArgs) { + Action a = ReturnNew(); + NullaryConstructorClass* c = a.Perform(make_tuple()); + EXPECT_EQ(123, c->value_); + delete c; +} + +class UnaryConstructorClass { + public: + explicit UnaryConstructorClass(int value) : value_(value) {} + int value_; +}; + +// Tests using ReturnNew() with a unary constructor. +TEST(ReturnNewTest, Unary) { + Action a = ReturnNew(4000); + UnaryConstructorClass* c = a.Perform(make_tuple()); + EXPECT_EQ(4000, c->value_); + delete c; +} + +TEST(ReturnNewTest, UnaryWorksWhenMockMethodHasArgs) { + Action a = + ReturnNew(4000); + UnaryConstructorClass* c = a.Perform(make_tuple(false, 5)); + EXPECT_EQ(4000, c->value_); + delete c; +} + +TEST(ReturnNewTest, UnaryWorksWhenMockMethodReturnsPointerToConst) { + Action a = + ReturnNew(4000); + const UnaryConstructorClass* c = a.Perform(make_tuple()); + EXPECT_EQ(4000, c->value_); + delete c; +} + +class TenArgConstructorClass { + public: + TenArgConstructorClass(int a1, int a2, int a3, int a4, int a5, + int a6, int a7, int a8, int a9, int a10) + : value_(a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10) { + } + int value_; +}; + +// Tests using ReturnNew() with a 10-argument constructor. +TEST(ReturnNewTest, ConstructorThatTakes10Arguments) { + Action a = + ReturnNew(1000000000, 200000000, 30000000, + 4000000, 500000, 60000, + 7000, 800, 90, 0); + TenArgConstructorClass* c = a.Perform(make_tuple()); + EXPECT_EQ(1234567890, c->value_); + delete c; +} + +// A class that can be used to verify that its destructor is called: it will set +// the bool provided to the constructor to true when destroyed. +class DeletionTester { + public: + explicit DeletionTester(bool* is_deleted) + : is_deleted_(is_deleted) { + // Make sure the bit is set to false. + *is_deleted_ = false; + } + + ~DeletionTester() { + *is_deleted_ = true; + } + + private: + bool* is_deleted_; +}; + +TEST(DeleteArgActionTest, OneArg) { + bool is_deleted = false; + DeletionTester* t = new DeletionTester(&is_deleted); + const Action a1 = DeleteArg<0>(); // NOLINT + EXPECT_FALSE(is_deleted); + a1.Perform(make_tuple(t)); + EXPECT_TRUE(is_deleted); +} + +TEST(DeleteArgActionTest, TenArgs) { + bool is_deleted = false; + DeletionTester* t = new DeletionTester(&is_deleted); + const Action a1 = DeleteArg<9>(); + EXPECT_FALSE(is_deleted); + a1.Perform(make_tuple(true, 5, 6, "hi", false, 7, 8, 9, 10, t)); + EXPECT_TRUE(is_deleted); +} + #if GTEST_HAS_EXCEPTIONS TEST(ThrowActionTest, ThrowsGivenExceptionInVoidFunction) {