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_CLANGD_UNITTESTS_MATCHERS_H
14#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_UNITTESTS_MATCHERS_H
15#include "Protocol.h"
16#include "gmock/gmock.h"
17
18namespace clang {
19namespace clangd {
20using ::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.
36template <typename T>
37class SubsequenceMatcher
38 : public ::testing::MatcherInterface<const std::vector<T> &> {
39 std::vector<Matcher<T>> Matchers;
40
41public:
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().
83template <typename... M> class PolySubsequenceMatcher {
84 std::tuple<M...> Matchers;
85
86public:
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
95private:
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.
105template <typename... Args>
106PolySubsequenceMatcher<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.
132template <typename InnerMatcher> class OptionalMatcher {
133public:
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
149private:
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)
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.
192template <typename InnerMatcher>
193inline OptionalMatcher<InnerMatcher>
194HasValue(const InnerMatcher &inner_matcher) {
195 return OptionalMatcher<InnerMatcher>(inner_matcher);
196}
197
198} // namespace clangd
199} // namespace clang
200#endif
201

source code of clang-tools-extra/clangd/unittests/Matchers.h