211 lines
6.5 KiB
C++
211 lines
6.5 KiB
C++
#include <gtest/gtest.h>
|
|
|
|
#include "renderive/inheritance/Inheritance.hpp"
|
|
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
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<std::size_t>(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<Trace_Step> 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<Child_Impl, Parent_Impl,
|
|
Implementation_Chain, Test_Event> {
|
|
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<position(
|
|
Registration_Position::implementation_parent)>,
|
|
Parent_Impl>);
|
|
static_assert(std::same_as<
|
|
Implementation_View::Type<position(
|
|
Registration_Position::object_branch)>,
|
|
Child_Impl>);
|
|
static_assert(inheritance::Chain_Registration_Count_V<
|
|
Combined_Registry, Implementation_Chain> ==
|
|
Implementation_Layer_Count);
|
|
static_assert(inheritance::Chain_Registration_Count_V<Combined_Registry,
|
|
Object_Chain> ==
|
|
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<Implementation_Chain>(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<Implementation_Chain>(
|
|
registered,
|
|
[&]<class Layer>(std::type_identity<Layer>,
|
|
Reverse_Declared_Registry& value) {
|
|
if constexpr (std::same_as<Layer, Parent_Impl>)
|
|
value.trace->order.push_back(Trace_Step::parent);
|
|
else if constexpr (std::same_as<Layer, Child_Impl>)
|
|
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
|