Files
yaze/test/e2e/dungeon_editor_tests.cc
scawful 6c331f1fd0 epic: refactor SDL2_Renderer usage to IRenderer and queued texture rendering
- Updated the testing guide to clarify the testing framework's organization and execution methods, improving user understanding.
- Refactored CMakeLists to include new platform-specific files, ensuring proper integration of the rendering backend.
- Modified main application files to utilize the new IRenderer interface, enhancing flexibility in rendering operations.
- Implemented deferred texture management in various components, allowing for more efficient graphics handling and improved performance.
- Introduced new methods for texture creation and updates, streamlining the rendering process across the application.
- Enhanced logging and error handling in the rendering pipeline to facilitate better debugging and diagnostics.
2025-10-07 17:15:11 -04:00

418 lines
14 KiB
C++

#include "imgui.h"
#ifdef IMGUI_ENABLE_TEST_ENGINE
#include "imgui_test_engine/imgui_te_context.h"
#include "imgui_test_engine/imgui_te_engine.h"
#include "imgui_test_engine/imgui_te_ui.h"
#endif
#include "app/editor/dungeon/dungeon_editor.h"
#include "app/gui/widgets/widget_id_registry.h"
#include "app/rom.h"
namespace yaze {
namespace test {
#ifdef IMGUI_ENABLE_TEST_ENGINE
/**
* @file dungeon_editor_tests.cc
* @brief Comprehensive ImGui Test Engine tests for the Dungeon Editor
*
* These tests cover:
* - Canvas rendering and visibility
* - Room selection and loading
* - Object placement and manipulation
* - Property editing
* - Layer management
* - Graphics and palette loading
*/
// ============================================================================
// Test Variables and Fixtures
// ============================================================================
struct DungeonEditorTestVars {
editor::DungeonEditor* editor = nullptr;
Rom* rom = nullptr;
bool rom_loaded = false;
int selected_room_id = 0;
bool canvas_visible = false;
ImVec2 canvas_size = ImVec2(0, 0);
int object_count = 0;
};
// ============================================================================
// Canvas Rendering Tests
// ============================================================================
void RegisterDungeonCanvasTests(ImGuiTestEngine* engine) {
// Test: Canvas should be visible after room selection
ImGuiTest* t =
IM_REGISTER_TEST(engine, "dungeon_editor", "canvas_visibility");
t->SetVarsDataType<DungeonEditorTestVars>();
t->TestFunc = [](ImGuiTestContext* ctx) {
DungeonEditorTestVars& vars = ctx->GetVars<DungeonEditorTestVars>();
// Wait for the dungeon editor window to be available
ctx->SetRef("Dungeon Editor");
// Verify canvas is present
ctx->ItemInfo("Dungeon/Canvas/canvas:DungeonCanvas");
IM_CHECK(ctx->ItemInfo("Dungeon/Canvas/canvas:DungeonCanvas").ID != 0);
// Canvas should be visible
ImGuiWindow* canvas_window = ctx->GetWindowByRef("Dungeon/Canvas");
IM_CHECK(canvas_window != nullptr);
IM_CHECK(canvas_window->Active);
vars.canvas_visible = true;
};
// Test: Canvas should render after loading ROM
t = IM_REGISTER_TEST(engine, "dungeon_editor", "canvas_rendering_after_load");
t->SetVarsDataType<DungeonEditorTestVars>();
t->TestFunc = [](ImGuiTestContext* ctx) {
DungeonEditorTestVars& vars = ctx->GetVars<DungeonEditorTestVars>();
ctx->SetRef("Dungeon Editor");
// Click "Load ROM" button if available
if (ctx->ItemExists("File/button:LoadROM")) {
ctx->ItemClick("File/button:LoadROM");
ctx->Yield(); // Wait for ROM to load
}
// Verify canvas renders something (not blank)
// We can check if the canvas texture was created
auto canvas_info = ctx->ItemInfo("Dungeon/Canvas/canvas:DungeonCanvas");
IM_CHECK(canvas_info.RectFull.GetSize().x > 0 &&
canvas_info.RectFull.GetSize().y > 0);
// Check that the canvas has non-zero size
vars.canvas_size = canvas_info.RectFull.GetSize();
IM_CHECK(vars.canvas_size.x > 0);
IM_CHECK(vars.canvas_size.y > 0);
};
// Test: Canvas should update when room changes
t = IM_REGISTER_TEST(engine, "dungeon_editor",
"canvas_updates_on_room_change");
t->SetVarsDataType<DungeonEditorTestVars>();
t->TestFunc = [](ImGuiTestContext* ctx) {
ctx->SetRef("Dungeon Editor");
// Select room 0
ctx->ItemClick("Dungeon/RoomSelector/selectable:Room_0");
ctx->Yield();
// Capture initial canvas state
ImVec2 size1 =
ctx->ItemInfo("Dungeon/Canvas/canvas:DungeonCanvas").RectFull.GetSize();
// Select room 1
ctx->ItemClick("Dungeon/RoomSelector/selectable:Room_1");
ctx->Yield();
// Canvas should still be valid (may have different content, but same size)
ImVec2 size2 =
ctx->ItemInfo("Dungeon/Canvas/canvas:DungeonCanvas").RectFull.GetSize();
IM_CHECK(size2.x > 0 && size2.y > 0);
};
}
// ============================================================================
// Room Selection Tests
// ============================================================================
void RegisterDungeonRoomSelectorTests(ImGuiTestEngine* engine) {
// Test: Room selector should be visible
ImGuiTest* t =
IM_REGISTER_TEST(engine, "dungeon_editor", "room_selector_visible");
t->TestFunc = [](ImGuiTestContext* ctx) {
ctx->SetRef("Dungeon Editor");
// Verify room selector table exists
ctx->ItemInfo("Dungeon/RoomSelector/table:RoomList");
IM_CHECK(ctx->ItemInfo("Dungeon/RoomSelector/table:RoomList").ID != 0);
};
// Test: Clicking room should change selection
t = IM_REGISTER_TEST(engine, "dungeon_editor", "room_selection_click");
t->SetVarsDataType<DungeonEditorTestVars>();
t->TestFunc = [](ImGuiTestContext* ctx) {
DungeonEditorTestVars& vars = ctx->GetVars<DungeonEditorTestVars>();
ctx->SetRef("Dungeon Editor");
// Click on room 5
ctx->ItemClick("Dungeon/RoomSelector/selectable:Room_5");
vars.selected_room_id = 5;
// Verify the room is now selected (visual feedback should exist)
// We can check if the canvas updates or if selection state changes
ctx->Yield();
// Success if we got here without errors
IM_CHECK(vars.selected_room_id == 5);
};
// Test: Multiple room tabs should work
t = IM_REGISTER_TEST(engine, "dungeon_editor", "room_tabs_switching");
t->TestFunc = [](ImGuiTestContext* ctx) {
ctx->SetRef("Dungeon Editor");
// Open room 0
ctx->ItemClick("Dungeon/RoomSelector/selectable:Room_0");
ctx->Yield();
// Open room 10 (should create a new tab)
ctx->ItemClick("Dungeon/RoomSelector/selectable:Room_10");
ctx->Yield();
// Switch back to room 0 tab
if (ctx->ItemExists("Dungeon/Canvas/tab:Room_0")) {
ctx->ItemClick("Dungeon/Canvas/tab:Room_0");
ctx->Yield();
// Verify we're on room 0
IM_CHECK(ctx->ItemInfo("Dungeon/Canvas/tab:Room_0").StatusFlags &
ImGuiItemStatusFlags_Opened);
}
};
}
// ============================================================================
// Object Editor Tests
// ============================================================================
void RegisterDungeonObjectEditorTests(ImGuiTestEngine* engine) {
// Test: Object selector should be visible
ImGuiTest* t =
IM_REGISTER_TEST(engine, "dungeon_editor", "object_selector_visible");
t->TestFunc = [](ImGuiTestContext* ctx) {
ctx->SetRef("Dungeon Editor");
// Verify object selector exists
IM_CHECK(ctx->ItemExists("Dungeon/ObjectSelector"));
};
// Test: Selecting object should enable placement mode
t = IM_REGISTER_TEST(engine, "dungeon_editor", "object_selection");
t->TestFunc = [](ImGuiTestContext* ctx) {
ctx->SetRef("Dungeon Editor");
// Click on an object in the selector
if (ctx->ItemExists("Dungeon/ObjectSelector/selectable:Object_0")) {
ctx->ItemClick("Dungeon/ObjectSelector/selectable:Object_0");
ctx->Yield();
// Object should be selected (visual feedback should exist)
// Success if no errors
}
};
// Test: Object property panel should show when object selected
t = IM_REGISTER_TEST(engine, "dungeon_editor", "object_property_panel");
t->TestFunc = [](ImGuiTestContext* ctx) {
ctx->SetRef("Dungeon Editor");
// Place or select an object
ctx->ItemClick("Dungeon/Canvas/canvas:DungeonCanvas",
ImGuiMouseButton_Left);
ctx->Yield();
// Property panel should appear
// (This might be conditional on having objects in the room)
if (ctx->ItemExists("Dungeon/ObjectEditor/input_int:ObjectID")) {
// Can edit object ID
ctx->ItemInputValue("Dungeon/ObjectEditor/input_int:ObjectID", 42);
ctx->Yield();
}
};
}
// ============================================================================
// Layer Management Tests
// ============================================================================
void RegisterDungeonLayerTests(ImGuiTestEngine* engine) {
// Test: Layer controls should be visible
ImGuiTest* t =
IM_REGISTER_TEST(engine, "dungeon_editor", "layer_controls_visible");
t->TestFunc = [](ImGuiTestContext* ctx) {
ctx->SetRef("Dungeon Editor");
// Verify layer checkboxes exist
if (ctx->ItemExists("Dungeon/ObjectEditor/checkbox:ShowBG1")) {
IM_CHECK(ctx->ItemInfo("Dungeon/ObjectEditor/checkbox:ShowBG1").ID != 0);
}
if (ctx->ItemExists("Dungeon/ObjectEditor/checkbox:ShowBG2")) {
IM_CHECK(ctx->ItemInfo("Dungeon/ObjectEditor/checkbox:ShowBG2").ID != 0);
}
};
// Test: Toggling layer visibility
t = IM_REGISTER_TEST(engine, "dungeon_editor", "layer_toggle");
t->TestFunc = [](ImGuiTestContext* ctx) {
ctx->SetRef("Dungeon Editor");
// Toggle BG1 layer
if (ctx->ItemExists("Dungeon/ObjectEditor/checkbox:ShowBG1")) {
ctx->ItemClick("Dungeon/ObjectEditor/checkbox:ShowBG1");
ctx->Yield();
// Toggle it back
ctx->ItemClick("Dungeon/ObjectEditor/checkbox:ShowBG1");
ctx->Yield();
}
};
}
// ============================================================================
// Palette and Graphics Tests
// ============================================================================
void RegisterDungeonGraphicsTests(ImGuiTestEngine* engine) {
// Test: Palette editor should open
ImGuiTest* t = IM_REGISTER_TEST(engine, "dungeon_editor", "palette_editor");
t->TestFunc = [](ImGuiTestContext* ctx) {
ctx->SetRef("Dungeon Editor");
// Click "Palette Editor" button if available
if (ctx->ItemExists("Dungeon/Toolset/button:PaletteEditor")) {
ctx->ItemClick("Dungeon/Toolset/button:PaletteEditor");
ctx->Yield();
// Palette window should open
IM_CHECK(ctx->WindowInfo("Palette Editor").Window != nullptr);
}
};
// Test: Graphics should load for selected room
t = IM_REGISTER_TEST(engine, "dungeon_editor", "graphics_loading");
t->TestFunc = [](ImGuiTestContext* ctx) {
ctx->SetRef("Dungeon Editor");
// Select a room
ctx->ItemClick("Dungeon/RoomSelector/selectable:Room_0");
ctx->Yield(2); // Wait for graphics to load
// Canvas should have valid content
auto canvas_info = ctx->ItemInfo("Dungeon/Canvas/canvas:DungeonCanvas");
IM_CHECK(canvas_info.RectFull.GetWidth() > 0);
};
}
// ============================================================================
// Integration Tests
// ============================================================================
void RegisterDungeonIntegrationTests(ImGuiTestEngine* engine) {
// Test: Full workflow - load ROM, select room, place object
ImGuiTest* t =
IM_REGISTER_TEST(engine, "dungeon_editor", "full_edit_workflow");
t->TestFunc = [](ImGuiTestContext* ctx) {
ctx->SetRef("Dungeon Editor");
// 1. Load ROM (if needed)
ctx->Yield(2);
// 2. Select a room
ctx->ItemClick("Dungeon/RoomSelector/selectable:Room_5");
ctx->Yield(2);
// 3. Select an object type
if (ctx->ItemExists("Dungeon/ObjectSelector/selectable:Object_1")) {
ctx->ItemClick("Dungeon/ObjectSelector/selectable:Object_1");
ctx->Yield();
}
// 4. Click on canvas to place object
ctx->ItemClick("Dungeon/Canvas/canvas:DungeonCanvas",
ImGuiMouseButton_Left);
ctx->Yield();
// 5. Verify object was placed (property panel should appear)
// This is a basic workflow test - success if no crashes
};
}
// ============================================================================
// Widget Discovery Tests
// ============================================================================
void RegisterDungeonWidgetDiscoveryTests(ImGuiTestEngine* engine) {
// Test: Widget registry should capture all dungeon editor widgets
ImGuiTest* t =
IM_REGISTER_TEST(engine, "dungeon_editor", "widget_registry_complete");
t->TestFunc = [](ImGuiTestContext* ctx) {
ctx->SetRef("Dungeon Editor");
// Yield a few frames to let widgets register
ctx->Yield(3);
// Query the widget registry
auto& registry = gui::WidgetIdRegistry::Instance();
auto all_widgets = registry.GetAllWidgets();
// Should have multiple widgets registered
IM_CHECK(all_widgets.size() > 10);
// Essential widgets should be present
IM_CHECK(registry.GetWidgetId("Dungeon/RoomSelector/table:RoomList") != 0);
IM_CHECK(registry.GetWidgetId("Dungeon/Canvas/canvas:DungeonCanvas") != 0);
};
// Test: Export widget catalog
t = IM_REGISTER_TEST(engine, "dungeon_editor", "widget_catalog_export");
t->TestFunc = [](ImGuiTestContext* ctx) {
ctx->SetRef("Dungeon Editor");
ctx->Yield(2);
auto& registry = gui::WidgetIdRegistry::Instance();
// Export to JSON
std::string json_catalog = registry.ExportCatalog("json");
IM_CHECK(!json_catalog.empty());
IM_CHECK(json_catalog.find("\"widgets\"") != std::string::npos);
// Export to YAML
std::string yaml_catalog = registry.ExportCatalog("yaml");
IM_CHECK(!yaml_catalog.empty());
IM_CHECK(yaml_catalog.find("widgets:") != std::string::npos);
};
}
// ============================================================================
// Registration Function
// ============================================================================
/**
* @brief Register all dungeon editor tests with the ImGui Test Engine
*
* Call this function during application initialization to register all
* automated tests for the dungeon editor.
*
* @param engine The ImGuiTestEngine instance
*/
void RegisterDungeonEditorTests(ImGuiTestEngine* engine) {
RegisterDungeonCanvasTests(engine);
RegisterDungeonRoomSelectorTests(engine);
RegisterDungeonObjectEditorTests(engine);
RegisterDungeonLayerTests(engine);
RegisterDungeonGraphicsTests(engine);
RegisterDungeonIntegrationTests(engine);
RegisterDungeonWidgetDiscoveryTests(engine);
}
#endif // IMGUI_ENABLE_TEST_ENGINE
} // namespace test
} // namespace yaze