test(surface): add fuzz testing
test(surface): add & fix unit tests fix(surface): bugs refactor(surface): minor refactors & some edge-case handling
This commit is contained in:
		
							parent
							
								
									60ad7cdc70
								
							
						
					
					
						commit
						e36991e6de
					
				
					 6 changed files with 256 additions and 47 deletions
				
			
		| 
						 | 
					@ -13,4 +13,4 @@ target_link_libraries(surface PUBLIC
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_test_module(surface system.test.cpp)
 | 
					add_test_module(surface system.test.cpp)
 | 
				
			||||||
target_link_libraries(surface_tests PRIVATE glfw)
 | 
					add_fuzz_module(surface system.fuzz.cpp)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,11 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt::surface {
 | 
					namespace lt::surface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void glfw_error_callbac(int32_t code, const char *description)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						log_err("GLFW ERROR: {} -> {}", code, description);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_event(GLFWwindow *window, const SurfaceComponent::Event &event)
 | 
					void handle_event(GLFWwindow *window, const SurfaceComponent::Event &event)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto &callbacks = *static_cast<std::vector<SurfaceComponent::EventCallback> *>(
 | 
						auto &callbacks = *static_cast<std::vector<SurfaceComponent::EventCallback> *>(
 | 
				
			||||||
| 
						 | 
					@ -92,9 +97,15 @@ void bind_glfw_events(GLFWwindow *handle)
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void init_glfw() {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
System::System(Ref<ecs::Registry> registry): m_registry(std::move(registry))
 | 
					System::System(Ref<ecs::Registry> registry): m_registry(std::move(registry))
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						glfwSetErrorCallback(&glfw_error_callbac);
 | 
				
			||||||
 | 
						ensure(glfwInit(), "Failed to initialize 'glfw'");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ensure(m_registry, "Failed to initialize surface system: null registry");
 | 
						ensure(m_registry, "Failed to initialize surface system: null registry");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ensure(
 | 
						ensure(
 | 
				
			||||||
	    m_registry->view<SurfaceComponent>().size() == 0,
 | 
						    m_registry->view<SurfaceComponent>().size() == 0,
 | 
				
			||||||
	    "Failed to initialize surface system: registry has surface component(s)"
 | 
						    "Failed to initialize surface system: registry has surface component(s)"
 | 
				
			||||||
| 
						 | 
					@ -129,7 +140,6 @@ System::~System()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m_registry->view<SurfaceComponent>().each([&](const entt::entity entity, SurfaceComponent &) {
 | 
						m_registry->view<SurfaceComponent>().each([&](const entt::entity entity, SurfaceComponent &) {
 | 
				
			||||||
		std::cout << "REMOVED SURFACE COMPONENT ON DESTRUCTION" << std::endl;
 | 
					 | 
				
			||||||
		m_registry->get_entt_registry().remove<SurfaceComponent>(entity);
 | 
							m_registry->get_entt_registry().remove<SurfaceComponent>(entity);
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -138,19 +148,18 @@ System::~System()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void System::on_surface_construct(entt::registry ®istry, entt::entity entity)
 | 
					void System::on_surface_construct(entt::registry ®istry, entt::entity entity)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ensure(glfwInit(), "Failed to initialize 'glfw'");
 | 
						try
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto &surface = registry.get<SurfaceComponent>(entity);
 | 
				
			||||||
 | 
							ensure_component_sanity(surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
 | 
							glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
 | 
				
			||||||
		glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
 | 
							glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
 | 
				
			||||||
		glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
 | 
							glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
 | 
				
			||||||
	// glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	auto &surface = registry.get<SurfaceComponent>(entity);
 | 
					 | 
				
			||||||
	auto [width, height] = surface.get_size();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		surface.m_glfw_handle = glfwCreateWindow(
 | 
							surface.m_glfw_handle = glfwCreateWindow(
 | 
				
			||||||
	    static_cast<int32_t>(width),
 | 
							    static_cast<int>(surface.get_resolution().x),
 | 
				
			||||||
	    static_cast<int32_t>(height),
 | 
							    static_cast<int>(surface.get_resolution().y),
 | 
				
			||||||
		    surface.get_title().begin(),
 | 
							    surface.get_title().begin(),
 | 
				
			||||||
		    nullptr,
 | 
							    nullptr,
 | 
				
			||||||
		    nullptr
 | 
							    nullptr
 | 
				
			||||||
| 
						 | 
					@ -160,6 +169,12 @@ void System::on_surface_construct(entt::registry ®istry, entt::entity entity)
 | 
				
			||||||
		glfwSetWindowUserPointer(surface.m_glfw_handle, &surface.m_event_callbacks);
 | 
							glfwSetWindowUserPointer(surface.m_glfw_handle, &surface.m_event_callbacks);
 | 
				
			||||||
		surface.m_native_handle = glfwGetX11Window(surface.m_glfw_handle);
 | 
							surface.m_native_handle = glfwGetX11Window(surface.m_glfw_handle);
 | 
				
			||||||
		bind_glfw_events(surface.m_glfw_handle);
 | 
							bind_glfw_events(surface.m_glfw_handle);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						catch (...)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							registry.remove<SurfaceComponent>(entity);
 | 
				
			||||||
 | 
							throw;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void System::on_surface_update(entt::registry ®istry, entt::entity entity)
 | 
					void System::on_surface_update(entt::registry ®istry, entt::entity entity)
 | 
				
			||||||
| 
						 | 
					@ -171,7 +186,11 @@ void System::on_surface_update(entt::registry ®istry, entt::entity entity)
 | 
				
			||||||
void System::on_surface_destroy(entt::registry ®istry, entt::entity entity)
 | 
					void System::on_surface_destroy(entt::registry ®istry, entt::entity entity)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto &surface = registry.get<SurfaceComponent>(entity);
 | 
						auto &surface = registry.get<SurfaceComponent>(entity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (surface.m_glfw_handle)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
		glfwDestroyWindow(surface.m_glfw_handle);
 | 
							glfwDestroyWindow(surface.m_glfw_handle);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void System::set_title(ecs::Entity entity, std::string_view new_title)
 | 
					void System::set_title(ecs::Entity entity, std::string_view new_title)
 | 
				
			||||||
| 
						 | 
					@ -179,11 +198,15 @@ void System::set_title(ecs::Entity entity, std::string_view new_title)
 | 
				
			||||||
	auto &surface = entity.get_component<SurfaceComponent>();
 | 
						auto &surface = entity.get_component<SurfaceComponent>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	surface.m_title = new_title;
 | 
						surface.m_title = new_title;
 | 
				
			||||||
	glfwSetWindowTitle(surface.m_glfw_handle, surface.m_title.begin());
 | 
						glfwSetWindowTitle(surface.m_glfw_handle, surface.m_title.c_str());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auto System::tick() -> bool
 | 
					auto System::tick() -> bool
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						m_registry->view<SurfaceComponent>().each([](SurfaceComponent &surface) {
 | 
				
			||||||
 | 
							glfwSwapBuffers(surface.m_glfw_handle);
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	glfwPollEvents();
 | 
						glfwPollEvents();
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -191,7 +214,7 @@ auto System::tick() -> bool
 | 
				
			||||||
void System::set_size(ecs::Entity surface_entity, const math::uvec2 &new_size)
 | 
					void System::set_size(ecs::Entity surface_entity, const math::uvec2 &new_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto &surface = surface_entity.get_component<SurfaceComponent>();
 | 
						auto &surface = surface_entity.get_component<SurfaceComponent>();
 | 
				
			||||||
	surface.m_size = new_size;
 | 
						surface.m_resolution = new_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	glfwSetWindowSize(
 | 
						glfwSetWindowSize(
 | 
				
			||||||
	    surface.m_glfw_handle,
 | 
						    surface.m_glfw_handle,
 | 
				
			||||||
| 
						 | 
					@ -232,6 +255,36 @@ void System::add_event_listener(
 | 
				
			||||||
	surface.m_event_callbacks.emplace_back(std::move(callback));
 | 
						surface.m_event_callbacks.emplace_back(std::move(callback));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void System::ensure_component_sanity(const SurfaceComponent &component)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						auto [width, height] = component.get_resolution();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(width != 0u, "Received bad values for surface component: width({}) == 0", width);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(height != 0u, "Received bad values for surface component: height({}) == 0", height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    width < SurfaceComponent::max_dimension,
 | 
				
			||||||
 | 
						    "Received bad values for surface component: width({}) > max_dimension({})",
 | 
				
			||||||
 | 
						    width,
 | 
				
			||||||
 | 
						    SurfaceComponent::max_dimension
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    height < SurfaceComponent::max_dimension,
 | 
				
			||||||
 | 
						    "Received bad values for surface component: height({}) > max_dimension({})",
 | 
				
			||||||
 | 
						    height,
 | 
				
			||||||
 | 
						    SurfaceComponent::max_dimension
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ensure(
 | 
				
			||||||
 | 
						    component.get_title().size() < SurfaceComponent::max_title_length,
 | 
				
			||||||
 | 
						    "Received bad values for surface component: title.size({}) > max_title_length({})",
 | 
				
			||||||
 | 
						    component.get_title().size(),
 | 
				
			||||||
 | 
						    SurfaceComponent::max_title_length
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace lt::surface
 | 
					} // namespace lt::surface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace lt {
 | 
					namespace lt {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										103
									
								
								modules/surface/private/system.fuzz.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								modules/surface/private/system.fuzz.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,103 @@
 | 
				
			||||||
 | 
					#include <ecs/scene.hpp>
 | 
				
			||||||
 | 
					#include <surface/system.hpp>
 | 
				
			||||||
 | 
					#include <test/fuzz.hpp>
 | 
				
			||||||
 | 
					#include <test/test.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace lt::surface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class Action : uint8_t
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						create_entity,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						create_surface_component,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						destroy_surface_component,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tick,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void create_surface_component(test::FuzzDataProvider &provider, ecs::Registry ®istry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const auto length = std::min(provider.consume<uint32_t>().value_or(16), 255u);
 | 
				
			||||||
 | 
						const auto title = provider.consume_string(length).value_or("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const auto resolution = math::uvec2 {
 | 
				
			||||||
 | 
							provider.consume<uint32_t>().value_or({ 32 }),
 | 
				
			||||||
 | 
							provider.consume<uint32_t>().value_or({ 64 }),
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						const auto visible = provider.consume<bool>().value_or(false);
 | 
				
			||||||
 | 
						const auto vsync = provider.consume<bool>().value_or(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						try
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							registry.create_entity("").add_component<surface::SurfaceComponent>(
 | 
				
			||||||
 | 
							    surface::SurfaceComponent::CreateInfo {
 | 
				
			||||||
 | 
							        .title = std::move(title),
 | 
				
			||||||
 | 
							        .resolution = resolution,
 | 
				
			||||||
 | 
							        .vsync = vsync,
 | 
				
			||||||
 | 
							        .visible = visible,
 | 
				
			||||||
 | 
							    }
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						catch (const std::exception &exp)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							std::ignore = exp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void remove_surface_component(ecs::Registry ®istry)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const auto view = registry.get_entt_registry().view<SurfaceComponent>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!view->empty())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							registry.get_entt_registry().remove<SurfaceComponent>(*view.begin());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void check_invariants()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test::FuzzHarness harness = [](const uint8_t *data, size_t size) {
 | 
				
			||||||
 | 
						auto provider = test::FuzzDataProvider { data, size };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto registry = create_ref<ecs::Registry>();
 | 
				
			||||||
 | 
						auto system = surface::System { registry };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (auto action = provider.consume<uint8_t>())
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							switch (static_cast<Action>(action.value()))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
							case Action::create_entity:
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								const auto length = std::min(provider.consume<uint32_t>().value_or(16), 255u);
 | 
				
			||||||
 | 
								const auto tag = provider.consume_string(length).value_or("");
 | 
				
			||||||
 | 
								registry->create_entity(tag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							case Action::create_surface_component:
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								create_surface_component(provider, *registry);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							case Action::destroy_surface_component:
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								remove_surface_component(*registry);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							case Action::tick:
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								system.tick();
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							check_invariants();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace lt::surface
 | 
				
			||||||
| 
						 | 
					@ -26,22 +26,24 @@ public:
 | 
				
			||||||
		return m_registry;
 | 
							return m_registry;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto add_surface_component() -> SurfaceComponent &
 | 
						auto add_surface_component(
 | 
				
			||||||
	{
 | 
						    SurfaceComponent::CreateInfo info = SurfaceComponent::CreateInfo {
 | 
				
			||||||
		auto entity = m_registry->create_entity("");
 | 
					 | 
				
			||||||
		return entity.add_component<SurfaceComponent>(SurfaceComponent::CreateInfo {
 | 
					 | 
				
			||||||
	        .title = title,
 | 
						        .title = title,
 | 
				
			||||||
		    .size = { width, height },
 | 
						        .resolution = { width, height },
 | 
				
			||||||
	        .vsync = vsync,
 | 
						        .vsync = vsync,
 | 
				
			||||||
	        .visible = visible,
 | 
						        .visible = visible,
 | 
				
			||||||
		});
 | 
						    }
 | 
				
			||||||
 | 
						) -> SurfaceComponent &
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							auto entity = m_registry->create_entity("");
 | 
				
			||||||
 | 
							return entity.add_component<SurfaceComponent>(info);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void check_values(const SurfaceComponent &component)
 | 
						void check_values(const SurfaceComponent &component)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		expect_ne(std::get<SurfaceComponent::X11NativeHandle>(component.get_native_handle()), 0);
 | 
							expect_ne(std::get<SurfaceComponent::X11NativeHandle>(component.get_native_handle()), 0);
 | 
				
			||||||
		expect_eq(component.get_size().x, width);
 | 
							expect_eq(component.get_resolution().x, width);
 | 
				
			||||||
		expect_eq(component.get_size().y, height);
 | 
							expect_eq(component.get_resolution().y, height);
 | 
				
			||||||
		expect_eq(component.get_title(), title);
 | 
							expect_eq(component.get_title(), title);
 | 
				
			||||||
		expect_eq(component.is_vsync(), vsync);
 | 
							expect_eq(component.is_vsync(), vsync);
 | 
				
			||||||
		expect_eq(component.is_visible(), visible);
 | 
							expect_eq(component.is_visible(), visible);
 | 
				
			||||||
| 
						 | 
					@ -57,9 +59,11 @@ Suite raii = [] {
 | 
				
			||||||
		ignore = System { fixture.registry() };
 | 
							ignore = System { fixture.registry() };
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Case { "many won't throw" } = [] {
 | 
						Case { "many won't freeze/throw" } = [] {
 | 
				
			||||||
		auto fixture = Fixture {};
 | 
							auto fixture = Fixture {};
 | 
				
			||||||
		for (auto idx : std::views::iota(0, 100'001))
 | 
					
 | 
				
			||||||
 | 
							/* range is small since glfw init/terminate is slow. */
 | 
				
			||||||
 | 
							for (auto idx : std::views::iota(0, 100))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			ignore = System { fixture.registry() };
 | 
								ignore = System { fixture.registry() };
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -78,6 +82,17 @@ Suite raii = [] {
 | 
				
			||||||
		auto system = System { fixture.registry() };
 | 
							auto system = System { fixture.registry() };
 | 
				
			||||||
		expect_eq(fixture.registry()->view<SurfaceComponent>()->size(), 0);
 | 
							expect_eq(fixture.registry()->view<SurfaceComponent>()->size(), 0);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "post destruct has correct state" } = [] {
 | 
				
			||||||
 | 
							auto fixture = Fixture {};
 | 
				
			||||||
 | 
							auto system = create_scope<System>(fixture.registry());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							fixture.add_surface_component();
 | 
				
			||||||
 | 
							expect_eq(fixture.registry()->view<SurfaceComponent>()->size(), 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							system.reset();
 | 
				
			||||||
 | 
							expect_eq(fixture.registry()->view<SurfaceComponent>()->size(), 0);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Suite system_events = [] {
 | 
					Suite system_events = [] {
 | 
				
			||||||
| 
						 | 
					@ -109,6 +124,41 @@ Suite registry_events = [] {
 | 
				
			||||||
		fixture.check_values(component);
 | 
							fixture.check_values(component);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "unhappy on_construct<SurfaceComponent> throws" } = [] {
 | 
				
			||||||
 | 
							auto fixture = Fixture {};
 | 
				
			||||||
 | 
							auto system = System { fixture.registry() };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_throw([&] { fixture.add_surface_component({ .resolution = { width, 0 } }); });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_throw([&] { fixture.add_surface_component({ .resolution = { 0, height } }); });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_throw([&] {
 | 
				
			||||||
 | 
								fixture.add_surface_component(
 | 
				
			||||||
 | 
								    { .title = "", .resolution = { SurfaceComponent::max_dimension + 1, height } }
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_throw([&] {
 | 
				
			||||||
 | 
								fixture.add_surface_component(
 | 
				
			||||||
 | 
								    { .title = "", .resolution = { width, SurfaceComponent::max_dimension + 1 } }
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							auto big_str = std::string {};
 | 
				
			||||||
 | 
							big_str.resize(SurfaceComponent::max_title_length + 1);
 | 
				
			||||||
 | 
							expect_throw([&] {
 | 
				
			||||||
 | 
								fixture.add_surface_component({ .title = big_str, .resolution = { width, height } });
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Case { "unhappy on_construct<SurfaceComponent> removes component" } = [] {
 | 
				
			||||||
 | 
							auto fixture = Fixture {};
 | 
				
			||||||
 | 
							auto system = System { fixture.registry() };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							expect_throw([&] { fixture.add_surface_component({ .resolution = { width, 0 } }); });
 | 
				
			||||||
 | 
							expect_eq(fixture.registry()->view<SurfaceComponent>().size(), 0);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Case { "on_destrroy<SurfaceComponent> cleans up component" } = [] {
 | 
						Case { "on_destrroy<SurfaceComponent> cleans up component" } = [] {
 | 
				
			||||||
		auto fixture = Fixture {};
 | 
							auto fixture = Fixture {};
 | 
				
			||||||
		auto system = create_scope<System>(fixture.registry());
 | 
							auto system = create_scope<System>(fixture.registry());
 | 
				
			||||||
| 
						 | 
					@ -137,7 +187,7 @@ Suite tick = [] {
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Case { "ticking on chaotic registry won't throw" } = [] {
 | 
						Case { "ticking on chaotic registry won't throw" } = [] {
 | 
				
			||||||
	}
 | 
						};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Suite property_setters = [] {
 | 
					Suite property_setters = [] {
 | 
				
			||||||
| 
						 | 
					@ -146,6 +196,3 @@ Suite property_setters = [] {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Suite listeners = [] {
 | 
					Suite listeners = [] {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
Suite fuzzy = [] {
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,11 +47,15 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	using NativeHandle = std::variant<WindowsNativeHandle, X11NativeHandle>;
 | 
						using NativeHandle = std::variant<WindowsNativeHandle, X11NativeHandle>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static constexpr auto max_dimension = 4096;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static constexpr auto max_title_length = 256;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct CreateInfo
 | 
						struct CreateInfo
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		std::string_view title;
 | 
							std::string_view title;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		math::uvec2 size;
 | 
							math::uvec2 resolution;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bool vsync;
 | 
							bool vsync;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,20 +64,20 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SurfaceComponent(const CreateInfo &info)
 | 
						SurfaceComponent(const CreateInfo &info)
 | 
				
			||||||
	    : m_title(info.title)
 | 
						    : m_title(info.title)
 | 
				
			||||||
	    , m_size(info.size)
 | 
						    , m_resolution(info.resolution)
 | 
				
			||||||
	    , m_vsync(info.vsync)
 | 
						    , m_vsync(info.vsync)
 | 
				
			||||||
	    , m_visible(info.visible)
 | 
						    , m_visible(info.visible)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] auto get_title() const -> const std::string_view &
 | 
						[[nodiscard]] auto get_title() const -> std::string_view
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return m_title;
 | 
							return m_title;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] auto get_size() const -> const math::uvec2 &
 | 
						[[nodiscard]] auto get_resolution() const -> const math::uvec2 &
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return m_size;
 | 
							return m_resolution;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] auto is_vsync() const -> bool
 | 
						[[nodiscard]] auto is_vsync() const -> bool
 | 
				
			||||||
| 
						 | 
					@ -97,9 +101,9 @@ private:
 | 
				
			||||||
		return m_glfw_handle;
 | 
							return m_glfw_handle;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::string_view m_title;
 | 
						std::string m_title;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	math::uvec2 m_size;
 | 
						math::uvec2 m_resolution;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool m_vsync;
 | 
						bool m_vsync;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,7 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto tick() -> bool override;
 | 
						auto tick() -> bool override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void set_title(ecs::Entity surface_entity, std::string_view new_title);
 | 
						static void set_title(ecs::Entity surface_entity, std::string_view new_title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void set_size(ecs::Entity surface_entity, const math::uvec2 &new_size);
 | 
						void set_size(ecs::Entity surface_entity, const math::uvec2 &new_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,6 +49,8 @@ private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void on_surface_destroy(entt::registry ®istry, entt::entity entity);
 | 
						void on_surface_destroy(entt::registry ®istry, entt::entity entity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void ensure_component_sanity(const SurfaceComponent &component);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Ref<ecs::Registry> m_registry;
 | 
						Ref<ecs::Registry> m_registry;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue