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 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: 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: 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> 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> 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 } // namespace clangd 131 } // namespace clang 132 #endif 133