aboutsummaryrefslogtreecommitdiffstats
path: root/include/gmock/gmock-matchers.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/gmock/gmock-matchers.h')
-rw-r--r--include/gmock/gmock-matchers.h215
1 files changed, 215 insertions, 0 deletions
diff --git a/include/gmock/gmock-matchers.h b/include/gmock/gmock-matchers.h
index db23a1bd..9e97866a 100644
--- a/include/gmock/gmock-matchers.h
+++ b/include/gmock/gmock-matchers.h
@@ -1925,6 +1925,221 @@ class KeyMatcher {
const M matcher_for_key_;
};
+// Implements ElementsAre() and ElementsAreArray().
+template <typename Container>
+class ElementsAreMatcherImpl : public MatcherInterface<Container> {
+ public:
+ typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container)) RawContainer;
+ typedef internal::StlContainerView<RawContainer> View;
+ typedef typename View::type StlContainer;
+ typedef typename View::const_reference StlContainerReference;
+ typedef typename StlContainer::value_type Element;
+
+ // Constructs the matcher from a sequence of element values or
+ // element matchers.
+ template <typename InputIter>
+ ElementsAreMatcherImpl(InputIter first, size_t count) {
+ matchers_.reserve(count);
+ InputIter it = first;
+ for (size_t i = 0; i != count; ++i, ++it) {
+ matchers_.push_back(MatcherCast<const Element&>(*it));
+ }
+ }
+
+ // Returns true iff 'container' matches.
+ virtual bool Matches(Container container) const {
+ StlContainerReference stl_container = View::ConstReference(container);
+ if (stl_container.size() != count())
+ return false;
+
+ typename StlContainer::const_iterator it = stl_container.begin();
+ for (size_t i = 0; i != count(); ++it, ++i) {
+ if (!matchers_[i].Matches(*it))
+ return false;
+ }
+
+ return true;
+ }
+
+ // Describes what this matcher does.
+ virtual void DescribeTo(::std::ostream* os) const {
+ if (count() == 0) {
+ *os << "is empty";
+ } else if (count() == 1) {
+ *os << "has 1 element that ";
+ matchers_[0].DescribeTo(os);
+ } else {
+ *os << "has " << Elements(count()) << " where\n";
+ for (size_t i = 0; i != count(); ++i) {
+ *os << "element " << i << " ";
+ matchers_[i].DescribeTo(os);
+ if (i + 1 < count()) {
+ *os << ",\n";
+ }
+ }
+ }
+ }
+
+ // Describes what the negation of this matcher does.
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ if (count() == 0) {
+ *os << "is not empty";
+ return;
+ }
+
+ *os << "does not have " << Elements(count()) << ", or\n";
+ for (size_t i = 0; i != count(); ++i) {
+ *os << "element " << i << " ";
+ matchers_[i].DescribeNegationTo(os);
+ if (i + 1 < count()) {
+ *os << ", or\n";
+ }
+ }
+ }
+
+ // Explains why 'container' matches, or doesn't match, this matcher.
+ virtual void ExplainMatchResultTo(Container container,
+ ::std::ostream* os) const {
+ StlContainerReference stl_container = View::ConstReference(container);
+ if (Matches(container)) {
+ // We need to explain why *each* element matches (the obvious
+ // ones can be skipped).
+
+ bool reason_printed = false;
+ typename StlContainer::const_iterator it = stl_container.begin();
+ for (size_t i = 0; i != count(); ++it, ++i) {
+ ::std::stringstream ss;
+ matchers_[i].ExplainMatchResultTo(*it, &ss);
+
+ const string s = ss.str();
+ if (!s.empty()) {
+ if (reason_printed) {
+ *os << ",\n";
+ }
+ *os << "element " << i << " " << s;
+ reason_printed = true;
+ }
+ }
+ } else {
+ // We need to explain why the container doesn't match.
+ const size_t actual_count = stl_container.size();
+ if (actual_count != count()) {
+ // The element count doesn't match. If the container is
+ // empty, there's no need to explain anything as Google Mock
+ // already prints the empty container. Otherwise we just need
+ // to show how many elements there actually are.
+ if (actual_count != 0) {
+ *os << "has " << Elements(actual_count);
+ }
+ return;
+ }
+
+ // The container has the right size but at least one element
+ // doesn't match expectation. We need to find this element and
+ // explain why it doesn't match.
+ typename StlContainer::const_iterator it = stl_container.begin();
+ for (size_t i = 0; i != count(); ++it, ++i) {
+ if (matchers_[i].Matches(*it)) {
+ continue;
+ }
+
+ *os << "element " << i << " doesn't match";
+
+ ::std::stringstream ss;
+ matchers_[i].ExplainMatchResultTo(*it, &ss);
+ const string s = ss.str();
+ if (!s.empty()) {
+ *os << " (" << s << ")";
+ }
+ return;
+ }
+ }
+ }
+
+ private:
+ static Message Elements(size_t count) {
+ return Message() << count << (count == 1 ? " element" : " elements");
+ }
+
+ size_t count() const { return matchers_.size(); }
+ std::vector<Matcher<const Element&> > matchers_;
+};
+
+// Implements ElementsAre() of 0 arguments.
+class ElementsAreMatcher0 {
+ public:
+ ElementsAreMatcher0() {}
+
+ template <typename Container>
+ operator Matcher<Container>() const {
+ typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
+ RawContainer;
+ typedef typename internal::StlContainerView<RawContainer>::type::value_type
+ Element;
+
+ const Matcher<const Element&>* const matchers = NULL;
+ return MakeMatcher(new ElementsAreMatcherImpl<Container>(matchers, 0));
+ }
+};
+
+// Implements ElementsAreArray().
+template <typename T>
+class ElementsAreArrayMatcher {
+ public:
+ ElementsAreArrayMatcher(const T* first, size_t count) :
+ first_(first), count_(count) {}
+
+ template <typename Container>
+ operator Matcher<Container>() const {
+ typedef GMOCK_REMOVE_CONST_(GMOCK_REMOVE_REFERENCE_(Container))
+ RawContainer;
+ typedef typename internal::StlContainerView<RawContainer>::type::value_type
+ Element;
+
+ return MakeMatcher(new ElementsAreMatcherImpl<Container>(first_, count_));
+ }
+
+ private:
+ const T* const first_;
+ const size_t count_;
+};
+
+// Constants denoting interpolations in a matcher description string.
+const int kTupleInterpolation = -1; // "%(*)s"
+const int kPercentInterpolation = -2; // "%%"
+const int kInvalidInterpolation = -3; // "%" followed by invalid text
+
+// Records the location and content of an interpolation.
+struct Interpolation {
+ Interpolation(const char* start, const char* end, int param)
+ : start_pos(start), end_pos(end), param_index(param) {}
+
+ // Points to the start of the interpolation (the '%' character).
+ const char* start_pos;
+ // Points to the first character after the interpolation.
+ const char* end_pos;
+ // 0-based index of the interpolated matcher parameter;
+ // kTupleInterpolation for "%(*)s"; kPercentInterpolation for "%%".
+ int param_index;
+};
+
+typedef ::std::vector<Interpolation> Interpolations;
+
+// Parses a matcher description string and returns a vector of
+// interpolations that appear in the string; generates non-fatal
+// failures iff 'description' is an invalid matcher description.
+// 'param_names' is a NULL-terminated array of parameter names in the
+// order they appear in the MATCHER_P*() parameter list.
+Interpolations ValidateMatcherDescription(
+ const char* param_names[], const char* description);
+
+// Returns the actual matcher description, given the matcher name,
+// user-supplied description template string, interpolations in the
+// string, and the printed values of the matcher parameters.
+string FormatMatcherDescription(
+ const char* matcher_name, const char* description,
+ const Interpolations& interp, const Strings& param_values);
+
} // namespace internal
// Implements MatcherCast().