Commit 16cf4739 authored by zhanyong.wan's avatar zhanyong.wan
Browse files

Finishes SafeMatcherCast by catching lossy arithmetic conversions at...

Finishes SafeMatcherCast by catching lossy arithmetic conversions at compile-time; uses ACTION_TEMPLATE to simplify the definition of many actions; makes mock object uncopyable; teaches gmock doctor about wrong MOCK_METHODn.
parent c6a41239
This diff is collapsed.
...@@ -198,77 +198,6 @@ $var Ts = [[$for j, [[T$j]]]] ...@@ -198,77 +198,6 @@ $var Ts = [[$for j, [[T$j]]]]
}; // class CallableHelper }; // class CallableHelper
// Invokes a nullary callable argument.
template <size_t N>
class InvokeArgumentAction0 {
public:
template <typename Result, typename ArgumentTuple>
static Result Perform(const ArgumentTuple& args) {
return CallableHelper<Result>::Call(::std::tr1::get<N>(args));
}
};
// Invokes a unary callable argument with the given argument.
template <size_t N, typename A1>
class InvokeArgumentAction1 {
public:
// We deliberately pass a1 by value instead of const reference here
// in case it is a C-string literal.
//
// Since this function is defined inline, the compiler can get rid
// of the copying of the arguments. Therefore the performance won't
// be hurt.
explicit InvokeArgumentAction1(A1 a1) : arg1_(a1) {}
template <typename Result, typename ArgumentTuple>
Result Perform(const ArgumentTuple& args) {
return CallableHelper<Result>::Call(::std::tr1::get<N>(args), arg1_);
}
private:
const A1 arg1_;
};
$range i 2..n
$for i [[
$var arity = [[$if 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[[]]_]]]]
// Invokes a $arity callable argument with the given arguments.
template <size_t N, $typename_As>
class InvokeArgumentAction$i {
public:
InvokeArgumentAction$i($for j, [[A$j a$j]]) :
$for j, [[arg$j[[]]_(a$j)]] {}
template <typename Result, typename ArgumentTuple>
Result Perform(const ArgumentTuple& args) {
$if i <= 4 [[
return CallableHelper<Result>::Call(::std::tr1::get<N>(args), $args_);
]] $else [[
// We extract the callable to a variable before invoking it, in
// case it is a functor passed by value and its operator() is not
// const.
typename ::std::tr1::tuple_element<N, ArgumentTuple>::type function =
::std::tr1::get<N>(args);
return function($args_);
]]
}
private:
$for j [[
const A$j arg$j[[]]_;
]]
};
]]
// An INTERNAL macro for extracting the type of a tuple field. It's // An INTERNAL macro for extracting the type of a tuple field. It's
// subject to change without notice - DO NOT USE IN USER CODE! // subject to change without notice - DO NOT USE IN USER CODE!
#define GMOCK_FIELD_(Tuple, N) \ #define GMOCK_FIELD_(Tuple, N) \
...@@ -478,74 +407,6 @@ inline internal::ReferenceWrapper<T> ByRef(T& l_value) { // NOLINT ...@@ -478,74 +407,6 @@ inline internal::ReferenceWrapper<T> ByRef(T& l_value) { // NOLINT
return internal::ReferenceWrapper<T>(l_value); return internal::ReferenceWrapper<T>(l_value);
} }
// Various overloads for InvokeArgument<N>().
//
// The InvokeArgument<N>(a1, a2, ..., a_k) action invokes the N-th
// (0-based) argument, which must be a k-ary callable, of the mock
// function, with arguments a1, a2, ..., a_k.
//
// Notes:
//
// 1. The arguments are passed by value by default. If you need to
// pass an argument by reference, wrap it inside ByRef(). For
// example,
//
// InvokeArgument<1>(5, string("Hello"), ByRef(foo))
//
// passes 5 and string("Hello") by value, and passes foo by
// reference.
//
// 2. If the callable takes an argument by reference but ByRef() is
// not used, it will receive the reference to a copy of the value,
// instead of the original value. For example, when the 0-th
// argument of the mock function takes a const string&, the action
//
// InvokeArgument<0>(string("Hello"))
//
// makes a copy of the temporary string("Hello") object and passes a
// reference of the copy, instead of the original temporary object,
// to the callable. This makes it easy for a user to define an
// InvokeArgument action from temporary values and have it performed
// later.
template <size_t N>
inline PolymorphicAction<internal::InvokeArgumentAction0<N> > InvokeArgument() {
return MakePolymorphicAction(internal::InvokeArgumentAction0<N>());
}
// We deliberately pass a1 by value instead of const reference here in
// case it is a C-string literal. If we had declared the parameter as
// 'const A1& a1' and write InvokeArgument<0>("Hi"), the compiler
// would've thought A1 is 'char[3]', which causes trouble as the
// implementation needs to copy a value of type A1. By declaring the
// parameter as 'A1 a1', the compiler will correctly infer that A1 is
// 'const char*' when it sees InvokeArgument<0>("Hi").
//
// Since this function is defined inline, the compiler can get rid of
// the copying of the arguments. Therefore the performance won't be
// hurt.
template <size_t N, typename A1>
inline PolymorphicAction<internal::InvokeArgumentAction1<N, A1> >
InvokeArgument(A1 a1) {
return MakePolymorphicAction(internal::InvokeArgumentAction1<N, A1>(a1));
}
$range i 2..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 <size_t N, $typename_As>
inline PolymorphicAction<internal::InvokeArgumentAction$i<N, $As> >
InvokeArgument($Aas) {
return MakePolymorphicAction(
internal::InvokeArgumentAction$i<N, $As>($as));
}
]]
// WithoutArgs(inner_action) can be used in a mock function with a // WithoutArgs(inner_action) can be used in a mock function with a
// non-empty argument list to perform inner_action, which takes no // non-empty argument list to perform inner_action, which takes no
// argument. In other words, it adapts an action accepting no // argument. In other words, it adapts an action accepting no
...@@ -1025,76 +886,89 @@ $$ // show up in the generated code. ...@@ -1025,76 +886,89 @@ $$ // show up in the generated code.
// updated. // updated.
namespace testing { namespace testing {
namespace internal { // Various overloads for InvokeArgument<N>().
//
// Saves argument #0 to where the pointer points. // The InvokeArgument<N>(a1, a2, ..., a_k) action invokes the N-th
ACTION_P(SaveArg0, pointer) { *pointer = arg0; } // (0-based) argument, which must be a k-ary callable, of the mock
// function, with arguments a1, a2, ..., a_k.
// Assigns 'value' to the variable referenced by argument #0. //
ACTION_P(SetArg0Referee, value) { // Notes:
// Ensures that argument #0 is a reference. If you get a compiler //
// error on the next line, you are using SetArgReferee<k>(value) in // 1. The arguments are passed by value by default. If you need to
// a mock function whose k-th (0-based) argument is not a reference. // pass an argument by reference, wrap it inside ByRef(). For
GMOCK_COMPILE_ASSERT_(internal::is_reference<arg0_type>::value, // example,
SetArgReferee_must_be_used_with_a_reference_argument); //
arg0 = value; // InvokeArgument<1>(5, string("Hello"), ByRef(foo))
} //
// passes 5 and string("Hello") by value, and passes foo by
// reference.
//
// 2. If the callable takes an argument by reference but ByRef() is
// not used, it will receive the reference to a copy of the value,
// instead of the original value. For example, when the 0-th
// argument of the mock function takes a const string&, the action
//
// InvokeArgument<0>(string("Hello"))
//
// makes a copy of the temporary string("Hello") object and passes a
// reference of the copy, instead of the original temporary object,
// to the callable. This makes it easy for a user to define an
// InvokeArgument action from temporary values and have it performed
// later.
// 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 $range i 0..n
$for i [[ $for i [[
$var arity = [[ $if i==0 [[nullary]] $range j 0..i-1
$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[[]]_;
]]
}; ACTION_TEMPLATE(InvokeArgument,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_$i[[]]_VALUE_PARAMS($for j, [[p$j]])) {
return internal::CallableHelper<return_type>::Call(
::std::tr1::get<k>(args)$for j [[, p$j]]);
}
]] ]]
// Deletes the object pointed to by argument #0.
ACTION(DeleteArg0) { delete arg0; }
} // 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
// mock function to *pointer. // mock function to *pointer.
template <int k, typename Pointer> ACTION_TEMPLATE(SaveArg,
inline internal::WithArgsAction<internal::SaveArg0ActionP<Pointer>, k> HAS_1_TEMPLATE_PARAMS(int, k),
SaveArg(const Pointer& pointer) { AND_1_VALUE_PARAMS(pointer)) {
return WithArg<k>(internal::SaveArg0(pointer)); *pointer = ::std::tr1::get<k>(args);
} }
// Action SetArgReferee<k>(value) assigns 'value' to the variable // Action SetArgReferee<k>(value) assigns 'value' to the variable
// referenced by the k-th (0-based) argument of the mock function. // referenced by the k-th (0-based) argument of the mock function.
template <int k, typename Value> ACTION_TEMPLATE(SetArgReferee,
inline internal::WithArgsAction<internal::SetArg0RefereeActionP<Value>, k> HAS_1_TEMPLATE_PARAMS(int, k),
SetArgReferee(const Value& value) { AND_1_VALUE_PARAMS(value)) {
return WithArg<k>(internal::SetArg0Referee(value)); typedef typename ::std::tr1::tuple_element<k, args_type>::type argk_type;
// Ensures that argument #k is a reference. If you get a compiler
// error on the next line, you are using SetArgReferee<k>(value) in
// a mock function whose k-th (0-based) argument is not a reference.
GMOCK_COMPILE_ASSERT_(internal::is_reference<argk_type>::value,
SetArgReferee_must_be_used_with_a_reference_argument);
::std::tr1::get<k>(args) = value;
}
// Action SetArrayArgument<k>(first, last) copies the elements in
// source range [first, last) to the array pointed to by the k-th
// (0-based) argument, which can be either a pointer or an
// iterator. The action does not take ownership of the elements in the
// source range.
ACTION_TEMPLATE(SetArrayArgument,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_2_VALUE_PARAMS(first, last)) {
// Microsoft compiler deprecates ::std::copy, so we want to suppress warning
// 4996 (Function call with parameters that may be unsafe) there.
#ifdef _MSC_VER
#pragma warning(push) // Saves the current warning state.
#pragma warning(disable:4996) // Temporarily disables warning 4996.
#endif
::std::copy(first, last, ::std::tr1::get<k>(args));
#ifdef _MSC_VER
#pragma warning(pop) // Restores the warning state.
#endif
} }
// Various overloads for ReturnNew<T>(). // Various overloads for ReturnNew<T>().
...@@ -1104,27 +978,23 @@ SetArgReferee(const Value& value) { ...@@ -1104,27 +978,23 @@ SetArgReferee(const Value& value) {
// a1, a2, ..., and a_k. The caller assumes ownership of the returned value. // a1, a2, ..., and a_k. The caller assumes ownership of the returned value.
$range i 0..n $range i 0..n
$for i [[ $for i [[
$range j 1..i $range j 0..i-1
$var typename_As = [[$for j [[, typename A$j]]]] $var ps = [[$for j, [[p$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> ACTION_TEMPLATE(ReturnNew,
inline PolymorphicAction<internal::ReturnNewAction$i<T$As> > HAS_1_TEMPLATE_PARAMS(typename, T),
ReturnNew($Aas) { AND_$i[[]]_VALUE_PARAMS($ps)) {
return MakePolymorphicAction( return new T($ps);
internal::ReturnNewAction$i<T$As>($as));
} }
]] ]]
// Action DeleteArg<k>() deletes the k-th (0-based) argument of the mock // Action DeleteArg<k>() deletes the k-th (0-based) argument of the mock
// function. // function.
template <int k> ACTION_TEMPLATE(DeleteArg,
inline internal::WithArgsAction<internal::DeleteArg0Action, k> HAS_1_TEMPLATE_PARAMS(int, k),
DeleteArg() { AND_0_VALUE_PARAMS()) {
return WithArg<k>(internal::DeleteArg0()); delete ::std::tr1::get<k>(args);
} }
// 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
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
#include <algorithm> #include <algorithm>
#include <limits>
#include <ostream> // NOLINT #include <ostream> // NOLINT
#include <sstream> #include <sstream>
#include <string> #include <string>
...@@ -340,6 +341,16 @@ Matcher<T> SafeMatcherCast(const Matcher<U>& matcher) { ...@@ -340,6 +341,16 @@ Matcher<T> SafeMatcherCast(const Matcher<U>& matcher) {
GMOCK_COMPILE_ASSERT_( GMOCK_COMPILE_ASSERT_(
internal::is_reference<T>::value || !internal::is_reference<U>::value, internal::is_reference<T>::value || !internal::is_reference<U>::value,
cannot_convert_non_referentce_arg_to_reference); 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<RawT, RawU>::value),
conversion_of_arithmetic_types_must_be_lossless);
return MatcherCast<T>(matcher); return MatcherCast<T>(matcher);
} }
...@@ -1164,8 +1175,8 @@ class EitherOfMatcher { ...@@ -1164,8 +1175,8 @@ class EitherOfMatcher {
// both Matcher1 and Matcher2 can match. // both Matcher1 and Matcher2 can match.
template <typename T> template <typename T>
operator Matcher<T>() const { operator Matcher<T>() const {
return Matcher<T>(new EitherOfMatcherImpl<T>(SafeMatcherCast<T>(matcher1_), return Matcher<T>(new EitherOfMatcherImpl<T>(
SafeMatcherCast<T>(matcher2_))); SafeMatcherCast<T>(matcher1_), SafeMatcherCast<T>(matcher2_)));
} }
private: private:
Matcher1 matcher1_; Matcher1 matcher1_;
...@@ -1184,7 +1195,7 @@ class TrulyMatcher { ...@@ -1184,7 +1195,7 @@ class TrulyMatcher {
// argument is passed by reference as the predicate may be // argument is passed by reference as the predicate may be
// interested in the address of the argument. // interested in the address of the argument.
template <typename T> template <typename T>
bool Matches(T& x) const { bool Matches(T& x) const { // NOLINT
#if GTEST_OS_WINDOWS #if GTEST_OS_WINDOWS
// MSVC warns about converting a value into bool (warning 4800). // MSVC warns about converting a value into bool (warning 4800).
#pragma warning(push) // Saves the current warning state. #pragma warning(push) // Saves the current warning state.
......
...@@ -341,12 +341,11 @@ inline void PrintTo(char* s, ::std::ostream* os) { ...@@ -341,12 +341,11 @@ inline void PrintTo(char* s, ::std::ostream* os) {
PrintTo(implicit_cast<const char*>(s), os); PrintTo(implicit_cast<const char*>(s), os);
} }
// MSVC compiler can be configured to define whar_t as a typedef // MSVC can be configured to define wchar_t as a typedef of unsigned
// of unsigned short. Defining an overload for const wchar_t* in that case // short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
// would cause pointers to unsigned shorts be printed as wide strings, // type. When wchar_t is a typedef, defining an overload for const
// possibly accessing more memory than intended and causing invalid // wchar_t* would cause unsigned short* be printed as a wide string,
// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when // possibly causing invalid memory accesses.
// wchar_t is implemented as a native type.
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
// Overloads for wide C strings // Overloads for wide C strings
void PrintTo(const wchar_t* s, ::std::ostream* os); void PrintTo(const wchar_t* s, ::std::ostream* os);
......
...@@ -1359,6 +1359,20 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { ...@@ -1359,6 +1359,20 @@ class FunctionMockerBase : public UntypedFunctionMockerBase {
std::vector<DefaultActionSpec<F> > default_actions_; std::vector<DefaultActionSpec<F> > default_actions_;
// All expectations for this function mocker. // All expectations for this function mocker.
Expectations expectations_; Expectations expectations_;
// There is no generally useful and implementable semantics of
// copying a mock object, so copying a mock is usually a user error.
// Thus we disallow copying function mockers. If the user really
// wants to copy a mock object, he should implement his own copy
// operation, for example:
//
// class MockFoo : public Foo {
// public:
// // Defines a copy constructor explicitly.
// MockFoo(const MockFoo& src) {}
// ...
// };
GTEST_DISALLOW_COPY_AND_ASSIGN_(FunctionMockerBase);
}; // class FunctionMockerBase }; // class FunctionMockerBase
#ifdef _MSC_VER #ifdef _MSC_VER
......
...@@ -157,7 +157,7 @@ inline Element* GetRawPointer(Element* p) { return p; } ...@@ -157,7 +157,7 @@ inline Element* GetRawPointer(Element* p) { return p; }
// This comparator allows linked_ptr to be stored in sets. // This comparator allows linked_ptr to be stored in sets.
template <typename T> template <typename T>
struct LinkedPtrLessThan { struct LinkedPtrLessThan {
bool operator()(const ::testing::internal::linked_ptr<T>& lhs, bool operator()(const ::testing::internal::linked_ptr<T>& lhs,
const ::testing::internal::linked_ptr<T>& rhs) const { const ::testing::internal::linked_ptr<T>& rhs) const {
return lhs.get() < rhs.get(); return lhs.get() < rhs.get();
} }
...@@ -210,17 +210,154 @@ class ImplicitlyConvertible { ...@@ -210,17 +210,154 @@ class ImplicitlyConvertible {
template <typename From, typename To> template <typename From, typename To>
const bool ImplicitlyConvertible<From, To>::value; const bool ImplicitlyConvertible<From, To>::value;
// 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
// when a matcher argument type can be safely converted to another
// type in the implementation of SafeMatcherCast.
enum TypeKind {
kBool, kInteger, kFloatingPoint, kOther
};
// KindOf<T>::value is the kind of type T.
template <typename T> struct KindOf {
enum { value = kOther }; // The default kind.
};
// This macro declares that the kind of 'type' is 'kind'.
#define GMOCK_DECLARE_KIND_(type, kind) \
template <> struct KindOf<type> { enum { value = kind }; }
GMOCK_DECLARE_KIND_(bool, kBool);
// All standard integer types.
GMOCK_DECLARE_KIND_(char, kInteger);
GMOCK_DECLARE_KIND_(signed char, kInteger);
GMOCK_DECLARE_KIND_(unsigned char, kInteger);
GMOCK_DECLARE_KIND_(short, kInteger); // NOLINT
GMOCK_DECLARE_KIND_(unsigned short, kInteger); // NOLINT
GMOCK_DECLARE_KIND_(int, kInteger);
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)
GMOCK_DECLARE_KIND_(wchar_t, kInteger);
#endif
// Non-standard integer types.
GMOCK_DECLARE_KIND_(Int64, kInteger);
GMOCK_DECLARE_KIND_(UInt64, kInteger);
// All standard floating-point types.
GMOCK_DECLARE_KIND_(float, kFloatingPoint);
GMOCK_DECLARE_KIND_(double, kFloatingPoint);
GMOCK_DECLARE_KIND_(long double, kFloatingPoint);
#undef GMOCK_DECLARE_KIND_
// Evaluates to the kind of 'type'.
#define GMOCK_KIND_OF_(type) \
static_cast< ::testing::internal::TypeKind>( \
::testing::internal::KindOf<type>::value)
// Evaluates to true iff integer type T is signed.
#define GMOCK_IS_SIGNED_(T) (static_cast<T>(-1) < 0)
// LosslessArithmeticConvertibleImpl<kFromKind, From, kToKind, To>::value
// is true iff arithmetic type From can be losslessly converted to
// arithmetic type To.
//
// It's the user's responsibility to ensure that both From and To are
// raw (i.e. has no CV modifier, is not a pointer, and is not a
// reference) built-in arithmetic types, kFromKind is the kind of
// From, and kToKind is the kind of To; the value is
// implementation-defined when the above pre-condition is violated.
template <TypeKind kFromKind, typename From, TypeKind kToKind, typename To>
struct LosslessArithmeticConvertibleImpl : public false_type {};
// Converting bool to bool is lossless.
template <>
struct LosslessArithmeticConvertibleImpl<kBool, bool, kBool, bool>
: public true_type {}; // NOLINT
// Converting bool to any integer type is lossless.
template <typename To>
struct LosslessArithmeticConvertibleImpl<kBool, bool, kInteger, To>
: public true_type {}; // NOLINT
// Converting bool to any floating-point type is lossless.
template <typename To>
struct LosslessArithmeticConvertibleImpl<kBool, bool, kFloatingPoint, To>
: public true_type {}; // NOLINT
// Converting an integer to bool is lossy.
template <typename From>
struct LosslessArithmeticConvertibleImpl<kInteger, From, kBool, bool>
: public false_type {}; // NOLINT
// Converting an integer to another non-bool integer is lossless iff
// the target type's range encloses the source type's range.
template <typename From, typename To>
struct LosslessArithmeticConvertibleImpl<kInteger, From, kInteger, To>
: public bool_constant<
// When converting from a smaller size to a larger size, we are
// fine as long as we are not converting from signed to unsigned.
((sizeof(From) < sizeof(To)) &&
(!GMOCK_IS_SIGNED_(From) || GMOCK_IS_SIGNED_(To))) ||
// When converting between the same size, the signedness must match.
((sizeof(From) == sizeof(To)) &&
(GMOCK_IS_SIGNED_(From) == GMOCK_IS_SIGNED_(To)))> {}; // NOLINT
#undef GMOCK_IS_SIGNED_
// Converting an integer to a floating-point type may be lossy, since
// the format of a floating-point number is implementation-defined.
template <typename From, typename To>
struct LosslessArithmeticConvertibleImpl<kInteger, From, kFloatingPoint, To>
: public false_type {}; // NOLINT
// Converting a floating-point to bool is lossy.
template <typename From>
struct LosslessArithmeticConvertibleImpl<kFloatingPoint, From, kBool, bool>
: public false_type {}; // NOLINT
// Converting a floating-point to an integer is lossy.
template <typename From, typename To>
struct LosslessArithmeticConvertibleImpl<kFloatingPoint, From, kInteger, To>
: public false_type {}; // NOLINT
// Converting a floating-point to another floating-point is lossless
// iff the target type is at least as big as the source type.
template <typename From, typename To>
struct LosslessArithmeticConvertibleImpl<
kFloatingPoint, From, kFloatingPoint, To>
: public bool_constant<sizeof(From) <= sizeof(To)> {}; // NOLINT
// LosslessArithmeticConvertible<From, To>::value is true iff arithmetic
// type From can be losslessly converted to arithmetic type To.
//
// It's the user's responsibility to ensure that both From and To are
// raw (i.e. has no CV modifier, is not a pointer, and is not a
// reference) built-in arithmetic types; the value is
// implementation-defined when the above pre-condition is violated.
template <typename From, typename To>
struct LosslessArithmeticConvertible
: public LosslessArithmeticConvertibleImpl<
GMOCK_KIND_OF_(From), From, GMOCK_KIND_OF_(To), To> {}; // NOLINT
// IsAProtocolMessage<T>::value is a compile-time bool constant that's // IsAProtocolMessage<T>::value is a compile-time bool constant that's
// true iff T is type ProtocolMessage, proto2::Message, or a subclass // true iff T is type ProtocolMessage, proto2::Message, or a subclass
// of those. // of those.
template <typename T> template <typename T>
struct IsAProtocolMessage { struct IsAProtocolMessage
static const bool value = : public bool_constant<
ImplicitlyConvertible<const T*, const ::ProtocolMessage*>::value || ImplicitlyConvertible<const T*, const ::ProtocolMessage*>::value ||
ImplicitlyConvertible<const T*, const ::proto2::Message*>::value; ImplicitlyConvertible<const T*, const ::proto2::Message*>::value> {
}; };
template <typename T>
const bool IsAProtocolMessage<T>::value;
// When the compiler sees expression IsContainerTest<C>(0), the first // When the compiler sees expression IsContainerTest<C>(0), the first
// overload of IsContainerTest will be picked if C is an STL-style // overload of IsContainerTest will be picked if C is an STL-style
...@@ -314,6 +451,8 @@ void Log(LogSeverity severity, const string& message, int stack_frames_to_skip); ...@@ -314,6 +451,8 @@ void Log(LogSeverity severity, const string& message, int stack_frames_to_skip);
// to declare an unused << operator in the global namespace. // to declare an unused << operator in the global namespace.
struct Unused {}; struct Unused {};
// TODO(wan@google.com): group all type utilities together.
// Type traits. // Type traits.
// is_reference<T>::value is non-zero iff T is a reference type. // is_reference<T>::value is non-zero iff T is a reference type.
...@@ -325,8 +464,8 @@ template <typename T1, typename T2> struct type_equals : public false_type {}; ...@@ -325,8 +464,8 @@ template <typename T1, typename T2> struct type_equals : public false_type {};
template <typename T> struct type_equals<T, T> : public true_type {}; template <typename T> struct type_equals<T, T> : public true_type {};
// remove_reference<T>::type removes the reference from type T, if any. // remove_reference<T>::type removes the reference from type T, if any.
template <typename T> struct remove_reference { typedef T type; }; template <typename T> struct remove_reference { typedef T type; }; // NOLINT
template <typename T> struct remove_reference<T&> { typedef T type; }; template <typename T> struct remove_reference<T&> { typedef T type; }; // NOLINT
// Invalid<T>() returns an invalid value of type T. This is useful // Invalid<T>() returns an invalid value of type T. This is useful
// when a value of type T is needed for compilation, but the statement // when a value of type T is needed for compilation, but the statement
......
...@@ -36,7 +36,7 @@ __author__ = 'wan@google.com (Zhanyong Wan)' ...@@ -36,7 +36,7 @@ __author__ = 'wan@google.com (Zhanyong Wan)'
import re import re
import sys import sys
_VERSION = '0.1.0.80421' _VERSION = '1.0.0'
_COMMON_GMOCK_SYMBOLS = [ _COMMON_GMOCK_SYMBOLS = [
# Matchers # Matchers
...@@ -148,11 +148,14 @@ Please use ReturnRef() instead.""" ...@@ -148,11 +148,14 @@ Please use ReturnRef() instead."""
def _NeedToReturnSomethingDiagnoser(msg): def _NeedToReturnSomethingDiagnoser(msg):
"""Diagnoses the NRS disease, given the error messages by gcc.""" """Diagnoses the NRS disease, given the error messages by gcc."""
regex = (r'(?P<file>.*):(?P<line>\d+):\s+instantiated from here\n' regex = (r'(?P<file>.*):(?P<line>\d+):\s+'
r'.*gmock-actions\.h.*error: void value not ignored') r'(instantiated from here\n.'
r'*gmock-actions\.h.*error: void value not ignored)'
r'|(error: control reaches end of non-void function)')
diagnosis = """%(file)s:%(line)s: diagnosis = """%(file)s:%(line)s:
You are using an action that returns void, but it needs to return You are using an action that returns void, but it needs to return
*something*. Please tell it *what* to return.""" *something*. Please tell it *what* to return. Perhaps you can use
the pattern DoAll(some_action, Return(some_value))?"""
return _GenericDiagnoser('NRS', 'Need to Return Something', return _GenericDiagnoser('NRS', 'Need to Return Something',
regex, diagnosis, msg) regex, diagnosis, msg)
...@@ -324,6 +327,23 @@ Note: the line number may be off; please fix all instances of Return(NULL).""" ...@@ -324,6 +327,23 @@ Note: the line number may be off; please fix all instances of Return(NULL)."""
regex, diagnosis, msg) regex, diagnosis, msg)
def _WrongMockMethodMacroDiagnoser(msg):
"""Diagnoses the WMM disease, given the error messages by gcc."""
regex = (r'(?P<file>.*):(?P<line>\d+):\s+'
r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n'
r'.*\n'
r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>'
)
diagnosis = """%(file)s:%(line)s:
You are using MOCK_METHOD%(wrong_args)s to define a mock method that has
%(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s,
MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead."""
return _GenericDiagnoser('WMM', 'Wrong MOCK_METHODn macro',
regex, diagnosis, msg)
_DIAGNOSERS = [ _DIAGNOSERS = [
_IncompleteByReferenceArgumentDiagnoser, _IncompleteByReferenceArgumentDiagnoser,
...@@ -337,6 +357,7 @@ _DIAGNOSERS = [ ...@@ -337,6 +357,7 @@ _DIAGNOSERS = [
_OverloadedFunctionMatcherDiagnoser, _OverloadedFunctionMatcherDiagnoser,
_OverloadedMethodActionDiagnoser1, _OverloadedMethodActionDiagnoser1,
_OverloadedMethodActionDiagnoser2, _OverloadedMethodActionDiagnoser2,
_WrongMockMethodMacroDiagnoser,
] ]
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
// This file tests the internal utilities. // This file tests the internal utilities.
#include <gmock/internal/gmock-internal-utils.h> #include <gmock/internal/gmock-internal-utils.h>
#include <stdlib.h>
#include <map> #include <map>
#include <string> #include <string>
#include <sstream> #include <sstream>
...@@ -43,6 +44,10 @@ ...@@ -43,6 +44,10 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gtest/gtest-spi.h> #include <gtest/gtest-spi.h>
#if GTEST_OS_CYGWIN
#include <sys/types.h> // For ssize_t. NOLINT
#endif
namespace testing { namespace testing {
namespace internal { namespace internal {
...@@ -232,6 +237,141 @@ TEST(ImplicitlyConvertibleTest, ValueIsFalseWhenNotConvertible) { ...@@ -232,6 +237,141 @@ TEST(ImplicitlyConvertibleTest, ValueIsFalseWhenNotConvertible) {
EXPECT_FALSE((ImplicitlyConvertible<Base&, Derived&>::value)); EXPECT_FALSE((ImplicitlyConvertible<Base&, Derived&>::value));
} }
// Tests KindOf<T>.
TEST(KindOfTest, Bool) {
EXPECT_EQ(kBool, GMOCK_KIND_OF_(bool)); // NOLINT
}
TEST(KindOfTest, Integer) {
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(char)); // NOLINT
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(signed char)); // NOLINT
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(unsigned char)); // NOLINT
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(short)); // NOLINT
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(unsigned short)); // NOLINT
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(int)); // NOLINT
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(unsigned int)); // NOLINT
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(long)); // NOLINT
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(unsigned long)); // NOLINT
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(wchar_t)); // NOLINT
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(Int64)); // NOLINT
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(UInt64)); // NOLINT
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(size_t)); // NOLINT
#if GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN
// ssize_t is not defined on Windows and possibly some other OSes.
EXPECT_EQ(kInteger, GMOCK_KIND_OF_(ssize_t)); // NOLINT
#endif
}
TEST(KindOfTest, FloatingPoint) {
EXPECT_EQ(kFloatingPoint, GMOCK_KIND_OF_(float)); // NOLINT
EXPECT_EQ(kFloatingPoint, GMOCK_KIND_OF_(double)); // NOLINT
EXPECT_EQ(kFloatingPoint, GMOCK_KIND_OF_(long double)); // NOLINT
}
TEST(KindOfTest, Other) {
EXPECT_EQ(kOther, GMOCK_KIND_OF_(void*)); // NOLINT
EXPECT_EQ(kOther, GMOCK_KIND_OF_(char**)); // NOLINT
EXPECT_EQ(kOther, GMOCK_KIND_OF_(Base)); // NOLINT
}
// Tests LosslessArithmeticConvertible<T, U>.
TEST(LosslessArithmeticConvertibleTest, BoolToBool) {
EXPECT_TRUE((LosslessArithmeticConvertible<bool, bool>::value));
}
TEST(LosslessArithmeticConvertibleTest, BoolToInteger) {
EXPECT_TRUE((LosslessArithmeticConvertible<bool, char>::value));
EXPECT_TRUE((LosslessArithmeticConvertible<bool, int>::value));
EXPECT_TRUE(
(LosslessArithmeticConvertible<bool, unsigned long>::value)); // NOLINT
}
TEST(LosslessArithmeticConvertibleTest, BoolToFloatingPoint) {
EXPECT_TRUE((LosslessArithmeticConvertible<bool, float>::value));
EXPECT_TRUE((LosslessArithmeticConvertible<bool, double>::value));
}
TEST(LosslessArithmeticConvertibleTest, IntegerToBool) {
EXPECT_FALSE((LosslessArithmeticConvertible<unsigned char, bool>::value));
EXPECT_FALSE((LosslessArithmeticConvertible<int, bool>::value));
}
TEST(LosslessArithmeticConvertibleTest, IntegerToInteger) {
// Unsigned => larger signed is fine.
EXPECT_TRUE((LosslessArithmeticConvertible<unsigned char, int>::value));
// Unsigned => larger unsigned is fine.
EXPECT_TRUE(
(LosslessArithmeticConvertible<unsigned short, UInt64>::value)); // NOLINT
// Signed => unsigned is not fine.
EXPECT_FALSE((LosslessArithmeticConvertible<short, UInt64>::value)); // NOLINT
EXPECT_FALSE((LosslessArithmeticConvertible<
signed char, unsigned int>::value)); // NOLINT
// Same size and same signedness: fine too.
EXPECT_TRUE((LosslessArithmeticConvertible<
unsigned char, unsigned char>::value));
EXPECT_TRUE((LosslessArithmeticConvertible<int, int>::value));
EXPECT_TRUE((LosslessArithmeticConvertible<wchar_t, wchar_t>::value));
EXPECT_TRUE((LosslessArithmeticConvertible<
unsigned long, unsigned long>::value)); // NOLINT
// Same size, different signedness: not fine.
EXPECT_FALSE((LosslessArithmeticConvertible<
unsigned char, signed char>::value));
EXPECT_FALSE((LosslessArithmeticConvertible<int, unsigned int>::value));
EXPECT_FALSE((LosslessArithmeticConvertible<UInt64, Int64>::value));
// Larger size => smaller size is not fine.
EXPECT_FALSE((LosslessArithmeticConvertible<long, char>::value)); // NOLINT
EXPECT_FALSE((LosslessArithmeticConvertible<int, signed char>::value));
EXPECT_FALSE((LosslessArithmeticConvertible<Int64, unsigned int>::value));
}
TEST(LosslessArithmeticConvertibleTest, IntegerToFloatingPoint) {
// Integers cannot be losslessly converted to floating-points, as
// the format of the latter is implementation-defined.
EXPECT_FALSE((LosslessArithmeticConvertible<char, float>::value));
EXPECT_FALSE((LosslessArithmeticConvertible<int, double>::value));
EXPECT_FALSE((LosslessArithmeticConvertible<
short, long double>::value)); // NOLINT
}
TEST(LosslessArithmeticConvertibleTest, FloatingPointToBool) {
EXPECT_FALSE((LosslessArithmeticConvertible<float, bool>::value));
EXPECT_FALSE((LosslessArithmeticConvertible<double, bool>::value));
}
TEST(LosslessArithmeticConvertibleTest, FloatingPointToInteger) {
EXPECT_FALSE((LosslessArithmeticConvertible<float, long>::value)); // NOLINT
EXPECT_FALSE((LosslessArithmeticConvertible<double, Int64>::value));
EXPECT_FALSE((LosslessArithmeticConvertible<long double, int>::value));
}
TEST(LosslessArithmeticConvertibleTest, FloatingPointToFloatingPoint) {
// Smaller size => larger size is fine.
EXPECT_TRUE((LosslessArithmeticConvertible<float, double>::value));
EXPECT_TRUE((LosslessArithmeticConvertible<float, long double>::value));
EXPECT_TRUE((LosslessArithmeticConvertible<double, long double>::value));
// Same size: fine.
EXPECT_TRUE((LosslessArithmeticConvertible<float, float>::value));
EXPECT_TRUE((LosslessArithmeticConvertible<double, double>::value));
// Larger size => smaller size is not fine.
EXPECT_FALSE((LosslessArithmeticConvertible<double, float>::value));
if (sizeof(double) == sizeof(long double)) { // NOLINT
// In some implementations (e.g. MSVC), double and long double
// have the same size.
EXPECT_TRUE((LosslessArithmeticConvertible<long double, double>::value));
} else {
EXPECT_FALSE((LosslessArithmeticConvertible<long double, double>::value));
}
}
// Tests that IsAProtocolMessage<T>::value is a compile-time constant. // Tests that IsAProtocolMessage<T>::value is a compile-time constant.
TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) {
GMOCK_COMPILE_ASSERT_(IsAProtocolMessage<ProtocolMessage>::value, const_true); GMOCK_COMPILE_ASSERT_(IsAProtocolMessage<ProtocolMessage>::value, const_true);
...@@ -265,8 +405,10 @@ TEST(IsContainerTestTest, WorksForNonContainer) { ...@@ -265,8 +405,10 @@ TEST(IsContainerTestTest, WorksForNonContainer) {
} }
TEST(IsContainerTestTest, WorksForContainer) { TEST(IsContainerTestTest, WorksForContainer) {
EXPECT_EQ(sizeof(IsContainer), sizeof(IsContainerTest<std::vector<bool> >(0))); EXPECT_EQ(sizeof(IsContainer),
EXPECT_EQ(sizeof(IsContainer), sizeof(IsContainerTest<std::map<int, double> >(0))); sizeof(IsContainerTest<std::vector<bool> >(0)));
EXPECT_EQ(sizeof(IsContainer),
sizeof(IsContainerTest<std::map<int, double> >(0)));
} }
// Tests the TupleMatches() template function. // Tests the TupleMatches() template function.
......
...@@ -376,13 +376,18 @@ TEST(SafeMatcherCastTest, FromPolymorphicMatcher) { ...@@ -376,13 +376,18 @@ TEST(SafeMatcherCastTest, FromPolymorphicMatcher) {
EXPECT_FALSE(m2.Matches('\n')); EXPECT_FALSE(m2.Matches('\n'));
} }
// Tests that SafeMatcherCast<T>(m) works when m is a Matcher<U> where T // Tests that SafeMatcherCast<T>(m) works when m is a Matcher<U> where
// can be implicitly converted to U. // T and U are arithmetic types and T can be losslessly converted to
TEST(SafeMatcherCastTest, FromImplicitlyConvertibleType) { // U.
TEST(SafeMatcherCastTest, FromLosslesslyConvertibleArithmeticType) {
Matcher<double> m1 = DoubleEq(1.0); Matcher<double> m1 = DoubleEq(1.0);
Matcher<int> m2 = SafeMatcherCast<int>(m1); Matcher<float> m2 = SafeMatcherCast<float>(m1);
EXPECT_TRUE(m2.Matches(1)); EXPECT_TRUE(m2.Matches(1.0f));
EXPECT_FALSE(m2.Matches(2)); EXPECT_FALSE(m2.Matches(2.0f));
Matcher<char> m3 = SafeMatcherCast<char>(TypedEq<int>('a'));
EXPECT_TRUE(m3.Matches('a'));
EXPECT_FALSE(m3.Matches('b'));
} }
// Tests that SafeMatcherCast<T>(m) works when m is a Matcher<U> where T and U // Tests that SafeMatcherCast<T>(m) works when m is a Matcher<U> where T and U
......
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