Bump version to 19.1.0git
[llvm-project.git] / clang-tools-extra / clangd / unittests / tweaks / TweakTesting.h
blob9c6b1f9c000aec99c97072d0506f5075375caea0
1 //===--- TweakTesting.h - Test helpers for refactoring actions ---*- 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 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_UNITTESTS_TWEAKS_TWEAKTESTING_H
10 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_UNITTESTS_TWEAKS_TWEAKTESTING_H
12 #include "ParsedAST.h"
13 #include "index/Index.h"
14 #include "llvm/ADT/StringMap.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Testing/Annotations/Annotations.h"
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
19 #include <memory>
20 #include <string>
22 namespace clang {
23 namespace clangd {
25 // Fixture base for testing tweaks. Intended to be subclassed for each tweak.
27 // Usage:
28 // TWEAK_TEST(ExpandDeducedType);
30 // TEST_F(ExpandDeducedTypeTest, ShortensTypes) {
31 // Header = R"cpp(
32 // namespace foo { template<typename> class X{}; }
33 // using namespace foo;
34 // )cpp";
35 // Context = Function;
36 // EXPECT_THAT(apply("[[auto]] X = foo<int>();"),
37 // "foo<int> X = foo<int();");
38 // EXPECT_AVAILABLE("^a^u^t^o^ X = foo<int>();");
39 // EXPECT_UNAVAILABLE("auto ^X^ = ^foo<int>();");
40 // }
41 class TweakTest : public ::testing::Test {
42 const char *TweakID;
44 public:
45 // Inputs are wrapped in file boilerplate before attempting to apply a tweak.
46 // Context describes the type of boilerplate.
47 enum CodeContext {
48 // Code snippet is placed directly into the source file. e.g. a declaration.
49 File,
50 // Snippet will appear within a function body. e.g. a statement.
51 Function,
52 // Snippet is an expression.
53 Expression,
56 // Mapping from file name to contents.
57 llvm::StringMap<std::string> ExtraFiles;
59 protected:
60 TweakTest(const char *TweakID) : TweakID(TweakID) {}
62 // Contents of a header file to be implicitly included.
63 // This typically contains declarations that will be used for a set of related
64 // testcases.
65 std::string Header;
67 llvm::StringRef FileName = "TestTU.cpp";
69 // Extra flags passed to the compilation in apply().
70 std::vector<std::string> ExtraArgs;
72 // Context in which snippets of code should be placed to run tweaks.
73 CodeContext Context = File;
75 // Index to be passed into Tweak::Selection.
76 std::unique_ptr<const SymbolIndex> Index = nullptr;
78 // Apply the current tweak to the range (or point) in MarkedCode.
79 // MarkedCode will be wrapped according to the Context.
80 // - if the tweak produces edits, returns the edited code (without markings)
81 // for the main file.
82 // Populates \p EditedFiles if there were changes to other files whenever
83 // it is non-null. It is a mapping from absolute path of the edited file to
84 // its new contents. Passing a nullptr to \p EditedFiles when there are
85 // changes, will result in a failure.
86 // The context added to MarkedCode will be stripped away before returning,
87 // unless the tweak edited it.
88 // - if the tweak produces a message, returns "message:\n<message>"
89 // - if prepare() returns false, returns "unavailable"
90 // - if apply() returns an error, returns "fail: <message>"
91 std::string apply(llvm::StringRef MarkedCode,
92 llvm::StringMap<std::string> *EditedFiles = nullptr) const;
94 // Helpers for EXPECT_AVAILABLE/EXPECT_UNAVAILABLE macros.
95 using WrappedAST = std::pair<ParsedAST, /*WrappingOffset*/ unsigned>;
96 WrappedAST build(llvm::StringRef) const;
97 bool isAvailable(WrappedAST &, llvm::Annotations::Range) const;
98 // Return code re-decorated with a single point/range.
99 static std::string decorate(llvm::StringRef, unsigned);
100 static std::string decorate(llvm::StringRef, llvm::Annotations::Range);
103 MATCHER_P2(FileWithContents, FileName, Contents, "") {
104 return arg.first() == FileName && arg.second == Contents;
107 #define TWEAK_TEST(TweakID) \
108 class TweakID##Test : public ::clang::clangd::TweakTest { \
109 protected: \
110 TweakID##Test() : TweakTest(#TweakID) {} \
113 #define EXPECT_AVAILABLE_(MarkedCode, Available) \
114 do { \
115 llvm::Annotations A{llvm::StringRef(MarkedCode)}; \
116 auto AST = build(A.code()); \
117 assert(!A.points().empty() || !A.ranges().empty()); \
118 for (const auto &P : A.points()) \
119 EXPECT_EQ(Available, isAvailable(AST, {P, P})) << decorate(A.code(), P); \
120 for (const auto &R : A.ranges()) \
121 EXPECT_EQ(Available, isAvailable(AST, R)) << decorate(A.code(), R); \
122 } while (0)
123 #define EXPECT_AVAILABLE(MarkedCode) EXPECT_AVAILABLE_(MarkedCode, true)
124 #define EXPECT_UNAVAILABLE(MarkedCode) EXPECT_AVAILABLE_(MarkedCode, false)
126 } // namespace clangd
127 } // namespace clang
129 #endif