| //===-- Matchers.h ----------------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // 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 <typename T> |
| class SubsequenceMatcher |
| : public ::testing::MatcherInterface<const std::vector<T> &> { |
| std::vector<Matcher<T>> Matchers; |
| |
| public: |
| SubsequenceMatcher(std::vector<Matcher<T>> 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<T> &V, |
| ::testing::MatchResultListener *L) const override { |
| std::vector<int> 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<vector<T>> if each matcher can be converted to Matcher<T>. |
| // This allows HasSubsequence() to accept polymorphic matchers like Not(). |
| template <typename... M> class PolySubsequenceMatcher { |
| std::tuple<M...> Matchers; |
| |
| public: |
| PolySubsequenceMatcher(M &&... Args) |
| : Matchers(std::make_tuple(std::forward<M>(Args)...)) {} |
| |
| template <typename T> operator Matcher<const std::vector<T> &>() const { |
| return ::testing::MakeMatcher(new SubsequenceMatcher<T>( |
| TypedMatchers<T>(std::index_sequence_for<M...>{}))); |
| } |
| |
| private: |
| template <typename T, size_t... I> |
| std::vector<Matcher<T>> TypedMatchers(std::index_sequence<I...>) const { |
| return {std::get<I>(Matchers)...}; |
| } |
| }; |
| |
| // HasSubsequence(m1, m2, ...) matches a vector containing elements that match |
| // m1, m2 ... in that order. |
| // The real implementation is in SubsequenceMatcher. |
| template <typename... Args> |
| PolySubsequenceMatcher<Args...> HasSubsequence(Args &&... M) { |
| return PolySubsequenceMatcher<Args...>(std::forward<Args>(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<T>, 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) |
| |
| // Implements the HasValue(m) matcher for matching an Optional whose |
| // value matches matcher m. |
| template <typename InnerMatcher> class OptionalMatcher { |
| public: |
| explicit OptionalMatcher(const InnerMatcher &matcher) : matcher_(matcher) {} |
| OptionalMatcher(const OptionalMatcher&) = default; |
| OptionalMatcher &operator=(const OptionalMatcher&) = delete; |
| |
| // This type conversion operator template allows Optional(m) to be |
| // used as a matcher for any Optional type whose value type is |
| // compatible with the inner matcher. |
| // |
| // The reason we do this instead of relying on |
| // MakePolymorphicMatcher() is that the latter is not flexible |
| // enough for implementing the DescribeTo() method of Optional(). |
| template <typename Optional> operator Matcher<Optional>() const { |
| return MakeMatcher(new Impl<Optional>(matcher_)); |
| } |
| |
| private: |
| // The monomorphic implementation that works for a particular optional type. |
| template <typename Optional> |
| class Impl : public ::testing::MatcherInterface<Optional> { |
| public: |
| using Value = typename std::remove_const< |
| typename std::remove_reference<Optional>::type>::type::value_type; |
| |
| explicit Impl(const InnerMatcher &matcher) |
| : matcher_(::testing::MatcherCast<const Value &>(matcher)) {} |
| |
| Impl(const Impl&) = default; |
| Impl &operator=(const Impl&) = delete; |
| |
| virtual void DescribeTo(::std::ostream *os) const { |
| *os << "has a value that "; |
| matcher_.DescribeTo(os); |
| } |
| |
| virtual void DescribeNegationTo(::std::ostream *os) const { |
| *os << "does not have a value that "; |
| matcher_.DescribeTo(os); |
| } |
| |
| virtual bool |
| MatchAndExplain(Optional optional, |
| ::testing::MatchResultListener *listener) const { |
| if (!optional.hasValue()) |
| return false; |
| |
| *listener << "which has a value "; |
| return MatchPrintAndExplain(*optional, matcher_, listener); |
| } |
| |
| private: |
| const Matcher<const Value &> matcher_; |
| }; |
| |
| const InnerMatcher matcher_; |
| }; |
| |
| // Creates a matcher that matches an Optional that has a value |
| // that matches inner_matcher. |
| template <typename InnerMatcher> |
| inline OptionalMatcher<InnerMatcher> |
| HasValue(const InnerMatcher &inner_matcher) { |
| return OptionalMatcher<InnerMatcher>(inner_matcher); |
| } |
| |
| } // namespace clangd |
| } // namespace clang |
| #endif |