refactor(tests): CMake-based CDB, workspace fixture, test cleanup (#378)
## Summary - **CMake-based CDB generation for module tests**: Replace hand-written compile_commands.json with CMakeLists.txt (CMake 3.28 `FILE_SET CXX_MODULES`) in all 26 `tests/data/modules/*/` directories. CDB is generated on-the-fly via `cmake -G Ninja` during test setup. - **`@pytest.mark.workspace()` decorator**: Introduce a marker + fixture pattern so tests declare their workspace via decorator and receive a resolved `workspace` path. The fixture auto-generates CDB when a CMakeLists.txt is present. - **`CliceClient` helper methods**: Add `initialize()`, `open()`, `wait_diagnostics()`, and `open_and_wait()` to reduce boilerplate across all test files. - **Use `asyncio_mode = "auto"`**: Switch from `@pytest_asyncio.fixture` + `@pytest.mark.asyncio` to `@pytest.fixture` + auto mode for proper Pylance type inference on fixtures. - **Test cleanup**: Remove redundant section separators and docstrings, delete `tests/pyproject.toml` (config moved to `pytest.ini`). - **Format task**: Add `.cppm` to `format-cpp` glob pattern. - **CI fix**: Disable `CMAKE_CXX_SCAN_FOR_MODULES` and prefer pixi clang++ to fix macOS CI where CMake rejects module scanning. ## Test plan - [x] All 26 module test directories have CMakeLists.txt with FILE_SET CXX_MODULES - [x] generate_cdb() produces valid compile_commands.json with module flags - [x] Integration tests pass locally - [ ] CI passes on all platforms (Linux, macOS, Windows) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Unified fixtures and client workflow: new init/open/wait helpers, workspace marker support, bounded diagnostics waiting, CMake-based compilation-database generation, and directory-backed temp-file workflows; enabled asyncio test mode. * **Chores** * Added many C++20 module test projects and test data; removed prior test pyproject in favor of pytest config; updated formatter to include .cppm files. * **Style** * Reformatted many module/source implementations to consistent multi-line function bodies. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,11 +13,6 @@ namespace {
|
||||
|
||||
namespace et = eventide;
|
||||
|
||||
void write_cdb(TempDir& tmp, CompilationDatabase& cdb, llvm::StringRef json_content) {
|
||||
tmp.touch("compile_commands.json", json_content);
|
||||
cdb.load(tmp.path("compile_commands.json"));
|
||||
}
|
||||
|
||||
/// Build a dispatch_fn that compiles PCMs in-process (no workers).
|
||||
/// Clang requires ALL transitive PCM deps (not just direct imports)
|
||||
/// in PrebuiltModuleFiles, so we pass every available PCM.
|
||||
|
||||
@@ -21,13 +21,15 @@ namespace et = eventide;
|
||||
TEST_SUITE(ModuleWorker) {
|
||||
|
||||
TEST_CASE(BuildPCMThenCompileWithImport) {
|
||||
TempDir tmp;
|
||||
// Module interface: produces PCM.
|
||||
TempFile iface(
|
||||
"mod_iface.cppm",
|
||||
"export module Hello;\n" R"(export const char* hello() { return "world"; })" "\n");
|
||||
tmp.touch("mod_iface.cppm",
|
||||
"export module Hello;\n" R"(export const char* hello() { return "world"; })" "\n");
|
||||
auto iface = tmp.path("mod_iface.cppm");
|
||||
|
||||
// Consumer: imports the module.
|
||||
TempFile consumer("consumer.cpp", "import Hello;\n" "int main() { return hello()[0]; }\n");
|
||||
tmp.touch("consumer.cpp", "import Hello;\n" "int main() { return hello()[0]; }\n");
|
||||
auto consumer = tmp.path("consumer.cpp");
|
||||
|
||||
// --- Phase 1: Build PCM via stateless worker ---
|
||||
WorkerHandle sl;
|
||||
@@ -38,14 +40,14 @@ TEST_CASE(BuildPCMThenCompileWithImport) {
|
||||
|
||||
sl.run([&]() -> et::task<> {
|
||||
worker::BuildPCMParams params;
|
||||
params.file = iface.path;
|
||||
params.file = iface;
|
||||
params.directory = "/tmp";
|
||||
params.arguments = {"clang++",
|
||||
"-resource-dir",
|
||||
std::string(resource_dir()),
|
||||
"-std=c++20",
|
||||
"--precompile",
|
||||
iface.path};
|
||||
iface};
|
||||
params.module_name = "Hello";
|
||||
|
||||
auto result = co_await sl.peer->send_request(params);
|
||||
@@ -69,7 +71,7 @@ TEST_CASE(BuildPCMThenCompileWithImport) {
|
||||
|
||||
sf.run([&]() -> et::task<> {
|
||||
worker::CompileParams params;
|
||||
params.path = consumer.path;
|
||||
params.path = consumer;
|
||||
params.version = 1;
|
||||
params.text = "import Hello;\n" "int main() { return hello()[0]; }\n";
|
||||
params.directory = "/tmp";
|
||||
@@ -78,7 +80,7 @@ TEST_CASE(BuildPCMThenCompileWithImport) {
|
||||
std::string(resource_dir()),
|
||||
"-std=c++20",
|
||||
"-fsyntax-only",
|
||||
consumer.path};
|
||||
consumer};
|
||||
// Pass the PCM — same as MasterServer fills CompileParams.pcms.
|
||||
params.pcms = {
|
||||
{"Hello", pcm_path}
|
||||
@@ -99,15 +101,19 @@ TEST_CASE(BuildPCMThenCompileWithImport) {
|
||||
}
|
||||
|
||||
TEST_CASE(BuildPCMChainThenCompile) {
|
||||
TempDir tmp;
|
||||
// Module A: no deps.
|
||||
TempFile mod_a("chain_a.cppm", "export module A;\n" "export int val_a() { return 1; }\n");
|
||||
tmp.touch("chain_a.cppm", "export module A;\n" "export int val_a() { return 1; }\n");
|
||||
auto mod_a = tmp.path("chain_a.cppm");
|
||||
// Module B: imports A.
|
||||
TempFile mod_b("chain_b.cppm",
|
||||
"export module B;\n"
|
||||
"import A;\n"
|
||||
"export int val_b() { return val_a() + 1; }\n");
|
||||
tmp.touch("chain_b.cppm",
|
||||
"export module B;\n"
|
||||
"import A;\n"
|
||||
"export int val_b() { return val_a() + 1; }\n");
|
||||
auto mod_b = tmp.path("chain_b.cppm");
|
||||
// Consumer: imports B (transitively needs A).
|
||||
TempFile consumer("chain_consumer.cpp", "import B;\n" "int main() { return val_b(); }\n");
|
||||
tmp.touch("chain_consumer.cpp", "import B;\n" "int main() { return val_b(); }\n");
|
||||
auto consumer = tmp.path("chain_consumer.cpp");
|
||||
|
||||
WorkerHandle sl;
|
||||
ASSERT_TRUE(sl.spawn("stateless-worker"));
|
||||
@@ -119,14 +125,14 @@ TEST_CASE(BuildPCMChainThenCompile) {
|
||||
// Build PCM for A first.
|
||||
{
|
||||
worker::BuildPCMParams params;
|
||||
params.file = mod_a.path;
|
||||
params.file = mod_a;
|
||||
params.directory = "/tmp";
|
||||
params.arguments = {"clang++",
|
||||
"-resource-dir",
|
||||
std::string(resource_dir()),
|
||||
"-std=c++20",
|
||||
"--precompile",
|
||||
mod_a.path};
|
||||
mod_a};
|
||||
params.module_name = "A";
|
||||
|
||||
auto result = co_await sl.peer->send_request(params);
|
||||
@@ -137,14 +143,14 @@ TEST_CASE(BuildPCMChainThenCompile) {
|
||||
// Build PCM for B, passing A's PCM (transitive dep).
|
||||
{
|
||||
worker::BuildPCMParams params;
|
||||
params.file = mod_b.path;
|
||||
params.file = mod_b;
|
||||
params.directory = "/tmp";
|
||||
params.arguments = {"clang++",
|
||||
"-resource-dir",
|
||||
std::string(resource_dir()),
|
||||
"-std=c++20",
|
||||
"--precompile",
|
||||
mod_b.path};
|
||||
mod_b};
|
||||
params.module_name = "B";
|
||||
params.pcms = {
|
||||
{"A", pcm_a}
|
||||
@@ -169,7 +175,7 @@ TEST_CASE(BuildPCMChainThenCompile) {
|
||||
|
||||
sf.run([&]() -> et::task<> {
|
||||
worker::CompileParams params;
|
||||
params.path = consumer.path;
|
||||
params.path = consumer;
|
||||
params.version = 1;
|
||||
params.text = "import B;\n" "int main() { return val_b(); }\n";
|
||||
params.directory = "/tmp";
|
||||
@@ -178,7 +184,7 @@ TEST_CASE(BuildPCMChainThenCompile) {
|
||||
std::string(resource_dir()),
|
||||
"-std=c++20",
|
||||
"-fsyntax-only",
|
||||
consumer.path};
|
||||
consumer};
|
||||
// Clang needs ALL transitive PCMs.
|
||||
params.pcms = {
|
||||
{"A", pcm_a},
|
||||
@@ -200,10 +206,13 @@ TEST_CASE(BuildPCMChainThenCompile) {
|
||||
}
|
||||
|
||||
TEST_CASE(ModuleImplementationUnitWithWorker) {
|
||||
TempDir tmp;
|
||||
// Module interface.
|
||||
TempFile iface("impl_iface.cppm", "export module Calc;\n" "export int add(int a, int b);\n");
|
||||
tmp.touch("impl_iface.cppm", "export module Calc;\n" "export int add(int a, int b);\n");
|
||||
auto iface = tmp.path("impl_iface.cppm");
|
||||
// Module implementation unit (no export).
|
||||
TempFile impl("impl_unit.cpp", "module Calc;\n" "int add(int a, int b) { return a + b; }\n");
|
||||
tmp.touch("impl_unit.cpp", "module Calc;\n" "int add(int a, int b) { return a + b; }\n");
|
||||
auto impl = tmp.path("impl_unit.cpp");
|
||||
|
||||
// Build PCM for interface.
|
||||
WorkerHandle sl;
|
||||
@@ -214,14 +223,14 @@ TEST_CASE(ModuleImplementationUnitWithWorker) {
|
||||
|
||||
sl.run([&]() -> et::task<> {
|
||||
worker::BuildPCMParams params;
|
||||
params.file = iface.path;
|
||||
params.file = iface;
|
||||
params.directory = "/tmp";
|
||||
params.arguments = {"clang++",
|
||||
"-resource-dir",
|
||||
std::string(resource_dir()),
|
||||
"-std=c++20",
|
||||
"--precompile",
|
||||
iface.path};
|
||||
iface};
|
||||
params.module_name = "Calc";
|
||||
|
||||
auto result = co_await sl.peer->send_request(params);
|
||||
@@ -242,7 +251,7 @@ TEST_CASE(ModuleImplementationUnitWithWorker) {
|
||||
|
||||
sf.run([&]() -> et::task<> {
|
||||
worker::CompileParams params;
|
||||
params.path = impl.path;
|
||||
params.path = impl;
|
||||
params.version = 1;
|
||||
params.text = "module Calc;\n" "int add(int a, int b) { return a + b; }\n";
|
||||
params.directory = "/tmp";
|
||||
@@ -251,7 +260,7 @@ TEST_CASE(ModuleImplementationUnitWithWorker) {
|
||||
std::string(resource_dir()),
|
||||
"-std=c++20",
|
||||
"-fsyntax-only",
|
||||
impl.path};
|
||||
impl};
|
||||
params.pcms = {
|
||||
{"Calc", pcm_path}
|
||||
};
|
||||
|
||||
@@ -24,7 +24,9 @@ TEST_CASE(SpawnAndExit) {
|
||||
}
|
||||
|
||||
TEST_CASE(CompileRequest) {
|
||||
TempFile src("compile_test.cpp", "int main() { return 0; }\n");
|
||||
TempDir tmp;
|
||||
tmp.touch("compile_test.cpp", "int main() { return 0; }\n");
|
||||
auto src = tmp.path("compile_test.cpp");
|
||||
|
||||
WorkerHandle w;
|
||||
ASSERT_TRUE(w.spawn("stateful-worker"));
|
||||
@@ -33,11 +35,11 @@ TEST_CASE(CompileRequest) {
|
||||
|
||||
w.run([&]() -> et::task<> {
|
||||
worker::CompileParams params;
|
||||
params.path = src.path;
|
||||
params.path = src;
|
||||
params.version = 1;
|
||||
params.text = "int main() { return 0; }\n";
|
||||
params.directory = "/tmp";
|
||||
params.arguments = make_args(src.path);
|
||||
params.arguments = make_args(src);
|
||||
params.pch = {"", 0};
|
||||
params.pcms = {};
|
||||
|
||||
@@ -76,7 +78,9 @@ TEST_CASE(HoverWithoutCompile) {
|
||||
|
||||
TEST_CASE(CompileThenHover) {
|
||||
std::string text = "int foo() { return 42; }\nint main() { return foo(); }\n";
|
||||
TempFile src("hover_test.cpp", text);
|
||||
TempDir tmp;
|
||||
tmp.touch("hover_test.cpp", text);
|
||||
auto src = tmp.path("hover_test.cpp");
|
||||
|
||||
WorkerHandle w;
|
||||
ASSERT_TRUE(w.spawn("stateful-worker"));
|
||||
@@ -86,11 +90,11 @@ TEST_CASE(CompileThenHover) {
|
||||
w.run([&]() -> et::task<> {
|
||||
// First compile
|
||||
worker::CompileParams cp;
|
||||
cp.path = src.path;
|
||||
cp.path = src;
|
||||
cp.version = 1;
|
||||
cp.text = text;
|
||||
cp.directory = "/tmp";
|
||||
cp.arguments = make_args(src.path);
|
||||
cp.arguments = make_args(src);
|
||||
|
||||
auto compile_result = co_await w.peer->send_request(cp);
|
||||
CO_ASSERT_TRUE(compile_result.has_value());
|
||||
@@ -98,7 +102,7 @@ TEST_CASE(CompileThenHover) {
|
||||
// After successful compilation, hover should return info.
|
||||
// "int foo() { return 42; }\n" is 25 chars, then char 22 on line 1 = offset 47
|
||||
worker::HoverParams hp;
|
||||
hp.path = src.path;
|
||||
hp.path = src;
|
||||
hp.offset = 47; // position of 'foo' in 'return foo();'
|
||||
|
||||
auto hover_result = co_await w.peer->send_request(hp);
|
||||
@@ -114,7 +118,9 @@ TEST_CASE(CompileThenHover) {
|
||||
}
|
||||
|
||||
TEST_CASE(DocumentUpdate) {
|
||||
TempFile src("update_test.cpp", "int x = 1;\n");
|
||||
TempDir tmp;
|
||||
tmp.touch("update_test.cpp", "int x = 1;\n");
|
||||
auto src = tmp.path("update_test.cpp");
|
||||
|
||||
WorkerHandle w;
|
||||
ASSERT_TRUE(w.spawn("stateful-worker"));
|
||||
@@ -124,25 +130,25 @@ TEST_CASE(DocumentUpdate) {
|
||||
w.run([&]() -> et::task<> {
|
||||
// Compile first
|
||||
worker::CompileParams cp;
|
||||
cp.path = src.path;
|
||||
cp.path = src;
|
||||
cp.version = 1;
|
||||
cp.text = "int x = 1;\n";
|
||||
cp.directory = "/tmp";
|
||||
cp.arguments = make_args(src.path);
|
||||
cp.arguments = make_args(src);
|
||||
|
||||
auto r1 = co_await w.peer->send_request(cp);
|
||||
CO_ASSERT_TRUE(r1.has_value());
|
||||
|
||||
// Send document update notification
|
||||
worker::DocumentUpdateParams up;
|
||||
up.path = src.path;
|
||||
up.path = src;
|
||||
up.version = 2;
|
||||
up.text = "int x = 2;\nint y = 3;\n";
|
||||
w.peer->send_notification(up);
|
||||
|
||||
// After update, hover still returns stale AST results (not null).
|
||||
worker::HoverParams hp;
|
||||
hp.path = src.path;
|
||||
hp.path = src;
|
||||
hp.offset = 4;
|
||||
|
||||
auto hover_result = co_await w.peer->send_request(hp);
|
||||
@@ -299,13 +305,15 @@ TEST_CASE(InlayHintsWithoutCompile) {
|
||||
}
|
||||
|
||||
TEST_CASE(MultipleSequentialRequests) {
|
||||
TempFile src("seq_test.cpp",
|
||||
TempDir tmp;
|
||||
tmp.touch("seq_test.cpp",
|
||||
"int foo(int x) {\n"
|
||||
" return x + 1;\n"
|
||||
"}\n"
|
||||
"int main() {\n"
|
||||
" return foo(0);\n"
|
||||
"}\n");
|
||||
auto src = tmp.path("seq_test.cpp");
|
||||
|
||||
WorkerHandle w;
|
||||
ASSERT_TRUE(w.spawn("stateful-worker"));
|
||||
@@ -315,24 +323,24 @@ TEST_CASE(MultipleSequentialRequests) {
|
||||
w.run([&]() -> et::task<> {
|
||||
// Compile first so feature requests return real data.
|
||||
worker::CompileParams cp;
|
||||
cp.path = src.path;
|
||||
cp.path = src;
|
||||
cp.version = 1;
|
||||
cp.text = "int foo(int x) {\n return x + 1;\n}\nint main() {\n return foo(0);\n}\n";
|
||||
cp.directory = "/tmp";
|
||||
cp.arguments = make_args(src.path);
|
||||
cp.arguments = make_args(src);
|
||||
|
||||
auto cr = co_await w.peer->send_request(cp);
|
||||
CO_ASSERT_TRUE(cr.has_value());
|
||||
|
||||
// Now send multiple different feature requests sequentially.
|
||||
worker::HoverParams hp;
|
||||
hp.path = src.path;
|
||||
hp.path = src;
|
||||
hp.offset = 4; // 'foo' on line 0
|
||||
auto r1 = co_await w.peer->send_request(hp);
|
||||
EXPECT_TRUE(r1.has_value());
|
||||
|
||||
worker::CodeActionParams cap;
|
||||
cap.path = src.path;
|
||||
cap.path = src;
|
||||
auto r2 = co_await w.peer->send_request(cap);
|
||||
EXPECT_TRUE(r2.has_value());
|
||||
|
||||
@@ -340,18 +348,18 @@ TEST_CASE(MultipleSequentialRequests) {
|
||||
// lines: "int foo(int x) {\n"=17, " return x + 1;\n"=18, "}\n"=2, "int main() {\n"=14
|
||||
// offset = 17+18+2+14+11 = 62
|
||||
worker::GoToDefinitionParams gdp;
|
||||
gdp.path = src.path;
|
||||
gdp.path = src;
|
||||
gdp.offset = 62;
|
||||
auto r3 = co_await w.peer->send_request(gdp);
|
||||
EXPECT_TRUE(r3.has_value());
|
||||
|
||||
worker::SemanticTokensParams stp;
|
||||
stp.path = src.path;
|
||||
stp.path = src;
|
||||
auto r4 = co_await w.peer->send_request(stp);
|
||||
EXPECT_TRUE(r4.has_value());
|
||||
|
||||
worker::FoldingRangeParams frp;
|
||||
frp.path = src.path;
|
||||
frp.path = src;
|
||||
auto r5 = co_await w.peer->send_request(frp);
|
||||
EXPECT_TRUE(r5.has_value());
|
||||
|
||||
@@ -363,12 +371,15 @@ TEST_CASE(MultipleSequentialRequests) {
|
||||
}
|
||||
|
||||
TEST_CASE(MultipleDocuments) {
|
||||
std::vector<std::unique_ptr<TempFile>> files;
|
||||
TempDir tmp;
|
||||
std::vector<std::string> paths;
|
||||
std::vector<std::string> texts;
|
||||
for(int i = 0; i < 3; i++) {
|
||||
auto name = "multi_" + std::to_string(i) + ".cpp";
|
||||
auto text = "int var_" + std::to_string(i) + " = " + std::to_string(i) + ";\n";
|
||||
tmp.touch(name, text);
|
||||
paths.push_back(tmp.path(name));
|
||||
texts.push_back(text);
|
||||
files.push_back(std::make_unique<TempFile>("multi_" + std::to_string(i) + ".cpp", text));
|
||||
}
|
||||
|
||||
WorkerHandle w;
|
||||
@@ -380,11 +391,11 @@ TEST_CASE(MultipleDocuments) {
|
||||
// Compile 3 different documents.
|
||||
for(int i = 0; i < 3; i++) {
|
||||
worker::CompileParams cp;
|
||||
cp.path = files[i]->path;
|
||||
cp.path = paths[i];
|
||||
cp.version = 1;
|
||||
cp.text = texts[i];
|
||||
cp.directory = "/tmp";
|
||||
cp.arguments = make_args(files[i]->path);
|
||||
cp.arguments = make_args(paths[i]);
|
||||
|
||||
auto result = co_await w.peer->send_request(cp);
|
||||
EXPECT_TRUE(result.has_value());
|
||||
@@ -393,7 +404,7 @@ TEST_CASE(MultipleDocuments) {
|
||||
// Hover on each document after compilation.
|
||||
for(int i = 0; i < 3; i++) {
|
||||
worker::HoverParams hp;
|
||||
hp.path = files[i]->path;
|
||||
hp.path = paths[i];
|
||||
hp.offset = 4; // 'var_N'
|
||||
|
||||
auto result = co_await w.peer->send_request(hp);
|
||||
@@ -436,7 +447,9 @@ TEST_CASE(EvictNotification) {
|
||||
}
|
||||
|
||||
TEST_CASE(SpawnWithMemoryLimit) {
|
||||
TempFile src("memlimit_test.cpp", "int memlimit_var = 42;\n");
|
||||
TempDir tmp;
|
||||
tmp.touch("memlimit_test.cpp", "int memlimit_var = 42;\n");
|
||||
auto src = tmp.path("memlimit_test.cpp");
|
||||
|
||||
WorkerHandle w;
|
||||
// Spawn with a specific memory limit to test the CLI flag is accepted.
|
||||
@@ -447,18 +460,18 @@ TEST_CASE(SpawnWithMemoryLimit) {
|
||||
w.run([&]() -> et::task<> {
|
||||
// Compile first.
|
||||
worker::CompileParams cp;
|
||||
cp.path = src.path;
|
||||
cp.path = src;
|
||||
cp.version = 1;
|
||||
cp.text = "int memlimit_var = 42;\n";
|
||||
cp.directory = "/tmp";
|
||||
cp.arguments = make_args(src.path);
|
||||
cp.arguments = make_args(src);
|
||||
|
||||
auto cr = co_await w.peer->send_request(cp);
|
||||
EXPECT_TRUE(cr.has_value());
|
||||
|
||||
// Feature request should work after compilation.
|
||||
worker::HoverParams hp;
|
||||
hp.path = src.path;
|
||||
hp.path = src;
|
||||
hp.offset = 4; // 'memlimit_var'
|
||||
|
||||
auto result = co_await w.peer->send_request(hp);
|
||||
|
||||
@@ -83,7 +83,9 @@ TEST_CASE(SpawnAndExit) {
|
||||
}
|
||||
|
||||
TEST_CASE(BuildPCHRequest) {
|
||||
TempFile hdr("test_pch.h", "#pragma once\nint pch_global = 42;\n");
|
||||
TempDir tmp;
|
||||
tmp.touch("test_pch.h", "#pragma once\nint pch_global = 42;\n");
|
||||
auto hdr = tmp.path("test_pch.h");
|
||||
|
||||
WorkerHandle w;
|
||||
ASSERT_TRUE(w.spawn("stateless-worker"));
|
||||
@@ -92,10 +94,10 @@ TEST_CASE(BuildPCHRequest) {
|
||||
|
||||
w.run([&]() -> et::task<> {
|
||||
worker::BuildPCHParams params;
|
||||
params.file = hdr.path;
|
||||
params.file = hdr;
|
||||
params.directory = "/tmp";
|
||||
params.arguments =
|
||||
{"clang++", "-resource-dir", std::string(resource_dir()), "-x", "c++-header", hdr.path};
|
||||
{"clang++", "-resource-dir", std::string(resource_dir()), "-x", "c++-header", hdr};
|
||||
params.content = "#pragma once\nint pch_global = 42;\n";
|
||||
|
||||
auto result = co_await w.peer->send_request(params);
|
||||
@@ -108,7 +110,9 @@ TEST_CASE(BuildPCHRequest) {
|
||||
}
|
||||
|
||||
TEST_CASE(IndexRequest) {
|
||||
TempFile src("test_index.cpp", "int indexed_var = 1;\n");
|
||||
TempDir tmp;
|
||||
tmp.touch("test_index.cpp", "int indexed_var = 1;\n");
|
||||
auto src = tmp.path("test_index.cpp");
|
||||
|
||||
WorkerHandle w;
|
||||
ASSERT_TRUE(w.spawn("stateless-worker"));
|
||||
@@ -117,9 +121,9 @@ TEST_CASE(IndexRequest) {
|
||||
|
||||
w.run([&]() -> et::task<> {
|
||||
worker::IndexParams params;
|
||||
params.file = src.path;
|
||||
params.file = src;
|
||||
params.directory = "/tmp";
|
||||
params.arguments = make_args(src.path);
|
||||
params.arguments = make_args(src);
|
||||
|
||||
auto result = co_await w.peer->send_request(params);
|
||||
EXPECT_TRUE(result.has_value());
|
||||
@@ -139,8 +143,10 @@ TEST_CASE(IndexRequest) {
|
||||
TEST_SUITE(StatelessWorkerExtended) {
|
||||
|
||||
TEST_CASE(BuildPCMRequest) {
|
||||
TempFile src("test_module.cppm",
|
||||
"export module test_module;\nexport int module_func() { return 1; }\n");
|
||||
TempDir tmp;
|
||||
tmp.touch("test_module.cppm",
|
||||
"export module test_module;\nexport int module_func() { return 1; }\n");
|
||||
auto src = tmp.path("test_module.cppm");
|
||||
|
||||
WorkerHandle w;
|
||||
ASSERT_TRUE(w.spawn("stateless-worker"));
|
||||
@@ -149,14 +155,14 @@ TEST_CASE(BuildPCMRequest) {
|
||||
|
||||
w.run([&]() -> et::task<> {
|
||||
worker::BuildPCMParams params;
|
||||
params.file = src.path;
|
||||
params.file = src;
|
||||
params.directory = "/tmp";
|
||||
params.arguments = {"clang++",
|
||||
"-resource-dir",
|
||||
std::string(resource_dir()),
|
||||
"-std=c++20",
|
||||
"--precompile",
|
||||
src.path};
|
||||
src};
|
||||
params.module_name = "test_module";
|
||||
|
||||
auto result = co_await w.peer->send_request(params);
|
||||
@@ -170,7 +176,9 @@ TEST_CASE(BuildPCMRequest) {
|
||||
|
||||
TEST_CASE(CompletionRequest) {
|
||||
std::string text = "int foo = 1;\nint bar = fo";
|
||||
TempFile src("completion_test.cpp", text);
|
||||
TempDir tmp;
|
||||
tmp.touch("completion_test.cpp", text);
|
||||
auto src = tmp.path("completion_test.cpp");
|
||||
|
||||
WorkerHandle w;
|
||||
ASSERT_TRUE(w.spawn("stateless-worker"));
|
||||
@@ -179,11 +187,11 @@ TEST_CASE(CompletionRequest) {
|
||||
|
||||
w.run([&]() -> et::task<> {
|
||||
worker::CompletionParams params;
|
||||
params.path = src.path;
|
||||
params.path = src;
|
||||
params.version = 1;
|
||||
params.text = text;
|
||||
params.directory = "/tmp";
|
||||
params.arguments = make_args(src.path);
|
||||
params.arguments = make_args(src);
|
||||
params.offset = 25; // after "fo" in "int bar = fo" (13 + 12)
|
||||
|
||||
auto result = co_await w.peer->send_request(params);
|
||||
@@ -197,7 +205,9 @@ TEST_CASE(CompletionRequest) {
|
||||
|
||||
TEST_CASE(SignatureHelpRequest) {
|
||||
std::string text = "void foo(int a, int b) {}\nint main() { foo(";
|
||||
TempFile src("sighelp_test.cpp", text);
|
||||
TempDir tmp;
|
||||
tmp.touch("sighelp_test.cpp", text);
|
||||
auto src = tmp.path("sighelp_test.cpp");
|
||||
|
||||
WorkerHandle w;
|
||||
ASSERT_TRUE(w.spawn("stateless-worker"));
|
||||
@@ -206,11 +216,11 @@ TEST_CASE(SignatureHelpRequest) {
|
||||
|
||||
w.run([&]() -> et::task<> {
|
||||
worker::SignatureHelpParams params;
|
||||
params.path = src.path;
|
||||
params.path = src;
|
||||
params.version = 1;
|
||||
params.text = text;
|
||||
params.directory = "/tmp";
|
||||
params.arguments = make_args(src.path);
|
||||
params.arguments = make_args(src);
|
||||
params.offset = 45; // after "foo(" (26 + 19)
|
||||
|
||||
auto result = co_await w.peer->send_request(params);
|
||||
@@ -224,11 +234,13 @@ TEST_CASE(SignatureHelpRequest) {
|
||||
}
|
||||
|
||||
TEST_CASE(MultipleStatelessRequests) {
|
||||
std::vector<std::unique_ptr<TempFile>> files;
|
||||
TempDir tmp;
|
||||
std::vector<std::string> paths;
|
||||
for(int i = 0; i < 3; i++) {
|
||||
auto name = "multi_index_" + std::to_string(i) + ".cpp";
|
||||
auto text = "int idx_var_" + std::to_string(i) + " = " + std::to_string(i) + ";\n";
|
||||
files.push_back(
|
||||
std::make_unique<TempFile>("multi_index_" + std::to_string(i) + ".cpp", text));
|
||||
tmp.touch(name, text);
|
||||
paths.push_back(tmp.path(name));
|
||||
}
|
||||
|
||||
WorkerHandle w;
|
||||
@@ -240,9 +252,9 @@ TEST_CASE(MultipleStatelessRequests) {
|
||||
// Send multiple index requests to test stateless worker handles them sequentially.
|
||||
for(int i = 0; i < 3; i++) {
|
||||
worker::IndexParams params;
|
||||
params.file = files[i]->path;
|
||||
params.file = paths[i];
|
||||
params.directory = "/tmp";
|
||||
params.arguments = make_args(files[i]->path);
|
||||
params.arguments = make_args(paths[i]);
|
||||
|
||||
auto result = co_await w.peer->send_request(params);
|
||||
EXPECT_TRUE(result.has_value());
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <csignal>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#ifndef _WIN32
|
||||
@@ -10,6 +8,7 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "test/temp_dir.h"
|
||||
#include "command/argument_parser.h"
|
||||
#include "command/command.h"
|
||||
#include "eventide/async/async.h"
|
||||
@@ -47,31 +46,6 @@ inline std::string clice_binary() {
|
||||
return std::string(path);
|
||||
}
|
||||
|
||||
/// RAII temporary file: writes content to disk, removes on destruction.
|
||||
struct TempFile {
|
||||
std::string path;
|
||||
|
||||
TempFile(const std::string& name, const std::string& content) {
|
||||
llvm::SmallString<256> tmp_dir;
|
||||
llvm::sys::path::system_temp_directory(true, tmp_dir);
|
||||
llvm::sys::path::append(tmp_dir, "clice_test_" + name);
|
||||
path = std::string(tmp_dir);
|
||||
std::ofstream ofs(path);
|
||||
ofs << content;
|
||||
}
|
||||
|
||||
~TempFile() {
|
||||
std::remove(path.c_str());
|
||||
}
|
||||
|
||||
std::string uri() const {
|
||||
return "file://" + path;
|
||||
}
|
||||
|
||||
TempFile(const TempFile&) = delete;
|
||||
TempFile& operator=(const TempFile&) = delete;
|
||||
};
|
||||
|
||||
/// Build compile arguments for a source file, including -resource-dir.
|
||||
inline std::vector<std::string> make_args(const std::string& file_path,
|
||||
const std::string& extra = "") {
|
||||
|
||||
Reference in New Issue
Block a user