#include "gmock/gmock.h" #include #include #include #include #include #include "testing_util.hpp" namespace { using namespace testing; TEST(LuaSerializationTest, Nil) { sol::state lua; EXPECT_EQ(LuaUtil::serialize(sol::nil), ""); EXPECT_EQ(LuaUtil::deserialize(lua, ""), sol::nil); } TEST(LuaSerializationTest, Number) { sol::state lua; std::string serialized = LuaUtil::serialize(sol::make_object(lua, 3.14)); EXPECT_EQ(serialized.size(), 10); // version, type, 8 bytes value sol::object value = LuaUtil::deserialize(lua, serialized); ASSERT_TRUE(value.is()); EXPECT_FLOAT_EQ(value.as(), 3.14); } TEST(LuaSerializationTest, Boolean) { sol::state lua; { std::string serialized = LuaUtil::serialize(sol::make_object(lua, true)); EXPECT_EQ(serialized.size(), 3); // version, type, 1 byte value sol::object value = LuaUtil::deserialize(lua, serialized); EXPECT_FALSE(value.is()); ASSERT_TRUE(value.is()); EXPECT_TRUE(value.as()); } { std::string serialized = LuaUtil::serialize(sol::make_object(lua, false)); EXPECT_EQ(serialized.size(), 3); // version, type, 1 byte value sol::object value = LuaUtil::deserialize(lua, serialized); EXPECT_FALSE(value.is()); ASSERT_TRUE(value.is()); EXPECT_FALSE(value.as()); } } TEST(LuaSerializationTest, String) { sol::state lua; std::string_view emptyString = ""; std::string_view shortString = "abc"; std::string_view longString = "It is a string with more than 32 characters..........................."; { std::string serialized = LuaUtil::serialize(sol::make_object(lua, emptyString)); EXPECT_EQ(serialized.size(), 2); // version, type sol::object value = LuaUtil::deserialize(lua, serialized); ASSERT_TRUE(value.is()); EXPECT_EQ(value.as(), emptyString); } { std::string serialized = LuaUtil::serialize(sol::make_object(lua, shortString)); EXPECT_EQ(serialized.size(), 2 + shortString.size()); // version, type, str data sol::object value = LuaUtil::deserialize(lua, serialized); ASSERT_TRUE(value.is()); EXPECT_EQ(value.as(), shortString); } { std::string serialized = LuaUtil::serialize(sol::make_object(lua, longString)); EXPECT_EQ(serialized.size(), 6 + longString.size()); // version, type, size, str data sol::object value = LuaUtil::deserialize(lua, serialized); ASSERT_TRUE(value.is()); EXPECT_EQ(value.as(), longString); } } TEST(LuaSerializationTest, Vector) { sol::state lua; osg::Vec2f vec2(1, 2); osg::Vec3f vec3(1, 2, 3); { std::string serialized = LuaUtil::serialize(sol::make_object(lua, vec2)); EXPECT_EQ(serialized.size(), 10); // version, type, 2x float sol::object value = LuaUtil::deserialize(lua, serialized); ASSERT_TRUE(value.is()); EXPECT_EQ(value.as(), vec2); } { std::string serialized = LuaUtil::serialize(sol::make_object(lua, vec3)); EXPECT_EQ(serialized.size(), 14); // version, type, 3x float sol::object value = LuaUtil::deserialize(lua, serialized); ASSERT_TRUE(value.is()); EXPECT_EQ(value.as(), vec3); } } TEST(LuaSerializationTest, Table) { sol::state lua; sol::table table(lua, sol::create); table["aa"] = 1; table["ab"] = true; table["nested"] = sol::table(lua, sol::create); table["nested"]["aa"] = 2; table["nested"]["bb"] = "something"; table["nested"][5] = -0.5; table["nested_empty"] = sol::table(lua, sol::create); table[1] = osg::Vec2f(1, 2); table[2] = osg::Vec2f(2, 1); std::string serialized = LuaUtil::serialize(table); EXPECT_EQ(serialized.size(), 123); sol::table res_table = LuaUtil::deserialize(lua, serialized); EXPECT_EQ(res_table.get("aa"), 1); EXPECT_EQ(res_table.get("ab"), true); EXPECT_EQ(res_table.get("nested").get("aa"), 2); EXPECT_EQ(res_table.get("nested").get("bb"), "something"); EXPECT_FLOAT_EQ(res_table.get("nested").get(5), -0.5); EXPECT_EQ(res_table.get(1), osg::Vec2f(1, 2)); EXPECT_EQ(res_table.get(2), osg::Vec2f(2, 1)); } struct TestStruct1 { double a, b; }; struct TestStruct2 { int a, b; }; class TestSerializer final : public LuaUtil::UserdataSerializer { bool serialize(LuaUtil::BinaryData& out, const sol::userdata& data) const override { if (data.is()) { TestStruct1 t = data.as(); t.a = Misc::toLittleEndian(t.a); t.b = Misc::toLittleEndian(t.b); append(out, "ts1", &t, sizeof(t)); return true; } if (data.is()) { TestStruct2 t = data.as(); t.a = Misc::toLittleEndian(t.a); t.b = Misc::toLittleEndian(t.b); append(out, "test_struct2", &t, sizeof(t)); return true; } return false; } bool deserialize(std::string_view typeName, std::string_view binaryData, sol::state& lua) const override { if (typeName == "ts1") { if (sizeof(TestStruct1) != binaryData.size()) throw std::runtime_error("Incorrect binaryData.size() for TestStruct1: " + std::to_string(binaryData.size())); TestStruct1 t = *reinterpret_cast(binaryData.data()); t.a = Misc::fromLittleEndian(t.a); t.b = Misc::fromLittleEndian(t.b); sol::stack::push(lua, t); return true; } if (typeName == "test_struct2") { if (sizeof(TestStruct2) != binaryData.size()) throw std::runtime_error("Incorrect binaryData.size() for TestStruct2: " + std::to_string(binaryData.size())); TestStruct2 t = *reinterpret_cast(binaryData.data()); t.a = Misc::fromLittleEndian(t.a); t.b = Misc::fromLittleEndian(t.b); sol::stack::push(lua, t); return true; } return false; } }; TEST(LuaSerializationTest, UserdataSerializer) { sol::state lua; sol::table table(lua, sol::create); table["x"] = TestStruct1{1.5, 2.5}; table["y"] = TestStruct2{4, 3}; TestSerializer serializer; EXPECT_ERROR(LuaUtil::serialize(table), "Unknown userdata"); std::string serialized = LuaUtil::serialize(table, &serializer); EXPECT_ERROR(LuaUtil::deserialize(lua, serialized), "Unknown type:"); sol::table res = LuaUtil::deserialize(lua, serialized, &serializer); TestStruct1 rx = res.get("x"); TestStruct2 ry = res.get("y"); EXPECT_EQ(rx.a, 1.5); EXPECT_EQ(rx.b, 2.5); EXPECT_EQ(ry.a, 4); EXPECT_EQ(ry.b, 3); } }