Files
2026-09-16 14:07:40 +08:00

590 lines
15 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file test_misc.cpp
* @brief misc 模块单元测试(Value、Locator、Timer、Layout、AStar、CodeWriter
*
*
* @version 1.0
* @author CodeBuddy
* @date 26-09-03
*
* @note
*/
#include <gtest/gtest.h>
#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 <OpenXLSX.hpp>
//------------------------------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<int, 3>{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<int, 3>"), dl::ValueType::ARRAY);
EXPECT_EQ(dl::String2ValueType("vector<int>"), dl::ValueType::VECTOR);
EXPECT_EQ(dl::String2ValueType("MyStruct"), dl::ValueType::STRUCT);
}
TEST(ValueTest, String2ValueTypeEx)
{
auto info = dl::String2ValueTypeEx("array<int, 3>");
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<float>");
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<int, 3>");
}
//------------------------------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<dl::Point, int> astar(dl::Point{}, g);
astar.SetSize({ 5, 5 });
std::list<dl::Point> 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<dl::Point, int> astar(dl::Point{}, g);
astar.SetSize({ 5, 5 });
std::list<dl::Point> 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<dl::Position{32.0f, 32.0f}> 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<dl::Position{32.0f, 32.0f}> 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);
}