• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
37 class SubsequenceMatcher
38     : public ::testing::MatcherInterface<const std::vector<T> &> {
39   std::vector<Matcher<T>> Matchers;
40 
41 public:
SubsequenceMatcher(std::vector<Matcher<T>> M)42   SubsequenceMatcher(std::vector<Matcher<T>> M) : Matchers(M) {}
43 
DescribeTo(std::ostream * OS)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 
MatchAndExplain(const std::vector<T> & V,::testing::MatchResultListener * L)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:
PolySubsequenceMatcher(M &&...Args)87   PolySubsequenceMatcher(M &&... Args)
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>
TypedMatchers(std::index_sequence<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>
HasSubsequence(Args &&...M)106 PolySubsequenceMatcher<Args...> HasSubsequence(Args &&... M) {
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:
OptionalMatcher(const InnerMatcher & matcher)134   explicit OptionalMatcher(const InnerMatcher &matcher) : matcher_(matcher) {}
135 
136   // This type conversion operator template allows Optional(m) to be
137   // used as a matcher for any Optional type whose value type is
138   // compatible with the inner matcher.
139   //
140   // The reason we do this instead of relying on
141   // MakePolymorphicMatcher() is that the latter is not flexible
142   // enough for implementing the DescribeTo() method of Optional().
143   template <typename Optional> operator Matcher<Optional>() const {
144     return MakeMatcher(new Impl<Optional>(matcher_));
145   }
146 
147 private:
148   // The monomorphic implementation that works for a particular optional type.
149   template <typename Optional>
150   class Impl : public ::testing::MatcherInterface<Optional> {
151   public:
152     using Value = typename std::remove_const<
153         typename std::remove_reference<Optional>::type>::type::value_type;
154 
Impl(const InnerMatcher & matcher)155     explicit Impl(const InnerMatcher &matcher)
156         : matcher_(::testing::MatcherCast<const Value &>(matcher)) {}
157 
DescribeTo(::std::ostream * os)158     virtual void DescribeTo(::std::ostream *os) const {
159       *os << "has a value that ";
160       matcher_.DescribeTo(os);
161     }
162 
DescribeNegationTo(::std::ostream * os)163     virtual void DescribeNegationTo(::std::ostream *os) const {
164       *os << "does not have a value that ";
165       matcher_.DescribeTo(os);
166     }
167 
168     virtual bool
MatchAndExplain(Optional optional,::testing::MatchResultListener * listener)169     MatchAndExplain(Optional optional,
170                     ::testing::MatchResultListener *listener) const {
171       if (!optional.hasValue())
172         return false;
173 
174       *listener << "which has a value ";
175       return MatchPrintAndExplain(*optional, matcher_, listener);
176     }
177 
178   private:
179     const Matcher<const Value &> matcher_;
180 
181     GTEST_DISALLOW_ASSIGN_(Impl);
182   };
183 
184   const InnerMatcher matcher_;
185 
186   GTEST_DISALLOW_ASSIGN_(OptionalMatcher);
187 };
188 
189 // Creates a matcher that matches an Optional that has a value
190 // that matches inner_matcher.
191 template <typename InnerMatcher>
192 inline OptionalMatcher<InnerMatcher>
HasValue(const InnerMatcher & inner_matcher)193 HasValue(const InnerMatcher &inner_matcher) {
194   return OptionalMatcher<InnerMatcher>(inner_matcher);
195 }
196 
197 } // namespace clangd
198 } // namespace clang
199 #endif
200