Makes all container matchers work with (possibly multi-dimensional) native arrays; makes Contains() accept a matcher; adds Value(x, m); improves gmock doctor to diagnose the Type in Template Base disease.
This commit is contained in:
@@ -99,6 +99,17 @@ struct RemoveConst { typedef T type; }; // NOLINT
|
||||
template <typename T>
|
||||
struct RemoveConst<const T> { typedef T type; }; // NOLINT
|
||||
|
||||
// MSVC 8.0 has a bug which causes the above definition to fail to
|
||||
// remove the const in 'const int[3]'. The following specialization
|
||||
// works around the bug. However, it causes trouble with gcc and thus
|
||||
// needs to be conditionally compiled.
|
||||
#ifdef _MSC_VER
|
||||
template <typename T, size_t N>
|
||||
struct RemoveConst<T[N]> {
|
||||
typedef typename RemoveConst<T>::type type[N];
|
||||
};
|
||||
#endif // _MSC_VER
|
||||
|
||||
// A handy wrapper around RemoveConst that works when the argument
|
||||
// T depends on template parameters.
|
||||
#define GMOCK_REMOVE_CONST_(T) \
|
||||
@@ -451,10 +462,6 @@ bool LogIsVisible(LogSeverity severity);
|
||||
// conservative.
|
||||
void Log(LogSeverity severity, const string& message, int stack_frames_to_skip);
|
||||
|
||||
// The universal value printer (public/gmock-printers.h) needs this
|
||||
// to declare an unused << operator in the global namespace.
|
||||
struct Unused {};
|
||||
|
||||
// TODO(wan@google.com): group all type utilities together.
|
||||
|
||||
// Type traits.
|
||||
@@ -482,6 +489,238 @@ inline T Invalid() {
|
||||
template <>
|
||||
inline void Invalid<void>() {}
|
||||
|
||||
// Utilities for native arrays.
|
||||
|
||||
// ArrayEq() compares two k-dimensional native arrays using the
|
||||
// elements' operator==, where k can be any integer >= 0. When k is
|
||||
// 0, ArrayEq() degenerates into comparing a single pair of values.
|
||||
|
||||
template <typename T, typename U>
|
||||
bool ArrayEq(const T* lhs, size_t size, const U* rhs);
|
||||
|
||||
// This generic version is used when k is 0.
|
||||
template <typename T, typename U>
|
||||
inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; }
|
||||
|
||||
// This overload is used when k >= 1.
|
||||
template <typename T, typename U, size_t N>
|
||||
inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) {
|
||||
return internal::ArrayEq(lhs, N, rhs);
|
||||
}
|
||||
|
||||
// This helper reduces code bloat. If we instead put its logic inside
|
||||
// the previous ArrayEq() function, arrays with different sizes would
|
||||
// lead to different copies of the template code.
|
||||
template <typename T, typename U>
|
||||
bool ArrayEq(const T* lhs, size_t size, const U* rhs) {
|
||||
for (size_t i = 0; i != size; i++) {
|
||||
if (!internal::ArrayEq(lhs[i], rhs[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Finds the first element in the iterator range [begin, end) that
|
||||
// equals elem. Element may be a native array type itself.
|
||||
template <typename Iter, typename Element>
|
||||
Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) {
|
||||
for (Iter it = begin; it != end; ++it) {
|
||||
if (internal::ArrayEq(*it, elem))
|
||||
return it;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
// CopyArray() copies a k-dimensional native array using the elements'
|
||||
// operator=, where k can be any integer >= 0. When k is 0,
|
||||
// CopyArray() degenerates into copying a single value.
|
||||
|
||||
template <typename T, typename U>
|
||||
void CopyArray(const T* from, size_t size, U* to);
|
||||
|
||||
// This generic version is used when k is 0.
|
||||
template <typename T, typename U>
|
||||
inline void CopyArray(const T& from, U* to) { *to = from; }
|
||||
|
||||
// This overload is used when k >= 1.
|
||||
template <typename T, typename U, size_t N>
|
||||
inline void CopyArray(const T(&from)[N], U(*to)[N]) {
|
||||
internal::CopyArray(from, N, *to);
|
||||
}
|
||||
|
||||
// This helper reduces code bloat. If we instead put its logic inside
|
||||
// the previous CopyArray() function, arrays with different sizes
|
||||
// would lead to different copies of the template code.
|
||||
template <typename T, typename U>
|
||||
void CopyArray(const T* from, size_t size, U* to) {
|
||||
for (size_t i = 0; i != size; i++) {
|
||||
internal::CopyArray(from[i], to + i);
|
||||
}
|
||||
}
|
||||
|
||||
// The relation between an NativeArray object (see below) and the
|
||||
// native array it represents.
|
||||
enum RelationToSource {
|
||||
kReference, // The NativeArray references the native array.
|
||||
kCopy // The NativeArray makes a copy of the native array and
|
||||
// owns the copy.
|
||||
};
|
||||
|
||||
// Adapts a native array to a read-only STL-style container. Instead
|
||||
// of the complete STL container concept, this adaptor only implements
|
||||
// members useful for Google Mock's container matchers. New members
|
||||
// should be added as needed. To simplify the implementation, we only
|
||||
// support Element being a raw type (i.e. having no top-level const or
|
||||
// reference modifier). It's the client's responsibility to satisfy
|
||||
// this requirement. Element can be an array type itself (hence
|
||||
// multi-dimensional arrays are supported).
|
||||
template <typename Element>
|
||||
class NativeArray {
|
||||
public:
|
||||
// STL-style container typedefs.
|
||||
typedef Element value_type;
|
||||
typedef const Element* const_iterator;
|
||||
|
||||
// Constructs from a native array passed by reference.
|
||||
template <size_t N>
|
||||
NativeArray(const Element (&array)[N], RelationToSource relation) {
|
||||
Init(array, N, relation);
|
||||
}
|
||||
|
||||
// Constructs from a native array passed by a pointer and a size.
|
||||
// For generality we don't artificially restrict the types of the
|
||||
// pointer and the size.
|
||||
template <typename Pointer, typename Size>
|
||||
NativeArray(const ::std::tr1::tuple<Pointer, Size>& array,
|
||||
RelationToSource relation) {
|
||||
Init(internal::GetRawPointer(::std::tr1::get<0>(array)),
|
||||
::std::tr1::get<1>(array),
|
||||
relation);
|
||||
}
|
||||
|
||||
// Copy constructor.
|
||||
NativeArray(const NativeArray& rhs) {
|
||||
Init(rhs.array_, rhs.size_, rhs.relation_to_source_);
|
||||
}
|
||||
|
||||
~NativeArray() {
|
||||
// Ensures that the user doesn't instantiate NativeArray with a
|
||||
// const or reference type.
|
||||
testing::StaticAssertTypeEq<Element,
|
||||
GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Element))>();
|
||||
if (relation_to_source_ == kCopy)
|
||||
delete[] array_;
|
||||
}
|
||||
|
||||
// STL-style container methods.
|
||||
size_t size() const { return size_; }
|
||||
const_iterator begin() const { return array_; }
|
||||
const_iterator end() const { return array_ + size_; }
|
||||
bool operator==(const NativeArray& rhs) const {
|
||||
return size() == rhs.size() &&
|
||||
ArrayEq(begin(), size(), rhs.begin());
|
||||
}
|
||||
|
||||
private:
|
||||
// Not implemented as we don't want to support assignment.
|
||||
void operator=(const NativeArray& rhs);
|
||||
|
||||
// Initializes this object; makes a copy of the input array if
|
||||
// 'relation' is kCopy.
|
||||
void Init(const Element* array, size_t size, RelationToSource relation) {
|
||||
if (relation == kReference) {
|
||||
array_ = array;
|
||||
} else {
|
||||
Element* const copy = new Element[size];
|
||||
CopyArray(array, size, copy);
|
||||
array_ = copy;
|
||||
}
|
||||
size_ = size;
|
||||
relation_to_source_ = relation;
|
||||
}
|
||||
|
||||
const Element* array_;
|
||||
size_t size_;
|
||||
RelationToSource relation_to_source_;
|
||||
};
|
||||
|
||||
// Given a raw type (i.e. having no top-level reference or const
|
||||
// modifier) RawContainer that's either an STL-style container or a
|
||||
// native array, class StlContainerView<RawContainer> has the
|
||||
// following members:
|
||||
//
|
||||
// - type is a type that provides an STL-style container view to
|
||||
// (i.e. implements the STL container concept for) RawContainer;
|
||||
// - const_reference is a type that provides a reference to a const
|
||||
// RawContainer;
|
||||
// - ConstReference(raw_container) returns a const reference to an STL-style
|
||||
// container view to raw_container, which is a RawContainer.
|
||||
// - Copy(raw_container) returns an STL-style container view of a
|
||||
// copy of raw_container, which is a RawContainer.
|
||||
//
|
||||
// This generic version is used when RawContainer itself is already an
|
||||
// STL-style container.
|
||||
template <class RawContainer>
|
||||
class StlContainerView {
|
||||
public:
|
||||
typedef RawContainer type;
|
||||
typedef const type& const_reference;
|
||||
|
||||
static const_reference ConstReference(const RawContainer& container) {
|
||||
// Ensures that RawContainer is not a const type.
|
||||
testing::StaticAssertTypeEq<RawContainer,
|
||||
GMOCK_REMOVE_CONST_(RawContainer)>();
|
||||
return container;
|
||||
}
|
||||
static type Copy(const RawContainer& container) { return container; }
|
||||
};
|
||||
|
||||
// This specialization is used when RawContainer is a native array type.
|
||||
template <typename Element, size_t N>
|
||||
class StlContainerView<Element[N]> {
|
||||
public:
|
||||
typedef GMOCK_REMOVE_CONST_(Element) RawElement;
|
||||
typedef internal::NativeArray<RawElement> type;
|
||||
// NativeArray<T> can represent a native array either by value or by
|
||||
// reference (selected by a constructor argument), so 'const type'
|
||||
// can be used to reference a const native array. We cannot
|
||||
// 'typedef const type& const_reference' here, as that would mean
|
||||
// ConstReference() has to return a reference to a local variable.
|
||||
typedef const type const_reference;
|
||||
|
||||
static const_reference ConstReference(const Element (&array)[N]) {
|
||||
// Ensures that Element is not a const type.
|
||||
testing::StaticAssertTypeEq<Element, RawElement>();
|
||||
return type(array, kReference);
|
||||
}
|
||||
static type Copy(const Element (&array)[N]) {
|
||||
return type(array, kCopy);
|
||||
}
|
||||
};
|
||||
|
||||
// This specialization is used when RawContainer is a native array
|
||||
// represented as a (pointer, size) tuple.
|
||||
template <typename ElementPointer, typename Size>
|
||||
class StlContainerView< ::std::tr1::tuple<ElementPointer, Size> > {
|
||||
public:
|
||||
typedef GMOCK_REMOVE_CONST_(
|
||||
typename internal::PointeeOf<ElementPointer>::type) RawElement;
|
||||
typedef internal::NativeArray<RawElement> type;
|
||||
typedef const type const_reference;
|
||||
|
||||
static const_reference ConstReference(
|
||||
const ::std::tr1::tuple<ElementPointer, Size>& array) {
|
||||
return type(array, kReference);
|
||||
}
|
||||
static type Copy(const ::std::tr1::tuple<ElementPointer, Size>& array) {
|
||||
return type(array, kCopy);
|
||||
}
|
||||
};
|
||||
|
||||
// The following specialization prevents the user from instantiating
|
||||
// StlContainer with a reference type.
|
||||
template <typename T> class StlContainerView<T&>;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
|
||||
Reference in New Issue
Block a user