428 lines
14 KiB
C++
428 lines
14 KiB
C++
module;
|
||
|
||
export module lsp.test.lsp_any.facade;
|
||
|
||
import std;
|
||
import glaze;
|
||
import lsp.test.framework;
|
||
import lsp.protocol.common.basic_types;
|
||
import lsp.codec.common;
|
||
import lsp.codec.transformer;
|
||
import lsp.codec.facade;
|
||
|
||
namespace lsp::test
|
||
{
|
||
namespace transform = lsp::codec;
|
||
|
||
// 测试用结构体
|
||
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);
|
||
};
|
||
|
||
export 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();
|
||
};
|
||
}
|
||
|
||
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(std::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
|