364 lines
8.5 KiB
C++
364 lines
8.5 KiB
C++
#include <psemek/test/test.hpp>
|
|
|
|
#include <psemek/ui/impl/component_factory_base.hpp>
|
|
#include <psemek/ui/label.hpp>
|
|
#include <psemek/ui/rectangle.hpp>
|
|
#include <psemek/ui/button.hpp>
|
|
#include <psemek/ui/stack_layout.hpp>
|
|
|
|
#include <type_traits>
|
|
|
|
using namespace psemek;
|
|
using namespace psemek::ui;
|
|
|
|
namespace
|
|
{
|
|
|
|
struct rectangle_impl
|
|
: impl::component
|
|
{
|
|
void update(rectangle const &)
|
|
{}
|
|
};
|
|
|
|
struct label_impl
|
|
: impl::component
|
|
{
|
|
void update(label const &)
|
|
{}
|
|
};
|
|
|
|
struct button_impl
|
|
: impl::single_container
|
|
{
|
|
void update(button const &)
|
|
{}
|
|
};
|
|
|
|
struct stack_layout_impl
|
|
: impl::container
|
|
{
|
|
void update(stack_layout const &)
|
|
{}
|
|
};
|
|
|
|
struct test_component_factory
|
|
: impl::component_factory_base
|
|
{
|
|
int rectangle_count = 0;
|
|
int label_count = 0;
|
|
int button_count = 0;
|
|
int stack_layout_count = 0;
|
|
|
|
test_component_factory()
|
|
{
|
|
register_type<rectangle, rectangle_impl>([this]{ ++rectangle_count; return std::make_unique<rectangle_impl>(); });
|
|
register_type<label, label_impl>([this]{ ++label_count; return std::make_unique<label_impl>(); });
|
|
register_type<button, button_impl>([this]{ ++button_count; return std::make_unique<button_impl>(); });
|
|
register_type<stack_layout, stack_layout_impl>([this]{ ++stack_layout_count; return std::make_unique<stack_layout_impl>(); });
|
|
}
|
|
};
|
|
|
|
struct check_children_helper
|
|
{
|
|
impl::component & component;
|
|
std::size_t i = 0;
|
|
|
|
template <typename Type>
|
|
void check()
|
|
{
|
|
if constexpr (std::is_same_v<Type, std::nullptr_t>)
|
|
{
|
|
expect_null(component.children()[i]);
|
|
}
|
|
else
|
|
{
|
|
expect_non_null(component.children()[i]);
|
|
expect_dynamic_type(*component.children()[i], Type);
|
|
}
|
|
++i;
|
|
}
|
|
};
|
|
|
|
template <typename ... Types>
|
|
void check_children(impl::component & component)
|
|
{
|
|
expect_equal(component.children().size(), sizeof...(Types));
|
|
|
|
check_children_helper helper{component};
|
|
|
|
(void)helper;
|
|
(helper.check<Types>(), ...);
|
|
}
|
|
|
|
}
|
|
|
|
test_case(ui_impl_factory_element)
|
|
{
|
|
test_component_factory factory;
|
|
|
|
auto test_ui = label{};
|
|
auto ui_root = factory.reconciliate(nullptr, test_ui);
|
|
|
|
expect_non_null(ui_root);
|
|
expect_dynamic_type(*ui_root, label_impl);
|
|
|
|
expect_equal(factory.label_count, 1);
|
|
}
|
|
|
|
test_case(ui_impl_factory_single__container)
|
|
{
|
|
test_component_factory factory;
|
|
|
|
auto test_ui = button{
|
|
.child = label{}
|
|
};
|
|
auto ui_root = factory.reconciliate(nullptr, test_ui);
|
|
|
|
expect_non_null(ui_root);
|
|
expect_dynamic_type(*ui_root, button_impl);
|
|
check_children<label_impl>(*ui_root);
|
|
|
|
expect_equal(factory.label_count, 1);
|
|
expect_equal(factory.button_count, 1);
|
|
}
|
|
|
|
test_case(ui_impl_factory_single__container__null)
|
|
{
|
|
test_component_factory factory;
|
|
|
|
auto test_ui = button{};
|
|
auto ui_root = factory.reconciliate(nullptr, test_ui);
|
|
|
|
expect_non_null(ui_root);
|
|
expect_dynamic_type(*ui_root, button_impl);
|
|
check_children<std::nullptr_t>(*ui_root);
|
|
|
|
expect_equal(factory.button_count, 1);
|
|
}
|
|
|
|
test_case(ui_impl_factory_container)
|
|
{
|
|
test_component_factory factory;
|
|
|
|
auto test_ui = stack_layout{{
|
|
{label{}},
|
|
{button{.child = label{}}},
|
|
{label{}},
|
|
}};
|
|
auto ui_root = factory.reconciliate(nullptr, test_ui);
|
|
|
|
expect_non_null(ui_root);
|
|
expect_dynamic_type(*ui_root, stack_layout_impl);
|
|
check_children<label_impl, button_impl, label_impl>(*ui_root);
|
|
check_children<label_impl>(*ui_root->children()[1]);
|
|
|
|
expect_equal(factory.label_count, 3);
|
|
expect_equal(factory.button_count, 1);
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
}
|
|
|
|
test_case(ui_impl_factory_container__null)
|
|
{
|
|
test_component_factory factory;
|
|
|
|
auto test_ui = stack_layout{};
|
|
auto ui_root = factory.reconciliate(nullptr, test_ui);
|
|
|
|
expect_non_null(ui_root);
|
|
expect_dynamic_type(*ui_root, stack_layout_impl);
|
|
check_children<>(*ui_root);
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
}
|
|
|
|
test_case(ui_impl_factory_container__null__child)
|
|
{
|
|
test_component_factory factory;
|
|
|
|
auto test_ui = stack_layout{{
|
|
{},
|
|
{},
|
|
}};
|
|
auto ui_root = factory.reconciliate(nullptr, test_ui);
|
|
|
|
expect_non_null(ui_root);
|
|
expect_dynamic_type(*ui_root, stack_layout_impl);
|
|
check_children<std::nullptr_t, std::nullptr_t>(*ui_root);
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
}
|
|
|
|
test_case(ui_impl_reconciliate_single__container)
|
|
{
|
|
test_component_factory factory;
|
|
|
|
auto child = react::source<std::any>(label{});
|
|
|
|
expect_equal((*child).type(), typeid(label{}));
|
|
|
|
auto test_ui = button{
|
|
.child = child
|
|
};
|
|
|
|
expect_equal((*test_ui.child).type(), typeid(label{}));
|
|
|
|
auto ui_root = factory.reconciliate(nullptr, test_ui);
|
|
|
|
expect_non_null(ui_root);
|
|
expect_dynamic_type(*ui_root, button_impl);
|
|
check_children<label_impl>(*ui_root);
|
|
|
|
expect_equal(factory.rectangle_count, 0);
|
|
expect_equal(factory.label_count, 1);
|
|
expect_equal(factory.button_count, 1);
|
|
|
|
child.set(label{});
|
|
|
|
check_children<label_impl>(*ui_root);
|
|
|
|
expect_equal(factory.rectangle_count, 0);
|
|
expect_equal(factory.label_count, 1);
|
|
expect_equal(factory.button_count, 1);
|
|
|
|
child.set(rectangle{});
|
|
|
|
check_children<rectangle_impl>(*ui_root);
|
|
|
|
expect_equal(factory.rectangle_count, 1);
|
|
expect_equal(factory.label_count, 1);
|
|
expect_equal(factory.button_count, 1);
|
|
|
|
child.set(label{});
|
|
|
|
check_children<label_impl>(*ui_root);
|
|
|
|
expect_equal(factory.rectangle_count, 1);
|
|
expect_equal(factory.label_count, 2);
|
|
expect_equal(factory.button_count, 1);
|
|
}
|
|
|
|
test_case(ui_impl_reconciliate_container__no__keys)
|
|
{
|
|
test_component_factory factory;
|
|
|
|
react::source<std::vector<stack_layout::element>> children;
|
|
|
|
auto test_ui = stack_layout{children};
|
|
|
|
auto ui_root = factory.reconciliate(nullptr, test_ui);
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 0);
|
|
expect_equal(factory.button_count, 0);
|
|
|
|
expect_non_null(ui_root);
|
|
expect_dynamic_type(*ui_root, stack_layout_impl);
|
|
check_children<>(*ui_root);
|
|
|
|
children.set({{label{}}});
|
|
|
|
check_children<label_impl>(*ui_root);
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 1);
|
|
expect_equal(factory.button_count, 0);
|
|
|
|
children.set({{label{}}, {label{}}});
|
|
|
|
check_children<label_impl, label_impl>(*ui_root);
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 2);
|
|
expect_equal(factory.button_count, 0);
|
|
|
|
children.set({{label{}}, {label{}}, {label{}}});
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 3);
|
|
expect_equal(factory.button_count, 0);
|
|
|
|
children.set({{label{}}, {button{}}, {label{}}});
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 3);
|
|
expect_equal(factory.button_count, 1);
|
|
|
|
children.set({{button{}}, {button{}}, {label{}}});
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 3);
|
|
expect_equal(factory.button_count, 2);
|
|
|
|
children.set({{button{}}, {button{}}});
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 3);
|
|
expect_equal(factory.button_count, 2);
|
|
|
|
children.set({{button{}}});
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 3);
|
|
expect_equal(factory.button_count, 2);
|
|
|
|
children.set({});
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 3);
|
|
expect_equal(factory.button_count, 2);
|
|
}
|
|
|
|
test_case(ui_impl_reconciliate_container__keys)
|
|
{
|
|
test_component_factory factory;
|
|
|
|
react::source<std::vector<stack_layout::element>> children;
|
|
|
|
auto test_ui = stack_layout{children};
|
|
|
|
auto ui_root = factory.reconciliate(nullptr, test_ui);
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 0);
|
|
|
|
expect_non_null(ui_root);
|
|
expect_dynamic_type(*ui_root, stack_layout_impl);
|
|
check_children<>(*ui_root);
|
|
|
|
children.set({{label{}, "Label 0"}});
|
|
|
|
check_children<label_impl>(*ui_root);
|
|
|
|
auto label0 = ui_root->children()[0].get();
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 1);
|
|
|
|
children.set({{label{}, "Label 0"}, {label{}, "Label 1"}});
|
|
|
|
check_children<label_impl, label_impl>(*ui_root);
|
|
expect_equal(ui_root->children()[0].get(), label0);
|
|
auto label1 = ui_root->children()[1].get();
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 2);
|
|
|
|
children.set({{label{}, "Label 1"}, {label{}, "Label 0"}});
|
|
|
|
check_children<label_impl, label_impl>(*ui_root);
|
|
expect_equal(ui_root->children()[0].get(), label1);
|
|
expect_equal(ui_root->children()[1].get(), label0);
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 2);
|
|
|
|
children.set({{label{}, "Label 0"}, {label{}, "Label 2"}});
|
|
|
|
check_children<label_impl, label_impl>(*ui_root);
|
|
expect_equal(ui_root->children()[0].get(), label0);
|
|
|
|
expect_equal(factory.stack_layout_count, 1);
|
|
expect_equal(factory.label_count, 3);
|
|
}
|
|
|