2026-01-20 13:22:30 +03:30
|
|
|
import test;
|
2025-12-08 16:41:41 +03:30
|
|
|
import input.system;
|
|
|
|
|
import input.codes;
|
|
|
|
|
import surface.events;
|
|
|
|
|
import memory.scope;
|
|
|
|
|
import memory.reference;
|
|
|
|
|
import app.system;
|
|
|
|
|
import ecs.entity;
|
|
|
|
|
import ecs.registry;
|
|
|
|
|
import surface.system;
|
|
|
|
|
|
2026-01-20 13:22:30 +03:30
|
|
|
using ::lt::input::InputComponent;
|
|
|
|
|
using ::lt::input::System;
|
2025-09-18 19:16:54 +03:30
|
|
|
|
2026-01-20 13:22:30 +03:30
|
|
|
[[nodiscard]] auto tick_info() -> lt::app::TickInfo
|
2025-09-22 18:51:23 +03:30
|
|
|
{
|
|
|
|
|
return {
|
|
|
|
|
.delta_time = std::chrono::milliseconds { 16 },
|
|
|
|
|
.budget = std::chrono::milliseconds { 10 },
|
|
|
|
|
.start_time = std::chrono::steady_clock::now(),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-18 19:16:54 +03:30
|
|
|
class Fixture
|
|
|
|
|
{
|
|
|
|
|
public:
|
2026-01-20 13:22:30 +03:30
|
|
|
[[nodiscard]] auto registry() -> lt::memory::Ref<lt::ecs::Registry>
|
2025-09-18 19:16:54 +03:30
|
|
|
{
|
|
|
|
|
return m_registry;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-20 13:22:30 +03:30
|
|
|
auto add_input_component() -> lt::ecs::EntityId
|
2025-09-18 19:16:54 +03:30
|
|
|
{
|
2025-09-20 15:39:45 +03:30
|
|
|
auto entity = m_registry->create_entity();
|
|
|
|
|
m_registry->add<InputComponent>(entity, {});
|
2025-09-18 19:16:54 +03:30
|
|
|
|
|
|
|
|
return entity;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-20 13:22:30 +03:30
|
|
|
auto add_surface_component() -> lt::ecs::EntityId
|
2025-09-18 19:16:54 +03:30
|
|
|
{
|
2025-09-20 15:39:45 +03:30
|
|
|
auto entity = m_registry->create_entity();
|
2025-10-08 06:29:00 +03:30
|
|
|
m_surface_system.create_surface_component(
|
2025-09-20 15:39:45 +03:30
|
|
|
entity,
|
2025-10-08 06:29:00 +03:30
|
|
|
{ .title = "", .resolution = { 20u, 20u } }
|
2025-09-20 15:39:45 +03:30
|
|
|
);
|
2025-09-18 19:16:54 +03:30
|
|
|
|
|
|
|
|
return entity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2026-01-20 13:22:30 +03:30
|
|
|
lt::memory::Ref<lt::ecs::Registry> m_registry = lt::memory::create_ref<lt::ecs::Registry>();
|
2025-10-08 06:29:00 +03:30
|
|
|
|
2026-01-20 13:22:30 +03:30
|
|
|
lt::surface::System m_surface_system = lt::surface::System { m_registry };
|
2025-09-18 19:16:54 +03:30
|
|
|
};
|
|
|
|
|
|
2025-09-30 06:44:09 +03:30
|
|
|
Suite raii = "raii"_suite = "raii"_suite = [] {
|
2026-01-20 13:22:30 +03:30
|
|
|
Case { "happy paths" } = [&] {
|
2025-09-18 19:16:54 +03:30
|
|
|
System { Fixture {}.registry() };
|
|
|
|
|
};
|
|
|
|
|
|
2026-01-20 13:22:30 +03:30
|
|
|
Case { "unhappy paths" } = [] {
|
|
|
|
|
expect_throw([] { ignore = System { {} }; });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Case { "many" } = [&] {
|
2025-09-18 19:16:54 +03:30
|
|
|
auto fixture = Fixture {};
|
|
|
|
|
for (auto idx : std::views::iota(0, 10'000))
|
|
|
|
|
{
|
2026-01-20 09:58:35 +03:30
|
|
|
ignore = idx;
|
2025-09-18 19:16:54 +03:30
|
|
|
ignore = System { fixture.registry() };
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-30 06:44:09 +03:30
|
|
|
Suite system_events = "system_events"_suite = [] {
|
2025-09-18 19:16:54 +03:30
|
|
|
Case { "on_register won't throw" } = [] {
|
|
|
|
|
auto fixture = Fixture {};
|
2025-09-20 15:39:45 +03:30
|
|
|
auto registry = fixture.registry();
|
|
|
|
|
auto system = System { registry };
|
2025-09-18 19:16:54 +03:30
|
|
|
|
|
|
|
|
system.on_register();
|
2025-09-20 15:39:45 +03:30
|
|
|
expect_eq(registry->view<InputComponent>().get_size(), 0);
|
2025-09-18 19:16:54 +03:30
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Case { "on_unregister won't throw" } = [] {
|
|
|
|
|
auto fixture = Fixture {};
|
2025-09-20 15:39:45 +03:30
|
|
|
auto registry = fixture.registry();
|
|
|
|
|
auto system = System { registry };
|
2025-09-18 19:16:54 +03:30
|
|
|
|
|
|
|
|
system.on_register();
|
|
|
|
|
system.on_unregister();
|
2025-09-20 15:39:45 +03:30
|
|
|
expect_eq(registry->view<InputComponent>().get_size(), 0);
|
2025-09-18 19:16:54 +03:30
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-30 06:44:09 +03:30
|
|
|
Suite registry_events = "registry_events"_suite = [] {
|
2025-09-18 19:16:54 +03:30
|
|
|
Case { "on_construct<InputComnent>" } = [] {
|
|
|
|
|
auto fixture = Fixture {};
|
2025-09-20 15:39:45 +03:30
|
|
|
auto registry = fixture.registry();
|
|
|
|
|
auto system = System { registry };
|
2025-09-18 19:16:54 +03:30
|
|
|
|
2026-01-09 21:53:37 +03:30
|
|
|
fixture.add_input_component();
|
2025-09-20 15:39:45 +03:30
|
|
|
expect_eq(registry->view<InputComponent>().get_size(), 1);
|
2025-09-18 19:16:54 +03:30
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Case { "on_destrroy<InputComponent>" } = [] {
|
|
|
|
|
auto fixture = Fixture {};
|
2025-09-20 15:39:45 +03:30
|
|
|
auto registry = fixture.registry();
|
2026-01-20 13:22:30 +03:30
|
|
|
auto system = lt::memory::create_scope<System>(registry);
|
2025-09-18 19:16:54 +03:30
|
|
|
|
|
|
|
|
auto entity_a = fixture.add_input_component();
|
|
|
|
|
auto entity_b = fixture.add_input_component();
|
2025-09-20 15:39:45 +03:30
|
|
|
expect_eq(registry->view<InputComponent>().get_size(), 2);
|
2025-09-18 19:16:54 +03:30
|
|
|
|
2025-09-20 15:39:45 +03:30
|
|
|
registry->remove<InputComponent>(entity_a);
|
|
|
|
|
expect_eq(registry->view<InputComponent>().get_size(), 1);
|
2025-09-18 19:16:54 +03:30
|
|
|
|
|
|
|
|
system.reset();
|
2025-09-20 15:39:45 +03:30
|
|
|
expect_eq(registry->view<InputComponent>().get_size(), 1);
|
2025-09-18 19:16:54 +03:30
|
|
|
|
2025-09-20 15:39:45 +03:30
|
|
|
registry->remove<InputComponent>(entity_b);
|
|
|
|
|
expect_eq(registry->view<InputComponent>().get_size(), 0);
|
2025-09-18 19:16:54 +03:30
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-30 06:44:09 +03:30
|
|
|
Suite tick = "tick"_suite = [] {
|
2025-09-18 19:16:54 +03:30
|
|
|
Case { "Empty tick won't throw" } = [] {
|
|
|
|
|
auto fixture = Fixture {};
|
2025-09-20 15:39:45 +03:30
|
|
|
auto registry = fixture.registry();
|
2025-09-18 19:16:54 +03:30
|
|
|
auto system = System { fixture.registry() };
|
|
|
|
|
|
2025-09-22 18:51:23 +03:30
|
|
|
system.tick(tick_info());
|
2025-09-18 19:16:54 +03:30
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Case { "Tick triggers input action" } = [] {
|
|
|
|
|
auto fixture = Fixture {};
|
2025-09-20 15:39:45 +03:30
|
|
|
auto registry = fixture.registry();
|
2025-09-18 19:16:54 +03:30
|
|
|
auto system = System { fixture.registry() };
|
|
|
|
|
|
2025-09-20 15:39:45 +03:30
|
|
|
auto surface_entity = fixture.add_surface_component();
|
2026-01-20 13:22:30 +03:30
|
|
|
auto &surface = registry->get<lt::surface::SurfaceComponent>(surface_entity);
|
2025-09-20 15:39:45 +03:30
|
|
|
|
|
|
|
|
auto input_entity = fixture.add_input_component();
|
|
|
|
|
auto &input = registry->get<InputComponent>(input_entity);
|
2025-09-18 19:16:54 +03:30
|
|
|
|
|
|
|
|
auto action_key = input.add_action(
|
|
|
|
|
{
|
|
|
|
|
.name { "test" },
|
2026-01-09 21:53:37 +03:30
|
|
|
.trigger = { .mapped_keycode = Key::a },
|
2025-09-18 19:16:54 +03:30
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
2026-01-20 13:22:30 +03:30
|
|
|
using enum ::lt::input::InputAction::State;
|
|
|
|
|
expect_eq(input.get_action(action_key).state, inactive);
|
2025-09-22 18:51:23 +03:30
|
|
|
system.tick(tick_info());
|
2026-01-20 13:22:30 +03:30
|
|
|
expect_eq(input.get_action(action_key).state, inactive);
|
2025-09-18 19:16:54 +03:30
|
|
|
|
2026-01-20 13:22:30 +03:30
|
|
|
surface.push_event(lt::surface::KeyPressedEvent(Key::a));
|
2025-09-22 18:51:23 +03:30
|
|
|
system.tick(tick_info());
|
2026-01-20 13:22:30 +03:30
|
|
|
expect_eq(input.get_action(action_key).state, triggered);
|
2025-09-18 19:16:54 +03:30
|
|
|
|
2025-09-22 18:51:23 +03:30
|
|
|
system.tick(tick_info());
|
2026-01-20 13:22:30 +03:30
|
|
|
expect_eq(input.get_action(action_key).state, active);
|
2025-09-18 19:16:54 +03:30
|
|
|
|
2025-09-22 18:51:23 +03:30
|
|
|
system.tick(tick_info());
|
|
|
|
|
system.tick(tick_info());
|
|
|
|
|
system.tick(tick_info());
|
2026-01-20 13:22:30 +03:30
|
|
|
expect_eq(input.get_action(action_key).state, active);
|
2025-09-18 19:16:54 +03:30
|
|
|
|
2026-01-20 13:22:30 +03:30
|
|
|
surface.push_event(lt::surface::KeyReleasedEvent(Key::a));
|
2025-09-22 18:51:23 +03:30
|
|
|
system.tick(tick_info());
|
2026-01-20 13:22:30 +03:30
|
|
|
expect_eq(input.get_action(action_key).state, inactive);
|
2025-09-18 19:16:54 +03:30
|
|
|
};
|
|
|
|
|
};
|