mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-04-02 05:27:41 -05:00
tests: Integrated ImGui Test Engine
This commit is contained in:
1120
lib/third_party/imgui/imgui_test_engine/source/imgui_capture_tool.cpp
vendored
Normal file
1120
lib/third_party/imgui/imgui_test_engine/source/imgui_capture_tool.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4314
lib/third_party/imgui/imgui_test_engine/source/imgui_te_context.cpp
vendored
Normal file
4314
lib/third_party/imgui/imgui_test_engine/source/imgui_te_context.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
170
lib/third_party/imgui/imgui_test_engine/source/imgui_te_coroutine.cpp
vendored
Normal file
170
lib/third_party/imgui/imgui_test_engine/source/imgui_te_coroutine.cpp
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
// dear imgui test engine
|
||||
// (coroutine interface + optional implementation)
|
||||
// Read https://github.com/ocornut/imgui_test_engine/wiki/Setting-Up
|
||||
|
||||
// This file is governed by the "Dear ImGui Test Engine License".
|
||||
// Details of the license are provided in the LICENSE.txt file in the same directory.
|
||||
|
||||
#include "imgui_te_coroutine.h"
|
||||
#include "imgui.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Coroutine implementation using std::thread
|
||||
// This implements a coroutine using std::thread, with a helper thread for each coroutine (with serialised execution, so threads never actually run concurrently)
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#if IMGUI_TEST_ENGINE_ENABLE_COROUTINE_STDTHREAD_IMPL
|
||||
|
||||
#include "imgui_te_utils.h"
|
||||
#include "thirdparty/Str/Str.h"
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
struct Coroutine_ImplStdThreadData
|
||||
{
|
||||
std::thread* Thread; // The thread this coroutine is using
|
||||
std::condition_variable StateChange; // Condition variable notified when the coroutine state changes
|
||||
std::mutex StateMutex; // Mutex to protect coroutine state
|
||||
bool CoroutineRunning; // Is the coroutine currently running? Lock StateMutex before access and notify StateChange on change
|
||||
bool CoroutineTerminated; // Has the coroutine terminated? Lock StateMutex before access and notify StateChange on change
|
||||
Str64 Name; // The name of this coroutine
|
||||
};
|
||||
|
||||
// The coroutine executing on the current thread (if it is a coroutine thread)
|
||||
static thread_local Coroutine_ImplStdThreadData* GThreadCoroutine = nullptr;
|
||||
|
||||
// The main function for a coroutine thread
|
||||
static void CoroutineThreadMain(Coroutine_ImplStdThreadData* data, ImGuiTestCoroutineMainFunc func, void* ctx)
|
||||
{
|
||||
// Set our thread name
|
||||
ImThreadSetCurrentThreadDescription(data->Name.c_str());
|
||||
|
||||
// Set the thread coroutine
|
||||
GThreadCoroutine = data;
|
||||
|
||||
// Wait for initial Run()
|
||||
while (1)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(data->StateMutex);
|
||||
if (data->CoroutineRunning)
|
||||
break;
|
||||
data->StateChange.wait(lock);
|
||||
}
|
||||
|
||||
// Run user code, which will then call Yield() when it wants to yield control
|
||||
func(ctx);
|
||||
|
||||
// Mark as terminated
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(data->StateMutex);
|
||||
|
||||
data->CoroutineTerminated = true;
|
||||
data->CoroutineRunning = false;
|
||||
data->StateChange.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ImGuiTestCoroutineHandle Coroutine_ImplStdThread_Create(ImGuiTestCoroutineMainFunc* func, const char* name, void* ctx)
|
||||
{
|
||||
Coroutine_ImplStdThreadData* data = new Coroutine_ImplStdThreadData();
|
||||
|
||||
data->Name = name;
|
||||
data->CoroutineRunning = false;
|
||||
data->CoroutineTerminated = false;
|
||||
data->Thread = new std::thread(CoroutineThreadMain, data, func, ctx);
|
||||
|
||||
return (ImGuiTestCoroutineHandle)data;
|
||||
}
|
||||
|
||||
static void Coroutine_ImplStdThread_Destroy(ImGuiTestCoroutineHandle handle)
|
||||
{
|
||||
Coroutine_ImplStdThreadData* data = (Coroutine_ImplStdThreadData*)handle;
|
||||
|
||||
IM_ASSERT(data->CoroutineTerminated); // The coroutine needs to run to termination otherwise it may leak all sorts of things and this will deadlock
|
||||
if (data->Thread)
|
||||
{
|
||||
data->Thread->join();
|
||||
|
||||
delete data->Thread;
|
||||
data->Thread = nullptr;
|
||||
}
|
||||
|
||||
delete data;
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
// Run the coroutine until the next call to Yield(). Returns TRUE if the coroutine yielded, FALSE if it terminated (or had previously terminated)
|
||||
static bool Coroutine_ImplStdThread_Run(ImGuiTestCoroutineHandle handle)
|
||||
{
|
||||
Coroutine_ImplStdThreadData* data = (Coroutine_ImplStdThreadData*)handle;
|
||||
|
||||
// Wake up coroutine thread
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(data->StateMutex);
|
||||
|
||||
if (data->CoroutineTerminated)
|
||||
return false; // Coroutine has already finished
|
||||
|
||||
data->CoroutineRunning = true;
|
||||
data->StateChange.notify_all();
|
||||
}
|
||||
|
||||
// Wait for coroutine to stop
|
||||
while (1)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(data->StateMutex);
|
||||
if (!data->CoroutineRunning)
|
||||
{
|
||||
// Breakpoint here to catch the point where we return from the coroutine
|
||||
if (data->CoroutineTerminated)
|
||||
return false; // Coroutine finished
|
||||
break;
|
||||
}
|
||||
data->StateChange.wait(lock);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Yield the current coroutine (can only be called from a coroutine)
|
||||
static void Coroutine_ImplStdThread_Yield()
|
||||
{
|
||||
IM_ASSERT(GThreadCoroutine); // This can only be called from a coroutine thread
|
||||
|
||||
Coroutine_ImplStdThreadData* data = GThreadCoroutine;
|
||||
|
||||
// Flag that we are not running any more
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(data->StateMutex);
|
||||
data->CoroutineRunning = false;
|
||||
data->StateChange.notify_all();
|
||||
}
|
||||
|
||||
// At this point the thread that called RunCoroutine() will leave the "Wait for coroutine to stop" loop
|
||||
// Wait until we get started up again
|
||||
while (1)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(data->StateMutex);
|
||||
if (data->CoroutineRunning)
|
||||
break; // Breakpoint here if you want to catch the point where execution of this coroutine resumes
|
||||
data->StateChange.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
ImGuiTestCoroutineInterface* Coroutine_ImplStdThread_GetInterface()
|
||||
{
|
||||
static ImGuiTestCoroutineInterface intf;
|
||||
intf.CreateFunc = Coroutine_ImplStdThread_Create;
|
||||
intf.DestroyFunc = Coroutine_ImplStdThread_Destroy;
|
||||
intf.RunFunc = Coroutine_ImplStdThread_Run;
|
||||
intf.YieldFunc = Coroutine_ImplStdThread_Yield;
|
||||
return &intf;
|
||||
}
|
||||
|
||||
#endif // #if IMGUI_TEST_ENGINE_ENABLE_COROUTINE_STDTHREAD_IMPL
|
||||
2677
lib/third_party/imgui/imgui_test_engine/source/imgui_te_engine.cpp
vendored
Normal file
2677
lib/third_party/imgui/imgui_test_engine/source/imgui_te_engine.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
308
lib/third_party/imgui/imgui_test_engine/source/imgui_te_exporters.cpp
vendored
Normal file
308
lib/third_party/imgui/imgui_test_engine/source/imgui_te_exporters.cpp
vendored
Normal file
@@ -0,0 +1,308 @@
|
||||
// dear imgui test engine
|
||||
// (result exporters)
|
||||
// Read https://github.com/ocornut/imgui_test_engine/wiki/Exporting-Results
|
||||
|
||||
// This file is governed by the "Dear ImGui Test Engine License".
|
||||
// Details of the license are provided in the LICENSE.txt file in the same directory.
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#include "imgui_te_exporters.h"
|
||||
#include "imgui_te_engine.h"
|
||||
#include "imgui_te_internal.h"
|
||||
#include "thirdparty/Str/Str.h"
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// [SECTION] FORWARD DECLARATIONS
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static void ImGuiTestEngine_ExportJUnitXml(ImGuiTestEngine* engine, const char* output_file);
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// [SECTION] TEST ENGINE EXPORTER FUNCTIONS
|
||||
//-------------------------------------------------------------------------
|
||||
// - ImGuiTestEngine_PrintResultSummary()
|
||||
// - ImGuiTestEngine_Export()
|
||||
// - ImGuiTestEngine_ExportEx()
|
||||
// - ImGuiTestEngine_ExportJUnitXml()
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
void ImGuiTestEngine_PrintResultSummary(ImGuiTestEngine* engine)
|
||||
{
|
||||
ImGuiTestEngineResultSummary summary;
|
||||
ImGuiTestEngine_GetResultSummary(engine, &summary);
|
||||
|
||||
if (summary.CountSuccess < summary.CountTested)
|
||||
{
|
||||
printf("\nFailing tests:\n");
|
||||
for (ImGuiTest* test : engine->TestsAll)
|
||||
if (test->Output.Status == ImGuiTestStatus_Error)
|
||||
printf("- %s\n", test->Name);
|
||||
}
|
||||
|
||||
bool success = (summary.CountSuccess == summary.CountTested);
|
||||
ImOsConsoleSetTextColor(ImOsConsoleStream_StandardOutput, success ? ImOsConsoleTextColor_BrightGreen : ImOsConsoleTextColor_BrightRed);
|
||||
printf("\nTests Result: %s\n", success ? "OK" : "Errors");
|
||||
printf("(%d/%d tests passed)\n", summary.CountSuccess, summary.CountTested);
|
||||
if (summary.CountInQueue > 0)
|
||||
printf("(%d queued tests remaining)\n", summary.CountInQueue);
|
||||
ImOsConsoleSetTextColor(ImOsConsoleStream_StandardOutput, ImOsConsoleTextColor_White);
|
||||
}
|
||||
|
||||
// This is mostly a copy of ImGuiTestEngine_PrintResultSummary with few additions.
|
||||
static void ImGuiTestEngine_ExportResultSummary(ImGuiTestEngine* engine, FILE* fp, int indent_count, ImGuiTestGroup group)
|
||||
{
|
||||
int count_tested = 0;
|
||||
int count_success = 0;
|
||||
|
||||
for (ImGuiTest* test : engine->TestsAll)
|
||||
{
|
||||
if (test->Group != group)
|
||||
continue;
|
||||
if (test->Output.Status != ImGuiTestStatus_Unknown)
|
||||
count_tested++;
|
||||
if (test->Output.Status == ImGuiTestStatus_Success)
|
||||
count_success++;
|
||||
}
|
||||
|
||||
Str64 indent_str;
|
||||
indent_str.reserve(indent_count + 1);
|
||||
memset(indent_str.c_str(), ' ', indent_count);
|
||||
indent_str[indent_count] = 0;
|
||||
const char* indent = indent_str.c_str();
|
||||
|
||||
if (count_success < count_tested)
|
||||
{
|
||||
fprintf(fp, "\n%sFailing tests:\n", indent);
|
||||
for (ImGuiTest* test : engine->TestsAll)
|
||||
{
|
||||
if (test->Group != group)
|
||||
continue;
|
||||
if (test->Output.Status == ImGuiTestStatus_Error)
|
||||
fprintf(fp, "%s- %s\n", indent, test->Name);
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
fprintf(fp, "%sTests Result: %s\n", indent, (count_success == count_tested) ? "OK" : "Errors");
|
||||
fprintf(fp, "%s(%d/%d tests passed)\n", indent, count_success, count_tested);
|
||||
}
|
||||
|
||||
static bool ImGuiTestEngine_HasAnyLogLines(ImGuiTestLog* test_log, ImGuiTestVerboseLevel level)
|
||||
{
|
||||
for (auto& line_info : test_log->LineInfo)
|
||||
if (line_info.Level <= level)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ImGuiTestEngine_PrintLogLines(FILE* fp, ImGuiTestLog* test_log, int indent, ImGuiTestVerboseLevel level)
|
||||
{
|
||||
Str128 log_line;
|
||||
for (auto& line_info : test_log->LineInfo)
|
||||
{
|
||||
if (line_info.Level > level)
|
||||
continue;
|
||||
const char* line_start = test_log->Buffer.c_str() + line_info.LineOffset;
|
||||
const char* line_end = strstr(line_start, "\n"); // FIXME: Incorrect.
|
||||
log_line.set(line_start, line_end);
|
||||
ImStrXmlEscape(&log_line); // FIXME: Should not be here considering the function name.
|
||||
|
||||
// Some users may want to disable indenting?
|
||||
fprintf(fp, "%*s%s\n", indent, "", log_line.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Export using settings stored in ImGuiTestEngineIO
|
||||
// This is called by ImGuiTestEngine_CrashHandler().
|
||||
void ImGuiTestEngine_Export(ImGuiTestEngine* engine)
|
||||
{
|
||||
ImGuiTestEngineIO& io = engine->IO;
|
||||
ImGuiTestEngine_ExportEx(engine, io.ExportResultsFormat, io.ExportResultsFilename);
|
||||
}
|
||||
|
||||
// Export using custom settings.
|
||||
void ImGuiTestEngine_ExportEx(ImGuiTestEngine* engine, ImGuiTestEngineExportFormat format, const char* filename)
|
||||
{
|
||||
if (format == ImGuiTestEngineExportFormat_None)
|
||||
return;
|
||||
IM_ASSERT(filename != nullptr);
|
||||
|
||||
if (format == ImGuiTestEngineExportFormat_JUnitXml)
|
||||
ImGuiTestEngine_ExportJUnitXml(engine, filename);
|
||||
else
|
||||
IM_ASSERT(0);
|
||||
}
|
||||
|
||||
void ImGuiTestEngine_ExportJUnitXml(ImGuiTestEngine* engine, const char* output_file)
|
||||
{
|
||||
IM_ASSERT(engine != nullptr);
|
||||
IM_ASSERT(output_file != nullptr);
|
||||
|
||||
FILE* fp = fopen(output_file, "w+b");
|
||||
if (fp == nullptr)
|
||||
{
|
||||
fprintf(stderr, "Writing '%s' failed.\n", output_file);
|
||||
return;
|
||||
}
|
||||
|
||||
// Per-testsuite test statistics.
|
||||
struct
|
||||
{
|
||||
const char* Name = nullptr;
|
||||
int Tests = 0;
|
||||
int Failures = 0;
|
||||
int Disabled = 0;
|
||||
} testsuites[ImGuiTestGroup_COUNT];
|
||||
testsuites[ImGuiTestGroup_Tests].Name = "tests";
|
||||
testsuites[ImGuiTestGroup_Perfs].Name = "perfs";
|
||||
|
||||
for (int n = 0; n < engine->TestsAll.Size; n++)
|
||||
{
|
||||
ImGuiTest* test = engine->TestsAll[n];
|
||||
auto* stats = &testsuites[test->Group];
|
||||
stats->Tests += 1;
|
||||
if (test->Output.Status == ImGuiTestStatus_Error)
|
||||
stats->Failures += 1;
|
||||
else if (test->Output.Status == ImGuiTestStatus_Unknown)
|
||||
stats->Disabled += 1;
|
||||
}
|
||||
|
||||
// Attributes for <testsuites> tag.
|
||||
const char* testsuites_name = "Dear ImGui";
|
||||
int testsuites_failures = 0;
|
||||
int testsuites_tests = 0;
|
||||
int testsuites_disabled = 0;
|
||||
float testsuites_time = (float)((double)(engine->BatchEndTime - engine->BatchStartTime) / 1000000.0);
|
||||
for (int testsuite_id = ImGuiTestGroup_Tests; testsuite_id < ImGuiTestGroup_COUNT; testsuite_id++)
|
||||
{
|
||||
testsuites_tests += testsuites[testsuite_id].Tests;
|
||||
testsuites_failures += testsuites[testsuite_id].Failures;
|
||||
testsuites_disabled += testsuites[testsuite_id].Disabled;
|
||||
}
|
||||
|
||||
// FIXME: "errors" attribute and <error> tag in <testcase> may be supported if we have means to catch unexpected errors like assertions.
|
||||
fprintf(fp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<testsuites disabled=\"%d\" errors=\"0\" failures=\"%d\" name=\"%s\" tests=\"%d\" time=\"%.3f\">\n",
|
||||
testsuites_disabled, testsuites_failures, testsuites_name, testsuites_tests, testsuites_time);
|
||||
|
||||
for (int testsuite_id = ImGuiTestGroup_Tests; testsuite_id < ImGuiTestGroup_COUNT; testsuite_id++)
|
||||
{
|
||||
// Attributes for <testsuite> tag.
|
||||
auto* testsuite = &testsuites[testsuite_id];
|
||||
float testsuite_time = testsuites_time; // FIXME: We do not differentiate between tests and perfs, they are executed in one big batch.
|
||||
Str30 testsuite_timestamp = "";
|
||||
ImTimestampToISO8601(engine->BatchStartTime, &testsuite_timestamp);
|
||||
fprintf(fp, " <testsuite name=\"%s\" tests=\"%d\" disabled=\"%d\" errors=\"0\" failures=\"%d\" hostname=\"\" id=\"%d\" package=\"\" skipped=\"0\" time=\"%.3f\" timestamp=\"%s\">\n",
|
||||
testsuite->Name, testsuite->Tests, testsuite->Disabled, testsuite->Failures, testsuite_id, testsuite_time, testsuite_timestamp.c_str());
|
||||
|
||||
for (int n = 0; n < engine->TestsAll.Size; n++)
|
||||
{
|
||||
ImGuiTest* test = engine->TestsAll[n];
|
||||
if (test->Group != testsuite_id)
|
||||
continue;
|
||||
|
||||
ImGuiTestOutput* test_output = &test->Output;
|
||||
ImGuiTestLog* test_log = &test_output->Log;
|
||||
|
||||
// Attributes for <testcase> tag.
|
||||
const char* testcase_name = test->Name;
|
||||
const char* testcase_classname = test->Category;
|
||||
const char* testcase_status = ImGuiTestEngine_GetStatusName(test_output->Status);
|
||||
const float testcase_time = (float)((double)(test_output->EndTime - test_output->StartTime) / 1000000.0);
|
||||
|
||||
fprintf(fp, " <testcase name=\"%s\" assertions=\"0\" classname=\"%s\" status=\"%s\" time=\"%.3f\">\n",
|
||||
testcase_name, testcase_classname, testcase_status, testcase_time);
|
||||
|
||||
if (test_output->Status == ImGuiTestStatus_Error)
|
||||
{
|
||||
// Skip last error message because it is generic information that test failed.
|
||||
Str128 log_line;
|
||||
for (int i = test_log->LineInfo.Size - 2; i >= 0; i--)
|
||||
{
|
||||
ImGuiTestLogLineInfo* line_info = &test_log->LineInfo[i];
|
||||
if (line_info->Level > engine->IO.ConfigVerboseLevelOnError)
|
||||
continue;
|
||||
if (line_info->Level == ImGuiTestVerboseLevel_Error)
|
||||
{
|
||||
const char* line_start = test_log->Buffer.c_str() + line_info->LineOffset;
|
||||
const char* line_end = strstr(line_start, "\n");
|
||||
log_line.set(line_start, line_end);
|
||||
ImStrXmlEscape(&log_line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Failing tests save their "on error" log output in text element of <failure> tag.
|
||||
fprintf(fp, " <failure message=\"%s\" type=\"error\">\n", log_line.c_str());
|
||||
ImGuiTestEngine_PrintLogLines(fp, test_log, 8, engine->IO.ConfigVerboseLevelOnError);
|
||||
fprintf(fp, " </failure>\n");
|
||||
}
|
||||
|
||||
if (test_output->Status == ImGuiTestStatus_Unknown)
|
||||
{
|
||||
fprintf(fp, " <skipped message=\"Skipped\" />\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Succeeding tests save their default log output output as "stdout".
|
||||
if (ImGuiTestEngine_HasAnyLogLines(test_log, engine->IO.ConfigVerboseLevel))
|
||||
{
|
||||
fprintf(fp, " <system-out>\n");
|
||||
ImGuiTestEngine_PrintLogLines(fp, test_log, 8, engine->IO.ConfigVerboseLevel);
|
||||
fprintf(fp, " </system-out>\n");
|
||||
}
|
||||
|
||||
// Save error messages as "stderr".
|
||||
if (ImGuiTestEngine_HasAnyLogLines(test_log, ImGuiTestVerboseLevel_Error))
|
||||
{
|
||||
fprintf(fp, " <system-err>\n");
|
||||
ImGuiTestEngine_PrintLogLines(fp, test_log, 8, ImGuiTestVerboseLevel_Error);
|
||||
fprintf(fp, " </system-err>\n");
|
||||
}
|
||||
}
|
||||
fprintf(fp, " </testcase>\n");
|
||||
}
|
||||
|
||||
if (testsuites[testsuite_id].Disabled < testsuites[testsuite_id].Tests) // Any tests executed
|
||||
{
|
||||
// Log all log messages as "stdout".
|
||||
fprintf(fp, " <system-out>\n");
|
||||
for (int n = 0; n < engine->TestsAll.Size; n++)
|
||||
{
|
||||
ImGuiTest* test = engine->TestsAll[n];
|
||||
ImGuiTestOutput* test_output = &test->Output;
|
||||
if (test->Group != testsuite_id)
|
||||
continue;
|
||||
if (test_output->Status == ImGuiTestStatus_Unknown)
|
||||
continue;
|
||||
fprintf(fp, " [0000] Test: '%s' '%s'..\n", test->Category, test->Name);
|
||||
ImGuiTestVerboseLevel level = test_output->Status == ImGuiTestStatus_Error ? engine->IO.ConfigVerboseLevelOnError : engine->IO.ConfigVerboseLevel;
|
||||
ImGuiTestEngine_PrintLogLines(fp, &test_output->Log, 6, level);
|
||||
}
|
||||
ImGuiTestEngine_ExportResultSummary(engine, fp, 6, (ImGuiTestGroup)testsuite_id);
|
||||
fprintf(fp, " </system-out>\n");
|
||||
|
||||
// Log all warning and error messages as "stderr".
|
||||
fprintf(fp, " <system-err>\n");
|
||||
for (int n = 0; n < engine->TestsAll.Size; n++)
|
||||
{
|
||||
ImGuiTest* test = engine->TestsAll[n];
|
||||
ImGuiTestOutput* test_output = &test->Output;
|
||||
if (test->Group != testsuite_id)
|
||||
continue;
|
||||
if (test_output->Status == ImGuiTestStatus_Unknown)
|
||||
continue;
|
||||
fprintf(fp, " [0000] Test: '%s' '%s'..\n", test->Category, test->Name);
|
||||
ImGuiTestEngine_PrintLogLines(fp, &test_output->Log, 6, ImGuiTestVerboseLevel_Warning);
|
||||
}
|
||||
ImGuiTestEngine_ExportResultSummary(engine, fp, 6, (ImGuiTestGroup)testsuite_id);
|
||||
fprintf(fp, " </system-err>\n");
|
||||
}
|
||||
fprintf(fp, " </testsuite>\n");
|
||||
}
|
||||
fprintf(fp, "</testsuites>\n");
|
||||
fclose(fp);
|
||||
fprintf(stdout, "Saved test results to '%s' successfully.\n", output_file);
|
||||
}
|
||||
1961
lib/third_party/imgui/imgui_test_engine/source/imgui_te_perftool.cpp
vendored
Normal file
1961
lib/third_party/imgui/imgui_test_engine/source/imgui_te_perftool.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
893
lib/third_party/imgui/imgui_test_engine/source/imgui_te_ui.cpp
vendored
Normal file
893
lib/third_party/imgui/imgui_test_engine/source/imgui_te_ui.cpp
vendored
Normal file
@@ -0,0 +1,893 @@
|
||||
// dear imgui test engine
|
||||
// (ui)
|
||||
// If you run tests in an interactive or visible application, you may want to call ImGuiTestEngine_ShowTestEngineWindows()
|
||||
|
||||
// This file is governed by the "Dear ImGui Test Engine License".
|
||||
// Details of the license are provided in the LICENSE.txt file in the same directory.
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#include "imgui_te_ui.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "imgui_te_engine.h"
|
||||
#include "imgui_te_context.h"
|
||||
#include "imgui_te_internal.h"
|
||||
#include "imgui_te_perftool.h"
|
||||
#include "thirdparty/Str/Str.h"
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// TEST ENGINE: USER INTERFACE
|
||||
//-------------------------------------------------------------------------
|
||||
// - DrawTestLog() [internal]
|
||||
// - GetVerboseLevelName() [internal]
|
||||
// - ShowTestGroup() [internal]
|
||||
// - ImGuiTestEngine_ShowTestEngineWindows()
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// Look for " filename:number " in the string and add menu option to open source.
|
||||
static bool ParseLineAndDrawFileOpenItemForSourceFile(ImGuiTestEngine* e, ImGuiTest* test, const char* line_start, const char* line_end)
|
||||
{
|
||||
const char* separator = ImStrchrRange(line_start, line_end, ':');
|
||||
if (separator == nullptr)
|
||||
return false;
|
||||
|
||||
const char* path_end = separator;
|
||||
const char* path_begin = separator - 1;
|
||||
while (path_begin > line_start&& path_begin[-1] != ' ')
|
||||
path_begin--;
|
||||
if (path_begin == path_end)
|
||||
return false;
|
||||
|
||||
int line_no = -1;
|
||||
sscanf(separator + 1, "%d ", &line_no);
|
||||
if (line_no == -1)
|
||||
return false;
|
||||
|
||||
Str256f buf("Open '%.*s' at line %d", (int)(path_end - path_begin), path_begin, line_no);
|
||||
if (ImGui::MenuItem(buf.c_str()))
|
||||
{
|
||||
// FIXME-TESTS: Assume folder is same as folder of test->SourceFile!
|
||||
const char* src_path = test->SourceFile;
|
||||
const char* src_name = ImPathFindFilename(src_path);
|
||||
buf.setf("%.*s%.*s", (int)(src_name - src_path), src_path, (int)(path_end - path_begin), path_begin);
|
||||
|
||||
ImGuiTestEngine_OpenSourceFile(e, buf.c_str(), line_no);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Look for "[ ,"]filename.png" in the string and add menu option to open image.
|
||||
static bool ParseLineAndDrawFileOpenItemForImageFile(ImGuiTestEngine* e, ImGuiTest* test, const char* line_start, const char* line_end, const char* file_ext)
|
||||
{
|
||||
IM_UNUSED(e);
|
||||
IM_UNUSED(test);
|
||||
|
||||
const char* extension = ImStristr(line_start, line_end, file_ext, nullptr);
|
||||
if (extension == nullptr)
|
||||
return false;
|
||||
|
||||
const char* path_end = extension + strlen(file_ext);
|
||||
const char* path_begin = extension - 1;
|
||||
while (path_begin > line_start && path_begin[-1] != ' ' && path_begin[-1] != '\'' && path_begin[-1] != '\"')
|
||||
path_begin--;
|
||||
if (path_begin == path_end)
|
||||
return false;
|
||||
|
||||
Str256 buf;
|
||||
|
||||
// Open file
|
||||
buf.setf("Open file: %.*s", (int)(path_end - path_begin), path_begin);
|
||||
if (ImGui::MenuItem(buf.c_str()))
|
||||
{
|
||||
buf.setf("%.*s", (int)(path_end - path_begin), path_begin);
|
||||
ImPathFixSeparatorsForCurrentOS(buf.c_str());
|
||||
ImOsOpenInShell(buf.c_str());
|
||||
}
|
||||
|
||||
// Open folder
|
||||
const char* folder_begin = path_begin;
|
||||
const char* folder_end = ImPathFindFilename(path_begin, path_end);
|
||||
buf.setf("Open folder: %.*s", (int)(folder_end - folder_begin), path_begin);
|
||||
if (ImGui::MenuItem(buf.c_str()))
|
||||
{
|
||||
buf.setf("%.*s", (int)(folder_end - folder_begin), folder_begin);
|
||||
ImPathFixSeparatorsForCurrentOS(buf.c_str());
|
||||
ImOsOpenInShell(buf.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseLineAndDrawFileOpenItem(ImGuiTestEngine* e, ImGuiTest* test, const char* line_start, const char* line_end)
|
||||
{
|
||||
if (ParseLineAndDrawFileOpenItemForSourceFile(e, test, line_start, line_end))
|
||||
return true;
|
||||
if (ParseLineAndDrawFileOpenItemForImageFile(e, test, line_start, line_end, ".png"))
|
||||
return true;
|
||||
if (ParseLineAndDrawFileOpenItemForImageFile(e, test, line_start, line_end, ".gif"))
|
||||
return true;
|
||||
if (ParseLineAndDrawFileOpenItemForImageFile(e, test, line_start, line_end, ".mp4"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static float GetDpiScale()
|
||||
{
|
||||
#ifdef IMGUI_HAS_VIEWPORT
|
||||
return ImGui::GetWindowViewport()->DpiScale;
|
||||
#else
|
||||
return 1.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void DrawTestLog(ImGuiTestEngine* e, ImGuiTest* test)
|
||||
{
|
||||
const ImU32 error_col = IM_COL32(255, 150, 150, 255);
|
||||
const ImU32 warning_col = IM_COL32(240, 240, 150, 255);
|
||||
const ImU32 unimportant_col = IM_COL32(190, 190, 190, 255);
|
||||
const float dpi_scale = GetDpiScale();
|
||||
|
||||
ImGuiTestOutput* test_output = &test->Output;
|
||||
|
||||
ImGuiTestLog* log = &test_output->Log;
|
||||
const char* text = log->Buffer.begin();
|
||||
const char* text_end = log->Buffer.end();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 2.0f) * dpi_scale);
|
||||
ImGuiListClipper clipper;
|
||||
ImGuiTestVerboseLevel max_log_level = test_output->Status == ImGuiTestStatus_Error ? e->IO.ConfigVerboseLevelOnError : e->IO.ConfigVerboseLevel;
|
||||
int line_count = log->ExtractLinesForVerboseLevels(ImGuiTestVerboseLevel_Silent, max_log_level, nullptr);
|
||||
int current_index_clipped = -1;
|
||||
int current_index_abs = 0;
|
||||
clipper.Begin(line_count);
|
||||
while (clipper.Step())
|
||||
{
|
||||
for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
|
||||
{
|
||||
// Advance index_by_log_level to find log entry indicated by line_no.
|
||||
ImGuiTestLogLineInfo* line_info = nullptr;
|
||||
while (current_index_clipped < line_no)
|
||||
{
|
||||
line_info = &log->LineInfo[current_index_abs];
|
||||
if (line_info->Level <= max_log_level)
|
||||
current_index_clipped++;
|
||||
current_index_abs++;
|
||||
}
|
||||
|
||||
const char* line_start = text + line_info->LineOffset;
|
||||
const char* line_end = strchr(line_start, '\n');
|
||||
if (line_end == nullptr)
|
||||
line_end = text_end;
|
||||
|
||||
switch (line_info->Level)
|
||||
{
|
||||
case ImGuiTestVerboseLevel_Error:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, error_col);
|
||||
break;
|
||||
case ImGuiTestVerboseLevel_Warning:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, warning_col);
|
||||
break;
|
||||
case ImGuiTestVerboseLevel_Debug:
|
||||
case ImGuiTestVerboseLevel_Trace:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, unimportant_col);
|
||||
break;
|
||||
default:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32_WHITE);
|
||||
break;
|
||||
}
|
||||
#if IMGUI_VERSION_NUM >= 19072
|
||||
ImGui::DebugTextUnformattedWithLocateItem(line_start, line_end);
|
||||
#else
|
||||
ImGui::TextUnformatted(line_start, line_end);
|
||||
#endif
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::PushID(line_no);
|
||||
if (ImGui::BeginPopupContextItem("Context", 1))
|
||||
{
|
||||
if (!ParseLineAndDrawFileOpenItem(e, test, line_start, line_end))
|
||||
ImGui::MenuItem("No options", nullptr, false, false);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
#if IMGUI_VERSION_NUM <= 18963
|
||||
namespace ImGui
|
||||
{
|
||||
void SetItemTooltip(const char* fmt, ...)
|
||||
{
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ImGui::SetTooltipV(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
} // namespace ImGui
|
||||
#endif
|
||||
|
||||
static bool ShowTestGroupFilterTest(ImGuiTestEngine* e, ImGuiTestGroup group, const char* filter, ImGuiTest* test)
|
||||
{
|
||||
if (test->Group != group)
|
||||
return false;
|
||||
if (!ImGuiTestEngine_PassFilter(test, *filter ? filter : "all"))
|
||||
return false;
|
||||
if ((e->UiFilterByStatusMask & (1 << test->Output.Status)) == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void GetFailingTestsAsString(ImGuiTestEngine* e, ImGuiTestGroup group, char separator, Str* out_string)
|
||||
{
|
||||
IM_ASSERT(out_string != nullptr);
|
||||
bool first = true;
|
||||
for (int i = 0; i < e->TestsAll.Size; i++)
|
||||
{
|
||||
ImGuiTest* failing_test = e->TestsAll[i];
|
||||
Str* filter = (group == ImGuiTestGroup_Tests) ? e->UiFilterTests : e->UiFilterPerfs;
|
||||
if (failing_test->Group != group)
|
||||
continue;
|
||||
if (failing_test->Output.Status != ImGuiTestStatus_Error)
|
||||
continue;
|
||||
if (!ImGuiTestEngine_PassFilter(failing_test, filter->empty() ? "all" : filter->c_str()))
|
||||
continue;
|
||||
if (!first)
|
||||
out_string->append(separator);
|
||||
out_string->append(failing_test->Name);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void TestStatusButton(const char* id, const ImVec4& color, bool running, int display_counter)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop | ImGuiItemFlags_NoNav, true);
|
||||
ImGui::ColorButton(id, color, ImGuiColorEditFlags_NoTooltip);
|
||||
ImGui::PopItemFlag();
|
||||
if (running)
|
||||
{
|
||||
//ImRect r = g.LastItemData.Rect;
|
||||
ImVec2 center = g.LastItemData.Rect.GetCenter();
|
||||
float radius = ImFloor(ImMin(g.LastItemData.Rect.GetWidth(), g.LastItemData.Rect.GetHeight()) * 0.40f);
|
||||
float t = (float)(ImGui::GetTime() * 20.0f);
|
||||
ImVec2 off(ImCos(t) * radius, ImSin(t) * radius);
|
||||
ImGui::GetWindowDrawList()->AddLine(center - off, center + off, ImGui::GetColorU32(ImGuiCol_Text), 1.5f);
|
||||
//ImGui::RenderText(r.Min + style.FramePadding + ImVec2(0, 0), &"|\0/\0-\0\\"[(((ImGui::GetFrameCount() / 5) & 3) << 1)], nullptr);
|
||||
}
|
||||
else if (display_counter >= 0)
|
||||
{
|
||||
ImVec2 center = g.LastItemData.Rect.GetCenter();
|
||||
Str30f buf("%d", display_counter);
|
||||
ImGui::GetWindowDrawList()->AddText(center - ImGui::CalcTextSize(buf.c_str()) * 0.5f, ImGui::GetColorU32(ImGuiCol_Text), buf.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
static void ShowTestGroup(ImGuiTestEngine* e, ImGuiTestGroup group, Str* filter)
|
||||
{
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
const float dpi_scale = GetDpiScale();
|
||||
|
||||
// Colored Status button: will be displayed later below
|
||||
// - Save position of test run status button and make space for it.
|
||||
const ImVec2 status_button_pos = ImGui::GetCursorPos();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetFrameHeight() + style.ItemInnerSpacing.x);
|
||||
|
||||
//ImGui::Text("TESTS (%d)", engine->TestsAll.Size);
|
||||
#if IMGUI_VERSION_NUM >= 19066
|
||||
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_R, ImGuiInputFlags_Tooltip | ImGuiInputFlags_RouteFromRootWindow);
|
||||
bool run = ImGui::Button("Run");
|
||||
#elif IMGUI_VERSION_NUM >= 18837
|
||||
bool run = ImGui::Button("Run") || ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_R);
|
||||
#if IMGUI_VERSION_NUM > 18963
|
||||
ImGui::SetItemTooltip("Ctrl+R");
|
||||
#endif
|
||||
#else
|
||||
bool run = ImGui::Button("Run");
|
||||
#endif
|
||||
if (run)
|
||||
{
|
||||
for (int n = 0; n < e->TestsAll.Size; n++)
|
||||
{
|
||||
ImGuiTest* test = e->TestsAll[n];
|
||||
if (!ShowTestGroupFilterTest(e, group, filter->c_str(), test))
|
||||
continue;
|
||||
ImGuiTestEngine_QueueTest(e, test, ImGuiTestRunFlags_None);
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
{
|
||||
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 6.0f);
|
||||
const char* filter_by_status_desc = "";
|
||||
if (e->UiFilterByStatusMask == ~0u)
|
||||
filter_by_status_desc = "All";
|
||||
else if (e->UiFilterByStatusMask == ~(1u << ImGuiTestStatus_Success))
|
||||
filter_by_status_desc = "Not OK";
|
||||
else if (e->UiFilterByStatusMask == (1u << ImGuiTestStatus_Error))
|
||||
filter_by_status_desc = "Errors";
|
||||
if (ImGui::BeginCombo("##filterbystatus", filter_by_status_desc))
|
||||
{
|
||||
if (ImGui::Selectable("All", e->UiFilterByStatusMask == ~0u))
|
||||
e->UiFilterByStatusMask = (ImU32)~0u;
|
||||
if (ImGui::Selectable("Not OK", e->UiFilterByStatusMask == ~(1u << ImGuiTestStatus_Success)))
|
||||
e->UiFilterByStatusMask = (ImU32)~(1u << ImGuiTestStatus_Success);
|
||||
if (ImGui::Selectable("Errors", e->UiFilterByStatusMask == (1u << ImGuiTestStatus_Error)))
|
||||
e->UiFilterByStatusMask = (ImU32)(1u << ImGuiTestStatus_Error);
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
const char* perflog_label = "Perf Tool";
|
||||
float filter_width = ImGui::GetContentRegionAvail().x;
|
||||
float perf_stress_factor_width = (30 * dpi_scale);
|
||||
if (group == ImGuiTestGroup_Perfs)
|
||||
{
|
||||
filter_width -= style.ItemSpacing.x + perf_stress_factor_width;
|
||||
filter_width -= style.ItemSpacing.x + style.FramePadding.x * 2 + ImGui::CalcTextSize(perflog_label).x;
|
||||
}
|
||||
filter_width -= ImGui::CalcTextSize("(?)").x + style.ItemSpacing.x;
|
||||
ImGui::SetNextItemWidth(ImMax(20.0f, filter_width));
|
||||
#if IMGUI_VERSION_NUM >= 19066
|
||||
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip | ImGuiInputFlags_RouteFromRootWindow);
|
||||
#endif
|
||||
ImGui::InputText("##filter", filter);
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled("(?)");
|
||||
ImGui::SetItemTooltip("Query is composed of one or more comma-separated filter terms with optional modifiers.\n"
|
||||
"Available modifiers:\n"
|
||||
"- '-' prefix excludes tests matched by the term.\n"
|
||||
"- '^' prefix anchors term matching to the start of the string.\n"
|
||||
"- '$' suffix anchors term matching to the end of the string.");
|
||||
if (group == ImGuiTestGroup_Perfs)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(perf_stress_factor_width);
|
||||
ImGui::DragInt("##PerfStress", &e->IO.PerfStressAmount, 0.1f, 1, 20, "x%d");
|
||||
ImGui::SetItemTooltip("Increase workload of performance tests (higher means longer run)."); // FIXME: Move?
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(perflog_label))
|
||||
{
|
||||
e->UiPerfToolOpen = true;
|
||||
ImGui::FocusWindow(ImGui::FindWindowByName("Dear ImGui Perf Tool"));
|
||||
}
|
||||
}
|
||||
|
||||
int tests_completed = 0;
|
||||
int tests_succeeded = 0;
|
||||
int tests_failed = 0;
|
||||
ImVector<ImGuiTest*> tests_to_remove;
|
||||
if (ImGui::BeginTable("Tests", 3, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Resizable | ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_SizingFixedFit))
|
||||
{
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
ImGui::TableSetupColumn("Status");
|
||||
ImGui::TableSetupColumn("Category");
|
||||
ImGui::TableSetupColumn("Test", ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6, 4) * dpi_scale);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4, 0) * dpi_scale);
|
||||
//ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(100, 10) * dpi_scale);
|
||||
for (int test_n = 0; test_n < e->TestsAll.Size; test_n++)
|
||||
{
|
||||
ImGuiTest* test = e->TestsAll[test_n];
|
||||
if (!ShowTestGroupFilterTest(e, group, filter->c_str(), test))
|
||||
continue;
|
||||
|
||||
ImGuiTestOutput* test_output = &test->Output;
|
||||
ImGuiTestContext* test_context = (e->TestContext && e->TestContext->Test == test) ? e->TestContext : nullptr; // Running context, if any
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::PushID(test_n);
|
||||
|
||||
// Colors match general test status colors defined below.
|
||||
ImVec4 status_color;
|
||||
switch (test_output->Status)
|
||||
{
|
||||
case ImGuiTestStatus_Error:
|
||||
status_color = ImVec4(0.9f, 0.1f, 0.1f, 1.0f);
|
||||
tests_completed++;
|
||||
tests_failed++;
|
||||
break;
|
||||
case ImGuiTestStatus_Success:
|
||||
status_color = ImVec4(0.1f, 0.9f, 0.1f, 1.0f);
|
||||
tests_completed++;
|
||||
tests_succeeded++;
|
||||
break;
|
||||
case ImGuiTestStatus_Queued:
|
||||
case ImGuiTestStatus_Running:
|
||||
case ImGuiTestStatus_Suspended:
|
||||
if (test_context && (test_context->RunFlags & ImGuiTestRunFlags_GuiFuncOnly))
|
||||
status_color = ImVec4(0.8f, 0.0f, 0.8f, 1.0f);
|
||||
else
|
||||
status_color = ImVec4(0.8f, 0.4f, 0.1f, 1.0f);
|
||||
break;
|
||||
default:
|
||||
status_color = ImVec4(0.4f, 0.4f, 0.4f, 1.0f);
|
||||
break;
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
TestStatusButton("status", status_color, test_output->Status == ImGuiTestStatus_Running || test_output->Status == ImGuiTestStatus_Suspended, -1);
|
||||
ImGui::SameLine();
|
||||
|
||||
bool queue_test = false;
|
||||
bool queue_gui_func_toggle = false;
|
||||
bool select_test = false;
|
||||
|
||||
if (test_output->Status == ImGuiTestStatus_Suspended)
|
||||
{
|
||||
// Resume IM_SUSPEND_TESTFUNC
|
||||
// FIXME: Terrible user experience to have this here.
|
||||
if (ImGui::Button("Con###Run"))
|
||||
test_output->Status = ImGuiTestStatus_Running;
|
||||
ImGui::SetItemTooltip("CTRL+Space to continue.");
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Space) && io.KeyCtrl)
|
||||
test_output->Status = ImGuiTestStatus_Running;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ImGui::Button("Run###Run"))
|
||||
queue_test = select_test = true;
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(test->Category, test == e->UiSelectedTest, ImGuiSelectableFlags_SpanAllColumns | (ImGuiSelectableFlags)ImGuiSelectableFlags_SelectOnNav))
|
||||
select_test = true;
|
||||
|
||||
// Double-click to run test, CTRL+Double-click to run GUI function
|
||||
const bool is_running_gui_func = (test_context && (test_context->RunFlags & ImGuiTestRunFlags_GuiFuncOnly));
|
||||
const bool has_gui_func = (test->GuiFunc != nullptr);
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0))
|
||||
{
|
||||
if (ImGui::GetIO().KeyCtrl)
|
||||
queue_gui_func_toggle = true;
|
||||
else
|
||||
queue_test = true;
|
||||
}
|
||||
|
||||
/*if (ImGui::IsItemHovered() && test->TestLog.size() > 0)
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
DrawTestLog(engine, test, false);
|
||||
ImGui::EndTooltip();
|
||||
}*/
|
||||
|
||||
if (e->UiSelectAndScrollToTest == test)
|
||||
ImGui::SetScrollHereY();
|
||||
|
||||
bool view_source = false;
|
||||
if (ImGui::BeginPopupContextItem())
|
||||
{
|
||||
select_test = true;
|
||||
|
||||
if (ImGui::MenuItem("Run test"))
|
||||
queue_test = true;
|
||||
if (ImGui::MenuItem("Run GUI func", "Ctrl+DblClick", is_running_gui_func, has_gui_func))
|
||||
queue_gui_func_toggle = true;
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
const bool open_source_available = (test->SourceFile != nullptr) && (e->IO.SrcFileOpenFunc != nullptr);
|
||||
|
||||
Str128 buf;
|
||||
if (test->SourceFile != nullptr) // This is normally set by IM_REGISTER_TEST() but custom registration may omit it.
|
||||
buf.setf("Open source (%s:%d)", ImPathFindFilename(test->SourceFile), test->SourceLine);
|
||||
else
|
||||
buf.set("Open source");
|
||||
if (ImGui::MenuItem(buf.c_str(), nullptr, false, open_source_available))
|
||||
ImGuiTestEngine_OpenSourceFile(e, test->SourceFile, test->SourceLine);
|
||||
if (ImGui::MenuItem("View source...", nullptr, false, test->SourceFile != nullptr))
|
||||
view_source = true;
|
||||
|
||||
if (group == ImGuiTestGroup_Perfs && ImGui::MenuItem("View perflog"))
|
||||
{
|
||||
e->PerfTool->ViewOnly(test->Name);
|
||||
e->UiPerfToolOpen = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Copy name", nullptr, false))
|
||||
ImGui::SetClipboardText(test->Name);
|
||||
|
||||
if (test_output->Status == ImGuiTestStatus_Error)
|
||||
if (ImGui::MenuItem("Copy names of all failing tests"))
|
||||
{
|
||||
Str256 failing_tests;
|
||||
GetFailingTestsAsString(e, group, ',', &failing_tests);
|
||||
ImGui::SetClipboardText(failing_tests.c_str());
|
||||
}
|
||||
|
||||
ImGuiTestLog* test_log = &test_output->Log;
|
||||
if (ImGui::BeginMenu("Copy log", !test_log->IsEmpty()))
|
||||
{
|
||||
for (int level_n = ImGuiTestVerboseLevel_Error; level_n < ImGuiTestVerboseLevel_COUNT; level_n++)
|
||||
{
|
||||
ImGuiTestVerboseLevel level = (ImGuiTestVerboseLevel)level_n;
|
||||
int count = test_log->ExtractLinesForVerboseLevels((ImGuiTestVerboseLevel)0, level, nullptr);
|
||||
if (ImGui::MenuItem(Str64f("%s (%d lines)", ImGuiTestEngine_GetVerboseLevelName(level), count).c_str(), nullptr, false, count > 0))
|
||||
{
|
||||
ImGuiTextBuffer buffer;
|
||||
test_log->ExtractLinesForVerboseLevels((ImGuiTestVerboseLevel)0, level, &buffer);
|
||||
ImGui::SetClipboardText(buffer.c_str());
|
||||
}
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("Clear log", nullptr, false, !test_log->IsEmpty()))
|
||||
test_log->Clear();
|
||||
|
||||
// [DEBUG] Simple way to exercise ImGuiTestEngine_UnregisterTest()
|
||||
//ImGui::Separator();
|
||||
//if (ImGui::MenuItem("Remove test"))
|
||||
// tests_to_remove.push_back(test);
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// Process source popup
|
||||
static ImGuiTextBuffer source_blurb;
|
||||
static int goto_line = -1;
|
||||
if (view_source)
|
||||
{
|
||||
source_blurb.clear();
|
||||
size_t file_size = 0;
|
||||
char* file_data = (char*)ImFileLoadToMemory(test->SourceFile, "rb", &file_size);
|
||||
if (file_data)
|
||||
source_blurb.append(file_data, file_data + file_size);
|
||||
else
|
||||
source_blurb.append("<Error loading sources>");
|
||||
goto_line = test->SourceLine;
|
||||
ImGui::OpenPopup("Source");
|
||||
}
|
||||
if (ImGui::BeginPopup("Source"))
|
||||
{
|
||||
const ImVec2 start_pos = ImGui::GetCursorScreenPos();
|
||||
const float line_height = ImGui::GetTextLineHeight();
|
||||
if (goto_line != -1)
|
||||
ImGui::SetScrollY(ImMax((goto_line - 5) * line_height, 0.0f));
|
||||
goto_line = -1;
|
||||
|
||||
ImRect r(0.0f, (test->SourceLine - 1) * line_height, ImGui::GetWindowWidth(), (test->SourceLineEnd - 1) * line_height);
|
||||
ImGui::GetWindowDrawList()->AddRectFilled(start_pos + r.Min, start_pos + r.Max, IM_COL32(80, 80, 150, 100));
|
||||
|
||||
ImGui::TextUnformatted(source_blurb.c_str(), source_blurb.end());
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(test->Name);
|
||||
|
||||
// Process selection
|
||||
if (select_test)
|
||||
e->UiSelectedTest = test;
|
||||
|
||||
// Process queuing
|
||||
if (queue_gui_func_toggle && is_running_gui_func)
|
||||
ImGuiTestEngine_AbortCurrentTest(e);
|
||||
else if (queue_gui_func_toggle && !e->IO.IsRunningTests)
|
||||
ImGuiTestEngine_QueueTest(e, test, ImGuiTestRunFlags_RunFromGui | ImGuiTestRunFlags_GuiFuncOnly);
|
||||
if (queue_test && !e->IO.IsRunningTests)
|
||||
ImGuiTestEngine_QueueTest(e, test, ImGuiTestRunFlags_RunFromGui);
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::Spacing();
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
// Process removal
|
||||
for (ImGuiTest* test : tests_to_remove)
|
||||
ImGuiTestEngine_UnregisterTest(e, test);
|
||||
|
||||
// Display test status recap (colors match per-test run button colors defined above)
|
||||
{
|
||||
ImVec4 status_color;
|
||||
if (tests_failed > 0)
|
||||
status_color = ImVec4(0.9f, 0.1f, 0.1f, 1.0f); // Red
|
||||
else if (e->IO.IsRunningTests)
|
||||
status_color = ImVec4(0.8f, 0.4f, 0.1f, 1.0f);
|
||||
else if (tests_succeeded > 0 && tests_completed == tests_succeeded)
|
||||
status_color = ImVec4(0.1f, 0.9f, 0.1f, 1.0f);
|
||||
else
|
||||
status_color = ImVec4(0.4f, 0.4f, 0.4f, 1.0f);
|
||||
//ImVec2 cursor_pos_bkp = ImGui::GetCursorPos();
|
||||
ImGui::SetCursorPos(status_button_pos);
|
||||
TestStatusButton("status", status_color, false, tests_failed > 0 ? tests_failed : -1);// e->IO.IsRunningTests);
|
||||
ImGui::SetItemTooltip("Filtered: %d\n- OK: %d\n- Errors: %d", tests_completed, tests_succeeded, tests_failed);
|
||||
//ImGui::SetCursorPos(cursor_pos_bkp); // Restore cursor position for rendering further widgets
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGuiTestEngine_ShowLogAndTools(ImGuiTestEngine* engine)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
const float dpi_scale = GetDpiScale();
|
||||
|
||||
if (!ImGui::BeginTabBar("##tools"))
|
||||
return;
|
||||
|
||||
if (ImGui::BeginTabItem("LOG"))
|
||||
{
|
||||
ImGuiTest* selected_test = engine->UiSelectedTest;
|
||||
|
||||
if (selected_test != nullptr)
|
||||
ImGui::Text("Log for '%s' '%s'", selected_test->Category, selected_test->Name);
|
||||
else
|
||||
ImGui::Text("N/A");
|
||||
if (ImGui::SmallButton("Clear"))
|
||||
if (selected_test)
|
||||
selected_test->Output.Log.Clear();
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton("Copy to clipboard"))
|
||||
if (engine->UiSelectedTest)
|
||||
ImGui::SetClipboardText(selected_test->Output.Log.Buffer.c_str());
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::BeginChild("Log");
|
||||
if (engine->UiSelectedTest)
|
||||
{
|
||||
DrawTestLog(engine, engine->UiSelectedTest);
|
||||
if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
|
||||
ImGui::SetScrollHereY();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
// Options
|
||||
if (ImGui::BeginTabItem("OPTIONS"))
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGui::Text("%.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
||||
ImGui::Text("TestEngine: HookItems: %d, HookPushId: %d, InfoTasks: %d", g.TestEngineHookItems, g.DebugHookIdInfo != 0, engine->InfoTasks.Size);
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Button("Reboot UI context"))
|
||||
engine->ToolDebugRebootUiContext = true;
|
||||
|
||||
const ImGuiInputTextCallback filter_callback = [](ImGuiInputTextCallbackData* data) { return (data->EventChar == ',' || data->EventChar == ';') ? 1 : 0; };
|
||||
ImGui::InputText("Branch/Annotation", engine->IO.GitBranchName, IM_ARRAYSIZE(engine->IO.GitBranchName), ImGuiInputTextFlags_CallbackCharFilter, filter_callback, nullptr);
|
||||
ImGui::SetItemTooltip("This will be stored in the CSV file for performance tools.");
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::TreeNode("Screen/video capture"))
|
||||
{
|
||||
ImGui::Checkbox("Capture when requested by API", &engine->IO.ConfigCaptureEnabled);
|
||||
ImGui::SetItemTooltip("Enable or disable screen capture API completely.");
|
||||
ImGui::Checkbox("Capture screen on error", &engine->IO.ConfigCaptureOnError);
|
||||
ImGui::SetItemTooltip("Capture a screenshot on test failure.");
|
||||
|
||||
// Fields modified by in this call will be synced to engine->CaptureContext.
|
||||
engine->CaptureTool._ShowEncoderConfigFields(&engine->CaptureContext);
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Performances"))
|
||||
{
|
||||
ImGui::Checkbox("Slow down whole app", &engine->ToolSlowDown);
|
||||
ImGui::SameLine(); ImGui::SetNextItemWidth(70 * dpi_scale);
|
||||
ImGui::SliderInt("##ms", &engine->ToolSlowDownMs, 0, 400, "%d ms");
|
||||
|
||||
// FIXME-TESTS: Need to be visualizing the samples/spikes.
|
||||
double dt_1 = 1.0 / ImGui::GetIO().Framerate;
|
||||
double fps_now = 1.0 / dt_1;
|
||||
double dt_100 = engine->PerfDeltaTime100.GetAverage();
|
||||
double dt_500 = engine->PerfDeltaTime500.GetAverage();
|
||||
|
||||
//if (engine->PerfRefDeltaTime <= 0.0 && engine->PerfRefDeltaTime.IsFull())
|
||||
// engine->PerfRefDeltaTime = dt_2000;
|
||||
|
||||
ImGui::Checkbox("Unthrolled", &engine->IO.ConfigNoThrottle);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Pick ref dt"))
|
||||
engine->PerfRefDeltaTime = dt_500;
|
||||
|
||||
double dt_ref = engine->PerfRefDeltaTime;
|
||||
ImGui::Text("[ref dt] %6.3f ms", engine->PerfRefDeltaTime * 1000);
|
||||
ImGui::Text("[last 001] %6.3f ms (%.1f FPS) ++ %6.3f ms", dt_1 * 1000.0, 1.0 / dt_1, (dt_1 - dt_ref) * 1000);
|
||||
ImGui::Text("[last 100] %6.3f ms (%.1f FPS) ++ %6.3f ms ~ converging in %.1f secs", dt_100 * 1000.0, 1.0 / dt_100, (dt_1 - dt_ref) * 1000, 100.0 / fps_now);
|
||||
ImGui::Text("[last 500] %6.3f ms (%.1f FPS) ++ %6.3f ms ~ converging in %.1f secs", dt_500 * 1000.0, 1.0 / dt_500, (dt_1 - dt_ref) * 1000, 500.0 / fps_now);
|
||||
|
||||
//ImGui::PlotLines("Last 100", &engine->PerfDeltaTime100.Samples.Data, engine->PerfDeltaTime100.Samples.Size, engine->PerfDeltaTime100.Idx, nullptr, 0.0f, dt_1000 * 1.10f, ImVec2(0.0f, ImGui::GetFontSize()));
|
||||
ImVec2 plot_size(0.0f, ImGui::GetFrameHeight() * 3);
|
||||
ImMovingAverage<double>* ma = &engine->PerfDeltaTime500;
|
||||
ImGui::PlotLines("Last 500",
|
||||
[](void* data, int n) { ImMovingAverage<double>* ma = (ImMovingAverage<double>*)data; return (float)(ma->Samples[n] * 1000); },
|
||||
ma, ma->Samples.Size, 0 * ma->Idx, nullptr, 0.0f, (float)(ImMax(dt_100, dt_500) * 1000.0 * 1.2f), plot_size);
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Dear ImGui Configuration Flags"))
|
||||
{
|
||||
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
|
||||
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", &io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
|
||||
#ifdef IMGUI_HAS_DOCK
|
||||
ImGui::Checkbox("io.ConfigDockingAlwaysTabBar", &io.ConfigDockingAlwaysTabBar);
|
||||
#endif
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
|
||||
static void ImGuiTestEngine_ShowTestTool(ImGuiTestEngine* engine, bool* p_open)
|
||||
{
|
||||
const float dpi_scale = GetDpiScale();
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(ImGui::GetFontSize() * 50, ImGui::GetFontSize() * 40), ImGuiCond_FirstUseEver);
|
||||
if (!ImGui::Begin("Dear ImGui Test Engine", p_open, ImGuiWindowFlags_MenuBar))
|
||||
{
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenuBar())
|
||||
{
|
||||
if (ImGui::BeginMenu("Tools"))
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGui::MenuItem("Metrics/Debugger", "", &engine->UiMetricsOpen);
|
||||
ImGui::MenuItem("Debug Log", "", &engine->UiDebugLogOpen);
|
||||
ImGui::MenuItem("Stack Tool", "", &engine->UiStackToolOpen);
|
||||
ImGui::MenuItem("Item Picker", "", &g.DebugItemPickerActive);
|
||||
ImGui::Separator();
|
||||
ImGui::MenuItem("Capture Tool", "", &engine->UiCaptureToolOpen);
|
||||
ImGui::MenuItem("Perf Tool", "", &engine->UiPerfToolOpen);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(90 * dpi_scale);
|
||||
if (ImGui::BeginCombo("##RunSpeed", ImGuiTestEngine_GetRunSpeedName(engine->IO.ConfigRunSpeed), ImGuiComboFlags_None))
|
||||
{
|
||||
for (ImGuiTestRunSpeed level = (ImGuiTestRunSpeed)0; level < ImGuiTestRunSpeed_COUNT; level = (ImGuiTestRunSpeed)(level + 1))
|
||||
if (ImGui::Selectable(ImGuiTestEngine_GetRunSpeedName(level), engine->IO.ConfigRunSpeed == level))
|
||||
engine->IO.ConfigRunSpeed = level;
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SetItemTooltip(
|
||||
"Running speed\n"
|
||||
"- Fast: Run tests as fast as possible (no delay/vsync, teleport mouse, etc.).\n"
|
||||
"- Normal: Run tests at human watchable speed (for debugging).\n"
|
||||
"- Cinematic: Run tests with pauses between actions (for e.g. tutorials)."
|
||||
);
|
||||
ImGui::SameLine();
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
ImGui::SameLine();
|
||||
|
||||
// (Would be good if we exposed horizontal layout mode..)
|
||||
ImGui::Checkbox("Stop", &engine->IO.ConfigStopOnError);
|
||||
ImGui::SetItemTooltip("When hitting an error:\n- Stop running other tests.");
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("DbgBrk", &engine->IO.ConfigBreakOnError);
|
||||
ImGui::SetItemTooltip("When hitting an error:\n- Break in debugger.");
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Capture", &engine->IO.ConfigCaptureOnError);
|
||||
ImGui::SetItemTooltip("When hitting an error:\n- Capture screen to PNG. Right-click filename in Test Log to open.");
|
||||
ImGui::SameLine();
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::Checkbox("KeepGUI", &engine->IO.ConfigKeepGuiFunc);
|
||||
ImGui::SetItemTooltip("After running single test or hitting an error:\n- Keep GUI function visible and interactive.\n- Hold ESC to abort a running GUI function.");
|
||||
ImGui::SameLine();
|
||||
bool keep_focus = !engine->IO.ConfigRestoreFocusAfterTests;
|
||||
if (ImGui::Checkbox("KeepFocus", &keep_focus))
|
||||
engine->IO.ConfigRestoreFocusAfterTests = !keep_focus;
|
||||
ImGui::SetItemTooltip("After running tests:\n- Keep GUI current focus, instead of restoring focus to this window.");
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::SetNextItemWidth(70 * dpi_scale);
|
||||
if (ImGui::BeginCombo("##Verbose", ImGuiTestEngine_GetVerboseLevelName(engine->IO.ConfigVerboseLevel), ImGuiComboFlags_None))
|
||||
{
|
||||
for (ImGuiTestVerboseLevel level = (ImGuiTestVerboseLevel)0; level < ImGuiTestVerboseLevel_COUNT; level = (ImGuiTestVerboseLevel)(level + 1))
|
||||
if (ImGui::Selectable(ImGuiTestEngine_GetVerboseLevelName(level), engine->IO.ConfigVerboseLevel == level))
|
||||
engine->IO.ConfigVerboseLevel = engine->IO.ConfigVerboseLevelOnError = level;
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SetItemTooltip("Verbose level.");
|
||||
|
||||
//ImGui::PopStyleVar();
|
||||
ImGui::Separator();
|
||||
|
||||
// SPLITTER
|
||||
// FIXME-OPT: A better splitter API supporting arbitrary number of splits would be useful.
|
||||
float list_height = 0.0f;
|
||||
float& log_height = engine->UiLogHeight;
|
||||
ImGui::Splitter("splitter", &list_height, &log_height, ImGuiAxis_Y, +1);
|
||||
|
||||
// TESTS
|
||||
ImGui::BeginChild("List", ImVec2(0, list_height), false, ImGuiWindowFlags_NoScrollbar);
|
||||
if (ImGui::BeginTabBar("##Tests", ImGuiTabBarFlags_NoTooltip)) // Add _NoPushId flag in TabBar?
|
||||
{
|
||||
if (ImGui::BeginTabItem("TESTS", nullptr, ImGuiTabItemFlags_NoPushId))
|
||||
{
|
||||
ShowTestGroup(engine, ImGuiTestGroup_Tests, engine->UiFilterTests);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("PERFS", nullptr, ImGuiTabItemFlags_NoPushId))
|
||||
{
|
||||
ShowTestGroup(engine, ImGuiTestGroup_Perfs, engine->UiFilterPerfs);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
engine->UiSelectAndScrollToTest = nullptr;
|
||||
|
||||
// LOG & TOOLS
|
||||
ImGui::BeginChild("Log", ImVec2(0, log_height));
|
||||
ImGuiTestEngine_ShowLogAndTools(engine);
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ImGuiTestEngine_ShowTestEngineWindows(ImGuiTestEngine* e, bool* p_open)
|
||||
{
|
||||
if (e->TestsSourceLinesDirty)
|
||||
ImGuiTestEngine_UpdateTestsSourceLines(e);
|
||||
|
||||
// Test Tool
|
||||
ImGuiTestEngine_ShowTestTool(e, p_open);
|
||||
|
||||
// Stack Tool
|
||||
#if IMGUI_VERSION_NUM < 18993
|
||||
if (e->UiStackToolOpen)
|
||||
ImGui::ShowStackToolWindow(&e->UiStackToolOpen);
|
||||
#else
|
||||
if (e->UiStackToolOpen)
|
||||
ImGui::ShowIDStackToolWindow(&e->UiStackToolOpen);
|
||||
#endif
|
||||
|
||||
// Capture Tool
|
||||
if (e->UiCaptureToolOpen)
|
||||
e->CaptureTool.ShowCaptureToolWindow(&e->CaptureContext, &e->UiCaptureToolOpen);
|
||||
|
||||
// Performance tool
|
||||
if (e->UiPerfToolOpen)
|
||||
e->PerfTool->ShowPerfToolWindow(e, &e->UiPerfToolOpen);;
|
||||
|
||||
// Show Dear ImGui windows
|
||||
// (we cannot show demo window here because it could lead to duplicate display, which demo windows isn't guarded for)
|
||||
if (e->UiMetricsOpen)
|
||||
ImGui::ShowMetricsWindow(&e->UiMetricsOpen);
|
||||
if (e->UiDebugLogOpen)
|
||||
ImGui::ShowDebugLogWindow(&e->UiDebugLogOpen);
|
||||
}
|
||||
|
||||
void ImGuiTestEngine_OpenSourceFile(ImGuiTestEngine* e, const char* source_filename, int source_line_no)
|
||||
{
|
||||
ImGuiTestEngineIO& e_io = ImGuiTestEngine_GetIO(e);
|
||||
if (e_io.SrcFileOpenFunc == nullptr)
|
||||
ImOsOpenInShell(source_filename); // This is never used by imgui_test_suite but we provide it as a second layer of convenience for test engine users.
|
||||
else
|
||||
e_io.SrcFileOpenFunc(source_filename, source_line_no, e_io.SrcFileOpenUserData);
|
||||
|
||||
// Debugger output which may be double-clicked
|
||||
// Print after opener so it appears in a neat place below e.g. DLL loading.
|
||||
if (ImGui::GetIO().ConfigDebugIsDebuggerPresent)
|
||||
ImOsOutputDebugString(Str256f("%s(%d): opening from user action.\n", source_filename, source_line_no).c_str());
|
||||
}
|
||||
1390
lib/third_party/imgui/imgui_test_engine/source/imgui_te_utils.cpp
vendored
Normal file
1390
lib/third_party/imgui/imgui_test_engine/source/imgui_te_utils.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user