#include #include "renderive/inheritance/Inheritance.hpp" #include #include namespace { namespace inheritance = renderive::inheritance; struct Object_Chain {}; struct Implementation_Chain {}; enum class Registration_Position : std::size_t { root, reserved, implementation_parent, object_branch }; constexpr auto position(Registration_Position value) noexcept { return static_cast(value); } enum class Trace_Step { parent, child, object_branch }; enum class Test_Payload { ready }; struct Test_Event { Test_Payload payload{Test_Payload::ready}; }; struct Trace { std::vector order; }; struct Test_Root : inheritance::Type_Root { explicit Test_Root(Trace& trace) : trace(&trace) {} Trace* trace; }; struct Parent_Impl : inheritance::Dispatch_Root< Parent_Impl, Test_Root, Implementation_Chain, Test_Event, position(Registration_Position::implementation_parent)> { using Dispatch_Root::Dispatch_Root; struct Event_Handler { using Owner = Parent_Impl; static void handle(Parent_Impl& impl, const Test_Event&) { impl.trace->order.push_back(Trace_Step::parent); } }; using Handler = Event_Handler; }; struct Child_Impl : inheritance::Dispatch_Node { using Dispatch_Node::Dispatch_Node; struct Event_Handler : Parent_Impl::Event_Handler { using Owner = Child_Impl; static void handle(Child_Impl& impl, const Test_Event&) { impl.trace->order.push_back(Trace_Step::child); } }; using Handler = Event_Handler; }; struct Object_Node : inheritance::Type_Node< Object_Node, Test_Root, Object_Chain, position(Registration_Position::object_branch)> { using Type_Node::Type_Node; }; struct Impl_With_Object_Branch : inheritance::Dispatch_Node< Impl_With_Object_Branch, Child_Impl, Object_Chain, Test_Event, position(Registration_Position::object_branch)> { using Dispatch_Node::Dispatch_Node; struct Event_Handler : Child_Impl::Event_Handler { using Owner = Impl_With_Object_Branch; static void handle(Impl_With_Object_Branch& impl, const Test_Event&) { impl.trace->order.push_back(Trace_Step::object_branch); } }; using Handler = Event_Handler; }; struct Reverse_Declared_Registry { using Inheritance_Registry = inheritance::Registry< inheritance::Registration< Implementation_Chain, position(Registration_Position::object_branch), Child_Impl>, inheritance::Registration< Implementation_Chain, position(Registration_Position::implementation_parent), Parent_Impl>>; Trace* trace; }; using Implementation_View = inheritance::Chain_View< typename Child_Impl::Inheritance_Registry, Implementation_Chain>; using Combined_Registry = inheritance::Merge_Registries_T< typename Child_Impl::Inheritance_Registry, typename Object_Node::Inheritance_Registry>; inline constexpr std::size_t Implementation_Layer_Count = position(Registration_Position::object_branch) - position(Registration_Position::reserved); inline constexpr std::size_t Object_Layer_Count = position(Registration_Position::reserved) - position(Registration_Position::root); static_assert(Implementation_View::count == Implementation_Layer_Count); static_assert(Implementation_View::next_position == position(Registration_Position::object_branch) + Object_Layer_Count); static_assert(std::same_as< Implementation_View::Type, Parent_Impl>); static_assert(std::same_as< Implementation_View::Type, Child_Impl>); static_assert(inheritance::Chain_Registration_Count_V< Combined_Registry, Implementation_Chain> == Implementation_Layer_Count); static_assert(inheritance::Chain_Registration_Count_V == Object_Layer_Count); static_assert(std::same_as< inheritance::Type_At_Position_T< Combined_Registry, Object_Chain, position(Registration_Position::object_branch)>, Object_Node>); TEST(inheritance_test, dispatches_parent_before_child) { Trace trace; Child_Impl child(trace); child.dispatch(Test_Event{}); EXPECT_EQ(trace.order, (std::vector{Trace_Step::parent, Trace_Step::child})); } TEST(inheritance_test, exposes_named_registration_positions) { EXPECT_EQ(Parent_Impl::Inheritance_Position, position(Registration_Position::implementation_parent)); EXPECT_EQ(Child_Impl::Inheritance_Position, position(Registration_Position::object_branch)); } TEST(inheritance_test, dispatches_only_the_selected_chain) { Trace trace; Impl_With_Object_Branch value(trace); const Test_Event event{}; value.dispatch(event); EXPECT_EQ(trace.order, (std::vector{Trace_Step::object_branch})); trace.order.clear(); value.dispatch_for(event); EXPECT_EQ(trace.order, (std::vector{Trace_Step::parent, Trace_Step::child})); } TEST(inheritance_test, initializes_registered_layers_by_position) { Trace trace; Reverse_Declared_Registry registered{&trace}; inheritance::initialize( registered, [&](std::type_identity, Reverse_Declared_Registry& value) { if constexpr (std::same_as) value.trace->order.push_back(Trace_Step::parent); else if constexpr (std::same_as) value.trace->order.push_back(Trace_Step::child); }); EXPECT_EQ(trace.order, (std::vector{Trace_Step::parent, Trace_Step::child})); } TEST(inheritance_test, initializes_final_value_with_ordered_steps) { auto initialized = inheritance::initialize( Trace{}, [](Trace& value) { value.order.push_back(Trace_Step::parent); }, [](Trace& value) { value.order.push_back(Trace_Step::child); }); EXPECT_EQ(initialized.order, (std::vector{Trace_Step::parent, Trace_Step::child})); } } // namespace