feat: Introduce automatic widget registration for ImGui with test engine integration

This commit is contained in:
scawful
2025-10-04 01:43:13 -04:00
parent 164f89e1bb
commit 3edc0c5b63
3 changed files with 770 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
#include "app/gui/widget_auto_register.h"
#include "imgui/imgui_internal.h"
#include "absl/strings/string_view.h"
namespace yaze {
namespace gui {
// Thread-local storage for the current auto-registration scope
thread_local std::vector<std::string> g_auto_scope_stack_;
AutoWidgetScope::AutoWidgetScope(const std::string& name)
: scope_(name), name_(name) {
g_auto_scope_stack_.push_back(name);
}
void AutoRegisterLastItem(const std::string& widget_type,
const std::string& explicit_label,
const std::string& description) {
ImGuiContext* ctx = ImGui::GetCurrentContext();
if (!ctx || !ctx->CurrentWindow) {
return;
}
// Get the last item's ID
ImGuiID imgui_id = ctx->LastItemData.ID;
if (imgui_id == 0) {
return; // No valid item to register
}
// Extract label
std::string label = explicit_label;
if (label.empty()) {
// Try to get label from ImGui
const char* imgui_label = ImGui::GetItemLabel();
if (imgui_label && imgui_label[0] != '\0') {
label = imgui_label;
} else {
// Fallback to widget type + ID
label = absl::StrCat(widget_type, "_", imgui_id);
}
}
// Build full hierarchical path
std::string full_path;
if (!g_auto_scope_stack_.empty()) {
full_path = absl::StrJoin(g_auto_scope_stack_, "/");
full_path += "/";
}
// Add widget type and normalized label
std::string normalized_label = WidgetIdRegistry::NormalizeLabel(label);
full_path += absl::StrCat(widget_type, ":", normalized_label);
// Capture metadata from ImGui's last item
WidgetIdRegistry::WidgetMetadata metadata;
metadata.label = label;
// Get window name
if (ctx->CurrentWindow) {
metadata.window_name = std::string(ctx->CurrentWindow->Name);
}
// Capture visibility and enabled state
const ImGuiLastItemData& last = ctx->LastItemData;
metadata.visible = (last.StatusFlags & ImGuiItemStatusFlags_Visible) != 0;
metadata.enabled = (last.ItemFlags & ImGuiItemFlags_Disabled) == 0;
// Capture bounding rectangle
WidgetIdRegistry::WidgetBounds bounds;
bounds.min_x = last.Rect.Min.x;
bounds.min_y = last.Rect.Min.y;
bounds.max_x = last.Rect.Max.x;
bounds.max_y = last.Rect.Max.y;
bounds.valid = true;
metadata.bounds = bounds;
// Register with the global registry
WidgetIdRegistry::Instance().RegisterWidget(
full_path, widget_type, imgui_id, description, metadata);
}
} // namespace gui
} // namespace yaze

View File

@@ -0,0 +1,268 @@
#ifndef YAZE_APP_GUI_WIDGET_AUTO_REGISTER_H_
#define YAZE_APP_GUI_WIDGET_AUTO_REGISTER_H_
#include "imgui/imgui.h"
#include "app/gui/widget_id_registry.h"
#include "absl/strings/str_cat.h"
/**
* @file widget_auto_register.h
* @brief Automatic widget registration helpers for ImGui Test Engine integration
*
* This file provides inline wrappers and RAII helpers that automatically
* register ImGui widgets with the WidgetIdRegistry for test automation.
*
* Usage:
* {
* gui::AutoWidgetScope scope("Dungeon/Canvas");
* if (gui::AutoButton("Save##DungeonSave")) {
* // Button clicked
* }
* gui::AutoInputText("RoomName", buffer, sizeof(buffer));
* }
*
* All widgets created within this scope will be automatically registered
* with their full hierarchical paths for test harness discovery.
*/
namespace yaze {
namespace gui {
/**
* @class AutoWidgetScope
* @brief RAII scope that enables automatic widget registration
*
* Creates a widget ID scope and enables auto-registration for all widgets
* created within this scope. Combines WidgetIdScope with automatic metadata
* capture.
*/
class AutoWidgetScope {
public:
explicit AutoWidgetScope(const std::string& name);
~AutoWidgetScope() = default;
// Get current scope path
std::string GetPath() const { return scope_.GetFullPath(); }
private:
WidgetIdScope scope_;
std::string name_;
};
/**
* @brief Automatically register the last ImGui item
*
* Call this after any ImGui widget creation to automatically register it.
* Captures widget type, bounds, visibility, and enabled state.
*
* @param widget_type Type of widget ("button", "input", "checkbox", etc.)
* @param explicit_label Optional explicit label (uses ImGui::GetItemLabel() if empty)
* @param description Optional description for the test harness
*/
void AutoRegisterLastItem(const std::string& widget_type,
const std::string& explicit_label = "",
const std::string& description = "");
// ============================================================================
// Automatic Registration Wrappers for Common ImGui Widgets
// ============================================================================
// These wrappers call the standard ImGui functions and automatically register
// the widget with the WidgetIdRegistry for test automation.
//
// They preserve the exact same API and return values as ImGui, so they can be
// drop-in replacements in existing code.
inline bool AutoButton(const char* label, const ImVec2& size = ImVec2(0, 0)) {
bool clicked = ImGui::Button(label, size);
AutoRegisterLastItem("button", label);
return clicked;
}
inline bool AutoSmallButton(const char* label) {
bool clicked = ImGui::SmallButton(label);
AutoRegisterLastItem("button", label, "Small button");
return clicked;
}
inline bool AutoCheckbox(const char* label, bool* v) {
bool changed = ImGui::Checkbox(label, v);
AutoRegisterLastItem("checkbox", label);
return changed;
}
inline bool AutoRadioButton(const char* label, bool active) {
bool clicked = ImGui::RadioButton(label, active);
AutoRegisterLastItem("radio", label);
return clicked;
}
inline bool AutoRadioButton(const char* label, int* v, int v_button) {
bool clicked = ImGui::RadioButton(label, v, v_button);
AutoRegisterLastItem("radio", label);
return clicked;
}
inline bool AutoInputText(const char* label, char* buf, size_t buf_size,
ImGuiInputTextFlags flags = 0,
ImGuiInputTextCallback callback = nullptr,
void* user_data = nullptr) {
bool changed = ImGui::InputText(label, buf, buf_size, flags, callback, user_data);
AutoRegisterLastItem("input", label);
return changed;
}
inline bool AutoInputTextMultiline(const char* label, char* buf, size_t buf_size,
const ImVec2& size = ImVec2(0, 0),
ImGuiInputTextFlags flags = 0,
ImGuiInputTextCallback callback = nullptr,
void* user_data = nullptr) {
bool changed = ImGui::InputTextMultiline(label, buf, buf_size, size, flags, callback, user_data);
AutoRegisterLastItem("textarea", label);
return changed;
}
inline bool AutoInputInt(const char* label, int* v, int step = 1, int step_fast = 100,
ImGuiInputTextFlags flags = 0) {
bool changed = ImGui::InputInt(label, v, step, step_fast, flags);
AutoRegisterLastItem("input_int", label);
return changed;
}
inline bool AutoInputFloat(const char* label, float* v, float step = 0.0f,
float step_fast = 0.0f, const char* format = "%.3f",
ImGuiInputTextFlags flags = 0) {
bool changed = ImGui::InputFloat(label, v, step, step_fast, format, flags);
AutoRegisterLastItem("input_float", label);
return changed;
}
inline bool AutoSliderInt(const char* label, int* v, int v_min, int v_max,
const char* format = "%d", ImGuiSliderFlags flags = 0) {
bool changed = ImGui::SliderInt(label, v, v_min, v_max, format, flags);
AutoRegisterLastItem("slider", label);
return changed;
}
inline bool AutoSliderFloat(const char* label, float* v, float v_min, float v_max,
const char* format = "%.3f", ImGuiSliderFlags flags = 0) {
bool changed = ImGui::SliderFloat(label, v, v_min, v_max, format, flags);
AutoRegisterLastItem("slider", label);
return changed;
}
inline bool AutoCombo(const char* label, int* current_item, const char* const items[],
int items_count, int popup_max_height_in_items = -1) {
bool changed = ImGui::Combo(label, current_item, items, items_count, popup_max_height_in_items);
AutoRegisterLastItem("combo", label);
return changed;
}
inline bool AutoSelectable(const char* label, bool selected = false,
ImGuiSelectableFlags flags = 0,
const ImVec2& size = ImVec2(0, 0)) {
bool clicked = ImGui::Selectable(label, selected, flags, size);
AutoRegisterLastItem("selectable", label);
return clicked;
}
inline bool AutoSelectable(const char* label, bool* p_selected,
ImGuiSelectableFlags flags = 0,
const ImVec2& size = ImVec2(0, 0)) {
bool clicked = ImGui::Selectable(label, p_selected, flags, size);
AutoRegisterLastItem("selectable", label);
return clicked;
}
inline bool AutoMenuItem(const char* label, const char* shortcut = nullptr,
bool selected = false, bool enabled = true) {
bool activated = ImGui::MenuItem(label, shortcut, selected, enabled);
AutoRegisterLastItem("menuitem", label);
return activated;
}
inline bool AutoMenuItem(const char* label, const char* shortcut, bool* p_selected,
bool enabled = true) {
bool activated = ImGui::MenuItem(label, shortcut, p_selected, enabled);
AutoRegisterLastItem("menuitem", label);
return activated;
}
inline bool AutoBeginMenu(const char* label, bool enabled = true) {
bool opened = ImGui::BeginMenu(label, enabled);
if (opened) {
AutoRegisterLastItem("menu", label, "Submenu");
}
return opened;
}
inline bool AutoBeginTabItem(const char* label, bool* p_open = nullptr,
ImGuiTabItemFlags flags = 0) {
bool selected = ImGui::BeginTabItem(label, p_open, flags);
if (selected) {
AutoRegisterLastItem("tab", label);
}
return selected;
}
inline bool AutoTreeNode(const char* label) {
bool opened = ImGui::TreeNode(label);
if (opened) {
AutoRegisterLastItem("treenode", label);
}
return opened;
}
inline bool AutoTreeNodeEx(const char* label, ImGuiTreeNodeFlags flags = 0) {
bool opened = ImGui::TreeNodeEx(label, flags);
if (opened) {
AutoRegisterLastItem("treenode", label);
}
return opened;
}
inline bool AutoCollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0) {
bool opened = ImGui::CollapsingHeader(label, flags);
if (opened) {
AutoRegisterLastItem("collapsing", label);
}
return opened;
}
// ============================================================================
// Canvas-specific registration helpers
// ============================================================================
/**
* @brief Register a canvas widget after BeginChild or similar
*
* Canvases typically use BeginChild which doesn't have a return value,
* so we provide a separate registration helper.
*
* @param canvas_name Name of the canvas (should match BeginChild name)
* @param description Optional description of the canvas purpose
*/
inline void RegisterCanvas(const char* canvas_name, const std::string& description = "") {
// Get the child window ID
ImGuiContext* ctx = ImGui::GetCurrentContext();
if (ctx && ctx->CurrentWindow) {
ImGuiID canvas_id = ImGui::GetID(canvas_name);
AutoRegisterLastItem("canvas", canvas_name, description);
}
}
/**
* @brief Register a table after BeginTable
*
* @param table_name Name of the table (should match BeginTable name)
* @param description Optional description
*/
inline void RegisterTable(const char* table_name, const std::string& description = "") {
ImGuiID table_id = ImGui::GetID(table_name);
AutoRegisterLastItem("table", table_name, description);
}
} // namespace gui
} // namespace yaze
#endif // YAZE_APP_GUI_WIDGET_AUTO_REGISTER_H_

View File

@@ -0,0 +1,417 @@
#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/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