CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
198 lines
7.9 KiB
C++
198 lines
7.9 KiB
C++
//===--- TweakTesting.h - Test helpers for refactoring actions ---*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_UNITTESTS_TWEAKS_TWEAKTESTING_H
|
|
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_UNITTESTS_TWEAKS_TWEAKTESTING_H
|
|
|
|
#include "ParsedAST.h"
|
|
#include "TestWorkspace.h"
|
|
#include "index/Index.h"
|
|
#include "llvm/ADT/StringMap.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Testing/Annotations/Annotations.h"
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
namespace clang {
|
|
namespace clangd {
|
|
|
|
// Fixture base for testing tweaks. Intended to be subclassed for each tweak.
|
|
//
|
|
// Usage:
|
|
// TWEAK_TEST(ExpandDeducedType);
|
|
//
|
|
// TEST_F(ExpandDeducedTypeTest, ShortensTypes) {
|
|
// Header = R"cpp(
|
|
// namespace foo { template<typename> class X{}; }
|
|
// using namespace foo;
|
|
// )cpp";
|
|
// Context = Function;
|
|
// EXPECT_THAT(apply("[[auto]] X = foo<int>();"),
|
|
// "foo<int> X = foo<int();");
|
|
// EXPECT_AVAILABLE("^a^u^t^o^ X = foo<int>();");
|
|
// EXPECT_UNAVAILABLE("auto ^X^ = ^foo<int>();");
|
|
// }
|
|
class TweakTest : public ::testing::Test {
|
|
const char *TweakID;
|
|
|
|
public:
|
|
// Inputs are wrapped in file boilerplate before attempting to apply a tweak.
|
|
// Context describes the type of boilerplate.
|
|
enum CodeContext {
|
|
// Code snippet is placed directly into the source file. e.g. a declaration.
|
|
File,
|
|
// Snippet will appear within a function body. e.g. a statement.
|
|
Function,
|
|
// Snippet is an expression.
|
|
Expression,
|
|
};
|
|
|
|
// Mapping from file name to contents.
|
|
llvm::StringMap<std::string> ExtraFiles;
|
|
|
|
protected:
|
|
TweakTest(const char *TweakID) : TweakID(TweakID) {}
|
|
|
|
// Contents of a header file to be implicitly included.
|
|
// This typically contains declarations that will be used for a set of related
|
|
// testcases.
|
|
std::string Header;
|
|
|
|
llvm::StringRef FileName = "TestTU.cpp";
|
|
|
|
// Extra flags passed to the compilation in apply().
|
|
std::vector<std::string> ExtraArgs;
|
|
|
|
// Context in which snippets of code should be placed to run tweaks.
|
|
CodeContext Context = File;
|
|
|
|
// Index to be passed into Tweak::Selection.
|
|
std::unique_ptr<const SymbolIndex> Index = nullptr;
|
|
|
|
// Apply the current tweak to the range (or point) in MarkedCode.
|
|
// MarkedCode will be wrapped according to the Context.
|
|
// - if the tweak produces edits, returns the edited code (without markings)
|
|
// for the main file.
|
|
// Populates \p EditedFiles if there were changes to other files whenever
|
|
// it is non-null. It is a mapping from absolute path of the edited file to
|
|
// its new contents. Passing a nullptr to \p EditedFiles when there are
|
|
// changes, will result in a failure.
|
|
// The context added to MarkedCode will be stripped away before returning,
|
|
// unless the tweak edited it.
|
|
// - if the tweak produces a message, returns "message:\n<message>"
|
|
// - if prepare() returns false, returns "unavailable"
|
|
// - if apply() returns an error, returns "fail: <message>"
|
|
std::string apply(llvm::StringRef MarkedCode,
|
|
llvm::StringMap<std::string> *EditedFiles = nullptr) const;
|
|
|
|
// Helpers for EXPECT_AVAILABLE/EXPECT_UNAVAILABLE macros.
|
|
using WrappedAST = std::pair<ParsedAST, /*WrappingOffset*/ unsigned>;
|
|
WrappedAST build(llvm::StringRef) const;
|
|
bool isAvailable(WrappedAST &, llvm::Annotations::Range) const;
|
|
// Return code re-decorated with a single point/range.
|
|
static std::string decorate(llvm::StringRef, unsigned);
|
|
static std::string decorate(llvm::StringRef, llvm::Annotations::Range);
|
|
};
|
|
|
|
MATCHER_P2(FileWithContents, FileName, Contents, "") {
|
|
return arg.first() == FileName && arg.second == Contents;
|
|
}
|
|
|
|
#define TWEAK_TEST(TweakID) \
|
|
class TweakID##Test : public ::clang::clangd::TweakTest { \
|
|
protected: \
|
|
TweakID##Test() : TweakTest(#TweakID) {} \
|
|
}
|
|
|
|
#define EXPECT_AVAILABLE_(MarkedCode, Available) \
|
|
do { \
|
|
llvm::Annotations A{llvm::StringRef(MarkedCode)}; \
|
|
auto AST = build(A.code()); \
|
|
assert(!A.points().empty() || !A.ranges().empty()); \
|
|
for (const auto &P : A.points()) \
|
|
EXPECT_EQ(Available, isAvailable(AST, {P, P})) << decorate(A.code(), P); \
|
|
for (const auto &R : A.ranges()) \
|
|
EXPECT_EQ(Available, isAvailable(AST, R)) << decorate(A.code(), R); \
|
|
} while (0)
|
|
#define EXPECT_AVAILABLE(MarkedCode) EXPECT_AVAILABLE_(MarkedCode, true)
|
|
#define EXPECT_UNAVAILABLE(MarkedCode) EXPECT_AVAILABLE_(MarkedCode, false)
|
|
|
|
// A helper class to represent the return value of TweakWorkspaceTest::apply().
|
|
struct TweakResult {
|
|
// A string representation the status of the operation.
|
|
// For failure cases, this is the same as the return value of
|
|
// TweakTest::apply() (see the comment above that for details).
|
|
// For success cases, this is "success".
|
|
std::string Status;
|
|
// The contents of all files changed by the tweak, including
|
|
// the file in which it was invoked. Keys are absolute paths.
|
|
llvm::StringMap<std::string> EditedFiles = {};
|
|
};
|
|
|
|
// GTest matchers to allow more easily writing assertions about the
|
|
// expected value of a TweakResult.
|
|
MATCHER_P(withStatus, S, "") { return arg.Status == S; }
|
|
template <class EditedFilesMatcher>
|
|
::testing::Matcher<TweakResult> editedFiles(EditedFilesMatcher M) {
|
|
return ::testing::Field(&TweakResult::EditedFiles, M);
|
|
}
|
|
|
|
// Used for formatting TweakResult objects in assertion failure messages,
|
|
// so it's easier to understand what didn't match.
|
|
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream,
|
|
const TweakResult &Result) {
|
|
Stream << "{ status: " << Result.Status << ", editedFiles: [";
|
|
for (const auto &F : Result.EditedFiles) {
|
|
Stream << F.first() << ":\n";
|
|
Stream << F.second;
|
|
}
|
|
return Stream << "] }";
|
|
}
|
|
|
|
// A version of TweakTest that makes it easier to create test cases that
|
|
// involve multiple files which are indexed.
|
|
// Usage:
|
|
// - Call `Workspace.addMainFile(filename, contents)` to add
|
|
// source files which are indexer entry points (e.g. would show
|
|
// up in `compile_commands.json`).
|
|
// - Call `Workspace.addSource(filename, contents)` to add other
|
|
// source files (e.g. header files).
|
|
// - Call `apply(filename, range)` to invoke the tweak on the
|
|
// indicated file with the given range selected. Can be called
|
|
// multiple times for the same set of added files.
|
|
// The implementation takes care of building an index reflecting
|
|
// all added source files, and making it available to the tweak.
|
|
// Unlike TweakTest, this does not have a notion of a `CodeContext`
|
|
// (i.e. the contents of all added files are interpreted as being
|
|
// in a File context).
|
|
class TweakWorkspaceTest : public ::testing::Test {
|
|
const char *TweakID;
|
|
|
|
public:
|
|
TweakWorkspaceTest(const char *TweakID) : TweakID(TweakID) {}
|
|
|
|
TweakResult apply(StringRef InvocationFile,
|
|
llvm::Annotations::Range InvocationRange);
|
|
|
|
protected:
|
|
TestWorkspace Workspace;
|
|
};
|
|
|
|
#define TWEAK_WORKSPACE_TEST(TweakID) \
|
|
class TweakID##WorkspaceTest : public ::clang::clangd::TweakWorkspaceTest { \
|
|
protected: \
|
|
TweakID##WorkspaceTest() : TweakWorkspaceTest(#TweakID) {} \
|
|
}
|
|
|
|
} // namespace clangd
|
|
} // namespace clang
|
|
|
|
#endif
|