From 6eb9d94884f217d84bcef9054818bd38aeab9d41 Mon Sep 17 00:00:00 2001 From: "kosak@google.com" Date: Sat, 14 Feb 2015 02:45:40 +0000 Subject: In C++11 and above, makes a mock method whose return type is default constructible return a default-constructed value by default. git-svn-id: http://googlemock.googlecode.com/svn/trunk@513 8415998a-534a-0410-bf83-d39667b30386 --- include/gmock/gmock-actions.h | 57 ++++++++++++++--- test/gmock-actions_test.cc | 128 ++++++++++++++++++++++++--------------- test/gmock-spec-builders_test.cc | 22 ++++--- test/gmock_ex_test.cc | 15 +++-- 4 files changed, 150 insertions(+), 72 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index 46b7bf9..c09c4d6 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -46,6 +46,10 @@ #include "gmock/internal/gmock-internal-utils.h" #include "gmock/internal/gmock-port.h" +#if GTEST_LANG_CXX11 // Defined by gtest-port.h via gmock-port.h. +#include +#endif + namespace testing { // To implement an action Foo, define: @@ -62,16 +66,17 @@ namespace internal { template class ActionAdaptor; -// BuiltInDefaultValue::Get() returns the "built-in" default -// value for type T, which is NULL when T is a pointer type, 0 when T -// is a numeric type, false when T is bool, or "" when T is string or -// std::string. For any other type T, this value is undefined and the -// function will abort the process. +// BuiltInDefaultValueGetter::Get() returns a +// default-constructed T value. BuiltInDefaultValueGetter::Get() crashes with an error. +// +// This primary template is used when kDefaultConstructible is true. +template +struct BuiltInDefaultValueGetter { + static T Get() { return T(); } +}; template -class BuiltInDefaultValue { - public: - // This function returns true iff type T has a built-in default value. - static bool Exists() { return false; } +struct BuiltInDefaultValueGetter { static T Get() { Assert(false, __FILE__, __LINE__, "Default action undefined for the function return type."); @@ -81,6 +86,40 @@ class BuiltInDefaultValue { } }; +// BuiltInDefaultValue::Get() returns the "built-in" default value +// for type T, which is NULL when T is a raw pointer type, 0 when T is +// a numeric type, false when T is bool, or "" when T is string or +// std::string. In addition, in C++11 and above, it turns a +// default-constructed T value if T is default constructible. For any +// other type T, the built-in default T value is undefined, and the +// function will abort the process. +template +class BuiltInDefaultValue { + public: +#if GTEST_LANG_CXX11 + // This function returns true iff type T has a built-in default value. + static bool Exists() { + return ::std::is_default_constructible::value; + } + + static T Get() { + return BuiltInDefaultValueGetter< + T, ::std::is_default_constructible::value>::Get(); + } + +#else // GTEST_LANG_CXX11 + // This function returns true iff type T has a built-in default value. + static bool Exists() { + return false; + } + + static T Get() { + return BuiltInDefaultValueGetter::Get(); + } + +#endif // GTEST_LANG_CXX11 +}; + // This partial specialization says that we use the same built-in // default value for T and const T. template diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index a055194..a665fc5 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -45,15 +45,7 @@ namespace { -using testing::get; -using testing::make_tuple; -using testing::tuple; -using testing::tuple_element; -using testing::internal::BuiltInDefaultValue; -using testing::internal::Int64; -using testing::internal::UInt64; // This list should be kept sorted. -using testing::_; using testing::Action; using testing::ActionInterface; using testing::Assign; @@ -73,6 +65,14 @@ using testing::ReturnRef; using testing::ReturnRefOfCopy; using testing::SetArgPointee; using testing::SetArgumentPointee; +using testing::_; +using testing::get; +using testing::internal::BuiltInDefaultValue; +using testing::internal::Int64; +using testing::internal::UInt64; +using testing::make_tuple; +using testing::tuple; +using testing::tuple_element; #if !GTEST_OS_WINDOWS_MOBILE using testing::SetErrnoAndReturn; @@ -191,16 +191,43 @@ TEST(BuiltInDefaultValueTest, WorksForConstTypes) { EXPECT_FALSE(BuiltInDefaultValue::Get()); } -// Tests that BuiltInDefaultValue::Get() aborts the program with -// the correct error message when T is a user-defined type. -struct UserType { - UserType() : value(0) {} +// A type that's default constructible. +class MyDefaultConstructible { + public: + MyDefaultConstructible() : value_(42) {} + + int value() const { return value_; } - int value; + private: + int value_; }; -TEST(BuiltInDefaultValueTest, UserTypeHasNoDefault) { - EXPECT_FALSE(BuiltInDefaultValue::Exists()); +// A type that's not default constructible. +class MyNonDefaultConstructible { + public: + // Does not have a default ctor. + explicit MyNonDefaultConstructible(int a_value) : value_(a_value) {} + + int value() const { return value_; } + + private: + int value_; +}; + +#if GTEST_LANG_CXX11 + +TEST(BuiltInDefaultValueTest, ExistsForDefaultConstructibleType) { + EXPECT_TRUE(BuiltInDefaultValue::Exists()); +} + +TEST(BuiltInDefaultValueTest, IsDefaultConstructedForDefaultConstructibleType) { + EXPECT_EQ(42, BuiltInDefaultValue::Get().value()); +} + +#endif // GTEST_LANG_CXX11 + +TEST(BuiltInDefaultValueTest, DoesNotExistForNonDefaultConstructibleType) { + EXPECT_FALSE(BuiltInDefaultValue::Exists()); } // Tests that BuiltInDefaultValue::Get() aborts the program. @@ -213,40 +240,42 @@ TEST(BuiltInDefaultValueDeathTest, IsUndefinedForReferences) { }, ""); } -TEST(BuiltInDefaultValueDeathTest, IsUndefinedForUserTypes) { +TEST(BuiltInDefaultValueDeathTest, IsUndefinedForNonDefaultConstructibleType) { EXPECT_DEATH_IF_SUPPORTED({ - BuiltInDefaultValue::Get(); + BuiltInDefaultValue::Get(); }, ""); } // Tests that DefaultValue::IsSet() is false initially. TEST(DefaultValueTest, IsInitiallyUnset) { EXPECT_FALSE(DefaultValue::IsSet()); - EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::IsSet()); } // Tests that DefaultValue can be set and then unset. TEST(DefaultValueTest, CanBeSetAndUnset) { EXPECT_TRUE(DefaultValue::Exists()); - EXPECT_FALSE(DefaultValue::Exists()); + EXPECT_FALSE(DefaultValue::Exists()); DefaultValue::Set(1); - DefaultValue::Set(UserType()); + DefaultValue::Set( + MyNonDefaultConstructible(42)); EXPECT_EQ(1, DefaultValue::Get()); - EXPECT_EQ(0, DefaultValue::Get().value); + EXPECT_EQ(42, DefaultValue::Get().value()); EXPECT_TRUE(DefaultValue::Exists()); - EXPECT_TRUE(DefaultValue::Exists()); + EXPECT_TRUE(DefaultValue::Exists()); DefaultValue::Clear(); - DefaultValue::Clear(); + DefaultValue::Clear(); EXPECT_FALSE(DefaultValue::IsSet()); - EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::IsSet()); EXPECT_TRUE(DefaultValue::Exists()); - EXPECT_FALSE(DefaultValue::Exists()); + EXPECT_FALSE(DefaultValue::Exists()); } // Tests that DefaultValue::Get() returns the @@ -255,22 +284,20 @@ TEST(DefaultValueTest, CanBeSetAndUnset) { TEST(DefaultValueDeathTest, GetReturnsBuiltInDefaultValueWhenUnset) { EXPECT_FALSE(DefaultValue::IsSet()); EXPECT_TRUE(DefaultValue::Exists()); - EXPECT_FALSE(DefaultValue::IsSet()); - EXPECT_FALSE(DefaultValue::Exists()); + EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::Exists()); EXPECT_EQ(0, DefaultValue::Get()); EXPECT_DEATH_IF_SUPPORTED({ - DefaultValue::Get(); + DefaultValue::Get(); }, ""); } #if GTEST_HAS_STD_UNIQUE_PTR_ -TEST(DefaultValueDeathTest, GetWorksForMoveOnlyIfSet) { - EXPECT_FALSE(DefaultValue>::Exists()); - EXPECT_DEATH_IF_SUPPORTED({ - DefaultValue>::Get(); - }, ""); +TEST(DefaultValueTest, GetWorksForMoveOnlyIfSet) { + EXPECT_TRUE(DefaultValue>::Exists()); + EXPECT_TRUE(DefaultValue>::Get() == NULL); DefaultValue>::SetFactory([] { return std::unique_ptr(new int(42)); }); @@ -290,36 +317,38 @@ TEST(DefaultValueTest, GetWorksForVoid) { // Tests that DefaultValue::IsSet() is false initially. TEST(DefaultValueOfReferenceTest, IsInitiallyUnset) { EXPECT_FALSE(DefaultValue::IsSet()); - EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::IsSet()); } // Tests that DefaultValue::Exists is false initiallly. TEST(DefaultValueOfReferenceTest, IsInitiallyNotExisting) { EXPECT_FALSE(DefaultValue::Exists()); - EXPECT_FALSE(DefaultValue::Exists()); + EXPECT_FALSE(DefaultValue::Exists()); + EXPECT_FALSE(DefaultValue::Exists()); } // Tests that DefaultValue can be set and then unset. TEST(DefaultValueOfReferenceTest, CanBeSetAndUnset) { int n = 1; DefaultValue::Set(n); - UserType u; - DefaultValue::Set(u); + MyNonDefaultConstructible x(42); + DefaultValue::Set(x); EXPECT_TRUE(DefaultValue::Exists()); - EXPECT_TRUE(DefaultValue::Exists()); + EXPECT_TRUE(DefaultValue::Exists()); EXPECT_EQ(&n, &(DefaultValue::Get())); - EXPECT_EQ(&u, &(DefaultValue::Get())); + EXPECT_EQ(&x, &(DefaultValue::Get())); DefaultValue::Clear(); - DefaultValue::Clear(); + DefaultValue::Clear(); EXPECT_FALSE(DefaultValue::Exists()); - EXPECT_FALSE(DefaultValue::Exists()); + EXPECT_FALSE(DefaultValue::Exists()); EXPECT_FALSE(DefaultValue::IsSet()); - EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::IsSet()); } // Tests that DefaultValue::Get() returns the @@ -327,13 +356,13 @@ TEST(DefaultValueOfReferenceTest, CanBeSetAndUnset) { // false. TEST(DefaultValueOfReferenceDeathTest, GetReturnsBuiltInDefaultValueWhenUnset) { EXPECT_FALSE(DefaultValue::IsSet()); - EXPECT_FALSE(DefaultValue::IsSet()); + EXPECT_FALSE(DefaultValue::IsSet()); EXPECT_DEATH_IF_SUPPORTED({ DefaultValue::Get(); }, ""); EXPECT_DEATH_IF_SUPPORTED({ - DefaultValue::Get(); + DefaultValue::Get(); }, ""); } @@ -661,14 +690,12 @@ TEST(ReturnRefOfCopyTest, IsCovariant) { // Tests that DoDefault() does the default action for the mock method. -class MyClass {}; - class MockClass { public: MockClass() {} MOCK_METHOD1(IntFunc, int(bool flag)); // NOLINT - MOCK_METHOD0(Foo, MyClass()); + MOCK_METHOD0(Foo, MyNonDefaultConstructible()); #if GTEST_HAS_STD_UNIQUE_PTR_ MOCK_METHOD0(MakeUnique, std::unique_ptr()); MOCK_METHOD0(MakeUniqueBase, std::unique_ptr()); @@ -1160,14 +1187,15 @@ TEST(IgnoreResultTest, MonomorphicAction) { // Tests using IgnoreResult() on an action that returns a class type. -MyClass ReturnMyClass(double /* x */) { +MyNonDefaultConstructible ReturnMyNonDefaultConstructible(double /* x */) { g_done = true; - return MyClass(); + return MyNonDefaultConstructible(42); } TEST(IgnoreResultTest, ActionReturningClass) { g_done = false; - Action a = IgnoreResult(Invoke(ReturnMyClass)); // NOLINT + Action a = + IgnoreResult(Invoke(ReturnMyNonDefaultConstructible)); // NOLINT a.Perform(make_tuple(2)); EXPECT_TRUE(g_done); } diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc index ae81149..b8f7a11 100644 --- a/test/gmock-spec-builders_test.cc +++ b/test/gmock-spec-builders_test.cc @@ -134,14 +134,21 @@ void PrintTo(const Incomplete& /* x */, ::std::ostream* os) { class Result {}; +// A type that's not default constructible. +class NonDefaultConstructible { + public: + explicit NonDefaultConstructible(int /* dummy */) {} +}; + class MockA { public: MockA() {} - MOCK_METHOD1(DoA, void(int n)); // NOLINT - MOCK_METHOD1(ReturnResult, Result(int n)); // NOLINT - MOCK_METHOD2(Binary, bool(int x, int y)); // NOLINT - MOCK_METHOD2(ReturnInt, int(int x, int y)); // NOLINT + MOCK_METHOD1(DoA, void(int n)); + MOCK_METHOD1(ReturnResult, Result(int n)); + MOCK_METHOD0(ReturnNonDefaultConstructible, NonDefaultConstructible()); + MOCK_METHOD2(Binary, bool(int x, int y)); + MOCK_METHOD2(ReturnInt, int(int x, int y)); private: GTEST_DISALLOW_COPY_AND_ASSIGN_(MockA); @@ -1108,15 +1115,16 @@ TEST(UnexpectedCallTest, UnsatisifiedPrerequisites) { b.DoB(4); } -TEST(UndefinedReturnValueTest, ReturnValueIsMandatory) { +TEST(UndefinedReturnValueTest, + ReturnValueIsMandatoryWhenNotDefaultConstructible) { MockA a; // TODO(wan@google.com): We should really verify the output message, // but we cannot yet due to that EXPECT_DEATH only captures stderr // while Google Mock logs to stdout. #if GTEST_HAS_EXCEPTIONS - EXPECT_ANY_THROW(a.ReturnResult(1)); + EXPECT_ANY_THROW(a.ReturnNonDefaultConstructible()); #else - EXPECT_DEATH_IF_SUPPORTED(a.ReturnResult(1), ""); + EXPECT_DEATH_IF_SUPPORTED(a.ReturnNonDefaultConstructible(), ""); #endif } diff --git a/test/gmock_ex_test.cc b/test/gmock_ex_test.cc index a5a8a42..3afed86 100644 --- a/test/gmock_ex_test.cc +++ b/test/gmock_ex_test.cc @@ -39,14 +39,17 @@ namespace { using testing::HasSubstr; using testing::internal::GoogleTestFailureException; -// A user-defined class. -class Something {}; +// A type that cannot be default constructed. +class NonDefaultConstructible { + public: + explicit NonDefaultConstructible(int /* dummy */) {} +}; class MockFoo { public: // A mock method that returns a user-defined type. Google Mock // doesn't know what the default value for this type is. - MOCK_METHOD0(GetSomething, Something()); + MOCK_METHOD0(GetNonDefaultConstructible, NonDefaultConstructible()); }; #if GTEST_HAS_EXCEPTIONS @@ -59,9 +62,9 @@ TEST(DefaultValueTest, ThrowsRuntimeErrorWhenNoDefaultValue) { // nothing about the return type, it doesn't know what to return, // and has to throw (when exceptions are enabled) or abort // (otherwise). - mock.GetSomething(); - FAIL() << "GetSomething()'s return type has no default value, " - << "so Google Mock should have thrown."; + mock.GetNonDefaultConstructible(); + FAIL() << "GetNonDefaultConstructible()'s return type has no default " + << "value, so Google Mock should have thrown."; } catch (const GoogleTestFailureException& /* unused */) { FAIL() << "Google Test does not try to catch an exception of type " << "GoogleTestFailureException, which is used for reporting " -- cgit v1.2.1