diff options
Diffstat (limited to 'test/entity.cpp')
-rw-r--r-- | test/entity.cpp | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/test/entity.cpp b/test/entity.cpp new file mode 100644 index 00000000..3c099a37 --- /dev/null +++ b/test/entity.cpp @@ -0,0 +1,259 @@ +#include "app.hpp" +#include "compat/assert.hpp" +#include "entity/metadata.hpp" +#include <tuple> + +using namespace floormat; +using namespace floormat::entities; + +namespace { + +struct TestAccessors { + constexpr int bar() const { return _bar; } + constexpr void set_bar(int value) { _bar = value; } + int foo; + int _bar; + int _baz; +}; + +} // namespace + +namespace floormat::entities { + +template<> struct entity_accessors<TestAccessors, inspect_intent_t> { + static constexpr auto accessors() + { + using entity = Entity<TestAccessors>; + constexpr auto r_baz = [](const TestAccessors& x) { return x._baz; }; + constexpr auto w_baz = [](TestAccessors& x, int v) { x._baz = v; }; + + constexpr auto tuple = std::make_tuple( + entity::type<int>::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo}, + entity::type<int>::field{"bar"_s, &TestAccessors::bar, &TestAccessors::set_bar}, + entity::type<int>::field("baz"_s, r_baz, w_baz) + ); + return tuple; + } +}; + +} // namespace floormat::entities + +namespace { + +using entity = Entity<TestAccessors>; +constexpr auto m_foo = entity::type<int>::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo}; +constexpr auto m_bar = entity::type<int>::field{"bar"_s, &TestAccessors::bar, &TestAccessors::set_bar}; +constexpr auto r_baz = [](const TestAccessors& x) { return x._baz; }; +constexpr auto w_baz = [](TestAccessors& x, int v) { x._baz = v; }; +constexpr auto m_baz = entity::type<int>::field("baz"_s, r_baz, w_baz); + +} // namespace + +namespace floormat { + +namespace { + +constexpr bool test_accessors() +{ + auto x = TestAccessors{111, 222, 333}; + + { + auto a = m_foo.read(x), b = m_bar.read(x), c = m_baz.read(x); + fm_assert(a == 111 && b == 222 && c == 333); + } + + { + m_foo.write(x, 1111); + m_bar.write(x, 2222); + m_baz.write(x, 3333); + auto a = m_foo.read(x), b = m_bar.read(x), c = m_baz.read(x); + fm_assert(a == 1111 && b == 2222 && c == 3333); + } + return true; +} + +constexpr bool test_visitor() +{ + { + auto tuple = std::make_tuple((unsigned char)1, (unsigned short)2, (int)3, (long)4); + long ret = 0; + visit_tuple([&](auto x) { ret += (long)x; }, tuple); + fm_assert(ret == 1 + 2 + 3 + 4); + } + { + int ret = 0; + visit_tuple([&] { ret++; }, std::tuple<>{}); + fm_assert(ret == 0); + } + { + constexpr auto tuple = std::make_tuple((char)1, (short)2, (long)3); + static_assert(find_in_tuple([](auto x) { return x == 3; }, tuple)); + static_assert(!find_in_tuple([](auto x) { return x == 5; }, tuple)); + } + + return true; +} + +void test_fun2() { + using entity = Entity<TestAccessors>; + static constexpr auto read_fn = [](const TestAccessors& x) constexpr { return x.bar(); }; + static constexpr auto write_fn = [](TestAccessors& x, int value) constexpr { x.set_bar(value); }; + constexpr auto read_bar = fu2::function_view<int(const TestAccessors&) const>{read_fn}; + constexpr auto write_bar = fu2::function_view<void(TestAccessors&, int) const>{write_fn}; + constexpr auto m_bar2 = entity::type<int>::field{"bar"_s, read_bar, write_bar}; + + auto x = TestAccessors{1, 2, 3}; + fm_assert(m_bar2.read(x) == 2); + m_bar2.write(x, 22); + fm_assert(m_bar2.read(x) == 22); +} + +void test_erasure() { + erased_accessor accessors[] = { + m_foo.erased(), + m_bar.erased(), + m_baz.erased(), + }; + auto obj = TestAccessors{1, 2, 3}; + int value = 0; + accessors[1].read_fun(&obj, accessors[1].reader, &value); + fm_assert(value == 2); + int value2 = 22222, value2_ = 0; + accessors[1].write_fun(&obj, accessors[1].writer, &value2); + accessors[1].read_fun(&obj, accessors[1].reader, &value2_); + fm_assert(value2 == value2_); +} + +void test_metadata() +{ + constexpr auto m = entity_metadata<TestAccessors, inspect_intent_t>(); + static_assert(sizeof m == 1); + fm_assert(m.class_name == name_of<TestAccessors>); + fm_assert(m.class_name.contains("TestAccessors"_s)); + const auto [foo, bar, baz] = m.accessors; + const auto [foo2, bar2, baz2] = m.erased_accessors; + TestAccessors x{0, 0, 0}; + foo.write(x, 1); + fm_assert(x.foo == 1); + int bar_ = 2; + bar2.write_fun(&x, bar2.writer, &bar_); + fm_assert(x.bar() == 2); + baz2.write<TestAccessors, int>(x, 3); + fm_assert(baz2.read<TestAccessors, int>(x) == 3); +} + +void test_type_name() +{ + struct foobar; + constexpr StringView name = name_of<foobar>; + fm_assert(name.contains("foobar"_s)); + static_assert(name.data() == name_of<foobar>.data()); + static_assert(name_of<int> != name_of<unsigned>); + static_assert(name_of<foobar*> != name_of<const foobar*>); + using foobar2 = foobar; + static_assert(name_of<foobar2>.data() == name_of<foobar>.data()); +} + +[[maybe_unused]] constexpr void test_null_writer() +{ + using entity = Entity<TestAccessors>; + constexpr auto foo = entity::type<int>::field{"foo"_s, &TestAccessors::foo, nullptr}; + static_assert(foo.writer == nullptr); + static_assert(!foo.can_write); + static_assert(std::get<0>(entity_accessors<TestAccessors, inspect_intent_t>::accessors()).can_write); +} + +void test_predicate() +{ + using entity = Entity<TestAccessors>; + constexpr TestAccessors x{0, 0, 0}; + constexpr auto foo = entity::type<int>::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo, + [](const TestAccessors&) { return field_status::hidden; }}; + static_assert(foo.is_enabled(x) == field_status::hidden); + fm_assert(foo.erased().is_enabled(&x) == field_status::hidden); + + foo.erased().do_asserts<TestAccessors>(); + + constexpr auto foo2 = entity::type<int>::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo, + [](const TestAccessors&) { return field_status::readonly; }}; + static_assert(foo2.is_enabled(x) == field_status::readonly); + fm_assert(foo2.erased().is_enabled(&x) == field_status::readonly); + constexpr auto foo3 = entity::type<int>::field{"foo"_s, &TestAccessors::foo, &TestAccessors::foo}; + static_assert(foo3.is_enabled(x) == field_status::enabled); + fm_assert(foo3.erased().is_enabled(&x) == field_status::enabled); +} + +constexpr bool test_names() +{ + constexpr auto m = entity_metadata<TestAccessors, inspect_intent_t>(); + auto [foo1, bar1, baz1] = m.accessors; + auto [foo2, bar2, baz2] = m.erased_accessors; + + fm_assert(foo1.name == "foo"_s); + fm_assert(bar1.name == "bar"_s); + fm_assert(baz1.name == "baz"_s); + + fm_assert(foo2.field_name == "foo"_s); + fm_assert(bar2.field_name == "bar"_s); + fm_assert(baz2.field_name == "baz"_s); + return true; +} + +constexpr void test_constraints() +{ + using entity = Entity<TestAccessors>; + constexpr auto x = TestAccessors{}; + constexpr auto foo = entity::type<int>::field { + "foo"_s, &TestAccessors::foo, &TestAccessors::foo, + constantly(constraints::max_length{42}), + constantly(constraints::range<int>{37, 42}), + }; + + static_assert(foo.get_range(x) == constraints::range<int>{37, 42}); + static_assert(foo.get_max_length(x) == 42); + + static_assert(m_foo.get_range(x) == constraints::range<int>{}); + static_assert(m_foo.get_max_length(x) == (size_t)-1); + + constexpr auto foo2 = entity::type<int>::field { + "foo"_s, &TestAccessors::foo, &TestAccessors::foo, + constantly(constraints::max_length {123}), + }; + static_assert(foo2.get_range(x) == constraints::range<int>{}); + static_assert(foo2.get_max_length(x) == 123); +} + +void test_erased_constraints() +{ + using entity = Entity<TestAccessors>; + static constexpr auto foo = entity::type<int>::field{ + "foo"_s, &TestAccessors::foo, &TestAccessors::foo, + constantly(constraints::max_length{42}), + constantly(constraints::range<int>{37, 42}), + }; + static constexpr auto erased = foo.erased(); + const auto x = TestAccessors{}; + + erased.do_asserts<TestAccessors>(); + fm_assert(erased.get_range(&x) == constraints::range<int>{37, 42}); + fm_assert(erased.get_max_length(&x) == 42); +} + +} // namespace + +void test_app::test_entity() +{ + static_assert(test_accessors()); + static_assert(test_visitor()); + test_null_writer(); + static_assert(test_names()); + test_predicate(); + test_fun2(); + test_erasure(); + test_type_name(); + test_metadata(); + test_constraints(); + test_erased_constraints(); +} + +} // namespace floormat |