Files
clice/unittests/Feature/FoldingRange.cpp
2025-02-20 20:56:51 +08:00

490 lines
7.3 KiB
C++

#include "Test/CTest.h"
#include "Feature/FoldingRange.h"
namespace clice::testing {
namespace {
using namespace clice::feature::foldingrange;
struct FoldingRange : public ::testing::Test {
std::optional<Tester> tester;
Result result;
void run(llvm::StringRef source) {
tester.emplace("main.cpp", source);
tester->run();
auto& info = tester->info;
proto::FoldingRangeParams param;
result = foldingRange(param, *info);
}
index::Shared<Result> runWithHeader(llvm::StringRef source, llvm::StringRef header) {
tester.emplace("main.cpp", source);
tester->addFile(path::join(".", "header.h"), header);
tester->run();
auto& info = tester->info;
proto::FoldingRangeParams param;
return foldingRange(*info);
}
void EXPECT_RANGE(std::size_t index,
llvm::StringRef begin,
llvm::StringRef end,
std::source_location current = std::source_location::current()) {
auto& folding = result[index];
auto begOff = tester->offset(begin);
EXPECT_EQ(begOff, folding.range.begin);
auto endOff = tester->offset(end);
EXPECT_EQ(endOff, folding.range.end);
}
};
TEST_F(FoldingRange, Namespace) {
run(R"cpp(
namespace single_line {$(1)
//
$(2)}
namespace with_nodes {$(3)
//
struct _ {};
$(4)}
namespace empty {}
namespace ugly
{$(5)
$(6)}
)cpp");
EXPECT_RANGE(0, "1", "2");
EXPECT_RANGE(1, "3", "4");
EXPECT_RANGE(2, "5", "6");
}
TEST_F(FoldingRange, NamespaceExpandedFromMacro) {
run(R"cpp(
#define NS_OUTER namespace outter {
#define NS_INNER namespace inner {
#define END_MACRO }
NS_OUTER$(1)
NS_INNER$(3)
namespace inner {$(5)
$(6)}
END_MACRO$(4)
END_MACRO$(2)
)cpp");
EXPECT_EQ(result.size(), 3);
EXPECT_RANGE(0, "1", "2");
EXPECT_RANGE(1, "3", "4");
EXPECT_RANGE(2, "5", "6");
}
TEST_F(FoldingRange, Enum) {
run(R"cpp(
enum _0 {$(1)
A,
B,
C
$(2)};
enum _1 { D };
enum class _2 {$(3)
A,
B,
C
$(4)};
)cpp");
EXPECT_RANGE(0, "1", "2");
EXPECT_RANGE(1, "3", "4");
}
TEST_F(FoldingRange, RecordDecl) {
run(R"cpp(
// struct _2 {$(1)
// int x;
// float y;
// $(2)};
//
// struct _3 {};
//
// struct _4;
//
// union _5 {$(3)
// int x;
// float y;
// $(4)};
//
// struct _6 {$(5)
// struct one_nested {$(7)
// //
// $(8)};
//
// //
// $(6)};
void f() {$(9)
struct another_nested {$(11)
//
$(12)};
$(10)}
)cpp");
// EXPECT_RANGE(0, "1", "2");
// EXPECT_RANGE(1, "3", "4");
// EXPECT_RANGE(2, "5", "6");
// EXPECT_RANGE(3, "7", "8");
// EXPECT_RANGE(4, "9", "10");
// EXPECT_RANGE(5, "11", "12");
EXPECT_RANGE(0, "9", "10");
EXPECT_RANGE(1, "11", "12");
}
TEST_F(FoldingRange, CXXRecordDeclAndMemberMethod) {
run(R"cpp(
struct _2 {$(1)
int x;
float y;
_2() = default;
$(2)};
struct _3 {$(3)
void method() {$(5)
int x = 0;
$(6)}
void parameter () {$(7)
//
$(8)}
void skip() {};
$(4)};
struct _4;
)cpp");
EXPECT_RANGE(0, "1", "2");
EXPECT_RANGE(1, "3", "4");
EXPECT_RANGE(2, "5", "6");
EXPECT_RANGE(3, "7", "8");
}
TEST_F(FoldingRange, LambdaCapture) {
run(R"cpp(
auto z = [$(1)
x = 0, y = 1
$(2)]() {$(3)
//
$(4)};
int array[4] = {0};
auto s = [$(5)
x=0,
y = 1,
z = array[
0],
k = -1
$(6)](){ return; };
)cpp");
EXPECT_EQ(result.size(), 3);
EXPECT_RANGE(0, "1", "2");
EXPECT_RANGE(1, "3", "4");
EXPECT_RANGE(2, "5", "6");
}
TEST_F(FoldingRange, LambdaExpression) {
run(R"cpp(
auto _0 = [](int _) {};
auto _1 = [](int _) {$(1)
//
$(2)};
auto _2 = [](int _) {$(3)
//
return 0;
$(4)};
auto _3 = []($(5)
int _1,
int _2
$(6)) {};
)cpp");
EXPECT_EQ(result.size(), 3);
EXPECT_RANGE(0, "1", "2");
EXPECT_RANGE(1, "3", "4");
EXPECT_RANGE(2, "5", "6");
}
TEST_F(FoldingRange, FunctionParams) {
run(R"cpp(
void e() {}
void f($(1)
//
//
$(2)) {}
void g($(3)
int x,
int y = 2
//
$(4)) {}
void d($(5)
int _1,
int _2,
...
$(6));
)cpp");
EXPECT_RANGE(0, "1", "2");
EXPECT_RANGE(1, "3", "4");
EXPECT_RANGE(2, "5", "6");
}
TEST_F(FoldingRange, FunctionBody) {
run(R"cpp(
void f() {$(1)
//
//
$(2)}
void g() {$(3)
int x = 0;
$(4)}
void e() {}
void n() {$(5)
{$(7)
// empty bock
$(8)}
//
$(6)}
)cpp");
EXPECT_EQ(result.size(), 4);
EXPECT_RANGE(0, "1", "2");
EXPECT_RANGE(1, "3", "4");
EXPECT_RANGE(2, "5", "6");
EXPECT_RANGE(3, "7", "8");
}
TEST_F(FoldingRange, FunctionCall) {
run(R"cpp(
int f(int _1, int _2, int _3, int _4, int _5, int _6) { return _1 + _2; }
int main() {$(1)
int _ = f(1, (1 + 2), 3, 4, 5, 6);
return f($(3)
1, 2, 3,
4, 5, 6
$(4));
$(2)}
)cpp");
EXPECT_RANGE(0, "1", "2");
EXPECT_RANGE(1, "3", "4");
}
TEST_F(FoldingRange, CompoundStmt) {
run(R"cpp(
int main () {$(1)
{$(3)
{$(5)
//
$(6)}
{$(7)
//
$(8)}
//
$(4)}
return 0;
$(2)}
)cpp");
EXPECT_RANGE(0, "1", "2");
EXPECT_RANGE(1, "3", "4");
EXPECT_RANGE(2, "5", "6");
}
TEST_F(FoldingRange, InitializeList) {
run(R"cpp(
struct L { int xs[4]; };
L l1 = {$(1)
1, 2, 3, 4
$(2)};
L l2 = {$(3)
//
//
$(4)};
)cpp");
EXPECT_RANGE(0, "1", "2");
EXPECT_RANGE(1, "3", "4");
}
TEST_F(FoldingRange, AccessControlBlock) {
run(R"cpp(
struct empty { int x; };
class _0 {$(1)
public:$(3)
int x;
$(4)private:$(5)
int z;
$(2)$(6)};
struct _1 {$(7)
int x;
private:$(9)
int z;
$(8)$(10)};
struct _2 {$(11)
public:
private:
public:$(13)
int x = 1;
$(12)$(14)};
)cpp");
EXPECT_EQ(result.size(), 9);
EXPECT_RANGE(0, "1", "2");
EXPECT_RANGE(1, "3", "4");
EXPECT_RANGE(2, "5", "6");
EXPECT_RANGE(3, "7", "8");
EXPECT_RANGE(4, "9", "10");
EXPECT_RANGE(5, "11", "12");
// do not test result[6] and result[7]
EXPECT_RANGE(8, "13", "14");
}
TEST_F(FoldingRange, Macro) {
run(R"cpp(
#ifdef M1
#else
#ifdef M2
#endif
#endif
)cpp");
EXPECT_EQ(result.size(), 3);
}
TEST_F(FoldingRange, PragmaRegion) {
run(R"cpp(
#pragma region level1 $(1)
#pragma region level2 $(2)
#pragma region level3 $(3)
$(4)#pragma endregion level3
$(5)#pragma endregion level2
$(6)#pragma endregion level1
#pragma endregion // mismatch region, skipped
// broken region, use the end of file as endregion
#pragma region $(7)
$(eof))cpp");
EXPECT_EQ(result.size(), 4);
EXPECT_RANGE(0, "3", "4");
EXPECT_RANGE(1, "2", "5");
EXPECT_RANGE(2, "1", "6");
EXPECT_RANGE(3, "7", "eof");
}
TEST_F(FoldingRange, WithHeader) {
auto header = R"cpp(
namespace _1 {
namespace _2 {
}
}
)cpp";
auto source = R"cpp(
#include "header.h"
int main() {$(3)
$(4)
}
)cpp";
auto multifiles = runWithHeader(source, header);
EXPECT_EQ(multifiles.size(), 2);
auto mainID = tester->info->srcMgr().getMainFileID();
for(auto& [id, result]: multifiles) {
if(id == mainID) {
EXPECT_EQ(result.size(), 1);
} else {
EXPECT_EQ(result.size(), 2);
}
}
}
} // namespace
} // namespace clice::testing