From 201ac161919b2c7f464b4f966a4f1a1a2379c486 Mon Sep 17 00:00:00 2001
From: vladlosev <vladlosev@8415998a-534a-0410-bf83-d39667b30386>
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<typename To, typename From>
-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<typename To, typename From>
+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 <gmock/internal/gmock-port.h>
 #include <gtest/gtest.h>
 
-// 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<Base*>(&derived));
+}
+
+TEST(ImplicitCastTest, CanUseInheritance) {
+  Derived derived(1);
+  Base base = ::testing::internal::implicit_cast<Base>(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<Base>(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<Base>(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<Base>(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<Base>(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<To>(&converted);
+  EXPECT_TRUE(converted);
+}
+
+}  // namespace gmock_port_test
+}  // namespace internal
+}  // namespace testing