#include #include "common/serde/Serde.h" #include "common/utils/DownwardBytes.h" #include "common/utils/Reflection.h" #include "common/utils/Result.h" #include "common/utils/RobinHood.h" #include "common/utils/StrongType.h" #include "fbs/mgmtd/RoutingInfo.h" #include "tests/GtestHelpers.h" namespace hf3fs::test { namespace { bool checkValue(float b) { return b > 10.0; } struct CheckString { constexpr CheckString() = default; constexpr bool operator()(const std::string &str) const { return !str.empty(); } }; struct Demo { SERDE_CLASS_FIELD(a, short{10}, [](short a) { return a > 0; }); // checker is lambda expr. SERDE_CLASS_FIELD(b, 20.0f, checkValue); // checker is function pointer. SERDE_CLASS_FIELD(c, std::string{"ok"}, CheckString{}); // checker is function object. }; static_assert(serde::count() == 3); static_assert(serde::name() == "a"); static_assert(serde::name() == "b"); static_assert(serde::name() == "c"); static_assert(serde::SerdeType); static_assert(!serde::SerdeType); TEST(TestSerde, Normal) { const Demo demo; ASSERT_EQ(serde::name<0>(demo), "a"); ASSERT_EQ(serde::name<1>(demo), "b"); ASSERT_EQ(serde::name<2>(demo), "c"); ASSERT_EQ(serde::value<0>(demo), 10); ASSERT_EQ(serde::value<1>(demo), 20.0); ASSERT_EQ(serde::value<2>(demo), "ok"); ASSERT_EQ(&serde::value<0>(demo), &demo.a()); ASSERT_EQ(&serde::value<1>(demo), &demo.b()); ASSERT_EQ(&serde::value<2>(demo), &demo.c()); } TEST(TestSerde, Serialize) { Demo demo; demo.a() = 100; demo.b() = 200.f; demo.c() = "hello"; const Demo &d = demo; auto out = serde::serialize(d); ASSERT_EQ(out.length(), serde::serializeLength(d)); constexpr auto size = 1 + 2 + 4 + 1 + 5; // struct size + short + float + str length + str content. ASSERT_EQ(out.length(), size); XLOGF(INFO, "out is {:02X}", fmt::join(out, ",")); Demo des; ASSERT_EQ(des.a(), 10); ASSERT_EQ(des.b(), 20.f); ASSERT_EQ(des.c(), "ok"); ASSERT_OK(serde::deserialize(des, out)); ASSERT_EQ(des.a(), 100); ASSERT_EQ(des.b(), 200.f); ASSERT_EQ(des.c(), "hello"); } struct Nested { SERDE_CLASS_FIELD(a, Demo{}); SERDE_CLASS_FIELD(b, Demo{}); }; TEST(TestSerde, Serialize2) { Nested nested; nested.b().a() = 100; nested.b().b() = 200.f; nested.b().c() = "hello"; auto out = serde::serialize(nested); ASSERT_EQ(out.length(), serde::serializeLength(nested)); constexpr auto size = 1 + (1 + 2 + 4 + 1 + 2) + (1 + 2 + 4 + 1 + 5); ASSERT_EQ(out.length(), size); Nested des; ASSERT_EQ(des.a().a(), des.b().a()); ASSERT_EQ(des.a().b(), des.b().b()); ASSERT_EQ(des.a().c(), des.b().c()); ASSERT_OK(serde::deserialize(des, out)); ASSERT_EQ(des.a().a(), 10); ASSERT_EQ(des.a().b(), 20.f); ASSERT_EQ(des.a().c(), "ok"); ASSERT_EQ(des.b().a(), 100); ASSERT_EQ(des.b().b(), 200.f); ASSERT_EQ(des.b().c(), "hello"); } TEST(TestSerde, Vector) { struct Test { SERDE_CLASS_FIELD(a, (std::vector{0, 1, 2})); SERDE_CLASS_FIELD(b, (std::vector{"x", "y"})); }; Test a; auto out = serde::serialize(a); ASSERT_EQ(out.length(), serde::serializeLength(a)); ASSERT_EQ(out.size(), 1 + 1 + 4 * 3 + 1 + 2 * (1 + 1)); // struct size + vsize + int * 3 + vsize + 2 * (ssize + c) a.a() = std::vector{0, 1, 0, 1}; a.b() = std::vector{"a", "b", "c", "d"}; out = serde::serialize(a); Test b; ASSERT_NE(b.a(), a.a()); ASSERT_NE(b.b(), a.b()); ASSERT_OK(serde::deserialize(b, out)); ASSERT_EQ(b.a(), a.a()); ASSERT_EQ(b.b(), a.b()); } TEST(TestSerde, Vector2) { struct Item { SERDE_STRUCT_FIELD(a, uint32_t{}); SERDE_STRUCT_FIELD(b, std::string{}); }; struct Vector { SERDE_STRUCT_FIELD(vec, std::vector{}); }; Vector vec; vec.vec.push_back({1, "one"}); vec.vec.push_back({2, "two"}); XLOGF(INFO, "vec is {}", vec); } TEST(TestSerde, Vector3) { struct Item { SERDE_STRUCT_FIELD(a, std::vector{}); }; Item item; item.a.push_back(2); item.a.push_back(0); item.a.push_back(2); item.a.push_back(3); auto out = serde::serialize(item); ASSERT_EQ(out.size(), 18); ASSERT_EQ(out[0], 17); ASSERT_EQ(out[1], 4); Item des; ASSERT_OK(serde::deserialize(des, out)); ASSERT_EQ(item.a, des.a); } TEST(TestSerde, Set) { struct Test { SERDE_CLASS_FIELD(a, (std::set{0, 1, 2})); SERDE_CLASS_FIELD(b, (std::set{"x", "y"})); }; Test a; auto out = serde::serialize(a); ASSERT_EQ(out.length(), serde::serializeLength(a)); ASSERT_EQ(out.size(), 1 + 1 + 4 * 3 + 1 + 2 * (1 + 1)); a.a() = std::set{0, 1, 0, 1}; a.b() = std::set{"a", "b", "c", "d"}; out = serde::serialize(a); Test b; ASSERT_NE(b.a(), a.a()); ASSERT_NE(b.b(), a.b()); ASSERT_OK(serde::deserialize(b, out)); ASSERT_EQ(b.a(), a.a()); ASSERT_EQ(b.b(), a.b()); } TEST(TestSerde, Map) { struct Test { SERDE_CLASS_FIELD(a, (std::map{})); SERDE_CLASS_FIELD(b, (robin_hood::unordered_map{})); }; Test a; auto out = serde::serialize(a); ASSERT_EQ(out.length(), serde::serializeLength(a)); ASSERT_EQ(out.size(), 1 + 1 + 1); a.a()[1] = 2; a.a()[3] = 4; a.b()["hello"] = "world"; a.b()["nice to"] = "meet you"; out = serde::serialize(a); ASSERT_EQ(out.size(), 1 + 1 + 4 * 4 + 1 + 4 * 1 + 5 + 5 + 7 + 8); Test b; ASSERT_NE(b.a(), a.a()); ASSERT_NE(b.b(), a.b()); ASSERT_OK(serde::deserialize(b, out)); ASSERT_EQ(b.a(), a.a()); ASSERT_EQ(b.b(), a.b()); } TEST(TestSerde, Optional) { struct Test { SERDE_CLASS_FIELD(a, std::optional{}); SERDE_CLASS_FIELD(b, std::optional{"OK"}); }; Test a; auto out = serde::serialize(a); ASSERT_EQ(out.length(), serde::serializeLength(a)); ASSERT_EQ(out.size(), 1 + 1 + 1 + 1 + 2); a.a() = "hello"; a.b() = std::nullopt; out = serde::serialize(a); ASSERT_EQ(out.size(), 1 + 1 + 1 + 5 + 1); Test b; ASSERT_NE(b.a(), a.a()); ASSERT_NE(b.b(), a.b()); ASSERT_OK(serde::deserialize(b, out)); ASSERT_EQ(b.a(), a.a()); ASSERT_EQ(b.b(), a.b()); } TEST(TestSerde, Variant) { struct Test { SERDE_CLASS_FIELD(a, (std::variant{})); }; Test a; auto out = serde::serialize(a); ASSERT_EQ(out.length(), serde::serializeLength(a)); ASSERT_EQ(out.size(), 1 + 1 + 3 + 4); a.a() = "hello"; out = serde::serialize(a); ASSERT_EQ(out.size(), 1 + 1 + 12 + 1 + 5); Test b; ASSERT_NE(b.a(), a.a()); ASSERT_OK(serde::deserialize(b, out)); ASSERT_EQ(b.a(), a.a()); } TEST(TestSerde, Compatibility) { struct Test { SERDE_CLASS_FIELD(a, std::optional{}); SERDE_CLASS_FIELD(b, std::vector{}); }; Test a; a.a() = "ok"; a.b() = {1, 2, 3}; auto out = serde::serialize(a); ASSERT_EQ(out.length(), serde::serializeLength(a)); ASSERT_EQ(out.length(), 1 + 1 + 1 + 2 + 1 + 4 * 3); XLOGF(INFO, "out is {:02x}", fmt::join(out, ",")); size_t size = out.length(); for (size_t i = 1; i <= size; ++i) { std::string_view view = out; *reinterpret_cast(out.data()) = i - 1; view = view.substr(0, i); Test t; if (i == 1) { ASSERT_OK(serde::deserialize(t, view)); ASSERT_FALSE(t.a().has_value()); ASSERT_TRUE(t.b().empty()); } else if (i == 5) { ASSERT_OK(serde::deserialize(t, view)); ASSERT_TRUE(t.a().has_value()); ASSERT_EQ(t.a().value(), "ok"); ASSERT_TRUE(t.b().empty()); } else if (i == size) { ASSERT_OK(serde::deserialize(t, view)); ASSERT_TRUE(t.a().has_value()); ASSERT_EQ(t.a().value(), "ok"); ASSERT_FALSE(t.b().empty()); } else { XLOGF(INFO, "length is {}", i); ASSERT_FALSE(serde::deserialize(a, view)); } } } struct Base { SERDE_STRUCT_FIELD(x, int{}); SERDE_STRUCT_FIELD(y, int{}); }; struct Derived : Base { SERDE_STRUCT_FIELD(z, int{}); }; struct Grandson : Derived { SERDE_STRUCT_FIELD(x, int{}); SERDE_STRUCT_FIELD(y, int{}); SERDE_STRUCT_FIELD(z, int{}); }; namespace v1 { struct Base { SERDE_STRUCT_FIELD(x, int{}); }; struct Derived : Base { SERDE_STRUCT_FIELD(z, int{}); }; struct Grandson : Derived { SERDE_STRUCT_FIELD(x, int{}); SERDE_STRUCT_FIELD(y, int{}); }; }; // namespace v1 namespace v3 { struct Base { SERDE_STRUCT_FIELD(x, int{}); SERDE_STRUCT_FIELD(y, int{}); SERDE_STRUCT_FIELD(z, int{}); }; struct Derived : Base { SERDE_STRUCT_FIELD(z, int{}); SERDE_STRUCT_FIELD(a, int{}); }; struct Grandson : Derived { SERDE_STRUCT_FIELD(x, int{}); SERDE_STRUCT_FIELD(y, int{}); SERDE_STRUCT_FIELD(z, int{}); SERDE_STRUCT_FIELD(a, int{}); }; }; // namespace v3 static_assert(serde::count() == 2, "field count of Base must be 2"); static_assert(serde::count() == 3, "field count of Derived must be 3"); static_assert(serde::count() == 6, "field count of Grandson must be 6"); static_assert(serde::count() == 4); static_assert(serde::getter() != serde::getter()); static_assert(serde::getter() != serde::getter()); static_assert(serde::getter() != serde::getter()); static_assert(serde::name() == "x"); static_assert(serde::name() == "y"); static_assert(serde::name() == "x"); static_assert(serde::name() == "y"); static_assert(serde::name() == "z"); static_assert(serde::name() == "x"); static_assert(serde::name() == "y"); static_assert(serde::name() == "z"); static_assert(serde::name() == "x"); static_assert(serde::name() == "y"); static_assert(serde::name() == "z"); TEST(TestSerde, Inherit) { Grandson x; x.Base::x = 10; x.Base::y = 12; x.Derived::z = 16; x.Grandson::x = 20; x.Grandson::y = 24; x.Grandson::z = 28; ASSERT_EQ(serde::count(x), 6); ASSERT_EQ(serde::value<0>(x), 10); ASSERT_EQ(serde::value<3>(x), 20); int typeCount = 1; refl::Helper::iterate([](auto t) { XLOGF(INFO, "field name: {}", t.name); }, [&]() { ++typeCount; XLOGF(INFO, "type changed"); }); ASSERT_EQ(typeCount, 3); auto out = serde::serialize(x); Grandson o; ASSERT_OK(serde::deserialize(o, out)); ASSERT_EQ(x.Base::x, o.Base::x); ASSERT_EQ(x.Base::y, o.Base::y); ASSERT_EQ(x.Derived::z, o.Derived::z); ASSERT_EQ(x.Grandson::x, o.Grandson::x); ASSERT_EQ(x.Grandson::y, o.Grandson::y); ASSERT_EQ(x.Grandson::z, o.Grandson::z); v1::Grandson p; ASSERT_OK(serde::deserialize(p, out)); ASSERT_EQ(x.Base::x, p.Base::x); ASSERT_EQ(x.Derived::z, p.Derived::z); ASSERT_EQ(x.Grandson::x, p.Grandson::x); ASSERT_EQ(x.Grandson::y, p.Grandson::y); v3::Grandson q; ASSERT_OK(serde::deserialize(q, out)); ASSERT_EQ(x.Base::x, q.Base::x); ASSERT_EQ(x.Base::y, q.Base::y); ASSERT_EQ(q.Base::z, 0); ASSERT_EQ(x.Derived::z, q.Derived::z); ASSERT_EQ(q.Derived::a, 0); ASSERT_EQ(x.Grandson::x, q.Grandson::x); ASSERT_EQ(x.Grandson::y, q.Grandson::y); ASSERT_EQ(x.Grandson::z, q.Grandson::z); ASSERT_EQ(q.Grandson::a, 0); } struct WithStringView { SERDE_STRUCT_FIELD(msg, std::string_view{}); SERDE_STRUCT_FIELD(test, std::string_view{}); }; TEST(TestSerde, StringView) { WithStringView view; view.msg = "OK"; view.test = "test"; auto out = serde::serialize(view); ASSERT_EQ(out.length(), serde::serializeLength(view)); WithStringView des; ASSERT_OK(serde::deserialize(des, out)); ASSERT_EQ(view.msg, des.msg); ASSERT_EQ(view.test, des.test); ASSERT_LT(out.data(), des.msg.data()); ASSERT_LT(des.msg.data() + des.msg.length(), des.test.data()); ASSERT_LE(des.test.data() + des.test.length(), out.data() + out.length()); } TEST(TestSerde, Result) { { Result ser = "OK"; XLOGF(INFO, "result: {}", serde::toJsonString(ser)); auto out = serde::serialize(ser); ASSERT_EQ(out.size(), 1 + 1 + 2); Result des = makeError(Status::OK); ASSERT_FALSE(des); ASSERT_OK(serde::deserialize(des, out)); ASSERT_OK(des); ASSERT_EQ(des, ser); } { Result ser = makeError(StatusCode::kInvalidArg); XLOGF(INFO, "result: {}", serde::toJsonString(ser)); auto out = serde::serialize(ser); ASSERT_EQ(out.size(), 1 + 2 + 1); Result des = makeError(Status::OK); ASSERT_OK(serde::deserialize(des, out)); ASSERT_EQ(des.error().code(), StatusCode::kInvalidArg); ASSERT_TRUE(des.error().message().empty()); } { Result ser = makeError(StatusCode::kInvalidArg, "TT"); XLOGF(INFO, "result: {}", serde::toJsonString(ser)); auto out = serde::serialize(ser); ASSERT_EQ(out.size(), 1 + 2 + 1 + 1 + 2); Result des = makeError(Status::OK); ASSERT_OK(serde::deserialize(des, out)); ASSERT_EQ(des.error().code(), StatusCode::kInvalidArg); ASSERT_EQ(des.error().message(), "TT"); } { Result ser = Void{}; XLOGF(INFO, "result: {}", serde::toJsonString(ser)); auto out = serde::serialize(ser); ASSERT_EQ(out.size(), 1); Result des = makeError(Status::OK); ASSERT_FALSE(des); ASSERT_OK(serde::deserialize(des, out)); ASSERT_OK(des); ASSERT_EQ(des, ser); } { Result ser = makeError(StatusCode::kInvalidArg); XLOGF(INFO, "result: {}", serde::toJsonString(ser)); auto out = serde::serialize(ser); ASSERT_EQ(out.size(), 1 + 2 + 1); Result des = makeError(Status::OK); ASSERT_OK(serde::deserialize(des, out)); ASSERT_EQ(des.error().code(), StatusCode::kInvalidArg); ASSERT_TRUE(des.error().message().empty()); } } TEST(TestSerde, NewDes) { Demo ser; ser.a() = 1; ser.b() = 2; ser.c() = "test"; auto out = serde::serialize(ser); Demo des; serde::In in(out); ASSERT_OK(serde::deserialize(des, in)); ASSERT_EQ(des.a(), 1); ASSERT_EQ(des.b(), 2); ASSERT_EQ(des.c(), "test"); } TEST(TestSerde, NewDesJson) { auto json = R"({ "a": 1, "b": 2.0, "c": "test" })"; Demo des; ASSERT_OK(serde::fromJsonString(des, json)); ASSERT_EQ(des.a(), 1); ASSERT_EQ(des.b(), 2); ASSERT_EQ(des.c(), "test"); } TEST(TestSerde, NewDesToml) { auto toml = R"( a = 1 b = 2.0 c = "test" )"; Demo des; ASSERT_OK(serde::fromTomlString(des, toml)); ASSERT_EQ(des.a(), 1); ASSERT_EQ(des.b(), 2); ASSERT_EQ(des.c(), "test"); } TEST(TestSerde, NewDesOptional) { struct Foo { SERDE_STRUCT_FIELD(num, std::optional{}); SERDE_STRUCT_FIELD(str, std::optional{}); }; { Foo ser; auto out = serde::serialize(ser); Foo des; serde::In in(out); ASSERT_OK(serde::deserialize(des, in)); ASSERT_FALSE(des.num.has_value()); ASSERT_FALSE(des.str.has_value()); } { Foo ser; auto out = serde::toJsonString(ser); XLOGF(INFO, "json is {}", out); Foo des; ASSERT_OK(serde::fromJsonString(des, out)); ASSERT_FALSE(des.num.has_value()); ASSERT_FALSE(des.str.has_value()); } { Foo ser; auto out = serde::toTomlString(ser); XLOGF(INFO, "toml is {}", out); Foo des; ASSERT_OK(serde::fromTomlString(des, out)); ASSERT_FALSE(des.num.has_value()); ASSERT_FALSE(des.str.has_value()); } { Foo des; des.num = 20; des.str = "Test"; ASSERT_OK(serde::fromJsonString(des, "{}")); ASSERT_FALSE(des.num.has_value()); ASSERT_FALSE(des.str.has_value()); } { Foo des; des.num = 20; des.str = "Test"; ASSERT_OK(serde::fromTomlString(des, "")); ASSERT_FALSE(des.num.has_value()); ASSERT_FALSE(des.str.has_value()); } { Foo ser; ser.num = 27; ser.str = "OK"; auto out = serde::serialize(ser); Foo des; serde::In in(out); ASSERT_OK(serde::deserialize(des, in)); ASSERT_TRUE(des.num.has_value()); ASSERT_EQ(ser.num, des.num); ASSERT_TRUE(des.str.has_value()); ASSERT_EQ(ser.str, des.str); } { Foo ser; ser.num = 27; ser.str = "OK"; auto out = serde::toJsonString(ser); XLOGF(INFO, "json is {}", out); Foo des; ASSERT_OK(serde::fromJsonString(des, out)); ASSERT_TRUE(des.num.has_value()); ASSERT_EQ(ser.num, des.num); ASSERT_TRUE(des.str.has_value()); ASSERT_EQ(ser.str, des.str); } { Foo ser; ser.num = 27; ser.str = "OK"; auto out = serde::toTomlString(ser); XLOGF(INFO, "toml is {}", out); Foo des; ASSERT_OK(serde::fromTomlString(des, out)); ASSERT_TRUE(des.num.has_value()); ASSERT_EQ(ser.num, des.num); ASSERT_TRUE(des.str.has_value()); ASSERT_EQ(ser.str, des.str); } } TEST(TestSerde, NewDesVariant) { struct Foo { SERDE_STRUCT_FIELD(num, (std::variant{})); SERDE_STRUCT_FIELD(val, (std::variant{})); }; { Foo ser; auto out = serde::serialize(ser); Foo des; serde::In in(out); ASSERT_OK(serde::deserialize(des, in)); ASSERT_EQ(des.num.index(), 0); ASSERT_EQ(des.val.index(), 0); } { Foo ser; ser.num = 20.0; ser.val = Demo{}; auto out = serde::serialize(ser); Foo des; ASSERT_EQ(des.num.index(), 0); ASSERT_EQ(des.val.index(), 0); serde::In in(out); ASSERT_OK(serde::deserialize(des, in)); ASSERT_EQ(des.num.index(), 1); ASSERT_EQ(des.val.index(), 1); } { auto json = R"({ "num": { "type": "double", "value": 70 }, "val": { "type": "basic_string", "value": "Test" } })"; Foo des; ASSERT_OK(serde::fromJsonString(des, json)); ASSERT_EQ(des.num.index(), 1); ASSERT_EQ(std::get<1>(des.num), 70.0); ASSERT_EQ(des.val.index(), 0); ASSERT_EQ(std::get<0>(des.val), "Test"); } { Foo ser; ser.num = 70.0; Demo demo; demo.c() = "OK"; ser.val = demo; auto out = serde::toJsonString(ser); XLOGF(INFO, "json is {}", out); Foo des; ASSERT_OK(serde::fromJsonString(des, out)); ASSERT_EQ(des.num.index(), 1); ASSERT_EQ(std::get<1>(des.num), 70.0); ASSERT_EQ(des.val.index(), 1); ASSERT_EQ(std::get<1>(des.val).c(), "OK"); } } TEST(TestSerde, NewDesContainer) { struct Foo { SERDE_STRUCT_FIELD(num, (std::vector{})); SERDE_STRUCT_FIELD(val, (std::set{})); SERDE_STRUCT_FIELD(map, (std::map{})); SERDE_STRUCT_FIELD(map2, (std::map{})); }; { auto json = R"({ "num": [1, 2, 3, 4], "val": ["A", "B"], "map": { "A": "1", "B": "2" }, "map2": { "1": "A", "2": "B" } })"; Foo des; ASSERT_OK(serde::fromJsonString(des, json)); ASSERT_EQ(des.num.size(), 4); ASSERT_EQ(des.val.size(), 2); ASSERT_EQ(des.map.size(), 2); ASSERT_EQ(des.map["A"], "1"); ASSERT_EQ(des.map["B"], "2"); ASSERT_EQ(des.map2.size(), 2); ASSERT_EQ(des.map2[1], "A"); ASSERT_EQ(des.map2[2], "B"); } } TEST(TestSerde, NewDesEnum) { enum class Foo { A, B, C }; Foo foo; { auto json = serde::toJsonString(Foo::B); ASSERT_OK(serde::fromJsonString(foo, json)); ASSERT_EQ(foo, Foo::B); } ASSERT_FALSE(serde::fromJsonString(foo, "\"D\"")); } TEST(TestSerde, UniquePtr) { struct Foo { SERDE_STRUCT_FIELD(value, std::unique_ptr{}); }; struct Bar { SERDE_STRUCT_FIELD(value, std::unique_ptr{}); }; Bar bar; XLOGF(INFO, "{}", bar); { Bar des; ASSERT_OK(serde::deserialize(des, serde::serialize(bar))); ASSERT_EQ(des.value, nullptr); } { Bar des; ASSERT_OK(serde::fromJsonString(des, serde::toJsonString(bar))); ASSERT_EQ(des.value, nullptr); } { Bar des; ASSERT_OK(serde::fromTomlString(des, serde::toTomlString(bar))); ASSERT_EQ(des.value, nullptr); } bar.value = std::make_unique(); XLOGF(INFO, "{}", bar); { Bar des; ASSERT_OK(serde::deserialize(des, serde::serialize(bar))); ASSERT_NE(des.value, nullptr); ASSERT_EQ(des.value->value, nullptr); } { Bar des; ASSERT_OK(serde::fromJsonString(des, serde::toJsonString(bar))); ASSERT_NE(des.value, nullptr); ASSERT_EQ(des.value->value, nullptr); } { Bar des; ASSERT_OK(serde::fromTomlString(des, serde::toTomlString(bar))); ASSERT_NE(des.value, nullptr); ASSERT_EQ(des.value->value, nullptr); } bar.value->value = std::make_unique("hello"); XLOGF(INFO, "{}", bar); { Bar des; ASSERT_OK(serde::deserialize(des, serde::serialize(bar))); ASSERT_NE(des.value, nullptr); ASSERT_NE(des.value->value, nullptr); ASSERT_EQ(*des.value->value, "hello"); } { Bar des; ASSERT_OK(serde::fromJsonString(des, serde::toJsonString(bar))); ASSERT_NE(des.value, nullptr); ASSERT_NE(des.value->value, nullptr); ASSERT_EQ(*des.value->value, "hello"); } { Bar des; ASSERT_OK(serde::fromTomlString(des, serde::toTomlString(bar))); ASSERT_NE(des.value, nullptr); ASSERT_NE(des.value->value, nullptr); ASSERT_EQ(*des.value->value, "hello"); } } TEST(TestSerde, SharedPtr) { struct Foo { SERDE_STRUCT_FIELD(value, std::shared_ptr{}); }; struct Bar { SERDE_STRUCT_FIELD(value, std::shared_ptr{}); }; Bar bar; XLOGF(INFO, "{}", bar); { Bar des; ASSERT_OK(serde::deserialize(des, serde::serialize(bar))); ASSERT_EQ(des.value, nullptr); } { Bar des; ASSERT_OK(serde::fromJsonString(des, serde::toJsonString(bar))); ASSERT_EQ(des.value, nullptr); } { Bar des; ASSERT_OK(serde::fromTomlString(des, serde::toTomlString(bar))); ASSERT_EQ(des.value, nullptr); } bar.value = std::make_unique(); XLOGF(INFO, "{}", bar); { Bar des; ASSERT_OK(serde::deserialize(des, serde::serialize(bar))); ASSERT_NE(des.value, nullptr); ASSERT_EQ(des.value->value, nullptr); } { Bar des; ASSERT_OK(serde::fromJsonString(des, serde::toJsonString(bar))); ASSERT_NE(des.value, nullptr); ASSERT_EQ(des.value->value, nullptr); } { Bar des; ASSERT_OK(serde::fromTomlString(des, serde::toTomlString(bar))); ASSERT_NE(des.value, nullptr); ASSERT_EQ(des.value->value, nullptr); } bar.value->value = std::make_unique("hello"); XLOGF(INFO, "{}", bar); { Bar des; ASSERT_OK(serde::deserialize(des, serde::serialize(bar))); ASSERT_NE(des.value, nullptr); ASSERT_NE(des.value->value, nullptr); ASSERT_EQ(*des.value->value, "hello"); } { Bar des; ASSERT_OK(serde::fromJsonString(des, serde::toJsonString(bar))); ASSERT_NE(des.value, nullptr); ASSERT_NE(des.value->value, nullptr); ASSERT_EQ(*des.value->value, "hello"); } { Bar des; ASSERT_OK(serde::fromTomlString(des, serde::toTomlString(bar))); ASSERT_NE(des.value, nullptr); ASSERT_NE(des.value->value, nullptr); ASSERT_EQ(*des.value->value, "hello"); } } TEST(TestSerde, AutoFallbackVariant) { std::variant src = Status(StatusCode::kUnknown, "Unknown"); static_assert(!serde::is_auto_fallback_variant_v); auto s = serde::serialize(src); serde::AutoFallbackVariant dst; static_assert(serde::is_auto_fallback_variant_v); ASSERT_OK(serde::deserialize(dst, s)); auto *uvt = std::get_if(&dst); ASSERT_TRUE(uvt != nullptr); ASSERT_EQ(uvt->type, "Status"); } TEST(TestSerde, UserBufferAllocator) { std::string ser = "hello world!"; auto len = serde::serializeLength(ser); std::string buf(len, '\0'); serde::serializeToUserBuffer(ser, (uint8_t *)buf.data(), buf.size()); std::string der; serde::deserialize(der, buf); ASSERT_EQ(ser, der); } } // namespace } // namespace hf3fs::test