From 8e7366dbfce9789f63d58c18b4d96879850b818b Mon Sep 17 00:00:00 2001 From: "zhanyong.wan" Date: Fri, 25 Sep 2009 18:55:50 +0000 Subject: Makes gmock work on Symbian (both 3rd & 5th editions), original patch contributed by Mika Raento. git-svn-id: http://googlemock.googlecode.com/svn/trunk@212 8415998a-534a-0410-bf83-d39667b30386 --- include/gmock/gmock-actions.h | 21 +------ include/gmock/gmock-generated-matchers.h | 14 +++-- include/gmock/gmock-generated-matchers.h.pump | 15 +++++ include/gmock/gmock-matchers.h | 88 +++++++++++++++------------ include/gmock/internal/gmock-internal-utils.h | 54 ++++++++++++++-- test/gmock-actions_test.cc | 19 ++++-- test/gmock-internal-utils_test.cc | 3 +- test/gmock-matchers_test.cc | 55 ++++++++++++----- test/gmock-printers_test.cc | 8 +-- 9 files changed, 185 insertions(+), 92 deletions(-) diff --git a/include/gmock/gmock-actions.h b/include/gmock/gmock-actions.h index f7daf82..7f21a7d 100644 --- a/include/gmock/gmock-actions.h +++ b/include/gmock/gmock-actions.h @@ -125,32 +125,13 @@ GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned char, '\0'); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed char, '\0'); GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(char, '\0'); -// signed wchar_t and unsigned wchar_t are NOT in the C++ standard. -// Using them is a bad practice and not portable. So don't use them. -// -// Still, Google Mock is designed to work even if the user uses signed -// wchar_t or unsigned wchar_t (obviously, assuming the compiler -// supports them). -// -// To gcc, -// -// wchar_t == signed wchar_t != unsigned wchar_t == unsigned int -// -// MSVC does not recognize signed wchar_t or unsigned wchar_t. It -// treats wchar_t as a native type usually, but treats it as the same -// as unsigned short when the compiler option /Zc:wchar_t- is -// specified. -// -// Therefore we provide a default action for wchar_t when compiled -// with gcc or _NATIVE_WCHAR_T_DEFINED is defined. -// // There's no need for a default action for signed wchar_t, as that // type is the same as wchar_t for gcc, and invalid for MSVC. // // There's also no need for a default action for unsigned wchar_t, as // that type is the same as unsigned int for gcc, and invalid for // MSVC. -#if defined(__GNUC__) || defined(_NATIVE_WCHAR_T_DEFINED) +#if GMOCK_WCHAR_T_IS_NATIVE_ GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(wchar_t, 0U); // NOLINT #endif diff --git a/include/gmock/gmock-generated-matchers.h b/include/gmock/gmock-generated-matchers.h index b2d5576..a59e457 100644 --- a/include/gmock/gmock-generated-matchers.h +++ b/include/gmock/gmock-generated-matchers.h @@ -304,11 +304,15 @@ class ElementsAreMatcher1 { typedef typename internal::StlContainerView::type::value_type Element; - const Matcher matchers[] = { - MatcherCast(e1_), - }; - - return MakeMatcher(new ElementsAreMatcherImpl(matchers, 1)); + // Nokia's Symbian Compiler has a nasty bug where the object put + // in a one-element local array is not destructed when the array + // goes out of scope. This leads to obvious badness as we've + // added the linked_ptr in it to our other linked_ptrs list. + // Hence we implement ElementsAreMatcher1 specially to avoid using + // a local array. + const Matcher matcher = + MatcherCast(e1_); + return MakeMatcher(new ElementsAreMatcherImpl(&matcher, 1)); } private: diff --git a/include/gmock/gmock-generated-matchers.h.pump b/include/gmock/gmock-generated-matchers.h.pump index 41294b7..c43aa87 100644 --- a/include/gmock/gmock-generated-matchers.h.pump +++ b/include/gmock/gmock-generated-matchers.h.pump @@ -192,6 +192,19 @@ class ElementsAreMatcher$i { typedef typename internal::StlContainerView::type::value_type Element; +$if i==1 [[ + + // Nokia's Symbian Compiler has a nasty bug where the object put + // in a one-element local array is not destructed when the array + // goes out of scope. This leads to obvious badness as we've + // added the linked_ptr in it to our other linked_ptrs list. + // Hence we implement ElementsAreMatcher1 specially to avoid using + // a local array. + const Matcher matcher = + MatcherCast(e1_); + return MakeMatcher(new ElementsAreMatcherImpl(&matcher, 1)); +]] $else [[ + const Matcher matchers[] = { $for j [[ @@ -201,6 +214,8 @@ $for j [[ }; return MakeMatcher(new ElementsAreMatcherImpl(matchers, $i)); +]] + } private: diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h index e2beff4..3d82279 100644 --- a/include/gmock/gmock-matchers.h +++ b/include/gmock/gmock-matchers.h @@ -320,47 +320,59 @@ inline PolymorphicMatcher MakePolymorphicMatcher(const Impl& impl) { template Matcher MatcherCast(M m); -// TODO(vladl@google.com): Modify the implementation to reject casting -// Matcher to Matcher. // Implements SafeMatcherCast(). // -// This overload handles polymorphic matchers only since monomorphic -// matchers are handled by the next one. -template -inline Matcher SafeMatcherCast(M polymorphic_matcher) { - return Matcher(polymorphic_matcher); -} +// We use an intermediate class to do the actual safe casting as Nokia's +// Symbian compiler cannot decide between +// template ... (M) and +// template ... (const Matcher&) +// for function templates but can for member function templates. +template +class SafeMatcherCastImpl { + public: + // This overload handles polymorphic matchers only since monomorphic + // matchers are handled by the next one. + template + static inline Matcher Cast(M polymorphic_matcher) { + return Matcher(polymorphic_matcher); + } -// This overload handles monomorphic matchers. -// -// In general, if type T can be implicitly converted to type U, we can -// safely convert a Matcher to a Matcher (i.e. Matcher is -// contravariant): just keep a copy of the original Matcher, convert the -// argument from type T to U, and then pass it to the underlying Matcher. -// The only exception is when U is a reference and T is not, as the -// underlying Matcher may be interested in the argument's address, which -// is not preserved in the conversion from T to U. -template -Matcher SafeMatcherCast(const Matcher& matcher) { - // Enforce that T can be implicitly converted to U. - GMOCK_COMPILE_ASSERT_((internal::ImplicitlyConvertible::value), - T_must_be_implicitly_convertible_to_U); - // Enforce that we are not converting a non-reference type T to a reference - // type U. - GMOCK_COMPILE_ASSERT_( - internal::is_reference::value || !internal::is_reference::value, - cannot_convert_non_referentce_arg_to_reference); - // In case both T and U are arithmetic types, enforce that the - // conversion is not lossy. - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(T)) RawT; - typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(U)) RawU; - const bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther; - const bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther; - GMOCK_COMPILE_ASSERT_( - kTIsOther || kUIsOther || - (internal::LosslessArithmeticConvertible::value), - conversion_of_arithmetic_types_must_be_lossless); - return MatcherCast(matcher); + // This overload handles monomorphic matchers. + // + // In general, if type T can be implicitly converted to type U, we can + // safely convert a Matcher to a Matcher (i.e. Matcher is + // contravariant): just keep a copy of the original Matcher, convert the + // argument from type T to U, and then pass it to the underlying Matcher. + // The only exception is when U is a reference and T is not, as the + // underlying Matcher may be interested in the argument's address, which + // is not preserved in the conversion from T to U. + template + static inline Matcher Cast(const Matcher& matcher) { + // Enforce that T can be implicitly converted to U. + GMOCK_COMPILE_ASSERT_((internal::ImplicitlyConvertible::value), + T_must_be_implicitly_convertible_to_U); + // Enforce that we are not converting a non-reference type T to a reference + // type U. + GMOCK_COMPILE_ASSERT_( + internal::is_reference::value || !internal::is_reference::value, + cannot_convert_non_referentce_arg_to_reference); + // In case both T and U are arithmetic types, enforce that the + // conversion is not lossy. + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(T)) RawT; + typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(U)) RawU; + const bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther; + const bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther; + GMOCK_COMPILE_ASSERT_( + kTIsOther || kUIsOther || + (internal::LosslessArithmeticConvertible::value), + conversion_of_arithmetic_types_must_be_lossless); + return MatcherCast(matcher); + } +}; + +template +inline Matcher SafeMatcherCast(const M& polymorphic_matcher) { + return SafeMatcherCastImpl::Cast(polymorphic_matcher); } // A() returns a matcher that matches any value of type T. diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h index 39e70b3..7b17335 100644 --- a/include/gmock/internal/gmock-internal-utils.h +++ b/include/gmock/internal/gmock-internal-utils.h @@ -221,6 +221,34 @@ class ImplicitlyConvertible { template const bool ImplicitlyConvertible::value; +// Symbian compilation can be done with wchar_t being either a native +// type or a typedef. Using Google Mock with OpenC without wchar_t +// should require the definition of _STLP_NO_WCHAR_T. +// +// MSVC treats wchar_t as a native type usually, but treats it as the +// same as unsigned short when the compiler option /Zc:wchar_t- is +// specified. It defines _NATIVE_WCHAR_T_DEFINED symbol when wchar_t +// is a native type. +#if (GTEST_OS_SYMBIAN && defined(_STLP_NO_WCHAR_T)) || \ + (defined(_MSC_VER) && !defined(_NATIVE_WCHAR_T_DEFINED)) +// wchar_t is a typedef. +#else +#define GMOCK_WCHAR_T_IS_NATIVE_ 1 +#endif + +// signed wchar_t and unsigned wchar_t are NOT in the C++ standard. +// Using them is a bad practice and not portable. So DON'T use them. +// +// Still, Google Mock is designed to work even if the user uses signed +// wchar_t or unsigned wchar_t (obviously, assuming the compiler +// supports them). +// +// To gcc, +// wchar_t == signed wchar_t != unsigned wchar_t == unsigned int +#ifdef __GNUC__ +#define GMOCK_HAS_SIGNED_WCHAR_T_ 1 // signed/unsigned wchar_t are valid types. +#endif + // In what follows, we use the term "kind" to indicate whether a type // is bool, an integer type (excluding bool), a floating-point type, // or none of them. This categorization is useful for determining @@ -252,10 +280,7 @@ GMOCK_DECLARE_KIND_(unsigned int, kInteger); GMOCK_DECLARE_KIND_(long, kInteger); // NOLINT GMOCK_DECLARE_KIND_(unsigned long, kInteger); // NOLINT -// MSVC can be configured to define wchar_t as a typedef of unsigned -// short. It defines _NATIVE_WCHAR_T_DEFINED symbol when wchar_t is a -// native type. -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +#if GMOCK_WCHAR_T_IS_NATIVE_ GMOCK_DECLARE_KIND_(wchar_t, kInteger); #endif @@ -679,10 +704,31 @@ class StlContainerView { static const_reference ConstReference(const Element (&array)[N]) { // Ensures that Element is not a const type. testing::StaticAssertTypeEq(); +#if GTEST_OS_SYMBIAN + // The Nokia Symbian compiler confuses itself in template instantiation + // for this call without the cast to Element*: + // function call '[testing::internal::NativeArray].NativeArray( + // {lval} const char *[4], long, testing::internal::RelationToSource)' + // does not match + // 'testing::internal::NativeArray::NativeArray( + // char *const *, unsigned int, testing::internal::RelationToSource)' + // (instantiating: 'testing::internal::ContainsMatcherImpl + // ::Matches(const char * (&)[4]) const') + // (instantiating: 'testing::internal::StlContainerView:: + // ConstReference(const char * (&)[4])') + // (and though the N parameter type is mismatched in the above explicit + // conversion of it doesn't help - only the conversion of the array). + return type(const_cast(&array[0]), N, kReference); +#else return type(array, N, kReference); +#endif // GTEST_OS_SYMBIAN } static type Copy(const Element (&array)[N]) { +#if GTEST_OS_SYMBIAN + return type(const_cast(&array[0]), N, kCopy); +#else return type(array, N, kCopy); +#endif // GTEST_OS_SYMBIAN } }; diff --git a/test/gmock-actions_test.cc b/test/gmock-actions_test.cc index 5d05bc5..d3d96c6 100644 --- a/test/gmock-actions_test.cc +++ b/test/gmock-actions_test.cc @@ -98,11 +98,13 @@ TEST(BuiltInDefaultValueTest, IsZeroForNumericTypes) { EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); -#if !GTEST_OS_WINDOWS +#if GMOCK_HAS_SIGNED_WCHAR_T_ EXPECT_EQ(0, BuiltInDefaultValue::Get()); EXPECT_EQ(0, BuiltInDefaultValue::Get()); -#endif // !GTEST_OS_WINDOWS +#endif +#if GMOCK_WCHAR_T_IS_NATIVE_ EXPECT_EQ(0, BuiltInDefaultValue::Get()); +#endif EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT EXPECT_EQ(0, BuiltInDefaultValue::Get()); // NOLINT @@ -124,11 +126,13 @@ TEST(BuiltInDefaultValueTest, ExistsForNumericTypes) { EXPECT_TRUE(BuiltInDefaultValue::Exists()); EXPECT_TRUE(BuiltInDefaultValue::Exists()); EXPECT_TRUE(BuiltInDefaultValue::Exists()); -#if !GTEST_OS_WINDOWS +#if GMOCK_HAS_SIGNED_WCHAR_T_ EXPECT_TRUE(BuiltInDefaultValue::Exists()); EXPECT_TRUE(BuiltInDefaultValue::Exists()); -#endif // !GTEST_OS_WINDOWS +#endif +#if GMOCK_WCHAR_T_IS_NATIVE_ EXPECT_TRUE(BuiltInDefaultValue::Exists()); +#endif EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT EXPECT_TRUE(BuiltInDefaultValue::Exists()); // NOLINT @@ -395,12 +399,19 @@ class IsNotZero : public ActionInterface { // NOLINT } }; +#if !GTEST_OS_SYMBIAN +// Compiling this test on Nokia's Symbian compiler fails with: +// 'Result' is not a member of class 'testing::internal::Function' +// (point of instantiation: '@unnamed@gmock_actions_test_cc@:: +// ActionTest_CanBeConvertedToOtherActionType_Test::TestBody()') +// with no obvious fix. TEST(ActionTest, CanBeConvertedToOtherActionType) { const Action a1(new IsNotZero); // NOLINT const Action a2 = Action(a1); // NOLINT EXPECT_EQ(1, a2.Perform(make_tuple('a'))); EXPECT_EQ(0, a2.Perform(make_tuple('\0'))); } +#endif // !GTEST_OS_SYMBIAN // The following two classes are for testing MakePolymorphicAction(). diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc index d3a16ad..ac3b2dd 100644 --- a/test/gmock-internal-utils_test.cc +++ b/test/gmock-internal-utils_test.cc @@ -211,7 +211,8 @@ TEST(GetRawPointerTest, WorksForSmartPointers) { TEST(GetRawPointerTest, WorksForRawPointers) { int* p = NULL; - EXPECT_EQ(NULL, GetRawPointer(p)); + // Don't use EXPECT_EQ as no NULL-testing magic on Symbian. + EXPECT_TRUE(NULL == GetRawPointer(p)); int n = 1; EXPECT_EQ(&n, GetRawPointer(&n)); } diff --git a/test/gmock-matchers_test.cc b/test/gmock-matchers_test.cc index fe88c64..20b9387 100644 --- a/test/gmock-matchers_test.cc +++ b/test/gmock-matchers_test.cc @@ -699,10 +699,20 @@ TEST(IsNullTest, MatchesNullPointer) { EXPECT_TRUE(m2.Matches(p2)); EXPECT_FALSE(m2.Matches("hi")); +#if !GTEST_OS_SYMBIAN + // Nokia's Symbian compiler generates: + // gmock-matchers.h: ambiguous access to overloaded function + // gmock-matchers.h: 'testing::Matcher::Matcher(void *)' + // gmock-matchers.h: 'testing::Matcher::Matcher(const testing:: + // MatcherInterface *)' + // gmock-matchers.h: (point of instantiation: 'testing:: + // gmock_matchers_test::IsNullTest_MatchesNullPointer_Test::TestBody()') + // gmock-matchers.h: (instantiating: 'testing::PolymorphicMatc Matcher m3 = IsNull(); void* p3 = NULL; EXPECT_TRUE(m3.Matches(p3)); EXPECT_FALSE(m3.Matches(reinterpret_cast(0xbeef))); +#endif } // Tests that IsNull() describes itself properly. @@ -933,24 +943,24 @@ TEST(KeyTest, SafelyCastsInnerMatcher) { } TEST(KeyTest, InsideContainsUsingMap) { - std::map container; - container.insert(std::make_pair(1, "foo")); - container.insert(std::make_pair(2, "bar")); - container.insert(std::make_pair(4, "baz")); + std::map container; + container.insert(std::make_pair(1, 'a')); + container.insert(std::make_pair(2, 'b')); + container.insert(std::make_pair(4, 'c')); EXPECT_THAT(container, Contains(Key(1))); EXPECT_THAT(container, Not(Contains(Key(3)))); } TEST(KeyTest, InsideContainsUsingMultimap) { - std::multimap container; - container.insert(std::make_pair(1, "foo")); - container.insert(std::make_pair(2, "bar")); - container.insert(std::make_pair(4, "baz")); + std::multimap container; + container.insert(std::make_pair(1, 'a')); + container.insert(std::make_pair(2, 'b')); + container.insert(std::make_pair(4, 'c')); EXPECT_THAT(container, Not(Contains(Key(25)))); - container.insert(std::make_pair(25, "more foo")); + container.insert(std::make_pair(25, 'd')); EXPECT_THAT(container, Contains(Key(25))); - container.insert(std::make_pair(25, "more bar")); + container.insert(std::make_pair(25, 'e')); EXPECT_THAT(container, Contains(Key(25))); EXPECT_THAT(container, Contains(Key(1))); @@ -1031,13 +1041,13 @@ TEST(PairTest, SafelyCastsInnerMatchers) { } TEST(PairTest, InsideContainsUsingMap) { - std::map container; - container.insert(std::make_pair(1, "foo")); - container.insert(std::make_pair(2, "bar")); - container.insert(std::make_pair(4, "baz")); - EXPECT_THAT(container, Contains(Pair(1, "foo"))); + std::map container; + container.insert(std::make_pair(1, 'a')); + container.insert(std::make_pair(2, 'b')); + container.insert(std::make_pair(4, 'c')); + EXPECT_THAT(container, Contains(Pair(1, 'a'))); EXPECT_THAT(container, Contains(Pair(1, _))); - EXPECT_THAT(container, Contains(Pair(_, "foo"))); + EXPECT_THAT(container, Contains(Pair(_, 'a'))); EXPECT_THAT(container, Not(Contains(Pair(3, _)))); } @@ -1961,8 +1971,20 @@ TEST(MatcherAssertionTest, WorksForByRefArguments) { "Actual: 0 (is located @"); } +#if !GTEST_OS_SYMBIAN // Tests that ASSERT_THAT() and EXPECT_THAT() work when the matcher is // monomorphic. + +// ASSERT_THAT("hello", starts_with_he) fails to compile with Nokia's +// Symbian compiler: it tries to compile +// template class MatcherCastImpl { ... +// virtual bool Matches(T x) const { +// return source_matcher_.Matches(static_cast(x)); +// with U == string and T == const char* +// With ASSERT_THAT("hello"...) changed to ASSERT_THAT(string("hello") ... ) +// the compiler silently crashes with no output. +// If MatcherCastImpl is changed to use U(x) instead of static_cast(x) +// the code compiles but the converted string is bogus. TEST(MatcherAssertionTest, WorksForMonomorphicMatcher) { Matcher starts_with_he = StartsWith("he"); ASSERT_THAT("hello", starts_with_he); @@ -1976,6 +1998,7 @@ TEST(MatcherAssertionTest, WorksForMonomorphicMatcher) { "Expected: is greater than 5\n" " Actual: 5"); } +#endif // !GTEST_OS_SYMBIAN // Tests floating-point matchers. template diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc index 0eb8e09..4b900c5 100644 --- a/test/gmock-printers_test.cc +++ b/test/gmock-printers_test.cc @@ -840,16 +840,16 @@ TEST(PrintTupleTest, VariousSizes) { const char* const str = "8"; tuple - t10(false, 'a', 3, 4, 5, 6.5F, 7.5, str, NULL, "10"); - EXPECT_EQ("(false, 'a' (97), 3, 4, 5, 6.5, 7.5, " + PrintPointer(str) + + t10(false, 'a', 3, 4, 5, 1.5F, -2.5, str, NULL, "10"); + EXPECT_EQ("(false, 'a' (97), 3, 4, 5, 1.5, -2.5, " + PrintPointer(str) + " pointing to \"8\", NULL, \"10\")", Print(t10)); } // Nested tuples. TEST(PrintTupleTest, NestedTuple) { - tuple, char> nested(make_tuple(5, 9.5), 'a'); - EXPECT_EQ("((5, 9.5), 'a' (97))", Print(nested)); + tuple, char> nested(make_tuple(5, true), 'a'); + EXPECT_EQ("((5, true), 'a' (97))", Print(nested)); } // Tests printing user-defined unprintable types. -- cgit v1.2.1