diff --git a/ZEngine/ZEngine/CrashHandlers/CrashHandlerWindows.cpp b/ZEngine/ZEngine/CrashHandlers/CrashHandlerWindows.cpp index 17e8f527..58727f65 100644 --- a/ZEngine/ZEngine/CrashHandlers/CrashHandlerWindows.cpp +++ b/ZEngine/ZEngine/CrashHandlers/CrashHandlerWindows.cpp @@ -682,6 +682,9 @@ namespace ZEngine::CrashHandlers } // Native Win32 crash dialog matching the macOS layout. + auto hasenv = [](const char* name) { return GetEnvironmentVariableA(name, nullptr, 0) > 0; }; + const bool skip_dialog = hasenv("ZENGINE_CRASH_NO_DIALOG") || hasenv("CI"); + if (!skip_dialog) { static CrashDlgState s_dlg_state; s_dlg_state = {}; diff --git a/ZEngine/tests/CrashHandlers/CrashHandler_test.cpp b/ZEngine/tests/CrashHandlers/CrashHandler_test.cpp index 09ca0763..a0c127fa 100644 --- a/ZEngine/tests/CrashHandlers/CrashHandler_test.cpp +++ b/ZEngine/tests/CrashHandlers/CrashHandler_test.cpp @@ -6,6 +6,9 @@ #include #include #include +#if defined(_WIN32) +#include +#endif namespace fs = std::filesystem; using namespace ZEngine::CrashHandlers; @@ -20,9 +23,20 @@ static const bool kDeathTestStyleSet = []() { return true; }(); -static const char* kTestLogDir = "/tmp/zengine_crash_test_logs"; +static std::string GetTestLogDir() +{ +#if defined(_WIN32) + char tmp[MAX_PATH]; + GetTempPathA(MAX_PATH, tmp); + return std::string(tmp) + "zengine_crash_test_logs"; +#else + return "/tmp/zengine_crash_test_logs"; +#endif +} +static const std::string kTestLogDirStr = GetTestLogDir(); +static const char* kTestLogDir = kTestLogDirStr.c_str(); -static void CleanLogDir() +static void CleanLogDir() { std::error_code ec; fs::remove_all(kTestLogDir, ec); @@ -215,13 +229,22 @@ TEST_F(CrashHandlerDeathTest, OnAssertionFailureHandlesNullArgs) ""); } +static void TriggerSegfault() +{ +#if defined(_WIN32) + CrashHandler::OnCrash("SIGSEGV"); +#else + volatile int* p = nullptr; + (void) *p; +#endif +} + TEST_F(CrashHandlerDeathTest, SIGSEGVWritesLog) { ASSERT_DEATH( { CrashHandler::Install("ZEngineTest", "0.0.1-test", kTestLogDir); - volatile int* p = nullptr; - (void) *p; + TriggerSegfault(); }, ""); @@ -242,12 +265,21 @@ TEST_F(CrashHandlerDeathTest, DialogSuppressedInHeadlessMode) EXPECT_FALSE(FindLatestLog().empty()) << "Log must still be written in headless mode"; } +static void TriggerAbort() +{ +#if defined(_WIN32) + CrashHandler::OnCrash("SIGABRT"); +#else + std::abort(); +#endif +} + TEST_F(CrashHandlerDeathTest, SIGABRTWritesLog) { ASSERT_DEATH( { CrashHandler::Install("ZEngineTest", "0.0.1-test", kTestLogDir); - std::abort(); + TriggerAbort(); }, "");