#include #include #include #include #include // NOLINTBEGIN using namespace lt; using input::InputComponent; using input::System; using std::ignore; using test::Case; using test::expect_eq; using test::expect_false; using test::expect_ne; using test::expect_not_nullptr; using test::expect_throw; using test::Suite; // NOLINTEND [[nodiscard]] auto tick_info() -> app::TickInfo { return { .delta_time = std::chrono::milliseconds { 16 }, .budget = std::chrono::milliseconds { 10 }, .start_time = std::chrono::steady_clock::now(), }; } class Fixture { public: [[nodiscard]] auto registry() -> Ref { return m_registry; } auto add_input_component() -> ecs::EntityId { auto entity = m_registry->create_entity(); m_registry->add(entity, {}); return entity; } auto add_surface_component() -> ecs::EntityId { auto entity = m_registry->create_entity(); m_registry->add( entity, surface::SurfaceComponent::CreateInfo {} ); return entity; } private: Ref m_registry = create_ref(); }; Suite raii = [] { Case { "happy path won't throw" } = [&] { System { Fixture {}.registry() }; }; Case { "many won't freeze/throw" } = [&] { auto fixture = Fixture {}; for (auto idx : std::views::iota(0, 10'000)) { ignore = System { fixture.registry() }; } }; Case { "unhappy path throws" } = [] { expect_throw([] { ignore = System { {} }; }); }; }; Suite system_events = [] { Case { "on_register won't throw" } = [] { auto fixture = Fixture {}; auto registry = fixture.registry(); auto system = System { registry }; system.on_register(); expect_eq(registry->view().get_size(), 0); }; Case { "on_unregister won't throw" } = [] { auto fixture = Fixture {}; auto registry = fixture.registry(); auto system = System { registry }; system.on_register(); system.on_unregister(); expect_eq(registry->view().get_size(), 0); }; }; Suite registry_events = [] { Case { "on_construct" } = [] { auto fixture = Fixture {}; auto registry = fixture.registry(); auto system = System { registry }; const auto &entity = fixture.add_input_component(); expect_eq(registry->view().get_size(), 1); }; Case { "on_destrroy" } = [] { auto fixture = Fixture {}; auto registry = fixture.registry(); auto system = create_scope(registry); auto entity_a = fixture.add_input_component(); auto entity_b = fixture.add_input_component(); expect_eq(registry->view().get_size(), 2); registry->remove(entity_a); expect_eq(registry->view().get_size(), 1); system.reset(); expect_eq(registry->view().get_size(), 1); registry->remove(entity_b); expect_eq(registry->view().get_size(), 0); }; }; Suite tick = [] { Case { "Empty tick won't throw" } = [] { auto fixture = Fixture {}; auto registry = fixture.registry(); auto system = System { fixture.registry() }; system.tick(tick_info()); }; Case { "Tick triggers input action" } = [] { auto fixture = Fixture {}; auto registry = fixture.registry(); auto system = System { fixture.registry() }; auto surface_entity = fixture.add_surface_component(); auto &surface = registry->get(surface_entity); auto input_entity = fixture.add_input_component(); auto &input = registry->get(input_entity); auto action_key = input.add_action( { .name { "test" }, .trigger = { .mapped_keycode = 69 }, } ); expect_eq(input.get_action(action_key).state, input::InputAction::State::inactive); system.tick(tick_info()); expect_eq(input.get_action(action_key).state, input::InputAction::State::inactive); surface.push_event(surface::KeyPressedEvent(69)); system.tick(tick_info()); expect_eq(input.get_action(action_key).state, input::InputAction::State::triggered); system.tick(tick_info()); expect_eq(input.get_action(action_key).state, input::InputAction::State::active); system.tick(tick_info()); system.tick(tick_info()); system.tick(tick_info()); expect_eq(input.get_action(action_key).state, input::InputAction::State::active); surface.push_event(surface::KeyReleasedEvent(69)); system.tick(tick_info()); expect_eq(input.get_action(action_key).state, input::InputAction::State::inactive); }; Case { "Tick triggers" } = [] { auto fixture = Fixture {}; auto registry = fixture.registry(); auto system = System { fixture.registry() }; auto surface_entity = fixture.add_surface_component(); auto &surface = registry->get(surface_entity); auto input_entity = fixture.add_input_component(); auto &input = registry->get(input_entity); auto action_key = input.add_action( { .name { "test" }, .trigger = { .mapped_keycode = 69 }, } ); }; };