🗑️ 移除`test_glaz`

 新增测试`test_lsp_any`
This commit is contained in:
csh 2025-11-02 15:47:48 +08:00
parent a81d9de71d
commit 64ec88f0c3
14 changed files with 2592 additions and 1156 deletions

View File

@ -1,308 +0,0 @@
#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 << 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::Incremental;
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::Invoked,
.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;
}

View File

@ -1,848 +0,0 @@
#include <glaze/glaze.hpp>
#include <variant>
#include <map>
#include <vector>
#include <string>
#include <cstdint>
#include <optional>
#include <type_traits>
using integer = std::int32_t;
using uinteger = std::uint32_t;
using decimal = double;
using boolean = bool;
using string = std::string;
// 前向声明
struct LSPAny;
using LSPObject = std::map<string, LSPAny>;
using LSPArray = std::vector<LSPAny>;
using LSPAnyVariant = std::variant<
LSPObject,
LSPArray,
string,
decimal, // 放在前面,优先匹配数字
boolean,
std::nullptr_t>;
struct LSPAny
{
LSPAnyVariant value;
// 默认构造函数
LSPAny() :
value(nullptr) {}
// 拷贝和移动构造函数
LSPAny(const LSPAny& other) :
value(other.value) {}
LSPAny(LSPAny&& other) noexcept :
value(std::move(other.value)) {}
// 针对每种支持的类型的构造函数
LSPAny(const std::map<string, LSPAny>& val) :
value(val) {}
LSPAny(std::map<string, LSPAny>&& val) :
value(std::move(val)) {}
LSPAny(const std::vector<LSPAny>& val) :
value(val) {}
LSPAny(std::vector<LSPAny>&& val) :
value(std::move(val)) {}
LSPAny(const string& val) :
value(val) {}
LSPAny(string&& val) :
value(std::move(val)) {}
LSPAny(const char* val) :
value(string(val)) {}
// 所有数字类型都转换为 decimal
LSPAny(int val) :
value(static_cast<decimal>(val)) {}
LSPAny(long val) :
value(static_cast<decimal>(val)) {}
LSPAny(long long val) :
value(static_cast<decimal>(val)) {}
LSPAny(unsigned int val) :
value(static_cast<decimal>(val)) {}
LSPAny(unsigned long val) :
value(static_cast<decimal>(val)) {}
LSPAny(unsigned long long val) :
value(static_cast<decimal>(val)) {}
LSPAny(float val) :
value(static_cast<decimal>(val)) {}
LSPAny(double val) :
value(val) {}
LSPAny(long double val) :
value(static_cast<decimal>(val)) {}
LSPAny(boolean val) :
value(val) {}
LSPAny(std::nullptr_t) :
value(nullptr) {}
// 赋值操作符
LSPAny& operator=(const LSPAny& other)
{
value = other.value;
return *this;
}
LSPAny& operator=(LSPAny&& other) noexcept
{
value = std::move(other.value);
return *this;
}
// 针对每种支持的类型的赋值操作符
LSPAny& operator=(const std::map<string, LSPAny>& val)
{
value = val;
return *this;
}
LSPAny& operator=(std::map<string, LSPAny>&& val)
{
value = std::move(val);
return *this;
}
LSPAny& operator=(const std::vector<LSPAny>& val)
{
value = val;
return *this;
}
LSPAny& operator=(std::vector<LSPAny>&& val)
{
value = std::move(val);
return *this;
}
LSPAny& operator=(const string& val)
{
value = val;
return *this;
}
LSPAny& operator=(string&& val)
{
value = std::move(val);
return *this;
}
LSPAny& operator=(const char* val)
{
value = string(val);
return *this;
}
// 所有数字类型都转换为 decimal
LSPAny& operator=(int val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(long val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(long long val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(unsigned int val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(unsigned long val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(unsigned long long val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(float val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(double val)
{
value = val;
return *this;
}
LSPAny& operator=(long double val)
{
value = static_cast<decimal>(val);
return *this;
}
LSPAny& operator=(boolean val)
{
value = val;
return *this;
}
LSPAny& operator=(std::nullptr_t)
{
value = nullptr;
return *this;
}
// 类型检查辅助函数
template<typename T>
bool is() const
{
return std::holds_alternative<T>(value);
}
template<typename T>
T& get()
{
return std::get<T>(value);
}
template<typename T>
const T& get() const
{
return std::get<T>(value);
}
// 访问操作符
template<typename Visitor>
auto visit(Visitor&& visitor) const
{
return std::visit(std::forward<Visitor>(visitor), value);
}
template<typename Visitor>
auto visit(Visitor&& visitor)
{
return std::visit(std::forward<Visitor>(visitor), value);
}
};
// glaze 自动支持 std::variant无需额外配置
namespace glz
{
template<>
struct meta<LSPAny>
{
using T = LSPAny;
static constexpr auto value = &T::value;
};
}
// ===== 简单清晰的转换模板 =====
// 转换工具类
struct LSPConvert
{
// === 基本类型的转换(优先级最高) ===
// boolean
static LSPAny ToLSPAny(boolean value)
{
return LSPAny(value);
}
// 整数类型
static LSPAny ToLSPAny(int value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(long value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(long long value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(unsigned int value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(unsigned long value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(unsigned long long value)
{
return LSPAny(value);
}
// 浮点类型
static LSPAny ToLSPAny(float value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(double value)
{
return LSPAny(value);
}
static LSPAny ToLSPAny(long double value)
{
return LSPAny(value);
}
// string
static LSPAny ToLSPAny(const string& str)
{
return LSPAny(str);
}
static LSPAny ToLSPAny(const char* str)
{
return LSPAny(str);
}
// nullptr
static LSPAny ToLSPAny(std::nullptr_t)
{
return LSPAny(nullptr);
}
// LSPAny 自身
static LSPAny ToLSPAny(const LSPAny& any)
{
return any;
}
// === 容器类型的转换 ===
// vector
template<typename T>
static LSPAny ToLSPAny(const std::vector<T>& vec)
{
LSPArray arr;
arr.reserve(vec.size());
for (const auto& item : vec)
{
arr.push_back(ToLSPAny(item));
}
return LSPAny(std::move(arr));
}
// map
template<typename T>
static LSPAny ToLSPAny(const std::map<string, T>& map)
{
LSPObject obj;
for (const auto& [key, value] : map)
{
obj[key] = ToLSPAny(value);
}
return LSPAny(std::move(obj));
}
// optional
template<typename T>
static LSPAny ToLSPAny(const std::optional<T>& opt)
{
if (opt.has_value())
{
return ToLSPAny(*opt);
}
return LSPAny(nullptr);
}
// === Struct 到 LSPAny 的转换(最低优先级) ===
template<typename T>
static typename std::enable_if<
!std::is_arithmetic<T>::value &&
!std::is_same<T, string>::value &&
!std::is_same<T, const char*>::value &&
!std::is_same<T, std::nullptr_t>::value &&
!std::is_same<T, LSPAny>::value,
LSPAny>::type
ToLSPAny(const T& obj)
{
// 序列化为 JSON 字符串
std::string json;
auto ec = glz::write_json(obj, json);
if (ec)
{
throw std::runtime_error("Failed to serialize to JSON");
}
// 直接解析为 LSPAny
LSPAny result;
ec = glz::read_json(result, json);
if (ec)
{
throw std::runtime_error("Failed to parse JSON to LSPAny");
}
return result;
}
// === LSPAny 到基本类型的转换 ===
// boolean
static boolean BoolFromLSPAny(const LSPAny& any)
{
if (!any.is<boolean>())
{
throw std::runtime_error("LSPAny is not a boolean");
}
return any.get<boolean>();
}
// 数字类型
template<typename T>
static typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, boolean>::value, T>::type
NumberFromLSPAny(const LSPAny& any)
{
if (!any.is<decimal>())
{
throw std::runtime_error("LSPAny is not a number");
}
return static_cast<T>(any.get<decimal>());
}
// string
static string StringFromLSPAny(const LSPAny& any)
{
if (!any.is<string>())
{
throw std::runtime_error("LSPAny is not a string");
}
return any.get<string>();
}
// === LSPAny 到容器类型的转换 ===
// vector
template<typename T>
static std::vector<T> VectorFromLSPAny(const LSPAny& any)
{
if (!any.is<LSPArray>())
{
throw std::runtime_error("LSPAny is not an array");
}
const auto& arr = any.get<LSPArray>();
std::vector<T> result;
result.reserve(arr.size());
for (const auto& item : arr)
{
result.push_back(FromLSPAny<T>(item));
}
return result;
}
// optional
template<typename T>
static std::optional<T> OptionalFromLSPAny(const LSPAny& any)
{
if (any.is<std::nullptr_t>())
{
return std::nullopt;
}
return FromLSPAny<T>(any);
}
// === LSPAny 到 Struct 的转换 ===
template<typename T>
static T FromLSPAny(const LSPAny& any)
{
return FromLSPAnyImpl<T>(any);
}
private:
// 内部实现,使用重载来处理不同类型
// boolean
static boolean FromLSPAnyImpl(const LSPAny& any, boolean*)
{
return BoolFromLSPAny(any);
}
// string
static string FromLSPAnyImpl(const LSPAny& any, string*)
{
return StringFromLSPAny(any);
}
// 数字类型
template<typename T>
static typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, boolean>::value, T>::type
FromLSPAnyImpl(const LSPAny& any, T*)
{
return NumberFromLSPAny<T>(any);
}
// LSPAny 自身
static LSPAny FromLSPAnyImpl(const LSPAny& any, LSPAny*)
{
return any;
}
// struct 类型
template<typename T>
static typename std::enable_if<
!std::is_arithmetic<T>::value &&
!std::is_same<T, string>::value &&
!std::is_same<T, LSPAny>::value,
T>::type
FromLSPAnyImpl(const LSPAny& any, T*)
{
// 序列化 LSPAny 为 JSON
std::string json;
auto ec = glz::write_json(any.value, json);
if (ec)
{
throw std::runtime_error("Failed to serialize LSPAny to JSON");
}
// 解析 JSON 到目标类型
T result;
ec = glz::read_json(result, json);
if (ec)
{
throw std::runtime_error("Failed to parse JSON to target type");
}
return result;
}
// 通过指针类型来分派
template<typename T>
static T FromLSPAnyImpl(const LSPAny& any)
{
return FromLSPAnyImpl(any, static_cast<T*>(nullptr));
}
};
// ===== 便利函数(可选) =====
// 基本类型的便利函数
inline LSPAny ToLSPAny(boolean value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(int value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(long value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(long long value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(unsigned int value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(unsigned long value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(unsigned long long value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(float value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(double value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(long double value) { return LSPConvert::ToLSPAny(value); }
inline LSPAny ToLSPAny(const string& str) { return LSPConvert::ToLSPAny(str); }
inline LSPAny ToLSPAny(const char* str) { return LSPConvert::ToLSPAny(str); }
inline LSPAny ToLSPAny(std::nullptr_t) { return LSPConvert::ToLSPAny(nullptr); }
inline LSPAny ToLSPAny(const LSPAny& any) { return LSPConvert::ToLSPAny(any); }
// 容器类型的便利函数
template<typename T>
LSPAny ToLSPAny(const std::vector<T>& vec)
{
return LSPConvert::ToLSPAny(vec);
}
template<typename T>
LSPAny ToLSPAny(const std::map<string, T>& map)
{
return LSPConvert::ToLSPAny(map);
}
template<typename T>
LSPAny ToLSPAny(const std::optional<T>& opt)
{
return LSPConvert::ToLSPAny(opt);
}
// struct 类型的便利函数
template<typename T>
typename std::enable_if<
!std::is_arithmetic<T>::value &&
!std::is_same<T, string>::value &&
!std::is_same<T, const char*>::value &&
!std::is_same<T, std::nullptr_t>::value &&
!std::is_same<T, LSPAny>::value,
LSPAny>::type
ToLSPAny(const T& value)
{
return LSPConvert::ToLSPAny(value);
}
// FromLSPAny 便利函数
template<typename T>
T FromLSPAny(const LSPAny& any)
{
return LSPConvert::FromLSPAny<T>(any);
}
// ===== 测试代码 =====
// 测试用的结构体
struct Message
{
string jsonrpc = "2.0";
string method;
int id = 0;
};
struct Position
{
int line;
int character;
};
struct Range
{
Position start;
Position end;
};
struct TextDocumentIdentifier
{
string uri;
};
struct TextDocumentPositionParams
{
TextDocumentIdentifier textDocument;
Position position;
};
struct CompletionItem
{
string label;
std::optional<int> kind;
std::optional<string> detail;
std::optional<string> documentation;
std::optional<boolean> deprecated;
std::optional<boolean> preselect;
std::optional<string> sortText;
std::optional<string> filterText;
std::optional<string> insertText;
};
// 为测试结构体提供 glaze 元数据
template<>
struct glz::meta<Message>
{
using T = Message;
static constexpr auto value = object(
"jsonrpc",
&T::jsonrpc,
"method",
&T::method,
"id",
&T::id);
};
template<>
struct glz::meta<Position>
{
using T = Position;
static constexpr auto value = object(
"line",
&T::line,
"character",
&T::character);
};
template<>
struct glz::meta<Range>
{
using T = Range;
static constexpr auto value = object(
"start",
&T::start,
"end",
&T::end);
};
template<>
struct glz::meta<TextDocumentIdentifier>
{
using T = TextDocumentIdentifier;
static constexpr auto value = object(
"uri",
&T::uri);
};
template<>
struct glz::meta<TextDocumentPositionParams>
{
using T = TextDocumentPositionParams;
static constexpr auto value = object(
"textDocument",
&T::textDocument,
"position",
&T::position);
};
template<>
struct glz::meta<CompletionItem>
{
using T = CompletionItem;
static constexpr auto value = object(
"label",
&T::label,
"kind",
&T::kind,
"detail",
&T::detail,
"documentation",
&T::documentation,
"deprecated",
&T::deprecated,
"preselect",
&T::preselect,
"sortText",
&T::sortText,
"filterText",
&T::filterText,
"insertText",
&T::insertText);
};
// 测试函数
#include <iostream>
void test_basic_conversion()
{
std::cout << "=== Testing Basic Conversion ===" << std::endl;
// 测试 struct 转换
Message msg;
msg.method = "textDocument/completion";
msg.id = 42;
// Struct -> LSPAny
LSPAny any = ToLSPAny(msg);
// 序列化查看
std::string json;
glz::write_json(any, json);
std::cout << "Message as JSON: " << json << std::endl;
// LSPAny -> Struct
Message restored = FromLSPAny<Message>(any);
std::cout << "Restored method: " << restored.method << std::endl;
std::cout << "Restored id: " << restored.id << 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 = ToLSPAny(positions);
std::string json;
glz::write_json(any, json);
std::cout << "Vector as JSON: " << json << std::endl;
// LSPAny -> Vector
auto restored = LSPConvert::VectorFromLSPAny<Position>(any);
std::cout << "Restored " << restored.size() << " positions" << std::endl;
}
void test_optional_conversion()
{
std::cout << "\n=== Testing Optional Conversion ===" << std::endl;
CompletionItem item;
item.label = "std::vector";
item.kind = 1;
item.detail = "template<typename T> class vector";
LSPAny any = ToLSPAny(item);
std::string json;
glz::write_json(any, json);
std::cout << "CompletionItem as JSON: " << json << std::endl;
// 测试 null optional
std::optional<string> empty_opt;
LSPAny null_any = ToLSPAny(empty_opt);
glz::write_json(null_any, json);
std::cout << "Empty optional as JSON: " << json << std::endl;
}
void test_mixed_usage()
{
std::cout << "\n=== Testing Mixed Usage ===" << std::endl;
// 创建复杂对象
LSPObject obj;
obj["message"] = ToLSPAny(Message{ "2.0", "test/method", 123 });
obj["position"] = ToLSPAny(Position{ 10, 20 });
obj["numbers"] = ToLSPAny(std::vector<int>{ 1, 2, 3 });
obj["flag"] = LSPAny(true);
obj["value"] = LSPAny(3.14);
obj["text"] = LSPAny("Hello LSP");
obj["empty"] = LSPAny(nullptr);
LSPAny root(obj);
std::string json;
glz::write_json(root, json);
std::cout << "Complex object: " << json << std::endl;
// 提取值
if (root.is<LSPObject>())
{
auto& root_obj = root.get<LSPObject>();
Message msg = FromLSPAny<Message>(root_obj["message"]);
std::cout << "Extracted message method: " << msg.method << std::endl;
Position pos = FromLSPAny<Position>(root_obj["position"]);
std::cout << "Extracted position: " << pos.line << ", " << pos.character << std::endl;
}
}
int main()
{
try
{
test_basic_conversion();
test_vector_conversion();
test_optional_conversion();
test_mixed_usage();
std::cout << "\nAll tests completed!" << std::endl;
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
return 1;
}
return 0;
}

View File

@ -0,0 +1,72 @@
cmake_minimum_required(VERSION 4.0)
project(test_lsp_any)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
message(STATUS "CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
if (DEFINED CMAKE_TOOLCHAIN_FILE)
message(STATUS ">>> CMAKE_TOOLCHAIN_FILE: ${CMAKE_TOOLCHAIN_FILE}")
endif()
if (DEFINED VCPKG_TARGET_TRIPLET)
message(STATUS ">>> VCPKG_TARGET_TRIPLET: ${VCPKG_TARGET_TRIPLET}")
endif()
#
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE
"Release"
CACHE STRING "Build type" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()
# MinGW/MSYS2
if(MINGW)
add_link_options(-static -static-libgcc -static-libstdc++)
elseif(UNIX AND NOT APPLE) # Linux
add_link_options(-static-libgcc -static-libstdc++)
endif()
if(WIN32)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".lib" ".dll.a")
else()
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".so")
endif()
find_package(glaze CONFIG REQUIRED)
if(UNIX AND NOT APPLE)
find_package(Threads REQUIRED)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
set(SOURCES
./common_test.cpp
./facade_test.cpp
./lsp_any_test.cpp
./test_framework.cpp
./test_main.cpp
./transformer_test.cpp
)
add_executable(${PROJECT_NAME} ${SOURCES})
target_include_directories(${PROJECT_NAME} PRIVATE src)
target_link_libraries(${PROJECT_NAME} PRIVATE
glaze::glaze
$<$<PLATFORM_ID:Linux>:Threads::Threads> # 使
)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(${PROJECT_NAME} PRIVATE
-Wall -Wextra -Wpedantic
$<$<CONFIG:Debug>:-g -O0>
$<$<CONFIG:Release>:-O3>
)
endif()

View File

@ -0,0 +1,325 @@
#include "common_test.hpp"
#include <vector>
#include <map>
#include <optional>
#include <variant>
#include "../../src/protocol/transform/common.hpp"
#include "../../src/protocol/detail/basic_types.hpp"
namespace lsp::test
{
// 用于测试的用户自定义结构体
struct UserStruct
{
int value;
std::string name;
};
void CommonTests::registerTests(TestRunner& runner)
{
// is_lsp_basic_type 测试
runner.addTest("Common - is_lsp_basic_type (integer)", testIsLSPBasicInteger);
runner.addTest("Common - is_lsp_basic_type (uinteger)", testIsLSPBasicUInteger);
runner.addTest("Common - is_lsp_basic_type (boolean)", testIsLSPBasicBoolean);
runner.addTest("Common - is_lsp_basic_type (string)", testIsLSPBasicString);
runner.addTest("Common - is_lsp_basic_type (decimal)", testIsLSPBasicDecimal);
runner.addTest("Common - is_lsp_basic_type (nullptr_t)", testIsLSPBasicNullptr);
runner.addTest("Common - is_lsp_basic_type (负面案例)", testIsLSPBasicNegativeCases);
// is_lsp_container_type 测试
runner.addTest("Common - is_lsp_container_type (LSPObject)", testIsLSPContainerObject);
runner.addTest("Common - is_lsp_container_type (LSPArray)", testIsLSPContainerArray);
runner.addTest("Common - is_lsp_container_type (LSPAny)", testIsLSPContainerAny);
runner.addTest("Common - is_lsp_container_type (负面案例)", testIsLSPContainerNegativeCases);
// is_user_struct 测试
runner.addTest("Common - is_user_struct (用户结构体)", testIsUserStructPositive);
runner.addTest("Common - is_user_struct (排除算术类型)", testIsUserStructExcludeArithmetic);
runner.addTest("Common - is_user_struct (排除字符串)", testIsUserStructExcludeString);
runner.addTest("Common - is_user_struct (排除LSP类型)", testIsUserStructExcludeLSPTypes);
runner.addTest("Common - is_user_struct (排除vector)", testIsUserStructExcludeVector);
runner.addTest("Common - is_user_struct (排除map)", testIsUserStructExcludeMap);
runner.addTest("Common - is_user_struct (排除optional)", testIsUserStructExcludeOptional);
runner.addTest("Common - is_user_struct (排除variant)", testIsUserStructExcludeVariant);
runner.addTest("Common - is_user_struct (排除指针)", testIsUserStructExcludePointers);
}
// ==================== is_lsp_basic_type 测试 ====================
TestResult CommonTests::testIsLSPBasicInteger()
{
TestResult result;
result.passed = true;
bool is_basic = transform::is_lsp_basic_type_v<protocol::integer>;
assertTrue(is_basic, "integer应该是LSP基本类型");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsLSPBasicUInteger()
{
TestResult result;
result.passed = true;
bool is_basic = transform::is_lsp_basic_type_v<protocol::uinteger>;
assertTrue(is_basic, "uinteger应该是LSP基本类型");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsLSPBasicBoolean()
{
TestResult result;
result.passed = true;
bool is_basic = transform::is_lsp_basic_type_v<protocol::boolean>;
assertTrue(is_basic, "boolean应该是LSP基本类型");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsLSPBasicString()
{
TestResult result;
result.passed = true;
bool is_basic = transform::is_lsp_basic_type_v<protocol::string>;
assertTrue(is_basic, "string应该是LSP基本类型");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsLSPBasicDecimal()
{
TestResult result;
result.passed = true;
bool is_basic = transform::is_lsp_basic_type_v<protocol::decimal>;
assertTrue(is_basic, "decimal应该是LSP基本类型");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsLSPBasicNullptr()
{
TestResult result;
result.passed = true;
bool is_basic = transform::is_lsp_basic_type_v<std::nullptr_t>;
assertTrue(is_basic, "nullptr_t应该是LSP基本类型");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsLSPBasicNegativeCases()
{
TestResult result;
result.passed = true;
// 测试明确不是 LSP 基本类型的类型
// 注意:避免测试 int/int32_t因为它们可能等于 protocol::integer
assertFalse(transform::is_lsp_basic_type_v<int64_t>,
"int64_t不应该是LSP基本类型");
assertFalse(transform::is_lsp_basic_type_v<long long>,
"long long不应该是LSP基本类型");
assertFalse(transform::is_lsp_basic_type_v<float>,
"float不应该是LSP基本类型");
assertFalse(transform::is_lsp_basic_type_v<std::vector<int>>,
"vector不应该是LSP基本类型");
assertFalse(transform::is_lsp_basic_type_v<UserStruct>,
"UserStruct不应该是LSP基本类型");
result.message = "成功";
return result;
}
// ==================== is_lsp_container_type 测试 ====================
TestResult CommonTests::testIsLSPContainerObject()
{
TestResult result;
result.passed = true;
bool is_container = transform::is_lsp_container_type_v<protocol::LSPObject>;
assertTrue(is_container, "LSPObject应该是LSP容器类型");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsLSPContainerArray()
{
TestResult result;
result.passed = true;
bool is_container = transform::is_lsp_container_type_v<protocol::LSPArray>;
assertTrue(is_container, "LSPArray应该是LSP容器类型");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsLSPContainerAny()
{
TestResult result;
result.passed = true;
bool is_container = transform::is_lsp_container_type_v<protocol::LSPAny>;
assertTrue(is_container, "LSPAny应该是LSP容器类型");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsLSPContainerNegativeCases()
{
TestResult result;
result.passed = true;
assertFalse(transform::is_lsp_container_type_v<int>,
"int不应该是LSP容器");
assertFalse(transform::is_lsp_container_type_v<std::string>,
"string不应该是LSP容器");
assertFalse(transform::is_lsp_container_type_v<std::vector<int>>,
"std::vector不应该是LSP容器");
result.message = "成功";
return result;
}
// ==================== is_user_struct 测试 ====================
TestResult CommonTests::testIsUserStructPositive()
{
TestResult result;
result.passed = true;
bool is_user = transform::is_user_struct_v<UserStruct>;
assertTrue(is_user, "UserStruct应该被识别为用户结构体");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsUserStructExcludeArithmetic()
{
TestResult result;
result.passed = true;
assertFalse(transform::is_user_struct_v<int>,
"int不应该是用户结构体");
assertFalse(transform::is_user_struct_v<double>,
"double不应该是用户结构体");
assertFalse(transform::is_user_struct_v<bool>,
"bool不应该是用户结构体");
assertFalse(transform::is_user_struct_v<char>,
"char不应该是用户结构体");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsUserStructExcludeString()
{
TestResult result;
result.passed = true;
assertFalse(transform::is_user_struct_v<std::string>,
"std::string不应该是用户结构体");
assertFalse(transform::is_user_struct_v<protocol::string>,
"protocol::string不应该是用户结构体");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsUserStructExcludeLSPTypes()
{
TestResult result;
result.passed = true;
assertFalse(transform::is_user_struct_v<protocol::LSPObject>,
"LSPObject不应该是用户结构体");
assertFalse(transform::is_user_struct_v<protocol::LSPArray>,
"LSPArray不应该是用户结构体");
assertFalse(transform::is_user_struct_v<protocol::LSPAny>,
"LSPAny不应该是用户结构体");
assertFalse(transform::is_user_struct_v<protocol::integer>,
"protocol::integer不应该是用户结构体");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsUserStructExcludeVector()
{
TestResult result;
result.passed = true;
bool is_user = transform::is_user_struct_v<std::vector<int>>;
assertFalse(is_user, "std::vector不应该是用户结构体");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsUserStructExcludeMap()
{
TestResult result;
result.passed = true;
bool is_user = transform::is_user_struct_v<std::map<std::string, int>>;
assertFalse(is_user, "std::map不应该是用户结构体");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsUserStructExcludeOptional()
{
TestResult result;
result.passed = true;
bool is_user = transform::is_user_struct_v<std::optional<int>>;
assertFalse(is_user, "std::optional不应该是用户结构体");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsUserStructExcludeVariant()
{
TestResult result;
result.passed = true;
bool is_user = transform::is_user_struct_v<std::variant<int, std::string>>;
assertFalse(is_user, "std::variant不应该是用户结构体");
result.message = "成功";
return result;
}
TestResult CommonTests::testIsUserStructExcludePointers()
{
TestResult result;
result.passed = true;
assertFalse(transform::is_user_struct_v<int*>,
"int*不应该是用户结构体");
assertFalse(transform::is_user_struct_v<const char*>,
"const char*不应该是用户结构体");
assertFalse(transform::is_user_struct_v<UserStruct*>,
"UserStruct*不应该是用户结构体");
result.message = "成功";
return result;
}
} // namespace lsp::test

View File

@ -0,0 +1,39 @@
#pragma once
#include "test_framework.hpp"
namespace lsp::test
{
// Common 类型特征测试类
class CommonTests
{
public:
static void registerTests(TestRunner& runner);
private:
// ==================== is_lsp_basic_type 测试 ====================
static TestResult testIsLSPBasicInteger();
static TestResult testIsLSPBasicUInteger();
static TestResult testIsLSPBasicBoolean();
static TestResult testIsLSPBasicString();
static TestResult testIsLSPBasicDecimal();
static TestResult testIsLSPBasicNullptr();
static TestResult testIsLSPBasicNegativeCases();
// ==================== is_lsp_container_type 测试 ====================
static TestResult testIsLSPContainerObject();
static TestResult testIsLSPContainerArray();
static TestResult testIsLSPContainerAny();
static TestResult testIsLSPContainerNegativeCases();
// ==================== is_user_struct 测试 ====================
static TestResult testIsUserStructPositive();
static TestResult testIsUserStructExcludeArithmetic();
static TestResult testIsUserStructExcludeString();
static TestResult testIsUserStructExcludeLSPTypes();
static TestResult testIsUserStructExcludeVector();
static TestResult testIsUserStructExcludeMap();
static TestResult testIsUserStructExcludeOptional();
static TestResult testIsUserStructExcludeVariant();
static TestResult testIsUserStructExcludePointers();
};
}

View File

@ -0,0 +1,389 @@
#include <glaze/glaze.hpp>
#include "facade_test.hpp"
#include "../../src/protocol/transform/facade.hpp"
#include "../../src/protocol/detail/basic_types.hpp"
namespace lsp::test
{
// 测试用结构体
struct TestPerson
{
std::string name;
int age;
};
struct TestConfig
{
std::string version;
bool enabled;
std::vector<int> ports;
};
}
// Glaze 元数据
template<>
struct glz::meta<lsp::test::TestPerson>
{
using T = lsp::test::TestPerson;
static constexpr auto value = object(
"name", &T::name,
"age", &T::age
);
};
template<>
struct glz::meta<lsp::test::TestConfig>
{
using T = lsp::test::TestConfig;
static constexpr auto value = object(
"version", &T::version,
"enabled", &T::enabled,
"ports", &T::ports
);
};
namespace lsp::test
{
void FacadeTests::registerTests(TestRunner& runner)
{
// Serialize/Deserialize 测试
runner.addTest("Facade - 序列化简单结构体", testSerializeSimpleStruct);
runner.addTest("Facade - 序列化复杂结构体", testSerializeComplexStruct);
runner.addTest("Facade - 序列化LSPAny", testSerializeLSPAny);
runner.addTest("Facade - 反序列化简单结构体", testDeserializeSimpleStruct);
runner.addTest("Facade - 反序列化复杂结构体", testDeserializeComplexStruct);
runner.addTest("Facade - 反序列化无效JSON", testDeserializeInvalidJSON);
runner.addTest("Facade - 序列化反序列化往返", testSerializeDeserializeRoundtrip);
// check 命名空间测试
runner.addTest("Facade - Check IsObject", testCheckIsObject);
runner.addTest("Facade - Check IsArray", testCheckIsArray);
runner.addTest("Facade - Check IsString", testCheckIsString);
runner.addTest("Facade - Check IsNumber", testCheckIsNumber);
runner.addTest("Facade - Check IsBool", testCheckIsBool);
runner.addTest("Facade - Check IsNull", testCheckIsNull);
runner.addTest("Facade - Check 多类型检查", testCheckMultipleTypes);
// debug 命名空间测试
runner.addTest("Facade - Debug GetTypeName", testDebugGetTypeName);
runner.addTest("Facade - Debug GetIdString (int)", testDebugGetIdStringInt);
runner.addTest("Facade - Debug GetIdString (string)", testDebugGetIdStringString);
}
// ==================== Serialize/Deserialize 测试 ====================
TestResult FacadeTests::testSerializeSimpleStruct()
{
TestResult result;
result.passed = true;
TestPerson person{"Alice", 30};
auto json_opt = transform::Serialize(person);
assertTrue(json_opt.has_value(), "序列化应该成功");
const auto& json = json_opt.value();
assertTrue(json.find("Alice") != std::string::npos, "JSON应该包含'Alice'");
assertTrue(json.find("30") != std::string::npos, "JSON应该包含'30'");
result.message = "成功";
return result;
}
TestResult FacadeTests::testSerializeComplexStruct()
{
TestResult result;
result.passed = true;
TestConfig config{"1.0.0", true, {8080, 8081, 8082}};
auto json_opt = transform::Serialize(config);
assertTrue(json_opt.has_value(), "序列化应该成功");
const auto& json = json_opt.value();
assertTrue(json.find("1.0.0") != std::string::npos, "JSON应该包含版本号");
assertTrue(json.find("true") != std::string::npos, "JSON应该包含enabled");
assertTrue(json.find("8080") != std::string::npos, "JSON应该包含端口");
result.message = "成功";
return result;
}
TestResult FacadeTests::testSerializeLSPAny()
{
TestResult result;
result.passed = true;
protocol::LSPObject obj;
obj["key"] = protocol::LSPAny(42);
obj["name"] = protocol::LSPAny("test");
protocol::LSPAny any(obj);
auto json_opt = transform::Serialize(any);
assertTrue(json_opt.has_value(), "序列化LSPAny应该成功");
result.message = "成功";
return result;
}
TestResult FacadeTests::testDeserializeSimpleStruct()
{
TestResult result;
result.passed = true;
std::string json = R"({"name":"Bob","age":25})";
auto person_opt = transform::Deserialize<TestPerson>(json);
assertTrue(person_opt.has_value(), "反序列化应该成功");
const auto& person = person_opt.value();
assertEqual(std::string("Bob"), person.name, "名字应该为'Bob'");
assertEqual(25, person.age, "年龄应该为25");
result.message = "成功";
return result;
}
TestResult FacadeTests::testDeserializeComplexStruct()
{
TestResult result;
result.passed = true;
std::string json = R"({"version":"2.0.0","enabled":false,"ports":[9000,9001,9002]})";
auto config_opt = transform::Deserialize<TestConfig>(json);
assertTrue(config_opt.has_value(), "反序列化应该成功");
const auto& config = config_opt.value();
assertEqual(std::string("2.0.0"), config.version, "版本应该为'2.0.0'");
assertEqual(false, config.enabled, "enabled应该为false");
assertEqual(size_t(3), config.ports.size(), "应该有3个端口");
assertEqual(9000, config.ports[0], "第一个端口应该为9000");
result.message = "成功";
return result;
}
TestResult FacadeTests::testDeserializeInvalidJSON()
{
TestResult result;
result.passed = true;
std::string json = R"({"invalid json syntax)";
auto person_opt = transform::Deserialize<TestPerson>(json);
assertFalse(person_opt.has_value(), "反序列化无效JSON应该失败");
result.message = "成功";
return result;
}
TestResult FacadeTests::testSerializeDeserializeRoundtrip()
{
TestResult result;
result.passed = true;
TestPerson original{"Charlie", 35};
auto json_opt = transform::Serialize(original);
assertTrue(json_opt.has_value(), "序列化应该成功");
auto person_opt = transform::Deserialize<TestPerson>(json_opt.value());
assertTrue(person_opt.has_value(), "反序列化应该成功");
const auto& restored = person_opt.value();
assertEqual(original.name, restored.name, "名字应该保持一致");
assertEqual(original.age, restored.age, "年龄应该保持一致");
result.message = "成功";
return result;
}
// ==================== check 命名空间测试 ====================
TestResult FacadeTests::testCheckIsObject()
{
TestResult result;
result.passed = true;
protocol::LSPObject obj;
obj["key"] = protocol::LSPAny(1);
protocol::LSPAny any(obj);
assertTrue(transform::check::IsObject(any), "应该识别为object");
protocol::LSPAny not_obj(42);
assertFalse(transform::check::IsObject(not_obj), "integer不应该识别为object");
result.message = "成功";
return result;
}
TestResult FacadeTests::testCheckIsArray()
{
TestResult result;
result.passed = true;
protocol::LSPArray arr;
arr.push_back(protocol::LSPAny(1));
protocol::LSPAny any(arr);
assertTrue(transform::check::IsArray(any), "应该识别为array");
protocol::LSPAny not_arr("string");
assertFalse(transform::check::IsArray(not_arr), "string不应该识别为array");
result.message = "成功";
return result;
}
TestResult FacadeTests::testCheckIsString()
{
TestResult result;
result.passed = true;
protocol::LSPAny any("hello");
assertTrue(transform::check::IsString(any), "应该识别为string");
protocol::LSPAny not_str(42);
assertFalse(transform::check::IsString(not_str), "integer不应该识别为string");
result.message = "成功";
return result;
}
TestResult FacadeTests::testCheckIsNumber()
{
TestResult result;
result.passed = true;
protocol::LSPAny int_any(42);
assertTrue(transform::check::IsNumber(int_any), "integer应该是数字");
protocol::LSPAny uint_any(100u);
assertTrue(transform::check::IsNumber(uint_any), "uinteger应该是数字");
protocol::LSPAny decimal_any(3.14);
assertTrue(transform::check::IsNumber(decimal_any), "decimal应该是数字");
protocol::LSPAny not_num("string");
assertFalse(transform::check::IsNumber(not_num), "string不应该是数字");
result.message = "成功";
return result;
}
TestResult FacadeTests::testCheckIsBool()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(true);
assertTrue(transform::check::IsBool(any), "应该识别为bool");
protocol::LSPAny not_bool(42);
assertFalse(transform::check::IsBool(not_bool), "integer不应该识别为bool");
result.message = "成功";
return result;
}
TestResult FacadeTests::testCheckIsNull()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(nullptr);
assertTrue(transform::check::IsNull(any), "应该识别为null");
protocol::LSPAny not_null(42);
assertFalse(transform::check::IsNull(not_null), "integer不应该识别为null");
result.message = "成功";
return result;
}
TestResult FacadeTests::testCheckMultipleTypes()
{
TestResult result;
result.passed = true;
// 测试一个值不能同时是多种类型
protocol::LSPAny any(42);
assertTrue(transform::check::IsNumber(any), "应该是数字");
assertFalse(transform::check::IsString(any), "不应该是字符串");
assertFalse(transform::check::IsBool(any), "不应该是布尔值");
assertFalse(transform::check::IsNull(any), "不应该是null");
assertFalse(transform::check::IsArray(any), "不应该是数组");
assertFalse(transform::check::IsObject(any), "不应该是对象");
result.message = "成功";
return result;
}
// ==================== debug 命名空间测试 ====================
TestResult FacadeTests::testDebugGetTypeName()
{
TestResult result;
result.passed = true;
protocol::LSPAny obj_any(protocol::LSPObject{});
assertEqual(std::string("LSPObject"), transform::debug::GetTypeName(obj_any),
"类型名应该为'LSPObject'");
protocol::LSPAny arr_any(protocol::LSPArray{});
assertEqual(std::string("LSPArray"), transform::debug::GetTypeName(arr_any),
"类型名应该为'LSPArray'");
protocol::LSPAny str_any("test");
assertEqual(std::string("string"), transform::debug::GetTypeName(str_any),
"类型名应该为'string'");
protocol::LSPAny int_any(42);
assertEqual(std::string("integer"), transform::debug::GetTypeName(int_any),
"类型名应该为'integer'");
protocol::LSPAny uint_any(100u);
assertEqual(std::string("uinteger"), transform::debug::GetTypeName(uint_any),
"类型名应该为'uinteger'");
protocol::LSPAny decimal_any(3.14);
assertEqual(std::string("decimal"), transform::debug::GetTypeName(decimal_any),
"类型名应该为'decimal'");
protocol::LSPAny bool_any(true);
assertEqual(std::string("boolean"), transform::debug::GetTypeName(bool_any),
"类型名应该为'boolean'");
protocol::LSPAny null_any(nullptr);
assertEqual(std::string("null"), transform::debug::GetTypeName(null_any),
"类型名应该为'null'");
result.message = "成功";
return result;
}
TestResult FacadeTests::testDebugGetIdStringInt()
{
TestResult result;
result.passed = true;
std::variant<int, std::string> id = 123;
std::string id_str = transform::debug::GetIdString(id);
assertEqual(std::string("123"), id_str, "int id应该转换为'123'");
result.message = "成功";
return result;
}
TestResult FacadeTests::testDebugGetIdStringString()
{
TestResult result;
result.passed = true;
std::variant<int, std::string> id = std::string("abc-123-def");
std::string id_str = transform::debug::GetIdString(id);
assertEqual(std::string("abc-123-def"), id_str, "string id应该保持为'abc-123-def'");
result.message = "成功";
return result;
}
} // namespace lsp::test

View File

@ -0,0 +1,36 @@
#pragma once
#include "test_framework.hpp"
namespace lsp::test
{
// Facade 接口测试类Serialize, Deserialize, check, debug
class FacadeTests
{
public:
static void registerTests(TestRunner& runner);
private:
// ==================== Serialize/Deserialize 测试 ====================
static TestResult testSerializeSimpleStruct();
static TestResult testSerializeComplexStruct();
static TestResult testSerializeLSPAny();
static TestResult testDeserializeSimpleStruct();
static TestResult testDeserializeComplexStruct();
static TestResult testDeserializeInvalidJSON();
static TestResult testSerializeDeserializeRoundtrip();
// ==================== check 命名空间测试 ====================
static TestResult testCheckIsObject();
static TestResult testCheckIsArray();
static TestResult testCheckIsString();
static TestResult testCheckIsNumber();
static TestResult testCheckIsBool();
static TestResult testCheckIsNull();
static TestResult testCheckMultipleTypes();
// ==================== debug 命名空间测试 ====================
static TestResult testDebugGetTypeName();
static TestResult testDebugGetIdStringInt();
static TestResult testDebugGetIdStringString();
};
}

View File

@ -0,0 +1,689 @@
#include <cmath>
#include <limits>
#include "../../src/protocol/detail/basic_types.hpp"
#include "./lsp_any_test.hpp"
namespace lsp::test
{
// ==================== LSPAnyTests 实现 ====================
void LSPAnyTests::registerTests(TestRunner& runner)
{
// 构造函数测试
runner.addTest("默认构造函数", testDefaultConstructor);
runner.addTest("浮点数构造函数", testDecimalConstructor);
runner.addTest("布尔构造函数", testBooleanConstructor);
runner.addTest("字符串构造函数", testStringConstructor);
runner.addTest("C字符串构造函数", testCStringConstructor);
runner.addTest("空指针构造函数", testNullptrConstructor);
runner.addTest("LSPObject构造函数", testLSPObjectConstructor);
runner.addTest("LSPArray构造函数", testLSPArrayConstructor);
// 拷贝和移动测试
runner.addTest("拷贝构造函数", testCopyConstructor);
runner.addTest("移动构造函数", testMoveConstructor);
runner.addTest("拷贝赋值", testCopyAssignment);
runner.addTest("移动赋值", testMoveAssignment);
// 赋值操作符测试
runner.addTest("浮点数赋值", testDecimalAssignment);
runner.addTest("布尔赋值", testBooleanAssignment);
runner.addTest("字符串赋值", testStringAssignment);
runner.addTest("空指针赋值", testNullptrAssignment);
runner.addTest("LSPObject赋值", testLSPObjectAssignment);
runner.addTest("LSPArray赋值", testLSPArrayAssignment);
// 类型检查测试
runner.addTest("Is类型检查", testIsMethod);
runner.addTest("Get获取值", testGetMethod);
// 访问者模式测试
runner.addTest("Visit访问者", testVisitMethod);
// 整数模板测试
runner.addTest("有符号整数模板", testIntegerTemplateSignedTypes);
runner.addTest("无符号整数模板", testIntegerTemplateUnsignedTypes);
runner.addTest("整数边界测试", testIntegerTemplateBoundaries);
// 复杂场景测试
runner.addTest("嵌套LSPObject", testNestedLSPObject);
runner.addTest("嵌套LSPArray", testNestedLSPArray);
runner.addTest("混合嵌套", testMixedNesting);
runner.addTest("类型转换", testTypeConversion);
// 边界情况测试
runner.addTest("浮点精度", testFloatPrecision);
runner.addTest("大数字", testLargeNumbers);
runner.addTest("空容器", testEmptyContainers);
}
// ==================== 构造函数测试 ====================
TestResult LSPAnyTests::testDefaultConstructor()
{
TestResult result;
result.passed = true;
protocol::LSPAny any;
assertTrue(any.Is<std::nullptr_t>(), "默认构造应该是nullptr类型");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testDecimalConstructor()
{
TestResult result;
result.passed = true;
protocol::decimal value = 3.14;
protocol::LSPAny any(value);
assertTrue(any.Is<protocol::decimal>(), "应该是decimal类型");
assertEqual(value, any.Get<protocol::decimal>(), "值应该相等");
// 测试 float 构造
float fValue = 2.5f;
protocol::LSPAny anyFloat(fValue);
assertTrue(anyFloat.Is<protocol::decimal>(), "float应该转为decimal类型");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testBooleanConstructor()
{
TestResult result;
result.passed = true;
protocol::LSPAny anyTrue(true);
protocol::LSPAny anyFalse(false);
assertTrue(anyTrue.Is<protocol::boolean>(), "应该是boolean类型");
assertTrue(anyFalse.Is<protocol::boolean>(), "应该是boolean类型");
assertEqual(true, anyTrue.Get<protocol::boolean>(), "值应该是true");
assertEqual(false, anyFalse.Get<protocol::boolean>(), "值应该是false");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testStringConstructor()
{
TestResult result;
result.passed = true;
protocol::string value = "Hello, LSP!";
protocol::LSPAny any(value);
assertTrue(any.Is<protocol::string>(), "应该是string类型");
assertEqual(value, any.Get<protocol::string>(), "值应该相等");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testCStringConstructor()
{
TestResult result;
result.passed = true;
const char* value = "C String";
protocol::LSPAny any(value);
assertTrue(any.Is<protocol::string>(), "应该是string类型");
assertEqual(std::string(value), any.Get<protocol::string>(), "值应该相等");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testNullptrConstructor()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(nullptr);
assertTrue(any.Is<std::nullptr_t>(), "应该是nullptr类型");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testLSPObjectConstructor()
{
TestResult result;
result.passed = true;
protocol::LSPObject obj;
obj["key1"] = protocol::LSPAny(42);
obj["key2"] = protocol::LSPAny("value");
protocol::LSPAny any(obj);
assertTrue(any.Is<protocol::LSPObject>(), "应该是LSPObject类型");
const auto& retrievedObj = any.Get<protocol::LSPObject>();
assertTrue(retrievedObj.count("key1") > 0, "应该包含key1");
assertTrue(retrievedObj.count("key2") > 0, "应该包含key2");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testLSPArrayConstructor()
{
TestResult result;
result.passed = true;
protocol::LSPArray arr;
arr.push_back(protocol::LSPAny(1));
arr.push_back(protocol::LSPAny(2));
arr.push_back(protocol::LSPAny(3));
protocol::LSPAny any(arr);
assertTrue(any.Is<protocol::LSPArray>(), "应该是LSPArray类型");
const auto& retrievedArr = any.Get<protocol::LSPArray>();
assertTrue(retrievedArr.size() == 3, "数组大小应该是3");
result.message = "成功";
return result;
}
// ==================== 拷贝和移动测试 ====================
TestResult LSPAnyTests::testCopyConstructor()
{
TestResult result;
result.passed = true;
protocol::LSPAny original(42);
protocol::LSPAny copy(original);
assertTrue(copy.Is<protocol::integer>(), "拷贝应该保持类型");
assertEqual(42, copy.Get<protocol::integer>(), "拷贝应该保持值");
assertEqual(42, original.Get<protocol::integer>(), "原值不应改变");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testMoveConstructor()
{
TestResult result;
result.passed = true;
protocol::LSPAny original(protocol::string("Move me"));
protocol::LSPAny moved(std::move(original));
assertTrue(moved.Is<protocol::string>(), "移动应该保持类型");
assertEqual(std::string("Move me"), moved.Get<protocol::string>(), "移动应该保持值");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testCopyAssignment()
{
TestResult result;
result.passed = true;
protocol::LSPAny original(42);
protocol::LSPAny target(nullptr);
target = original;
assertTrue(target.Is<protocol::integer>(), "赋值应该保持类型");
assertEqual(42, target.Get<protocol::integer>(), "赋值应该保持值");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testMoveAssignment()
{
TestResult result;
result.passed = true;
protocol::LSPAny original(protocol::string("Move me"));
protocol::LSPAny target(nullptr);
target = std::move(original);
assertTrue(target.Is<protocol::string>(), "移动赋值应该保持类型");
assertEqual(std::string("Move me"), target.Get<protocol::string>(), "移动赋值应该保持值");
result.message = "成功";
return result;
}
// ==================== 赋值操作符测试 ====================
TestResult LSPAnyTests::testDecimalAssignment()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(nullptr);
any = 2.718;
assertTrue(any.Is<protocol::decimal>(), "赋值后应该是decimal类型");
assertEqual(2.718, any.Get<protocol::decimal>(), "赋值后值应该正确");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testBooleanAssignment()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(nullptr);
any = true;
assertTrue(any.Is<protocol::boolean>(), "赋值后应该是boolean类型");
assertEqual(true, any.Get<protocol::boolean>(), "赋值后值应该正确");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testStringAssignment()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(nullptr);
any = protocol::string("Assigned");
assertTrue(any.Is<protocol::string>(), "赋值后应该是string类型");
assertEqual(std::string("Assigned"), any.Get<protocol::string>(), "赋值后值应该正确");
// 测试 C 字符串赋值
any = "C String";
assertEqual(std::string("C String"), any.Get<protocol::string>(), "C字符串赋值应该正确");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testNullptrAssignment()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(42);
any = nullptr;
assertTrue(any.Is<std::nullptr_t>(), "赋值后应该是nullptr类型");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testLSPObjectAssignment()
{
TestResult result;
result.passed = true;
protocol::LSPObject obj;
obj["test"] = protocol::LSPAny(999);
protocol::LSPAny any(nullptr);
any = obj;
assertTrue(any.Is<protocol::LSPObject>(), "赋值后应该是LSPObject类型");
const auto& retrievedObj = any.Get<protocol::LSPObject>();
assertTrue(retrievedObj.count("test") > 0, "应该包含test键");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testLSPArrayAssignment()
{
TestResult result;
result.passed = true;
protocol::LSPArray arr;
arr.push_back(protocol::LSPAny(10));
arr.push_back(protocol::LSPAny(20));
protocol::LSPAny any(nullptr);
any = arr;
assertTrue(any.Is<protocol::LSPArray>(), "赋值后应该是LSPArray类型");
const auto& retrievedArr = any.Get<protocol::LSPArray>();
assertTrue(retrievedArr.size() == 2, "数组大小应该是2");
result.message = "成功";
return result;
}
// ==================== 类型检查测试 ====================
TestResult LSPAnyTests::testIsMethod()
{
TestResult result;
result.passed = true;
protocol::LSPAny intAny(42);
assertTrue(intAny.Is<protocol::integer>(), "Is应该正确识别integer");
assertFalse(intAny.Is<protocol::string>(), "Is应该正确排除string");
assertFalse(intAny.Is<protocol::decimal>(), "Is应该正确排除decimal");
protocol::LSPAny strAny(protocol::string("test"));
assertTrue(strAny.Is<protocol::string>(), "Is应该正确识别string");
assertFalse(strAny.Is<protocol::integer>(), "Is应该正确排除integer");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testGetMethod()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(42);
assertEqual(42, any.Get<protocol::integer>(), "Get应该返回正确的值");
// 修改值
any.Get<protocol::integer>() = 100;
assertEqual(100, any.Get<protocol::integer>(), "Get应该返回可修改的引用");
// const Get 测试
const protocol::LSPAny constAny(200);
assertEqual(200, constAny.Get<protocol::integer>(), "const Get应该正常工作");
result.message = "成功";
return result;
}
// ==================== 访问者模式测试 ====================
TestResult LSPAnyTests::testVisitMethod()
{
TestResult result;
result.passed = true;
protocol::LSPAny intAny(42);
protocol::LSPAny strAny(protocol::string("hello"));
protocol::LSPAny boolAny(true);
// 测试 const Visit
auto visitor = [](const auto& value) -> std::string {
using T = std::decay_t<decltype(value)>;
if constexpr (std::is_same_v<T, protocol::integer>)
{
return "integer:" + std::to_string(value);
}
else if constexpr (std::is_same_v<T, protocol::string>)
{
return "string:" + value;
}
else if constexpr (std::is_same_v<T, protocol::boolean>)
{
return value ? "bool:true" : "bool:false";
}
else
{
return "other";
}
};
std::string result1 = intAny.Visit(visitor);
assertEqual(std::string("integer:42"), result1, "Visit应该正确访问integer");
std::string result2 = strAny.Visit(visitor);
assertEqual(std::string("string:hello"), result2, "Visit应该正确访问string");
std::string result3 = boolAny.Visit(visitor);
assertEqual(std::string("bool:true"), result3, "Visit应该正确访问boolean");
result.message = "成功";
return result;
}
// ==================== 整数模板测试 ====================
TestResult LSPAnyTests::testIntegerTemplateSignedTypes()
{
TestResult result;
result.passed = true;
// 测试各种有符号整数类型
protocol::LSPAny anyInt8(static_cast<int8_t>(-10));
assertTrue(anyInt8.Is<protocol::integer>(), "int8_t应该转为integer");
assertEqual(-10, anyInt8.Get<protocol::integer>(), "int8_t值应该正确");
protocol::LSPAny anyInt16(static_cast<int16_t>(-1000));
assertTrue(anyInt16.Is<protocol::integer>(), "int16_t应该转为integer");
assertEqual(-1000, anyInt16.Get<protocol::integer>(), "int16_t值应该正确");
protocol::LSPAny anyInt64(static_cast<int64_t>(100000));
assertTrue(anyInt64.Is<protocol::integer>(), "int64_t应该转为integer");
assertEqual(100000, anyInt64.Get<protocol::integer>(), "int64_t值应该正确");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testIntegerTemplateUnsignedTypes()
{
TestResult result;
result.passed = true;
// 测试各种无符号整数类型 - 无符号整数应该存储为uinteger
protocol::LSPAny anyUint8(static_cast<uint8_t>(255));
assertTrue(anyUint8.Is<protocol::uinteger>(), "uint8_t应该转为uinteger");
assertEqual(255u, anyUint8.Get<protocol::uinteger>(), "uint8_t值应该正确");
protocol::LSPAny anyUint16(static_cast<uint16_t>(5000));
assertTrue(anyUint16.Is<protocol::uinteger>(), "uint16_t应该转为uinteger");
assertEqual(5000u, anyUint16.Get<protocol::uinteger>(), "uint16_t值应该正确");
protocol::LSPAny anySize(static_cast<size_t>(12345));
assertTrue(anySize.Is<protocol::uinteger>(), "size_t应该转为uinteger");
assertEqual(12345u, anySize.Get<protocol::uinteger>(), "size_t值应该正确");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testIntegerTemplateBoundaries()
{
TestResult result;
result.passed = true;
// 测试 int32 边界
protocol::LSPAny anyMax(std::numeric_limits<int32_t>::max());
assertTrue(anyMax.Is<protocol::integer>(), "int32_max应该是integer");
assertEqual(std::numeric_limits<int32_t>::max(), anyMax.Get<protocol::integer>(), "int32_max值应该正确");
protocol::LSPAny anyMin(std::numeric_limits<int32_t>::min());
assertTrue(anyMin.Is<protocol::integer>(), "int32_min应该是integer");
assertEqual(std::numeric_limits<int32_t>::min(), anyMin.Get<protocol::integer>(), "int32_min值应该正确");
// 测试超出 int32 范围的 int64
int64_t largeValue = static_cast<int64_t>(std::numeric_limits<int32_t>::max()) + 1;
protocol::LSPAny anyLarge(largeValue);
assertTrue(anyLarge.Is<protocol::decimal>(), "超出int32范围应该转为decimal");
// 测试 uint32 边界
protocol::LSPAny anyUintMax(std::numeric_limits<uint32_t>::max());
assertTrue(anyUintMax.Is<protocol::uinteger>(), "uint32_max应该是uinteger");
assertEqual(std::numeric_limits<uint32_t>::max(), anyUintMax.Get<protocol::uinteger>(), "uint32_max值应该正确");
result.message = "成功";
return result;
}
// ==================== 复杂场景测试 ====================
TestResult LSPAnyTests::testNestedLSPObject()
{
TestResult result;
result.passed = true;
protocol::LSPObject innerObj;
innerObj["inner_key"] = protocol::LSPAny(42);
protocol::LSPObject outerObj;
outerObj["outer_key"] = protocol::LSPAny(innerObj);
outerObj["name"] = protocol::LSPAny(protocol::string("test"));
protocol::LSPAny any(outerObj);
assertTrue(any.Is<protocol::LSPObject>(), "应该是LSPObject类型");
const auto& obj = any.Get<protocol::LSPObject>();
assertTrue(obj.count("outer_key") > 0, "应该包含outer_key");
assertTrue(obj.count("name") > 0, "应该包含name");
const auto& inner = obj.at("outer_key");
assertTrue(inner.Is<protocol::LSPObject>(), "嵌套值应该是LSPObject");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testNestedLSPArray()
{
TestResult result;
result.passed = true;
protocol::LSPArray innerArr;
innerArr.push_back(protocol::LSPAny(1));
innerArr.push_back(protocol::LSPAny(2));
protocol::LSPArray outerArr;
outerArr.push_back(protocol::LSPAny(innerArr));
outerArr.push_back(protocol::LSPAny(protocol::string("text")));
protocol::LSPAny any(outerArr);
assertTrue(any.Is<protocol::LSPArray>(), "应该是LSPArray类型");
const auto& arr = any.Get<protocol::LSPArray>();
assertTrue(arr.size() == 2, "外层数组大小应该是2");
assertTrue(arr[0].Is<protocol::LSPArray>(), "第一个元素应该是LSPArray");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testMixedNesting()
{
TestResult result;
result.passed = true;
protocol::LSPArray arr;
arr.push_back(protocol::LSPAny(1));
arr.push_back(protocol::LSPAny(protocol::string("two")));
arr.push_back(protocol::LSPAny(3.0));
protocol::LSPObject obj;
obj["array"] = protocol::LSPAny(arr);
obj["number"] = protocol::LSPAny(42);
obj["flag"] = protocol::LSPAny(true);
protocol::LSPAny any(obj);
assertTrue(any.Is<protocol::LSPObject>(), "应该是LSPObject类型");
const auto& retrievedObj = any.Get<protocol::LSPObject>();
assertTrue(retrievedObj.count("array") > 0, "应该包含array");
assertTrue(retrievedObj.at("array").Is<protocol::LSPArray>(), "array应该是LSPArray类型");
const auto& retrievedArr = retrievedObj.at("array").Get<protocol::LSPArray>();
assertTrue(retrievedArr.size() == 3, "数组大小应该是3");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testTypeConversion()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(42);
assertTrue(any.Is<protocol::integer>(), "初始应该是integer");
// 改变类型
any = protocol::string("now a string");
assertTrue(any.Is<protocol::string>(), "现在应该是string");
assertFalse(any.Is<protocol::integer>(), "不应该再是integer");
// 再次改变
any = 3.14;
assertTrue(any.Is<protocol::decimal>(), "现在应该是decimal");
assertFalse(any.Is<protocol::string>(), "不应该再是string");
result.message = "成功";
return result;
}
// ==================== 边界情况测试 ====================
TestResult LSPAnyTests::testFloatPrecision()
{
TestResult result;
result.passed = true;
float fValue = 1.23456789f;
protocol::LSPAny anyFloat(fValue);
assertTrue(anyFloat.Is<protocol::decimal>(), "float应该转为decimal");
// 注意float 转为 double 可能有精度变化,这里只是验证类型转换正确
protocol::decimal retrieved = anyFloat.Get<protocol::decimal>();
assertTrue(std::abs(retrieved - static_cast<double>(fValue)) < 1e-6,
"转换后的值应该接近原值");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testLargeNumbers()
{
TestResult result;
result.passed = true;
// 测试大的 uint64 值转为 decimal
uint64_t largeUint = 10000000000ULL; // 超出 uint32 范围
protocol::LSPAny anyLarge(largeUint);
assertTrue(anyLarge.Is<protocol::decimal>(), "大整数应该转为decimal");
protocol::decimal retrieved = anyLarge.Get<protocol::decimal>();
assertTrue(std::abs(retrieved - static_cast<double>(largeUint)) < 1.0,
"转换后的值应该接近原值");
result.message = "成功";
return result;
}
TestResult LSPAnyTests::testEmptyContainers()
{
TestResult result;
result.passed = true;
protocol::LSPObject emptyObj;
protocol::LSPAny anyObj(emptyObj);
assertTrue(anyObj.Is<protocol::LSPObject>(), "应该是LSPObject类型");
const auto& obj = anyObj.Get<protocol::LSPObject>();
assertTrue(obj.empty(), "对象应该为空");
protocol::LSPArray emptyArr;
protocol::LSPAny anyArr(emptyArr);
assertTrue(anyArr.Is<protocol::LSPArray>(), "应该是LSPArray类型");
const auto& arr = anyArr.Get<protocol::LSPArray>();
assertTrue(arr.empty(), "数组应该为空");
result.message = "成功";
return result;
}
} // namespace lsp::test

View File

@ -0,0 +1,62 @@
#pragma once
#include "./test_framework.hpp"
namespace lsp::test
{
// LSPAny 测试类
class LSPAnyTests
{
public:
static void registerTests(TestRunner& runner);
private:
// 构造函数测试
static TestResult testDefaultConstructor();
static TestResult testDecimalConstructor();
static TestResult testBooleanConstructor();
static TestResult testStringConstructor();
static TestResult testCStringConstructor();
static TestResult testNullptrConstructor();
static TestResult testLSPObjectConstructor();
static TestResult testLSPArrayConstructor();
// 拷贝和移动测试
static TestResult testCopyConstructor();
static TestResult testMoveConstructor();
static TestResult testCopyAssignment();
static TestResult testMoveAssignment();
// 赋值操作符测试
static TestResult testIntegerAssignment();
static TestResult testUIntegerAssignment();
static TestResult testDecimalAssignment();
static TestResult testBooleanAssignment();
static TestResult testStringAssignment();
static TestResult testNullptrAssignment();
static TestResult testLSPObjectAssignment();
static TestResult testLSPArrayAssignment();
// 类型检查测试
static TestResult testIsMethod();
static TestResult testGetMethod();
// 访问者模式测试
static TestResult testVisitMethod();
// 整数模板测试
static TestResult testIntegerTemplateSignedTypes();
static TestResult testIntegerTemplateUnsignedTypes();
static TestResult testIntegerTemplateBoundaries();
// 复杂场景测试
static TestResult testNestedLSPObject();
static TestResult testNestedLSPArray();
static TestResult testMixedNesting();
static TestResult testTypeConversion();
// 边界情况测试
static TestResult testFloatPrecision();
static TestResult testLargeNumbers();
static TestResult testEmptyContainers();
};
}

View File

@ -0,0 +1,178 @@
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <cmath>
#include "./test_framework.hpp"
namespace lsp::test
{
// ==================== TestRunner 实现 ====================
void TestRunner::addTest(const std::string& name, TestFunction test)
{
tests.push_back({ name, test });
}
void TestRunner::runAllTests()
{
results.clear();
std::cout << "\n========== 开始运行测试 ==========\n"
<< std::endl;
for (const auto& testCase : tests)
{
try
{
TestResult result = testCase.function();
result.testName = testCase.name;
results.push_back(result);
printResult(result);
}
catch (const std::exception& e)
{
TestResult result;
result.testName = testCase.name;
result.passed = false;
result.message = std::string("异常: ") + e.what();
results.push_back(result);
printResult(result);
}
}
printSummary();
}
int TestRunner::getFailedCount() const
{
int count = 0;
for (const auto& result : results)
{
if (!result.passed)
{
count++;
}
}
return count;
}
int TestRunner::getTotalCount() const
{
return static_cast<int>(results.size());
}
void TestRunner::printResult(const TestResult& result)
{
if (result.passed)
{
std::cout << "[✓] " << result.testName << std::endl;
}
else
{
std::cout << "[✗] " << result.testName << std::endl;
std::cout << " 失败: " << result.message << std::endl;
}
}
void TestRunner::printSummary()
{
int passed = getTotalCount() - getFailedCount();
int failed = getFailedCount();
int total = getTotalCount();
std::cout << "\n========== 测试总结 ==========\n";
std::cout << "总计: " << total << " 个测试\n";
std::cout << "通过: " << passed << "\n";
std::cout << "失败: " << failed << "\n";
if (failed == 0)
{
std::cout << "\n所有测试通过! ✓\n"
<< std::endl;
}
else
{
std::cout << "\n部分测试失败 ✗\n"
<< std::endl;
}
}
// ==================== 断言辅助函数实现 ====================
void assertTrue(bool condition, const std::string& message)
{
if (!condition)
{
throw std::runtime_error(message);
}
}
void assertFalse(bool condition, const std::string& message)
{
if (condition)
{
throw std::runtime_error(message);
}
}
void assertEqual(int expected, int actual, const std::string& message)
{
if (expected != actual)
{
std::stringstream ss;
ss << message << " (期望: " << expected << ", 实际: " << actual << ")";
throw std::runtime_error(ss.str());
}
}
void assertEqual(unsigned int expected, unsigned int actual, const std::string& message)
{
if (expected != actual)
{
std::stringstream ss;
ss << message << " (期望: " << expected << ", 实际: " << actual << ")";
throw std::runtime_error(ss.str());
}
}
void assertEqual(double expected, double actual, const std::string& message)
{
if (std::abs(expected - actual) > 1e-9)
{
std::stringstream ss;
ss << message << " (期望: " << expected << ", 实际: " << actual << ")";
throw std::runtime_error(ss.str());
}
}
void assertEqual(bool expected, bool actual, const std::string& message)
{
if (expected != actual)
{
std::stringstream ss;
ss << message << " (期望: " << (expected ? "true" : "false")
<< ", 实际: " << (actual ? "true" : "false") << ")";
throw std::runtime_error(ss.str());
}
}
void assertEqual(const std::string& expected, const std::string& actual, const std::string& message)
{
if (expected != actual)
{
std::stringstream ss;
ss << message << " (期望: \"" << expected << "\", 实际: \"" << actual << "\")";
throw std::runtime_error(ss.str());
}
}
void assertEqual(size_t expected, size_t actual, const std::string& message)
{
if (expected != actual)
{
std::stringstream ss;
ss << message << " (期望: " << expected << ", 实际: " << actual << ")";
throw std::runtime_error(ss.str());
}
}
} // namespace lsp::test

View File

@ -0,0 +1,50 @@
#pragma once
#include <string>
#include <vector>
#include <functional>
namespace lsp::test
{
// 简单的测试结果结构
struct TestResult
{
std::string testName;
bool passed;
std::string message;
};
// 测试运行器类
class TestRunner
{
public:
using TestFunction = std::function<TestResult()>;
void addTest(const std::string& name, TestFunction test);
void runAllTests();
int getFailedCount() const;
int getTotalCount() const;
private:
struct TestCase
{
std::string name;
TestFunction function;
};
std::vector<TestCase> tests;
std::vector<TestResult> results;
void printResult(const TestResult& result);
void printSummary();
};
// 断言辅助函数
void assertTrue(bool condition, const std::string& message);
void assertFalse(bool condition, const std::string& message);
void assertEqual(int expected, int actual, const std::string& message);
void assertEqual(unsigned int expected, unsigned int actual, const std::string& message);
void assertEqual(double expected, double actual, const std::string& message);
void assertEqual(bool expected, bool actual, const std::string& message);
void assertEqual(const std::string& expected, const std::string& actual, const std::string& message);
void assertEqual(size_t expected, size_t actual, const std::string& message);
}

View File

@ -0,0 +1,36 @@
#include <iostream>
#include "test_framework.hpp"
#include "lsp_any_test.hpp"
#include "transformer_test.hpp"
#include "facade_test.hpp"
#include "common_test.hpp"
int main()
{
lsp::test::TestRunner runner;
std::cout << "\n========================================" << std::endl;
std::cout << " LSP Transform 库单元测试套件" << std::endl;
std::cout << "========================================\n" << std::endl;
// 注册所有测试
std::cout << "正在注册测试..." << std::endl;
std::cout << " - LSPAny 基本功能测试" << std::endl;
lsp::test::LSPAnyTests::registerTests(runner);
std::cout << " - Transformer 转换功能测试" << std::endl;
lsp::test::TransformerTests::registerTests(runner);
std::cout << " - Facade 接口测试" << std::endl;
lsp::test::FacadeTests::registerTests(runner);
std::cout << " - Common 类型特征测试" << std::endl;
lsp::test::CommonTests::registerTests(runner);
// 运行所有测试
runner.runAllTests();
// 返回失败的测试数量用于CI/CD
return runner.getFailedCount();
}

View File

@ -0,0 +1,654 @@
#include "transformer_test.hpp"
#include "../../src/protocol/transform/transformer.hpp"
#include "../../src/protocol/transform/common.hpp"
#include "../../src/protocol/detail/basic_types.hpp"
#include <vector>
#include <map>
#include <optional>
namespace lsp::test
{
void TransformerTests::registerTests(TestRunner& runner)
{
// ToLSPAny 基本类型
runner.addTest("Transformer - ToLSPAny Boolean", testToLSPAnyBoolean);
runner.addTest("Transformer - ToLSPAny Integer", testToLSPAnyInteger);
runner.addTest("Transformer - ToLSPAny UInteger", testToLSPAnyUInteger);
runner.addTest("Transformer - ToLSPAny Float", testToLSPAnyFloat);
runner.addTest("Transformer - ToLSPAny Double", testToLSPAnyDouble);
runner.addTest("Transformer - ToLSPAny String", testToLSPAnyString);
runner.addTest("Transformer - ToLSPAny CString", testToLSPAnyCString);
// ToLSPAny 容器类型
runner.addTest("Transformer - ToLSPAny Vector", testToLSPAnyVector);
runner.addTest("Transformer - ToLSPAny Map", testToLSPAnyMap);
runner.addTest("Transformer - ToLSPAny Optional (有值)", testToLSPAnyOptionalValue);
runner.addTest("Transformer - ToLSPAny Optional (nullopt)", testToLSPAnyOptionalNullopt);
// ToLSPAny LSP类型
runner.addTest("Transformer - ToLSPAny LSPObject", testToLSPAnyLSPObject);
runner.addTest("Transformer - ToLSPAny LSPArray", testToLSPAnyLSPArray);
runner.addTest("Transformer - ToLSPAny LSPAny", testToLSPAnyLSPAny);
// FromLSPAny 基本类型
runner.addTest("Transformer - FromLSPAny Boolean", testFromLSPAnyBoolean);
runner.addTest("Transformer - FromLSPAny Integer", testFromLSPAnyInteger);
runner.addTest("Transformer - FromLSPAny String", testFromLSPAnyString);
runner.addTest("Transformer - FromLSPAny Double", testFromLSPAnyDouble);
// FromLSPAny 容器类型
runner.addTest("Transformer - FromLSPAny Vector", testFromLSPAnyVector);
runner.addTest("Transformer - FromLSPAny Optional (有值)", testFromLSPAnyOptionalValue);
runner.addTest("Transformer - FromLSPAny Optional (null)", testFromLSPAnyOptionalNull);
runner.addTest("Transformer - FromLSPAny LSPObject", testFromLSPAnyLSPObject);
runner.addTest("Transformer - FromLSPAny LSPArray", testFromLSPAnyLSPArray);
// 数字类型转换
runner.addTest("Transformer - 提取Integer", testExtractNumberFromInteger);
runner.addTest("Transformer - 提取UInteger", testExtractNumberFromUInteger);
runner.addTest("Transformer - 提取Decimal", testExtractNumberFromDecimal);
runner.addTest("Transformer - 跨类型数字提取", testExtractNumberCrossType);
// 错误处理
runner.addTest("Transformer - 类型不匹配错误", testFromLSPAnyTypeMismatch);
runner.addTest("Transformer - 无效数字错误", testFromLSPAnyInvalidNumber);
runner.addTest("Transformer - 无效数组错误", testFromLSPAnyInvalidArray);
// 嵌套结构
runner.addTest("Transformer - 嵌套Vector", testNestedVector);
runner.addTest("Transformer - 嵌套LSPObject", testNestedLSPObject);
runner.addTest("Transformer - 混合类型嵌套", testMixedTypeNesting);
}
// ==================== ToLSPAny 基本类型测试 ====================
TestResult TransformerTests::testToLSPAnyBoolean()
{
TestResult result;
result.passed = true;
auto any = transform::LSPAnyConverter::ToLSPAny(true);
assertTrue(any.Is<protocol::boolean>(), "应该转换为boolean类型");
assertEqual(true, any.Get<protocol::boolean>(), "值应该为true");
auto any_false = transform::LSPAnyConverter::ToLSPAny(false);
assertEqual(false, any_false.Get<protocol::boolean>(), "值应该为false");
result.message = "成功";
return result;
}
TestResult TransformerTests::testToLSPAnyInteger()
{
TestResult result;
result.passed = true;
auto any = transform::LSPAnyConverter::ToLSPAny(42);
assertTrue(any.Is<protocol::integer>(), "应该转换为integer类型");
assertEqual(42, any.Get<protocol::integer>(), "值应该为42");
auto any_negative = transform::LSPAnyConverter::ToLSPAny(-100);
assertEqual(-100, any_negative.Get<protocol::integer>(), "负数应该正确转换");
result.message = "成功";
return result;
}
TestResult TransformerTests::testToLSPAnyUInteger()
{
TestResult result;
result.passed = true;
auto any = transform::LSPAnyConverter::ToLSPAny(42u);
assertTrue(any.Is<protocol::uinteger>(), "应该转换为uinteger类型");
assertEqual(42u, any.Get<protocol::uinteger>(), "值应该为42");
result.message = "成功";
return result;
}
TestResult TransformerTests::testToLSPAnyFloat()
{
TestResult result;
result.passed = true;
auto any = transform::LSPAnyConverter::ToLSPAny(3.14f);
assertTrue(any.Is<protocol::decimal>(), "float应该转换为decimal类型");
result.message = "成功";
return result;
}
TestResult TransformerTests::testToLSPAnyDouble()
{
TestResult result;
result.passed = true;
auto any = transform::LSPAnyConverter::ToLSPAny(2.718);
assertTrue(any.Is<protocol::decimal>(), "应该转换为decimal类型");
assertEqual(2.718, any.Get<protocol::decimal>(), "值应该为2.718");
result.message = "成功";
return result;
}
TestResult TransformerTests::testToLSPAnyString()
{
TestResult result;
result.passed = true;
std::string str = "hello world";
auto any = transform::LSPAnyConverter::ToLSPAny(str);
assertTrue(any.Is<protocol::string>(), "应该转换为string类型");
assertEqual(str, any.Get<protocol::string>(), "值应该为'hello world'");
result.message = "成功";
return result;
}
TestResult TransformerTests::testToLSPAnyCString()
{
TestResult result;
result.passed = true;
auto any = transform::LSPAnyConverter::ToLSPAny("test");
assertTrue(any.Is<protocol::string>(), "C字符串应该转换为string类型");
assertEqual(std::string("test"), any.Get<protocol::string>(), "值应该为'test'");
result.message = "成功";
return result;
}
// ==================== ToLSPAny 容器类型测试 ====================
TestResult TransformerTests::testToLSPAnyVector()
{
TestResult result;
result.passed = true;
std::vector<int> vec = { 1, 2, 3, 4, 5 };
auto any = transform::LSPAnyConverter::ToLSPAny(vec);
assertTrue(any.Is<protocol::LSPArray>(), "应该转换为LSPArray类型");
const auto& arr = any.Get<protocol::LSPArray>();
assertEqual(size_t(5), arr.size(), "数组大小应该为5");
assertTrue(arr[0].Is<protocol::integer>(), "元素应该是integer类型");
assertEqual(1, arr[0].Get<protocol::integer>(), "第一个元素应该为1");
assertEqual(5, arr[4].Get<protocol::integer>(), "最后一个元素应该为5");
result.message = "成功";
return result;
}
TestResult TransformerTests::testToLSPAnyMap()
{
TestResult result;
result.passed = true;
std::map<std::string, int> map = { { "a", 1 }, { "b", 2 }, { "c", 3 } };
auto any = transform::LSPAnyConverter::ToLSPAny(map);
assertTrue(any.Is<protocol::LSPObject>(), "应该转换为LSPObject类型");
const auto& obj = any.Get<protocol::LSPObject>();
assertEqual(size_t(3), obj.size(), "对象大小应该为3");
assertTrue(obj.count("a") > 0, "应该包含键'a'");
assertEqual(1, obj.at("a").Get<protocol::integer>(), "键'a'的值应该为1");
result.message = "成功";
return result;
}
TestResult TransformerTests::testToLSPAnyOptionalValue()
{
TestResult result;
result.passed = true;
std::optional<int> opt = 100;
auto any = transform::LSPAnyConverter::ToLSPAny(opt);
assertTrue(any.Is<protocol::integer>(), "有值的optional应该转换为对应类型");
assertEqual(100, any.Get<protocol::integer>(), "值应该为100");
result.message = "成功";
return result;
}
TestResult TransformerTests::testToLSPAnyOptionalNullopt()
{
TestResult result;
result.passed = true;
std::optional<int> opt = std::nullopt;
auto any = transform::LSPAnyConverter::ToLSPAny(opt);
assertTrue(any.Is<std::nullptr_t>(), "nullopt应该转换为null");
result.message = "成功";
return result;
}
// ==================== ToLSPAny LSP类型测试 ====================
TestResult TransformerTests::testToLSPAnyLSPObject()
{
TestResult result;
result.passed = true;
protocol::LSPObject obj;
obj["key"] = protocol::LSPAny(42);
auto any = transform::LSPAnyConverter::ToLSPAny(obj);
assertTrue(any.Is<protocol::LSPObject>(), "应该保持LSPObject类型");
const auto& retrieved = any.Get<protocol::LSPObject>();
assertEqual(size_t(1), retrieved.size(), "对象应该包含1个元素");
result.message = "成功";
return result;
}
TestResult TransformerTests::testToLSPAnyLSPArray()
{
TestResult result;
result.passed = true;
protocol::LSPArray arr;
arr.push_back(protocol::LSPAny(1));
arr.push_back(protocol::LSPAny(2));
auto any = transform::LSPAnyConverter::ToLSPAny(arr);
assertTrue(any.Is<protocol::LSPArray>(), "应该保持LSPArray类型");
const auto& retrieved = any.Get<protocol::LSPArray>();
assertEqual(size_t(2), retrieved.size(), "数组应该包含2个元素");
result.message = "成功";
return result;
}
TestResult TransformerTests::testToLSPAnyLSPAny()
{
TestResult result;
result.passed = true;
protocol::LSPAny original(42);
auto any = transform::LSPAnyConverter::ToLSPAny(original);
assertTrue(any.Is<protocol::integer>(), "应该保持类型");
assertEqual(42, any.Get<protocol::integer>(), "应该保持值");
result.message = "成功";
return result;
}
// ==================== FromLSPAny 基本类型测试 ====================
TestResult TransformerTests::testFromLSPAnyBoolean()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(true);
bool value = transform::LSPAnyConverter::FromLSPAny<bool>(any);
assertEqual(true, value, "应该提取出true");
protocol::LSPAny any_false(false);
bool value_false = transform::LSPAnyConverter::FromLSPAny<bool>(any_false);
assertEqual(false, value_false, "应该提取出false");
result.message = "成功";
return result;
}
TestResult TransformerTests::testFromLSPAnyInteger()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(42);
int value = transform::LSPAnyConverter::FromLSPAny<int>(any);
assertEqual(42, value, "应该提取出42");
result.message = "成功";
return result;
}
TestResult TransformerTests::testFromLSPAnyString()
{
TestResult result;
result.passed = true;
protocol::LSPAny any("test string");
std::string value = transform::LSPAnyConverter::FromLSPAny<std::string>(any);
assertEqual(std::string("test string"), value, "应该提取出'test string'");
result.message = "成功";
return result;
}
TestResult TransformerTests::testFromLSPAnyDouble()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(3.14159);
double value = transform::LSPAnyConverter::FromLSPAny<double>(any);
assertEqual(3.14159, value, "应该提取出3.14159");
result.message = "成功";
return result;
}
// ==================== FromLSPAny 容器类型测试 ====================
TestResult TransformerTests::testFromLSPAnyVector()
{
TestResult result;
result.passed = true;
protocol::LSPArray arr;
arr.push_back(protocol::LSPAny(10));
arr.push_back(protocol::LSPAny(20));
arr.push_back(protocol::LSPAny(30));
protocol::LSPAny any(arr);
auto vec = transform::LSPAnyConverter::FromLSPAny<std::vector<int>>(any);
assertEqual(size_t(3), vec.size(), "vector大小应该为3");
assertEqual(10, vec[0], "第一个元素应该为10");
assertEqual(20, vec[1], "第二个元素应该为20");
assertEqual(30, vec[2], "第三个元素应该为30");
result.message = "成功";
return result;
}
TestResult TransformerTests::testFromLSPAnyOptionalValue()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(42);
auto opt = transform::LSPAnyConverter::FromLSPAny<std::optional<int>>(any);
assertTrue(opt.has_value(), "optional应该有值");
assertEqual(42, opt.value(), "值应该为42");
result.message = "成功";
return result;
}
TestResult TransformerTests::testFromLSPAnyOptionalNull()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(nullptr);
auto opt = transform::LSPAnyConverter::FromLSPAny<std::optional<int>>(any);
assertFalse(opt.has_value(), "optional应该为nullopt");
result.message = "成功";
return result;
}
TestResult TransformerTests::testFromLSPAnyLSPObject()
{
TestResult result;
result.passed = true;
protocol::LSPObject obj;
obj["key1"] = protocol::LSPAny(100);
obj["key2"] = protocol::LSPAny("value");
protocol::LSPAny any(obj);
auto retrieved = transform::LSPAnyConverter::FromLSPAny<protocol::LSPObject>(any);
assertEqual(size_t(2), retrieved.size(), "对象应该有2个键");
assertTrue(retrieved.count("key1") > 0, "应该包含key1");
assertTrue(retrieved.count("key2") > 0, "应该包含key2");
result.message = "成功";
return result;
}
TestResult TransformerTests::testFromLSPAnyLSPArray()
{
TestResult result;
result.passed = true;
protocol::LSPArray arr;
arr.push_back(protocol::LSPAny(1));
arr.push_back(protocol::LSPAny(2));
protocol::LSPAny any(arr);
auto retrieved = transform::LSPAnyConverter::FromLSPAny<protocol::LSPArray>(any);
assertEqual(size_t(2), retrieved.size(), "数组应该有2个元素");
result.message = "成功";
return result;
}
// ==================== 数字类型转换测试 ====================
TestResult TransformerTests::testExtractNumberFromInteger()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(static_cast<protocol::integer>(42));
int value = transform::LSPAnyConverter::FromLSPAny<int>(any);
assertEqual(42, value, "应该从integer提取出42");
result.message = "成功";
return result;
}
TestResult TransformerTests::testExtractNumberFromUInteger()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(static_cast<protocol::uinteger>(100));
unsigned int value = transform::LSPAnyConverter::FromLSPAny<unsigned int>(any);
assertEqual(100u, value, "应该从uinteger提取出100");
result.message = "成功";
return result;
}
TestResult TransformerTests::testExtractNumberFromDecimal()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(static_cast<protocol::decimal>(3.14));
double value = transform::LSPAnyConverter::FromLSPAny<double>(any);
assertEqual(3.14, value, "应该从decimal提取出3.14");
result.message = "成功";
return result;
}
TestResult TransformerTests::testExtractNumberCrossType()
{
TestResult result;
result.passed = true;
// integer -> double
protocol::LSPAny int_any(42);
double double_value = transform::LSPAnyConverter::FromLSPAny<double>(int_any);
assertEqual(42.0, double_value, "integer应该能转换为double");
// uinteger -> int
protocol::LSPAny uint_any(100u);
int int_value = transform::LSPAnyConverter::FromLSPAny<int>(uint_any);
assertEqual(100, int_value, "uinteger应该能转换为int");
result.message = "成功";
return result;
}
// ==================== 错误处理测试 ====================
TestResult TransformerTests::testFromLSPAnyTypeMismatch()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(42);
try
{
// 尝试将integer提取为string应该抛出异常
(void)transform::LSPAnyConverter::FromLSPAny<std::string>(any);
result.passed = false;
result.message = "应该抛出ConversionError异常";
}
catch (const transform::ConversionError& e)
{
// 预期的异常
result.message = "成功";
}
catch (...)
{
result.passed = false;
result.message = "抛出了错误的异常类型";
}
return result;
}
TestResult TransformerTests::testFromLSPAnyInvalidNumber()
{
TestResult result;
result.passed = true;
protocol::LSPAny any("not a number");
try
{
// 尝试将string提取为int应该抛出异常
(void)transform::LSPAnyConverter::FromLSPAny<int>(any);
result.passed = false;
result.message = "应该抛出ConversionError异常";
}
catch (const transform::ConversionError& e)
{
// 预期的异常
result.message = "成功";
}
catch (...)
{
result.passed = false;
result.message = "抛出了错误的异常类型";
}
return result;
}
TestResult TransformerTests::testFromLSPAnyInvalidArray()
{
TestResult result;
result.passed = true;
protocol::LSPAny any(42);
try
{
// 尝试将integer提取为vector应该抛出异常
(void)transform::LSPAnyConverter::FromLSPAny<std::vector<int>>(any);
result.passed = false;
result.message = "应该抛出ConversionError异常";
}
catch (const transform::ConversionError& e)
{
// 预期的异常
result.message = "成功";
}
catch (...)
{
result.passed = false;
result.message = "抛出了错误的异常类型";
}
return result;
}
// ==================== 嵌套结构测试 ====================
TestResult TransformerTests::testNestedVector()
{
TestResult result;
result.passed = true;
std::vector<std::vector<int>> nested = { { 1, 2 }, { 3, 4, 5 } };
auto any = transform::LSPAnyConverter::ToLSPAny(nested);
assertTrue(any.Is<protocol::LSPArray>(), "应该转换为LSPArray");
const auto& arr = any.Get<protocol::LSPArray>();
assertEqual(size_t(2), arr.size(), "外层数组应该有2个元素");
assertTrue(arr[0].Is<protocol::LSPArray>(), "第一个元素应该是LSPArray");
auto result_vec = transform::LSPAnyConverter::FromLSPAny<std::vector<std::vector<int>>>(any);
assertEqual(size_t(2), result_vec.size(), "应该有2个子vector");
assertEqual(size_t(2), result_vec[0].size(), "第一个子vector应该有2个元素");
assertEqual(1, result_vec[0][0], "第一个元素应该为1");
result.message = "成功";
return result;
}
TestResult TransformerTests::testNestedLSPObject()
{
TestResult result;
result.passed = true;
// 直接使用 LSPObject 创建嵌套结构:{"outer": {"inner": 42}}
protocol::LSPObject innerObj;
innerObj["inner"] = protocol::LSPAny(42);
protocol::LSPObject outerObj;
outerObj["outer"] = protocol::LSPAny(innerObj);
auto any = transform::LSPAnyConverter::ToLSPAny(outerObj);
assertTrue(any.Is<protocol::LSPObject>(), "应该保持为LSPObject");
// 提取为 LSPObject然后手动检查嵌套值
auto result_obj = transform::LSPAnyConverter::FromLSPAny<protocol::LSPObject>(any);
assertTrue(result_obj.count("outer") > 0, "应该包含'outer'键");
assertTrue(result_obj.at("outer").Is<protocol::LSPObject>(), "'outer'应该是LSPObject");
const auto& inner_obj = result_obj.at("outer").Get<protocol::LSPObject>();
assertTrue(inner_obj.count("inner") > 0, "应该包含'inner'键");
assertEqual(42, inner_obj.at("inner").Get<protocol::integer>(), "嵌套值应该为42");
result.message = "成功";
return result;
}
TestResult TransformerTests::testMixedTypeNesting()
{
TestResult result;
result.passed = true;
// 直接使用 LSPArray 和 LSPObject 创建混合嵌套结构
protocol::LSPArray arr;
arr.push_back(protocol::LSPAny(1));
arr.push_back(protocol::LSPAny(nullptr)); // 表示 nullopt
arr.push_back(protocol::LSPAny(3));
protocol::LSPObject obj;
obj["data"] = protocol::LSPAny(arr);
auto any = transform::LSPAnyConverter::ToLSPAny(obj);
assertTrue(any.Is<protocol::LSPObject>(), "应该保持为LSPObject");
const auto& retrieved_obj = any.Get<protocol::LSPObject>();
const auto& retrieved_arr = retrieved_obj.at("data").Get<protocol::LSPArray>();
assertEqual(size_t(3), retrieved_arr.size(), "数组应该有3个元素");
assertTrue(retrieved_arr[0].Is<protocol::integer>(), "第一个元素应该是integer");
assertTrue(retrieved_arr[1].Is<std::nullptr_t>(), "第二个元素应该是null");
assertTrue(retrieved_arr[2].Is<protocol::integer>(), "第三个元素应该是integer");
result.message = "成功";
return result;
}
} // namespace lsp::test

View File

@ -0,0 +1,62 @@
#pragma once
#include "test_framework.hpp"
namespace lsp::test
{
// Transformer 转换功能测试类
class TransformerTests
{
public:
static void registerTests(TestRunner& runner);
private:
// ==================== ToLSPAny 基本类型测试 ====================
static TestResult testToLSPAnyBoolean();
static TestResult testToLSPAnyInteger();
static TestResult testToLSPAnyUInteger();
static TestResult testToLSPAnyFloat();
static TestResult testToLSPAnyDouble();
static TestResult testToLSPAnyString();
static TestResult testToLSPAnyCString();
// ==================== ToLSPAny 容器类型测试 ====================
static TestResult testToLSPAnyVector();
static TestResult testToLSPAnyMap();
static TestResult testToLSPAnyOptionalValue();
static TestResult testToLSPAnyOptionalNullopt();
// ==================== ToLSPAny LSP类型测试 ====================
static TestResult testToLSPAnyLSPObject();
static TestResult testToLSPAnyLSPArray();
static TestResult testToLSPAnyLSPAny();
// ==================== FromLSPAny 基本类型测试 ====================
static TestResult testFromLSPAnyBoolean();
static TestResult testFromLSPAnyInteger();
static TestResult testFromLSPAnyString();
static TestResult testFromLSPAnyDouble();
// ==================== FromLSPAny 容器类型测试 ====================
static TestResult testFromLSPAnyVector();
static TestResult testFromLSPAnyOptionalValue();
static TestResult testFromLSPAnyOptionalNull();
static TestResult testFromLSPAnyLSPObject();
static TestResult testFromLSPAnyLSPArray();
// ==================== 数字类型转换测试 ====================
static TestResult testExtractNumberFromInteger();
static TestResult testExtractNumberFromUInteger();
static TestResult testExtractNumberFromDecimal();
static TestResult testExtractNumberCrossType();
// ==================== 错误处理测试 ====================
static TestResult testFromLSPAnyTypeMismatch();
static TestResult testFromLSPAnyInvalidNumber();
static TestResult testFromLSPAnyInvalidArray();
// ==================== 嵌套结构测试 ====================
static TestResult testNestedVector();
static TestResult testNestedLSPObject();
static TestResult testMixedTypeNesting();
};
}