clang-tools  14.0.0git
clangd/unittests/Matchers.h
Go to the documentation of this file.
1 //===-- Matchers.h ----------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // GMock matchers that aren't specific to particular tests.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_MATCHERS_H
14 #define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_MATCHERS_H
15 #include "Protocol.h"
16 #include "gmock/gmock.h"
17 
18 namespace clang {
19 namespace clangd {
20 using ::testing::Matcher;
21 
22 // EXPECT_IFF expects matcher if condition is true, and Not(matcher) if false.
23 // This is hard to write as a function, because matchers may be polymorphic.
24 #define EXPECT_IFF(condition, value, matcher) \
25  do { \
26  if (condition) \
27  EXPECT_THAT(value, matcher); \
28  else \
29  EXPECT_THAT(value, ::testing::Not(matcher)); \
30  } while (0)
31 
32 // HasSubsequence(m1, m2, ...) matches a vector containing elements that match
33 // m1, m2 ... in that order.
34 //
35 // SubsequenceMatcher implements this once the type of vector is known.
36 template <typename T>
38  : public ::testing::MatcherInterface<const std::vector<T> &> {
39  std::vector<Matcher<T>> Matchers;
40 
41 public:
42  SubsequenceMatcher(std::vector<Matcher<T>> M) : Matchers(M) {}
43 
44  void DescribeTo(std::ostream *OS) const override {
45  *OS << "Contains the subsequence [";
46  const char *Sep = "";
47  for (const auto &M : Matchers) {
48  *OS << Sep;
49  M.DescribeTo(OS);
50  Sep = ", ";
51  }
52  *OS << "]";
53  }
54 
55  bool MatchAndExplain(const std::vector<T> &V,
56  ::testing::MatchResultListener *L) const override {
57  std::vector<int> Matches(Matchers.size());
58  size_t I = 0;
59  for (size_t J = 0; I < Matchers.size() && J < V.size(); ++J)
60  if (Matchers[I].Matches(V[J]))
61  Matches[I++] = J;
62  if (I == Matchers.size()) // We exhausted all matchers.
63  return true;
64  if (L->IsInterested()) {
65  *L << "\n Matched:";
66  for (size_t K = 0; K < I; ++K) {
67  *L << "\n\t";
68  Matchers[K].DescribeTo(L->stream());
69  *L << " ==> " << ::testing::PrintToString(V[Matches[K]]);
70  }
71  *L << "\n\t";
72  Matchers[I].DescribeTo(L->stream());
73  *L << " ==> no subsequent match";
74  }
75  return false;
76  }
77 };
78 
79 // PolySubsequenceMatcher implements a "polymorphic" SubsequenceMatcher.
80 // It captures the types of the element matchers, and can be converted to
81 // Matcher<vector<T>> if each matcher can be converted to Matcher<T>.
82 // This allows HasSubsequence() to accept polymorphic matchers like Not().
83 template <typename... M> class PolySubsequenceMatcher {
84  std::tuple<M...> Matchers;
85 
86 public:
88  : Matchers(std::make_tuple(std::forward<M>(Args)...)) {}
89 
90  template <typename T> operator Matcher<const std::vector<T> &>() const {
91  return ::testing::MakeMatcher(new SubsequenceMatcher<T>(
92  TypedMatchers<T>(std::index_sequence_for<M...>{})));
93  }
94 
95 private:
96  template <typename T, size_t... I>
97  std::vector<Matcher<T>> TypedMatchers(std::index_sequence<I...>) const {
98  return {std::get<I>(Matchers)...};
99  }
100 };
101 
102 // HasSubsequence(m1, m2, ...) matches a vector containing elements that match
103 // m1, m2 ... in that order.
104 // The real implementation is in SubsequenceMatcher.
105 template <typename... Args>
107  return PolySubsequenceMatcher<Args...>(std::forward<Args>(M)...);
108 }
109 
110 // EXPECT_ERROR seems like a pretty generic name, make sure it's not defined
111 // already.
112 #ifdef EXPECT_ERROR
113 #error "Refusing to redefine EXPECT_ERROR"
114 #endif
115 
116 // Consumes llvm::Expected<T>, checks it contains an error and marks it as
117 // handled.
118 #define EXPECT_ERROR(expectedValue) \
119  do { \
120  auto &&ComputedValue = (expectedValue); \
121  if (ComputedValue) { \
122  ADD_FAILURE() << "expected an error from " << #expectedValue \
123  << " but got " \
124  << ::testing::PrintToString(*ComputedValue); \
125  break; \
126  } \
127  llvm::consumeError(ComputedValue.takeError()); \
128  } while (false)
129 
130 // Implements the HasValue(m) matcher for matching an Optional whose
131 // value matches matcher m.
132 template <typename InnerMatcher> class OptionalMatcher {
133 public:
134  explicit OptionalMatcher(const InnerMatcher &matcher) : matcher_(matcher) {}
135  OptionalMatcher(const OptionalMatcher&) = default;
136  OptionalMatcher &operator=(const OptionalMatcher&) = delete;
137 
138  // This type conversion operator template allows Optional(m) to be
139  // used as a matcher for any Optional type whose value type is
140  // compatible with the inner matcher.
141  //
142  // The reason we do this instead of relying on
143  // MakePolymorphicMatcher() is that the latter is not flexible
144  // enough for implementing the DescribeTo() method of Optional().
145  template <typename Optional> operator Matcher<Optional>() const {
146  return MakeMatcher(new Impl<Optional>(matcher_));
147  }
148 
149 private:
150  // The monomorphic implementation that works for a particular optional type.
151  template <typename Optional>
152  class Impl : public ::testing::MatcherInterface<Optional> {
153  public:
154  using Value = typename std::remove_const<
155  typename std::remove_reference<Optional>::type>::type::value_type;
156 
157  explicit Impl(const InnerMatcher &matcher)
158  : matcher_(::testing::MatcherCast<const Value &>(matcher)) {}
159 
160  Impl(const Impl&) = default;
161  Impl &operator=(const Impl&) = delete;
162 
163  virtual void DescribeTo(::std::ostream *os) const {
164  *os << "has a value that ";
165  matcher_.DescribeTo(os);
166  }
167 
168  virtual void DescribeNegationTo(::std::ostream *os) const {
169  *os << "does not have a value that ";
170  matcher_.DescribeTo(os);
171  }
172 
173  virtual bool
174  MatchAndExplain(Optional optional,
175  ::testing::MatchResultListener *listener) const {
176  if (!optional.hasValue())
177  return false;
178 
179  *listener << "which has a value ";
180  return MatchPrintAndExplain(*optional, matcher_, listener);
181  }
182 
183  private:
184  const Matcher<const Value &> matcher_;
185  };
186 
187  const InnerMatcher matcher_;
188 };
189 
190 // Creates a matcher that matches an Optional that has a value
191 // that matches inner_matcher.
192 template <typename InnerMatcher>
193 inline OptionalMatcher<InnerMatcher>
194 HasValue(const InnerMatcher &inner_matcher) {
195  return OptionalMatcher<InnerMatcher>(inner_matcher);
196 }
197 
198 } // namespace clangd
199 } // namespace clang
200 #endif
clang::clangd::OptionalMatcher::OptionalMatcher
OptionalMatcher(const InnerMatcher &matcher)
Definition: clangd/unittests/Matchers.h:134
Protocol.h
M
const google::protobuf::Message & M
Definition: Server.cpp:309
clang::clangd::OptionalMatcher
Definition: clangd/unittests/Matchers.h:132
Args
llvm::json::Object Args
Definition: Trace.cpp:139
clang::clangd::SubsequenceMatcher::DescribeTo
void DescribeTo(std::ostream *OS) const override
Definition: clangd/unittests/Matchers.h:44
clang::clangd::PolySubsequenceMatcher::PolySubsequenceMatcher
PolySubsequenceMatcher(M &&... Args)
Definition: clangd/unittests/Matchers.h:87
clang::clangd::OptionalMatcher::operator=
OptionalMatcher & operator=(const OptionalMatcher &)=delete
clang::clangd::SubsequenceMatcher::SubsequenceMatcher
SubsequenceMatcher(std::vector< Matcher< T >> M)
Definition: clangd/unittests/Matchers.h:42
clang::clangd::PolySubsequenceMatcher
Definition: clangd/unittests/Matchers.h:83
clang::clangd::HasSubsequence
PolySubsequenceMatcher< Args... > HasSubsequence(Args &&... M)
Definition: clangd/unittests/Matchers.h:106
clang::clangd::SubsequenceMatcher::MatchAndExplain
bool MatchAndExplain(const std::vector< T > &V, ::testing::MatchResultListener *L) const override
Definition: clangd/unittests/Matchers.h:55
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
OS
llvm::raw_string_ostream OS
Definition: TraceTests.cpp:163
clang::clangd::HasValue
OptionalMatcher< InnerMatcher > HasValue(const InnerMatcher &inner_matcher)
Definition: clangd/unittests/Matchers.h:194
clang::clangd::SubsequenceMatcher
Definition: clangd/unittests/Matchers.h:37
K
Kind K
Definition: Rename.cpp:442