133 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8//9// GMock matchers that aren't specific to particular tests.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_UNITTESTS_MATCHERS_H14#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_UNITTESTS_MATCHERS_H15#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 match33// m1, m2 ... in that order.34//35// SubsequenceMatcher implements this once the type of vector is known.36template <typename T>37class SubsequenceMatcher38 : 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 to81// 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 match103// 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 defined111// already.112#ifdef EXPECT_ERROR113#error "Refusing to redefine EXPECT_ERROR"114#endif115 116// Consumes llvm::Expected<T>, checks it contains an error and marks it as117// 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 clangd131} // namespace clang132#endif133