tsl-devkit/lsp-server/test/test_glaz.cpp

312 lines
9.1 KiB
C++

#include <iostream>
#include <vector>
#include "../src/protocol/protocol.hpp"
#include "../src/protocol/transform/facade.hpp"
using namespace lsp::protocol;
using namespace lsp;
template<typename T>
void print_json(const string& name, const T& obj)
{
if (auto result = glz::write_json(obj); result)
{
std::cout << name << " = " << *result << std::endl;
} else
{
std::cerr << "Error: " << result.error() << "\n";
}
}
void test_basic_conversion()
{
std::cout << "\n=== Testing Basic Conversion ===" << std::endl;
// 测试 struct 转换
RequestMessage msg;
msg.method = "textDocument/completion";
msg.id = 42;
// Struct -> LSPAny
LSPAny any = transform::LSPAny(msg);
std::string json;
auto ce = glz::write_json(any, json);
if(ce)
std::cout << "Error" << std::endl;
std::cout << "Message as JSON: " << json << std::endl;
// LSPAny -> Struct
RequestMessage restored = transform::As<RequestMessage>(any);
std::cout << "Restored method: " << restored.method << std::endl;
std::cout << "id = ";
std::visit([](const auto& value)
{
std::cout << value;
}, restored.id);
std::cout << std::endl;
}
void test_vector_conversion()
{
std::cout << "\n=== Testing Vector Conversion ===" << std::endl;
std::vector<Position> positions = {
{10, 5},
{20, 15},
{30, 25}
};
// Vector -> LSPAny
LSPAny any = transform::LSPAny(positions);
std::string json;
auto ce = glz::write_json(any, json);
std::cout << "Vector as JSON: " << json << std::endl;
// LSPAny -> Vector
auto restored = transform::As<std::vector<Position>>(any);
std::cout << "Restored " << restored.size() << " positions" << std::endl;
}
void test_json_string()
{
std::cout << "\n=== Test json_string ===" << std::endl;
string json = R"({"jsonrpc":"2.0","id":1,"method":"initialize","params":{"processId":null,"rootUri":"file:///tmp","workDoneToken":"abc"}})";
RequestMessage request;
auto ret = glz::read_json(request, json);
std::cout << "jsonrpc = " << request.jsonrpc << std::endl;
std::cout << "method = " << request.method << std::endl;
std::cout << "id = ";
std::visit([](const auto& value)
{
std::cout << value;
}, request.id);
std::cout << std::endl;
auto result = glz::write_json(request.params);
std::cout << *result << std::endl;
InitializeParams params;
// std::string buffer = R"({"workDoneToken":123,"processId":"id","clientInfo":{"name":"VSCode","version":"1.0.0"},"rootPath":"456","initializationOptions":"options","trace":"messages"})";
auto r2= glz::read_json(params, *result);
if (params.processId.has_value())
std::cout << "processId = " << params.processId.value() << "\n";
else
std::cout << "processId = null\n";
std::cout << "rootUri = " << params.rootUri.value() << std::endl;
std::cout << std::endl;
}
void test_basic_types()
{
std::cout << "\n=== Test basic_types.hpp ===" << std::endl;
Range range =
{
.start = {1, 3},
.end = {2, 4}
};
DocumentFilter df = {
.language = "en",
.scheme = "scheme",
.pattern = "pattern",
};
AnnotatedTextEdit ate;
ate.range = {.start = {1, 3}, .end = {2, 4}};
ate.newText = "text_edit";
ate.annotationId = "id";
Location location =
{
.uri = "location_uri",
.range = {.start = {1, 3}, .end = {2, 4}}
};
Command command1 =
{
.title = "command_title",
.command = "command_command",
};
Command command2 =
{
.title = "command_title",
.command = "command_command",
.arguments = "any_string"
};
Command command3 =
{
.title = "command_title",
.command = "command_command",
.arguments = 123
};
std::vector<LSPAny> array = {
1.0, // decimal
string("two"),
3.0, // decimal
true,
nullptr
};
LSPAny array_val = array;
LSPObject object = {
{"name", string("test object")},
{"count", 42.0}, // decimal
{"active", boolean(true)},
{"data", array_val},
{"metadata", nullptr}
};
Command command4 =
{
.title = "command_title",
.command = "command_command",
.arguments = object
};
MarkdownClientCapabilities mkcp =
{
.parser = "parse",
.allowedTags = std::vector<string>{"h1", "h2", "p", "code", "pre"}
};
std::cout << "Test....basic_types" << std::endl;
print_json("Range", range);
print_json("DocumentFilter", df);
print_json("AnnotatedTextEdit", ate);
print_json("Location", location);
print_json("Command1", command1);
print_json("Command2", command2);
print_json("Command3", command3);
print_json("Command4", command4);
print_json("MarkdownClientCapabilities", mkcp);
std::cout << std::endl;
}
void test_capabilities()
{
std::cout << "\n=== Test capabilities.hpp ===" << std::endl;
InitializeParams ip;
ip.workDoneToken = 123;
ip.processId = std::nullopt;
ip.clientInfo = InitializeParams::ClientInfo{"VSCode", "1.0.0"};
// ip.rootPath = "456";
ip.initializationOptions = "options";
ip.trace = TraceValueLiterals::Messages;
std::cout << "Test....capabilities" << std::endl;
print_json("InitializeParams", ip);
std::cout << std::endl;
}
void test_RequestMessage_serialize()
{
// // 1. 直接从 LSPObject 转换
// lsp::protocol::LSPObject obj = [> ... <];
// auto result = lsp::transform::As<CompletionParams>(obj);
// // 2. 从 variant 转换
// std::variant<lsp::protocol::LSPArray, lsp::protocol::LSPObject> var = [> ... <];
// auto result = lsp::transform::As<CompletionParams>(var);
// // 3. 从 optional 转换
// std::optional<lsp::protocol::LSPObject> opt = [> ... <];
// auto result = lsp::transform::As<CompletionParams>(opt); // 返回 optional<CompletionParams>
// // 4. 从复杂的嵌套类型转换
// std::optional<std::variant<lsp::protocol::LSPArray, lsp::protocol::LSPObject>> complex = [> ... <];
// auto result = lsp::transform::As<CompletionParams>(complex); // 返回 optional<CompletionParams>
// // 5. 实际使用场景
// if (request.params.has_value()) {
// // 直接处理 optional<variant<LSPArray, LSPObject>>
// auto completionParams = lsp::transform::As<lsp::protocol::CompletionParams>(request.params);
// if (completionParams.has_value()) {
// std::cout << "URI: " << completionParams->textDocument.uri << std::endl;
// }
// }
std::string json = R"({
"jsonrpc":"2.0",
"id":"4",
"method":"textDocument/completion",
"params":{
"context":{"triggerKind":1},
"partialResultToken":0,
"position":{"character":12,"line":22},
"textDocument":{"uri":"file://path/to_file.ts"},
"workDoneToken":0
}
})";
RequestMessage request;
auto error = glz::read_json(request, json);
if (error) {
std::cerr << "Failed to parse JSON: " << glz::format_error(error, json) << std::endl;
}
std::cout << "jsonrpc: " << request.jsonrpc << std::endl;
std::cout << "method: " << request.method << std::endl;
std::visit([](const auto& id)
{
using T = std::decay_t<decltype(id)>;
if constexpr (std::is_same_v<T, lsp::protocol::string>) {
std::cout << "ID (string): " << id << std::endl;
} else if constexpr (std::is_same_v<T, lsp::protocol::integer>) {
std::cout << "ID (integer): " << id << std::endl;
}
}, request.id);
auto completionParams = transform::As<CompletionParams>(request.params.value());
std::cout << "URI: " << completionParams.textDocument.uri << std::endl;
// std::visit([](const auto& value)
// {
// std::cout << value;
// }, request.id);
// std::visit([](const auto& params) {
// }, request.params.value());
}
void test_message()
{
std::cout << "\n=== Test message.hpp ===" << std::endl;
ResponseMessage response;
response.id = "123";
InitializeResult result;
result.serverInfo.name = "TSL Language Server";
result.serverInfo.version = "1.0.0";
TextDocumentSyncOptions opts;
opts.openClose = true;
opts.change = TextDocumentSyncKind::kIncremental;
result.capabilities.textDocumentSync = opts;
CompletionParams comparams;
comparams.textDocument.uri = "file://path/to_file.ts";
comparams.position.character = 12;
comparams.position.line = 22;
comparams.context = CompletionContext{
.triggerKind = CompletionTriggerKind::kInvoked,
.triggerCharacter = std::nullopt
};
RequestMessage rm;
rm.id = "4";
rm.method = "textDocument/completion";
rm.params = transform::LSPObject(comparams);
print_json("ResponseMessage", response);
print_json("rm", rm);
}
int main()
{
// test_basic_conversion();
// test_vector_conversion();
// test_json_string();
// test_basic_types();
// test_capabilities();
test_message();
test_RequestMessage_serialize();
return 0;
}