#include "Test/Test.h" #include "Support/Struct.h" namespace clice::testing { namespace { struct X { int x; int y; friend constexpr bool operator== (const X& lhs, const X& rhs) noexcept = default; }; static_assert(std::is_same_v, type_list>); TEST(Reflection, FieldName) { static struct X { int a; int b; } x; static_assert(refl::impl::member_name<&x.a>() == "a", "Member name mismatch"); static_assert(refl::impl::member_name<&x.b>() == "b", "Member name mismatch"); static_assert(refl::member_names() == std::array{"a", "b"}); static struct Y { X x; } y; static_assert(refl::impl::member_name<&y.x>() == "x", "Member name mismatch"); static_assert(refl::impl::member_name<&y.x.a>() == "a", "Member name mismatch"); static_assert(refl::impl::member_name<&y.x.b>() == "b", "Member name mismatch"); static_assert(refl::member_names() == std::array{"x"}); struct H { X x; Y y; H() = delete; }; static union Z { char dummy; H h; Z() {}; ~Z() {}; } z; static_assert(refl::impl::member_name<&z.h.x>() == "x", "Member name mismatch"); static_assert(refl::impl::member_name<&z.h.y>() == "y", "Member name mismatch"); static_assert(refl::impl::member_name<&z.h.y.x>() == "x", "Member name mismatch"); struct M { X x; Y y; H h; }; static_assert(refl::member_names() == std::array{"x", "y", "h"}); } TEST(Reflection, Foreach) { bool x = false, y = false; refl::foreach(X{1, 2}, [&](auto name, auto value) { if(name == "x") { x = true; EXPECT_EQ(value, 1); } else if(name == "y") { y = true; EXPECT_EQ(value, 2); } else { EXPECT_TRUE(false); } }); EXPECT_TRUE(x && y); X x1 = {1, 2}; X x2 = {3, 4}; EXPECT_TRUE(refl::foreach(x1, x2, [](auto& lhs, auto& rhs) { return lhs = rhs; })); EXPECT_EQ(x1.x, 3); EXPECT_EQ(x1.y, 4); } TEST(Reflection, Inheritance) { inherited_struct(Y, X) { int z; }; static_assert(std::is_same_v, type_list>); bool x = false, y = false, z = false; refl::foreach(Y{1, 2, 3}, [&](auto name, auto value) { if(name == "x") { x = true; EXPECT_EQ(value, 1); } else if(name == "y") { y = true; EXPECT_EQ(value, 2); } else if(name == "z") { z = true; EXPECT_EQ(value, 3); } else { EXPECT_TRUE(false); } }); EXPECT_TRUE(x && y && z); Y y1 = {1, 2, 3}; Y y2 = {4, 5, 6}; EXPECT_TRUE(refl::foreach(y1, y2, [](auto& lhs, auto& rhs) { return lhs = rhs; })); EXPECT_EQ(y1.x, 4); EXPECT_EQ(y1.y, 5); EXPECT_EQ(y1.z, 6); } TEST(Reflection, TupleLike) { std::pair p = {1, 2}; static_assert(refl::member_names() == std::array{"0", "1"}); std::tuple t = {1, 2}; static_assert(refl::member_names() == std::array{"0", "1"}); bool x = false, y = false; refl::foreach(t, [&](auto name, auto value) { if(name == "0") { x = true; EXPECT_EQ(value, 1); } else if(name == "1") { y = true; EXPECT_EQ(value, 2); } else { EXPECT_TRUE(false); } }); EXPECT_TRUE(x && y); std::tuple t1 = {1, 2}; std::tuple t2 = {3, 4}; EXPECT_TRUE(refl::foreach(t1, t2, [](auto& lhs, auto& rhs) { return lhs = rhs; })); EXPECT_EQ(std::get<0>(t1), 3); EXPECT_EQ(std::get<1>(t1), 4); EXPECT_EQ(std::get<0>(t2), 3); } } // namespace } // namespace clice::testing