aboutsummaryrefslogtreecommitdiff
path: root/vendor/zgui/libs/imgui_test_engine/imgui_te_engine.h
blob: c5a585d07fd25a5c36f903135b0946e13ca42d38 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
// dear imgui test engine
// (core)
// This is the interface that your initial setup (app init, main loop) will mostly be using.
// Actual tests will mostly use the interface of imgui_te_context.h

#pragma once

#include "imgui.h"
#include "imgui_internal.h"         // ImPool<>, ImRect, ImGuiItemStatusFlags, ImFormatString
#include "imgui_te_utils.h"         // ImFuncPtr
#include "imgui_capture_tool.h"     // ImGuiScreenCaptureFunc

//-------------------------------------------------------------------------
// Forward Declarations
//-------------------------------------------------------------------------

struct ImGuiTest;                   // Data for a test registered with IM_REGISTER_TEST()
struct ImGuiTestContext;            // Context while a test is running
struct ImGuiTestCoroutineInterface; // Interface to expose coroutine functions (imgui_te_coroutine provides a default implementation for C++11 using std::thread, but you may use your own)
struct ImGuiTestEngine;             // Test engine instance
struct ImGuiTestEngineIO;           // Test engine public I/O
struct ImGuiTestItemInfo;           // Info queried from item (id, geometry, status flags, debug label)
struct ImGuiTestItemList;           // A list of items
struct ImGuiTestInputs;             // Simulated user inputs (will be fed into ImGuiIO by the test engine)
struct ImGuiTestRunTask;            // A queued test (test + runflags)

typedef int ImGuiTestFlags;         // Flags: See ImGuiTestFlags_
typedef int ImGuiTestCheckFlags;    // Flags: See ImGuiTestCheckFlags_
typedef int ImGuiTestLogFlags;      // Flags: See ImGuiTestLogFlags_
typedef int ImGuiTestRunFlags;      // Flags: See ImGuiTestRunFlags_

enum ImGuiTestActiveFunc : int;
enum ImGuiTestGroup : int;
enum ImGuiTestRunSpeed : int;
enum ImGuiTestStatus : int;
enum ImGuiTestVerboseLevel : int;
enum ImGuiTestEngineExportFormat : int;

//-------------------------------------------------------------------------
// Types
//-------------------------------------------------------------------------

// Stored in ImGuiTestContext: where we are currently running GuiFunc or TestFunc
enum ImGuiTestActiveFunc : int
{
    ImGuiTestActiveFunc_None,
    ImGuiTestActiveFunc_GuiFunc,
    ImGuiTestActiveFunc_TestFunc
};

enum ImGuiTestRunSpeed : int
{
    ImGuiTestRunSpeed_Fast          = 0,    // Run tests as fast as possible (teleport mouse, skip delays, etc.)
    ImGuiTestRunSpeed_Normal        = 1,    // Run tests at human watchable speed (for debugging)
    ImGuiTestRunSpeed_Cinematic     = 2,    // Run tests with pauses between actions (for e.g. tutorials)
    ImGuiTestRunSpeed_COUNT
};

enum ImGuiTestVerboseLevel : int
{
    ImGuiTestVerboseLevel_Silent    = 0,    // -v0
    ImGuiTestVerboseLevel_Error     = 1,    // -v1
    ImGuiTestVerboseLevel_Warning   = 2,    // -v2
    ImGuiTestVerboseLevel_Info      = 3,    // -v3
    ImGuiTestVerboseLevel_Debug     = 4,    // -v4
    ImGuiTestVerboseLevel_Trace     = 5,
    ImGuiTestVerboseLevel_COUNT
};

// Test status (stored in ImGuiTest)
enum ImGuiTestStatus : int
{
    ImGuiTestStatus_Unknown     = -1,
    ImGuiTestStatus_Success     = 0,
    ImGuiTestStatus_Queued      = 1,
    ImGuiTestStatus_Running     = 2,
    ImGuiTestStatus_Error       = 3,
    ImGuiTestStatus_Suspended   = 4,
    ImGuiTestStatus_COUNT
};

// Test group: this is mostly used to categorize tests in our testing UI. (Stored in ImGuiTest)
enum ImGuiTestGroup : int
{
    ImGuiTestGroup_Unknown      = -1,
    ImGuiTestGroup_Tests        = 0,
    ImGuiTestGroup_Perfs        = 1,
    ImGuiTestGroup_COUNT
};

// Flags (stored in ImGuiTest)
enum ImGuiTestFlags_
{
    ImGuiTestFlags_None                 = 0,
    ImGuiTestFlags_NoGuiWarmUp          = 1 << 0,   // Disable running the GUI func for 2 frames before starting test code. For tests which absolutely need to start before GuiFunc.
    ImGuiTestFlags_NoAutoFinish         = 1 << 1,   // By default, tests with no TestFunc (only a GuiFunc) will end after warmup. Setting this require test to call ctx->Finish().
    ImGuiTestFlags_NoRecoveryWarnings   = 1 << 2    // Disable state recovery warnings (missing End/Pop calls etc.) for tests which may rely on those.
    //ImGuiTestFlags_RequireViewports   = 1 << 10
};

// Flags for IM_CHECK* macros.
enum ImGuiTestCheckFlags_
{
    ImGuiTestCheckFlags_None            = 0,
    ImGuiTestCheckFlags_SilentSuccess   = 1 << 0
};

// Flags for ImGuiTestContext::Log* functions.
enum ImGuiTestLogFlags_
{
    ImGuiTestLogFlags_None              = 0,
    ImGuiTestLogFlags_NoHeader          = 1 << 0    // Do not display frame count and depth padding
};

enum ImGuiTestRunFlags_
{
    ImGuiTestRunFlags_None              = 0,
    ImGuiTestRunFlags_GuiFuncDisable    = 1 << 0,   // Used internally to temporarily disable the GUI func (at the end of a test, etc)
    ImGuiTestRunFlags_GuiFuncOnly       = 1 << 1,   // Set when user selects "Run GUI func"
    ImGuiTestRunFlags_NoSuccessMsg      = 1 << 2,
    ImGuiTestRunFlags_EnableRawInputs   = 1 << 3,   // Disable input submission to let test submission raw input event (in order to test e.g. IO queue)
    ImGuiTestRunFlags_RunFromGui        = 1 << 4,   // Test ran manually from GUI, will disable watchdog.
    ImGuiTestRunFlags_RunFromCommandLine= 1 << 5,   // Test queued from command-line.

    // Flags for ImGuiTestContext::RunChildTest()
    ImGuiTestRunFlags_NoError           = 1 << 10,
    ImGuiTestRunFlags_ShareVars         = 1 << 11,  // Share generic vars and custom vars between child and parent tests (custom vars need to be same type)
    ImGuiTestRunFlags_ShareTestContext  = 1 << 12,  // Share ImGuiTestContext instead of creating a new one (unsure what purpose this may be useful for yet)
    // TODO: Add GuiFunc options
};

//-------------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------------

// Hooks for core imgui/ library (generally called via macros)
extern void         ImGuiTestEngineHook_ItemAdd(ImGuiContext* ui_ctx, ImGuiID id, const ImRect& bb, const ImGuiLastItemData* item_data);
#if IMGUI_VERSION_NUM < 18934
extern void         ImGuiTestEngineHook_ItemAdd(ImGuiContext* ui_ctx, const ImRect& bb, ImGuiID id);
#endif
#ifdef IMGUI_HAS_IMSTR
extern void         ImGuiTestEngineHook_ItemInfo(ImGuiContext* ui_ctx, ImGuiID id, ImStrv label, ImGuiItemStatusFlags flags);
#else
extern void         ImGuiTestEngineHook_ItemInfo(ImGuiContext* ui_ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags);
#endif
extern void         ImGuiTestEngineHook_Log(ImGuiContext* ui_ctx, const char* fmt, ...);
extern const char*  ImGuiTestEngine_FindItemDebugLabel(ImGuiContext* ui_ctx, ImGuiID id);

// Functions (generally called via IM_CHECK() macros)
IMGUI_API bool      ImGuiTestEngine_Check(const char* file, const char* func, int line, ImGuiTestCheckFlags flags, bool result, const char* expr);
IMGUI_API bool      ImGuiTestEngine_CheckStrOp(const char* file, const char* func, int line, ImGuiTestCheckFlags flags, const char* op, const char* lhs_var, const char* lhs_value, const char* rhs_var, const char* rhs_value, bool* out_result);
IMGUI_API bool      ImGuiTestEngine_Error(const char* file, const char* func, int line, ImGuiTestCheckFlags flags, const char* fmt, ...);
IMGUI_API void      ImGuiTestEngine_AssertLog(const char* expr, const char* file, const char* function, int line);
IMGUI_API ImGuiTextBuffer* ImGuiTestEngine_GetTempStringBuilder();

//-------------------------------------------------------------------------
// ImGuiTestEngine API
//-------------------------------------------------------------------------

// Functions: Initialization
IMGUI_API ImGuiTestEngine*    ImGuiTestEngine_CreateContext();                                      // Create test engine
IMGUI_API void                ImGuiTestEngine_DestroyContext(ImGuiTestEngine* engine);              // Destroy test engine. Call after ImGui::DestroyContext() so test engine specific ini data gets saved.
IMGUI_API void                ImGuiTestEngine_Start(ImGuiTestEngine* engine, ImGuiContext* ui_ctx); // Bind to a dear imgui context. Start coroutine.
IMGUI_API void                ImGuiTestEngine_Stop(ImGuiTestEngine* engine);                        // Stop coroutine and export if any. (Unbind will lazily happen on context shutdown)
IMGUI_API void                ImGuiTestEngine_PostSwap(ImGuiTestEngine* engine);                    // Call every frame after framebuffer swap, will process screen capture and call test_io.ScreenCaptureFunc()
IMGUI_API ImGuiTestEngineIO&  ImGuiTestEngine_GetIO(ImGuiTestEngine* engine);

// Macros: Register Test
#define IM_REGISTER_TEST(_ENGINE, _CATEGORY, _NAME)  ImGuiTestEngine_RegisterTest(_ENGINE, _CATEGORY, _NAME, __FILE__, __LINE__)
IMGUI_API ImGuiTest*          ImGuiTestEngine_RegisterTest(ImGuiTestEngine* engine, const char* category, const char* name, const char* src_file = NULL, int src_line = 0); // Prefer calling IM_REGISTER_TEST()

// Functions: Main
IMGUI_API void                ImGuiTestEngine_QueueTest(ImGuiTestEngine* engine, ImGuiTest* test, ImGuiTestRunFlags run_flags = 0);
IMGUI_API void                ImGuiTestEngine_QueueTests(ImGuiTestEngine* engine, ImGuiTestGroup group, const char* filter = NULL, ImGuiTestRunFlags run_flags = 0);
IMGUI_API bool                ImGuiTestEngine_TryAbortEngine(ImGuiTestEngine* engine);
IMGUI_API void                ImGuiTestEngine_AbortCurrentTest(ImGuiTestEngine* engine);
IMGUI_API ImGuiTest*          ImGuiTestEngine_FindTestByName(ImGuiTestEngine* engine, const char* category, const char* name);

// Functions: Status Queries
// FIXME: Clarify API to avoid function calls vs raw bools in ImGuiTestEngineIO
IMGUI_API bool                ImGuiTestEngine_IsTestQueueEmpty(ImGuiTestEngine* engine);
IMGUI_API bool                ImGuiTestEngine_IsUsingSimulatedInputs(ImGuiTestEngine* engine);
IMGUI_API void                ImGuiTestEngine_GetResult(ImGuiTestEngine* engine, int& count_tested, int& success_count);
IMGUI_API void                ImGuiTestEngine_GetTestList(ImGuiTestEngine* engine, ImVector<ImGuiTest*>* out_tests);
IMGUI_API void                ImGuiTestEngine_GetTestQueue(ImGuiTestEngine* engine, ImVector<ImGuiTestRunTask>* out_tests);

// Functions: Crash Handling
// Ensure past test results are properly exported even if application crash during a test.
IMGUI_API void                ImGuiTestEngine_InstallDefaultCrashHandler();     // Install default crash handler (if you don't have one)
IMGUI_API void                ImGuiTestEngine_CrashHandler();                   // Default crash handler, should be called from a custom crash handler if such exists

//-----------------------------------------------------------------------------
// IO structure to configure the test engine
//-----------------------------------------------------------------------------

// Function bound to right-clicking on a test and selecting "Open source" in the UI
// - Easy: you can make this function call OS shell to "open" the file (e.g. ImOsOpenInShell() helper).
// - Better: bind this function to a custom setup which can pass line number to a text editor (e.g. see 'imgui_test_suite/tools/win32_open_with_sublime.cmd' example)
typedef void (ImGuiTestEngineSrcFileOpenFunc)(const char* filename, int line_no, void* user_data);

struct IMGUI_API ImGuiTestEngineIO
{
    //-------------------------------------------------------------------------
    // Functions
    //-------------------------------------------------------------------------

    // Options: Functions
    ImGuiTestCoroutineInterface*                CoroutineFuncs = NULL;          // (Required) Coroutine functions (see imgui_te_coroutines.h)
    ImFuncPtr(ImGuiTestEngineSrcFileOpenFunc)   SrcFileOpenFunc = NULL;         // (Optional) To open source files from test engine UI
    ImFuncPtr(ImGuiScreenCaptureFunc)           ScreenCaptureFunc = NULL;       // (Optional) To capture graphics output (application _MUST_ call ImGuiTestEngine_PostSwap() function after swapping is framebuffer)
    void*                                       SrcFileOpenUserData = NULL;     // (Optional) User data for SrcFileOpenFunc
    void*                                       ScreenCaptureUserData = NULL;   // (Optional) User data for ScreenCaptureFunc

    // Options: Main
    bool                        ConfigSavedSettings = true;                     // Load/Save settings in main context .ini file.
    ImGuiTestRunSpeed           ConfigRunSpeed = ImGuiTestRunSpeed_Fast;        // Run tests in fast/normal/cinematic mode
    bool                        ConfigStopOnError = false;                      // Stop queued tests on test error
    bool                        ConfigBreakOnError = false;                     // Break debugger on test error by calling IM_DEBUG_BREAK()
    bool                        ConfigKeepGuiFunc = false;                      // Keep test GUI running at the end of the test
    ImGuiTestVerboseLevel       ConfigVerboseLevel = ImGuiTestVerboseLevel_Warning;
    ImGuiTestVerboseLevel       ConfigVerboseLevelOnError = ImGuiTestVerboseLevel_Info;
    bool                        ConfigLogToTTY = false;
    bool                        ConfigLogToDebugger = false;
    bool                        ConfigRestoreFocusAfterTests = true;// Restore focus back after running tests
    bool                        ConfigCaptureEnabled = true;        // Master enable flags for capturing and saving captures. Disable to avoid e.g. lengthy saving of large PNG files.
    bool                        ConfigCaptureOnError = false;
    bool                        ConfigNoThrottle = false;           // Disable vsync for performance measurement or fast test running
    bool                        ConfigMouseDrawCursor = true;       // Enable drawing of Dear ImGui software mouse cursor when running tests
    float                       ConfigFixedDeltaTime = 0.0f;        // Use fixed delta time instead of calculating it from wall clock
    int                         PerfStressAmount = 1;               // Integer to scale the amount of items submitted in test
    char                        GitBranchName[64] = "";             // e.g. fill in branch name (e.g. recorded in perf samples .csv)

    // Options: Speed of user simulation
    float                       MouseSpeed = 600.0f;                // Mouse speed (pixel/second) when not running in fast mode
    float                       MouseWobble = 0.25f;                // (0.0f..1.0f) How much wobble to apply to the mouse (pixels per pixel of move distance) when not running in fast mode
    float                       ScrollSpeed = 1400.0f;              // Scroll speed (pixel/second) when not running in fast mode
    float                       TypingSpeed = 20.0f;                // Char input speed (characters/second) when not running in fast mode
    float                       ActionDelayShort = 0.15f;           // Time between short actions
    float                       ActionDelayStandard = 0.40f;        // Time between most actions

    // Options: Screen/video capture
    char                        VideoCaptureEncoderPath[256] = "";  // Video encoder executable path, e.g. "path/to/ffmpeg.exe".
    char                        VideoCaptureEncoderParams[256] = "";// Video encoder parameters for .MP4 captures, e.g. see IMGUI_CAPTURE_DEFAULT_VIDEO_PARAMS_FOR_FFMPEG
    char                        GifCaptureEncoderParams[512] = "";  // Video encoder parameters for .GIF captures, e.g. see IMGUI_CAPTURE_DEFAULT_GIF_PARAMS_FOR_FFMPEG
    char                        VideoCaptureExtension[8] = ".mp4";  // Video file extension (default, may be overridden by test).

    // Options: Watchdog. Set values to FLT_MAX to disable.
    // Interactive GUI applications that may be slower tend to use higher values.
    float                       ConfigWatchdogWarning = 30.0f;      // Warn when a test exceed this time (in second)
    float                       ConfigWatchdogKillTest = 60.0f;     // Attempt to stop running a test when exceeding this time (in second)
    float                       ConfigWatchdogKillApp = FLT_MAX;    // Stop application when exceeding this time (in second)

    // Options: Export
    // While you can manually call ImGuiTestEngine_Export(), registering filename/format here ensure the crash handler will always export if application crash.
    const char*                 ExportResultsFilename = NULL;
    ImGuiTestEngineExportFormat ExportResultsFormat = (ImGuiTestEngineExportFormat)0;

    // Options: Sanity Checks
    bool                        CheckDrawDataIntegrity = false;     // Check ImDrawData integrity (buffer count, etc.). Currently cheap but may become a slow operation.

    //-------------------------------------------------------------------------
    // Output
    //-------------------------------------------------------------------------

    // Output: State of test engine
    bool                        IsRunningTests = false;
    bool                        IsRequestingMaxAppSpeed = false;    // When running in fast mode: request app to skip vsync or even skip rendering if it wants
    bool                        IsCapturing = false;                // Capture is in progress
};

//-------------------------------------------------------------------------
// ImGuiTestItemInfo
//-------------------------------------------------------------------------

// Information about a given item or window, result of an ItemInfo() or WindowInfo() query
struct ImGuiTestItemInfo
{
    int                         RefCount : 8;               // User can increment this if they want to hold on the result pointer across frames, otherwise the task will be GC-ed.
    unsigned int                NavLayer : 1;               // Nav layer of the item (ImGuiNavLayer)
    int                         Depth : 16;                 // Depth from requested parent id. 0 == ID is immediate child of requested parent id.
    int                         TimestampMain = -1;         // Timestamp of main result (all fields)
    int                         TimestampStatus = -1;       // Timestamp of StatusFlags
    ImGuiID                     ID = 0;                     // Item ID
    ImGuiID                     ParentID = 0;               // Item Parent ID (value at top of the ID stack)
    ImGuiWindow*                Window = NULL;              // Item Window
    ImRect                      RectFull = ImRect();        // Item Rectangle
    ImRect                      RectClipped = ImRect();     // Item Rectangle (clipped with window->ClipRect at time of item submission)
    ImGuiItemFlags              InFlags = 0;                // Item flags
    ImGuiItemStatusFlags        StatusFlags = 0;            // Item Status flags (fully updated for some items only, compare TimestampStatus to FrameCount)
    char                        DebugLabel[32] = {};        // Shortened label for debugging purpose

    ImGuiTestItemInfo()         { RefCount = 0; NavLayer = 0; Depth = 0; }
    bool                        IsEmpty() const         { return ID == 0; }
};

// Result of an GatherItems() query
struct IMGUI_API ImGuiTestItemList
{
    ImPool<ImGuiTestItemInfo>   Pool;

    void                        Clear()                 { Pool.Clear(); }
    void                        Reserve(int capacity)   { Pool.Reserve(capacity); }
    int                         GetSize() const         { return Pool.GetMapSize(); }
    const ImGuiTestItemInfo*    GetByIndex(int n)       { return Pool.GetByIndex(n); }
    const ImGuiTestItemInfo*    GetByID(ImGuiID id)     { return Pool.GetByKey(id); }

    // For range-for
    size_t                      size() const            { return (size_t)Pool.GetMapSize(); }
    const ImGuiTestItemInfo*    begin() const           { return Pool.Buf.begin(); }
    const ImGuiTestItemInfo*    end() const             { return Pool.Buf.end(); }
    const ImGuiTestItemInfo*    operator[] (size_t n)   { return &Pool.Buf[(int)n]; }
};

//-------------------------------------------------------------------------
// ImGuiTestLog: store textual output of one given Test.
//-------------------------------------------------------------------------

struct IMGUI_API ImGuiTestLogLineInfo
{
    ImGuiTestVerboseLevel           Level;
    int                             LineOffset;
};

struct IMGUI_API ImGuiTestLog
{
    ImGuiTextBuffer                 Buffer;
    ImVector<ImGuiTestLogLineInfo>  LineInfo;
    int                             CountPerLevel[ImGuiTestVerboseLevel_COUNT] = {};

    // Functions
    ImGuiTestLog() {}
    bool    IsEmpty() const         { return Buffer.empty(); }
    void    Clear();

    // Extract log contents filtered per log-level.
    // Output:
    // - If 'buffer != NULL': all extracted lines are appended to 'buffer'. Use 'buffer->c_str()' on your side to obtain the text.
    // - Return value: number of lines extracted (should be equivalent to number of '\n' inside buffer->c_str()).
    // - You may call the function with buffer == NULL to only obtain a count without getting the data.
    // Verbose levels are inclusive:
    // - To get ONLY Error:                     Use level_min == ImGuiTestVerboseLevel_Error, level_max = ImGuiTestVerboseLevel_Error
    // - To get ONLY Error and Warnings:        Use level_min == ImGuiTestVerboseLevel_Error, level_max = ImGuiTestVerboseLevel_Warning
    // - To get All Errors, Warnings, Debug...  Use level_min == ImGuiTestVerboseLevel_Error, level_max = ImGuiTestVerboseLevel_Trace
    int     ExtractLinesForVerboseLevels(ImGuiTestVerboseLevel level_min, ImGuiTestVerboseLevel level_max, ImGuiTextBuffer* out_buffer);

    // [Internal]
    void    UpdateLineOffsets(ImGuiTestEngineIO* engine_io, ImGuiTestVerboseLevel level, const char* start);
};

//-------------------------------------------------------------------------
// ImGuiTest
//-------------------------------------------------------------------------

typedef void    (ImGuiTestGuiFunc)(ImGuiTestContext* ctx);
typedef void    (ImGuiTestTestFunc)(ImGuiTestContext* ctx);

// Wraps a placement new of a given type (where 'buffer' is the allocated memory)
typedef void    (ImGuiTestVarsConstructor)(void* buffer);
typedef void    (ImGuiTestVarsPostConstructor)(ImGuiTestContext* ctx, void* ptr, void* fn);
typedef void    (ImGuiTestVarsDestructor)(void* ptr);

// Storage for the output of a test run
struct IMGUI_API ImGuiTestOutput
{
    ImGuiTestStatus                 Status = ImGuiTestStatus_Unknown;
    ImGuiTestLog                    Log;
    ImU64                           StartTime = 0;
    ImU64                           EndTime = 0;
};

// Storage for one test
struct IMGUI_API ImGuiTest
{
    // Test Definition
    const char*                     Category = NULL;                // Literal, not owned
    const char*                     Name = NULL;                    // Literal, generally not owned unless NameOwned=true
    ImGuiTestGroup                  Group = ImGuiTestGroup_Unknown; // Coarse groups: 'Tests' or 'Perf'
    bool                            NameOwned = false;              //
    const char*                     SourceFile = NULL;              // __FILE__
    int                             SourceLine = 0;                 // __LINE__
    int                             SourceLineEnd = 0;              // Calculated by ImGuiTestEngine_StartCalcSourceLineEnds()
    int                             ArgVariant = 0;                 // User parameter. Generally we use it to run variations of a same test by sharing GuiFunc/TestFunc
    ImGuiTestFlags                  Flags = ImGuiTestFlags_None;    // See ImGuiTestFlags_
    ImFuncPtr(ImGuiTestGuiFunc)     GuiFunc = NULL;                 // GUI function (optional if your test are running over an existing GUI application)
    ImFuncPtr(ImGuiTestTestFunc)    TestFunc = NULL;                // Test function
    void*                           UserData = NULL;                // General purpose user data (if assigning capturing lambdas on GuiFunc/TestFunc you may not need to use this)
    //ImVector<ImGuiTestRunTask>    Dependencies;                   // Registered via AddDependencyTest(), ran automatically before our test. This is a simpler wrapper to calling ctx->RunChildTest()

    // Last Test Output/Status
    // (this is the only part that may change after registration)
    ImGuiTestOutput                 Output;

    // User variables (which are instantiated when running the test)
    // Setup after test registration with SetVarsDataType<>(), access instance during test with GetVars<>().
    // This is mostly useful to communicate between GuiFunc and TestFunc. If you don't use both you may not want to use it!
    size_t                          VarsSize = 0;
    ImGuiTestVarsConstructor*       VarsConstructor = NULL;
    ImGuiTestVarsPostConstructor*   VarsPostConstructor = NULL;     // To override constructor default (in case the default are problematic on the first GuiFunc frame)
    void*                           VarsPostConstructorUserFn = NULL;
    ImGuiTestVarsDestructor*        VarsDestructor = NULL;

    // Functions
    ImGuiTest() {}
    ~ImGuiTest();

    void SetOwnedName(const char* name);

    template <typename T>
    void SetVarsDataType(void(*post_initialize)(ImGuiTestContext* ctx, T& vars) = NULL)
    {
        VarsSize = sizeof(T);
        VarsConstructor = [](void* ptr) { IM_PLACEMENT_NEW(ptr) T; };
        VarsDestructor = [](void* ptr) { IM_UNUSED(ptr); reinterpret_cast<T*>(ptr)->~T(); };
        if (post_initialize != NULL)
        {
            VarsPostConstructorUserFn = (void*)post_initialize;
            VarsPostConstructor = [](ImGuiTestContext* ctx, void* ptr, void* fn) { ((void (*)(ImGuiTestContext*, T&))(fn))(ctx, *(T*)ptr); };
        }
    }
};

// Stored in test queue
struct IMGUI_API ImGuiTestRunTask
{
    ImGuiTest*          Test = NULL;
    ImGuiTestRunFlags   RunFlags = ImGuiTestRunFlags_None;
};

//-------------------------------------------------------------------------