Commit 1c8eb1c0 by zhanyong.wan

Adds actions ReturnNew<T>(...) and DeleteArg<k>(), by Jason Hsueh.

parent 56fe7460
...@@ -806,6 +806,45 @@ ACTION_P(SetArg0Referee, value) { ...@@ -806,6 +806,45 @@ ACTION_P(SetArg0Referee, value) {
arg0 = value; arg0 = value;
} }
// ReturnNewAction<T> 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 <typename T$typename_As>
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 <typename Result, typename ArgumentTuple>
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 } // namespace internal
// Action SaveArg<k>(pointer) saves the k-th (0-based) argument of the // Action SaveArg<k>(pointer) saves the k-th (0-based) argument of the
...@@ -824,6 +863,36 @@ SetArgReferee(const Value& value) { ...@@ -824,6 +863,36 @@ SetArgReferee(const Value& value) {
return WithArg<k>(internal::SetArg0Referee(value)); return WithArg<k>(internal::SetArg0Referee(value));
} }
// Various overloads for ReturnNew<T>().
//
// The ReturnNew<T>(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 <typename T$typename_As>
inline PolymorphicAction<internal::ReturnNewAction$i<T$As> >
ReturnNew($Aas) {
return MakePolymorphicAction(
internal::ReturnNewAction$i<T$As>($as));
}
]]
// Action DeleteArg<k>() deletes the k-th (0-based) argument of the mock
// function.
template <int k>
inline internal::WithArgsAction<internal::DeleteArg0Action, k>
DeleteArg() {
return WithArg<k>(internal::DeleteArg0());
}
// Action Throw(exception) can be used in a mock function of any type // Action Throw(exception) can be used in a mock function of any type
// to throw the given exception. Any copyable value can be thrown. // to throw the given exception. Any copyable value can be thrown.
#if GTEST_HAS_EXCEPTIONS #if GTEST_HAS_EXCEPTIONS
......
...@@ -53,10 +53,12 @@ using testing::_; ...@@ -53,10 +53,12 @@ using testing::_;
using testing::Action; using testing::Action;
using testing::ActionInterface; using testing::ActionInterface;
using testing::ByRef; using testing::ByRef;
using testing::DeleteArg;
using testing::DoAll; using testing::DoAll;
using testing::Invoke; using testing::Invoke;
using testing::InvokeArgument; using testing::InvokeArgument;
using testing::Return; using testing::Return;
using testing::ReturnNew;
using testing::SaveArg; using testing::SaveArg;
using testing::SetArgReferee; using testing::SetArgReferee;
using testing::SetArgumentPointee; using testing::SetArgumentPointee;
...@@ -1371,6 +1373,107 @@ TEST(SetArgRefereeActionTest, WorksWithExtraArguments) { ...@@ -1371,6 +1373,107 @@ TEST(SetArgRefereeActionTest, WorksWithExtraArguments) {
EXPECT_EQ('a', value); EXPECT_EQ('a', value);
} }
class NullaryConstructorClass {
public:
NullaryConstructorClass() : value_(123) {}
int value_;
};
// Tests using ReturnNew() with a nullary constructor.
TEST(ReturnNewTest, NoArgs) {
Action<NullaryConstructorClass*()> a = ReturnNew<NullaryConstructorClass>();
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<UnaryConstructorClass*()> a = ReturnNew<UnaryConstructorClass>(4000);
UnaryConstructorClass* c = a.Perform(make_tuple());
EXPECT_EQ(4000, c->value_);
delete c;
}
TEST(ReturnNewTest, UnaryWorksWhenMockMethodHasArgs) {
Action<UnaryConstructorClass*(bool, int)> a =
ReturnNew<UnaryConstructorClass>(4000);
UnaryConstructorClass* c = a.Perform(make_tuple(false, 5));
EXPECT_EQ(4000, c->value_);
delete c;
}
TEST(ReturnNewTest, UnaryWorksWhenMockMethodReturnsPointerToConst) {
Action<const UnaryConstructorClass*()> a =
ReturnNew<UnaryConstructorClass>(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<TenArgConstructorClass*()> a =
ReturnNew<TenArgConstructorClass>(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<void(DeletionTester*)> 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<void(bool, int, int, const char*, bool,
int, int, int, int, DeletionTester*)> 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 #if GTEST_HAS_EXCEPTIONS
TEST(ThrowActionTest, ThrowsGivenExceptionInVoidFunction) { TEST(ThrowActionTest, ThrowsGivenExceptionInVoidFunction) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment