//===-- Matchers.h ----------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // GMock matchers that aren't specific to particular tests. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_MATCHERS_H #define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_MATCHERS_H #include "Protocol.h" #include "gmock/gmock.h" namespace clang { namespace clangd { using ::testing::Matcher; // EXPECT_IFF expects matcher if condition is true, and Not(matcher) if false. // This is hard to write as a function, because matchers may be polymorphic. #define EXPECT_IFF(condition, value, matcher) \ do { \ if (condition) \ EXPECT_THAT(value, matcher); \ else \ EXPECT_THAT(value, ::testing::Not(matcher)); \ } while (0) // HasSubsequence(m1, m2, ...) matches a vector containing elements that match // m1, m2 ... in that order. // // SubsequenceMatcher implements this once the type of vector is known. template class SubsequenceMatcher : public ::testing::MatcherInterface &> { std::vector> Matchers; public: SubsequenceMatcher(std::vector> M) : Matchers(M) {} void DescribeTo(std::ostream *OS) const override { *OS << "Contains the subsequence ["; const char *Sep = ""; for (const auto &M : Matchers) { *OS << Sep; M.DescribeTo(OS); Sep = ", "; } *OS << "]"; } bool MatchAndExplain(const std::vector &V, ::testing::MatchResultListener *L) const override { std::vector Matches(Matchers.size()); size_t I = 0; for (size_t J = 0; I < Matchers.size() && J < V.size(); ++J) if (Matchers[I].Matches(V[J])) Matches[I++] = J; if (I == Matchers.size()) // We exhausted all matchers. return true; if (L->IsInterested()) { *L << "\n Matched:"; for (size_t K = 0; K < I; ++K) { *L << "\n\t"; Matchers[K].DescribeTo(L->stream()); *L << " ==> " << ::testing::PrintToString(V[Matches[K]]); } *L << "\n\t"; Matchers[I].DescribeTo(L->stream()); *L << " ==> no subsequent match"; } return false; } }; // PolySubsequenceMatcher implements a "polymorphic" SubsequenceMatcher. // It captures the types of the element matchers, and can be converted to // Matcher> if each matcher can be converted to Matcher. // This allows HasSubsequence() to accept polymorphic matchers like Not(). template class PolySubsequenceMatcher { std::tuple Matchers; public: PolySubsequenceMatcher(M &&... Args) : Matchers(std::make_tuple(std::forward(Args)...)) {} template operator Matcher &>() const { return ::testing::MakeMatcher(new SubsequenceMatcher( TypedMatchers(llvm::index_sequence_for{}))); } private: template std::vector> TypedMatchers(llvm::index_sequence) const { return {std::get(Matchers)...}; } }; // HasSubsequence(m1, m2, ...) matches a vector containing elements that match // m1, m2 ... in that order. // The real implementation is in SubsequenceMatcher. template PolySubsequenceMatcher HasSubsequence(Args &&... M) { return PolySubsequenceMatcher(std::forward(M)...); } // EXPECT_ERROR seems like a pretty generic name, make sure it's not defined // already. #ifdef EXPECT_ERROR #error "Refusing to redefine EXPECT_ERROR" #endif // Consumes llvm::Expected, checks it contains an error and marks it as // handled. #define EXPECT_ERROR(expectedValue) \ do { \ auto &&ComputedValue = (expectedValue); \ if (ComputedValue) { \ ADD_FAILURE() << "expected an error from " << #expectedValue \ << " but got " \ << ::testing::PrintToString(*ComputedValue); \ break; \ } \ llvm::consumeError(ComputedValue.takeError()); \ } while (false) } // namespace clangd } // namespace clang #endif