From 201ac161919b2c7f464b4f966a4f1a1a2379c486 Mon Sep 17 00:00:00 2001 From: vladlosev Date: Wed, 18 Nov 2009 00:12:05 +0000 Subject: [PATCH] Enables gmock's implicit_cast to work with source types that have a non-const conversion operator (by Zhanyong Wan). --- include/gmock/internal/gmock-port.h | 14 ++- test/gmock-port_test.cc | 139 +++++++++++++++++++++++++++- 2 files changed, 148 insertions(+), 5 deletions(-) diff --git a/include/gmock/internal/gmock-port.h b/include/gmock/internal/gmock-port.h index 0263491e..1bd455b2 100644 --- a/include/gmock/internal/gmock-port.h +++ b/include/gmock/internal/gmock-port.h @@ -99,9 +99,21 @@ namespace internal { // but the proposal was submitted too late. It will probably make // its way into the language in the future. template -inline To implicit_cast(From const &f) { +inline To implicit_cast(const From& f) { return f; } +// Nokia's compiler can't tell which version of implicit_cast to use when +// the source is a const, causing the compilation to fail with the error +// "ambiguous access to overloaded function". So we only support the const +// version of implicit_cast on Symbian. +#if !GTEST_OS_SYMBIAN +// This overload is needed in case the From type has a non-const type +// conversion operator to type To. +template +inline To implicit_cast(From& f) { + return f; +} +#endif // When you upcast (that is, cast a pointer from type Foo to type // SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts diff --git a/test/gmock-port_test.cc b/test/gmock-port_test.cc index fe844e72..3d983d52 100644 --- a/test/gmock-port_test.cc +++ b/test/gmock-port_test.cc @@ -36,8 +36,139 @@ #include #include -// This file intentionally contains no tests at this moment. +// NOTE: if this file is left without tests for some reason, put a dummy +// test here to make references to symbols in the gtest library and avoid +// 'undefined symbol' linker errors in gmock_main: +// +// TEST(DummyTest, Dummy) {} -// Putting a dummy test here makes references to symbols in the gtest -// library and avoids 'undefined symbol' linker errors in gmock_main. -TEST(DummyTest, Dummy) {} +namespace testing { +namespace internal { +// Needed to avoid name collisions in gmock_all_test.cc. +namespace gmock_port_test { + +class Base { + public: + // Copy constructor and assignment operator do exactly what we need, so we + // use them. + Base() : member_(0) {} + explicit Base(int n) : member_(n) {} + virtual ~Base() {} + int member() { return member_; } + + private: + int member_; +}; + +class Derived : public Base { + public: + explicit Derived(int n) : Base(n) {} +}; + +TEST(ImplicitCastTest, ConvertsPointers) { + Derived derived(0); + EXPECT_TRUE(&derived == ::testing::internal::implicit_cast(&derived)); +} + +TEST(ImplicitCastTest, CanUseInheritance) { + Derived derived(1); + Base base = ::testing::internal::implicit_cast(derived); + EXPECT_EQ(derived.member(), base.member()); +} + +// The non-const version is not enabled for Symbian since the Nokia compiler +// cannot decide which version of the overloaded implicit_cast method to use +// when the source is a const. +#if !GTEST_OS_SYMBIAN +class Castable { + public: + Castable(bool* converted) : converted_(converted) {} + operator Base() { + *converted_ = true; + return Base(); + } + + private: + bool* const converted_; +}; + +TEST(ImplicitCastTest, CanUseNonConstCastOperator) { + bool converted = false; + Castable castable(&converted); + Base base = ::testing::internal::implicit_cast(castable); + EXPECT_TRUE(converted); +} +#endif // !GTEST_OS_SYMBIAN + +class ConstCastable { + public: + ConstCastable(bool* converted) : converted_(converted) {} + operator Base() const { + *converted_ = true; + return Base(); + } + + private: + bool* const converted_; +}; + +TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) { + bool converted = false; + const ConstCastable const_castable(&converted); + Base base = ::testing::internal::implicit_cast(const_castable); + EXPECT_TRUE(converted); +} + +// The non-const version is not enabled for Symbian since the Nokia compiler +// cannot decide which version of the overloaded implicit_cast method to use +// when the source is a const. +#if !GTEST_OS_SYMBIAN +class ConstAndNonConstCastable { + public: + ConstAndNonConstCastable(bool* converted, bool* const_converted) + : converted_(converted), const_converted_(const_converted) {} + operator Base() { + *converted_ = true; + return Base(); + } + operator Base() const { + *const_converted_ = true; + return Base(); + } + + private: + bool* const converted_; + bool* const const_converted_; +}; + +TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) { + bool converted = false; + bool const_converted = false; + ConstAndNonConstCastable castable(&converted, &const_converted); + Base base = ::testing::internal::implicit_cast(castable); + EXPECT_TRUE(converted); + EXPECT_FALSE(const_converted); + + converted = false; + const_converted = false; + const ConstAndNonConstCastable const_castable(&converted, &const_converted); + base = ::testing::internal::implicit_cast(const_castable); + EXPECT_FALSE(converted); + EXPECT_TRUE(const_converted); +} +#endif // !GTEST_OS_SYMBIAN + +class To { + public: + To(bool* converted) { *converted = true; } // NOLINT +}; + +TEST(ImplicitCastTest, CanUseImplicitConstructor) { + bool converted = false; + To to = ::testing::internal::implicit_cast(&converted); + EXPECT_TRUE(converted); +} + +} // namespace gmock_port_test +} // namespace internal +} // namespace testing