/** * @file test_misc.cpp * @brief misc 模块单元测试(Value、Locator、Timer、Layout、AStar、CodeWriter) * * * @version 1.0 * @author CodeBuddy * @date 26-09-03 * * @note */ #include #include "dl_type.h" #include "misc/dl_value.h" #include "misc/dl_locator.h" #include "misc/dl_layout.h" #include "misc/dl_timer.h" #include "misc/dl_astar.h" #include "misc/dl_code_writer.h" #include "misc/dl_tilemap.h" #include "misc/dl_json_config.h" #include "misc/dl_language.h" #include "io/dl_file.h" #include "render/dl_factory.h" #include //------------------------------Value------------------------------ TEST(ValueTest, DefaultNone) { dl::Value v; EXPECT_EQ(v.GetType(), dl::ValueType::NONE); EXPECT_FALSE(v); EXPECT_EQ(v.GetString(), "null"); } TEST(ValueTest, Bool) { dl::Value v(true); EXPECT_EQ(v.GetType(), dl::ValueType::BOOL); EXPECT_TRUE(v.ToBool()); EXPECT_EQ(v.GetString(), "true"); dl::Value vf(false); EXPECT_FALSE(vf.ToBool()); EXPECT_EQ(vf.GetString(), "false"); } TEST(ValueTest, Int) { dl::Value v(42); EXPECT_EQ(v.GetType(), dl::ValueType::INT); EXPECT_EQ(v.ToInt(), 42); EXPECT_FLOAT_EQ(v.ToFloat(), 42.0f); EXPECT_DOUBLE_EQ(v.ToDouble(), 42.0); EXPECT_EQ(v.GetString(), "42"); } TEST(ValueTest, FloatDouble) { dl::Value vf(3.14f); EXPECT_EQ(vf.GetType(), dl::ValueType::FLOAT); EXPECT_FLOAT_EQ(vf.ToFloat(), 3.14f); dl::Value vd(3.14); EXPECT_EQ(vd.GetType(), dl::ValueType::DOUBLE); EXPECT_DOUBLE_EQ(vd.ToDouble(), 3.14); } TEST(ValueTest, String) { dl::Value v("hello"); EXPECT_EQ(v.GetType(), dl::ValueType::STRING); EXPECT_EQ(v.ToString(), "hello"); EXPECT_EQ(v.GetString(), "\"hello\""); EXPECT_EQ(v.GetString(false), "hello"); } TEST(ValueTest, CopyString) { dl::Value a(std::string("hello")); dl::Value b = a; EXPECT_EQ(b.GetType(), dl::ValueType::STRING); EXPECT_EQ(b.ToString(), "hello"); } TEST(ValueTest, Vector) { dl::ValueVector vec(dl::ValueType::INT); vec.PushBack(1); vec.PushBack(2); vec.PushBack(3); dl::Value v(vec); EXPECT_EQ(v.GetType(), dl::ValueType::VECTOR); EXPECT_EQ(v.GetString(), "{ 1, 2, 3 }"); auto j = v.GetJson(); ASSERT_TRUE(j.is_array()); ASSERT_EQ(j.size(), 3u); EXPECT_EQ(j[0], 1); EXPECT_EQ(j[2], 3); } TEST(ValueTest, Array) { dl::Value v(std::array{10, 20, 30}); EXPECT_EQ(v.GetType(), dl::ValueType::ARRAY); auto arr = v.ToArray<3>(); EXPECT_EQ(arr[0].ToInt(), 10); EXPECT_EQ(arr[1].ToInt(), 20); EXPECT_EQ(arr[2].ToInt(), 30); } TEST(ValueTest, Struct) { dl::ValueStruct s("student"); dl::Value v_id(100); dl::Value v_name("tom"); s.AddMember("id", v_id); s.AddMember("name", v_name); EXPECT_EQ(s.GetName(), "student"); EXPECT_EQ(s["id"].ToInt(), 100); EXPECT_EQ(s.GetMember("name").ToString(), "tom"); } TEST(ValueTest, CastFailed) { dl::Value v("hello"); EXPECT_EQ(v.ToInt(), 0); EXPECT_FLOAT_EQ(v.ToFloat(), 0.0f); EXPECT_FALSE(v.ToBool()); } TEST(ValueTest, OperatorBool) { dl::Value v_none; EXPECT_FALSE(v_none); dl::Value v_false(false); EXPECT_FALSE(v_false); dl::Value v_true(true); EXPECT_TRUE(v_true); dl::Value v_int(0); EXPECT_TRUE(v_int); // 非 NONE/BOOL 恒为真 } //------------------------------类型转换------------------------------ TEST(ValueTest, String2ValueType) { EXPECT_EQ(dl::String2ValueType("bool"), dl::ValueType::BOOL); EXPECT_EQ(dl::String2ValueType("int"), dl::ValueType::INT); EXPECT_EQ(dl::String2ValueType("uint"), dl::ValueType::UINT); EXPECT_EQ(dl::String2ValueType("int64"), dl::ValueType::INT64); EXPECT_EQ(dl::String2ValueType("float"), dl::ValueType::FLOAT); EXPECT_EQ(dl::String2ValueType("double"), dl::ValueType::DOUBLE); EXPECT_EQ(dl::String2ValueType("string"), dl::ValueType::STRING); EXPECT_EQ(dl::String2ValueType("array"), dl::ValueType::ARRAY); EXPECT_EQ(dl::String2ValueType("vector"), dl::ValueType::VECTOR); EXPECT_EQ(dl::String2ValueType("MyStruct"), dl::ValueType::STRUCT); } TEST(ValueTest, String2ValueTypeEx) { auto info = dl::String2ValueTypeEx("array"); EXPECT_EQ(info._type0, dl::ValueType::ARRAY); EXPECT_EQ(info._type1, dl::ValueType::INT); EXPECT_EQ(info._length, 3u); EXPECT_EQ(info._strType1, "int"); auto info2 = dl::String2ValueTypeEx("vector"); EXPECT_EQ(info2._type0, dl::ValueType::VECTOR); EXPECT_EQ(info2._type1, dl::ValueType::FLOAT); EXPECT_EQ(info2._length, 0u); } TEST(ValueTest, ToStringType) { EXPECT_EQ(dl::to_string(dl::ValueType::NONE), "null"); EXPECT_EQ(dl::to_string(dl::ValueType::INT), "int"); EXPECT_EQ(dl::to_string(dl::ValueType::STRING), "string"); EXPECT_EQ(dl::to_string(dl::ValueType::ARRAY), "array"); EXPECT_EQ(dl::to_string(dl::ValueType::MAP), "map"); } TEST(ValueTest, Type2CppType) { EXPECT_EQ(dl::Type2CppType(dl::ValueType::INT), "int"); EXPECT_EQ(dl::Type2CppType(dl::ValueType::UINT), "unsigned"); EXPECT_EQ(dl::Type2CppType(dl::ValueType::UCHAR), "unsigned char"); EXPECT_EQ(dl::Type2CppType(dl::ValueType::STRING), "std::string"); EXPECT_EQ(dl::Type2CppType(dl::ValueType::ARRAY), "std::array"); EXPECT_EQ(dl::Type2CppType(dl::ValueType::VECTOR), "std::vector"); EXPECT_EQ(dl::Type2CppType(dl::ValueType::POINTER), "void*"); EXPECT_EQ(dl::Type2CppTypeEx(dl::ValueType::ARRAY, dl::ValueType::INT, 3), "std::array"); } //------------------------------Layout------------------------------ TEST(LayoutTest, String2Layout) { EXPECT_EQ(dl::String2Layout("x"), dl::Layout::X); EXPECT_EQ(dl::String2Layout("y"), dl::Layout::Y); EXPECT_EQ(dl::String2Layout("xy"), dl::Layout::XY); EXPECT_EQ(dl::String2Layout("origin"), dl::Layout::ORIGIN); EXPECT_EQ(dl::String2Layout("X"), dl::Layout::X); EXPECT_EQ(dl::String2Layout("XY"), dl::Layout::XY); } //------------------------------Locator------------------------------ TEST(LocatorTest, DirectX) { auto loc = dl::createLocatorX(10.0f); EXPECT_FLOAT_EQ(loc.Get(0)[0], 0.0f); EXPECT_FLOAT_EQ(loc.Get(0)[1], 0.0f); EXPECT_FLOAT_EQ(loc.Get(1)[0], 10.0f); EXPECT_FLOAT_EQ(loc.Get(2)[0], 20.0f); } TEST(LocatorTest, DirectXWrap) { auto loc = dl::createLocatorX(10.0f, 3); EXPECT_FLOAT_EQ(loc.Get(0)[0], 0.0f); EXPECT_FLOAT_EQ(loc.Get(1)[0], 10.0f); EXPECT_FLOAT_EQ(loc.Get(2)[0], 20.0f); auto p3 = loc.Get(3); EXPECT_FLOAT_EQ(p3[0], 0.0f); EXPECT_FLOAT_EQ(p3[1], 32.0f); } TEST(LocatorTest, DirectY) { auto loc = dl::createLocatorY(10.0f); EXPECT_FLOAT_EQ(loc.Get(0)[1], 0.0f); EXPECT_FLOAT_EQ(loc.Get(1)[1], 10.0f); EXPECT_FLOAT_EQ(loc.Get(2)[1], 20.0f); } TEST(LocatorTest, DirectXY) { dl::Locator::SL sl; sl._dt = { 10.0f, 20.0f }; sl._layout = dl::Layout::XY; dl::Locator loc(sl); auto p = loc.Get(3); EXPECT_FLOAT_EQ(p[0], 30.0f); EXPECT_FLOAT_EQ(p[1], 60.0f); } TEST(LocatorTest, Origin) { auto loc = dl::createLocatorZero(); auto p = loc.Get(5); EXPECT_FLOAT_EQ(p[0], 0.0f); EXPECT_FLOAT_EQ(p[1], 0.0f); } TEST(LocatorTest, AdaptX) { auto loc = dl::createLocatorX(10.0f, 0, 32.0f, dl::Locator::Mode::ADAPT); dl::Size s{ 10, 10 }; auto p0 = loc.Get(s); EXPECT_FLOAT_EQ(p0[0], 0.0f); auto p1 = loc.Get(s); EXPECT_FLOAT_EQ(p1[0], 20.0f); } TEST(LocatorTest, ExGet) { auto loc = dl::createLocatorX(10.0f); dl::Position pos{ 5.0f, 5.0f }; EXPECT_TRUE(loc.ExGet(2, dl::Size{}, pos)); EXPECT_FLOAT_EQ(pos[0], 25.0f); EXPECT_FLOAT_EQ(pos[1], 5.0f); } //------------------------------Timer------------------------------ TEST(TimerTest, Regular) { dl::TimerRegular t(2.0f); EXPECT_FALSE(t.Run(1.0f)); EXPECT_FALSE(t.Run(0.5f)); EXPECT_TRUE(t.Run(0.5f)); EXPECT_FALSE(t.Run(0.1f)); } TEST(TimerTest, Reverse) { dl::TimerReverse t(1.0f); EXPECT_FALSE(t.Run(0.5f)); EXPECT_TRUE(t.Run(0.5f)); EXPECT_TRUE(t.Run(0.5f)); EXPECT_FALSE(t.Run(0.5f)); } //------------------------------AStar------------------------------ TEST(AStarTest, Search) { auto g = [](const dl::Point& a, const dl::Point& b) -> int { return 10; }; dl::AStar astar(dl::Point{}, g); astar.SetSize({ 5, 5 }); std::list path; EXPECT_TRUE(astar.Search({ 0, 0 }, { 4, 4 }, false, path)); EXPECT_FALSE(path.empty()); EXPECT_EQ(path.front(), (dl::Point{ 0, 0 })); EXPECT_EQ(path.back(), (dl::Point{ 4, 4 })); } TEST(AStarTest, SearchBlocked) { auto g = [](const dl::Point& a, const dl::Point& b) -> int { if (b.x == 2) return 0; // x=2 整列不可通行 return 10; }; dl::AStar astar(dl::Point{}, g); astar.SetSize({ 5, 5 }); std::list path; EXPECT_FALSE(astar.Search({ 0, 0 }, { 4, 4 }, false, path)); } //------------------------------CodeWriter------------------------------ TEST(CodeWriterTest, IsStdType) { EXPECT_TRUE(dl::CodeWriter::IsStdType("string")); EXPECT_FALSE(dl::CodeWriter::IsStdType("int")); } TEST(CodeWriterTest, AddStdNamespace) { std::string s = "string"; dl::CodeWriter::AddStdNamespace(s); EXPECT_EQ(s, "std::string"); std::string i = "int"; dl::CodeWriter::AddStdNamespace(i); EXPECT_EQ(i, "int"); } TEST(CodeWriterTest, ReplaceType) { std::string s = "uchar"; dl::CodeWriter::ReplaceType(s); EXPECT_EQ(s, "unsigned char"); std::string i = "int64"; dl::CodeWriter::ReplaceType(i); EXPECT_EQ(i, "int64_t"); std::string i2 = "int32"; dl::CodeWriter::ReplaceType(i2); EXPECT_EQ(i2, "int32_t"); } TEST(CodeWriterTest, StructGetVariable) { dl::CodeWriter::Struct s; s._name = "Student"; s._value = "stu"; dl::CodeWriter::Variable v; v._name = "id"; v._type = "int"; s._allVariable.push_back(v); auto* p = s.GetVariable("id"); ASSERT_NE(p, nullptr); EXPECT_EQ(p->_type, "int"); EXPECT_EQ(s.GetVariable("none"), nullptr); } TEST(CodeWriterTest, SegmentGetStruct) { dl::CodeWriter::Segment seg; dl::CodeWriter::Struct s; s._name = "Student"; s._value = "stu"; dl::CodeWriter::Variable v; v._name = "id"; v._type = "int"; s._allVariable.push_back(v); seg._allStruct.push_back(s); auto* ps = seg.GetStruct("Student"); ASSERT_NE(ps, nullptr); EXPECT_EQ(ps->_value, "stu"); auto* pv = seg.GetVariable("Student", "id"); ASSERT_NE(pv, nullptr); EXPECT_EQ(pv->_type, "int"); EXPECT_EQ(seg.GetStruct("None"), nullptr); EXPECT_EQ(seg.GetVariable("Student", "none"), nullptr); } TEST(CodeWriterTest, StructFormatVariable) { dl::CodeWriter::Struct s; s._name = "Test"; s._value = "t"; dl::CodeWriter::Variable v1; v1._name = "a"; v1._type = "int"; dl::CodeWriter::Variable v2; v2._name = "long_name"; v2._type = "std::string"; s._allVariable.push_back(v1); s._allVariable.push_back(v2); s.FormatVariable(); // 对齐后,短的名字/类型会被补 tab,长度不小于 4 EXPECT_GE(s._allVariable[0]._name.size(), 4u); EXPECT_GE(s._allVariable[1]._name.size(), 4u); EXPECT_GE(s._allVariable[0]._type.size(), 4u); EXPECT_GE(s._allVariable[1]._type.size(), 4u); EXPECT_EQ(s._allVariable[0]._name.back(), '\t'); EXPECT_EQ(s._allVariable[1]._name.back(), '\t'); EXPECT_EQ(s._allVariable[0]._type.back(), '\t'); EXPECT_EQ(s._allVariable[1]._type.back(), '\t'); } //------------------------------TileMap------------------------------ TEST(TileMapTest, Rectangle) { dl::TileMap::Rectangle map; auto world = map.Map2World(dl::Point{1, 2}); EXPECT_FLOAT_EQ(world[0], 32.0f); EXPECT_FLOAT_EQ(world[1], 64.0f); auto mp = map.World2Map(dl::Position{32.0f, 64.0f}); EXPECT_EQ(mp[0], 1); EXPECT_EQ(mp[1], 2); } TEST(TileMapTest, DiamondSlant) { dl::TileMap::DiamondSlant map; auto world = map.Map2World(dl::Point{0, 0}); EXPECT_FLOAT_EQ(world[0], 0.0f); EXPECT_FLOAT_EQ(world[1], 0.0f); auto world2 = map.Map2World(dl::Point{1, 0}); EXPECT_FLOAT_EQ(world2[0], 16.0f); EXPECT_FLOAT_EQ(world2[1], -16.0f); } //------------------------------JsonConfig------------------------------ TEST(JsonConfigTest, LoadFailed) { dl::JsonConfig cfg; EXPECT_FALSE(cfg.Load("/nonexistent/path/file.json")); } TEST(JsonConfigTest, LoadGenerateCode) { std::string path = dl::g_factory->GetPathTemp() + "dl_json_config_test.json"; std::string json_str = R"({ "name": "测试配置", "desc": "配置描述", "type": "config", "value": { "speed": { "name": "速度", "desc": "移动速度", "type": "int", "value": 100 }, "title": { "name": "标题", "type": "string", "value": "hello" } } })"; ASSERT_TRUE(dl::File::SaveString(json_str, path)); dl::JsonConfig cfg; ASSERT_TRUE(cfg.Load(path)); dl::JsonConfig::GenerateParam p; p._filename = "test.h"; p._brief = "测试"; p._author = "tester"; p._date = "2026"; p._logFunction = "log_err"; p._namespace = "test"; std::string code = cfg.GenerateCode(p); EXPECT_FALSE(code.empty()); EXPECT_NE(code.find("struct config"), std::string::npos); EXPECT_NE(code.find("int speed"), std::string::npos); dl::File::Delete(path); } TEST(JsonConfigTest, GenerateConfigUser) { std::string path = dl::g_factory->GetPathTemp() + "dl_json_config_test.json"; std::string json_str = R"({ "name": "测试配置", "type": "config", "value": { "speed": { "type": "int", "value": 100 } } })"; ASSERT_TRUE(dl::File::SaveString(json_str, path)); dl::JsonConfig cfg; ASSERT_TRUE(cfg.Load(path)); std::string user = cfg.GenerateConfigUser(); EXPECT_FALSE(user.empty()); EXPECT_NE(user.find("speed"), std::string::npos); EXPECT_NE(user.find("100"), std::string::npos); dl::File::Delete(path); } //------------------------------Language------------------------------ TEST(LanguageTest, LoadGet) { std::string path = dl::g_factory->GetPathTemp() + "dl_language_test.xlsx"; // 用 OpenXLSX 写临时 xlsx:第0列 tag、第1列 name、第2+列语言 { OpenXLSX::XLDocument doc; doc.create(path); auto wks = doc.workbook().worksheet("Sheet1"); wks.cell(1, 1).value() = "tag"; wks.cell(1, 2).value() = "name"; wks.cell(1, 3).value() = "English"; wks.cell(1, 4).value() = "简体中文"; wks.cell(2, 1).value() = "menu"; wks.cell(2, 2).value() = "start"; wks.cell(2, 3).value() = "Start"; wks.cell(2, 4).value() = "开始"; wks.cell(3, 1).value() = "menu"; wks.cell(3, 2).value() = "exit"; wks.cell(3, 3).value() = "Exit"; wks.cell(3, 4).value() = "退出"; doc.save(); doc.close(); } dl::Language lang; lang.LoadXlsx(path); // 英文 lang.SetLangCurrent(dl::Language::E_ENGLISH); EXPECT_EQ(lang.Get("menu", "start"), "Start"); EXPECT_EQ(lang.Get("menu", "exit"), "Exit"); // 中文 lang.SetLangCurrent(dl::Language::E_CHINESE); EXPECT_EQ(lang.Get("menu", "start"), "开始"); EXPECT_EQ(lang.Get("menu", "exit"), "退出"); // 失败返回特定字符串 EXPECT_EQ(lang.Get("nottag", "start"), "not_find_tag"); EXPECT_EQ(lang.Get("menu", "notname"), "not_find"); // GetCheck auto check = lang.GetCheck("menu", "start"); ASSERT_TRUE(check.has_value()); EXPECT_EQ(*check, "开始"); EXPECT_FALSE(lang.GetCheck("menu", "none").has_value()); // GetTagSize EXPECT_EQ(lang.GetTagSize("menu"), 2u); // GetTagMap auto m = lang.GetTagMap("menu"); EXPECT_EQ(m.size(), 2u); EXPECT_EQ(m["start"], "开始"); EXPECT_EQ(m["exit"], "退出"); // GetLangAll const auto& langs = lang.GetLangAll(); ASSERT_EQ(langs.size(), 2u); EXPECT_EQ(langs[0], "English"); dl::File::Delete(path); }