From fdaf4a0cc2c02d881b9488b734204078c01c08ec Mon Sep 17 00:00:00 2001 From: Juuso Piippo Date: Mon, 25 May 2026 00:31:18 +0300 Subject: [PATCH 1/8] Add doctest build and exclude code from tests Added a doctest build which can be run by "build test" or release "build rel test". It will build the test file and run the tests after the app is built --- README.md | 4 + build.bat | 43 +- src/compressor_tests.cpp | 14 + src/win32_compressor.cpp | 1309 +++++++++++++++++++------------------- 4 files changed, 717 insertions(+), 653 deletions(-) create mode 100644 src/compressor_tests.cpp diff --git a/README.md b/README.md index 4fff8fa..37e299c 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,10 @@ Run x64 Native Tools Command Prompt for VS (version optional) build.bat ``` +### Tests + +[Doctest](https://github.com/doctest/doctest), version used 2.5.2. Put doctest.h into "vendor" + ## Notes / limits - If the requested size is too small for the video's length (would force video bitrate < 50 kbps), diff --git a/build.bat b/build.bat index b512ee1..b552310 100644 --- a/build.bat +++ b/build.bat @@ -38,7 +38,7 @@ if !config! == debug ( echo !defines! echo !flags! -set flags=!defines! !flags! +set flagsCombined=!defines! !flags! rem TODO: take a look at /FIXED rem TODO: examine flags that might make Microsoft Defender flag as a virus @@ -51,9 +51,9 @@ set dxLibraries=d3d11.lib dxgi.lib d3dcompiler.lib set buildFailed=0 -if exist *.pdb del /q *.pdb +if exist *.pdb del /q win32_compressor.pdb -cl !flags! ../src/win32_compressor.cpp /I ../src /I ../vendor/imgui ^ +cl !flagsCombined! ../src/win32_compressor.cpp /I ../src /I ../vendor/imgui ^ /link !linkerFlags! !win32Libraries! !dxLibraries! if ERRORLEVEL 1 ( @@ -74,3 +74,40 @@ if !buildFailed! NEQ 0 ( ) else ( echo Build succeeded !DATE! !NOW! ) +echo. + +pushd build + +rem Tests +if "!config!" == "debug" ( + set argMode=%1 +) else ( + set argMode=%2 +) + +if "!argMode!" == "test" ( + echo Building tests... + set defines=!defines! -DCOMPRESSOR_TESTS=1 + echo !defines! + echo !flags! + set flagsCombined=!defines! !flags! + + cl !flagsCombined! /wd4505 ../src/compressor_tests.cpp /I ../src /I ../vendor ^ + /link /SUBSYSTEM:CONSOLE + set NOW=!TIME:~0,8! + if ERRORLEVEL 1 ( + echo tests.cpp failed !DATE! !NOW! + set buildFailed=1 + ) else ( + echo Running tests... + compressor_tests.exe --no-intro + if ERRORLEVEL 1 ( + echo Tests failed !DATE! !NOW! + set buildFailed=1 + ) else ( + echo Tests passed !DATE! !NOW! + ) + ) +) + +popd diff --git a/src/compressor_tests.cpp b/src/compressor_tests.cpp new file mode 100644 index 0000000..9d6b83c --- /dev/null +++ b/src/compressor_tests.cpp @@ -0,0 +1,14 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN + +// https://github.com/doctest/doctest/blob/master/doc/markdown/benchmarks.md#cost-of-an-assertion-macro +#define DOCTEST_CONFIG_SUPER_FAST_ASSERTS // Speed!!! +#include "doctest.h" + +#include "win32_compressor.cpp" + +TEST_CASE("Test fail") { + CHECK_EQ(2, 1); + CHECK_EQ(2, 6); +} + +TEST_CASE("Test success") { CHECK_EQ(2.5f, 2.5f); } diff --git a/src/win32_compressor.cpp b/src/win32_compressor.cpp index 0c7e072..ebd94bd 100644 --- a/src/win32_compressor.cpp +++ b/src/win32_compressor.cpp @@ -43,18 +43,22 @@ # endif #endif -#include "imgui_draw.cpp" -#include "imgui_tables.cpp" -#include "imgui_widgets.cpp" +#if !COMPRESSOR_TESTS +# include "imgui_draw.cpp" +# include "imgui_tables.cpp" +# include "imgui_widgets.cpp" -#include "imgui.cpp" +# include "imgui.cpp" -#include "backends/imgui_impl_dx11.cpp" -#include "backends/imgui_impl_win32.cpp" +# include "backends/imgui_impl_dx11.cpp" +# include "backends/imgui_impl_win32.cpp" //#include "backends/imgui_impl_dx11.h" //#include "backends/imgui_impl_win32.h" //#include "imgui.h" +#else +# include +#endif #include "compressor.h" @@ -1112,16 +1116,12 @@ PickInputFiles(HINSTANCE hInstance, HWND hWnd, AppState* appState) { // Multiple files while (*file) { wchar fullW[MAX_PATH_COUNT]; - swprintf(fullW, L"%s\\%s", dir, file); + swprintf(fullW, ARR_COUNT(fullW), L"%s\\%s", dir, file); AddJob(appState, fullW); file += StrLengthW(file) + 1; } } -/// ----------------------------------------------------------------------------- -/// ImGui -/// ----------------------------------------------------------------------------- - static const char* JobStatusText(JobStatus s) { switch (s) { @@ -1176,135 +1176,451 @@ CancelBatch(AppState* appState) { DEBUG_PRINT("Cancel pressed!\n"); } -static void -DrawUi(AppState* appState, HINSTANCE hInstance, HWND hWnd, f32 scale, f32 delta) { - UIState* uiState = &appState->uiState; - - ImGui::SetNextWindowPos(ImVec2(0, 0)); - ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize); - ImGui::Begin(COMPRESSOR_NAME, nullptr, - ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | - ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_MenuBar); +static bool32 +CreateDefaultConfigFile(const char* path) { + DEBUG_PRINT("Trying to create default config file...\n"); + wchar pathW[MAX_PATH_COUNT]; + UTF8To16(path, pathW); + HANDLE file = + CreateFileW(pathW, GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); + if (!file) { + DEBUG_PRINT("Couldn't create default config file!\n"); + return false; + } - if (ImGui::BeginMenuBar()) { - if (ImGui::BeginMenu("File")) { - if (ImGui::MenuItem("Add files...")) { - DEBUG_PRINT("File -> Add files\n"); - PickInputFiles(hInstance, hWnd, appState); - } + char content[] = + "# IMPORTANT: H264 and H265 are the only codecs currently supported\n" + "# Use the app to set the default output path, it's much easier that way!\n\n" - if (ImGui::MenuItem("Exit")) { - PostQuitMessage(0); - } + "# You can specify up to 5 preset sizes the app loads when it starts, only the " + "first 5 are used\n" + "# Append ! after a value to signal it as the default value\n" + "# Note that the min and max values are 0.5 and 5000.0. Values outside this " + "range are clamped\n\n" + "[Sizes]\n5.0\n10.0 !\n25.0\n50.0\n100.0\n\n" + "[Codecs]\nh264 !\nh265\n\n" + "# Has to be an absolute path\n" + "[OutputPath]\n"; - ImGui::EndMenu(); - } + DWORD written = 0; + // Don't write null terminator + WriteFile(file, content, ARR_COUNT(content) - 1, &written, nullptr); + if (written == 0) { + DEBUG_PRINT("Couldn't write to default config file!\n"); + CloseHandle(file); + return false; + } - if (ImGui::BeginMenu("Help")) { - if (ImGui::MenuItem("About")) { - uiState->helpAboutClicked = true; - DEBUG_PRINT("About clicked\n"); - } + DEBUG_PRINT("Created default config file!\n"); + CloseHandle(file); + return true; +} - if (ImGui::MenuItem("Open config folder...")) { - OpenInExplorer(hWnd, appState->appData); - } +/** + * Return value depends solely on the target sizes! + */ +static bool32 +LoadConfigFile(HWND hWnd, AppState* appState, const char* path) { + wchar pathW[MAX_PATH_COUNT]; + UTF8To16(path, pathW); + HANDLE file = CreateFileW(pathW, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, nullptr); + if (!file) { + DEBUG_PRINT("Config file didn't exist or couldn't open!\n"); + return false; + } - ImGui::EndMenu(); - } + char buf[512 + MAX_PATH_COUNT]; + DWORD bytesRead = 0; - ImGui::EndMenuBar(); + if (!ReadFile(file, buf, ARR_COUNT(buf), &bytesRead, nullptr) || bytesRead == 0) { + DEBUG_PRINT("Couldn't read file!\n"); + CloseHandle(file); + return false; } - /// END MENU - - ImGui::TextDisabled("Drop video files anywhere on this window. Max %d", MAX_JOBS); - ImGui::Separator(); + buf[bytesRead] = '\0'; - bool32 compressing = _InterlockedCompareExchange(&appState->compressing, 0, 0); - bool32 cancelled = _InterlockedCompareExchange(&appState->cancelRequested, 0, 0); - bool32 noJobs = appState->jobCount == 0; + i32 sizesParsed = 0; + bool32 inSizes = false; + bool32 inCodecs = false; + bool32 inOutputPath = false; + bool32 foundDefaultForSize = false; + bool32 foundDefaultForCodec = false; + const char* p = buf; -#if COMPRESSOR_DEV - ImGui::TextDisabled("Compressing: %d, cancelled: %d", compressing, cancelled); -#endif + i32 sizesCount = ARR_COUNT(appState->targetSizes); - const f32 sliderWidth = 190 * scale; + // Currently handles whitespace and other characters at the end only + // I think this is fine + while (*p) { + while (*p == ' ' || *p == '\r' || *p == '\n') { + ++p; + } - /// Default target size + if (!*p) { + break; + } - ImGui::TextUnformatted("Default target size:"); - f32* defaultTargetSize = &appState->defaultTargetSize; - ImGui::SetNextItemWidth(sliderWidth); - ImGui::SliderFloat("##mb_slider_default", defaultTargetSize, MIN_TARGET_SIZE, MAX_TARGET_SIZE, - "%.1f MB", ImGuiSliderFlags_Logarithmic); + // Comments + if (*p == '#') { + while (*p && *p != '\n') { + ++p; + } - ImGui::SameLine(); - ImGui::BeginDisabled(compressing || noJobs); - if (ImGui::Button("Apply new size to all files")) { - SetTargetSizeForAll(appState, *defaultTargetSize); - } + continue; + } - ImGui::EndDisabled(); + // Section + if (*p == '[') { + inSizes = (p[1] == 'S' && p[2] == 'i' && p[3] == 'z' && p[4] == 'e' && p[5] == 's' && + p[6] == ']'); - ImGui::SameLine(0.0f, 10.0f); - ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); - ImGui::SameLine(0.0f, 10.0f); + inCodecs = (p[1] == 'C' && p[2] == 'o' && p[3] == 'd' && p[4] == 'e' && p[5] == 'c' && + p[6] == 's' && p[7] == ']'); - ImGui::TextUnformatted("Codec used:"); - ImGui::SameLine(); - ImGui::BeginDisabled(compressing); + inOutputPath = (p[1] == 'O' && p[2] == 'u' && p[3] == 't' && p[4] == 'p' && + p[5] == 'u' && p[6] == 't' && p[7] == 'P' && p[8] == 'a' && + p[9] == 't' && p[10] == 'h' && p[11] == ']'); - /// Codec + while (*p && *p != '\n') { + ++p; + } - Codec currentCodec = appState->defaultCodec; - if (ImGui::RadioButton("H.264", appState->defaultCodec == Codec::H264)) { - appState->defaultCodec = Codec::H264; - } + continue; + } - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::TextUnformatted("Recommended default codec"); - ImGui::EndTooltip(); - } + if (inSizes) { + f32 value = StrToF32(p); + if (value != 0.0f || (*p >= '0' && *p <= '9')) { + f32 oldValue = value; + value = ClampF32(value, MIN_TARGET_SIZE, MAX_TARGET_SIZE); + if (oldValue != value) { + DEBUG_PRINTF("Clamped %.2f to %.2f\n", oldValue, value); + } - ImGui::SameLine(); - if (ImGui::RadioButton("H.265", currentCodec == Codec::H265)) { - appState->defaultCodec = Codec::H265; - } + if (sizesParsed == sizesCount) { + DEBUG_PRINTF("Tried to parse more than %d sizes, SUCCESS\n", sizesCount); + break; + } - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::TextUnformatted( - "Can reduce video size 20-75% more compared to H.264, but will take a lot longer\n" - "Final size may end up being significantly below the target"); - ImGui::EndTooltip(); - } + appState->targetSizes[sizesParsed++] = value; + DEBUG_PRINTF("Parsed size: %.2f\n", value); - ImGui::EndDisabled(); + if (!foundDefaultForSize) { + const char* start = p; + while (*p && *p != '\n') { + ++p; + } - ImGui::SetNextItemWidth(sliderWidth); - ImGui::InputFloat("##mb_input_default", defaultTargetSize, 0.0f, 0.0f, "%.2f MB"); - *defaultTargetSize = ClampF32(*defaultTargetSize, MIN_TARGET_SIZE, MAX_TARGET_SIZE); + bool32 isDefault = false; + for (const char* t = start; t < p; ++t) { + if (*t == '!') { + isDefault = true; + break; + } + } - ImGui::SameLine(0.0f, 10.0f); - ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); - ImGui::SameLine(0.0f, 10.0f); + if (isDefault) { + foundDefaultForSize = true; + DEBUG_PRINTF("Found default target size of %.2f!\n", value); + appState->defaultTargetSize = value; + } + } + } + } else if (inCodecs) { + if (!foundDefaultForCodec) { + const char* start = p; + while (*p && *p != '\n') { + ++p; + } - ImGui::TextUnformatted("Output folder:"); + bool32 isDefault = false; + for (const char* t = start; t < p; ++t) { + if (*t == '!') { + isDefault = true; + break; + } + } - ImGui::SameLine(); - if (appState->outputFolder[0] == '\0') { - ImGui::TextUnformatted("No default folder selected"); - } else { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.2f, 1.0f, 0.7f, 1.0f)); + // Skip leading whitespace + const char* end = p; + const char* t = start; + while (t < end && *t == ' ') { + ++t; + } - // TODO: easily configurable if needed - const f32 maxWidth = 550.0f; - f32 requiredWidth = ImGui::CalcTextSize(appState->outputFolder).x; - requiredWidth = ClampF32(requiredWidth, 0.0f, maxWidth); + Codec codec = Codec::NONE; + if ((end - t) >= 4 && t[0] == 'h' && t[1] == '2' && t[2] == '6' && t[3] == '4') { + codec = Codec::H264; + } else if ((end - t) >= 4 && t[0] == 'h' && t[1] == '2' && t[2] == '6' && + t[3] == '5') { + codec = Codec::H265; + } - ImGui::PushItemWidth(requiredWidth); + if (codec != Codec::NONE && isDefault) { + foundDefaultForCodec = true; + DEBUG_PRINTF("Found default codec %s!\n", CodecText_(codec)); + appState->defaultCodec = codec; + } + } + } else if (inOutputPath) { + const char* start = p; + while (*p && *p != '\n') { + ++p; + } + + const char* end = p; + const char* t = start; + while (t < end && *t == ' ') { + ++t; + } + + char outputPath[MAX_PATH_COUNT]; + i32 len = static_cast(end - start); + + if (len > 0 && len < MAX_PATH_COUNT) { + CopyMemory(outputPath, start, len); + outputPath[len] = '\0'; + + wchar outputPathW[ARR_COUNT(outputPath)]; + UTF8To16(outputPath, outputPathW); + + if (PathIsRelativeW(outputPathW)) { + DEBUG_PRINTF("Tried to use relative path %s\n", outputPath); + } else { + DWORD attrs = GetFileAttributesW(outputPathW); + bool32 valid = false; + + if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { + valid = true; + } else { + if (CreateDirectoryW(outputPathW, nullptr)) { + valid = true; + } else { + DWORD err = GetLastError(); + if (err == ERROR_ALREADY_EXISTS) { + valid = true; + } + } + } + + if (valid) { + DEBUG_PRINTF("Using output path: %s\n", outputPath); + snprintf(appState->outputFolder, ARR_COUNT(appState->outputFolder), + outputPath); + } else { + DEBUG_PRINTF("Invalid output path: %s\n", outputPath); + } + } + } else { + DEBUG_PRINTF("Invalid output path length: %d\n", len); + } + } + + while (*p && *p != '\n') { + ++p; + } + } + + CloseHandle(file); + + // Having no output path is NOT considered a failure + // We just use the default User/Documents/EasyCompressor + if (appState->outputFolder[0] == '\0') { + wchar outputFolder[MAX_PATH_COUNT]; + if (!SUCCEEDED(SHGetFolderPathW(hWnd, CSIDL_MYDOCUMENTS, nullptr, 0, outputFolder))) { + DEBUG_PRINT("Couldn't get user documents folder, using exe dir as working dir...\n"); + // Use exe dir as working dir... + snprintf(appState->outputFolder, ARR_COUNT(appState->outputFolder), "%s", + appState->exeDir); + } else { + DEBUG_PRINTF("Found documents %ls\n", outputFolder); + swprintf(outputFolder, ARR_COUNT(outputFolder), L"%ls\\EasyCompressor", outputFolder); + // It's okay to fail silently + BOOL created = CreateDirectoryW(outputFolder, nullptr); + UTF16To8(outputFolder, appState->outputFolder); + if (!created) { + DWORD err = GetLastError(); + if (err != ERROR_ALREADY_EXISTS) { + // This shouldn't ever happen though + INVALID_CODE_PATH; + DEBUG_PRINTF("SHGetFolderPathA returned %s but couldn't create the directory " + "there. Using exe dir...\n"); + snprintf(appState->outputFolder, ARR_COUNT(appState->outputFolder), "%s", + appState->exeDir); + } + } + } + } + + // I guess this for now as the default + //appState->useOutputFolder = true; + + // Having no codecs is NOT considered a failure + // Having no default codec is also NOT considered a failure + // This is just for the simplicity and differs heavily from the logic of target sizes + // Simply: if we don't have the default set via "!", we assign a default + // TODO: maybe revise the logic here, see above + if (appState->defaultCodec == Codec::NONE) { + DEBUG_PRINT("No codec specified, assigning default!\n"); + appState->defaultCodec = Codec::H264; + } + + // User added some sizes but not the full amount + // We consider having 0 target sizes a failure + if (sizesParsed > 0 && sizesParsed < sizesCount) { + DEBUG_PRINTF("Parsed %d out of %d, meaning SUCCESS\n", sizesParsed, sizesCount); + if (!foundDefaultForSize) { + // Set the first user-supplied size as the default + f32 defaultSize = appState->targetSizes[0]; + DEBUG_PRINTF("Didn't find default, setting it to %.2f\n", defaultSize, 0); + appState->defaultTargetSize = defaultSize; + } + + sizesParsed = sizesCount; + } + + bool32 success = sizesParsed == sizesCount; + return success; +} + +// Tests don't need this stuff +#if !COMPRESSOR_TESTS + +/// ----------------------------------------------------------------------------- +/// ImGui +/// ----------------------------------------------------------------------------- + +static void +DrawUi(AppState* appState, HINSTANCE hInstance, HWND hWnd, f32 scale, f32 delta) { + UIState* uiState = &appState->uiState; + + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize); + ImGui::Begin(COMPRESSOR_NAME, nullptr, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_MenuBar); + + if (ImGui::BeginMenuBar()) { + if (ImGui::BeginMenu("File")) { + if (ImGui::MenuItem("Add files...")) { + DEBUG_PRINT("File -> Add files\n"); + PickInputFiles(hInstance, hWnd, appState); + } + + if (ImGui::MenuItem("Exit")) { + PostQuitMessage(0); + } + + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Help")) { + if (ImGui::MenuItem("About")) { + uiState->helpAboutClicked = true; + DEBUG_PRINT("About clicked\n"); + } + + if (ImGui::MenuItem("Open config folder...")) { + OpenInExplorer(hWnd, appState->appData); + } + + ImGui::EndMenu(); + } + + ImGui::EndMenuBar(); + } + + /// END MENU + + ImGui::TextDisabled("Drop video files anywhere on this window. Max %d", MAX_JOBS); + ImGui::Separator(); + + bool32 compressing = _InterlockedCompareExchange(&appState->compressing, 0, 0); + bool32 cancelled = _InterlockedCompareExchange(&appState->cancelRequested, 0, 0); + bool32 noJobs = appState->jobCount == 0; + +# if COMPRESSOR_DEV + ImGui::TextDisabled("Compressing: %d, cancelled: %d", compressing, cancelled); +# endif + + const f32 sliderWidth = 190 * scale; + + /// Default target size + + ImGui::TextUnformatted("Default target size:"); + f32* defaultTargetSize = &appState->defaultTargetSize; + ImGui::SetNextItemWidth(sliderWidth); + ImGui::SliderFloat("##mb_slider_default", defaultTargetSize, MIN_TARGET_SIZE, MAX_TARGET_SIZE, + "%.1f MB", ImGuiSliderFlags_Logarithmic); + + ImGui::SameLine(); + ImGui::BeginDisabled(compressing || noJobs); + if (ImGui::Button("Apply new size to all files")) { + SetTargetSizeForAll(appState, *defaultTargetSize); + } + + ImGui::EndDisabled(); + + ImGui::SameLine(0.0f, 10.0f); + ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); + ImGui::SameLine(0.0f, 10.0f); + + ImGui::TextUnformatted("Codec used:"); + ImGui::SameLine(); + ImGui::BeginDisabled(compressing); + + /// Codec + + Codec currentCodec = appState->defaultCodec; + if (ImGui::RadioButton("H.264", appState->defaultCodec == Codec::H264)) { + appState->defaultCodec = Codec::H264; + } + + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::TextUnformatted("Recommended default codec"); + ImGui::EndTooltip(); + } + + ImGui::SameLine(); + if (ImGui::RadioButton("H.265", currentCodec == Codec::H265)) { + appState->defaultCodec = Codec::H265; + } + + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::TextUnformatted( + "Can reduce video size 20-75% more compared to H.264, but will take a lot longer\n" + "Final size may end up being significantly below the target"); + ImGui::EndTooltip(); + } + + ImGui::EndDisabled(); + + ImGui::SetNextItemWidth(sliderWidth); + ImGui::InputFloat("##mb_input_default", defaultTargetSize, 0.0f, 0.0f, "%.2f MB"); + *defaultTargetSize = ClampF32(*defaultTargetSize, MIN_TARGET_SIZE, MAX_TARGET_SIZE); + + ImGui::SameLine(0.0f, 10.0f); + ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); + ImGui::SameLine(0.0f, 10.0f); + + ImGui::TextUnformatted("Output folder:"); + + ImGui::SameLine(); + if (appState->outputFolder[0] == '\0') { + ImGui::TextUnformatted("No default folder selected"); + } else { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.2f, 1.0f, 0.7f, 1.0f)); + + // TODO: easily configurable if needed + const f32 maxWidth = 550.0f; + f32 requiredWidth = ImGui::CalcTextSize(appState->outputFolder).x; + requiredWidth = ClampF32(requiredWidth, 0.0f, maxWidth); + + ImGui::PushItemWidth(requiredWidth); ImGui::Selectable(appState->outputFolder, false, 0, ImVec2(requiredWidth, 0.0f)); ImGui::PopItemWidth(); ImGui::PopStyleColor(); @@ -1659,590 +1975,281 @@ DrawUi(AppState* appState, HINSTANCE hInstance, HWND hWnd, f32 scale, f32 delta) ImDrawList* dl = ImGui::GetWindowDrawList(); f32 fileW = size * 0.7f; - f32 fold = size * 0.25f; - - ImU32 col = IM_COL32(200, 200, 200, 255); - - // File outline - dl->AddLine(ImVec2(pos.x, pos.y), ImVec2(pos.x + fileW - fold, pos.y), col, 2.0f); - dl->AddLine(ImVec2(pos.x, pos.y), ImVec2(pos.x, pos.y + size), col, 2.0f); - dl->AddLine(ImVec2(pos.x, pos.y + size), ImVec2(pos.x + fileW, pos.y + size), col, 2.0f); - dl->AddLine(ImVec2(pos.x + fileW, pos.y + fold), ImVec2(pos.x + fileW, pos.y + size), col, - 2.0f); - - // Fold diagonal - dl->AddLine(ImVec2(pos.x + fileW - fold, pos.y), ImVec2(pos.x + fileW, pos.y + fold), col, - 2.0f); - - // Corner triangle - dl->AddTriangleFilled(ImVec2(pos.x + fileW - fold - 1.0f, pos.y + 1.0f), - ImVec2(pos.x + fileW - 1.0f, pos.y + fold + 1.0f), - ImVec2(pos.x + fileW - fold - 1.0f, pos.y + fold + 1.0f), - IM_COL32(150, 150, 150, 255)); - - // Plus sign - f32 cx = pos.x + (size * 0.35f); - f32 cy = pos.y + (size * 0.65f); - f32 arm = size * 0.15f; - f32 thickness = 2.0f; - dl->AddLine(ImVec2(cx - arm, cy), ImVec2(cx + arm, cy), IM_COL32(100, 220, 100, 255), - thickness); - dl->AddLine(ImVec2(cx, cy - arm), ImVec2(cx, cy + arm), IM_COL32(100, 220, 100, 255), - thickness); - - // Invisible button for interaction - ImGui::InvisibleButton("##add_files", ImVec2(fileW, size)); - if (ImGui::IsItemClicked()) { - PickInputFiles(hInstance, hWnd, appState); - ImGui::GetIO().ClearInputMouse(); // ImGui input really doesn't like blocking functions - } - - if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::TextUnformatted("Shortcut: Control + A"); - ImGui::EndTooltip(); - } - - ImGui::SameLine(); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (size - ImGui::GetTextLineHeight()) * 0.5f); - ImGui::TextDisabled("Add files..."); - - ImGui::Separator(); - - ImGui::BeginDisabled(compressing || noJobs); - if (ImGui::Button("Clear", ImVec2(80 * scale, 0))) { - DEBUG_PRINT("Clear\n"); - _InterlockedExchange(&appState->jobCount, 0); - } - - ImGui::EndDisabled(); - - ImGui::End(); - - /// ImGui::End() - - // We have to do popup stuff here - - //ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, - // ImVec2(0.5f, 0.5f)); - - // Declare popups - - if (ImGui::BeginPopupModal("HelpAboutPopup", nullptr, - ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | - ImGuiWindowFlags_NoCollapse)) { - ImGui::TextUnformatted(COMPRESSOR_NAME); - ImGui::Separator(); - - ImGui::TextUnformatted("Built with:"); - ImGui::SameLine(); - ImGui::TextLinkOpenURL("ImGui", "https://github.com/ocornut/imgui"); - ImGui::SameLine(); - ImGui::TextUnformatted("Source:"); - ImGui::SameLine(); - ImGui::TextLinkOpenURL("EasyCompressor", "https://github.com/JuJuz1/EasyCompressor"); - - ImGui::Text("Max length for input/output paths is %d", MAX_PATH_COUNT); - ImGui::TextUnformatted("Small target sizes (below 10 MB) might result in the\ncompressed " - "size being slightly above the target size"); - - if (ImGui::Button("OK") || uiState->escJustPressed) { - ImGui::CloseCurrentPopup(); - } - - ImGui::EndPopup(); - } - - if (ImGui::BeginPopupModal("ErrorPopup", nullptr, - ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | - ImGuiWindowFlags_NoCollapse)) { - ImGui::TextUnformatted(uiState->errorMsg); - if (ImGui::Button("OK") || uiState->escJustPressed) { - ImGui::CloseCurrentPopup(); - } - - ImGui::EndPopup(); - } - - // Handle popups - - if (uiState->helpAboutClicked) { - ImGui::OpenPopup("HelpAboutPopup"); - uiState->helpAboutClicked = false; - } - - if (uiState->showError) { - ImGui::OpenPopup("ErrorPopup"); - uiState->showError = false; - } -} - -/// ----------------------------------------------------------------------------- -/// Win32 / DX11 boilerplate (from the ImGui example, trimmed) -/// ----------------------------------------------------------------------------- - -static ID3D11Device* gDevice; -static ID3D11DeviceContext* gContext; -static IDXGISwapChain* gSwap; -static ID3D11RenderTargetView* gRtv; - -static bool32 gSwapChainOccluded; -static i32 gResizeWidth, gResizeHeight; - -static void -CreateRenderTarget() { - ID3D11Texture2D* pBackBuffer; - gSwap->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); - gDevice->CreateRenderTargetView(pBackBuffer, nullptr, &gRtv); - pBackBuffer->Release(); -} - -static void -CleanupRenderTarget() { - if (gRtv) { - gRtv->Release(); - gRtv = nullptr; - } -} - -static bool -CreateDeviceD3D(HWND hWnd) { - // Setup swap chain - // This is a basic setup. Optimally could use e.g. DXGI_SWAP_EFFECT_FLIP_DISCARD and handle - // fullscreen mode differently. See #8979 for suggestions. - DXGI_SWAP_CHAIN_DESC sd = {}; - - sd.BufferCount = 2; - sd.BufferDesc.Width = 0; - sd.BufferDesc.Height = 0; - sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - sd.BufferDesc.RefreshRate.Numerator = 60; - sd.BufferDesc.RefreshRate.Denominator = 1; - sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; - sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - sd.OutputWindow = hWnd; - sd.SampleDesc.Count = 1; - sd.SampleDesc.Quality = 0; - sd.Windowed = TRUE; - sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - - UINT createDeviceFlags = 0; - //createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; - D3D_FEATURE_LEVEL featureLevel; - const D3D_FEATURE_LEVEL featureLevelArray[2] = { - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_0, - }; - - HRESULT res = D3D11CreateDeviceAndSwapChain( - nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, - D3D11_SDK_VERSION, &sd, &gSwap, &gDevice, &featureLevel, &gContext); - if (res == DXGI_ERROR_UNSUPPORTED) { // Try high-performance WARP software driver if - // hardware is not available. - res = D3D11CreateDeviceAndSwapChain( - nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, - D3D11_SDK_VERSION, &sd, &gSwap, &gDevice, &featureLevel, &gContext); - } - if (res != S_OK) { - return false; - } - - CreateRenderTarget(); - return true; -} - -static void -CleanupDeviceD3D() { - CleanupRenderTarget(); - if (gSwap) { - gSwap->Release(); - gSwap = nullptr; - } - if (gContext) { - gContext->Release(); - gContext = nullptr; - } - if (gDevice) { - gDevice->Release(); - gDevice = nullptr; - } -} - -extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, - LPARAM lParam); - -static LRESULT WINAPI -WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { - if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) { - return true; - } - - switch (msg) { - case WM_DROPFILES: { - HDROP drop = reinterpret_cast(wParam); - UINT fileCount = DragQueryFileW(drop, 0xFFFFFFFF, nullptr, 0); - // TODO: validate by most common video file extensions? - // We do allow files with no extension so probably not... - for (UINT i = 0; i < fileCount && i < MAX_JOBS; ++i) { - wchar path[MAX_PATH_COUNT]; - // Query the required character amount first, not including null terminator - // If we don't query we have no way of deducing if the path was truncated or it's - // exactly MAX_PATH_COUNT long - UINT required = DragQueryFileW(drop, i, nullptr, 0); - - // Get the path and get the copied amount, not including null terminator - UINT copied = DragQueryFileW(drop, i, path, ARR_COUNT(path)); - - DEBUG_PRINTF("Required: %u, copied %u (both not including null terminator)\n", required, - copied); - - // required > copied would work as well - if (required >= ARR_COUNT(path)) { - DEBUG_PRINTF("Path was truncated, didn't add job! Max length: %d\nPath would have " - "been %s\n", - MAX_PATH_COUNT, path); - // TODO: show error for user for discarded files, or no? It's quite self-evident - // what is happening - continue; - } - - ASSERT(gAppState); - AddJob(gAppState, path); - } + f32 fold = size * 0.25f; - DragFinish(drop); - return 0; - } break; + ImU32 col = IM_COL32(200, 200, 200, 255); - case WM_SIZE: { - if (gDevice && wParam != SIZE_MINIMIZED) { - CleanupRenderTarget(); - gSwap->ResizeBuffers(0, LOWORD(lParam), HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0); - CreateRenderTarget(); - } + // File outline + dl->AddLine(ImVec2(pos.x, pos.y), ImVec2(pos.x + fileW - fold, pos.y), col, 2.0f); + dl->AddLine(ImVec2(pos.x, pos.y), ImVec2(pos.x, pos.y + size), col, 2.0f); + dl->AddLine(ImVec2(pos.x, pos.y + size), ImVec2(pos.x + fileW, pos.y + size), col, 2.0f); + dl->AddLine(ImVec2(pos.x + fileW, pos.y + fold), ImVec2(pos.x + fileW, pos.y + size), col, + 2.0f); - return 0; - } break; + // Fold diagonal + dl->AddLine(ImVec2(pos.x + fileW - fold, pos.y), ImVec2(pos.x + fileW, pos.y + fold), col, + 2.0f); - case WM_DESTROY: { - PostQuitMessage(0); - return 0; - } break; + // Corner triangle + dl->AddTriangleFilled(ImVec2(pos.x + fileW - fold - 1.0f, pos.y + 1.0f), + ImVec2(pos.x + fileW - 1.0f, pos.y + fold + 1.0f), + ImVec2(pos.x + fileW - fold - 1.0f, pos.y + fold + 1.0f), + IM_COL32(150, 150, 150, 255)); - default: { - } break; - } + // Plus sign + f32 cx = pos.x + (size * 0.35f); + f32 cy = pos.y + (size * 0.65f); + f32 arm = size * 0.15f; + f32 thickness = 2.0f; + dl->AddLine(ImVec2(cx - arm, cy), ImVec2(cx + arm, cy), IM_COL32(100, 220, 100, 255), + thickness); + dl->AddLine(ImVec2(cx, cy - arm), ImVec2(cx, cy + arm), IM_COL32(100, 220, 100, 255), + thickness); - return DefWindowProcW(hWnd, msg, wParam, lParam); -} + // Invisible button for interaction + ImGui::InvisibleButton("##add_files", ImVec2(fileW, size)); + if (ImGui::IsItemClicked()) { + PickInputFiles(hInstance, hWnd, appState); + ImGui::GetIO().ClearInputMouse(); // ImGui input really doesn't like blocking functions + } -static bool32 -CreateDefaultConfigFile(const char* path) { - DEBUG_PRINT("Trying to create default config file...\n"); - wchar pathW[MAX_PATH_COUNT]; - UTF8To16(path, pathW); - HANDLE file = - CreateFileW(pathW, GENERIC_WRITE, 0, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); - if (!file) { - DEBUG_PRINT("Couldn't create default config file!\n"); - return false; + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::TextUnformatted("Shortcut: Control + A"); + ImGui::EndTooltip(); } - char content[] = - "# IMPORTANT: H264 and H265 are the only codecs currently supported\n" - "# Use the app to set the default output path, it's much easier that way!\n\n" + ImGui::SameLine(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + (size - ImGui::GetTextLineHeight()) * 0.5f); + ImGui::TextDisabled("Add files..."); - "# You can specify up to 5 preset sizes the app loads when it starts, only the " - "first 5 are used\n" - "# Append ! after a value to signal it as the default value\n" - "# Note that the min and max values are 0.5 and 5000.0. Values outside this " - "range are clamped\n\n" - "[Sizes]\n5.0\n10.0 !\n25.0\n50.0\n100.0\n\n" - "[Codecs]\nh264 !\nh265\n\n" - "# Has to be an absolute path\n" - "[OutputPath]\n"; + ImGui::Separator(); - DWORD written = 0; - // Don't write null terminator - WriteFile(file, content, ARR_COUNT(content) - 1, &written, nullptr); - if (written == 0) { - DEBUG_PRINT("Couldn't write to default config file!\n"); - CloseHandle(file); - return false; + ImGui::BeginDisabled(compressing || noJobs); + if (ImGui::Button("Clear", ImVec2(80 * scale, 0))) { + DEBUG_PRINT("Clear\n"); + _InterlockedExchange(&appState->jobCount, 0); } - DEBUG_PRINT("Created default config file!\n"); - CloseHandle(file); - return true; -} - -/** - * Return value depends solely on the target sizes! - */ -static bool32 -LoadConfigFile(HWND hWnd, AppState* appState, const char* path) { - wchar pathW[MAX_PATH_COUNT]; - UTF8To16(path, pathW); - HANDLE file = CreateFileW(pathW, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, nullptr); - if (!file) { - DEBUG_PRINT("Config file didn't exist or couldn't open!\n"); - return false; - } + ImGui::EndDisabled(); - char buf[512 + MAX_PATH_COUNT]; - DWORD bytesRead = 0; + ImGui::End(); - if (!ReadFile(file, buf, ARR_COUNT(buf), &bytesRead, nullptr) || bytesRead == 0) { - DEBUG_PRINT("Couldn't read file!\n"); - CloseHandle(file); - return false; - } + /// ImGui::End() - buf[bytesRead] = '\0'; + // We have to do popup stuff here - i32 sizesParsed = 0; - bool32 inSizes = false; - bool32 inCodecs = false; - bool32 inOutputPath = false; - bool32 foundDefaultForSize = false; - bool32 foundDefaultForCodec = false; - const char* p = buf; + //ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, + // ImVec2(0.5f, 0.5f)); - i32 sizesCount = ARR_COUNT(appState->targetSizes); + // Declare popups - // Currently handles whitespace and other characters at the end only - // I think this is fine - while (*p) { - while (*p == ' ' || *p == '\r' || *p == '\n') { - ++p; - } + if (ImGui::BeginPopupModal("HelpAboutPopup", nullptr, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoCollapse)) { + ImGui::TextUnformatted(COMPRESSOR_NAME); + ImGui::Separator(); - if (!*p) { - break; - } + ImGui::TextUnformatted("Built with:"); + ImGui::SameLine(); + ImGui::TextLinkOpenURL("ImGui", "https://github.com/ocornut/imgui"); + ImGui::SameLine(); + ImGui::TextUnformatted("Source:"); + ImGui::SameLine(); + ImGui::TextLinkOpenURL("EasyCompressor", "https://github.com/JuJuz1/EasyCompressor"); - // Comments - if (*p == '#') { - while (*p && *p != '\n') { - ++p; - } + ImGui::Text("Max length for input/output paths is %d", MAX_PATH_COUNT); + ImGui::TextUnformatted("Small target sizes (below 10 MB) might result in the\ncompressed " + "size being slightly above the target size"); - continue; + if (ImGui::Button("OK") || uiState->escJustPressed) { + ImGui::CloseCurrentPopup(); } - // Section - if (*p == '[') { - inSizes = (p[1] == 'S' && p[2] == 'i' && p[3] == 'z' && p[4] == 'e' && p[5] == 's' && - p[6] == ']'); + ImGui::EndPopup(); + } - inCodecs = (p[1] == 'C' && p[2] == 'o' && p[3] == 'd' && p[4] == 'e' && p[5] == 'c' && - p[6] == 's' && p[7] == ']'); + if (ImGui::BeginPopupModal("ErrorPopup", nullptr, + ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | + ImGuiWindowFlags_NoCollapse)) { + ImGui::TextUnformatted(uiState->errorMsg); + if (ImGui::Button("OK") || uiState->escJustPressed) { + ImGui::CloseCurrentPopup(); + } - inOutputPath = (p[1] == 'O' && p[2] == 'u' && p[3] == 't' && p[4] == 'p' && - p[5] == 'u' && p[6] == 't' && p[7] == 'P' && p[8] == 'a' && - p[9] == 't' && p[10] == 'h' && p[11] == ']'); + ImGui::EndPopup(); + } - while (*p && *p != '\n') { - ++p; - } + // Handle popups - continue; - } + if (uiState->helpAboutClicked) { + ImGui::OpenPopup("HelpAboutPopup"); + uiState->helpAboutClicked = false; + } - if (inSizes) { - f32 value = StrToF32(p); - if (value != 0.0f || (*p >= '0' && *p <= '9')) { - f32 oldValue = value; - value = ClampF32(value, MIN_TARGET_SIZE, MAX_TARGET_SIZE); - if (oldValue != value) { - DEBUG_PRINTF("Clamped %.2f to %.2f\n", oldValue, value); - } + if (uiState->showError) { + ImGui::OpenPopup("ErrorPopup"); + uiState->showError = false; + } +} - if (sizesParsed == sizesCount) { - DEBUG_PRINTF("Tried to parse more than %d sizes, SUCCESS\n", sizesCount); - break; - } +/// ----------------------------------------------------------------------------- +/// Win32 / DX11 boilerplate (from the ImGui example, trimmed) +/// ----------------------------------------------------------------------------- - appState->targetSizes[sizesParsed++] = value; - DEBUG_PRINTF("Parsed size: %.2f\n", value); +static ID3D11Device* gDevice; +static ID3D11DeviceContext* gContext; +static IDXGISwapChain* gSwap; +static ID3D11RenderTargetView* gRtv; - if (!foundDefaultForSize) { - const char* start = p; - while (*p && *p != '\n') { - ++p; - } +static bool32 gSwapChainOccluded; +static i32 gResizeWidth, gResizeHeight; - bool32 isDefault = false; - for (const char* t = start; t < p; ++t) { - if (*t == '!') { - isDefault = true; - break; - } - } +static void +CreateRenderTarget() { + ID3D11Texture2D* pBackBuffer; + gSwap->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); + gDevice->CreateRenderTargetView(pBackBuffer, nullptr, &gRtv); + pBackBuffer->Release(); +} - if (isDefault) { - foundDefaultForSize = true; - DEBUG_PRINTF("Found default target size of %.2f!\n", value); - appState->defaultTargetSize = value; - } - } - } - } else if (inCodecs) { - if (!foundDefaultForCodec) { - const char* start = p; - while (*p && *p != '\n') { - ++p; - } +static void +CleanupRenderTarget() { + if (gRtv) { + gRtv->Release(); + gRtv = nullptr; + } +} - bool32 isDefault = false; - for (const char* t = start; t < p; ++t) { - if (*t == '!') { - isDefault = true; - break; - } - } +static bool +CreateDeviceD3D(HWND hWnd) { + // Setup swap chain + // This is a basic setup. Optimally could use e.g. DXGI_SWAP_EFFECT_FLIP_DISCARD and handle + // fullscreen mode differently. See #8979 for suggestions. + DXGI_SWAP_CHAIN_DESC sd = {}; - // Skip leading whitespace - const char* end = p; - const char* t = start; - while (t < end && *t == ' ') { - ++t; - } + sd.BufferCount = 2; + sd.BufferDesc.Width = 0; + sd.BufferDesc.Height = 0; + sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.BufferDesc.RefreshRate.Numerator = 60; + sd.BufferDesc.RefreshRate.Denominator = 1; + sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.OutputWindow = hWnd; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = 0; + sd.Windowed = TRUE; + sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - Codec codec = Codec::NONE; - if ((end - t) >= 4 && t[0] == 'h' && t[1] == '2' && t[2] == '6' && t[3] == '4') { - codec = Codec::H264; - } else if ((end - t) >= 4 && t[0] == 'h' && t[1] == '2' && t[2] == '6' && - t[3] == '5') { - codec = Codec::H265; - } + UINT createDeviceFlags = 0; + //createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; + D3D_FEATURE_LEVEL featureLevel; + const D3D_FEATURE_LEVEL featureLevelArray[2] = { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_0, + }; - if (codec != Codec::NONE && isDefault) { - foundDefaultForCodec = true; - DEBUG_PRINTF("Found default codec %s!\n", CodecText_(codec)); - appState->defaultCodec = codec; - } - } - } else if (inOutputPath) { - const char* start = p; - while (*p && *p != '\n') { - ++p; - } + HRESULT res = D3D11CreateDeviceAndSwapChain( + nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, + D3D11_SDK_VERSION, &sd, &gSwap, &gDevice, &featureLevel, &gContext); + if (res == DXGI_ERROR_UNSUPPORTED) { // Try high-performance WARP software driver if + // hardware is not available. + res = D3D11CreateDeviceAndSwapChain( + nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, + D3D11_SDK_VERSION, &sd, &gSwap, &gDevice, &featureLevel, &gContext); + } + if (res != S_OK) { + return false; + } - const char* end = p; - const char* t = start; - while (t < end && *t == ' ') { - ++t; - } + CreateRenderTarget(); + return true; +} - char outputPath[MAX_PATH_COUNT]; - i32 len = static_cast(end - start); +static void +CleanupDeviceD3D() { + CleanupRenderTarget(); + if (gSwap) { + gSwap->Release(); + gSwap = nullptr; + } + if (gContext) { + gContext->Release(); + gContext = nullptr; + } + if (gDevice) { + gDevice->Release(); + gDevice = nullptr; + } +} - if (len > 0 && len < MAX_PATH_COUNT) { - CopyMemory(outputPath, start, len); - outputPath[len] = '\0'; +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, + LPARAM lParam); - wchar outputPathW[ARR_COUNT(outputPath)]; - UTF8To16(outputPath, outputPathW); +static LRESULT WINAPI +WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { + if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) { + return true; + } - if (PathIsRelativeW(outputPathW)) { - DEBUG_PRINTF("Tried to use relative path %s\n", outputPath); - } else { - DWORD attrs = GetFileAttributesW(outputPathW); - bool32 valid = false; + switch (msg) { + case WM_DROPFILES: { + HDROP drop = reinterpret_cast(wParam); + UINT fileCount = DragQueryFileW(drop, 0xFFFFFFFF, nullptr, 0); + // TODO: validate by most common video file extensions? + // We do allow files with no extension so probably not... + for (UINT i = 0; i < fileCount && i < MAX_JOBS; ++i) { + wchar path[MAX_PATH_COUNT]; + // Query the required character amount first, not including null terminator + // If we don't query we have no way of deducing if the path was truncated or it's + // exactly MAX_PATH_COUNT long + UINT required = DragQueryFileW(drop, i, nullptr, 0); - if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) { - valid = true; - } else { - if (CreateDirectoryW(outputPathW, nullptr)) { - valid = true; - } else { - DWORD err = GetLastError(); - if (err == ERROR_ALREADY_EXISTS) { - valid = true; - } - } - } + // Get the path and get the copied amount, not including null terminator + UINT copied = DragQueryFileW(drop, i, path, ARR_COUNT(path)); - if (valid) { - DEBUG_PRINTF("Using output path: %s\n", outputPath); - snprintf(appState->outputFolder, ARR_COUNT(appState->outputFolder), - outputPath); - } else { - DEBUG_PRINTF("Invalid output path: %s\n", outputPath); - } - } - } else { - DEBUG_PRINTF("Invalid output path length: %d\n", len); + DEBUG_PRINTF("Required: %u, copied %u (both not including null terminator)\n", required, + copied); + + // required > copied would work as well + if (required >= ARR_COUNT(path)) { + DEBUG_PRINTF("Path was truncated, didn't add job! Max length: %d\nPath would have " + "been %s\n", + MAX_PATH_COUNT, path); + // TODO: show error for user for discarded files, or no? It's quite self-evident + // what is happening + continue; } - } - while (*p && *p != '\n') { - ++p; + ASSERT(gAppState); + AddJob(gAppState, path); } - } - CloseHandle(file); + DragFinish(drop); + return 0; + } break; - // Having no output path is NOT considered a failure - // We just use the default User/Documents/EasyCompressor - if (appState->outputFolder[0] == '\0') { - wchar outputFolder[MAX_PATH_COUNT]; - if (!SUCCEEDED(SHGetFolderPathW(hWnd, CSIDL_MYDOCUMENTS, nullptr, 0, outputFolder))) { - DEBUG_PRINT("Couldn't get user documents folder, using exe dir as working dir...\n"); - // Use exe dir as working dir... - snprintf(appState->outputFolder, ARR_COUNT(appState->outputFolder), "%s", - appState->exeDir); - } else { - DEBUG_PRINTF("Found documents %ls\n", outputFolder); - swprintf(outputFolder, ARR_COUNT(outputFolder), L"%ls\\EasyCompressor", outputFolder); - // It's okay to fail silently - BOOL created = CreateDirectoryW(outputFolder, nullptr); - UTF16To8(outputFolder, appState->outputFolder); - if (!created) { - DWORD err = GetLastError(); - if (err != ERROR_ALREADY_EXISTS) { - // This shouldn't ever happen though - INVALID_CODE_PATH; - DEBUG_PRINTF("SHGetFolderPathA returned %s but couldn't create the directory " - "there. Using exe dir...\n"); - snprintf(appState->outputFolder, ARR_COUNT(appState->outputFolder), "%s", - appState->exeDir); - } - } + case WM_SIZE: { + if (gDevice && wParam != SIZE_MINIMIZED) { + CleanupRenderTarget(); + gSwap->ResizeBuffers(0, LOWORD(lParam), HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0); + CreateRenderTarget(); } - } - - // I guess this for now as the default - //appState->useOutputFolder = true; - // Having no codecs is NOT considered a failure - // Having no default codec is also NOT considered a failure - // This is just for the simplicity and differs heavily from the logic of target sizes - // Simply: if we don't have the default set via "!", we assign a default - // TODO: maybe revise the logic here, see above - if (appState->defaultCodec == Codec::NONE) { - DEBUG_PRINT("No codec specified, assigning default!\n"); - appState->defaultCodec = Codec::H264; - } + return 0; + } break; - // User added some sizes but not the full amount - // We consider having 0 target sizes a failure - if (sizesParsed > 0 && sizesParsed < sizesCount) { - DEBUG_PRINTF("Parsed %d out of %d, meaning SUCCESS\n", sizesParsed, sizesCount); - if (!foundDefaultForSize) { - // Set the first user-supplied size as the default - f32 defaultSize = appState->targetSizes[0]; - DEBUG_PRINTF("Didn't find default, setting it to %.2f\n", defaultSize, 0); - appState->defaultTargetSize = defaultSize; - } + case WM_DESTROY: { + PostQuitMessage(0); + return 0; + } break; - sizesParsed = sizesCount; + default: { + } break; } - bool32 success = sizesParsed == sizesCount; - return success; + return DefWindowProcW(hWnd, msg, wParam, lParam); } int WINAPI @@ -2254,14 +2261,14 @@ WinMain(HINSTANCE hInstance, HINSTANCE /*unused*/, LPSTR /*unused*/, int /*unuse // | DEV | DEBUG char windowName[ARR_COUNT(COMPRESSOR_NAME) + 6 + 8]; snprintf(windowName, ARR_COUNT(windowName), COMPRESSOR_NAME); -#if COMPRESSOR_DEV +# if COMPRESSOR_DEV snprintf(windowName, ARR_COUNT(windowName), "%s | DEV", windowName); //windowName += L" | DEV"; -#endif -#if COMPRESSOR_DEBUG +# endif +# if COMPRESSOR_DEBUG snprintf(windowName, ARR_COUNT(windowName), "%s | DEBUG", windowName); //windowName += L" | DEBUG"; -#endif +# endif wchar windowNameW[ARR_COUNT(windowName)]; UTF8To16(windowName, windowNameW); @@ -2336,15 +2343,15 @@ WinMain(HINSTANCE hInstance, HINSTANCE /*unused*/, LPSTR /*unused*/, int /*unuse /// Font { -#if 1 +# if 1 char buff[MAX_PATH_COUNT + 64]; // This should show basically all Unicode characters snprintf(buff, ARR_COUNT(buff), "%s\\vendor\\NotoSans-Regular.ttf", appState.exeDir); io.Fonts->AddFontFromFileTTF(buff, 18.0f, nullptr, io.Fonts->GetGlyphRangesDefault()); -#else +# else io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\segoeui.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesDefault()); -#endif +# endif } //GetFFMpegPath(&pathInfo); TODO? @@ -2437,7 +2444,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE /*unused*/, LPSTR /*unused*/, int /*unuse appState.workerThread = workerThread; // Test data -#if COMPRESSOR_DEV +# if COMPRESSOR_DEV DEBUG_PRINT("Adding test files at startup...\n"); wchar testPath1[MAX_PATH_COUNT]; @@ -2454,7 +2461,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE /*unused*/, LPSTR /*unused*/, int /*unuse AddJob(&appState, testPath1); AddJob(&appState, testPath2); AddJob(&appState, testPath3); -#endif +# endif /// Performance statistics LARGE_INTEGER freqCounter; @@ -2599,13 +2606,13 @@ WinMain(HINSTANCE hInstance, HINSTANCE /*unused*/, LPSTR /*unused*/, int /*unuse gSwap->Present(1, 0); // (1, 0) -> vsync, otherwise we hog the cpu quite a lot auto presentEnd = GetWallClock(); f32 presentMs = GetMsElapsed(presentStart, presentEnd); -#if 0 +# if 0 PRINTF("frame work: %.5f (avg: %.5f) ms | msg: %.5f ms | ui: %.5f ms | render: " "%.5f ms | present: %.5f ms\nFPS: %.0f | cycles: %.4f M\n", frameWorkMs, frameWorkAvgMs, msgMs, uiMs, renderMs, presentMs, fps, cycleElapsedM); -#else +# else (void)(msgMs, uiMs, renderMs, presentMs, fps, cycleElapsedM); -#endif +# endif } ImGui_ImplDX11_Shutdown(); @@ -2617,3 +2624,5 @@ WinMain(HINSTANCE hInstance, HINSTANCE /*unused*/, LPSTR /*unused*/, int /*unuse UnregisterClassW(windowClass.lpszClassName, windowClass.hInstance); return 0; } + +#endif From 7ca83c7f3250cf4448f8f7cd0ff9fbee83f3f6c1 Mon Sep 17 00:00:00 2001 From: Juuso Piippo Date: Mon, 25 May 2026 02:11:29 +0300 Subject: [PATCH 2/8] Refactor AddJob and add tests for conversions and more Trying out the framework, seems to be quite fast and work well --- build.bat | 3 +- src/compressor.h | 3 ++ src/compressor_tests.cpp | 113 +++++++++++++++++++++++++++++++++++++-- src/win32_compressor.cpp | 26 ++++----- 4 files changed, 126 insertions(+), 19 deletions(-) diff --git a/build.bat b/build.bat index b552310..aeb2afc 100644 --- a/build.bat +++ b/build.bat @@ -93,13 +93,14 @@ if "!argMode!" == "test" ( set flagsCombined=!defines! !flags! cl !flagsCombined! /wd4505 ../src/compressor_tests.cpp /I ../src /I ../vendor ^ - /link /SUBSYSTEM:CONSOLE + /link /SUBSYSTEM:CONSOLE !win32Libraries! set NOW=!TIME:~0,8! if ERRORLEVEL 1 ( echo tests.cpp failed !DATE! !NOW! set buildFailed=1 ) else ( echo Running tests... + rem --success, show all INFO output compressor_tests.exe --no-intro if ERRORLEVEL 1 ( echo Tests failed !DATE! !NOW! diff --git a/src/compressor.h b/src/compressor.h index 7ee19c5..d97e925 100644 --- a/src/compressor.h +++ b/src/compressor.h @@ -70,6 +70,9 @@ StrLengthW(const wchar* str) { return len; } +/** + * Inspects the bytes in order + */ static bool32 StrEqual(const char* a, const char* b) { ASSERT(a && b); diff --git a/src/compressor_tests.cpp b/src/compressor_tests.cpp index 9d6b83c..9aff2e5 100644 --- a/src/compressor_tests.cpp +++ b/src/compressor_tests.cpp @@ -1,14 +1,117 @@ #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN // https://github.com/doctest/doctest/blob/master/doc/markdown/benchmarks.md#cost-of-an-assertion-macro -#define DOCTEST_CONFIG_SUPER_FAST_ASSERTS // Speed!!! +#define DOCTEST_CONFIG_SUPER_FAST_ASSERTS // Speed!!! +#define DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING // For printing the strings out #include "doctest.h" #include "win32_compressor.cpp" -TEST_CASE("Test fail") { - CHECK_EQ(2, 1); - CHECK_EQ(2, 6); +/* +CANDIDATES TO TEST: + - UTF8To16 / UTF16To8 + - ConstructPathsForJob + - AddJob / RemoveJob / MoveJob + - RunProbe / RunCompress + - ParseTimeFromOutput + - StrToF32 + - LoadConfigFile / CreateDefaultConfigFile + - GetExeDirectory +*/ + +struct AppStateFixture { + AppState appState = {}; + + AppStateFixture() { + // Other stuff? + snprintf(appState.outputFolder, ARR_COUNT(appState.outputFolder), "C:\\output"); + } +}; + +TEST_CASE("StrEqual works correctly") { + struct TC { + const char* a; + const char* b; + bool32 exp; + }; + + auto tc = GENERATE(TC{ "first", "first", true }, TC{ "first", "second", false }, + TC{ "", "", true }, TC{ "a", "ab", false }, TC{ "ab", "a", false }); + CHECK_EQ(StrEqual(tc.a, tc.b), tc.exp); +} + +TEST_CASE("UTF8 round trip") { + const char* str = GENERATE( + "Easy Compressor is here!", "äöå", "C:\\Users\\Andy\\Desktop\\test_file – kopöäl.mp4", "", + "ascii only", "mixed äöå and ascii", "∞ ≠ ≤ ≥ ± √ π Σ Δ", "– — “quotes” ‘single’ … • ™ © ®", + "γειά σου κόσμε", "你好世界", "안녕하세요 세계", "مرحبا بالعالم", "שלום עולם", + "😈 👩 🚀 some emojis", "👨‍👩‍👧‍👦 🏳️‍🌈 👍🏻", "☢ ☣ ⚠ ♫ ❤"); + + wchar strW[MAX_PATH_COUNT]; + UTF8To16(str, strW); + char back[MAX_PATH_COUNT]; + UTF16To8(strW, back); + CHECK(StrEqual(str, back)); +} + +TEST_CASE("UTF16 round trip") { + const wchar* strW = GENERATE( + L"Easy Compressor is here!", L"äöå", L"C:\\Users\\Andy\\Desktop\\test_file – kopöäl.mp4", + L"", L"ascii only", L"mixed äöå and ascii", L"∞ ≠ ≤ ≥ ± √ π Σ Δ", + L"– — “quotes” ‘single’ … • ™ © ®", L"γειά σου κόσμε", L"你好世界", L"안녕하세요 세계", + L"مرحبا بالعالم", L"שלום עולם", L"😈 👩 🚀 some emojis", + L"👨‍👩‍👧‍👦 🏳️‍🌈 👍🏻", L"☢ ☣ ⚠ ♫ ❤"); + + char str[MAX_PATH_COUNT]; + UTF16To8(strW, str); + wchar back[MAX_PATH_COUNT]; + UTF8To16(str, back); + char str2[MAX_PATH_COUNT]; + UTF16To8(back, str2); + CHECK(StrEqual(str, str2)); } -TEST_CASE("Test success") { CHECK_EQ(2.5f, 2.5f); } +TEST_CASE_FIXTURE(AppStateFixture, "ConstructPathsForJob works correctly") { + struct TC { + const wchar* input; + const char* exp; + }; + + auto tc = GENERATE(TC{ L"C:\\input\\video.mp4", "C:\\output\\video.mp4" }, + TC{ L"C:\\input\\video äöå.mp4", "C:\\output\\video äöå.mp4" }, + TC{ L"C:\\some\\deep\\path\\video.mp4", "C:\\output\\video.mp4" }, + TC{ L"D:\\input\\no_extension", "C:\\output\\no_extension" }, + TC{ L"C:\\input\\multiple.dots.mp4", "C:\\output\\multiple.dots.mp4" }, + TC{ L"F:\\äöå folder\\video.mp4", "C:\\output\\video.mp4" }, + TC{ L"C:\\input\\video 😈.mp4", "C:\\output\\video 😈.mp4" }, + TC{ L"D:\\input\\фывьн - --.mp4", "C:\\output\\фывьн - --.mp4" }, + TC{ L"K:\\input\\요 세계.hgfh.mp4", "C:\\output\\요 세계.hgfh.mp4" }); + + UIJob j = {}; + ConstructPathsForJob(&appState, &j, tc.input); + + char inputUtf8[MAX_PATH_COUNT]; + UTF16To8(tc.input, inputUtf8); + INFO("input: ", inputUtf8); + INFO("expected: ", tc.exp); + INFO("actual: ", j.output); + CHECK(StrEqual(j.output, tc.exp)); +} + +TEST_CASE_FIXTURE(AppStateFixture, "IsPathFromOutputFolder") { + struct TC { + const wchar* input; + bool32 exp; + }; + + auto tc = GENERATE( + TC{ L"C:\\output\\video.mp4", true }, TC{ L"C:\\output\\subfolder\\video.mp4", false }, + TC{ L"C:\\other\\video.avi", false }, TC{ L"C:\\output äöå\\video.mkv", false }, + TC{ L"C:\\other\\", false }, TC{ L"C:\\output\\", true }, TC{ L"C:\\output", false }); + + char inputUtf8[MAX_PATH_COUNT]; + UTF16To8(tc.input, inputUtf8); + INFO("input: ", inputUtf8); + INFO("expected: ", tc.exp); + CHECK_EQ(IsPathFromOutputFolder(&appState, tc.input), tc.exp); +} diff --git a/src/win32_compressor.cpp b/src/win32_compressor.cpp index ebd94bd..fef3ce4 100644 --- a/src/win32_compressor.cpp +++ b/src/win32_compressor.cpp @@ -260,6 +260,17 @@ SetPopupError(AppState* appState, const char* error) { snprintf(uiState->errorMsg, ARR_COUNT(uiState->errorMsg), "%s", error); } +static bool32 +IsPathFromOutputFolder(AppState* appState, const wchar* path) { + wchar pathW[MAX_PATH_COUNT]; + CopyMemory(pathW, path, sizeof(pathW)); + // This removes the file or a folder, so any last "element" of the path + PathCchRemoveFileSpec(pathW, ARR_COUNT(pathW)); + char copy[MAX_PATH_COUNT]; + UTF16To8(pathW, copy); + return StrEqual(copy, appState->outputFolder); +} + static void AddJob(AppState* appState, const wchar* path) { if (appState->jobCount >= MAX_JOBS) { @@ -270,19 +281,8 @@ AddJob(AppState* appState, const wchar* path) { // Reject inputs from default output folder to avoid name conflicts // TODO: Other approaches? - // TODO: consider writing tests for this and ConstructPathsForJob - // Would make testing different unicode strings easier - - wchar pathW[MAX_PATH_COUNT]; - CopyMemory(pathW, path, sizeof(pathW)); - // We can assume the path always ends with a filename - // This function also removes a folder name if its the last "element" in the path - PathCchRemoveFileSpec(pathW, ARR_COUNT(pathW)); - - char copy[MAX_PATH_COUNT]; - UTF16To8(pathW, copy); - if (StrEqual(copy, appState->outputFolder)) { - DEBUG_PRINTF("Tried to input from default output folder %s\n", copy); + if (IsPathFromOutputFolder(appState, path)) { + DEBUG_PRINTF("Tried to input from default output folder\n"); SetPopupError(appState, "Don't input files from the output folder!\n" "This is to avoid name conflicts"); return; From 2a0e7550d5fe6a3cf46c48722fd59b6a74fcce40 Mon Sep 17 00:00:00 2001 From: Juuso Piippo Date: Mon, 25 May 2026 17:45:22 +0300 Subject: [PATCH 3/8] Tests for AddJob using temp files --- build.bat | 1 + src/compressor_tests.cpp | 102 +++++++++++++++++++++++++++++++++++---- src/win32_compressor.cpp | 10 ++-- 3 files changed, 100 insertions(+), 13 deletions(-) diff --git a/build.bat b/build.bat index aeb2afc..50c96a1 100644 --- a/build.bat +++ b/build.bat @@ -19,6 +19,7 @@ rem /FAs /Fm, .asm and .map rem /LTCG link time optimization, not really used for unity builds I suppose rem not used: /Zc:__cplusplus +rem remove debug from release set defines=-DCOMPRESSOR_WIN32=1 -DCOMPRESSOR_DEBUG=1 set flags=/W4 /FC /Oi /EHa- /GR- /GS /std:c++20 /utf-8 /nologo diff --git a/src/compressor_tests.cpp b/src/compressor_tests.cpp index 9aff2e5..67c86ac 100644 --- a/src/compressor_tests.cpp +++ b/src/compressor_tests.cpp @@ -1,8 +1,9 @@ #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN // https://github.com/doctest/doctest/blob/master/doc/markdown/benchmarks.md#cost-of-an-assertion-macro -#define DOCTEST_CONFIG_SUPER_FAST_ASSERTS // Speed!!! -#define DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING // For printing the strings out +#define DOCTEST_CONFIG_SUPER_FAST_ASSERTS // Speed!!! +#define DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING // For printing the strings out +#define DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS // To use: REQUIRE #include "doctest.h" #include "win32_compressor.cpp" @@ -55,12 +56,12 @@ TEST_CASE("UTF8 round trip") { } TEST_CASE("UTF16 round trip") { - const wchar* strW = GENERATE( - L"Easy Compressor is here!", L"äöå", L"C:\\Users\\Andy\\Desktop\\test_file – kopöäl.mp4", - L"", L"ascii only", L"mixed äöå and ascii", L"∞ ≠ ≤ ≥ ± √ π Σ Δ", - L"– — “quotes” ‘single’ … • ™ © ®", L"γειά σου κόσμε", L"你好世界", L"안녕하세요 세계", - L"مرحبا بالعالم", L"שלום עולם", L"😈 👩 🚀 some emojis", - L"👨‍👩‍👧‍👦 🏳️‍🌈 👍🏻", L"☢ ☣ ⚠ ♫ ❤"); + const wchar* strW = + GENERATE(L"Easy Compr!", L"äöå", L"C:\\Users\\Andy\\Desktop\\test_file – kopöäl.mp4", L"", + L"ascii only", L"mixed äöå and ascii", L"∞ ≠ ≤ ≥ ± √ π Σ Δ", + L"– — “quotes” ‘single’ … • ™ © ®", L"γειά σου κόσμε", L"你好世界", + L"안녕하세요 세계", L"مرحبا بالعالم", L"שלום עולם", L"😈 👩 🚀 some emojis", + L"👨‍👩‍👧‍👦 🏳️‍🌈 👍🏻", L"☢ ☣ ⚠ ♫ ❤"); char str[MAX_PATH_COUNT]; UTF16To8(strW, str); @@ -98,7 +99,7 @@ TEST_CASE_FIXTURE(AppStateFixture, "ConstructPathsForJob works correctly") { CHECK(StrEqual(j.output, tc.exp)); } -TEST_CASE_FIXTURE(AppStateFixture, "IsPathFromOutputFolder") { +TEST_CASE_FIXTURE(AppStateFixture, "IsPathFromOutputFolder works correctly") { struct TC { const wchar* input; bool32 exp; @@ -115,3 +116,86 @@ TEST_CASE_FIXTURE(AppStateFixture, "IsPathFromOutputFolder") { INFO("expected: ", tc.exp); CHECK_EQ(IsPathFromOutputFolder(&appState, tc.input), tc.exp); } + +// Temp file for AddJob +struct TempFileFixture { + // TODO: test paths greater than MAX_PATH: 260 and current MAX_PATH_COUNT + wchar dir[MAX_PATH_COUNT]; + wchar path[MAX_PATH_COUNT]; + + TempFileFixture() { + i32 val = GetTempPathW(ARR_COUNT(dir), dir); + REQUIRE(val != 0); + dir[val - 1] = '\0'; // Remove trailing slash... + //CreateDirectoryW(dir, nullptr); + + swprintf(path, ARR_COUNT(path), L"%ls\\test_file.mp4", dir); + HANDLE file = CreateFileW(path, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, nullptr); + REQUIRE(file != INVALID_HANDLE_VALUE); + + char data[4096] = {}; + DWORD written = 0; + + BOOL ok = WriteFile(file, data, sizeof(data), &written, nullptr); + REQUIRE(ok); + REQUIRE(written == ARR_COUNT(data)); + CloseHandle(file); + } + + ~TempFileFixture() { + DeleteFileW(path); + //RemoveDirectoryW(dir); + } +}; + +struct AddJobFixture : AppStateFixture, TempFileFixture {}; + +TEST_CASE_FIXTURE(AddJobFixture, "AddJob reads file size") { + CAPTURE(appState); + bool32 ok = AddJob(&appState, path); + CHECK(ok); + CHECK(appState.jobCount == 1); + CHECK(appState.jobs[0].inputFileSize > 0.0f); +} + +TEST_CASE_FIXTURE(AddJobFixture, "AddJob fails at MAX_JOBS") { + appState.jobCount = MAX_JOBS; + bool32 ok = AddJob(&appState, path); + CHECK(!ok); + CHECK(appState.jobCount == MAX_JOBS); +} + +TEST_CASE_FIXTURE(AddJobFixture, "AddJob succeeds at MAX_JOBS - 1") { + appState.jobCount = MAX_JOBS - 1; + bool32 ok = AddJob(&appState, path); + CHECK(ok); + CHECK(appState.jobCount == MAX_JOBS); +} + +TEST_CASE_FIXTURE(AddJobFixture, "AddJob increments job list correctly") { + CHECK(AddJob(&appState, path)); + CHECK(AddJob(&appState, path)); + CHECK(AddJob(&appState, path)); + + CHECK(appState.jobCount == 3); + + CHECK(appState.jobs[0].status == JobStatus::QUEUED); + CHECK(appState.jobs[1].status == JobStatus::QUEUED); + CHECK(appState.jobs[2].status == JobStatus::QUEUED); +} + +TEST_CASE_FIXTURE(AddJobFixture, "AddJob rejects input from output folder") { + char pathUtf8[MAX_PATH_COUNT]; + char dirUtf8[MAX_PATH_COUNT]; + UTF16To8(path, pathUtf8); + UTF16To8(dir, dirUtf8); + INFO(pathUtf8); + + snprintf(appState.outputFolder, ARR_COUNT(appState.outputFolder), "%s", dirUtf8); + INFO(appState.outputFolder); + + bool32 ok = AddJob(&appState, path); + CHECK(!ok); + CHECK(appState.jobCount == 0); +} diff --git a/src/win32_compressor.cpp b/src/win32_compressor.cpp index fef3ce4..d7ecee1 100644 --- a/src/win32_compressor.cpp +++ b/src/win32_compressor.cpp @@ -271,11 +271,11 @@ IsPathFromOutputFolder(AppState* appState, const wchar* path) { return StrEqual(copy, appState->outputFolder); } -static void +static bool32 AddJob(AppState* appState, const wchar* path) { if (appState->jobCount >= MAX_JOBS) { DEBUG_PRINT("Jobs full!\n"); - return; + return false; } // Reject inputs from default output folder to avoid name conflicts @@ -285,7 +285,7 @@ AddJob(AppState* appState, const wchar* path) { DEBUG_PRINTF("Tried to input from default output folder\n"); SetPopupError(appState, "Don't input files from the output folder!\n" "This is to avoid name conflicts"); - return; + return false; } UIJob* j = &appState->jobs[appState->jobCount]; @@ -302,12 +302,14 @@ AddJob(AppState* appState, const wchar* path) { j->inputFileSize = static_cast(bytes) / (1024.0f * 1024.0f); } else { DEBUG_PRINT("Failed to get file size!\n"); + INVALID_CODE_PATH; } // Publish the new job at the end _InterlockedIncrement(&appState->jobCount); DEBUG_PRINTF("Added job: index = %d, input = %s,\ntarget size = %.2f MB, output = %s\n", appState->jobCount - 1, j->input, j->targetSizeMb, j->output); + return true; } static void @@ -1116,7 +1118,7 @@ PickInputFiles(HINSTANCE hInstance, HWND hWnd, AppState* appState) { // Multiple files while (*file) { wchar fullW[MAX_PATH_COUNT]; - swprintf(fullW, ARR_COUNT(fullW), L"%s\\%s", dir, file); + swprintf(fullW, ARR_COUNT(fullW), L"%ls\\%ls", dir, file); AddJob(appState, fullW); file += StrLengthW(file) + 1; } From 0d9068ef55119756bb3205ee552b5882e580c6ed Mon Sep 17 00:00:00 2001 From: Juuso Piippo Date: Mon, 25 May 2026 18:13:31 +0300 Subject: [PATCH 4/8] Always include shellapi.h --- src/compressor_tests.cpp | 18 ++++++++++-------- src/win32_compressor.cpp | 5 +++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/compressor_tests.cpp b/src/compressor_tests.cpp index 67c86ac..cec2b49 100644 --- a/src/compressor_tests.cpp +++ b/src/compressor_tests.cpp @@ -174,15 +174,17 @@ TEST_CASE_FIXTURE(AddJobFixture, "AddJob succeeds at MAX_JOBS - 1") { } TEST_CASE_FIXTURE(AddJobFixture, "AddJob increments job list correctly") { - CHECK(AddJob(&appState, path)); - CHECK(AddJob(&appState, path)); - CHECK(AddJob(&appState, path)); - - CHECK(appState.jobCount == 3); + // TODO: this fails if we start to reject duplicate input + i32 count = 3; + REQUIRE(count < MAX_JOBS); + for (i32 i = 0; i < count; ++i) { + CHECK(AddJob(&appState, path)); + } - CHECK(appState.jobs[0].status == JobStatus::QUEUED); - CHECK(appState.jobs[1].status == JobStatus::QUEUED); - CHECK(appState.jobs[2].status == JobStatus::QUEUED); + CHECK(appState.jobCount == count); + for (i32 i = 0; i < count; ++i) { + CHECK(appState.jobs[i].status == JobStatus::QUEUED); + } } TEST_CASE_FIXTURE(AddJobFixture, "AddJob rejects input from output folder") { diff --git a/src/win32_compressor.cpp b/src/win32_compressor.cpp index d7ecee1..eb32d4f 100644 --- a/src/win32_compressor.cpp +++ b/src/win32_compressor.cpp @@ -26,6 +26,7 @@ # include // CommDlg errors # include // OFN, GetSaveFileNameW # include // PathCchRemoveFileSpec +# include // DragQueryFileW, ShellExecuteW etc. # include // SHGetFolderPathW, SHBrowseForFolderW # include // PathFileExistsW @@ -56,8 +57,6 @@ //#include "backends/imgui_impl_dx11.h" //#include "backends/imgui_impl_win32.h" //#include "imgui.h" -#else -# include #endif #include "compressor.h" @@ -278,6 +277,8 @@ AddJob(AppState* appState, const wchar* path) { return false; } + // TODO: reject duplicate files? + // Reject inputs from default output folder to avoid name conflicts // TODO: Other approaches? From 42ecd79edb084af993952c44e6273a7132662e80 Mon Sep 17 00:00:00 2001 From: Juuso Piippo Date: Mon, 25 May 2026 19:28:56 +0300 Subject: [PATCH 5/8] Add CI workflow, commit doctest.h to repo Better build.bat script to have a test-only argument option. This iwll only build and run the tests. CI workflow file for Github Actions to run the build script with test-only --- .github/workflows/main.yml | 25 + .gitignore | 6 +- build.bat | 105 +- vendor/DOCTEST_LICENSE | 21 + vendor/NotoSans-Regular.ttf | Bin 0 -> 629024 bytes vendor/doctest.h | 9119 +++++++++++++++++++++++++++++++++++ 6 files changed, 9241 insertions(+), 35 deletions(-) create mode 100644 .github/workflows/main.yml create mode 100644 vendor/DOCTEST_LICENSE create mode 100644 vendor/NotoSans-Regular.ttf create mode 100644 vendor/doctest.h diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..3e4f8c1 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,25 @@ +# To run locally: +# act -P windows-latest=-self-hosted +# Worked fine + +name: Run tests + +on: + push: + pull_request: + +jobs: + build-and-test: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v6 + + - name: Setup MSVC + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + + - name: Build and run only tests + shell: cmd + run: build.bat test-only diff --git a/.gitignore b/.gitignore index 5ff9034..65b3502 100644 --- a/.gitignore +++ b/.gitignore @@ -58,7 +58,11 @@ dkms.conf build/ # Vendor -vendor/ +vendor/* +# include doctest and font +!vendor/doctest.h +!vendor/DOCTEST_LICENSE +!vendor/NotoSans-Regular.ttf # ffmpeg logs *.log diff --git a/build.bat b/build.bat index 50c96a1..9114e32 100644 --- a/build.bat +++ b/build.bat @@ -4,16 +4,53 @@ setlocal enabledelayedexpansion IF not EXIST build mkdir build pushd build -set argConfig=%1 -set config=debug +set arg1=%1 +set arg2=%2 -if "!argConfig!" == "rel" ( +set config=debug +set modeApp=1 +set modeTest=0 + +rem default modeApp: 1 modeTest: 0 +rem build test: modeApp: 1 modeTest: 1 +rem test-only: modeApp: 0 modeTest: 1 + +rem build -> debug build +rem build rel -> release build +rem build test -> debug build and run debug test +rem build rel test -> rel build and run rel test +rem build test-only -> run debug test +rem build rel test-only -> run rel test +rem "rel" can be replaced with "release" anytime + +if "!arg1!" == "rel" ( + set config=release +) else if "!arg1!" == "release" ( set config=release -) else if "!argConfig!" == "release" ( +) else if "!arg2!" == "rel" ( + set config=release +) else if "!arg2!" == "release" ( set config=release ) +if "!arg1!" == "test" ( + set modeTest=1 +) else if "!arg2!" == "test" ( + set modeTest=1 +) + +rem test-only overrides everything +if "!arg1!" == "test-only" ( + set modeApp=0 + set modeTest=1 +) else if "!arg2!" == "test-only" ( + set modeApp=0 + set modeTest=1 +) + echo Config: !config! +echo App: !modeApp! +echo Test: !modeTest! rem /FAs /Fm, .asm and .map rem /LTCG link time optimization, not really used for unity builds I suppose @@ -37,8 +74,6 @@ if !config! == debug ( set flags=!flags! /MD /Od ) -echo !defines! -echo !flags! set flagsCombined=!defines! !flags! rem TODO: take a look at /FIXED @@ -52,41 +87,34 @@ set dxLibraries=d3d11.lib dxgi.lib d3dcompiler.lib set buildFailed=0 -if exist *.pdb del /q win32_compressor.pdb - -cl !flagsCombined! ../src/win32_compressor.cpp /I ../src /I ../vendor/imgui ^ -/link !linkerFlags! !win32Libraries! !dxLibraries! +if !modeApp! == 1 ( + if exist *.pdb del /q win32_compressor.pdb -if ERRORLEVEL 1 ( - set buildFailed=1 - echo win32_compressor.cpp failed -) - -popd + echo !defines! + echo !flags! -rem Don't remember the layout when testing UX -IF EXIST imgui.ini del imgui.ini + cl !flagsCombined! ../src/win32_compressor.cpp /I ../src /I ../vendor/imgui ^ + /link !linkerFlags! !win32Libraries! !dxLibraries! -set NOW=!TIME:~0,8! + if ERRORLEVEL 1 ( + set buildFailed=1 + echo win32_compressor.cpp failed + ) -echo. -if !buildFailed! NEQ 0 ( - echo Build failed !DATE! !NOW! -) else ( - echo Build succeeded !DATE! !NOW! -) -echo. + rem Don't remember the layout when testing UX + IF EXIST imgui.ini del imgui.ini -pushd build + set NOW=!TIME:~0,8! -rem Tests -if "!config!" == "debug" ( - set argMode=%1 -) else ( - set argMode=%2 + echo. + if !buildFailed! NEQ 0 ( + echo Build failed !DATE! !NOW! + ) else ( + echo Build succeeded !DATE! !NOW! + ) ) -if "!argMode!" == "test" ( +if !modeTest! == 1 ( echo Building tests... set defines=!defines! -DCOMPRESSOR_TESTS=1 echo !defines! @@ -104,8 +132,8 @@ if "!argMode!" == "test" ( rem --success, show all INFO output compressor_tests.exe --no-intro if ERRORLEVEL 1 ( - echo Tests failed !DATE! !NOW! set buildFailed=1 + echo Tests failed !DATE! !NOW! ) else ( echo Tests passed !DATE! !NOW! ) @@ -113,3 +141,12 @@ if "!argMode!" == "test" ( ) popd + +echo. +if !buildFailed! NEQ 0 ( + echo BUILD FAILED + exit /b 1 +) else ( + echo BUILD SUCCESS + exit /b 0 +) diff --git a/vendor/DOCTEST_LICENSE b/vendor/DOCTEST_LICENSE new file mode 100644 index 0000000..5ae0eb1 --- /dev/null +++ b/vendor/DOCTEST_LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016-2023 Viktor Kirilov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/NotoSans-Regular.ttf b/vendor/NotoSans-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4bac02f2f46dcbf78fe25be1992785d749ae3bf5 GIT binary patch literal 629024 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⪻QChR<{9 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

{<*E@vFTHKDk&X_bvAIEL1Dmb4h#H<~2AV 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

Sf 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≫OY++Y@xgiK-(B8-+ZK0UstEvly~dFb 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 +// - the Approx() helper class for floating point comparison +// - colors in the console +// - breaking into a debugger +// - signal / SEH handling +// - timer +// - XmlWriter class - thanks to Phil Nash for allowing the direct reuse (AKA copy/paste) +// +// The expression decomposing templates are taken from lest - https://github.com/martinmoene/lest +// which uses the Boost Software License - Version 1.0 +// see here - https://github.com/martinmoene/lest/blob/master/LICENSE.txt +// +// ================================================================================================= +// ================================================================================================= +// ================================================================================================= + +#ifndef DOCTEST_LIBRARY_INCLUDED +#define DOCTEST_LIBRARY_INCLUDED + +// ================================================================================================= +// == VERSION ====================================================================================== +// ================================================================================================= + +#ifndef DOCTEST_PARTS_PUBLIC_VERSION +#define DOCTEST_PARTS_PUBLIC_VERSION + +// NOLINTBEGIN(cppcoreguidelines-macro-to-enum, modernize-macro-to-enum) +#define DOCTEST_VERSION_MAJOR 2 +#define DOCTEST_VERSION_MINOR 5 +#define DOCTEST_VERSION_PATCH 2 +// NOLINTEND(cppcoreguidelines-macro-to-enum, modernize-macro-to-enum) + +// util we need here +#define DOCTEST_TOSTR_IMPL(x) #x +#define DOCTEST_TOSTR(x) DOCTEST_TOSTR_IMPL(x) + +// clang-format off +#define DOCTEST_VERSION_STR \ + DOCTEST_TOSTR(DOCTEST_VERSION_MAJOR) "." \ + DOCTEST_TOSTR(DOCTEST_VERSION_MINOR) "." \ + DOCTEST_TOSTR(DOCTEST_VERSION_PATCH) +// clang-format on + +#define DOCTEST_VERSION (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH) + +#endif // DOCTEST_PARTS_PUBLIC_VERSION +// ================================================================================================= +// == COMPILER VERSION ============================================================================= +// ================================================================================================= + +#ifndef DOCTEST_PARTS_PUBLIC_COMPILER +#define DOCTEST_PARTS_PUBLIC_COMPILER + +// ideas for the version stuff are taken from here: https://github.com/cxxstuff/cxx_detect + +#ifdef _MSC_VER +#define DOCTEST_CPLUSPLUS _MSVC_LANG +#else +#define DOCTEST_CPLUSPLUS __cplusplus +#endif + +#define DOCTEST_COMPILER(MAJOR, MINOR, PATCH) ((MAJOR) * 10000000 + (MINOR) * 100000 + (PATCH)) + +// GCC/Clang and GCC/MSVC are mutually exclusive, but Clang/MSVC are not because of clang-cl... +#if defined(_MSC_VER) && defined(_MSC_FULL_VER) +#if _MSC_VER == _MSC_FULL_VER / 10000 +#define DOCTEST_MSVC DOCTEST_COMPILER(_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 10000) +#else // MSVC +#define DOCTEST_MSVC DOCTEST_COMPILER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000) +#endif // MSVC +#endif // MSVC +#if defined(__clang__) && defined(__clang_minor__) && defined(__clang_patchlevel__) +#define DOCTEST_CLANG DOCTEST_COMPILER(__clang_major__, __clang_minor__, __clang_patchlevel__) +#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && !defined(__INTEL_COMPILER) +#define DOCTEST_GCC DOCTEST_COMPILER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#endif // GCC +#if defined(__INTEL_COMPILER) +#define DOCTEST_ICC DOCTEST_COMPILER(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif // ICC + +#ifndef DOCTEST_MSVC +#define DOCTEST_MSVC 0 +#endif // DOCTEST_MSVC +#ifndef DOCTEST_CLANG +#define DOCTEST_CLANG 0 +#endif // DOCTEST_CLANG +#ifndef DOCTEST_GCC +#define DOCTEST_GCC 0 +#endif // DOCTEST_GCC +#ifndef DOCTEST_ICC +#define DOCTEST_ICC 0 +#endif // DOCTEST_ICC + +#endif // DOCTEST_PARTS_PUBLIC_COMPILER +// ================================================================================================= +// == COMPILER WARNINGS HELPERS ==================================================================== +// ================================================================================================= + +#ifndef DOCTEST_PARTS_PUBLIC_WARNINGS +#define DOCTEST_PARTS_PUBLIC_WARNINGS + + +#if DOCTEST_CLANG && !DOCTEST_ICC +#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) +#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH _Pragma("clang diagnostic push") +#define DOCTEST_CLANG_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(clang diagnostic ignored w) +#define DOCTEST_CLANG_SUPPRESS_WARNING_POP _Pragma("clang diagnostic pop") +#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) \ + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING(w) +#else // DOCTEST_CLANG +#define DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +#define DOCTEST_CLANG_SUPPRESS_WARNING(w) +#define DOCTEST_CLANG_SUPPRESS_WARNING_POP +#define DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) +#endif // DOCTEST_CLANG + +#if DOCTEST_GCC +#define DOCTEST_PRAGMA_TO_STR(x) _Pragma(#x) +#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH _Pragma("GCC diagnostic push") +#define DOCTEST_GCC_SUPPRESS_WARNING(w) DOCTEST_PRAGMA_TO_STR(GCC diagnostic ignored w) +#define DOCTEST_GCC_SUPPRESS_WARNING_POP _Pragma("GCC diagnostic pop") +#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) DOCTEST_GCC_SUPPRESS_WARNING_PUSH DOCTEST_GCC_SUPPRESS_WARNING(w) +#else // DOCTEST_GCC +#define DOCTEST_GCC_SUPPRESS_WARNING_PUSH +#define DOCTEST_GCC_SUPPRESS_WARNING(w) +#define DOCTEST_GCC_SUPPRESS_WARNING_POP +#define DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH(w) +#endif // DOCTEST_GCC + +#if DOCTEST_MSVC +#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH __pragma(warning(push)) +#define DOCTEST_MSVC_SUPPRESS_WARNING(w) __pragma(warning(disable : w)) +#define DOCTEST_MSVC_SUPPRESS_WARNING_POP __pragma(warning(pop)) +#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) DOCTEST_MSVC_SUPPRESS_WARNING_PUSH DOCTEST_MSVC_SUPPRESS_WARNING(w) +#else // DOCTEST_MSVC +#define DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +#define DOCTEST_MSVC_SUPPRESS_WARNING(w) +#define DOCTEST_MSVC_SUPPRESS_WARNING_POP +#define DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) +#endif // DOCTEST_MSVC + +// ================================================================================================= +// == COMPILER WARNINGS ============================================================================ +// ================================================================================================= + +// both the header and the implementation suppress all of these, +// so it only makes sense to aggregate them like so +#define DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH \ + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wunknown-warning-option") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wweak-vtables") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wpadded") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wunsafe-buffer-usage") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-macros") \ + \ + DOCTEST_GCC_SUPPRESS_WARNING_PUSH \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wpragmas") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Weffc++") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-overflow") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-declarations") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wuseless-cast") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wnoexcept") \ + \ + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH \ + /* these 4 also disabled globally via cmake: */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4514) /* unreferenced inline function has been removed */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4571) /* SEH related */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4710) /* function not inlined */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4711) /* function selected for inline expansion*/ \ + /* common ones */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4616) /* invalid compiler warning */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4619) /* invalid compiler warning */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4996) /* The compiler encountered a deprecated declaration */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4706) /* assignment within conditional expression */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4512) /* 'class' : assignment operator could not be generated */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4127) /* conditional expression is constant */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4820) /* padding */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4625) /* copy constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4626) /* assignment operator was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5027) /* move assignment operator implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5026) /* move constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4640) /* construction of local static object not thread-safe */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5264) /* 'variable-name': 'const' variable is not used */ \ + /* static analysis */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26439) /* Function may not throw. Declare it 'noexcept' */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26495) /* Always initialize a member variable */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26451) /* Arithmetic overflow ... */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26444) /* Avoid unnamed objects with custom ctor and dtor... */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(26812) /* Prefer 'enum class' over 'enum' */ + +#define DOCTEST_SUPPRESS_COMMON_WARNINGS_POP \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP \ + DOCTEST_GCC_SUPPRESS_WARNING_POP \ + DOCTEST_MSVC_SUPPRESS_WARNING_POP + +#define DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH \ + DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH \ + \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wnon-virtual-dtor") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wdeprecated") \ + \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wctor-dtor-privacy") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wnon-virtual-dtor") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-promo") \ + \ + DOCTEST_MSVC_SUPPRESS_WARNING(4623) /* default constructor was implicitly deleted */ + +#define DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP DOCTEST_SUPPRESS_COMMON_WARNINGS_POP + +#define DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH \ + DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH \ + \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wglobal-constructors") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wshorten-64-to-32") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-variable-declarations") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch-enum") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wcovered-switch-default") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-noreturn") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wdisabled-macro-expansion") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-braces") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-field-initializers") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-function") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wnonportable-system-include-path") \ + DOCTEST_CLANG_SUPPRESS_WARNING("-Wnrvo") \ + \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-field-initializers") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wmissing-braces") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-enum") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-default") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wunsafe-loop-optimizations") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wold-style-cast") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wunused-function") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wmultiple-inheritance") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wsuggest-attribute") \ + DOCTEST_GCC_SUPPRESS_WARNING("-Wnrvo") \ + \ + DOCTEST_MSVC_SUPPRESS_WARNING(4267) /* conversion from 'x' to 'y', possible loss of data */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4530) /* exception handler, but unwind semantics not enabled */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4577) /* 'noexcept' with no exception handling mode specified */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4774) /* format string in argument is not a string literal */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4365) /* signed/unsigned mismatch */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5039) /* pointer to pot. throwing function passed to extern C */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4800) /* forcing value to bool (performance warning) */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5245) /* unreferenced function with internal linkage removed */ + +#define DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP DOCTEST_SUPPRESS_COMMON_WARNINGS_POP + +#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN \ + DOCTEST_MSVC_SUPPRESS_WARNING_PUSH \ + DOCTEST_MSVC_SUPPRESS_WARNING(4548) /* before comma no effect; expected side - effect */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4265) /* virtual functions, but destructor is not virtual */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4986) /* exception specification does not match previous */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4350) /* 'member1' called instead of 'member2' */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4668) /* not defined as a preprocessor macro */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4365) /* signed/unsigned mismatch */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4774) /* format string not a string literal */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4820) /* padding */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4625) /* copy constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4626) /* assignment operator was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5027) /* move assignment operator implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5026) /* move constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4623) /* default constructor was implicitly deleted */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5039) /* pointer to pot. throwing function passed to extern C */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5105) /* macro producing 'defined' has undefined behavior */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(4738) /* storing float result in memory, loss of performance */ \ + DOCTEST_MSVC_SUPPRESS_WARNING(5262) /* implicit fall-through */ + +#define DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END DOCTEST_MSVC_SUPPRESS_WARNING_POP + +#endif // DOCTEST_PARTS_PUBLIC_WARNINGS + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +// ================================================================================================= +// == FEATURE DETECTION ============================================================================ +// ================================================================================================= + +#ifndef DOCTEST_PARTS_PUBLIC_CONFIG +#define DOCTEST_PARTS_PUBLIC_CONFIG + +#ifndef DOCTEST_PARTS_PUBLIC_PLATFORM +#define DOCTEST_PARTS_PUBLIC_PLATFORM + +#if defined(__APPLE__) +// Apple detection taken from Catch2 codebase +// For information: +// https://github.com/swiftlang/swift-corelibs-foundation/blob/release/5.10/CoreFoundation/Base.subproj/SwiftRuntime/TargetConditionals.h +#include +#if (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) || (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) +#define DOCTEST_PLATFORM_MAC + +#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1 +#define DOCTEST_PLATFORM_IPHONE +#endif + +#elif defined(WIN32) || defined(_WIN32) +#define DOCTEST_PLATFORM_WINDOWS + +#elif defined(__wasi__) +#define DOCTEST_PLATFORM_WASI + +#else // defined(linux) || defined(__linux) // defined(__linux__) +#define DOCTEST_PLATFORM_LINUX +#endif // DOCTEST_PLATFORM + +#endif // DOCTEST_PARTS_PUBLIC_PLATFORM + +// general compiler feature support table: https://en.cppreference.com/w/cpp/compiler_support +// MSVC C++11 feature support table: https://msdn.microsoft.com/en-us/library/hh567368.aspx +// GCC C++11 feature support table: https://gcc.gnu.org/projects/cxx-status.html +// MSVC version table: +// https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering +// MSVC++ 14.3 (17) _MSC_VER == 1930 (Visual Studio 2022) +// MSVC++ 14.2 (16) _MSC_VER == 1920 (Visual Studio 2019) +// MSVC++ 14.1 (15) _MSC_VER == 1910 (Visual Studio 2017) +// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) +// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) +// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) +// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) +// MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) +// MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) + +// Universal Windows Platform support +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +#define DOCTEST_CONFIG_NO_WINDOWS_SEH +#endif // WINAPI_FAMILY +#if DOCTEST_MSVC && !defined(DOCTEST_CONFIG_WINDOWS_SEH) +#define DOCTEST_CONFIG_WINDOWS_SEH +#endif // MSVC +#if defined(DOCTEST_CONFIG_NO_WINDOWS_SEH) && defined(DOCTEST_CONFIG_WINDOWS_SEH) +#undef DOCTEST_CONFIG_WINDOWS_SEH +#endif // DOCTEST_CONFIG_NO_WINDOWS_SEH + +#if !defined(_WIN32) && !defined(__QNX__) && !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(__EMSCRIPTEN__) && \ + !defined(__wasi__) +#define DOCTEST_CONFIG_POSIX_SIGNALS +#endif // _WIN32 +#if defined(DOCTEST_CONFIG_NO_POSIX_SIGNALS) && defined(DOCTEST_CONFIG_POSIX_SIGNALS) +#undef DOCTEST_CONFIG_POSIX_SIGNALS +#endif // DOCTEST_CONFIG_NO_POSIX_SIGNALS + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS +#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) || defined(__wasi__) +#define DOCTEST_CONFIG_NO_EXCEPTIONS +#endif // no exceptions +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS +#define DOCTEST_CONFIG_NO_EXCEPTIONS +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS + +#if defined(DOCTEST_CONFIG_NO_EXCEPTIONS) && !defined(DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS) +#define DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS && !DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS + +#ifdef __wasi__ +#define DOCTEST_CONFIG_NO_MULTITHREADING +#endif + +#if defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) && !defined(DOCTEST_CONFIG_IMPLEMENT) +#define DOCTEST_CONFIG_IMPLEMENT +#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN + +#if defined(_WIN32) || defined(__CYGWIN__) +#if DOCTEST_MSVC +#define DOCTEST_SYMBOL_EXPORT __declspec(dllexport) +#define DOCTEST_SYMBOL_IMPORT __declspec(dllimport) +#else // MSVC +#define DOCTEST_SYMBOL_EXPORT __attribute__((dllexport)) +#define DOCTEST_SYMBOL_IMPORT __attribute__((dllimport)) +#endif // MSVC +#else // _WIN32 +#define DOCTEST_SYMBOL_EXPORT __attribute__((visibility("default"))) +#define DOCTEST_SYMBOL_IMPORT +#endif // _WIN32 + +#ifdef DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL +#ifdef DOCTEST_CONFIG_IMPLEMENT +#define DOCTEST_INTERFACE DOCTEST_SYMBOL_EXPORT +#else // DOCTEST_CONFIG_IMPLEMENT +#define DOCTEST_INTERFACE DOCTEST_SYMBOL_IMPORT +#endif // DOCTEST_CONFIG_IMPLEMENT +#else // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL +#define DOCTEST_INTERFACE +#endif // DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL + +// needed for extern template instantiations +// see https://github.com/fmtlib/fmt/issues/2228 +#if DOCTEST_MSVC +#define DOCTEST_INTERFACE_DECL +#define DOCTEST_INTERFACE_DEF DOCTEST_INTERFACE +#else // DOCTEST_MSVC +#define DOCTEST_INTERFACE_DECL DOCTEST_INTERFACE +#define DOCTEST_INTERFACE_DEF +#endif // DOCTEST_MSVC + +#define DOCTEST_EMPTY + +#if DOCTEST_MSVC +#define DOCTEST_NOINLINE __declspec(noinline) +#define DOCTEST_UNUSED +#define DOCTEST_ALIGNMENT(x) +#elif DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 5, 0) +#define DOCTEST_NOINLINE +#define DOCTEST_UNUSED +#define DOCTEST_ALIGNMENT(x) +#else +#define DOCTEST_NOINLINE __attribute__((noinline)) +#define DOCTEST_UNUSED __attribute__((unused)) +#define DOCTEST_ALIGNMENT(x) __attribute__((aligned(x))) +#endif + +#ifdef DOCTEST_CONFIG_NO_CONTRADICTING_INLINE +#define DOCTEST_INLINE_NOINLINE inline +#else +#define DOCTEST_INLINE_NOINLINE inline DOCTEST_NOINLINE +#endif + +#ifndef DOCTEST_NORETURN +#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) +#define DOCTEST_NORETURN +#else // DOCTEST_MSVC +#define DOCTEST_NORETURN [[noreturn]] +#endif // DOCTEST_MSVC +#endif // DOCTEST_NORETURN + +#ifndef DOCTEST_NOEXCEPT +#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) +#define DOCTEST_NOEXCEPT +#else // DOCTEST_MSVC +#define DOCTEST_NOEXCEPT noexcept +#endif // DOCTEST_MSVC +#endif // DOCTEST_NOEXCEPT + +#ifndef DOCTEST_CONSTEXPR +#if DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) +#define DOCTEST_CONSTEXPR const +#define DOCTEST_CONSTEXPR_FUNC inline +#else // DOCTEST_MSVC +#define DOCTEST_CONSTEXPR constexpr +#define DOCTEST_CONSTEXPR_FUNC constexpr +#endif // DOCTEST_MSVC +#endif // DOCTEST_CONSTEXPR + +#ifndef DOCTEST_NO_SANITIZE_INTEGER +#if DOCTEST_CLANG >= DOCTEST_COMPILER(3, 7, 0) +#define DOCTEST_NO_SANITIZE_INTEGER __attribute__((no_sanitize("integer"))) +#else +#define DOCTEST_NO_SANITIZE_INTEGER +#endif +#endif // DOCTEST_NO_SANITIZE_INTEGER + +// this is kept here for backwards compatibility since the config option was changed +#ifdef DOCTEST_CONFIG_USE_IOSFWD +#ifndef DOCTEST_CONFIG_USE_STD_HEADERS +#define DOCTEST_CONFIG_USE_STD_HEADERS +#endif +#endif // DOCTEST_CONFIG_USE_IOSFWD + +// for clang - always include or (which drags some std stuff) +// because we want to check if we are using libc++ with the _LIBCPP_VERSION macro in +// which case we don't want to forward declare stuff from std - for reference: +// https://github.com/doctest/doctest/issues/126 +// https://github.com/doctest/doctest/issues/356 +#if DOCTEST_CLANG +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN +#if DOCTEST_CPLUSPLUS >= 201703L && __has_include() +#include +#else +#include +#endif +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END +#endif // clang + +#ifdef _LIBCPP_VERSION +#ifndef DOCTEST_CONFIG_USE_STD_HEADERS +#define DOCTEST_CONFIG_USE_STD_HEADERS +#endif +#endif // _LIBCPP_VERSION + +#ifdef DOCTEST_CONFIG_USE_STD_HEADERS +#ifndef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#define DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#endif // DOCTEST_CONFIG_USE_STD_HEADERS + +#if defined(__has_builtin) +#define DOCTEST_HAS_BUILTIN(x) __has_builtin(x) +#else +#define DOCTEST_HAS_BUILTIN(x) 0 +#endif // __has_builtin + +#endif // DOCTEST_PARTS_PUBLIC_CONFIG + +// ================================================================================================= +// == FEATURE DETECTION END ======================================================================== +// ================================================================================================= +#ifndef DOCTEST_PARTS_PUBLIC_UTILITY +#define DOCTEST_PARTS_PUBLIC_UTILITY + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +#define DOCTEST_DECLARE_INTERFACE(name) \ + virtual ~name(); \ + name() = default; \ + name(const name &) = delete; \ + name(name &&) = delete; \ + name &operator=(const name &) = delete; \ + name &operator=(name &&) = delete; + +#define DOCTEST_DEFINE_INTERFACE(name) name::~name() = default; + +#if !defined(DOCTEST_COUNTER) +#if DOCTEST_CLANG >= DOCTEST_COMPILER(22, 0, 0) +#define DOCTEST_COUNTER __LINE__ +#elif defined(__COUNTER__) +#define DOCTEST_COUNTER __COUNTER__ +#else +#define DOCTEST_COUNTER __LINE__ +#endif +#endif // defined(DOCTEST_COUNTER) + +// internal macros for string concatenation and anonymous variable name generation +#define DOCTEST_CAT_IMPL(s1, s2) s1##s2 +#define DOCTEST_CAT(s1, s2) DOCTEST_CAT_IMPL(s1, s2) +#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, DOCTEST_COUNTER) + +#ifndef DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE +#define DOCTEST_REF_WRAP(x) x & +#else // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE +#define DOCTEST_REF_WRAP(x) x +#endif // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE + +namespace doctest { +namespace detail { +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-function") +static DOCTEST_CONSTEXPR int consume(const int *, int) noexcept { + return 0; +} +DOCTEST_CLANG_SUPPRESS_WARNING_POP +} // namespace detail +} // namespace doctest + +#define DOCTEST_GLOBAL_NO_WARNINGS(var, ...) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") \ + static const int var = doctest::detail::consume(&var, __VA_ARGS__); \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_UTILITY +#ifndef DOCTEST_PARTS_PUBLIC_DEBUGGER +#define DOCTEST_PARTS_PUBLIC_DEBUGGER + + +#ifndef DOCTEST_BREAK_INTO_DEBUGGER + +// should probably take a look at https://github.com/scottt/debugbreak +#if DOCTEST_CLANG && DOCTEST_HAS_BUILTIN(__builtin_debugtrap) +#define DOCTEST_BREAK_INTO_DEBUGGER() __builtin_debugtrap() + +#elif defined(DOCTEST_PLATFORM_LINUX) +#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) +// Break at the location of the failing check if possible +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" ::) // NOLINT(hicpp-no-assembler) +#else +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN +#include +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END +#define DOCTEST_BREAK_INTO_DEBUGGER() raise(SIGTRAP) +#endif + +#elif defined(DOCTEST_PLATFORM_MAC) +#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386) +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" ::) // NOLINT(hicpp-no-assembler) +#elif defined(__ppc__) || defined(__ppc64__) +// https://www.cocoawithlove.com/2008/03/break-into-debugger.html +#define DOCTEST_BREAK_INTO_DEBUGGER() /* NOLINTNEXTLINE(hicpp-no-assembler) */ \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" ::: "memory", "r0", "r3", "r4") +#else +#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("brk #0"); // NOLINT(hicpp-no-assembler) +#endif + +#elif DOCTEST_MSVC +#define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() + +#elif defined(__MINGW32__) +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wredundant-decls") +extern "C" __declspec(dllimport) void __stdcall DebugBreak(); +DOCTEST_GCC_SUPPRESS_WARNING_POP +#define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak() +#else // linux +#define DOCTEST_BREAK_INTO_DEBUGGER() (static_cast(0)) +#endif // linux +#endif // DOCTEST_BREAK_INTO_DEBUGGER + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { +DOCTEST_INTERFACE bool isDebuggerActive(); +} // namespace detail +} // namespace doctest + +#endif + +#endif // DOCTEST_PARTS_PUBLIC_DEBUGGER +#ifndef DOCTEST_PARTS_PUBLIC_STD_FWD +#define DOCTEST_PARTS_PUBLIC_STD_FWD + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +#ifdef DOCTEST_CONFIG_USE_STD_HEADERS +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN +#include +#include +#include +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END +#else // DOCTEST_CONFIG_USE_STD_HEADERS + +// Forward declaring 'X' in namespace std is not permitted by the C++ Standard. +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4643) + +// NOLINTBEGIN(bugprone-std-namespace-modification, cert-dcl58-cpp) +namespace std { +typedef decltype(nullptr) nullptr_t; // NOLINT(modernize-use-using) +typedef decltype(sizeof(void *)) size_t; // NOLINT(modernize-use-using) +template +struct char_traits; +template <> +struct char_traits; +template +class basic_ostream; // NOLINT(fuchsia-virtual-inheritance) +typedef basic_ostream> ostream; // NOLINT(modernize-use-using) +template +// NOLINTNEXTLINE +basic_ostream &operator<<(basic_ostream &, const char *); +template +class basic_istream; +typedef basic_istream> istream; // NOLINT(modernize-use-using) +template +class tuple; +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183 +template +class allocator; +template +class basic_string; +using string = basic_string, allocator>; +#endif // VS 2019 +} // namespace std +// NOLINTEND(bugprone-std-namespace-modification, cert-dcl58-cpp) + +DOCTEST_MSVC_SUPPRESS_WARNING_POP + +#endif // DOCTEST_CONFIG_USE_STD_HEADERS + +namespace doctest { +using std::size_t; +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_STD_FWD +#ifndef DOCTEST_PARTS_PUBLIC_STD_TYPE_TRAITS +#define DOCTEST_PARTS_PUBLIC_STD_TYPE_TRAITS + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN +#include +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + +namespace doctest { +namespace detail { +namespace types { + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +using namespace std; +#else +template +struct enable_if {}; + +template +struct enable_if { + using type = T; +}; + +struct true_type { + static DOCTEST_CONSTEXPR bool value = true; +}; + +struct false_type { + static DOCTEST_CONSTEXPR bool value = false; +}; + +template +struct remove_reference { + using type = T; +}; + +template +struct remove_reference { + using type = T; +}; + +template +struct remove_reference { + using type = T; +}; + +template +struct is_same : false_type {}; + +template +struct is_same : true_type {}; + +template +struct is_rvalue_reference : false_type {}; + +template +struct is_rvalue_reference : true_type {}; + +template +struct remove_const { + using type = T; +}; + +template +struct remove_const { + using type = T; +}; + +// Compiler intrinsics +template +struct is_enum { + static DOCTEST_CONSTEXPR bool value = __is_enum(T); +}; + +template +struct underlying_type { + using type = __underlying_type(T); +}; + +template +struct is_pointer : false_type {}; + +template +struct is_pointer : true_type {}; + +template +struct is_array : false_type {}; +// NOLINTNEXTLINE(*-avoid-c-arrays) +template +struct is_array : true_type {}; +#endif + +#if !(defined(DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS) && (DOCTEST_CPLUSPLUS >= 201703L)) +template +using void_t = void; +#endif + +} // namespace types +} // namespace detail +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_STD_TYPE_TRAITS +#ifndef DOCTEST_PARTS_PUBLIC_STD_UTILITY +#define DOCTEST_PARTS_PUBLIC_STD_UTILITY + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { +namespace detail { + +// +template +T &&declval(); + +template +DOCTEST_CONSTEXPR_FUNC T &&forward(typename types::remove_reference::type &t) DOCTEST_NOEXCEPT { + return static_cast(t); +} + +template +// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) +DOCTEST_CONSTEXPR_FUNC T &&forward(typename types::remove_reference::type &&t) DOCTEST_NOEXCEPT { + return static_cast(t); +} + +template +struct deferred_false : types::false_type {}; + +} // namespace detail +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_STD_UTILITY +#ifndef DOCTEST_PARTS_PUBLIC_STRING +#define DOCTEST_PARTS_PUBLIC_STRING + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { +#ifndef DOCTEST_CONFIG_STRING_SIZE_TYPE +#define DOCTEST_CONFIG_STRING_SIZE_TYPE unsigned +#endif + +namespace detail { + +template +struct is_std_string : types::false_type {}; + +template +struct is_std_string< + T, + typename types::enable_if< + types::is_same().c_str()), const char *>::value && + types::is_same().size()), size_t>::value>::type> : types::true_type {}; + +} // namespace detail + +// A 24 byte string class (can be as small as 17 for x64 and 13 for x86) that can hold strings +// with length of up to 23 chars on the stack before going on the heap - +// the last byte of the buffer is used for: +// - "is small" bit - the highest bit - if "0" then it is small - otherwise its "1" (128) +// - if small - capacity left before going on the heap - using the lowest 5 bits +// - if small - 2 bits are left unused - the second and third highest ones +// - if small - acts as a null terminator if strlen() is 23 (24 including the null terminator) +// and the "is small" bit remains "0" ("as well as the capacity left") so its OK +// Idea taken from this lecture about the string implementation of facebook/folly - fbstring +// https://www.youtube.com/watch?v=kPR8h4-qZdk +// TODO: +// - optimizations - like not deleting memory unnecessarily in operator= and etc. +// - resize/reserve/clear +// - replace +// - back/front +// - iterator stuff +// - find & friends +// - push_back/pop_back +// - assign/insert/erase +// - relational operators as free functions - taking const char* as one of the params +class DOCTEST_INTERFACE String { +public: + using size_type = DOCTEST_CONFIG_STRING_SIZE_TYPE; + +private: + static DOCTEST_CONSTEXPR size_type len = 24; + static DOCTEST_CONSTEXPR size_type last = len - 1; + + struct view // len should be more than sizeof(view) - because of the final byte for flags + { + char *ptr; + size_type size; + size_type capacity; + }; + + union { + char buf[len]; // NOLINT(*-avoid-c-arrays) + view data; + }; + + char *allocate(size_type sz); + + bool isOnStack() const noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) + return (buf[last] & 128) == 0; + } + + void setOnHeap() noexcept; + void setLast(size_type in = last) noexcept; + void setSize(size_type sz) noexcept; + + void copy(const String &other); + +public: + static DOCTEST_CONSTEXPR size_type npos = static_cast(-1); + + String() noexcept; + ~String(); + + String(const char *in); + String(const char *in, size_type in_size); + + String(std::istream &in, size_type in_size); + + template ::value, bool>::type = true> + String(const T &in) + : String(in.c_str(), static_cast(in.size())) {} + + String(const String &other); + String &operator=(const String &other); + + String &operator+=(const String &other); + + String(String &&other) noexcept; + String &operator=(String &&other) noexcept; + + char operator[](size_type i) const; + char &operator[](size_type i); + + // the only functions I'm willing to leave in the interface - available for inlining + const char *c_str() const { + return const_cast(this)->c_str(); // NOLINT + } + + // NOLINTBEGIN(cppcoreguidelines-pro-type-union-access) + char *c_str() { + if (isOnStack()) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + return reinterpret_cast(buf); + } + return data.ptr; + } + // NOLINTEND(cppcoreguidelines-pro-type-union-access) + + size_type size() const; + size_type capacity() const; + + String substr(size_type pos, size_type cnt = npos) &&; + String substr(size_type pos, size_type cnt = npos) const &; + + size_type find(char ch, size_type pos = 0) const; + size_type rfind(char ch, size_type pos = npos) const; + + int compare(const char *other, bool no_case = false) const; + int compare(const String &other, bool no_case = false) const; + + friend DOCTEST_INTERFACE std::ostream &operator<<(std::ostream &s, const String &in); +}; + +DOCTEST_INTERFACE String operator+(const String &lhs, const String &rhs); + +DOCTEST_INTERFACE bool operator==(const String &lhs, const String &rhs); +DOCTEST_INTERFACE bool operator!=(const String &lhs, const String &rhs); +DOCTEST_INTERFACE bool operator<(const String &lhs, const String &rhs); +DOCTEST_INTERFACE bool operator>(const String &lhs, const String &rhs); +DOCTEST_INTERFACE bool operator<=(const String &lhs, const String &rhs); +DOCTEST_INTERFACE bool operator>=(const String &lhs, const String &rhs); + +namespace detail { + +// MSVS 2015 :( +#if !DOCTEST_CLANG && defined(_MSC_VER) && _MSC_VER <= 1900 +template +struct has_global_insertion_operator : types::false_type {}; + +template +struct has_global_insertion_operator(), declval()), void())> + : types::true_type {}; + +template +struct has_insertion_operator { + static DOCTEST_CONSTEXPR bool value = has_global_insertion_operator::value; +}; + +template +struct insert_hack; + +template +struct insert_hack { + static void insert(std::ostream &os, const T &t) { + ::operator<<(os, t); + } +}; + +template +struct insert_hack { + static void insert(std::ostream &os, const T &t) { + operator<<(os, t); + } +}; + +template +using insert_hack_t = insert_hack::value>; +#else +template +struct has_insertion_operator : types::false_type {}; +#endif + +template +struct has_insertion_operator(), declval()), void())> + : types::true_type {}; + +template +struct should_stringify_as_underlying_type { + static DOCTEST_CONSTEXPR bool value = + detail::types::is_enum::value && !doctest::detail::has_insertion_operator::value; +}; + +template +struct is_pair : types::false_type {}; + +template +struct is_pair< + T, + types::void_t< + typename T::first_type, + typename T::second_type, + decltype(declval().first), + decltype(declval().second)>> : types::true_type {}; + +template +struct is_container : types::false_type {}; + +template +struct is_container< + T, + types::void_t< + typename T::value_type, + typename T::iterator, + decltype(declval().begin()), + decltype(declval().end())>> : types::true_type {}; + +DOCTEST_INTERFACE std::ostream *tlssPush(); +DOCTEST_INTERFACE String tlssPop(); + +template +struct StringMakerBase { + template + static String convert(const DOCTEST_REF_WRAP(T)) { +#ifdef DOCTEST_CONFIG_REQUIRE_STRINGIFICATION_FOR_ALL_USED_TYPES + static_assert(deferred_false::value, "No stringification detected for type T. See string conversion manual"); +#endif + return "{?}"; + } +}; + +template +struct filldata; + +template +void filloss(std::ostream *stream, const T &in) { + filldata::fill(stream, in); +} + +template +void filloss(std::ostream *stream, const T (&in)[N]) { // NOLINT(*-avoid-c-arrays) + // T[N], T(&)[N], T(&&)[N] have same behaviour. + // Hence remove reference. + filloss::type>(stream, in); +} + +template +String toStream(const T &in) { + std::ostream *stream = tlssPush(); + filloss(stream, in); + return tlssPop(); +} + +template <> +struct StringMakerBase { + template + static String convert(const DOCTEST_REF_WRAP(T) in) { + return toStream(in); + } +}; + +} // namespace detail + +template +struct StringMaker + : public detail::StringMakerBase< + detail::has_insertion_operator::value || detail::types::is_pointer::value || + detail::types::is_array::value || detail::is_pair::value || detail::is_container::value> {}; + +#ifndef DOCTEST_STRINGIFY +#ifdef DOCTEST_CONFIG_DOUBLE_STRINGIFY +#define DOCTEST_STRINGIFY(...) toString(toString(__VA_ARGS__)) +#else +#define DOCTEST_STRINGIFY(...) toString(__VA_ARGS__) +#endif +#endif + +template +String toString() { +#if DOCTEST_CLANG == 0 && DOCTEST_GCC == 0 && DOCTEST_ICC == 0 + String ret = __FUNCSIG__; // class doctest::String __cdecl doctest::toString(void) + String::size_type beginPos = ret.find('<'); + return ret.substr(beginPos + 1, ret.size() - beginPos - static_cast(sizeof(">(void)"))); +#else + const String ret = __PRETTY_FUNCTION__; // doctest::String toString() [with T = TYPE] + const String::size_type begin = ret.find('=') + 2; + return ret.substr(begin, ret.size() - begin - 1); +#endif // Compiler +} + +template < + typename T, + typename detail::types::enable_if::value, bool>::type = true> +String toString(const DOCTEST_REF_WRAP(T) value) { + return StringMaker::convert(value); +} + +// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) +inline String &&toString(String &&in) { + return static_cast(in); +} + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +DOCTEST_INTERFACE String toString(const char *in); +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183 +DOCTEST_INTERFACE String toString(const std::string &in); +#endif // VS 2019 + +DOCTEST_INTERFACE String toString(const String &in); + +DOCTEST_INTERFACE String toString(std::nullptr_t); + +DOCTEST_INTERFACE String toString(bool in); + +DOCTEST_INTERFACE String toString(float in); +DOCTEST_INTERFACE String toString(double in); +DOCTEST_INTERFACE String toString(double long in); + +DOCTEST_INTERFACE String toString(char in); +DOCTEST_INTERFACE String toString(char signed in); +DOCTEST_INTERFACE String toString(char unsigned in); +DOCTEST_INTERFACE String toString(short in); +DOCTEST_INTERFACE String toString(short unsigned in); +DOCTEST_INTERFACE String toString(signed in); +DOCTEST_INTERFACE String toString(unsigned in); +DOCTEST_INTERFACE String toString(long in); +DOCTEST_INTERFACE String toString(long unsigned in); +DOCTEST_INTERFACE String toString(long long in); +DOCTEST_INTERFACE String toString(long long unsigned in); + +template < + typename T, + typename detail::types::enable_if::value, bool>::type = true> +String toString(const DOCTEST_REF_WRAP(T) value) { + using UT = typename detail::types::underlying_type::type; + return (DOCTEST_STRINGIFY(static_cast(value))); +} + +namespace detail { +template +struct filldata { + static void fill(std::ostream *stream, const T &in) { +#if defined(_MSC_VER) && _MSC_VER <= 1900 + insert_hack_t::insert(*stream, in); +#else + operator<<(*stream, in); +#endif // _MSV_VER + } +}; + +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4866) +// NOLINTBEGIN(*-avoid-c-arrays) +template +struct filldata { + static void fill(std::ostream *stream, const T (&in)[N]) { + *stream << "["; + for (size_t i = 0; i < N; i++) { + if (i != 0) { + *stream << ", "; + } + *stream << (DOCTEST_STRINGIFY(in[i])); + } + *stream << "]"; + } +}; +// NOLINTEND(*-avoid-c-arrays) +DOCTEST_MSVC_SUPPRESS_WARNING_POP + +// Specialized since we don't want the terminating null byte! +// NOLINTBEGIN(*-avoid-c-arrays) +template +struct filldata { + static void fill(std::ostream *stream, const char (&in)[N]) { + *stream << String(in, in[N - 1] ? N : N - 1); + } // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) +}; +// NOLINTEND(*-avoid-c-arrays) + +template <> +struct filldata { + DOCTEST_INTERFACE static void fill(std::ostream *stream, const void *in); +}; + +template <> +struct filldata { + DOCTEST_INTERFACE static void fill(std::ostream *stream, const volatile void *in); +}; + +template +struct filldata { + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4180) + static void fill(std::ostream *stream, const T *in) { + DOCTEST_MSVC_SUPPRESS_WARNING_POP + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wmicrosoft-cast") + filldata::fill( + stream, +#if DOCTEST_GCC == 0 || DOCTEST_GCC >= DOCTEST_COMPILER(4, 9, 0) + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + reinterpret_cast(in) +#else + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + *reinterpret_cast(&in) +#endif // DOCTEST_GCC + ); + DOCTEST_CLANG_SUPPRESS_WARNING_POP + } +}; + +template +struct filldata< + T, + typename detail::types::enable_if::value && detail::is_pair::value>::type> { + static void fill(std::ostream *stream, const T &in) { + *stream << "{" << DOCTEST_STRINGIFY(in.first) << ", " << DOCTEST_STRINGIFY(in.second) << "}"; + } +}; + +template +struct filldata< + T, + typename detail::types::enable_if< + !detail::has_insertion_operator::value && detail::is_container::value>::type> { + static void fill(std::ostream *stream, const DOCTEST_REF_WRAP(T) in) { + *stream << "{"; + for (auto it = in.begin(); it != in.end(); ++it) { + if (it != in.begin()) { + *stream << ", "; + } + *stream << DOCTEST_STRINGIFY(*it); + } + *stream << "}"; + } +}; + +#ifndef DOCTEST_CONFIG_DISABLE +template +String stringifyBinaryExpr(const DOCTEST_REF_WRAP(L) lhs, const char *op, const DOCTEST_REF_WRAP(R) rhs) { + return (DOCTEST_STRINGIFY(lhs)) + op + (DOCTEST_STRINGIFY(rhs)); +} +#endif // DOCTEST_CONFIG_DISABLE +} // namespace detail + +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_STRING +#ifndef DOCTEST_PARTS_PUBLIC_MATCHERS_CONTAINS +#define DOCTEST_PARTS_PUBLIC_MATCHERS_CONTAINS + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { + +class DOCTEST_INTERFACE Contains { +public: + explicit Contains(const String &string); + + bool checkWith(const String &other) const; + + String string; +}; + +DOCTEST_INTERFACE String toString(const Contains &in); + +DOCTEST_INTERFACE bool operator==(const String &lhs, const Contains &rhs); +DOCTEST_INTERFACE bool operator==(const Contains &lhs, const String &rhs); +DOCTEST_INTERFACE bool operator!=(const String &lhs, const Contains &rhs); +DOCTEST_INTERFACE bool operator!=(const Contains &lhs, const String &rhs); + +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_MATCHERS_CONTAINS +#ifndef DOCTEST_PARTS_PUBLIC_MATCHERS_APPROX +#define DOCTEST_PARTS_PUBLIC_MATCHERS_APPROX + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { + +struct DOCTEST_INTERFACE Approx { + Approx(double value); + + Approx operator()(double value) const; + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + explicit Approx( + const T &value, + typename detail::types::enable_if::value>::type * = static_cast(nullptr) + ) { + *this = static_cast(value); + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + Approx &epsilon(double newEpsilon); + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + typename std::enable_if::value, Approx &>::type epsilon(const T &newEpsilon) { + m_epsilon = static_cast(newEpsilon); + return *this; + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + Approx &scale(double newScale); + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + template + typename std::enable_if::value, Approx &>::type scale(const T &newScale) { + m_scale = static_cast(newScale); + return *this; + } +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + // clang-format off + DOCTEST_INTERFACE friend bool operator==(double lhs, const Approx &rhs); + DOCTEST_INTERFACE friend bool operator==(const Approx &lhs, double rhs); + DOCTEST_INTERFACE friend bool operator!=(double lhs, const Approx &rhs); + DOCTEST_INTERFACE friend bool operator!=(const Approx &lhs, double rhs); + DOCTEST_INTERFACE friend bool operator<=(double lhs, const Approx &rhs); + DOCTEST_INTERFACE friend bool operator<=(const Approx &lhs, double rhs); + DOCTEST_INTERFACE friend bool operator>=(double lhs, const Approx &rhs); + DOCTEST_INTERFACE friend bool operator>=(const Approx &lhs, double rhs); + DOCTEST_INTERFACE friend bool operator< (double lhs, const Approx &rhs); + DOCTEST_INTERFACE friend bool operator< (const Approx &lhs, double rhs); + DOCTEST_INTERFACE friend bool operator> (double lhs, const Approx &rhs); + DOCTEST_INTERFACE friend bool operator> (const Approx &lhs, double rhs); + // clang-format on + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#define DOCTEST_APPROX_PREFIX \ + template \ + friend typename std::enable_if::value, bool>::type + + // clang-format off + DOCTEST_APPROX_PREFIX operator==(const T &lhs, const Approx &rhs) { return operator==(static_cast(lhs), rhs); } + DOCTEST_APPROX_PREFIX operator==(const Approx &lhs, const T &rhs) { return operator==(rhs, lhs); } + DOCTEST_APPROX_PREFIX operator!=(const T &lhs, const Approx &rhs) { return !operator==(lhs, rhs); } + DOCTEST_APPROX_PREFIX operator!=(const Approx &lhs, const T &rhs) { return !operator==(rhs, lhs); } + DOCTEST_APPROX_PREFIX operator<=(const T &lhs, const Approx &rhs) { return static_cast(lhs) < rhs.m_value || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator<=(const Approx &lhs, const T &rhs) { return lhs.m_value < static_cast(rhs) || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator>=(const T &lhs, const Approx &rhs) { return static_cast(lhs) > rhs.m_value || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator>=(const Approx &lhs, const T &rhs) { return lhs.m_value > static_cast(rhs) || lhs == rhs; } + DOCTEST_APPROX_PREFIX operator< (const T &lhs, const Approx &rhs) { return static_cast(lhs) < rhs.m_value && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator< (const Approx &lhs, const T &rhs) { return lhs.m_value < static_cast(rhs) && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator> (const T &lhs, const Approx &rhs) { return static_cast(lhs) > rhs.m_value && lhs != rhs; } + DOCTEST_APPROX_PREFIX operator> (const Approx &lhs, const T &rhs) { return lhs.m_value > static_cast(rhs) && lhs != rhs; } + // clang-format off +#undef DOCTEST_APPROX_PREFIX +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + double m_epsilon; + double m_scale; + double m_value; +}; + +DOCTEST_INTERFACE String toString(const Approx &in); + +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_MATCHERS_APPROX +#ifndef DOCTEST_PARTS_PUBLIC_MATCHERS_IS_NAN +#define DOCTEST_PARTS_PUBLIC_MATCHERS_IS_NAN + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { + +template +struct DOCTEST_INTERFACE_DECL IsNaN { + F value; + bool flipped; + IsNaN(F f, bool flip = false) + : value(f), flipped(flip) {} + + IsNaN operator!() const { + return {value, !flipped}; + } + + operator bool() const; +}; + +#ifndef __MINGW32__ +extern template struct DOCTEST_INTERFACE_DECL IsNaN; +extern template struct DOCTEST_INTERFACE_DECL IsNaN; +extern template struct DOCTEST_INTERFACE_DECL IsNaN; +#endif + +DOCTEST_INTERFACE String toString(IsNaN in); +DOCTEST_INTERFACE String toString(IsNaN in); +DOCTEST_INTERFACE String toString(IsNaN in); + +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_MATCHERS_IS_NAN +#ifndef DOCTEST_PARTS_PUBLIC_CONTEXT_OPTIONS +#define DOCTEST_PARTS_PUBLIC_CONTEXT_OPTIONS + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { +namespace detail { +struct DOCTEST_INTERFACE TestCase; +} // namespace detail + +struct ContextOptions { + std::ostream *cout = nullptr; // stdout stream + String binary_name; // the test binary name + + const detail::TestCase *currentTest = nullptr; + + // == parameters from the command line + String out; // output filename + String order_by; // how tests should be ordered + unsigned rand_seed; // the seed for rand ordering + + unsigned first; // the first (matching) test to be executed + unsigned last; // the last (matching) test to be executed + + int abort_after; // stop tests after this many failed assertions + int subcase_filter_levels; // apply the subcase filters for the first N levels + + bool success; // include successful assertions in output + bool case_sensitive; // if filtering should be case sensitive + bool exit; // if the program should be exited after the tests are ran/whatever + bool duration; // print the time duration of each test case + bool minimal; // minimal console output (only test failures) + bool quiet; // no console output + bool no_throw; // to skip exceptions-related assertion macros + bool no_exitcode; // if the framework should return 0 as the exitcode + bool no_run; // to not run the tests at all (can be done with an "*" exclude) + bool no_intro; // to not print the intro of the framework + bool no_version; // to not print the version of the framework + bool no_colors; // if output to the console should be colorized + bool force_colors; // forces the use of colors even when a tty cannot be detected + bool no_breaks; // to not break into the debugger + bool no_skip; // don't skip test cases which are marked to be skipped + bool gnu_file_line; // if line numbers should be surrounded with :x: and not (x): + bool no_path_in_filenames; // if the path to files should be removed from the output + String strip_file_prefixes; // remove the longest matching one of these prefixes from any file paths in the output + bool no_line_numbers; // if source code line numbers should be omitted from the output + bool no_debug_output; // no output in the debug console when a debugger is attached + bool no_skipped_summary; // don't print "skipped" in the summary !!! UNDOCUMENTED !!! + bool no_time_in_output; // omit any time/timestamps from output !!! UNDOCUMENTED !!! + + bool help; // to print the help + bool version; // to print the version + bool count; // if only the count of matching tests is to be retrieved + bool list_test_cases; // to list all tests matching the filters + bool list_test_suites; // to list all suites matching the filters + bool list_reporters; // lists all registered reporters +}; + +DOCTEST_INTERFACE const ContextOptions *getContextOptions(); + +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_CONTEXT_OPTIONS +#ifndef DOCTEST_PARTS_PUBLIC_ASSERT_TYPE +#define DOCTEST_PARTS_PUBLIC_ASSERT_TYPE + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { +namespace assertType { +enum Enum { + // macro traits + + is_warn = 1, + is_check = 2 * is_warn, + is_require = 2 * is_check, + + is_normal = 2 * is_require, + is_throws = 2 * is_normal, + is_throws_as = 2 * is_throws, + is_throws_with = 2 * is_throws_as, + is_nothrow = 2 * is_throws_with, + + is_false = 2 * is_nothrow, + is_unary = 2 * is_false, // not checked anywhere - used just to distinguish the types + + is_eq = 2 * is_unary, + is_ne = 2 * is_eq, + + is_lt = 2 * is_ne, + is_gt = 2 * is_lt, + + is_ge = 2 * is_gt, + is_le = 2 * is_ge, + + // macro types + + DT_WARN = is_normal | is_warn, + DT_CHECK = is_normal | is_check, + DT_REQUIRE = is_normal | is_require, + + DT_WARN_FALSE = is_normal | is_false | is_warn, + DT_CHECK_FALSE = is_normal | is_false | is_check, + DT_REQUIRE_FALSE = is_normal | is_false | is_require, + + DT_WARN_THROWS = is_throws | is_warn, + DT_CHECK_THROWS = is_throws | is_check, + DT_REQUIRE_THROWS = is_throws | is_require, + + DT_WARN_THROWS_AS = is_throws_as | is_warn, + DT_CHECK_THROWS_AS = is_throws_as | is_check, + DT_REQUIRE_THROWS_AS = is_throws_as | is_require, + + DT_WARN_THROWS_WITH = is_throws_with | is_warn, + DT_CHECK_THROWS_WITH = is_throws_with | is_check, + DT_REQUIRE_THROWS_WITH = is_throws_with | is_require, + + DT_WARN_THROWS_WITH_AS = is_throws_with | is_throws_as | is_warn, + DT_CHECK_THROWS_WITH_AS = is_throws_with | is_throws_as | is_check, + DT_REQUIRE_THROWS_WITH_AS = is_throws_with | is_throws_as | is_require, + + DT_WARN_NOTHROW = is_nothrow | is_warn, + DT_CHECK_NOTHROW = is_nothrow | is_check, + DT_REQUIRE_NOTHROW = is_nothrow | is_require, + + DT_WARN_EQ = is_normal | is_eq | is_warn, + DT_CHECK_EQ = is_normal | is_eq | is_check, + DT_REQUIRE_EQ = is_normal | is_eq | is_require, + + DT_WARN_NE = is_normal | is_ne | is_warn, + DT_CHECK_NE = is_normal | is_ne | is_check, + DT_REQUIRE_NE = is_normal | is_ne | is_require, + + DT_WARN_GT = is_normal | is_gt | is_warn, + DT_CHECK_GT = is_normal | is_gt | is_check, + DT_REQUIRE_GT = is_normal | is_gt | is_require, + + DT_WARN_LT = is_normal | is_lt | is_warn, + DT_CHECK_LT = is_normal | is_lt | is_check, + DT_REQUIRE_LT = is_normal | is_lt | is_require, + + DT_WARN_GE = is_normal | is_ge | is_warn, + DT_CHECK_GE = is_normal | is_ge | is_check, + DT_REQUIRE_GE = is_normal | is_ge | is_require, + + DT_WARN_LE = is_normal | is_le | is_warn, + DT_CHECK_LE = is_normal | is_le | is_check, + DT_REQUIRE_LE = is_normal | is_le | is_require, + + DT_WARN_UNARY = is_normal | is_unary | is_warn, + DT_CHECK_UNARY = is_normal | is_unary | is_check, + DT_REQUIRE_UNARY = is_normal | is_unary | is_require, + + DT_WARN_UNARY_FALSE = is_normal | is_false | is_unary | is_warn, + DT_CHECK_UNARY_FALSE = is_normal | is_false | is_unary | is_check, + DT_REQUIRE_UNARY_FALSE = is_normal | is_false | is_unary | is_require, +}; +} // namespace assertType + +DOCTEST_INTERFACE const char *assertString(assertType::Enum at); +DOCTEST_INTERFACE const char *failureString(assertType::Enum at); + +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_ASSERT_TYPE +#ifndef DOCTEST_PARTS_PUBLIC_ASSERT_DATA +#define DOCTEST_PARTS_PUBLIC_ASSERT_DATA + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { + +struct DOCTEST_INTERFACE TestCaseData; + +struct DOCTEST_INTERFACE AssertData { + // common - for all asserts + const TestCaseData *m_test_case; + assertType::Enum m_at; + const char *m_file; + int m_line; + const char *m_expr; + bool m_failed; + + // exception-related - for all asserts + bool m_threw; + String m_exception; + + // for normal asserts + String m_decomp; + + // for specific exception-related asserts + bool m_threw_as; + const char *m_exception_type; + + class DOCTEST_INTERFACE StringContains { + private: + Contains content; + bool isContains; + + public: + StringContains(const String &str) + : content(str), isContains(false) {} + + StringContains(Contains cntn) + : content(static_cast(cntn)), isContains(true) {} + + bool check(const String &str) { + return isContains ? (content == str) : (content.string == str); + } + + operator const String &() const { + return content.string; + } + + const char *c_str() const { + return content.string.c_str(); + } + } m_exception_string; + + AssertData( + assertType::Enum at, + const char *file, + int line, + const char *expr, + const char *exception_type, + const StringContains &exception_string + ); +}; + +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_ASSERT_DATA +#ifndef DOCTEST_PARTS_PUBLIC_ASSERT_COMPARATOR +#define DOCTEST_PARTS_PUBLIC_ASSERT_COMPARATOR + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +// clang-format off +template struct decay_array { using type = T; }; +template struct decay_array { using type = T *; }; +template struct decay_array { using type = T *; }; + +template struct not_char_pointer { static DOCTEST_CONSTEXPR int value = 1; }; +template<> struct not_char_pointer { static DOCTEST_CONSTEXPR int value = 0; }; +template<> struct not_char_pointer { static DOCTEST_CONSTEXPR int value = 0; }; + +template struct can_use_op : public not_char_pointer::type> {}; +// clang-format on +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + +#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_COMPARISON_RETURN_TYPE bool +#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +// clang-format off +#define DOCTEST_COMPARISON_RETURN_TYPE typename types::enable_if::value || can_use_op::value, bool>::type +inline bool eq(const char *lhs, const char *rhs) { return String(lhs) == String(rhs); } +inline bool ne(const char *lhs, const char *rhs) { return String(lhs) != String(rhs); } +inline bool lt(const char *lhs, const char *rhs) { return String(lhs) < String(rhs); } +inline bool gt(const char *lhs, const char *rhs) { return String(lhs) > String(rhs); } +inline bool le(const char *lhs, const char *rhs) { return String(lhs) <= String(rhs); } +inline bool ge(const char *lhs, const char *rhs) { return String(lhs) >= String(rhs); } +// clang-format on +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + +#define DOCTEST_RELATIONAL_OP(name, op) \ + template \ + DOCTEST_COMPARISON_RETURN_TYPE name(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { \ + return lhs op rhs; \ + } + +DOCTEST_RELATIONAL_OP(eq, ==) +DOCTEST_RELATIONAL_OP(ne, !=) +DOCTEST_RELATIONAL_OP(lt, <) +DOCTEST_RELATIONAL_OP(gt, >) +DOCTEST_RELATIONAL_OP(le, <=) +DOCTEST_RELATIONAL_OP(ge, >=) + +#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_CMP_EQ(l, r) l == r +#define DOCTEST_CMP_NE(l, r) l != r +#define DOCTEST_CMP_GT(l, r) l > r +#define DOCTEST_CMP_LT(l, r) l < r +#define DOCTEST_CMP_GE(l, r) l >= r +#define DOCTEST_CMP_LE(l, r) l <= r +#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_CMP_EQ(l, r) eq(l, r) +#define DOCTEST_CMP_NE(l, r) ne(l, r) +#define DOCTEST_CMP_GT(l, r) gt(l, r) +#define DOCTEST_CMP_LT(l, r) lt(l, r) +#define DOCTEST_CMP_GE(l, r) ge(l, r) +#define DOCTEST_CMP_LE(l, r) le(l, r) +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + +namespace binaryAssertComparison { +enum Enum { eq = 0, ne, gt, lt, ge, le }; +} // namespace binaryAssertComparison + +// clang-format off +template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L), const DOCTEST_REF_WRAP(R) ) const { return false; } }; + +#define DOCTEST_BINARY_RELATIONAL_OP(n, op) \ + template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return op(lhs, rhs); } }; +// clang-format on + +DOCTEST_BINARY_RELATIONAL_OP(0, doctest::detail::eq) +DOCTEST_BINARY_RELATIONAL_OP(1, doctest::detail::ne) +DOCTEST_BINARY_RELATIONAL_OP(2, doctest::detail::gt) +DOCTEST_BINARY_RELATIONAL_OP(3, doctest::detail::lt) +DOCTEST_BINARY_RELATIONAL_OP(4, doctest::detail::ge) +DOCTEST_BINARY_RELATIONAL_OP(5, doctest::detail::le) + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_ASSERT_COMPARATOR +#ifndef DOCTEST_PARTS_PUBLIC_ASSERT_RESULT +#define DOCTEST_PARTS_PUBLIC_ASSERT_RESULT + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +// more checks could be added - like in Catch: +// https://github.com/catchorg/Catch2/pull/1480/files +// https://github.com/catchorg/Catch2/pull/1481/files +#define DOCTEST_FORBIT_EXPRESSION(rt, op) \ + template \ + rt &operator op(const R &) { \ + static_assert(deferred_false::value, "Expression Too Complex Please Rewrite As Binary Comparison!"); \ + return *this; \ + } + +struct DOCTEST_INTERFACE Result { // NOLINT(*-member-init) + bool m_passed; + String m_decomp; + + Result() = default; // TODO: Why do we need this? (To remove NOLINT) + Result(bool passed, const String &decomposition = String()); + + // forbidding some expressions based on this table: + // https://en.cppreference.com/w/cpp/language/operator_precedence + DOCTEST_FORBIT_EXPRESSION(Result, &) + DOCTEST_FORBIT_EXPRESSION(Result, ^) + DOCTEST_FORBIT_EXPRESSION(Result, |) + DOCTEST_FORBIT_EXPRESSION(Result, &&) + DOCTEST_FORBIT_EXPRESSION(Result, ||) + DOCTEST_FORBIT_EXPRESSION(Result, ==) + DOCTEST_FORBIT_EXPRESSION(Result, !=) + DOCTEST_FORBIT_EXPRESSION(Result, <) + DOCTEST_FORBIT_EXPRESSION(Result, >) + DOCTEST_FORBIT_EXPRESSION(Result, <=) + DOCTEST_FORBIT_EXPRESSION(Result, >=) + DOCTEST_FORBIT_EXPRESSION(Result, =) + DOCTEST_FORBIT_EXPRESSION(Result, +=) + DOCTEST_FORBIT_EXPRESSION(Result, -=) + DOCTEST_FORBIT_EXPRESSION(Result, *=) + DOCTEST_FORBIT_EXPRESSION(Result, /=) + DOCTEST_FORBIT_EXPRESSION(Result, %=) + DOCTEST_FORBIT_EXPRESSION(Result, <<=) + DOCTEST_FORBIT_EXPRESSION(Result, >>=) + DOCTEST_FORBIT_EXPRESSION(Result, &=) + DOCTEST_FORBIT_EXPRESSION(Result, ^=) + DOCTEST_FORBIT_EXPRESSION(Result, |=) +}; + +struct DOCTEST_INTERFACE ResultBuilder : public AssertData { + ResultBuilder( + assertType::Enum at, + const char *file, + int line, + const char *expr, + const char *exception_type = "", + const String &exception_string = "" + ); + + ResultBuilder( + assertType::Enum at, + const char *file, + int line, + const char *expr, + const char *exception_type, + const Contains &exception_string + ); + + void setResult(const Result &res); + + template + DOCTEST_NOINLINE bool binary_assert(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { + m_failed = !RelationalComparator()(lhs, rhs); + if (m_failed || getContextOptions()->success) { + m_decomp = stringifyBinaryExpr(lhs, ", ", rhs); + } + return !m_failed; + } + + template + DOCTEST_NOINLINE bool unary_assert(const DOCTEST_REF_WRAP(L) val) { + m_failed = !val; + + if (m_at & assertType::is_false) { + m_failed = !m_failed; + } + + if (m_failed || getContextOptions()->success) { + m_decomp = (DOCTEST_STRINGIFY(val)); + } + + return !m_failed; + } + + void translateException(); + + bool log(); + void react() const; +}; + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_ASSERT_RESULT +#ifndef DOCTEST_PARTS_PUBLIC_ASSERT_EXPRESSION +#define DOCTEST_PARTS_PUBLIC_ASSERT_EXPRESSION + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0) +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison") +#endif + +// This will check if there is any way it could find a operator like member or friend and uses it. +// If not it doesn't find the operator or if the operator at global scope is defined after +// this template, the template won't be instantiated due to SFINAE. Once the template is not +// instantiated it can look for global operator using normal conversions. +#ifdef __NVCC__ +#define SFINAE_OP(ret, op) ret +#else +#define SFINAE_OP(ret, op) decltype((void)(doctest::detail::declval() op doctest::detail::declval()), ret{}) +#endif + +#define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \ + /* NOLINTBEGIN(cppcoreguidelines-missing-std-forward) */ \ + template \ + DOCTEST_NOINLINE SFINAE_OP(Result, op) operator op(R &&rhs) { \ + bool res = op_macro(doctest::detail::forward(lhs), doctest::detail::forward(rhs)); \ + if (m_at & assertType::is_false) \ + res = !res; \ + if (!res || doctest::getContextOptions()->success) \ + return Result(res, stringifyBinaryExpr(lhs, op_str, rhs)); \ + return Result(res); \ + } \ + /* NOLINTEND(cppcoreguidelines-missing-std-forward) */ + +#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + +DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-compare") +// DOCTEST_CLANG_SUPPRESS_WARNING("-Wdouble-promotion") +// DOCTEST_CLANG_SUPPRESS_WARNING("-Wconversion") +// DOCTEST_CLANG_SUPPRESS_WARNING("-Wfloat-equal") + +DOCTEST_GCC_SUPPRESS_WARNING_PUSH +DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion") +DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-compare") +// DOCTEST_GCC_SUPPRESS_WARNING("-Wdouble-promotion") +// DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion") +// DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-equal") + +DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +// https://stackoverflow.com/questions/39479163 what's the difference between 4018 and 4389 +DOCTEST_MSVC_SUPPRESS_WARNING(4388) // signed/unsigned mismatch +DOCTEST_MSVC_SUPPRESS_WARNING(4389) // 'operator' : signed/unsigned mismatch +DOCTEST_MSVC_SUPPRESS_WARNING(4018) // 'expression' : signed/unsigned mismatch +// DOCTEST_MSVC_SUPPRESS_WARNING(4805) // 'operation' : unsafe mix of type 'type' and type 'type' in +// operation + +#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + +template +struct Expression_lhs { + L lhs; + assertType::Enum m_at; + + // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) + explicit Expression_lhs(L &&in, assertType::Enum at) + : lhs(static_cast(in)), m_at(at) {} + + DOCTEST_NOINLINE operator Result() { + // this is needed only for MSVC 2015 + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4800) // 'int': forcing value to bool + bool res = static_cast(lhs); // NOLINT(bugprone-non-zero-enum-to-bool-conversion) + DOCTEST_MSVC_SUPPRESS_WARNING_POP + if (m_at & assertType::is_false) { + res = !res; + } + + if (!res || getContextOptions()->success) { + return {res, (DOCTEST_STRINGIFY(lhs))}; + } + return {res}; + } + + /* This is required for user-defined conversions from Expression_lhs to L */ + operator L() const { + return lhs; + } + + // clang-format off + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, " == ", DOCTEST_CMP_EQ) + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>, " > ", DOCTEST_CMP_GT) + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<, " < ", DOCTEST_CMP_LT) + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>=, " >= ", DOCTEST_CMP_GE) + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<=, " <= ", DOCTEST_CMP_LE) + // clang-format on + + // forbidding some expressions based on this table: + // https://en.cppreference.com/w/cpp/language/operator_precedence + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &&) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ||) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, =) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, +=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, -=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, *=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, /=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, %=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, &=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, ^=) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, |=) + // these 2 are unfortunate because they should be allowed - they have higher precedence over the + // comparisons, but the ExpressionDecomposer class uses the left shift operator to capture the + // left operand of the binary expression... + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, <<) + DOCTEST_FORBIT_EXPRESSION(Expression_lhs, >>) +}; + +#ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_MSVC_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP + +#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION + +#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0) +DOCTEST_CLANG_SUPPRESS_WARNING_POP +#endif + +struct DOCTEST_INTERFACE ExpressionDecomposer { + assertType::Enum m_at; + + ExpressionDecomposer(assertType::Enum at); + + // The right operator for capturing expressions is "<=" instead of "<<" (based on the operator + // precedence table) but then there will be warnings from GCC about "-Wparentheses" and since + // "_Pragma()" is problematic this will stay for now... + // https://github.com/catchorg/Catch2/issues/870 + // https://github.com/catchorg/Catch2/issues/565 + template + Expression_lhs + operator<<(const L &&operand) { // bitfields bind to universal ref but not const rvalue ref + return Expression_lhs(static_cast(operand), m_at); + } + + template < + typename L, + typename types::enable_if::value, void>::type * = nullptr> + Expression_lhs operator<<(const L &operand) { + return Expression_lhs(operand, m_at); + } +}; + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_ASSERT_EXPRESSION +#ifndef DOCTEST_PARTS_PUBLIC_COLOR +#define DOCTEST_PARTS_PUBLIC_COLOR + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { +namespace Color { +enum Enum { // NOLINT(cert-int09-c, readability-enum-initial-value) + None = 0, + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White +}; + +DOCTEST_INTERFACE std::ostream &operator<<(std::ostream &s, Color::Enum code); +} // namespace Color +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_COLOR +#ifndef DOCTEST_PARTS_PUBLIC_SUBCASE +#define DOCTEST_PARTS_PUBLIC_SUBCASE + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { + +struct DOCTEST_INTERFACE SubcaseSignature { + String m_name; + const char *m_file; + int m_line; + + bool operator==(const SubcaseSignature &other) const; + bool operator<(const SubcaseSignature &other) const; +}; + +#ifndef DOCTEST_CONFIG_DISABLE +namespace detail { +struct DOCTEST_INTERFACE Subcase { + SubcaseSignature m_signature; + bool m_entered = false; + + Subcase(const String &name, const char *file, int line); + Subcase(const Subcase &) = delete; + Subcase(Subcase &&) = delete; + Subcase &operator=(const Subcase &) = delete; + Subcase &operator=(Subcase &&) = delete; + ~Subcase(); + + operator bool() const; + +private: + bool checkFilters(); +}; +} // namespace detail +#endif // DOCTEST_CONFIG_DISABLE + +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_SUBCASE +#ifndef DOCTEST_PARTS_PUBLIC_TEST_SUITE +#define DOCTEST_PARTS_PUBLIC_TEST_SUITE + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +struct DOCTEST_INTERFACE TestSuite { + const char *m_test_suite = nullptr; + const char *m_description = nullptr; + bool m_skip = false; + bool m_no_breaks = false; + bool m_no_output = false; + bool m_may_fail = false; + bool m_should_fail = false; + int m_expected_failures = 0; + double m_timeout = 0; + + TestSuite &operator*(const char *in) noexcept; + + template + TestSuite &operator*(const T &in) noexcept { + in.fill(*this); + return *this; + } +}; + +// forward declarations of functions used by the macros +DOCTEST_INTERFACE int setTestSuite(const TestSuite &ts) noexcept; + +} // namespace detail + +} // namespace doctest + +// in a separate namespace outside of doctest because the DOCTEST_TEST_SUITE macro +// introduces an anonymous namespace in which getCurrentTestSuite gets overridden +namespace doctest_detail_test_suite_ns { +DOCTEST_INTERFACE doctest::detail::TestSuite &getCurrentTestSuite() noexcept; + +// this is here to clear the 'current test suite' for the current translation unit - at the top +DOCTEST_GLOBAL_NO_WARNINGS(/* NOLINT(cert-err58-cpp) */ + DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_), + doctest::detail::setTestSuite(doctest::detail::TestSuite() * "") +) + +} // namespace doctest_detail_test_suite_ns + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_TEST_SUITE +#ifndef DOCTEST_PARTS_PUBLIC_TEST_CASE +#define DOCTEST_PARTS_PUBLIC_TEST_CASE + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { + +struct DOCTEST_INTERFACE TestCaseData { + String m_file; // the file in which the test was registered (using String - see #350) + unsigned m_line; // the line where the test was registered + const char *m_name; // name of the test case + const char *m_test_suite; // the test suite in which the test was added + const char *m_description; + bool m_skip; + bool m_no_breaks; + bool m_no_output; + bool m_may_fail; + bool m_should_fail; + int m_expected_failures; + double m_timeout; +}; + +#ifndef DOCTEST_CONFIG_DISABLE +namespace detail { + +using funcType = void (*)(); + +struct DOCTEST_INTERFACE TestCase : public TestCaseData { + funcType m_test; // a function pointer to the test case + + String m_type; // for templated test cases - gets appended to the real name + int m_template_id; // an ID used to distinguish between the different versions of a templated + // test case + String m_full_name; // contains the name (only for templated test cases!) + the template type + + TestCase( + funcType test, + const char *file, + unsigned line, + const TestSuite &test_suite, + const String &type = String(), + int template_id = -1 + ) noexcept; + + TestCase(const TestCase &other) noexcept; + TestCase(TestCase &&) = delete; + + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function + TestCase &operator=(const TestCase &other) noexcept; + DOCTEST_MSVC_SUPPRESS_WARNING_POP + + TestCase &operator=(TestCase &&) = delete; + + TestCase &operator*(const char *in) noexcept; + + template + TestCase &operator*(const T &in) noexcept { + in.fill(*this); + return *this; + } + + bool operator<(const TestCase &other) const noexcept; + + ~TestCase() = default; +}; + +// forward declarations of functions used by the macros +DOCTEST_INTERFACE int regTest(const TestCase &tc) noexcept; + +} // namespace detail +#endif // DOCTEST_CONFIG_DISABLE + +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_TEST_CASE +#ifndef DOCTEST_PARTS_PUBLIC_DECORATORS +#define DOCTEST_PARTS_PUBLIC_DECORATORS + + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { + +#define DOCTEST_DEFINE_DECORATOR(name, type, def) \ + struct name { \ + type data; \ + name(type in = def) noexcept \ + : data(in) {} \ + void fill(detail::TestCase &state) const noexcept { \ + state.DOCTEST_CAT(m_, name) = data; \ + } \ + void fill(detail::TestSuite &state) const noexcept { \ + state.DOCTEST_CAT(m_, name) = data; \ + } \ + } + +DOCTEST_DEFINE_DECORATOR(test_suite, const char *, ""); +DOCTEST_DEFINE_DECORATOR(description, const char *, ""); +DOCTEST_DEFINE_DECORATOR(skip, bool, true); +DOCTEST_DEFINE_DECORATOR(no_breaks, bool, true); +DOCTEST_DEFINE_DECORATOR(no_output, bool, true); +DOCTEST_DEFINE_DECORATOR(timeout, double, 0); +DOCTEST_DEFINE_DECORATOR(may_fail, bool, true); +DOCTEST_DEFINE_DECORATOR(should_fail, bool, true); +DOCTEST_DEFINE_DECORATOR(expected_failures, int, 0); + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +#endif // DOCTEST_PARTS_PUBLIC_DECORATORS +#ifndef DOCTEST_PARTS_PUBLIC_EXCEPTION_TRANSLATOR +#define DOCTEST_PARTS_PUBLIC_EXCEPTION_TRANSLATOR + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { +namespace detail { + +#ifndef DOCTEST_CONFIG_DISABLE + +struct DOCTEST_INTERFACE IExceptionTranslator { + DOCTEST_DECLARE_INTERFACE(IExceptionTranslator) + virtual bool translate(String &) const = 0; +}; + +template +class ExceptionTranslator : public IExceptionTranslator { +public: + explicit ExceptionTranslator(String (*translateFunction)(T)) noexcept + : m_translateFunction(translateFunction) {} + + bool translate(String &res) const override { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + try { + throw; + } catch (const T &ex) { + res = m_translateFunction(ex); + return true; + } catch (...) {} // NOLINT(bugprone-empty-catch) +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + static_cast(res); // to silence -Wunused-parameter + return false; + } + +private: + String (*m_translateFunction)(T); +}; + +DOCTEST_INTERFACE void registerExceptionTranslatorImpl(const IExceptionTranslator *et) noexcept; + +#endif // DOCTEST_CONFIG_DISABLE + +} // namespace detail + +#ifndef DOCTEST_CONFIG_DISABLE + +template +int registerExceptionTranslator(String (*translateFunction)(T)) noexcept { + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") + static detail::ExceptionTranslator exceptionTranslator(translateFunction); + DOCTEST_CLANG_SUPPRESS_WARNING_POP + detail::registerExceptionTranslatorImpl(&exceptionTranslator); + return 0; +} + +#else // DOCTEST_CONFIG_DISABLE + +template +int registerExceptionTranslator(String (*)(T)) noexcept { + return 0; +} + +#endif // DOCTEST_CONFIG_DISABLE + +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_EXCEPTION_TRANSLATOR +#ifndef DOCTEST_PARTS_PUBLIC_CONTEXT_SCOPE +#define DOCTEST_PARTS_PUBLIC_CONTEXT_SCOPE + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { + +struct DOCTEST_INTERFACE IContextScope { + DOCTEST_DECLARE_INTERFACE(IContextScope) + virtual void stringify(std::ostream *) const = 0; +}; + +#ifndef DOCTEST_CONFIG_DISABLE +namespace detail { + +// ContextScope base class used to allow implementing methods of ContextScope +// that don't depend on the template parameter in doctest.cpp. +struct DOCTEST_INTERFACE ContextScopeBase : public IContextScope { + ContextScopeBase(const ContextScopeBase &) = delete; + + ContextScopeBase &operator=(const ContextScopeBase &) = delete; + ContextScopeBase &operator=(ContextScopeBase &&) = delete; + + ~ContextScopeBase() override = default; + +protected: + ContextScopeBase(); + ContextScopeBase(ContextScopeBase &&other) noexcept; + + void destroy(); + bool need_to_destroy{true}; +}; + +template +class ContextScope : public ContextScopeBase { + L lambda_; + +public: + explicit ContextScope(const L &lambda) + : lambda_(lambda) {} + + // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) + explicit ContextScope(L &&lambda) + : lambda_(static_cast(lambda)) {} + + ContextScope(const ContextScope &) = delete; + ContextScope(ContextScope &&) noexcept = default; + + ContextScope &operator=(const ContextScope &) = delete; + ContextScope &operator=(ContextScope &&) = delete; + + void stringify(std::ostream *s) const override { + lambda_(s); + } + + ~ContextScope() override { + if (need_to_destroy) { + destroy(); + } + } +}; + +template +ContextScope MakeContextScope(const L &lambda) { + return ContextScope(lambda); +} + +} // namespace detail +#endif // DOCTEST_CONFIG_DISABLE + +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_CONTEXT_SCOPE +#ifndef DOCTEST_PARTS_PUBLIC_ASSERT_MESSAGE +#define DOCTEST_PARTS_PUBLIC_ASSERT_MESSAGE + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { + +struct DOCTEST_INTERFACE MessageData { + String m_string; + const char *m_file; + int m_line; + assertType::Enum m_severity; +}; + +#ifndef DOCTEST_CONFIG_DISABLE +namespace detail { + +struct DOCTEST_INTERFACE MessageBuilder : public MessageData { + std::ostream *m_stream; + bool logged = false; + + MessageBuilder(const char *file, int line, assertType::Enum severity); + + MessageBuilder(const MessageBuilder &) = delete; + MessageBuilder(MessageBuilder &&) = delete; + + MessageBuilder &operator=(const MessageBuilder &) = delete; + MessageBuilder &operator=(MessageBuilder &&) = delete; + + ~MessageBuilder() noexcept(false); + + // the preferred way of chaining parameters for stringification + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4866) + template + MessageBuilder &operator,(const T &in) { + *m_stream << (DOCTEST_STRINGIFY(in)); + return *this; + } + DOCTEST_MSVC_SUPPRESS_WARNING_POP + + // kept here just for backwards-compatibility - the comma operator should be preferred now + template + MessageBuilder &operator<<(const T &in) { + return this->operator,(in); + } + + // the `,` operator has the lowest operator precedence - if `<<` is used by the user then + // the `,` operator will be called last which is not what we want and thus the `*` operator + // is used first (has higher operator precedence compared to `<<`) so that we guarantee that + // an operator of the MessageBuilder class is called first before the rest of the parameters + template + MessageBuilder &operator*(const T &in) { + return this->operator,(in); + } + + bool log(); + void react(); +}; + +} // namespace detail +#endif // DOCTEST_CONFIG_DISABLE + +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_ASSERT_MESSAGE +#ifndef DOCTEST_PARTS_PUBLIC_PATH +#define DOCTEST_PARTS_PUBLIC_PATH + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { + +DOCTEST_INTERFACE const char *skipPathFromFilename(const char *file); + +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_PATH +#ifndef DOCTEST_PARTS_PUBLIC_EXCEPTIONS +#define DOCTEST_PARTS_PUBLIC_EXCEPTIONS + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +struct DOCTEST_INTERFACE TestFailureException {}; + +DOCTEST_INTERFACE bool checkIfShouldThrow(assertType::Enum at); + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS +DOCTEST_NORETURN +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS +DOCTEST_INTERFACE void throwException(); + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_EXCEPTIONS +#ifndef DOCTEST_PARTS_PUBLIC_CONTEXT +#define DOCTEST_PARTS_PUBLIC_CONTEXT + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { + +DOCTEST_INTERFACE extern bool is_running_in_test; + +namespace detail { +using assert_handler = void (*)(const AssertData &); +struct ContextState; +} // namespace detail + +class DOCTEST_INTERFACE Context { + detail::ContextState *p; + + void parseArgs(int argc, const char *const *argv, bool withDefaults = false); + +public: + explicit Context(int argc = 0, const char *const *argv = nullptr); + + Context(const Context &) = delete; + Context(Context &&) = delete; + + Context &operator=(const Context &) = delete; + Context &operator=(Context &&) = delete; + + ~Context(); // NOLINT(performance-trivially-destructible) + + void applyCommandLine(int argc, const char *const *argv); + + void addFilter(const char *filter, const char *value); + void clearFilters(); + void setOption(const char *option, bool value); + void setOption(const char *option, int value); + void setOption(const char *option, const char *value); + + bool shouldExit(); + + void setAsDefaultForAssertsOutOfTestCases(); + + void setAssertHandler(detail::assert_handler ah); + + void setCout(std::ostream *out); + + int run(); +}; +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_CONTEXT +#ifndef DOCTEST_PARTS_PUBLIC_ASSERT_HANDLER +#define DOCTEST_PARTS_PUBLIC_ASSERT_HANDLER + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +DOCTEST_INTERFACE void failed_out_of_a_testing_context(const AssertData &ad); + +DOCTEST_INTERFACE bool +decomp_assert(assertType::Enum at, const char *file, int line, const char *expr, const Result &result); + +#define DOCTEST_ASSERT_OUT_OF_TESTS(decomp) \ + do { /* NOLINT(cppcoreguidelines-avoid-do-while) */ \ + if (!is_running_in_test) { \ + if (failed) { \ + ResultBuilder rb(at, file, line, expr); \ + rb.m_failed = failed; \ + rb.m_decomp = decomp; \ + failed_out_of_a_testing_context(rb); \ + if (isDebuggerActive() && !getContextOptions()->no_breaks) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + if (checkIfShouldThrow(at)) \ + throwException(); \ + } \ + return !failed; \ + } \ + } while (false) + +#define DOCTEST_ASSERT_IN_TESTS(decomp) \ + ResultBuilder rb(at, file, line, expr); \ + rb.m_failed = failed; \ + if (rb.m_failed || getContextOptions()->success) \ + rb.m_decomp = decomp; \ + if (rb.log()) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + if (rb.m_failed && checkIfShouldThrow(at)) \ + throwException() + +template +DOCTEST_NOINLINE bool binary_assert( + assertType::Enum at, + const char *file, + int line, + const char *expr, + const DOCTEST_REF_WRAP(L) lhs, + const DOCTEST_REF_WRAP(R) rhs +) { + const bool failed = !RelationalComparator()(lhs, rhs); + + // ################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ################################################################################### + DOCTEST_ASSERT_OUT_OF_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); + DOCTEST_ASSERT_IN_TESTS(stringifyBinaryExpr(lhs, ", ", rhs)); + return !failed; +} + +template +DOCTEST_NOINLINE bool +unary_assert(assertType::Enum at, const char *file, int line, const char *expr, const DOCTEST_REF_WRAP(L) val) { + bool failed = !val; + + if (at & assertType::is_false) + failed = !failed; + + // ################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ################################################################################### + DOCTEST_ASSERT_OUT_OF_TESTS((DOCTEST_STRINGIFY(val))); + DOCTEST_ASSERT_IN_TESTS((DOCTEST_STRINGIFY(val))); + return !failed; +} + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_ASSERT_HANDLER +#ifndef DOCTEST_PARTS_PUBLIC_REPORTER +#define DOCTEST_PARTS_PUBLIC_REPORTER + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +namespace doctest { + +namespace TestCaseFailureReason { +enum Enum { + None = 0, + AssertFailure = 1, // an assertion has failed in the test case + Exception = 2, // test case threw an exception + Crash = 4, // a crash... + TooManyFailedAsserts = 8, // the abort-after option + Timeout = 16, // see the timeout decorator + ShouldHaveFailedButDidnt = 32, // see the should_fail decorator + ShouldHaveFailedAndDid = 64, // see the should_fail decorator + DidntFailExactlyNumTimes = 128, // see the expected_failures decorator + FailedExactlyNumTimes = 256, // see the expected_failures decorator + CouldHaveFailedAndDid = 512 // see the may_fail decorator +}; +} // namespace TestCaseFailureReason + +struct DOCTEST_INTERFACE CurrentTestCaseStats { + int numAssertsCurrentTest; + int numAssertsFailedCurrentTest; + double seconds; + int failure_flags; // use TestCaseFailureReason::Enum + bool testCaseSuccess; +}; + +struct DOCTEST_INTERFACE TestCaseException { + String error_string; + bool is_crash; +}; + +struct DOCTEST_INTERFACE TestRunStats { + unsigned numTestCases; + unsigned numTestCasesPassingFilters; + unsigned numTestSuitesPassingFilters; + unsigned numTestCasesFailed; + int numAsserts; + int numAssertsFailed; +}; + +struct QueryData { + const TestRunStats *run_stats = nullptr; + const TestCaseData **data = nullptr; + unsigned num_data = 0; +}; + +struct DOCTEST_INTERFACE IReporter { + // The constructor has to accept "const ContextOptions&" as a single argument + // which has most of the options for the run + a pointer to the stdout stream + // Reporter(const ContextOptions& in) + + // called when a query should be reported (listing test cases, printing the version, etc.) + virtual void report_query(const QueryData &) = 0; + + // called when the whole test run starts + virtual void test_run_start() = 0; + // called when the whole test run ends (caching a pointer to the input doesn't make sense here) + virtual void test_run_end(const TestRunStats &) = 0; + + // called when a test case is started (safe to cache a pointer to the input) + virtual void test_case_start(const TestCaseData &) = 0; + // called when a test case is reentered because of unfinished subcases (safe to cache a pointer to the input) + virtual void test_case_reenter(const TestCaseData &) = 0; + // called when a test case has ended + virtual void test_case_end(const CurrentTestCaseStats &) = 0; + + // called when an exception is thrown from the test case (or it crashes) + virtual void test_case_exception(const TestCaseException &) = 0; + + // called whenever a subcase is entered (don't cache pointers to the input) + virtual void subcase_start(const SubcaseSignature &) = 0; + // called whenever a subcase is exited (don't cache pointers to the input) + virtual void subcase_end() = 0; + + // called for each assert (don't cache pointers to the input) + virtual void log_assert(const AssertData &) = 0; + // called for each message (don't cache pointers to the input) + virtual void log_message(const MessageData &) = 0; + + // called when a test case is skipped either because it doesn't pass the filters, + // has a skip decorator or isn't in the execution range (between first and last) + // (safe to cache a pointer to the input) + virtual void test_case_skipped(const TestCaseData &) = 0; + + DOCTEST_DECLARE_INTERFACE(IReporter) + + // can obtain all currently active contexts and stringify them if one wishes to do so + static int get_num_active_contexts(); + static const IContextScope *const *get_active_contexts(); + + // can iterate through contexts which have been stringified automatically + // in their destructors when an exception has been thrown + static int get_num_stringified_contexts(); + static const String *get_stringified_contexts(); +}; + +namespace detail { +using reporterCreatorFunc = IReporter *(*)(const ContextOptions &); + +DOCTEST_INTERFACE void +registerReporterImpl(const char *name, int prio, reporterCreatorFunc c, bool isReporter) noexcept; + +template +IReporter *reporterCreator(const ContextOptions &o) { + return new Reporter(o); +} +} // namespace detail + +template +int registerReporter(const char *name, int priority, bool isReporter) noexcept { + detail::registerReporterImpl(name, priority, detail::reporterCreator, isReporter); + return 0; +} +} // namespace doctest + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_REPORTER +#ifndef DOCTEST_PARTS_PUBLIC_GENERATOR +#define DOCTEST_PARTS_PUBLIC_GENERATOR + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE +namespace doctest { +namespace detail { + +DOCTEST_INTERFACE size_t acquireGeneratorDecisionIndex(size_t count); + +template +T acquireGeneratorValue(T first, Rest... rest) { + const T values[] = {first, static_cast(rest)...}; + const size_t idx = acquireGeneratorDecisionIndex(1 + sizeof...(Rest)); + return values[idx]; +} + +} // namespace detail +} // namespace doctest +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_GENERATOR +#ifndef DOCTEST_PARTS_PUBLIC_MACROS +#define DOCTEST_PARTS_PUBLIC_MACROS + + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE +namespace doctest { +namespace detail { +template +int instantiationHelper(const T &) noexcept { + return 0; +} + +} // namespace detail +} // namespace doctest +#endif // DOCTEST_CONFIG_DISABLE + +#ifdef DOCTEST_CONFIG_ASSERTS_RETURN_VALUES +#define DOCTEST_FUNC_EMPTY [] { return false; }() +#else +#define DOCTEST_FUNC_EMPTY (void)0 +#endif + +// if registering is not disabled +#ifndef DOCTEST_CONFIG_DISABLE + +#ifdef DOCTEST_CONFIG_ASSERTS_RETURN_VALUES +#define DOCTEST_FUNC_SCOPE_BEGIN [&] +#define DOCTEST_FUNC_SCOPE_END () +#define DOCTEST_FUNC_SCOPE_RET(v) return v +#else +#define DOCTEST_FUNC_SCOPE_BEGIN do /* NOLINT(cppcoreguidelines-avoid-do-while)*/ +#define DOCTEST_FUNC_SCOPE_END while (false) +#define DOCTEST_FUNC_SCOPE_RET(v) (void)0 +#endif + +// common code in asserts - for convenience +#define DOCTEST_ASSERT_LOG_REACT_RETURN(b) \ + if (b.log()) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + b.react(); \ + DOCTEST_FUNC_SCOPE_RET(!b.m_failed) + +#ifdef DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#define DOCTEST_WRAP_IN_TRY(x) x; +#else // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS +#define DOCTEST_WRAP_IN_TRY(x) \ + try { \ + x; \ + } catch (...) { DOCTEST_RB.translateException(); } +#endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS + +#ifdef DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS +#define DOCTEST_CAST_TO_VOID(...) \ + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wuseless-cast") \ + static_cast(__VA_ARGS__); \ + DOCTEST_GCC_SUPPRESS_WARNING_POP +#else // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS +#define DOCTEST_CAST_TO_VOID(...) __VA_ARGS__; +#endif // DOCTEST_CONFIG_VOID_CAST_EXPRESSIONS + +// registers the test by initializing a dummy var with a function +#define DOCTEST_REGISTER_FUNCTION(global_prefix, f, decorators) \ + global_prefix DOCTEST_GLOBAL_NO_WARNINGS( \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_), /* NOLINT */ \ + doctest::detail::regTest( \ + doctest::detail::TestCase(f, __FILE__, __LINE__, doctest_detail_test_suite_ns::getCurrentTestSuite()) * \ + decorators \ + ) \ + ) + +#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, decorators) \ + namespace { /* NOLINT */ \ + struct der : public base { \ + void f(); \ + }; \ + static DOCTEST_INLINE_NOINLINE void func() { \ + der v; \ + v.f(); \ + } \ + DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, func, decorators) \ + } \ + DOCTEST_INLINE_NOINLINE void der::f() // NOLINT(misc-definitions-in-headers) + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, decorators) \ + static void f(); \ + DOCTEST_REGISTER_FUNCTION(DOCTEST_EMPTY, f, decorators) \ + static void f() + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS(f, proxy, decorators) \ + static doctest::detail::funcType proxy() { \ + return f; \ + } \ + DOCTEST_REGISTER_FUNCTION(inline, proxy(), decorators) \ + static void f() + +// for registering tests +#define DOCTEST_TEST_CASE(decorators) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), decorators) + +// for registering tests in classes - requires C++17 for inline variables! +#if DOCTEST_CPLUSPLUS >= 201703L +#define DOCTEST_TEST_CASE_CLASS(decorators) \ + DOCTEST_CREATE_AND_REGISTER_FUNCTION_IN_CLASS( \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), DOCTEST_ANONYMOUS(DOCTEST_ANON_PROXY_), decorators \ + ) +#else // DOCTEST_TEST_CASE_CLASS +#define DOCTEST_TEST_CASE_CLASS(...) TEST_CASES_CAN_BE_REGISTERED_IN_CLASSES_ONLY_IN_CPP17_MODE_OR_WITH_VS_2017_OR_NEWER +#endif // DOCTEST_TEST_CASE_CLASS + +// for registering tests with a fixture +#define DOCTEST_TEST_CASE_FIXTURE(c, decorators) \ + DOCTEST_IMPLEMENT_FIXTURE( \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_CLASS_), c, DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), decorators \ + ) + +// for converting types to strings without the header and demangling +#define DOCTEST_TYPE_TO_STRING_AS(str, ...) \ + namespace doctest { \ + template <> \ + inline String toString<__VA_ARGS__>() { \ + return str; \ + } \ + } \ + static_assert(true, "") + +#define DOCTEST_TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING_AS(#__VA_ARGS__, __VA_ARGS__) + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, iter, func) \ + template \ + static void func(); \ + namespace { /* NOLINT */ \ + template \ + struct iter; \ + template \ + struct iter> { \ + iter(const char *file, unsigned line, int index) noexcept { \ + doctest::detail::regTest( \ + doctest::detail::TestCase( \ + func, \ + file, \ + line, \ + doctest_detail_test_suite_ns::getCurrentTestSuite(), \ + doctest::toString(), \ + int(line) * 1000 + index \ + ) * \ + dec \ + ); \ + iter>(file, line, index + 1); \ + } \ + }; \ + template <> \ + struct iter> { \ + iter(const char *, unsigned, int) {} \ + }; \ + } \ + template \ + static void func() + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(dec, T, id) \ + DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(id, ITERATOR), DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)) + +#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, anon, ...) \ + DOCTEST_GLOBAL_NO_WARNINGS( \ + DOCTEST_CAT(anon, DUMMY), /* NOLINT(cert-err58-cpp, fuchsia-statically-constructed-objects) */ \ + doctest::detail::instantiationHelper(DOCTEST_CAT(id, ITERATOR) < __VA_ARGS__ > (__FILE__, __LINE__, 0)) \ + ) + +#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), std::tuple<__VA_ARGS__>) \ + static_assert(true, "") + +#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(id, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), __VA_ARGS__) \ + static_assert(true, "") + +#define DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, anon, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_DEFINE_IMPL(dec, T, DOCTEST_CAT(anon, ITERATOR), anon); \ + DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE_IMPL(anon, anon, std::tuple<__VA_ARGS__>) \ + template \ + static void anon() + +#define DOCTEST_TEST_CASE_TEMPLATE(dec, T, ...) \ + DOCTEST_TEST_CASE_TEMPLATE_IMPL(dec, T, DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_), __VA_ARGS__) + +// for subcases +#define DOCTEST_SUBCASE(name) \ + if (const doctest::detail::Subcase &DOCTEST_ANONYMOUS(DOCTEST_ANON_SUBCASE_) DOCTEST_UNUSED = \ + doctest::detail::Subcase(name, __FILE__, __LINE__)) + +// for generating value-parameterized test inputs +#define DOCTEST_GENERATE(...) doctest::detail::acquireGeneratorValue(__VA_ARGS__) + +// for grouping tests in test suites by using code blocks +#define DOCTEST_TEST_SUITE_IMPL(decorators, ns_name) \ + namespace ns_name { \ + namespace doctest_detail_test_suite_ns { \ + static DOCTEST_NOINLINE doctest::detail::TestSuite &getCurrentTestSuite() noexcept { \ + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4640) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") \ + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmissing-field-initializers") \ + static doctest::detail::TestSuite data{}; \ + static bool inited = false; \ + DOCTEST_MSVC_SUPPRESS_WARNING_POP \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP \ + DOCTEST_GCC_SUPPRESS_WARNING_POP \ + if (!inited) { \ + data *decorators; \ + inited = true; \ + } \ + return data; \ + } \ + } \ + } \ + namespace ns_name + +#define DOCTEST_TEST_SUITE(decorators) DOCTEST_TEST_SUITE_IMPL(decorators, DOCTEST_ANONYMOUS(DOCTEST_ANON_SUITE_)) + +// for starting a testsuite block +#define DOCTEST_TEST_SUITE_BEGIN(decorators) \ + DOCTEST_GLOBAL_NO_WARNINGS( \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_), /* NOLINT(cert-err58-cpp) */ \ + doctest::detail::setTestSuite(doctest::detail::TestSuite() * decorators) \ + ) \ + static_assert(true, "") + +// for ending a testsuite block +#define DOCTEST_TEST_SUITE_END \ + DOCTEST_GLOBAL_NO_WARNINGS( \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_VAR_), /* NOLINT(cert-err58-cpp) */ \ + doctest::detail::setTestSuite(doctest::detail::TestSuite() * "") \ + ) \ + using DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_) = int + +// for registering exception translators +#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(translatorName, signature) \ + inline doctest::String translatorName(signature); \ + DOCTEST_GLOBAL_NO_WARNINGS( \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_VAR_), /* NOLINT(cert-err58-cpp) */ \ + doctest::registerExceptionTranslator(translatorName) \ + ) \ + doctest::String translatorName(signature) + +#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ + DOCTEST_REGISTER_EXCEPTION_TRANSLATOR_IMPL(DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_), signature) + +// for registering reporters +#define DOCTEST_REGISTER_REPORTER(name, priority, reporter) \ + DOCTEST_GLOBAL_NO_WARNINGS( \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_REPORTER_VAR_), /* NOLINT(cert-err58-cpp) */ \ + doctest::registerReporter(name, priority, true) \ + ) \ + static_assert(true, "") + +// for registering listeners +#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) \ + DOCTEST_GLOBAL_NO_WARNINGS( \ + DOCTEST_ANONYMOUS(DOCTEST_ANON_REPORTER_VAR_), /* NOLINT(cert-err58-cpp) */ \ + doctest::registerReporter(name, priority, false) \ + ) \ + static_assert(true, "") + +#define DOCTEST_INFO(...) \ + DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_MB_), DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_OTHER_), __VA_ARGS__) + +#define DOCTEST_INFO_IMPL(mb_name, s_name, ...) \ + auto DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope([&](std::ostream *s_name) { \ + doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \ + mb_name.m_stream = s_name; \ + mb_name *__VA_ARGS__; \ + }) + +#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := ", x) + +#define DOCTEST_ADD_AT_IMPL(type, file, line, mb, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + doctest::detail::MessageBuilder mb(file, line, doctest::assertType::type); \ + mb *__VA_ARGS__; \ + if (mb.log()) \ + DOCTEST_BREAK_INTO_DEBUGGER(); \ + mb.react(); \ + } \ + DOCTEST_FUNC_SCOPE_END + +#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) \ + DOCTEST_ADD_AT_IMPL(is_warn, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__) +#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) \ + DOCTEST_ADD_AT_IMPL(is_check, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__) +#define DOCTEST_ADD_FAIL_AT(file, line, ...) \ + DOCTEST_ADD_AT_IMPL(is_require, file, line, DOCTEST_ANONYMOUS(DOCTEST_MESSAGE_), __VA_ARGS__) + +#define DOCTEST_MESSAGE(...) DOCTEST_ADD_MESSAGE_AT(__FILE__, __LINE__, __VA_ARGS__) +#define DOCTEST_FAIL_CHECK(...) DOCTEST_ADD_FAIL_CHECK_AT(__FILE__, __LINE__, __VA_ARGS__) +#define DOCTEST_FAIL(...) DOCTEST_ADD_FAIL_AT(__FILE__, __LINE__, __VA_ARGS__) + +#define DOCTEST_TO_LVALUE(...) __VA_ARGS__ // Not removed to keep backwards compatibility. + +#ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#define DOCTEST_ASSERT_IMPLEMENT_2(assert_type, ...) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ + /* NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) */ \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__); \ + DOCTEST_WRAP_IN_TRY( \ + DOCTEST_RB.setResult(doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type) << __VA_ARGS__) \ + ) /* NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) */ \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB) \ + DOCTEST_CLANG_SUPPRESS_WARNING_POP + +#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + DOCTEST_ASSERT_IMPLEMENT_2(assert_type, __VA_ARGS__); \ + } \ + DOCTEST_FUNC_SCOPE_END // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + +#define DOCTEST_BINARY_ASSERT(assert_type, comp, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__); \ + DOCTEST_WRAP_IN_TRY(DOCTEST_RB.binary_assert(__VA_ARGS__)) \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } \ + DOCTEST_FUNC_SCOPE_END + +#define DOCTEST_UNARY_ASSERT(assert_type, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__); \ + DOCTEST_WRAP_IN_TRY(DOCTEST_RB.unary_assert(__VA_ARGS__)) \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } \ + DOCTEST_FUNC_SCOPE_END + +#else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +// necessary for _MESSAGE +#define DOCTEST_ASSERT_IMPLEMENT_2 DOCTEST_ASSERT_IMPLEMENT_1 + +#define DOCTEST_ASSERT_IMPLEMENT_1(assert_type, ...) \ + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Woverloaded-shift-op-parentheses") \ + doctest::detail::decomp_assert( \ + doctest::assertType::assert_type, \ + __FILE__, \ + __LINE__, \ + #__VA_ARGS__, \ + doctest::detail::ExpressionDecomposer(doctest::assertType::assert_type) << __VA_ARGS__ \ + ) DOCTEST_CLANG_SUPPRESS_WARNING_POP + +#define DOCTEST_BINARY_ASSERT(assert_type, comparison, ...) \ + doctest::detail::binary_assert( \ + doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, __VA_ARGS__ \ + ) + +#define DOCTEST_UNARY_ASSERT(assert_type, ...) \ + doctest::detail::unary_assert(doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__, __VA_ARGS__) + +#endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS + +#define DOCTEST_WARN(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN, __VA_ARGS__) +#define DOCTEST_CHECK(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK, __VA_ARGS__) +#define DOCTEST_REQUIRE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE, __VA_ARGS__) +#define DOCTEST_WARN_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_WARN_FALSE, __VA_ARGS__) +#define DOCTEST_CHECK_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_CHECK_FALSE, __VA_ARGS__) +#define DOCTEST_REQUIRE_FALSE(...) DOCTEST_ASSERT_IMPLEMENT_1(DT_REQUIRE_FALSE, __VA_ARGS__) + +// clang-format off +#define DOCTEST_WARN_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_WARN_FALSE, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_CHECK_FALSE, cond); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_ASSERT_IMPLEMENT_2(DT_REQUIRE_FALSE, cond); } DOCTEST_FUNC_SCOPE_END +// clang-format on + +#define DOCTEST_WARN_EQ(...) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, eq, __VA_ARGS__) +#define DOCTEST_CHECK_EQ(...) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, eq, __VA_ARGS__) +#define DOCTEST_REQUIRE_EQ(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, eq, __VA_ARGS__) +#define DOCTEST_WARN_NE(...) DOCTEST_BINARY_ASSERT(DT_WARN_NE, ne, __VA_ARGS__) +#define DOCTEST_CHECK_NE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, ne, __VA_ARGS__) +#define DOCTEST_REQUIRE_NE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, ne, __VA_ARGS__) +#define DOCTEST_WARN_GT(...) DOCTEST_BINARY_ASSERT(DT_WARN_GT, gt, __VA_ARGS__) +#define DOCTEST_CHECK_GT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, gt, __VA_ARGS__) +#define DOCTEST_REQUIRE_GT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, gt, __VA_ARGS__) +#define DOCTEST_WARN_LT(...) DOCTEST_BINARY_ASSERT(DT_WARN_LT, lt, __VA_ARGS__) +#define DOCTEST_CHECK_LT(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, lt, __VA_ARGS__) +#define DOCTEST_REQUIRE_LT(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, lt, __VA_ARGS__) +#define DOCTEST_WARN_GE(...) DOCTEST_BINARY_ASSERT(DT_WARN_GE, ge, __VA_ARGS__) +#define DOCTEST_CHECK_GE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, ge, __VA_ARGS__) +#define DOCTEST_REQUIRE_GE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, ge, __VA_ARGS__) +#define DOCTEST_WARN_LE(...) DOCTEST_BINARY_ASSERT(DT_WARN_LE, le, __VA_ARGS__) +#define DOCTEST_CHECK_LE(...) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, le, __VA_ARGS__) +#define DOCTEST_REQUIRE_LE(...) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, le, __VA_ARGS__) + +#define DOCTEST_WARN_UNARY(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, __VA_ARGS__) +#define DOCTEST_CHECK_UNARY(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, __VA_ARGS__) +#define DOCTEST_REQUIRE_UNARY(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, __VA_ARGS__) +#define DOCTEST_WARN_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, __VA_ARGS__) +#define DOCTEST_CHECK_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, __VA_ARGS__) +#define DOCTEST_REQUIRE_UNARY_FALSE(...) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, __VA_ARGS__) + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + +#define DOCTEST_ASSERT_THROWS_AS(expr, assert_type, message, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + if (!doctest::getContextOptions()->no_throw) { \ + doctest::detail::ResultBuilder DOCTEST_RB( \ + doctest::assertType::assert_type, __FILE__, __LINE__, #expr, #__VA_ARGS__, message \ + ); \ + try { \ + DOCTEST_CAST_TO_VOID(expr) \ + } catch (const typename doctest::detail::types::remove_const< \ + typename doctest::detail::types::remove_reference<__VA_ARGS__>::type>::type &) { \ + DOCTEST_RB.translateException(); \ + DOCTEST_RB.m_threw_as = true; \ + } catch (...) { DOCTEST_RB.translateException(); } \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } else { /* NOLINT(*-else-after-return) */ \ + DOCTEST_FUNC_SCOPE_RET(false); \ + } \ + } \ + DOCTEST_FUNC_SCOPE_END + +#define DOCTEST_ASSERT_THROWS_WITH(expr, expr_str, assert_type, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + if (!doctest::getContextOptions()->no_throw) { \ + doctest::detail::ResultBuilder DOCTEST_RB( \ + doctest::assertType::assert_type, __FILE__, __LINE__, expr_str, "", __VA_ARGS__ \ + ); \ + try { \ + DOCTEST_CAST_TO_VOID(expr) \ + } catch (...) { DOCTEST_RB.translateException(); } \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } else { /* NOLINT(*-else-after-return) */ \ + DOCTEST_FUNC_SCOPE_RET(false); \ + } \ + } \ + DOCTEST_FUNC_SCOPE_END + +#define DOCTEST_ASSERT_NOTHROW(assert_type, ...) \ + DOCTEST_FUNC_SCOPE_BEGIN { \ + doctest::detail::ResultBuilder DOCTEST_RB(doctest::assertType::assert_type, __FILE__, __LINE__, #__VA_ARGS__); \ + try { \ + DOCTEST_CAST_TO_VOID(__VA_ARGS__) \ + } catch (...) { DOCTEST_RB.translateException(); } \ + DOCTEST_ASSERT_LOG_REACT_RETURN(DOCTEST_RB); \ + } \ + DOCTEST_FUNC_SCOPE_END + +// clang-format off +#define DOCTEST_WARN_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_WARN_THROWS, "") +#define DOCTEST_CHECK_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_CHECK_THROWS, "") +#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_ASSERT_THROWS_WITH((__VA_ARGS__), #__VA_ARGS__, DT_REQUIRE_THROWS, "") + +#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_AS, "", __VA_ARGS__) +#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_AS, "", __VA_ARGS__) +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_AS, "", __VA_ARGS__) + +#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_WARN_THROWS_WITH, __VA_ARGS__) +#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_CHECK_THROWS_WITH, __VA_ARGS__) +#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_ASSERT_THROWS_WITH(expr, #expr, DT_REQUIRE_THROWS_WITH, __VA_ARGS__) + +#define DOCTEST_WARN_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_WARN_THROWS_WITH_AS, message, __VA_ARGS__) +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_CHECK_THROWS_WITH_AS, message, __VA_ARGS__) +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, message, ...) DOCTEST_ASSERT_THROWS_AS(expr, DT_REQUIRE_THROWS_WITH_AS, message, __VA_ARGS__) + +#define DOCTEST_WARN_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_WARN_NOTHROW, __VA_ARGS__) +#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_CHECK_NOTHROW, __VA_ARGS__) +#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_ASSERT_NOTHROW(DT_REQUIRE_NOTHROW, __VA_ARGS__) + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_AS(expr, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_AS(expr, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_AS(expr, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH(expr, with); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH(expr, with); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH(expr, with); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_WARN_NOTHROW(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_CHECK_NOTHROW(expr); } DOCTEST_FUNC_SCOPE_END +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_SCOPE_BEGIN { DOCTEST_INFO(__VA_ARGS__); DOCTEST_REQUIRE_NOTHROW(expr); } DOCTEST_FUNC_SCOPE_END +// clang-format on + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +// ================================================================================================= +// == WHAT FOLLOWS IS VERSIONS OF THE MACROS THAT DO NOT DO ANY REGISTERING! == +// == THIS CAN BE ENABLED BY DEFINING DOCTEST_CONFIG_DISABLE GLOBALLY! == +// ================================================================================================= +#else // DOCTEST_CONFIG_DISABLE + +#define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name) \ + namespace /* NOLINT */ { \ + template \ + struct der : public base { \ + void f(); \ + }; \ + } \ + template \ + inline void der::f() + +#define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, name) \ + template \ + static inline void f() + +// for registering tests +#define DOCTEST_TEST_CASE(name) DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name) + +// for registering tests in classes +#define DOCTEST_TEST_CASE_CLASS(name) DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name) + +// for registering tests with a fixture +#define DOCTEST_TEST_CASE_FIXTURE(x, name) \ + DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(DOCTEST_ANON_CLASS_), x, DOCTEST_ANONYMOUS(DOCTEST_ANON_FUNC_), name) + +// for converting types to strings without the header and demangling +#define DOCTEST_TYPE_TO_STRING_AS(str, ...) static_assert(true, "") +#define DOCTEST_TYPE_TO_STRING(...) static_assert(true, "") + +// for typed tests +#define DOCTEST_TEST_CASE_TEMPLATE(name, type, ...) \ + template \ + inline void DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)() + +#define DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, type, id) \ + template \ + inline void DOCTEST_ANONYMOUS(DOCTEST_ANON_TMP_)() + +#define DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, ...) static_assert(true, "") +#define DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, ...) static_assert(true, "") + +// for subcases +#define DOCTEST_SUBCASE(name) + +// for generating value-parameterized test inputs +#define DOCTEST_GENERATE_IMPL(first, ...) (first) +#define DOCTEST_GENERATE(...) DOCTEST_GENERATE_IMPL(__VA_ARGS__, DOCTEST_EMPTY) + +// for a testsuite block +#define DOCTEST_TEST_SUITE(name) namespace // NOLINT + +// for starting a testsuite block +#define DOCTEST_TEST_SUITE_BEGIN(name) static_assert(true, "") + +// for ending a testsuite block +#define DOCTEST_TEST_SUITE_END using DOCTEST_ANONYMOUS(DOCTEST_ANON_FOR_SEMICOLON_) = int + +#define DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) \ + template \ + static inline doctest::String DOCTEST_ANONYMOUS(DOCTEST_ANON_TRANSLATOR_)(signature) + +#define DOCTEST_REGISTER_REPORTER(name, priority, reporter) +#define DOCTEST_REGISTER_LISTENER(name, priority, reporter) + +#define DOCTEST_INFO(...) (static_cast(0)) +#define DOCTEST_CAPTURE(x) (static_cast(0)) +#define DOCTEST_ADD_MESSAGE_AT(file, line, ...) (static_cast(0)) +#define DOCTEST_ADD_FAIL_CHECK_AT(file, line, ...) (static_cast(0)) +#define DOCTEST_ADD_FAIL_AT(file, line, ...) (static_cast(0)) +#define DOCTEST_MESSAGE(...) (static_cast(0)) +#define DOCTEST_FAIL_CHECK(...) (static_cast(0)) +#define DOCTEST_FAIL(...) (static_cast(0)) + +#if defined(DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED) && defined(DOCTEST_CONFIG_ASSERTS_RETURN_VALUES) + +#define DOCTEST_WARN(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_CHECK(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_REQUIRE(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_WARN_FALSE(...) [&] { return !(__VA_ARGS__); }() +#define DOCTEST_CHECK_FALSE(...) [&] { return !(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_FALSE(...) [&] { return !(__VA_ARGS__); }() + +#define DOCTEST_WARN_MESSAGE(cond, ...) [&] { return cond; }() +#define DOCTEST_CHECK_MESSAGE(cond, ...) [&] { return cond; }() +#define DOCTEST_REQUIRE_MESSAGE(cond, ...) [&] { return cond; }() +#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }() +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }() +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) [&] { return !(cond); }() + +namespace doctest { +namespace detail { +#define DOCTEST_RELATIONAL_OP(name, op) \ + template \ + bool name(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { \ + return lhs op rhs; \ + } + +DOCTEST_RELATIONAL_OP(eq, ==) +DOCTEST_RELATIONAL_OP(ne, !=) +DOCTEST_RELATIONAL_OP(lt, <) +DOCTEST_RELATIONAL_OP(gt, >) +DOCTEST_RELATIONAL_OP(le, <=) +DOCTEST_RELATIONAL_OP(ge, >=) +} // namespace detail +} // namespace doctest + +#define DOCTEST_WARN_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }() +#define DOCTEST_CHECK_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_EQ(...) [&] { return doctest::detail::eq(__VA_ARGS__); }() +#define DOCTEST_WARN_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }() +#define DOCTEST_CHECK_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_NE(...) [&] { return doctest::detail::ne(__VA_ARGS__); }() +#define DOCTEST_WARN_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }() +#define DOCTEST_CHECK_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_LT(...) [&] { return doctest::detail::lt(__VA_ARGS__); }() +#define DOCTEST_WARN_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }() +#define DOCTEST_CHECK_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_GT(...) [&] { return doctest::detail::gt(__VA_ARGS__); }() +#define DOCTEST_WARN_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }() +#define DOCTEST_CHECK_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_LE(...) [&] { return doctest::detail::le(__VA_ARGS__); }() +#define DOCTEST_WARN_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }() +#define DOCTEST_CHECK_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_GE(...) [&] { return doctest::detail::ge(__VA_ARGS__); }() +#define DOCTEST_WARN_UNARY(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_CHECK_UNARY(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_REQUIRE_UNARY(...) [&] { return __VA_ARGS__; }() +#define DOCTEST_WARN_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }() +#define DOCTEST_CHECK_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }() +#define DOCTEST_REQUIRE_UNARY_FALSE(...) [&] { return !(__VA_ARGS__); }() + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + +#define DOCTEST_WARN_THROWS_WITH(expr, with, ...) \ + [] { \ + static_assert(false, "Exception translation is not available when doctest is disabled."); \ + return false; \ + }() +#define DOCTEST_CHECK_THROWS_WITH(expr, with, ...) DOCTEST_WARN_THROWS_WITH(, , ) +#define DOCTEST_REQUIRE_THROWS_WITH(expr, with, ...) DOCTEST_WARN_THROWS_WITH(, , ) +#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(, , ) +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(, , ) +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(, , ) + +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH(, , ) +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH(, , ) +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH(, , ) +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(, , ) +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(, , ) +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH(, , ) + +// clang-format off +#define DOCTEST_WARN_THROWS(...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_CHECK_THROWS(...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_REQUIRE_THROWS(...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_WARN_THROWS_AS(expr, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_CHECK_THROWS_AS(expr, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_WARN_NOTHROW(...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() +#define DOCTEST_CHECK_NOTHROW(...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() +#define DOCTEST_REQUIRE_NOTHROW(...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return false; } catch (...) { return true; } }() +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) [&] { try { expr; } catch (__VA_ARGS__) { return true; } catch (...) { } return false; }() +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) [&] { try { __VA_ARGS__; return true; } catch (...) { return false; } }() +// clang-format on + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +#else // DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED + +#define DOCTEST_WARN(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_FALSE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_FALSE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_FALSE(...) DOCTEST_FUNC_EMPTY + +#define DOCTEST_WARN_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_FUNC_EMPTY + +#define DOCTEST_WARN_EQ(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_EQ(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_EQ(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_NE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_NE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_NE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_GT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_GT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_GT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_LT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_LT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_LT(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_GE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_GE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_GE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_LE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_LE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_LE(...) DOCTEST_FUNC_EMPTY + +#define DOCTEST_WARN_UNARY(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_UNARY(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_UNARY(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_UNARY_FALSE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_UNARY_FALSE(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_UNARY_FALSE(...) DOCTEST_FUNC_EMPTY + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + +#define DOCTEST_WARN_THROWS(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_NOTHROW(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_FUNC_EMPTY + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_FUNC_EMPTY + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +#endif // DOCTEST_CONFIG_EVALUATE_ASSERTS_EVEN_WHEN_DISABLED + +#endif // DOCTEST_CONFIG_DISABLE + +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS + +#ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +#define DOCTEST_EXCEPTION_EMPTY_FUNC DOCTEST_FUNC_EMPTY +#else // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS +#define DOCTEST_EXCEPTION_EMPTY_FUNC \ + [] { \ + static_assert( \ + false, \ + "Exceptions are disabled! " \ + "Use DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS if you want " \ + "to compile with exceptions disabled." \ + ); \ + return false; \ + }() + +#undef DOCTEST_REQUIRE +#undef DOCTEST_REQUIRE_FALSE +#undef DOCTEST_REQUIRE_MESSAGE +#undef DOCTEST_REQUIRE_FALSE_MESSAGE +#undef DOCTEST_REQUIRE_EQ +#undef DOCTEST_REQUIRE_NE +#undef DOCTEST_REQUIRE_GT +#undef DOCTEST_REQUIRE_LT +#undef DOCTEST_REQUIRE_GE +#undef DOCTEST_REQUIRE_LE +#undef DOCTEST_REQUIRE_UNARY +#undef DOCTEST_REQUIRE_UNARY_FALSE + +#define DOCTEST_REQUIRE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_FALSE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_MESSAGE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_FALSE_MESSAGE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_EQ DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_NE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_GT DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_LT DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_GE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_LE DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_UNARY DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_UNARY_FALSE DOCTEST_EXCEPTION_EMPTY_FUNC + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS + +#define DOCTEST_WARN_THROWS(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_AS(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_AS(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_AS(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_WITH(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_WITH(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_WITH(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_NOTHROW(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_NOTHROW(...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_NOTHROW(...) DOCTEST_EXCEPTION_EMPTY_FUNC + +#define DOCTEST_WARN_THROWS_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC +#define DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_EXCEPTION_EMPTY_FUNC + +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +// KEPT FOR BACKWARDS COMPATIBILITY - FORWARDING TO THE RIGHT MACROS +#define DOCTEST_FAST_WARN_EQ DOCTEST_WARN_EQ +#define DOCTEST_FAST_CHECK_EQ DOCTEST_CHECK_EQ +#define DOCTEST_FAST_REQUIRE_EQ DOCTEST_REQUIRE_EQ +#define DOCTEST_FAST_WARN_NE DOCTEST_WARN_NE +#define DOCTEST_FAST_CHECK_NE DOCTEST_CHECK_NE +#define DOCTEST_FAST_REQUIRE_NE DOCTEST_REQUIRE_NE +#define DOCTEST_FAST_WARN_GT DOCTEST_WARN_GT +#define DOCTEST_FAST_CHECK_GT DOCTEST_CHECK_GT +#define DOCTEST_FAST_REQUIRE_GT DOCTEST_REQUIRE_GT +#define DOCTEST_FAST_WARN_LT DOCTEST_WARN_LT +#define DOCTEST_FAST_CHECK_LT DOCTEST_CHECK_LT +#define DOCTEST_FAST_REQUIRE_LT DOCTEST_REQUIRE_LT +#define DOCTEST_FAST_WARN_GE DOCTEST_WARN_GE +#define DOCTEST_FAST_CHECK_GE DOCTEST_CHECK_GE +#define DOCTEST_FAST_REQUIRE_GE DOCTEST_REQUIRE_GE +#define DOCTEST_FAST_WARN_LE DOCTEST_WARN_LE +#define DOCTEST_FAST_CHECK_LE DOCTEST_CHECK_LE +#define DOCTEST_FAST_REQUIRE_LE DOCTEST_REQUIRE_LE + +#define DOCTEST_FAST_WARN_UNARY DOCTEST_WARN_UNARY +#define DOCTEST_FAST_CHECK_UNARY DOCTEST_CHECK_UNARY +#define DOCTEST_FAST_REQUIRE_UNARY DOCTEST_REQUIRE_UNARY +#define DOCTEST_FAST_WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE +#define DOCTEST_FAST_CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE +#define DOCTEST_FAST_REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE + +#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, __VA_ARGS__) + +// BDD style macros +// clang-format off +#define DOCTEST_SCENARIO(name) DOCTEST_TEST_CASE(" Scenario: " name) +#define DOCTEST_SCENARIO_CLASS(name) DOCTEST_TEST_CASE_CLASS(" Scenario: " name) +#define DOCTEST_SCENARIO_METHOD(x, name) DOCTEST_TEST_CASE_FIXTURE(x, " Scenario: " name) +#define DOCTEST_SCENARIO_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(" Scenario: " name, T, __VA_ARGS__) +#define DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(" Scenario: " name, T, id) + +#define DOCTEST_GIVEN(name) DOCTEST_SUBCASE(" Given: " name) +#define DOCTEST_AND_GIVEN(name) DOCTEST_SUBCASE(" And: " name) +#define DOCTEST_WHEN(name) DOCTEST_SUBCASE(" When: " name) +#define DOCTEST_AND_WHEN(name) DOCTEST_SUBCASE(" And: " name) +#define DOCTEST_THEN(name) DOCTEST_SUBCASE(" Then: " name) +#define DOCTEST_AND_THEN(name) DOCTEST_SUBCASE(" And: " name) +// clang-format on + +// == SHORT VERSIONS OF THE MACROS +#ifndef DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES + +#define TEST_CASE(name) DOCTEST_TEST_CASE(name) +#define TEST_CASE_CLASS(name) DOCTEST_TEST_CASE_CLASS(name) +#define TEST_CASE_FIXTURE(x, name) DOCTEST_TEST_CASE_FIXTURE(x, name) +#define TYPE_TO_STRING_AS(str, ...) DOCTEST_TYPE_TO_STRING_AS(str, __VA_ARGS__) +#define TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING(__VA_ARGS__) +#define TEST_CASE_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(name, T, __VA_ARGS__) +#define TEST_CASE_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, T, id) +#define TEST_CASE_TEMPLATE_INVOKE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, __VA_ARGS__) +#define TEST_CASE_TEMPLATE_APPLY(id, ...) DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, __VA_ARGS__) +#define SUBCASE(name) DOCTEST_SUBCASE(name) +#define GENERATE(...) DOCTEST_GENERATE(__VA_ARGS__) +#define TEST_SUITE(decorators) DOCTEST_TEST_SUITE(decorators) +#define TEST_SUITE_BEGIN(name) DOCTEST_TEST_SUITE_BEGIN(name) +#define TEST_SUITE_END DOCTEST_TEST_SUITE_END +#define REGISTER_EXCEPTION_TRANSLATOR(signature) DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature) +#define REGISTER_REPORTER(name, priority, reporter) DOCTEST_REGISTER_REPORTER(name, priority, reporter) +#define REGISTER_LISTENER(name, priority, reporter) DOCTEST_REGISTER_LISTENER(name, priority, reporter) +#define INFO(...) DOCTEST_INFO(__VA_ARGS__) +#define CAPTURE(x) DOCTEST_CAPTURE(x) +#define ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_MESSAGE_AT(file, line, __VA_ARGS__) +#define ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_FAIL_CHECK_AT(file, line, __VA_ARGS__) +#define ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_FAIL_AT(file, line, __VA_ARGS__) +#define MESSAGE(...) DOCTEST_MESSAGE(__VA_ARGS__) +#define FAIL_CHECK(...) DOCTEST_FAIL_CHECK(__VA_ARGS__) +#define FAIL(...) DOCTEST_FAIL(__VA_ARGS__) +#define TO_LVALUE(...) DOCTEST_TO_LVALUE(__VA_ARGS__) + +#define WARN(...) DOCTEST_WARN(__VA_ARGS__) +#define WARN_FALSE(...) DOCTEST_WARN_FALSE(__VA_ARGS__) +#define WARN_THROWS(...) DOCTEST_WARN_THROWS(__VA_ARGS__) +#define WARN_THROWS_AS(expr, ...) DOCTEST_WARN_THROWS_AS(expr, __VA_ARGS__) +#define WARN_THROWS_WITH(expr, ...) DOCTEST_WARN_THROWS_WITH(expr, __VA_ARGS__) +#define WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_WARN_THROWS_WITH_AS(expr, with, __VA_ARGS__) +#define WARN_NOTHROW(...) DOCTEST_WARN_NOTHROW(__VA_ARGS__) +#define CHECK(...) DOCTEST_CHECK(__VA_ARGS__) +#define CHECK_FALSE(...) DOCTEST_CHECK_FALSE(__VA_ARGS__) +#define CHECK_THROWS(...) DOCTEST_CHECK_THROWS(__VA_ARGS__) +#define CHECK_THROWS_AS(expr, ...) DOCTEST_CHECK_THROWS_AS(expr, __VA_ARGS__) +#define CHECK_THROWS_WITH(expr, ...) DOCTEST_CHECK_THROWS_WITH(expr, __VA_ARGS__) +#define CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_AS(expr, with, __VA_ARGS__) +#define CHECK_NOTHROW(...) DOCTEST_CHECK_NOTHROW(__VA_ARGS__) +#define REQUIRE(...) DOCTEST_REQUIRE(__VA_ARGS__) +#define REQUIRE_FALSE(...) DOCTEST_REQUIRE_FALSE(__VA_ARGS__) +#define REQUIRE_THROWS(...) DOCTEST_REQUIRE_THROWS(__VA_ARGS__) +#define REQUIRE_THROWS_AS(expr, ...) DOCTEST_REQUIRE_THROWS_AS(expr, __VA_ARGS__) +#define REQUIRE_THROWS_WITH(expr, ...) DOCTEST_REQUIRE_THROWS_WITH(expr, __VA_ARGS__) +#define REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, __VA_ARGS__) +#define REQUIRE_NOTHROW(...) DOCTEST_REQUIRE_NOTHROW(__VA_ARGS__) + +// clang-format off +#define WARN_MESSAGE(cond, ...) DOCTEST_WARN_MESSAGE(cond, __VA_ARGS__) +#define WARN_FALSE_MESSAGE(cond, ...) DOCTEST_WARN_FALSE_MESSAGE(cond, __VA_ARGS__) +#define WARN_THROWS_MESSAGE(expr, ...) DOCTEST_WARN_THROWS_MESSAGE(expr, __VA_ARGS__) +#define WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) +#define WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) +#define WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) +#define WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_WARN_NOTHROW_MESSAGE(expr, __VA_ARGS__) +#define CHECK_MESSAGE(cond, ...) DOCTEST_CHECK_MESSAGE(cond, __VA_ARGS__) +#define CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_CHECK_FALSE_MESSAGE(cond, __VA_ARGS__) +#define CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_CHECK_THROWS_MESSAGE(expr, __VA_ARGS__) +#define CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) +#define CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) +#define CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) +#define CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_CHECK_NOTHROW_MESSAGE(expr, __VA_ARGS__) +#define REQUIRE_MESSAGE(cond, ...) DOCTEST_REQUIRE_MESSAGE(cond, __VA_ARGS__) +#define REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_REQUIRE_FALSE_MESSAGE(cond, __VA_ARGS__) +#define REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_REQUIRE_THROWS_MESSAGE(expr, __VA_ARGS__) +#define REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__) +#define REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__) +#define REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__) +#define REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, __VA_ARGS__) +// clang-format on + +#define SCENARIO(name) DOCTEST_SCENARIO(name) +#define SCENARIO_METHOD(x, name) DOCTEST_SCENARIO_METHOD(x, name) +#define SCENARIO_CLASS(name) DOCTEST_SCENARIO_CLASS(name) +#define SCENARIO_TEMPLATE(name, T, ...) DOCTEST_SCENARIO_TEMPLATE(name, T, __VA_ARGS__) +#define SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id) +#define GIVEN(name) DOCTEST_GIVEN(name) +#define AND_GIVEN(name) DOCTEST_AND_GIVEN(name) +#define WHEN(name) DOCTEST_WHEN(name) +#define AND_WHEN(name) DOCTEST_AND_WHEN(name) +#define THEN(name) DOCTEST_THEN(name) +#define AND_THEN(name) DOCTEST_AND_THEN(name) + +#define WARN_EQ(...) DOCTEST_WARN_EQ(__VA_ARGS__) +#define CHECK_EQ(...) DOCTEST_CHECK_EQ(__VA_ARGS__) +#define REQUIRE_EQ(...) DOCTEST_REQUIRE_EQ(__VA_ARGS__) +#define WARN_NE(...) DOCTEST_WARN_NE(__VA_ARGS__) +#define CHECK_NE(...) DOCTEST_CHECK_NE(__VA_ARGS__) +#define REQUIRE_NE(...) DOCTEST_REQUIRE_NE(__VA_ARGS__) +#define WARN_GT(...) DOCTEST_WARN_GT(__VA_ARGS__) +#define CHECK_GT(...) DOCTEST_CHECK_GT(__VA_ARGS__) +#define REQUIRE_GT(...) DOCTEST_REQUIRE_GT(__VA_ARGS__) +#define WARN_LT(...) DOCTEST_WARN_LT(__VA_ARGS__) +#define CHECK_LT(...) DOCTEST_CHECK_LT(__VA_ARGS__) +#define REQUIRE_LT(...) DOCTEST_REQUIRE_LT(__VA_ARGS__) +#define WARN_GE(...) DOCTEST_WARN_GE(__VA_ARGS__) +#define CHECK_GE(...) DOCTEST_CHECK_GE(__VA_ARGS__) +#define REQUIRE_GE(...) DOCTEST_REQUIRE_GE(__VA_ARGS__) +#define WARN_LE(...) DOCTEST_WARN_LE(__VA_ARGS__) +#define CHECK_LE(...) DOCTEST_CHECK_LE(__VA_ARGS__) +#define REQUIRE_LE(...) DOCTEST_REQUIRE_LE(__VA_ARGS__) +#define WARN_UNARY(...) DOCTEST_WARN_UNARY(__VA_ARGS__) +#define CHECK_UNARY(...) DOCTEST_CHECK_UNARY(__VA_ARGS__) +#define REQUIRE_UNARY(...) DOCTEST_REQUIRE_UNARY(__VA_ARGS__) +#define WARN_UNARY_FALSE(...) DOCTEST_WARN_UNARY_FALSE(__VA_ARGS__) +#define CHECK_UNARY_FALSE(...) DOCTEST_CHECK_UNARY_FALSE(__VA_ARGS__) +#define REQUIRE_UNARY_FALSE(...) DOCTEST_REQUIRE_UNARY_FALSE(__VA_ARGS__) + +// KEPT FOR BACKWARDS COMPATIBILITY +#define FAST_WARN_EQ(...) DOCTEST_FAST_WARN_EQ(__VA_ARGS__) +#define FAST_CHECK_EQ(...) DOCTEST_FAST_CHECK_EQ(__VA_ARGS__) +#define FAST_REQUIRE_EQ(...) DOCTEST_FAST_REQUIRE_EQ(__VA_ARGS__) +#define FAST_WARN_NE(...) DOCTEST_FAST_WARN_NE(__VA_ARGS__) +#define FAST_CHECK_NE(...) DOCTEST_FAST_CHECK_NE(__VA_ARGS__) +#define FAST_REQUIRE_NE(...) DOCTEST_FAST_REQUIRE_NE(__VA_ARGS__) +#define FAST_WARN_GT(...) DOCTEST_FAST_WARN_GT(__VA_ARGS__) +#define FAST_CHECK_GT(...) DOCTEST_FAST_CHECK_GT(__VA_ARGS__) +#define FAST_REQUIRE_GT(...) DOCTEST_FAST_REQUIRE_GT(__VA_ARGS__) +#define FAST_WARN_LT(...) DOCTEST_FAST_WARN_LT(__VA_ARGS__) +#define FAST_CHECK_LT(...) DOCTEST_FAST_CHECK_LT(__VA_ARGS__) +#define FAST_REQUIRE_LT(...) DOCTEST_FAST_REQUIRE_LT(__VA_ARGS__) +#define FAST_WARN_GE(...) DOCTEST_FAST_WARN_GE(__VA_ARGS__) +#define FAST_CHECK_GE(...) DOCTEST_FAST_CHECK_GE(__VA_ARGS__) +#define FAST_REQUIRE_GE(...) DOCTEST_FAST_REQUIRE_GE(__VA_ARGS__) +#define FAST_WARN_LE(...) DOCTEST_FAST_WARN_LE(__VA_ARGS__) +#define FAST_CHECK_LE(...) DOCTEST_FAST_CHECK_LE(__VA_ARGS__) +#define FAST_REQUIRE_LE(...) DOCTEST_FAST_REQUIRE_LE(__VA_ARGS__) + +#define FAST_WARN_UNARY(...) DOCTEST_FAST_WARN_UNARY(__VA_ARGS__) +#define FAST_CHECK_UNARY(...) DOCTEST_FAST_CHECK_UNARY(__VA_ARGS__) +#define FAST_REQUIRE_UNARY(...) DOCTEST_FAST_REQUIRE_UNARY(__VA_ARGS__) +#define FAST_WARN_UNARY_FALSE(...) DOCTEST_FAST_WARN_UNARY_FALSE(__VA_ARGS__) +#define FAST_CHECK_UNARY_FALSE(...) DOCTEST_FAST_CHECK_UNARY_FALSE(__VA_ARGS__) +#define FAST_REQUIRE_UNARY_FALSE(...) DOCTEST_FAST_REQUIRE_UNARY_FALSE(__VA_ARGS__) + +#define TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, __VA_ARGS__) + +#endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_PARTS_PUBLIC_MACROS + +DOCTEST_SUPPRESS_PUBLIC_WARNINGS_POP + +#endif // DOCTEST_LIBRARY_INCLUDED + +#if defined(DOCTEST_CONFIG_IMPLEMENT) && !defined(DOCTEST_LIBRARY_IMPLEMENTATION) + +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-macros") +#define DOCTEST_LIBRARY_IMPLEMENTATION +DOCTEST_CLANG_SUPPRESS_WARNING_POP + +#ifndef DOCTEST_PARTS_PRIVATE_PRELUDE +#define DOCTEST_PARTS_PRIVATE_PRELUDE + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN + +// required includes - will go only in one translation unit! +#include +#include +#include +// borland (Embarcadero) compiler requires math.h and not cmath - +// https://github.com/doctest/doctest/pull/37 +#ifdef __BORLANDC__ +#include +#endif // __BORLANDC__ +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM +#include +#endif // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM +#include +#include +#include +#ifndef DOCTEST_CONFIG_NO_MULTITHREADING +#include +#include +#define DOCTEST_DECLARE_MUTEX(name) std::mutex name; +#define DOCTEST_DECLARE_STATIC_MUTEX(name) static DOCTEST_DECLARE_MUTEX(name) +#define DOCTEST_LOCK_MUTEX(name) const std::lock_guard DOCTEST_ANONYMOUS(DOCTEST_ANON_LOCK_)(name); +#else // DOCTEST_CONFIG_NO_MULTITHREADING +#define DOCTEST_DECLARE_MUTEX(name) +#define DOCTEST_DECLARE_STATIC_MUTEX(name) +#define DOCTEST_LOCK_MUTEX(name) +#endif // DOCTEST_CONFIG_NO_MULTITHREADING +#include +#include +#include +#include +#include +#if defined(DOCTEST_CONFIG_POSIX_SIGNALS) || defined(DOCTEST_CONFIG_WINDOWS_SEH) +#include +#endif // DOCTEST_CONFIG_POSIX_SIGNALS +#include +#include +#include +#include + +#ifdef DOCTEST_PLATFORM_MAC +#include +#include +#include +#endif // DOCTEST_PLATFORM_MAC + +#ifdef DOCTEST_PLATFORM_WINDOWS + +// defines for a leaner windows.h +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#define DOCTEST_UNDEF_WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#ifndef NOMINMAX +#define NOMINMAX +#define DOCTEST_UNDEF_NOMINMAX +#endif // NOMINMAX + +// not sure what AfxWin.h is for - here I do what Catch does +#ifdef __AFXDLL +#include +#else +#include +#endif +#include + +#ifdef DOCTEST_UNDEF_WIN32_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#undef DOCTEST_UNDEF_WIN32_LEAN_AND_MEAN +#endif // DOCTEST_UNDEF_WIN32_LEAN_AND_MEAN +#ifdef DOCTEST_UNDEF_NOMINMAX +#undef NOMINMAX +#undef DOCTEST_UNDEF_NOMINMAX +#endif // DOCTEST_UNDEF_NOMINMAX + +#else // DOCTEST_PLATFORM_WINDOWS + +#include +#include + +#endif // DOCTEST_PLATFORM_WINDOWS + +// this is a fix for https://github.com/doctest/doctest/issues/348 +// https://mail.gnome.org/archives/xml/2012-January/msg00000.html +#if !defined(HAVE_UNISTD_H) && !defined(STDOUT_FILENO) +#define STDOUT_FILENO fileno(stdout) +#endif // HAVE_UNISTD_H + +DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END + +// counts the number of elements in a C array +#define DOCTEST_COUNTOF(x) (sizeof(x) / sizeof(x[0])) + +#ifdef DOCTEST_CONFIG_DISABLE +#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_disabled +#else // DOCTEST_CONFIG_DISABLE +#define DOCTEST_BRANCH_ON_DISABLED(if_disabled, if_not_disabled) if_not_disabled +#endif // DOCTEST_CONFIG_DISABLE + +#ifndef DOCTEST_THREAD_LOCAL +#if defined(DOCTEST_CONFIG_NO_MULTITHREADING) || DOCTEST_MSVC && (DOCTEST_MSVC < DOCTEST_COMPILER(19, 0, 0)) +#define DOCTEST_THREAD_LOCAL +#else // DOCTEST_MSVC +#define DOCTEST_THREAD_LOCAL thread_local +#endif // DOCTEST_MSVC +#endif // DOCTEST_THREAD_LOCAL + +#ifndef DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES +#define DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES 32 +#endif + +#ifndef DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE +#define DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE 64 +#endif + +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +#define DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS +#endif + +#ifndef DOCTEST_CDECL +#define DOCTEST_CDECL __cdecl +#endif + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_PRELUDE +#ifndef DOCTEST_PARTS_PRIVATE_CONTEXT_STATE +#define DOCTEST_PARTS_PRIVATE_CONTEXT_STATE + +#ifndef DOCTEST_PARTS_PRIVATE_TIMER +#define DOCTEST_PARTS_PRIVATE_TIMER + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +namespace timer_large_integer { + +#if defined(DOCTEST_PLATFORM_WINDOWS) +using type = ULONGLONG; +#else // DOCTEST_PLATFORM_WINDOWS +using type = std::uint64_t; +#endif // DOCTEST_PLATFORM_WINDOWS +} // namespace timer_large_integer + +using ticks_t = timer_large_integer::type; + +ticks_t getCurrentTicks(); + +struct Timer { + void start(); + unsigned int getElapsedMicroseconds() const; + double getElapsedSeconds() const; + +private: + ticks_t m_ticks = 0; +}; + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_TIMER +#ifndef DOCTEST_PARTS_PRIVATE_ATOMIC +#define DOCTEST_PARTS_PRIVATE_ATOMIC + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +#ifdef DOCTEST_CONFIG_NO_MULTITHREADING +template +using Atomic = T; +#else // DOCTEST_CONFIG_NO_MULTITHREADING +template +using Atomic = std::atomic; +#endif // DOCTEST_CONFIG_NO_MULTITHREADING + +#if defined(DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS) || defined(DOCTEST_CONFIG_NO_MULTITHREADING) +template +using MultiLaneAtomic = Atomic; +#else // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS +// Provides a multilane implementation of an atomic variable that supports add, sub, load, +// store. Instead of using a single atomic variable, this splits up into multiple ones, +// each sitting on a separate cache line. The goal is to provide a speedup when most +// operations are modifying. It achieves this with two properties: +// +// * Multiple atomics are used, so chance of congestion from the same atomic is reduced. +// * Each atomic sits on a separate cache line, so false sharing is reduced. +// +// The disadvantage is that there is a small overhead due to the use of TLS, and load/store +// is slower because all atomics have to be accessed. +template +class MultiLaneAtomic { + struct CacheLineAlignedAtomic { + Atomic atomic{}; + char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(Atomic)]; + }; + CacheLineAlignedAtomic m_atomics[DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES]; + + static_assert( + sizeof(CacheLineAlignedAtomic) == DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE, + "guarantee one atomic takes exactly one cache line" + ); + +public: + T operator++() DOCTEST_NOEXCEPT { + return fetch_add(1) + 1; + } + + T operator++(int) DOCTEST_NOEXCEPT { // NOLINT(cert-dcl21-cpp) + return fetch_add(1); + } + + T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { + return myAtomic().fetch_add(arg, order); + } + + T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { + return myAtomic().fetch_sub(arg, order); + } + + operator T() const DOCTEST_NOEXCEPT { + return load(); + } + + T load(std::memory_order order = std::memory_order_seq_cst) const DOCTEST_NOEXCEPT { + auto result = T(); + for (const auto &c: m_atomics) { + result += c.atomic.load(order); + } + return result; + } + + // NOLINTNEXTLINE(cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator) + T operator=(T desired) DOCTEST_NOEXCEPT { + store(desired); + return desired; + } + + void store(T desired, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT { + // first value becomes desired", all others become 0. + for (auto &c: m_atomics) { + c.atomic.store(desired, order); + desired = {}; + } + } + +private: + // Each thread has a different atomic that it operates on. If more than NumLanes threads + // use this, some will use the same atomic. So performance will degrade a bit, but still + // everything will work. + // + // The logic here is a bit tricky. The call should be as fast as possible, so that there + // is minimal to no overhead in determining the correct atomic for the current thread. + // + // 1. A global static counter laneCounter counts continuously up. + // 2. Each successive thread will use modulo operation of that counter so it gets an atomic + // assigned in a round-robin fashion. + // 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with + // little overhead. + Atomic &myAtomic() DOCTEST_NOEXCEPT { + static Atomic laneCounter; + DOCTEST_THREAD_LOCAL size_t tlsLaneIdx = laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES; + + return m_atomics[tlsLaneIdx].atomic; + } +}; +#endif // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_ATOMIC +#ifndef DOCTEST_PARTS_PRIVATE_TRAVERSAL +#define DOCTEST_PARTS_PRIVATE_TRAVERSAL + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +struct DecisionPoint { + // Number of branches available at this depth for the current traversal path. + size_t branch_count = 0; + // Encountered sibling subcases in source order for subcase decision points. + std::vector subcases; +}; + +class TraversalState { +public: + size_t activeSubcaseDepth() const { + return m_activeSubcaseDepth; + } + + void resetForTestCase(); + void resetForRun(); + bool advance(); + bool tryEnterSubcase(const SubcaseSignature &signature); + void leaveSubcase(); + size_t unwindActiveSubcases(); + size_t acquireGeneratorIndex(size_t count); + +private: + // decisionPath is the selected traversal prefix; discoveredDecisionPath is rebuilt + // on each rerun to describe the branches encountered at each depth. + std::vector m_discoveredDecisionPath; + std::vector m_decisionPath; + size_t m_decisionDepth = 0; + std::vector m_enteredSubcaseDepths; + size_t m_activeSubcaseDepth = 0; + + DecisionPoint &ensureDecisionPointAtCurrentDepth(); +}; + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_TRAVERSAL + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +// this holds both parameters from the command line and runtime data for tests +struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats { + MultiLaneAtomic numAssertsCurrentTest_atomic; + MultiLaneAtomic numAssertsFailedCurrentTest_atomic; + + std::vector> filters = decltype(filters)(9); // 9 different filters + + std::vector reporters_currently_used; + + assert_handler ah = nullptr; + + Timer timer; + + std::vector stringifiedContexts; // logging from INFO() due to an exception + + // Backtrack traversal state shared by SUBCASE and GENERATE. + TraversalState traversal; + Atomic shouldLogCurrentException; + + void resetRunData(); + + void finalizeTestCaseData(); +}; + +extern ContextState *g_cs; + +// used to avoid locks for the debug output +// TODO: figure out if this is indeed necessary/correct - seems like either there still +// could be a race or that there wouldn't be a race even if using the context directly +extern DOCTEST_THREAD_LOCAL bool g_no_colors; + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_CONTEXT_STATE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { + +using detail::g_cs; + +AssertData::AssertData( + assertType::Enum at, + const char *file, + int line, + const char *expr, + const char *exception_type, + const StringContains &exception_string +) + : m_test_case(g_cs->currentTest), + m_at(at), + m_file(file), + m_line(line), + m_expr(expr), + m_failed(true), + m_threw(false), + m_threw_as(false), + m_exception_type(exception_type), + m_exception_string(exception_string) { +#if DOCTEST_MSVC + if (m_expr[0] == ' ') // this happens when variadic macros are disabled under MSVC + ++m_expr; +#endif // MSVC +} + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +ExpressionDecomposer::ExpressionDecomposer(assertType::Enum at) + : m_at(at) {} + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP +#ifndef DOCTEST_PARTS_PRIVATE_REPORTER +#define DOCTEST_PARTS_PRIVATE_REPORTER + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { +// the int (priority) is part of the key for automatic sorting - sadly one can register a +// reporter with a duplicate name and a different priority but hopefully that won't happen often :| +using reporterMap = std::map, detail::reporterCreatorFunc>; + +reporterMap &getReporters() noexcept; +reporterMap &getListeners() noexcept; +} // namespace detail + +#define DOCTEST_ITERATE_THROUGH_REPORTERS(function, ...) \ + for (auto &curr_rep: g_cs->reporters_currently_used) \ + curr_rep->function(__VA_ARGS__) + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_REPORTER +#ifndef DOCTEST_PARTS_PRIVATE_ASSERT_HANDLER +#define DOCTEST_PARTS_PRIVATE_ASSERT_HANDLER + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +void addAssert(assertType::Enum at); + +void addFailedAssert(assertType::Enum at); + +#if defined(DOCTEST_CONFIG_POSIX_SIGNALS) || defined(DOCTEST_CONFIG_WINDOWS_SEH) +void reportFatal(const std::string &message); +#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_ASSERT_HANDLER + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +void addAssert(assertType::Enum at) { + if ((at & assertType::is_warn) == 0) + g_cs->numAssertsCurrentTest_atomic++; +} + +void addFailedAssert(assertType::Enum at) { + if ((at & assertType::is_warn) == 0) + g_cs->numAssertsFailedCurrentTest_atomic++; +} + +#if defined(DOCTEST_CONFIG_POSIX_SIGNALS) || defined(DOCTEST_CONFIG_WINDOWS_SEH) +void reportFatal(const std::string &message) { + g_cs->failure_flags |= TestCaseFailureReason::Crash; + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, {message.c_str(), true}); + + for (size_t i = g_cs->traversal.unwindActiveSubcases(); i > 0; --i) + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); + g_cs->finalizeTestCaseData(); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs); +} +#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + +void failed_out_of_a_testing_context(const AssertData &ad) { + if (g_cs->ah) + g_cs->ah(ad); + else + std::abort(); +} + +bool decomp_assert(assertType::Enum at, const char *file, int line, const char *expr, const Result &result) { + const bool failed = !result.m_passed; + + // ################################################################################### + // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK FOR THE FAILING ASSERT + // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED + // ################################################################################### + DOCTEST_ASSERT_OUT_OF_TESTS(result.m_decomp); + DOCTEST_ASSERT_IN_TESTS(result.m_decomp); + return !failed; +} + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +MessageBuilder::MessageBuilder(const char *file, int line, assertType::Enum severity) { + m_stream = tlssPush(); + m_file = file; + m_line = line; + m_severity = severity; +} + +MessageBuilder::~MessageBuilder() noexcept(false) { + if (!logged) + tlssPop(); +} + +bool MessageBuilder::log() { + if (!logged) { + m_string = tlssPop(); + logged = true; + } + + DOCTEST_ITERATE_THROUGH_REPORTERS(log_message, *this); + + const bool isWarn = m_severity & assertType::is_warn; + + // warn is just a message in this context so we don't treat it as an assert + if (!isWarn) { + addAssert(m_severity); + addFailedAssert(m_severity); + } + + return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn && + (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger +} + +void MessageBuilder::react() { + if (m_severity & assertType::is_require) + throwException(); +} + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP +#ifndef DOCTEST_PARTS_PRIVATE_EXCEPTION_TRANSLATOR +#define DOCTEST_PARTS_PRIVATE_EXCEPTION_TRANSLATOR + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +std::vector &getExceptionTranslators() noexcept; +String translateActiveException() noexcept; + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_EXCEPTION_TRANSLATOR + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +Result::Result(bool passed, const String &decomposition) + : m_passed(passed), m_decomp(decomposition) {} + +ResultBuilder::ResultBuilder( + assertType::Enum at, + const char *file, + int line, + const char *expr, + const char *exception_type, + const String &exception_string +) + : AssertData(at, file, line, expr, exception_type, exception_string) { +} // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + +ResultBuilder::ResultBuilder( + assertType::Enum at, + const char *file, + int line, + const char *expr, + const char *exception_type, + const Contains &exception_string +) + : AssertData(at, file, line, expr, exception_type, exception_string) {} + +void ResultBuilder::setResult(const Result &res) { + m_decomp = res.m_decomp; + m_failed = !res.m_passed; +} + +void ResultBuilder::translateException() { + m_threw = true; + m_exception = translateActiveException(); +} + +bool ResultBuilder::log() { + if (m_at & assertType::is_throws) { + m_failed = !m_threw; + } else if ((m_at & assertType::is_throws_as) && (m_at & assertType::is_throws_with)) { + m_failed = !m_threw_as || !m_exception_string.check(m_exception); + } else if (m_at & assertType::is_throws_as) { + m_failed = !m_threw_as; + } else if (m_at & assertType::is_throws_with) { + m_failed = !m_exception_string.check(m_exception); + } else if (m_at & assertType::is_nothrow) { + m_failed = m_threw; + } + + if (m_exception.size()) + m_exception = "\"" + m_exception + "\""; + + if (is_running_in_test) { + addAssert(m_at); + DOCTEST_ITERATE_THROUGH_REPORTERS(log_assert, *this); + + if (m_failed) + addFailedAssert(m_at); + } else if (m_failed) { + failed_out_of_a_testing_context(*this); + } + + return m_failed && isDebuggerActive() && !getContextOptions()->no_breaks && + (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger +} + +void ResultBuilder::react() const { + if (m_failed && checkIfShouldThrow(m_at)) + throwException(); +} + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP +#ifndef DOCTEST_PARTS_PRIVATE_EXCEPTIONS +#define DOCTEST_PARTS_PRIVATE_EXCEPTIONS + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +namespace doctest { +namespace detail { + +template +DOCTEST_NORETURN void throw_exception(const Ex &e) { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + throw e; +#else // DOCTEST_CONFIG_NO_EXCEPTIONS +#ifdef DOCTEST_CONFIG_HANDLE_EXCEPTION + DOCTEST_CONFIG_HANDLE_EXCEPTION(e); +#else // DOCTEST_CONFIG_HANDLE_EXCEPTION +#ifndef DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + std::cerr << "doctest will terminate because it needed to throw an exception.\n" + << "The message was: " << e.what() << '\n'; +#endif // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM +#endif // DOCTEST_CONFIG_HANDLE_EXCEPTION + std::terminate(); +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS +} + +#ifndef DOCTEST_INTERNAL_ERROR +#define DOCTEST_INTERNAL_ERROR(msg) \ + detail::throw_exception(std::logic_error(__FILE__ ":" DOCTEST_TOSTR(__LINE__) ": Internal doctest error: " msg)) +#endif // DOCTEST_INTERNAL_ERROR +} // namespace detail + +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_EXCEPTIONS + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +namespace doctest { + +const char *assertString(assertType::Enum at) { + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4061) // enum 'x' in switch of enum 'y' is not explicitly handled +#define DOCTEST_GENERATE_ASSERT_TYPE_CASE(assert_type) \ + case assertType::DT_##assert_type: return #assert_type +#define DOCTEST_GENERATE_ASSERT_TYPE_CASES(assert_type) \ + DOCTEST_GENERATE_ASSERT_TYPE_CASE(WARN_##assert_type); \ + DOCTEST_GENERATE_ASSERT_TYPE_CASE(CHECK_##assert_type); \ + DOCTEST_GENERATE_ASSERT_TYPE_CASE(REQUIRE_##assert_type) + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH + DOCTEST_CLANG_SUPPRESS_WARNING("-Wswitch-enum") + DOCTEST_GCC_SUPPRESS_WARNING_PUSH + DOCTEST_GCC_SUPPRESS_WARNING("-Wswitch-enum") + switch (at) { + DOCTEST_GENERATE_ASSERT_TYPE_CASE(WARN); + DOCTEST_GENERATE_ASSERT_TYPE_CASE(CHECK); + DOCTEST_GENERATE_ASSERT_TYPE_CASE(REQUIRE); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(FALSE); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(THROWS); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(THROWS_AS); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(THROWS_WITH); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(THROWS_WITH_AS); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(NOTHROW); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(EQ); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(NE); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(GT); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(LT); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(GE); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(LE); + + DOCTEST_GENERATE_ASSERT_TYPE_CASES(UNARY); + DOCTEST_GENERATE_ASSERT_TYPE_CASES(UNARY_FALSE); + + default: DOCTEST_INTERNAL_ERROR("Tried stringifying invalid assert type!"); + } + DOCTEST_CLANG_SUPPRESS_WARNING_POP + DOCTEST_GCC_SUPPRESS_WARNING_POP + DOCTEST_MSVC_SUPPRESS_WARNING_POP +} + +const char *failureString(assertType::Enum at) { + if (at & assertType::is_warn) + return "WARNING"; + if (at & assertType::is_check) + return "ERROR"; + if (at & assertType::is_require) + return "FATAL ERROR"; + return ""; +} + +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#if !defined(DOCTEST_CONFIG_COLORS_NONE) +#if !defined(DOCTEST_CONFIG_COLORS_WINDOWS) && !defined(DOCTEST_CONFIG_COLORS_ANSI) +#ifdef DOCTEST_PLATFORM_WINDOWS +#define DOCTEST_CONFIG_COLORS_WINDOWS +#else // linux +#define DOCTEST_CONFIG_COLORS_ANSI +#endif // platform +#endif // DOCTEST_CONFIG_COLORS_WINDOWS && DOCTEST_CONFIG_COLORS_ANSI +#endif // DOCTEST_CONFIG_COLORS_NONE + +namespace doctest { + +namespace detail { +void color_to_stream(std::ostream &, Color::Enum) DOCTEST_BRANCH_ON_DISABLED({}, ;) +} // namespace detail + +namespace Color { +std::ostream &operator<<(std::ostream &s, Color::Enum code) { + detail::color_to_stream(s, code); + return s; +} +} // namespace Color + +#ifndef DOCTEST_CONFIG_DISABLE +namespace detail { +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") +void color_to_stream(std::ostream &s, Color::Enum code) { + static_cast(s); // for DOCTEST_CONFIG_COLORS_NONE or DOCTEST_CONFIG_COLORS_WINDOWS + static_cast(code); // for DOCTEST_CONFIG_COLORS_NONE +#ifdef DOCTEST_CONFIG_COLORS_ANSI + if (g_no_colors || (isatty(STDOUT_FILENO) == false && getContextOptions()->force_colors == false)) + return; + + auto col = ""; // NOLINT(clang-analyzer-deadcode.DeadStores) + DOCTEST_CLANG_SUPPRESS_WARNING_PUSH + DOCTEST_CLANG_SUPPRESS_WARNING("-Wcovered-switch-default") + switch (code) { + case Color::Red: col = "[0;31m"; break; + case Color::Green: col = "[0;32m"; break; + case Color::Blue: col = "[0;34m"; break; + case Color::Cyan: col = "[0;36m"; break; + case Color::Yellow: col = "[0;33m"; break; + case Color::Grey: col = "[1;30m"; break; + case Color::LightGrey: col = "[0;37m"; break; + case Color::BrightRed: col = "[1;31m"; break; + case Color::BrightGreen: col = "[1;32m"; break; + case Color::BrightWhite: col = "[1;37m"; break; + case Color::Bright: // invalid + case Color::None: + case Color::White: + default: col = "[0m"; + } + DOCTEST_CLANG_SUPPRESS_WARNING_POP + s << "\033" << col; +#endif // DOCTEST_CONFIG_COLORS_ANSI + +#ifdef DOCTEST_CONFIG_COLORS_WINDOWS + if (g_no_colors || (_isatty(_fileno(stdout)) == false && getContextOptions()->force_colors == false)) + return; + + static struct ConsoleHelper { + HANDLE stdoutHandle; + WORD origFgAttrs; + WORD origBgAttrs; + + ConsoleHelper() { + stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo(stdoutHandle, &csbiInfo); + origFgAttrs = + csbiInfo.wAttributes & ~(BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY); + origBgAttrs = + csbiInfo.wAttributes & ~(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY); + } + } ch; + +#define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(ch.stdoutHandle, x | ch.origBgAttrs) + + // clang-format off + switch (code) { + case Color::White: DOCTEST_SET_ATTR(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; + case Color::Red: DOCTEST_SET_ATTR(FOREGROUND_RED); break; + case Color::Green: DOCTEST_SET_ATTR(FOREGROUND_GREEN); break; + case Color::Blue: DOCTEST_SET_ATTR(FOREGROUND_BLUE); break; + case Color::Cyan: DOCTEST_SET_ATTR(FOREGROUND_BLUE | FOREGROUND_GREEN); break; + case Color::Yellow: DOCTEST_SET_ATTR(FOREGROUND_RED | FOREGROUND_GREEN); break; + case Color::Grey: DOCTEST_SET_ATTR(0); break; + case Color::LightGrey: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY); break; + case Color::BrightRed: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_RED); break; + case Color::BrightGreen: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN); break; + case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; + case Color::None: + case Color::Bright: // invalid + default: DOCTEST_SET_ATTR(ch.origFgAttrs); + } + // clang-format on +#endif // DOCTEST_CONFIG_COLORS_WINDOWS +} +DOCTEST_CLANG_SUPPRESS_WARNING_POP +} // namespace detail +#endif // DOCTEST_CONFIG_DISABLED +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +namespace doctest { + +const ContextOptions *getContextOptions() { + return DOCTEST_BRANCH_ON_DISABLED(nullptr, detail::g_cs); +} + +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP +#ifndef DOCTEST_PARTS_PRIVATE_REPORTERS_COMMON +#define DOCTEST_PARTS_PRIVATE_REPORTERS_COMMON + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_OPTIONS_PREFIX +#define DOCTEST_CONFIG_OPTIONS_PREFIX "dt-" +#endif + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { + +void fulltext_log_assert_to_stream(std::ostream &s, const AssertData &rb); + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_REPORTERS_COMMON +#ifndef DOCTEST_PARTS_PRIVATE_REPORTERS_DEBUG_OUTPUT_WINDOW +#define DOCTEST_PARTS_PRIVATE_REPORTERS_DEBUG_OUTPUT_WINDOW + +#ifndef DOCTEST_PARTS_PRIVATE_REPORTERS_CONSOLE +#define DOCTEST_PARTS_PRIVATE_REPORTERS_CONSOLE + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS +#define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX +#else +#define DOCTEST_OPTIONS_PREFIX_DISPLAY "" +#endif + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { + +struct Whitespace { + int nrSpaces; + explicit Whitespace(int nr); +}; + +std::ostream &operator<<(std::ostream &out, const Whitespace &ws); + +struct ConsoleReporter : public IReporter { + std::ostream &s; + bool hasLoggedCurrentTestStart; + std::vector subcasesStack; + size_t currentSubcaseLevel; + DOCTEST_DECLARE_MUTEX(mutex) + + // caching pointers/references to objects of these types - safe to do + const ContextOptions &opt; + const TestCaseData *tc; + + ConsoleReporter(const ContextOptions &co); + + ConsoleReporter(const ContextOptions &co, std::ostream &ostr); + + // ========================================================================================= + // WHAT FOLLOWS ARE HELPERS USED BY THE OVERRIDES OF THE VIRTUAL METHODS OF THE INTERFACE + // ========================================================================================= + + void separator_to_stream(); + + static const char *getSuccessOrFailString(bool success, assertType::Enum at, const char *success_str); + + static Color::Enum getSuccessOrFailColor(bool success, assertType::Enum at); + + void successOrFailColoredStringToStream(bool success, assertType::Enum at, const char *success_str = "SUCCESS"); + + void log_contexts(); + + // this was requested to be made virtual so users could override it + virtual void file_line_to_stream(const char *file, int line, const char *tail = ""); + + void logTestStart(); + + void printVersion(); + + void printIntro(); + + void printHelp(); + + void printRegisteredReporters(); + + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData &in) override; + + void test_run_start() override; + + void test_run_end(const TestRunStats &p) override; + + void test_case_start(const TestCaseData &in) override; + + void test_case_reenter(const TestCaseData &) override; + + void test_case_end(const CurrentTestCaseStats &st) override; + + void test_case_exception(const TestCaseException &e) override; + + void subcase_start(const SubcaseSignature &subc) override; + + void subcase_end() override; + + void log_assert(const AssertData &rb) override; + + void log_message(const MessageData &mb) override; + + void test_case_skipped(const TestCaseData &) override; +}; + +DOCTEST_REGISTER_REPORTER("console", 0, ConsoleReporter); + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_REPORTERS_CONSOLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +#ifdef DOCTEST_PLATFORM_WINDOWS +struct DebugOutputWindowReporter : public ConsoleReporter { + DOCTEST_THREAD_LOCAL static std::ostringstream oss; + + DebugOutputWindowReporter(const ContextOptions &co); + + void test_run_start() override; + void test_run_end(const TestRunStats &in) override; + void test_case_start(const TestCaseData &in) override; + void test_case_reenter(const TestCaseData &in) override; + void test_case_end(const CurrentTestCaseStats &in) override; + void test_case_exception(const TestCaseException &in) override; + void subcase_start(const SubcaseSignature &in) override; + void subcase_end(DOCTEST_EMPTY DOCTEST_EMPTY) override; + void log_assert(const AssertData &in) override; + void log_message(const MessageData &in) override; + void test_case_skipped(const TestCaseData &in) override; +}; +#endif // DOCTEST_PLATFORM_WINDOWS + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_REPORTERS_DEBUG_OUTPUT_WINDOW +#ifndef DOCTEST_PARTS_PRIVATE_TEST_CASE +#define DOCTEST_PARTS_PRIVATE_TEST_CASE + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +// all the registered tests +std::set &getRegisteredTests(); + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_TEST_CASE +#ifndef DOCTEST_PARTS_PRIVATE_FILTERS +#define DOCTEST_PARTS_PRIVATE_FILTERS + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +// matching of a string against a wildcard mask (case sensitivity configurable) taken from +// https://www.codeproject.com/Articles/1088/Wildcard-string-compare-globbing +int wildcmp(const char *str, const char *wild, bool caseSensitive); + +// checks if the name matches any of the filters (and can be configured what to do when empty) +bool matchesAny(const char *name, const std::vector &filters, bool matchEmpty, bool caseSensitive); + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_FILTERS +#ifndef DOCTEST_PARTS_PRIVATE_SIGNALS +#define DOCTEST_PARTS_PRIVATE_SIGNALS + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +#if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH) +struct FatalConditionHandler { + static void reset(); + static void allocateAltStackMem(); + static void freeAltStackMem(); +}; +#else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + +#ifdef DOCTEST_PLATFORM_WINDOWS + +struct SignalDefs { + DWORD id; + const char *name; +}; + +struct FatalConditionHandler { + static LONG CALLBACK handleException(PEXCEPTION_POINTERS ExceptionInfo); + static void allocateAltStackMem(); + static void freeAltStackMem(); + + FatalConditionHandler(); + + static void reset(); + + ~FatalConditionHandler(); + +private: + static UINT prev_error_mode_1; + static int prev_error_mode_2; + static unsigned int prev_abort_behavior; + static int prev_report_mode; + static _HFILE prev_report_file; + static void(DOCTEST_CDECL *prev_sigabrt_handler)(int); + static std::terminate_handler original_terminate_handler; + static bool isSet; + static ULONG guaranteeSize; + static LPTOP_LEVEL_EXCEPTION_FILTER previousTop; +}; + +#else // DOCTEST_PLATFORM_WINDOWS + +struct SignalDefs { + int id; + const char *name; +}; + +struct FatalConditionHandler { + static bool isSet; + static struct sigaction oldSigActions[6]; + static stack_t oldSigStack; + static size_t altStackSize; + static char *altStackMem; + + static void handleSignal(int sig); + + static void allocateAltStackMem(); + + static void freeAltStackMem(); + + FatalConditionHandler(); + + ~FatalConditionHandler(); + static void reset(); +}; + +#endif // DOCTEST_PLATFORM_WINDOWS +#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_SIGNALS + +// Fix for #1035 +#ifndef DOCTEST_PARTS_PRIVATE_REPORTERS_JUNIT +#define DOCTEST_PARTS_PRIVATE_REPORTERS_JUNIT + +#ifndef DOCTEST_PARTS_PRIVATE_XML +#define DOCTEST_PARTS_PRIVATE_XML + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +// ================================================================================================= +// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h +// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. +// ================================================================================================= +/* clang-format off */ /* NOLINTBEGIN */ + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); + + void encodeTo( std::ostream& os ) const; + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ); + + ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT; + ScopedElement& operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT; + + ~ScopedElement(); + + ScopedElement& writeText( std::string const& text, bool indent = true ); + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer = nullptr; + }; + +#ifndef DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + XmlWriter( std::ostream& os = std::cout ); +#else // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + XmlWriter( std::ostream& os ); +#endif // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + ~XmlWriter(); + + XmlWriter( XmlWriter const& ) = delete; + XmlWriter& operator=( XmlWriter const& ) = delete; + + XmlWriter& startElement( std::string const& name ); + + ScopedElement scopedElement( std::string const& name ); + + XmlWriter& endElement(); + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); + + XmlWriter& writeAttribute( std::string const& name, const char* attribute ); + + XmlWriter& writeAttribute( std::string const& name, bool attribute ); + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + std::stringstream rss; + rss << attribute; + return writeAttribute( name, rss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ); + + //XmlWriter& writeComment( std::string const& text ); + + //void writeStylesheetRef( std::string const& url ); + + //XmlWriter& writeBlankLine(); + + void ensureTagClosed(); + + void writeDeclaration(); + + private: + + void newlineIfNecessary(); + + bool m_tagIsOpen = false; + bool m_needsNewline = false; + std::vector m_tags; + std::string m_indent; + std::ostream& m_os; + }; + +/* clang-format on */ /* NOLINTEND */ +// ================================================================================================= +// End of copy-pasted code from Catch +// ================================================================================================= + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_XML + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { + +// TODO: +// - log_message() +// - respond to queries +// - honor remaining options +// - more attributes in tags +struct JUnitReporter : public IReporter { + detail::XmlWriter xml; + DOCTEST_DECLARE_MUTEX(mutex) + detail::Timer timer; + std::vector deepestSubcaseStackNames; + + struct JUnitTestCaseData { + static std::string getCurrentTimestamp(); + + struct JUnitTestMessage { + JUnitTestMessage(const std::string &_message, const std::string &_type, const std::string &_details); + + JUnitTestMessage(const std::string &_message, const std::string &_details); + + std::string message, type, details; + }; + + struct JUnitTestCase { + JUnitTestCase(const std::string &_classname, const std::string &_name); + + std::string classname, name; + double time; + std::vector failures, errors; + }; + + void add(const std::string &classname, const std::string &name); + + void appendSubcaseNamesToLastTestcase(std::vector nameStack); + + void addTime(double time); + + void addFailure(const std::string &message, const std::string &type, const std::string &details); + + void addError(const std::string &message, const std::string &details); + + std::vector testcases; + double totalSeconds = 0; + int totalErrors = 0, totalFailures = 0; + }; + + JUnitTestCaseData testCaseData; + + // caching pointers/references to objects of these types - safe to do + const ContextOptions &opt; + const TestCaseData *tc = nullptr; + + JUnitReporter(const ContextOptions &co); + + unsigned line(unsigned l) const; + + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData &) override; + + void test_run_start() override; + + void test_run_end(const TestRunStats &p) override; + + void test_case_start(const TestCaseData &in) override; + + void test_case_reenter(const TestCaseData &in) override; + + void test_case_end(const CurrentTestCaseStats &) override; + + void test_case_exception(const TestCaseException &e) override; + + void subcase_start(const SubcaseSignature &in) override; + + void subcase_end() override; + + void log_assert(const AssertData &rb) override; + + void log_message(const MessageData &mb) override; + + void test_case_skipped(const TestCaseData &) override; + + static void log_contexts(std::ostringstream &s); +}; + +DOCTEST_REGISTER_REPORTER("junit", 0, JUnitReporter); + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_REPORTERS_JUNIT +#ifndef DOCTEST_PARTS_PRIVATE_REPORTERS_XML +#define DOCTEST_PARTS_PRIVATE_REPORTERS_XML + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { + +struct XmlReporter : public IReporter { + detail::XmlWriter xml; + DOCTEST_DECLARE_MUTEX(mutex) + + // caching pointers/references to objects of these types - safe to do + const ContextOptions &opt; + const TestCaseData *tc = nullptr; + + XmlReporter(const ContextOptions &co); + + void log_contexts(); + + unsigned line(unsigned l) const; + + void test_case_start_impl(const TestCaseData &in); + + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData &in) override; + + void test_run_start() override; + + void test_run_end(const TestRunStats &p) override; + + void test_case_start(const TestCaseData &in) override; + + void test_case_reenter(const TestCaseData &) override; + + void test_case_end(const CurrentTestCaseStats &st) override; + + void test_case_exception(const TestCaseException &e) override; + + void subcase_start(const SubcaseSignature &in) override; + + void subcase_end() override; + + void log_assert(const AssertData &rb) override; + + void log_message(const MessageData &mb) override; + + void test_case_skipped(const TestCaseData &in) override; +}; + +DOCTEST_REGISTER_REPORTER("xml", 0, XmlReporter); + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_REPORTERS_XML + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +namespace doctest { + +bool is_running_in_test = false; + +#ifdef DOCTEST_CONFIG_DISABLE + +// NOLINTBEGIN(readability-convert-member-functions-to-static) +Context::Context(int, const char *const *) {} +Context::~Context() = default; +void Context::applyCommandLine(int, const char *const *) {} +void Context::addFilter(const char *, const char *) {} +void Context::clearFilters() {} +void Context::setOption(const char *, bool) {} +void Context::setOption(const char *, int) {} +void Context::setOption(const char *, const char *) {} +bool Context::shouldExit() { + return false; +} +void Context::setAsDefaultForAssertsOutOfTestCases() {} +void Context::setAssertHandler(detail::assert_handler) {} +void Context::setCout(std::ostream *) {} +int Context::run() { + return 0; +} +// NOLINTEND(readability-convert-member-functions-to-static) + +#else + +namespace detail { +// for sorting tests by file/line +bool fileOrderComparator(const TestCase *lhs, const TestCase *rhs) { + // this is needed because MSVC gives different case for drive letters + // for __FILE__ when evaluated in a header and a source file + const int res = lhs->m_file.compare(rhs->m_file, static_cast(DOCTEST_MSVC)); + if (res != 0) + return res < 0; + if (lhs->m_line != rhs->m_line) + return lhs->m_line < rhs->m_line; + return lhs->m_template_id < rhs->m_template_id; +} + +// for sorting tests by suite/file/line +bool suiteOrderComparator(const TestCase *lhs, const TestCase *rhs) { + const int res = std::strcmp(lhs->m_test_suite, rhs->m_test_suite); + if (res != 0) + return res < 0; + return fileOrderComparator(lhs, rhs); +} + +// for sorting tests by name/suite/file/line +bool nameOrderComparator(const TestCase *lhs, const TestCase *rhs) { + const int res = std::strcmp(lhs->m_name, rhs->m_name); + if (res != 0) + return res < 0; + return suiteOrderComparator(lhs, rhs); +} + +// the implementation of parseOption() +bool parseOptionImpl(int argc, const char *const *argv, const char *pattern, String *value) { + // going from the end to the beginning and stopping on the first occurrence from the end + for (int i = argc; i > 0; --i) { + auto index = i - 1; + auto temp = std::strstr(argv[index], pattern); + if (temp && (value || strlen(temp) == strlen(pattern))) { + // eliminate matches in which the chars before the option are not '-' + bool noBadCharsFound = true; + auto curr = argv[index]; + while (curr != temp) { + if (*curr++ != '-') { + noBadCharsFound = false; + break; + } + } + if (noBadCharsFound && argv[index][0] == '-') { + if (value) { + // parsing the value of an option + temp += strlen(pattern); + const unsigned len = strlen(temp); + if (len) { + *value = temp; + return true; + } + } else { + // just a flag - no value + return true; + } + } + } + } + return false; +} + +// parses an option and returns the string after the '=' character +bool parseOption( + int argc, const char *const *argv, const char *pattern, String *value = nullptr, const String &defaultVal = String() +) { + if (value) + *value = defaultVal; +#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + // offset (normally 3 for "dt-") to skip prefix + if (parseOptionImpl(argc, argv, pattern + strlen(DOCTEST_CONFIG_OPTIONS_PREFIX), value)) + return true; +#endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + return parseOptionImpl(argc, argv, pattern, value); +} + +// locates a flag on the command line +bool parseFlag(int argc, const char *const *argv, const char *pattern) { + return parseOption(argc, argv, pattern); +} + +// parses a comma separated list of words after a pattern in one of the arguments in argv +bool parseCommaSepArgs(int argc, const char *const *argv, const char *pattern, std::vector &res) { + String filtersString; + if (parseOption(argc, argv, pattern, &filtersString)) { + // tokenize with "," as a separator, unless escaped with backslash + std::ostringstream s; + auto flush = [&s, &res]() { + auto string = s.str(); + if (!string.empty()) { + res.emplace_back(string.c_str()); + } + s.str(""); + }; + + bool seenBackslash = false; + const char *current = filtersString.c_str(); + const char *end = current + strlen(current); + while (current != end) { + const char character = *current++; + if (seenBackslash) { + seenBackslash = false; + if (character == ',' || character == '\\') { + s.put(character); + continue; + } + s.put('\\'); + } + if (character == '\\') { + seenBackslash = true; + } else if (character == ',') { + flush(); + } else { + s.put(character); + } + } + + if (seenBackslash) { + s.put('\\'); + } + flush(); + return true; + } + return false; +} + +enum optionType { option_bool, option_int }; + +// parses an int/bool option from the command line +bool parseIntOption(int argc, const char *const *argv, const char *pattern, optionType type, int &res) { + String parsedValue; + if (!parseOption(argc, argv, pattern, &parsedValue)) + return false; + + if (type) { + // integer + // TODO: change this to use std::stoi or something else! currently it uses undefined + // behavior - assumes '0' on failed parse... + // NOLINTNEXTLINE(bugprone-unchecked-string-to-number-conversion, cert-err34-c) + const int theInt = std::atoi(parsedValue.c_str()); + if (theInt != 0) { + res = theInt; + return true; + } + } else { + // boolean + const char positive[][5] = {"1", "true", "on", "yes"}; // 5 - strlen("true") + 1 + const char negative[][6] = {"0", "false", "off", "no"}; // 6 - strlen("false") + 1 + + // if the value matches any of the positive/negative possibilities + for (unsigned i = 0; i < 4; i++) { + if (parsedValue.compare(positive[i], true) == 0) { + res = 1; + return true; + } + if (parsedValue.compare(negative[i], true) == 0) { + res = 0; + return true; + } + } + } + return false; +} + +} // namespace detail + +Context::Context(int argc, const char *const *argv) + : p(new detail::ContextState) { + parseArgs(argc, argv, true); + if (argc) + p->binary_name = argv[0]; +} + +Context::~Context() { + if (detail::g_cs == p) + detail::g_cs = nullptr; + delete p; +} + +void Context::applyCommandLine(int argc, const char *const *argv) { + parseArgs(argc, argv); + if (argc) + p->binary_name = argv[0]; +} + +// parses args +void Context::parseArgs(int argc, const char *const *argv, bool withDefaults) { + using namespace detail; + + // clang-format off + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file=", p->filters[0]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sf=", p->filters[0]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "source-file-exclude=",p->filters[1]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sfe=", p->filters[1]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite=", p->filters[2]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ts=", p->filters[2]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-suite-exclude=", p->filters[3]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tse=", p->filters[3]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case=", p->filters[4]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tc=", p->filters[4]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "test-case-exclude=", p->filters[5]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "tce=", p->filters[5]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase=", p->filters[6]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sc=", p->filters[6]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "subcase-exclude=", p->filters[7]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "sce=", p->filters[7]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "reporters=", p->filters[8]); + parseCommaSepArgs(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "r=", p->filters[8]); + // clang-format on + + int intRes = 0; + String strRes; + +#define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \ + if (parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_bool, intRes) || \ + parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_bool, intRes)) \ + p->var = static_cast(intRes); \ + else if ( \ + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) || \ + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname) \ + ) \ + p->var = true; \ + else if (withDefaults) \ + p->var = default + +#define DOCTEST_PARSE_INT_OPTION(name, sname, var, default) \ + if (parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_int, intRes) || \ + parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_int, intRes)) \ + p->var = intRes; \ + else if (withDefaults) \ + p->var = default + +#define DOCTEST_PARSE_STR_OPTION(name, sname, var, default) \ + if (parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", &strRes, default) || \ + parseOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", &strRes, default) || withDefaults) \ + p->var = strRes + + DOCTEST_PARSE_STR_OPTION("out", "o", out, ""); + DOCTEST_PARSE_STR_OPTION("order-by", "ob", order_by, "file"); + DOCTEST_PARSE_INT_OPTION("rand-seed", "rs", rand_seed, 0); + + DOCTEST_PARSE_INT_OPTION("first", "f", first, 0); + DOCTEST_PARSE_INT_OPTION("last", "l", last, UINT_MAX); + + DOCTEST_PARSE_INT_OPTION("abort-after", "aa", abort_after, 0); + DOCTEST_PARSE_INT_OPTION("subcase-filter-levels", "scfl", subcase_filter_levels, INT_MAX); + + DOCTEST_PARSE_AS_BOOL_OR_FLAG("success", "s", success, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("case-sensitive", "cs", case_sensitive, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("exit", "e", exit, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("duration", "d", duration, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("minimal", "m", minimal, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("quiet", "q", quiet, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-throw", "nt", no_throw, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-exitcode", "ne", no_exitcode, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-run", "nr", no_run, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-intro", "ni", no_intro, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-version", "nv", no_version, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-colors", "nc", no_colors, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("force-colors", "fc", force_colors, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-breaks", "nb", no_breaks, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skip", "ns", no_skip, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("gnu-file-line", "gfl", gnu_file_line, !bool(DOCTEST_MSVC)); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-path-filenames", "npf", no_path_in_filenames, false); + DOCTEST_PARSE_STR_OPTION("strip-file-prefixes", "sfp", strip_file_prefixes, ""); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-line-numbers", "nln", no_line_numbers, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-debug-output", "ndo", no_debug_output, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-skipped-summary", "nss", no_skipped_summary, false); + DOCTEST_PARSE_AS_BOOL_OR_FLAG("no-time-in-output", "ntio", no_time_in_output, false); + + if (withDefaults) { + p->help = false; + p->version = false; + p->count = false; + p->list_test_cases = false; + p->list_test_suites = false; + p->list_reporters = false; + } + if (parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "help") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "h") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "?")) { + p->help = true; + p->exit = true; + } + if (parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "version") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "v")) { + p->version = true; + p->exit = true; + } + if (parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "count") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "c")) { + p->count = true; + p->exit = true; + } + if (parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-cases") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "ltc")) { + p->list_test_cases = true; + p->exit = true; + } + if (parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-test-suites") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lts")) { + p->list_test_suites = true; + p->exit = true; + } + if (parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "list-reporters") || + parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX "lr")) { + p->list_reporters = true; + p->exit = true; + } +} + +// allows the user to add procedurally to the filters from the command line +void Context::addFilter(const char *filter, const char *value) { + setOption(filter, value); +} + +// allows the user to clear all filters from the command line +void Context::clearFilters() { + for (auto &curr: p->filters) + curr.clear(); +} + +// allows the user to override procedurally the bool options from the command line +void Context::setOption(const char *option, bool value) { + setOption(option, value ? "true" : "false"); +} + +// allows the user to override procedurally the int options from the command line +void Context::setOption(const char *option, int value) { + setOption(option, toString(value).c_str()); +} + +// allows the user to override procedurally the string options from the command line +void Context::setOption(const char *option, const char *value) { + auto argv = String("-") + option + "=" + value; + auto lvalue = argv.c_str(); + parseArgs(1, &lvalue); +} + +// users should query this in their main() and exit the program if true +bool Context::shouldExit() { + return p->exit; +} + +void Context::setAsDefaultForAssertsOutOfTestCases() { + detail::g_cs = p; +} + +void Context::setAssertHandler(detail::assert_handler ah) { + p->ah = ah; +} + +void Context::setCout(std::ostream *out) { + p->cout = out; +} + +static class DiscardOStream : public std::ostream { +private: + class : public std::streambuf { + private: + // allowing some buffering decreases the amount of calls to overflow + char buf[1024]; + + protected: + std::streamsize xsputn(const char_type *, std::streamsize count) override { + return count; + } + + int_type overflow(int_type ch) override { + setp(std::begin(buf), std::end(buf)); + return traits_type::not_eof(ch); + } + } discardBuf; + +public: + DiscardOStream() noexcept + : std::ostream(&discardBuf) {} +} discardOut; + +// the main function that does all the filtering and test running +int Context::run() { + using namespace detail; + + // save the old context state in case such was setup - for using asserts out of a testing context + auto old_cs = g_cs; + // this is the current contest + g_cs = p; + is_running_in_test = true; + + g_no_colors = p->no_colors; + p->resetRunData(); + + std::fstream fstr; + if (p->cout == nullptr) { + if (p->quiet) { + p->cout = &discardOut; + } else if (p->out.size()) { + // to a file if specified + fstr.open(p->out.c_str(), std::fstream::out); + p->cout = &fstr; + if (!fstr.is_open()) { + // clang-format off + std::cerr << Color::Cyan << "[doctest] " << Color::None << "Could not open " << p->out << " for writing!" << std::endl; + std::cerr << Color::Cyan << "[doctest] " << Color::None << "Defaulting to std::cout instead" << std::endl; + p->cout = &std::cout; + // clang-format on + } + + } else { +#ifndef DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + // stdout by default + p->cout = &std::cout; +#else // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + return EXIT_FAILURE; +#endif // DOCTEST_CONFIG_NO_INCLUDE_IOSTREAM + } + } + + FatalConditionHandler::allocateAltStackMem(); + + auto cleanup_and_return = [&]() { + FatalConditionHandler::freeAltStackMem(); + + if (fstr.is_open()) + fstr.close(); + + // restore context + g_cs = old_cs; + is_running_in_test = false; + + // we have to free the reporters which were allocated when the run started + for (auto &curr: p->reporters_currently_used) + delete curr; + p->reporters_currently_used.clear(); + + if (p->numTestCasesFailed && !p->no_exitcode) + return EXIT_FAILURE; + return EXIT_SUCCESS; + }; + + // setup default reporter if none is given through the command line + if (p->filters[8].empty()) + p->filters[8].emplace_back("console"); + + // check to see if any of the registered reporters has been selected + for (auto &curr: getReporters()) { + if (matchesAny(curr.first.second.c_str(), p->filters[8], false, p->case_sensitive)) + p->reporters_currently_used.push_back(curr.second(*g_cs)); + } + + // TODO: check if there is nothing in reporters_currently_used + + // prepend all listeners + for (auto &curr: getListeners()) + p->reporters_currently_used.insert(p->reporters_currently_used.begin(), curr.second(*g_cs)); + +#ifdef DOCTEST_PLATFORM_WINDOWS + if (isDebuggerActive() && p->no_debug_output == false) + p->reporters_currently_used.push_back(new DebugOutputWindowReporter(*g_cs)); +#endif // DOCTEST_PLATFORM_WINDOWS + + // handle version, help and no_run + if (p->no_run || p->version || p->help || p->list_reporters) { + DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, QueryData()); + + return cleanup_and_return(); + } + + std::vector testArray; + for (auto &curr: getRegisteredTests()) + testArray.push_back(&curr); + p->numTestCases = testArray.size(); + + // sort the collected records + if (!testArray.empty()) { + if (p->order_by.compare("file", true) == 0) { + std::sort(testArray.begin(), testArray.end(), fileOrderComparator); + } else if (p->order_by.compare("suite", true) == 0) { + std::sort(testArray.begin(), testArray.end(), suiteOrderComparator); + } else if (p->order_by.compare("name", true) == 0) { + std::sort(testArray.begin(), testArray.end(), nameOrderComparator); + } else if (p->order_by.compare("rand", true) == 0) { + std::srand(p->rand_seed); + + // random_shuffle implementation + const auto first = testArray.data(); + for (size_t i = testArray.size() - 1; i > 0; --i) { + // NOLINTNEXTLINE(cert-msc30-c, cert-msc50-cpp, concurrency-mt-unsafe, misc-predictable-rand) + const int idxToSwap = static_cast(std::rand() % (i + 1)); + + const auto temp = first[i]; + + first[i] = first[idxToSwap]; + first[idxToSwap] = temp; + } + } else if (p->order_by.compare("none", true) == 0) { + // means no sorting - beneficial for death tests which call into the executable + // with a specific test case in mind - we don't want to slow down the startup times + } + } + + std::set testSuitesPassingFilt; + + const bool query_mode = p->count || p->list_test_cases || p->list_test_suites; + std::vector queryResults; + + if (!query_mode) + DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_start, DOCTEST_EMPTY); + + // invoke the registered functions if they match the filter criteria (or just count them) + for (auto &curr: testArray) { + const auto &tc = *curr; + + bool skip_me = false; + if (tc.m_skip && !p->no_skip) + skip_me = true; + + if (!matchesAny(tc.m_file.c_str(), p->filters[0], true, p->case_sensitive)) + skip_me = true; + if (matchesAny(tc.m_file.c_str(), p->filters[1], false, p->case_sensitive)) + skip_me = true; + if (!matchesAny(tc.m_test_suite, p->filters[2], true, p->case_sensitive)) + skip_me = true; + if (matchesAny(tc.m_test_suite, p->filters[3], false, p->case_sensitive)) + skip_me = true; + if (!matchesAny(tc.m_name, p->filters[4], true, p->case_sensitive)) + skip_me = true; + if (matchesAny(tc.m_name, p->filters[5], false, p->case_sensitive)) + skip_me = true; + + if (!skip_me) + p->numTestCasesPassingFilters++; + + // skip the test if it is not in the execution range + if ((p->last < p->numTestCasesPassingFilters && p->first <= p->last) || + (p->first > p->numTestCasesPassingFilters)) + skip_me = true; + + if (skip_me) { + if (!query_mode) + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_skipped, tc); + continue; + } + + // do not execute the test if we are to only count the number of filter passing tests + if (p->count) + continue; + + // print the name of the test and don't execute it + if (p->list_test_cases) { + queryResults.push_back(&tc); + continue; + } + + // print the name of the test suite if not done already and don't execute it + if (p->list_test_suites) { + if ((testSuitesPassingFilt.count(tc.m_test_suite) == 0) && tc.m_test_suite[0] != '\0') { + queryResults.push_back(&tc); + testSuitesPassingFilt.insert(tc.m_test_suite); + p->numTestSuitesPassingFilters++; + } + continue; + } + + // execute the test if it passes all the filtering + { + p->currentTest = &tc; + + p->failure_flags = TestCaseFailureReason::None; + p->seconds = 0; + + // reset atomic counters + p->numAssertsFailedCurrentTest_atomic = 0; + p->numAssertsCurrentTest_atomic = 0; + + p->traversal.resetForTestCase(); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_start, tc); + + p->timer.start(); + + bool run_test = true; + + do { // NOLINT(cppcoreguidelines-avoid-do-while) + // Reset per-run traversal data while keeping the current decision path prefix. + p->traversal.resetForRun(); + + p->shouldLogCurrentException = true; + + // reset stuff for logging with INFO() + p->stringifiedContexts.clear(); + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + try { +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + // MSVC 2015 diagnoses fatalConditionHandler as unused (because reset() is a + // static method) + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4101) // unreferenced local variable + const FatalConditionHandler fatalConditionHandler; // Handle signals + static_cast(fatalConditionHandler); + // execute the test + tc.m_test(); + FatalConditionHandler::reset(); + DOCTEST_MSVC_SUPPRESS_WARNING_POP +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + } catch (const TestFailureException &) { + p->failure_flags |= TestCaseFailureReason::AssertFailure; + } catch (...) { + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_exception, {translateActiveException(), false}); + p->failure_flags |= TestCaseFailureReason::Exception; + } +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + + // exit this loop if enough assertions have failed - even if there are more subcases + if (p->abort_after > 0 && + p->numAssertsFailed + p->numAssertsFailedCurrentTest_atomic >= p->abort_after) { + run_test = false; + p->failure_flags |= TestCaseFailureReason::TooManyFailedAsserts; + } + + const bool has_next_path = run_test ? p->traversal.advance() : false; + + if (has_next_path && run_test) + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_reenter, tc); + if (!has_next_path) + run_test = false; + } while (run_test); + + p->finalizeTestCaseData(); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_end, *g_cs); + + p->currentTest = nullptr; + + // stop executing tests if enough assertions have failed + if (p->abort_after > 0 && p->numAssertsFailed >= p->abort_after) + break; + } + } + + if (!query_mode) { + DOCTEST_ITERATE_THROUGH_REPORTERS(test_run_end, *g_cs); + } else { + QueryData qdata; + qdata.run_stats = g_cs; + qdata.data = queryResults.data(); + qdata.num_data = static_cast(queryResults.size()); + DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, qdata); + } + + return cleanup_and_return(); +} + +#endif // DOCTEST_CONFIG_DISABLE + +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP +#ifndef DOCTEST_PARTS_PRIVATE_CONTEXT_SCOPE +#define DOCTEST_PARTS_PRIVATE_CONTEXT_SCOPE + + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { +extern DOCTEST_THREAD_LOCAL std::vector g_infoContexts; // for logging with INFO() +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // DOCTEST_PARTS_PRIVATE_CONTEXT_SCOPE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +namespace doctest { + +DOCTEST_DEFINE_INTERFACE(IContextScope) + +#ifndef DOCTEST_CONFIG_DISABLE +namespace detail { +DOCTEST_THREAD_LOCAL std::vector g_infoContexts; // for logging with INFO() + +ContextScopeBase::ContextScopeBase() { + g_infoContexts.push_back(this); +} + +ContextScopeBase::ContextScopeBase(ContextScopeBase &&other) noexcept { + if (other.need_to_destroy) { + other.destroy(); + } + other.need_to_destroy = false; + g_infoContexts.push_back(this); +} + +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") +// destroy cannot be inlined into the destructor because that would mean calling stringify after +// ContextScope has been destroyed (base class destructors run after derived class destructors). +// Instead, ContextScope calls this method directly from its destructor. +void ContextScopeBase::destroy() { +#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && \ + (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) + if (std::uncaught_exceptions() > 0) { +#else + if (std::uncaught_exception()) { +#endif + std::ostringstream s; + this->stringify(&s); + g_cs->stringifiedContexts.emplace_back(s.str().c_str()); + } + g_infoContexts.pop_back(); +} +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP +DOCTEST_MSVC_SUPPRESS_WARNING_POP +} // namespace detail +#endif // DOCTEST_CONFIG_DISABLE + +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +ContextState *g_cs = nullptr; +DOCTEST_THREAD_LOCAL bool g_no_colors; + +void ContextState::resetRunData() { + numTestCases = 0; + numTestCasesPassingFilters = 0; + numTestSuitesPassingFilters = 0; + numTestCasesFailed = 0; + numAsserts = 0; + numAssertsFailed = 0; + numAssertsCurrentTest = 0; + numAssertsFailedCurrentTest = 0; +} + +void ContextState::finalizeTestCaseData() { + seconds = timer.getElapsedSeconds(); + + // update the non-atomic counters + numAsserts += numAssertsCurrentTest_atomic; + numAssertsFailed += numAssertsFailedCurrentTest_atomic; + numAssertsCurrentTest = numAssertsCurrentTest_atomic; + numAssertsFailedCurrentTest = numAssertsFailedCurrentTest_atomic; + + if (numAssertsFailedCurrentTest) + failure_flags |= TestCaseFailureReason::AssertFailure; + + if (Approx(currentTest->m_timeout).epsilon(DBL_EPSILON) != 0 && + Approx(seconds).epsilon(DBL_EPSILON) > currentTest->m_timeout) + failure_flags |= TestCaseFailureReason::Timeout; + + if (currentTest->m_should_fail) { + if (failure_flags) { + failure_flags |= TestCaseFailureReason::ShouldHaveFailedAndDid; + } else { + failure_flags |= TestCaseFailureReason::ShouldHaveFailedButDidnt; + } + } else if (failure_flags && currentTest->m_may_fail) { + failure_flags |= TestCaseFailureReason::CouldHaveFailedAndDid; + } else if (currentTest->m_expected_failures > 0) { + if (numAssertsFailedCurrentTest == currentTest->m_expected_failures) { + failure_flags |= TestCaseFailureReason::FailedExactlyNumTimes; + } else { + failure_flags |= TestCaseFailureReason::DidntFailExactlyNumTimes; + } + } + + const bool ok_to_fail = (TestCaseFailureReason::ShouldHaveFailedAndDid & failure_flags) || + (TestCaseFailureReason::CouldHaveFailedAndDid & failure_flags) || + (TestCaseFailureReason::FailedExactlyNumTimes & failure_flags); + + // if any subcase has failed - the whole test case has failed + testCaseSuccess = !(failure_flags && !ok_to_fail); + if (!testCaseSuccess) + numTestCasesFailed++; +} + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { +#ifdef DOCTEST_IS_DEBUGGER_ACTIVE +bool isDebuggerActive() { + return DOCTEST_IS_DEBUGGER_ACTIVE(); +} +#else // DOCTEST_IS_DEBUGGER_ACTIVE +#ifdef DOCTEST_PLATFORM_LINUX +class ErrnoGuard { +public: + ErrnoGuard() + : m_oldErrno(errno) {} + ~ErrnoGuard() { + errno = m_oldErrno; + } + +private: + int m_oldErrno; +}; +// See the comments in Catch2 for the reasoning behind this implementation: +// https://github.com/catchorg/Catch2/blob/v2.13.1/include/internal/catch_debugger.cpp#L79-L102 +bool isDebuggerActive() { + const ErrnoGuard guard; + std::ifstream in("/proc/self/status"); + for (std::string line; std::getline(in, line);) { + static const int PREFIX_LEN = 11; + if (line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0) { + return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; + } + } + return false; +} +#elif defined(DOCTEST_PLATFORM_MAC) +// The following function is taken directly from the following technical note: +// https://developer.apple.com/library/archive/qa/qa1361/_index.html +// Returns true if the current process is being debugged (either +// running under the debugger or has a debugger attached post facto). +bool isDebuggerActive() { + int mib[4]; + kinfo_proc info; + size_t size; + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + info.kp_proc.p_flag = 0; + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + // Call sysctl. + size = sizeof(info); + if (sysctl(mib, DOCTEST_COUNTOF(mib), &info, &size, nullptr, 0) != 0) { + std::cerr << "\nCall to sysctl failed - unable to determine if debugger is active **\n"; + return false; + } + // We're being debugged if the P_TRACED flag is set. + return ((info.kp_proc.p_flag & P_TRACED) != 0); +} +#elif DOCTEST_MSVC || defined(__MINGW32__) || defined(__MINGW64__) +bool isDebuggerActive() { + return ::IsDebuggerPresent() != 0; +} +#else +bool isDebuggerActive() { + return false; +} +#endif // Platform +#endif // DOCTEST_IS_DEBUGGER_ACTIVE +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +DOCTEST_DEFINE_INTERFACE(IExceptionTranslator) + +void registerExceptionTranslatorImpl(const IExceptionTranslator *et) noexcept { + if (std::find(getExceptionTranslators().begin(), getExceptionTranslators().end(), et) == + getExceptionTranslators().end()) + getExceptionTranslators().push_back(et); +} + +std::vector &getExceptionTranslators() noexcept { + static std::vector data; + return data; +} + +String translateActiveException() noexcept { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + String res; + auto &translators = getExceptionTranslators(); + for (auto &curr: translators) + if (curr->translate(res)) + return res; + // clang-format off + DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wcatch-value") + try { + throw; + } catch (std::exception &ex) { + return ex.what(); + } catch (std::string &msg) { + return msg.c_str(); + } catch (const char *msg) { + return msg; + } catch (...) { + return "unknown exception"; + } + DOCTEST_GCC_SUPPRESS_WARNING_POP + // clang-format on +#else // DOCTEST_CONFIG_NO_EXCEPTIONS + return ""; +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS +} + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +bool checkIfShouldThrow(assertType::Enum at) { + if (at & assertType::is_require) + return true; + + if ((at & assertType::is_check) && getContextOptions()->abort_after > 0 && + (g_cs->numAssertsFailed + g_cs->numAssertsFailedCurrentTest_atomic) >= getContextOptions()->abort_after) + return true; + + return false; +} + +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS +DOCTEST_NORETURN void throwException() { + g_cs->shouldLogCurrentException = false; + throw TestFailureException(); // NOLINT(hicpp-exception-baseclass) +} +#else // DOCTEST_CONFIG_NO_EXCEPTIONS +void throwException() {} +#endif // DOCTEST_CONFIG_NO_EXCEPTIONS + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +namespace doctest { +namespace detail { + +int wildcmp(const char *str, const char *wild, bool caseSensitive) { + const char *cp = str; + const char *mp = wild; + + while ((*str) && (*wild != '*')) { + if ((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) && (*wild != '?')) { + return 0; + } + wild++; + str++; + } + + while (*str) { + if (*wild == '*') { + if (!*++wild) { + return 1; + } + mp = wild; + cp = str + 1; + } else if ((caseSensitive ? (*wild == *str) : (tolower(*wild) == tolower(*str))) || (*wild == '?')) { + wild++; + str++; + } else { + wild = mp; + str = cp++; + } + } + + while (*wild == '*') { + wild++; + } + return !*wild; +} + +bool matchesAny(const char *name, const std::vector &filters, bool matchEmpty, bool caseSensitive) { + if (filters.empty() && matchEmpty) + return true; + for (auto &curr: filters) + if (wildcmp(name, curr.c_str(), caseSensitive)) + return true; + return false; +} + +} // namespace detail +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifdef DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) // 'function' : must be 'attribute' - see issue #182 +int main(int argc, char **argv) { + return doctest::Context(argc, argv).run(); +} +DOCTEST_MSVC_SUPPRESS_WARNING_POP +#endif // DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +namespace doctest { + +Approx::Approx(double value) + : m_epsilon(static_cast(std::numeric_limits::epsilon()) * 100), m_scale(1.0), m_value(value) {} + +Approx Approx::operator()(double value) const { + Approx approx(value); + approx.epsilon(m_epsilon); + approx.scale(m_scale); + return approx; +} + +Approx &Approx::epsilon(double newEpsilon) { + m_epsilon = newEpsilon; + return *this; +} +Approx &Approx::scale(double newScale) { + m_scale = newScale; + return *this; +} + +bool operator==(double lhs, const Approx &rhs) { + // Thanks to Richard Harris for his help refining this formula + return std::fabs(lhs - rhs.m_value) < + rhs.m_epsilon * (rhs.m_scale + std::max(std::fabs(lhs), std::fabs(rhs.m_value))); +} + +bool operator==(const Approx &lhs, double rhs) { + return operator==(rhs, lhs); +} + +bool operator!=(double lhs, const Approx &rhs) { + return !operator==(lhs, rhs); +} + +bool operator!=(const Approx &lhs, double rhs) { + return !operator==(rhs, lhs); +} + +bool operator<=(double lhs, const Approx &rhs) { + return lhs < rhs.m_value || lhs == rhs; +} + +bool operator<=(const Approx &lhs, double rhs) { + return lhs.m_value < rhs || lhs == rhs; +} + +bool operator>=(double lhs, const Approx &rhs) { + return lhs > rhs.m_value || lhs == rhs; +} + +bool operator>=(const Approx &lhs, double rhs) { + return lhs.m_value > rhs || lhs == rhs; +} + +bool operator<(double lhs, const Approx &rhs) { + return lhs < rhs.m_value && lhs != rhs; +} + +bool operator<(const Approx &lhs, double rhs) { + return lhs.m_value < rhs && lhs != rhs; +} + +bool operator>(double lhs, const Approx &rhs) { + return lhs > rhs.m_value && lhs != rhs; +} + +bool operator>(const Approx &lhs, double rhs) { + return lhs.m_value > rhs && lhs != rhs; +} + +String toString(const Approx &in) { + return "Approx( " + doctest::toString(in.m_value) + " )"; +} + +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +namespace doctest { + +Contains::Contains(const String &str) + : string(str) {} + +bool Contains::checkWith(const String &other) const { + return strstr(other.c_str(), string.c_str()) != nullptr; +} + +String toString(const Contains &in) { + return "Contains( " + in.string + " )"; +} + +bool operator==(const String &lhs, const Contains &rhs) { + return rhs.checkWith(lhs); +} + +bool operator==(const Contains &lhs, const String &rhs) { + return lhs.checkWith(rhs); +} + +bool operator!=(const String &lhs, const Contains &rhs) { + return !rhs.checkWith(lhs); +} + +bool operator!=(const Contains &lhs, const String &rhs) { + return !lhs.checkWith(rhs); +} + +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +namespace doctest { + +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4738) +template +IsNaN::operator bool() const { + return std::isnan(value) ^ flipped; +} +DOCTEST_MSVC_SUPPRESS_WARNING_POP +template struct DOCTEST_INTERFACE_DEF IsNaN; +template struct DOCTEST_INTERFACE_DEF IsNaN; +template struct DOCTEST_INTERFACE_DEF IsNaN; + +template +String toString(IsNaN in) { + return String(in.flipped ? "! " : "") + "IsNaN( " + doctest::toString(in.value) + " )"; +} + +String toString(IsNaN in) { + return toString(in); +} + +String toString(IsNaN in) { + return toString(in); +} + +String toString(IsNaN in) { + return toString(in); +} + +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_OPTIONS_FILE_PREFIX_SEPARATOR +#define DOCTEST_CONFIG_OPTIONS_FILE_PREFIX_SEPARATOR ':' +#endif + +namespace doctest { + +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference") +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wnull-dereference") +// depending on the current options this will remove the path of filenames +const char *skipPathFromFilename(const char *file) { +#ifndef DOCTEST_CONFIG_DISABLE + if (getContextOptions()->no_path_in_filenames) { + auto back = std::strrchr(file, '\\'); + auto forward = std::strrchr(file, '/'); + if (back || forward) { + if (back > forward) + forward = back; + return forward + 1; + } + } else { + const auto prefixes = getContextOptions()->strip_file_prefixes; + const char separator = DOCTEST_CONFIG_OPTIONS_FILE_PREFIX_SEPARATOR; + String::size_type longest_match = 0U; + for (String::size_type pos = 0U; pos < prefixes.size(); ++pos) { + const auto prefix_start = pos; + pos = std::min(prefixes.find(separator, prefix_start), prefixes.size()); + + const auto prefix_size = pos - prefix_start; + if (prefix_size > longest_match) { + // TODO under DOCTEST_MSVC: does the comparison need strnicmp() to work with drive + // letter capitalization? + if (0 == std::strncmp(prefixes.c_str() + prefix_start, file, prefix_size)) { + longest_match = prefix_size; + } + } + } + return &file[longest_match]; + } +#endif // DOCTEST_CONFIG_DISABLE + return file; +} +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP + +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +namespace doctest { +#ifdef DOCTEST_CONFIG_DISABLE + +DOCTEST_DEFINE_INTERFACE(IReporter) + +int IReporter::get_num_active_contexts() { + return 0; +} + +const IContextScope *const *IReporter::get_active_contexts() { + return nullptr; +} + +int IReporter::get_num_stringified_contexts() { + return 0; +} + +const String *IReporter::get_stringified_contexts() { + return nullptr; +} + +int registerReporter(const char *, int, IReporter *) { + return 0; +} + +#else + +namespace detail { +reporterMap &getReporters() noexcept { + static reporterMap data; + return data; +} + +reporterMap &getListeners() noexcept { + static reporterMap data; + return data; +} +} // namespace detail + +DOCTEST_DEFINE_INTERFACE(IReporter) + +int IReporter::get_num_active_contexts() { + return static_cast(detail::g_infoContexts.size()); +} + +const IContextScope *const *IReporter::get_active_contexts() { + return get_num_active_contexts() ? detail::g_infoContexts.data() : nullptr; +} + +int IReporter::get_num_stringified_contexts() { + return static_cast(detail::g_cs->stringifiedContexts.size()); +} + +const String *IReporter::get_stringified_contexts() { + return get_num_stringified_contexts() ? detail::g_cs->stringifiedContexts.data() : nullptr; +} + +namespace detail { +void registerReporterImpl(const char *name, int priority, reporterCreatorFunc c, bool isReporter) noexcept { + if (isReporter) + getReporters().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); + else + getListeners().insert(reporterMap::value_type(reporterMap::key_type(priority, name), c)); +} +} // namespace detail + +#endif // DOCTEST_CONFIG_DISABLE +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { + +void fulltext_log_assert_to_stream(std::ostream &s, const AssertData &rb) { + // clang-format off + if ((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) == 0) + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << " ) " << Color::None; + + if (rb.m_at & assertType::is_throws) { + s << (rb.m_threw ? "threw as expected!" : "did NOT throw at all!") << "\n"; + } else if ((rb.m_at & assertType::is_throws_as) && (rb.m_at & assertType::is_throws_with)) { + s << Color::Cyan << assertString(rb.m_at) << "( " + << rb.m_expr << ", \"" << rb.m_exception_string.c_str() << "\", " << rb.m_exception_type + << " ) " << Color::None; + + if (rb.m_threw) { + if (!rb.m_failed) { + s << "threw as expected!\n"; + } else { + s << "threw a DIFFERENT exception! (contents: " << rb.m_exception << ")\n"; + } + } else { + s << "did NOT throw at all!\n"; + } + } else if (rb.m_at & assertType::is_throws_as) { + s << Color::Cyan << assertString(rb.m_at) << "( " + << rb.m_expr << ", " << rb.m_exception_type + << " ) " << Color::None + << (rb.m_threw ? (rb.m_threw_as ? "threw as expected!" : "threw a DIFFERENT exception: ") : "did NOT throw at all!") + << Color::Cyan << rb.m_exception << "\n"; + } else if (rb.m_at & assertType::is_throws_with) { + s << Color::Cyan << assertString(rb.m_at) << "( " + << rb.m_expr << ", \"" << rb.m_exception_string.c_str() + << "\" ) " << Color::None + << (rb.m_threw ? (!rb.m_failed ? "threw as expected!" : "threw a DIFFERENT exception: ") : "did NOT throw at all!") + << Color::Cyan << rb.m_exception << "\n"; + } else if (rb.m_at & assertType::is_nothrow) { + s << (rb.m_threw ? "THREW exception: " : "didn't throw!") << Color::Cyan << rb.m_exception << "\n"; + } else { + s << (rb.m_threw ? "THREW exception: " : (!rb.m_failed ? "is correct!\n" : "is NOT correct!\n")); + if (rb.m_threw) + s << rb.m_exception << "\n"; + else + s << " values: " << assertString(rb.m_at) << "( " << rb.m_decomp << " )\n"; + } + // clang-format on +} + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { + +using detail::g_cs; + +Whitespace::Whitespace(int nr) + : nrSpaces(nr) {} + +std::ostream &operator<<(std::ostream &out, const Whitespace &ws) { + if (ws.nrSpaces != 0) + out << std::setw(ws.nrSpaces) << ' '; + return out; +} + +ConsoleReporter::ConsoleReporter(const ContextOptions &co) + : s(*co.cout), opt(co) {} + +ConsoleReporter::ConsoleReporter(const ContextOptions &co, std::ostream &ostr) + : s(ostr), opt(co) {} + +void ConsoleReporter::separator_to_stream() { + s << Color::Yellow + << "===============================================================================" + "\n"; +} + +const char *ConsoleReporter::getSuccessOrFailString(bool success, assertType::Enum at, const char *success_str) { + if (success) + return success_str; + return failureString(at); +} + +Color::Enum ConsoleReporter::getSuccessOrFailColor(bool success, assertType::Enum at) { + return success ? Color::BrightGreen : (at & assertType::is_warn) ? Color::Yellow : Color::Red; +} + +void ConsoleReporter::successOrFailColoredStringToStream(bool success, assertType::Enum at, const char *success_str) { + s << getSuccessOrFailColor(success, at) << getSuccessOrFailString(success, at, success_str) << ": "; +} + +void ConsoleReporter::log_contexts() { + const int num_contexts = get_num_active_contexts(); + if (num_contexts) { + auto contexts = get_active_contexts(); + + s << Color::None << " logged: "; + for (int i = 0; i < num_contexts; ++i) { + s << (i == 0 ? "" : " "); + contexts[i]->stringify(&s); + s << "\n"; + } + } + + s << "\n"; +} + +// this was requested to be made virtual so users could override it +void ConsoleReporter::file_line_to_stream(const char *file, int line, const char *tail) { + s << Color::LightGrey << skipPathFromFilename(file) << (opt.gnu_file_line ? ":" : "(") + << (opt.no_line_numbers ? 0 : line) // 0 or the real num depending on the option + << (opt.gnu_file_line ? ":" : "):") << tail; +} + +void ConsoleReporter::logTestStart() { + if (hasLoggedCurrentTestStart) + return; + + separator_to_stream(); + file_line_to_stream(tc->m_file.c_str(), static_cast(tc->m_line), "\n"); + if (tc->m_description) + s << Color::Yellow << "DESCRIPTION: " << Color::None << tc->m_description << "\n"; + if (tc->m_test_suite && tc->m_test_suite[0] != '\0') + s << Color::Yellow << "TEST SUITE: " << Color::None << tc->m_test_suite << "\n"; + if (strncmp(tc->m_name, " Scenario:", 11) != 0) + s << Color::Yellow << "TEST CASE: "; + s << Color::None << tc->m_name << "\n"; + + for (size_t i = 0; i < currentSubcaseLevel; ++i) { + if (subcasesStack[i].m_name[0] != '\0') + s << " " << subcasesStack[i].m_name << "\n"; + } + + if (currentSubcaseLevel != subcasesStack.size()) { + s << Color::Yellow << "\nDEEPEST SUBCASE STACK REACHED (DIFFERENT FROM THE CURRENT ONE):\n" << Color::None; + for (size_t i = 0; i < subcasesStack.size(); ++i) { + if (subcasesStack[i].m_name[0] != '\0') + s << " " << subcasesStack[i].m_name << "\n"; + } + } + + s << "\n"; + + hasLoggedCurrentTestStart = true; +} + +void ConsoleReporter::printVersion() { + if (opt.no_version == false) + s << Color::Cyan << "[doctest] " << Color::None << "doctest version is \"" << DOCTEST_VERSION_STR << "\"\n"; +} + +void ConsoleReporter::printIntro() { + if (opt.no_intro == false) { + printVersion(); + s << Color::Cyan << "[doctest] " << Color::None + << "run with \"--" DOCTEST_OPTIONS_PREFIX_DISPLAY "help\" for options\n"; + } +} + +void ConsoleReporter::printHelp() { + const int sizePrefixDisplay = static_cast(strlen(DOCTEST_OPTIONS_PREFIX_DISPLAY)); + printVersion(); + // clang-format off + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "boolean values: \"1/on/yes/true\" or \"0/off/no/false\"\n"; + s << Color::Cyan << "[doctest] " << Color::None; + s << "filter values: \"str1,str2,str3\" (comma separated strings)\n"; + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "filters use wildcards for matching strings\n"; + s << Color::Cyan << "[doctest] " << Color::None; + s << "something passes a filter if any of the strings in a filter matches\n"; +#ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "ALL FLAGS, OPTIONS AND FILTERS ALSO AVAILABLE WITH A \"" DOCTEST_CONFIG_OPTIONS_PREFIX "\" PREFIX!!!\n"; +#endif + s << Color::Cyan << "[doctest]\n" << Color::None; + s << Color::Cyan << "[doctest] " << Color::None; + s << "Query flags - the program quits after them. Available:\n\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "?, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "help, -" DOCTEST_OPTIONS_PREFIX_DISPLAY "h " + << Whitespace(sizePrefixDisplay * 0) << "prints this message\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "v, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "version " + << Whitespace(sizePrefixDisplay * 1) << "prints the version\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "c, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "count " + << Whitespace(sizePrefixDisplay * 1) << "prints the number of matching tests\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ltc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-cases " + << Whitespace(sizePrefixDisplay * 1) << "lists all matching tests by name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-test-suites " + << Whitespace(sizePrefixDisplay * 1) << "lists all matching test suites\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "lr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "list-reporters " + << Whitespace(sizePrefixDisplay * 1) << "lists all registered reporters\n\n"; + // ================================================================================== << 79 + s << Color::Cyan << "[doctest] " << Color::None; + s << "The available / options/filters are:\n\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case= " + << Whitespace(sizePrefixDisplay * 1) << "filters tests by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-case-exclude= " + << Whitespace(sizePrefixDisplay * 1) << "filters OUT tests by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file= " + << Whitespace(sizePrefixDisplay * 1) << "filters tests by their file\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sfe, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "source-file-exclude= " + << Whitespace(sizePrefixDisplay * 1) << "filters OUT tests by their file\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ts, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite= " + << Whitespace(sizePrefixDisplay * 1) << "filters tests by their test suite\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "tse, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "test-suite-exclude= " + << Whitespace(sizePrefixDisplay * 1) << "filters OUT tests by their test suite\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase= " + << Whitespace(sizePrefixDisplay * 1) << "filters subcases by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sce, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-exclude= " + << Whitespace(sizePrefixDisplay * 1) << "filters OUT subcases by their name\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "r, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "reporters= " + << Whitespace(sizePrefixDisplay * 1) << "reporters to use (console is default)\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "o, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "out= " + << Whitespace(sizePrefixDisplay * 1) << "output filename\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ob, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "order-by= " + << Whitespace(sizePrefixDisplay * 1) << "how the tests should be ordered\n"; + s << Whitespace(sizePrefixDisplay * 3) << " - [file/suite/name/rand/none]\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "rs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "rand-seed= " + << Whitespace(sizePrefixDisplay * 1) << "seed for random ordering\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "f, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "first= " + << Whitespace(sizePrefixDisplay * 1) << "the first test passing the filters to\n"; + s << Whitespace(sizePrefixDisplay * 3) << " execute - for range-based execution\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "l, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "last= " + << Whitespace(sizePrefixDisplay * 1) << "the last test passing the filters to\n"; + s << Whitespace(sizePrefixDisplay * 3) << " execute - for range-based execution\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "aa, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "abort-after= " + << Whitespace(sizePrefixDisplay * 1) << "stop after failed assertions\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "scfl,--" DOCTEST_OPTIONS_PREFIX_DISPLAY "subcase-filter-levels= " + << Whitespace(sizePrefixDisplay * 1) << "apply filters for the first levels\n"; + s << Color::Cyan << "\n[doctest] " << Color::None; + s << "Bool options - can be used like flags and true is assumed. Available:\n\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "s, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "success= " + << Whitespace(sizePrefixDisplay * 1) << "include successful assertions in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "cs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "case-sensitive= " + << Whitespace(sizePrefixDisplay * 1) << "filters being treated as case sensitive\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "e, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "exit= " + << Whitespace(sizePrefixDisplay * 1) << "exits after the tests finish\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "d, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "duration= " + << Whitespace(sizePrefixDisplay * 1) << "prints the time duration of each test\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "m, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "minimal= " + << Whitespace(sizePrefixDisplay * 1) << "minimal console output (only failures)\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "q, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "quiet= " + << Whitespace(sizePrefixDisplay * 1) << "no console output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nt, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-throw= " + << Whitespace(sizePrefixDisplay * 1) << "skips exceptions-related assert checks\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ne, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-exitcode= " + << Whitespace(sizePrefixDisplay * 1) << "returns (or exits) always with success\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nr, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-run= " + << Whitespace(sizePrefixDisplay * 1) << "skips all runtime doctest operations\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ni, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-intro= " + << Whitespace(sizePrefixDisplay * 1) << "omit the framework intro in the output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nv, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-version= " + << Whitespace(sizePrefixDisplay * 1) << "omit the framework version in the output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-colors= " + << Whitespace(sizePrefixDisplay * 1) << "disables colors in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "fc, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "force-colors= " + << Whitespace(sizePrefixDisplay * 1) << "use colors even when not in a tty\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nb, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-breaks= " + << Whitespace(sizePrefixDisplay * 1) << "disables breakpoints in debuggers\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ns, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-skip= " + << Whitespace(sizePrefixDisplay * 1) << "don't skip test cases marked as skip\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "gfl, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "gnu-file-line= " + << Whitespace(sizePrefixDisplay * 1) << ":n: vs (n): for line numbers in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "npf, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-path-filenames= " + << Whitespace(sizePrefixDisplay * 1) << "only filenames and no paths in output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "sfp, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "strip-file-prefixes= " + << Whitespace(sizePrefixDisplay * 1) << "whenever file paths start with this prefix, remove it from the output\n"; + s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "nln, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "no-line-numbers= " + << Whitespace(sizePrefixDisplay * 1) << "0 instead of real line numbers in output\n"; + // ================================================================================== << 79 + // clang-format on + + s << Color::Cyan << "\n[doctest] " << Color::None; + s << "for more information visit the project documentation\n\n"; +} + +void ConsoleReporter::printRegisteredReporters() { + printVersion(); + auto printReporters = [this](const detail::reporterMap &reporters, const char *type) { + if (!reporters.empty()) { + s << Color::Cyan << "[doctest] " << Color::None << "listing all registered " << type << "\n"; + for (auto &curr: reporters) + s << "priority: " << std::setw(5) << curr.first.first << " name: " << curr.first.second << "\n"; + } + }; + printReporters(detail::getListeners(), "listeners"); + printReporters(detail::getReporters(), "reporters"); +} + +void ConsoleReporter::report_query(const QueryData &in) { + if (opt.version) { + printVersion(); + } else if (opt.help) { + printHelp(); + } else if (opt.list_reporters) { + printRegisteredReporters(); + } else if (opt.count || opt.list_test_cases) { + if (opt.list_test_cases) { + s << Color::Cyan << "[doctest] " << Color::None << "listing all test case names\n"; + separator_to_stream(); + } + + for (unsigned i = 0; i < in.num_data; ++i) + s << Color::None << in.data[i]->m_name << "\n"; + + separator_to_stream(); + + s << Color::Cyan << "[doctest] " << Color::None + << "unskipped test cases passing the current filters: " << g_cs->numTestCasesPassingFilters << "\n"; + + } else if (opt.list_test_suites) { + s << Color::Cyan << "[doctest] " << Color::None << "listing all test suites\n"; + separator_to_stream(); + + for (unsigned i = 0; i < in.num_data; ++i) + s << Color::None << in.data[i]->m_test_suite << "\n"; + + separator_to_stream(); + + s << Color::Cyan << "[doctest] " << Color::None + << "unskipped test cases passing the current filters: " << g_cs->numTestCasesPassingFilters << "\n"; + s << Color::Cyan << "[doctest] " << Color::None + << "test suites with unskipped test cases passing the current filters: " << g_cs->numTestSuitesPassingFilters + << "\n"; + } +} + +void ConsoleReporter::test_run_start() { + if (!opt.minimal) + printIntro(); +} + +void ConsoleReporter::test_run_end(const TestRunStats &p) { + if (opt.minimal && p.numTestCasesFailed == 0) + return; + + separator_to_stream(); + s << std::dec; + + auto totwidth = static_cast(std::ceil( + log10(static_cast(std::max(p.numTestCasesPassingFilters, static_cast(p.numAsserts))) + 1) + )); + auto passwidth = static_cast(std::ceil(log10( + static_cast(std::max( + p.numTestCasesPassingFilters - p.numTestCasesFailed, + static_cast(p.numAsserts - p.numAssertsFailed) + )) + + 1 + ))); + auto failwidth = static_cast(std::ceil( + log10(static_cast(std::max(p.numTestCasesFailed, static_cast(p.numAssertsFailed))) + 1) + )); + const bool anythingFailed = p.numTestCasesFailed > 0 || p.numAssertsFailed > 0; + s << Color::Cyan << "[doctest] " << Color::None << "test cases: " << std::setw(totwidth) + << p.numTestCasesPassingFilters << " | " + << ((p.numTestCasesPassingFilters == 0 || anythingFailed) ? Color::None : Color::Green) << std::setw(passwidth) + << p.numTestCasesPassingFilters - p.numTestCasesFailed << " passed" << Color::None << " | " + << (p.numTestCasesFailed > 0 ? Color::Red : Color::None) << std::setw(failwidth) << p.numTestCasesFailed + << " failed" << Color::None << " |"; + if (opt.no_skipped_summary == false) { + const unsigned int numSkipped = p.numTestCases - p.numTestCasesPassingFilters; + s << " " << (numSkipped == 0 ? Color::None : Color::Yellow) << numSkipped << " skipped" << Color::None; + } + s << "\n"; + s << Color::Cyan << "[doctest] " << Color::None << "assertions: " << std::setw(totwidth) << p.numAsserts << " | " + << ((p.numAsserts == 0 || anythingFailed) ? Color::None : Color::Green) << std::setw(passwidth) + << (p.numAsserts - p.numAssertsFailed) << " passed" << Color::None << " | " + << (p.numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(failwidth) << p.numAssertsFailed << " failed" + << Color::None << " |\n"; + s << Color::Cyan << "[doctest] " << Color::None + << "Status: " << (p.numTestCasesFailed > 0 ? Color::Red : Color::Green) + << ((p.numTestCasesFailed > 0) ? "FAILURE!" : "SUCCESS!") << Color::None << std::endl; +} + +void ConsoleReporter::test_case_start(const TestCaseData &in) { + DOCTEST_LOCK_MUTEX(mutex) + hasLoggedCurrentTestStart = false; + tc = ∈ + subcasesStack.clear(); + currentSubcaseLevel = 0; +} + +void ConsoleReporter::test_case_reenter(const TestCaseData &) { + DOCTEST_LOCK_MUTEX(mutex) + subcasesStack.clear(); +} + +void ConsoleReporter::test_case_end(const CurrentTestCaseStats &st) { + DOCTEST_LOCK_MUTEX(mutex) + if (tc->m_no_output) + return; + + // log the preamble of the test case only if there is something + // else to print - something other than that an assert has failed + if (opt.duration || + (st.failure_flags && st.failure_flags != static_cast(TestCaseFailureReason::AssertFailure))) + logTestStart(); + + if (opt.duration) + s << Color::None << std::setprecision(6) << std::fixed << st.seconds << " s: " << tc->m_name << "\n"; + + if (st.failure_flags & TestCaseFailureReason::Timeout) + s << Color::Red << "Test case exceeded time limit of " << std::setprecision(6) << std::fixed << tc->m_timeout + << "!\n"; + + if (st.failure_flags & TestCaseFailureReason::ShouldHaveFailedButDidnt) { + s << Color::Red << "Should have failed but didn't! Marking it as failed!\n"; + } else if (st.failure_flags & TestCaseFailureReason::ShouldHaveFailedAndDid) { + s << Color::Yellow << "Failed as expected so marking it as not failed\n"; + } else if (st.failure_flags & TestCaseFailureReason::CouldHaveFailedAndDid) { + s << Color::Yellow << "Allowed to fail so marking it as not failed\n"; + } else if (st.failure_flags & TestCaseFailureReason::DidntFailExactlyNumTimes) { + s << Color::Red << "Didn't fail exactly " << tc->m_expected_failures << " times so marking it as failed!\n"; + } else if (st.failure_flags & TestCaseFailureReason::FailedExactlyNumTimes) { + s << Color::Yellow << "Failed exactly " << tc->m_expected_failures + << " times as expected so marking it as not failed!\n"; + } + if (st.failure_flags & TestCaseFailureReason::TooManyFailedAsserts) { + s << Color::Red << "Aborting - too many failed asserts!\n"; + } + s << Color::None; +} + +void ConsoleReporter::test_case_exception(const TestCaseException &e) { + DOCTEST_LOCK_MUTEX(mutex) + if (tc->m_no_output) + return; + + logTestStart(); + + file_line_to_stream(tc->m_file.c_str(), static_cast(tc->m_line), " "); + successOrFailColoredStringToStream(false, e.is_crash ? assertType::is_require : assertType::is_check); + s << Color::Red << (e.is_crash ? "test case CRASHED: " : "test case THREW exception: "); + s << Color::Cyan << e.error_string << "\n"; + + const int num_stringified_contexts = get_num_stringified_contexts(); + if (num_stringified_contexts) { + auto stringified_contexts = get_stringified_contexts(); + s << Color::None << " logged: "; + for (int i = num_stringified_contexts; i > 0; --i) { + s << (i == num_stringified_contexts ? "" : " ") << stringified_contexts[i - 1] << "\n"; + } + } + s << "\n" << Color::None; +} + +void ConsoleReporter::subcase_start(const SubcaseSignature &subc) { + DOCTEST_LOCK_MUTEX(mutex) + subcasesStack.push_back(subc); + ++currentSubcaseLevel; + hasLoggedCurrentTestStart = false; +} + +void ConsoleReporter::subcase_end() { + DOCTEST_LOCK_MUTEX(mutex) + --currentSubcaseLevel; + hasLoggedCurrentTestStart = false; +} + +void ConsoleReporter::log_assert(const AssertData &rb) { + if ((!rb.m_failed && !opt.success) || tc->m_no_output) + return; + + DOCTEST_LOCK_MUTEX(mutex) + + logTestStart(); + + file_line_to_stream(rb.m_file, rb.m_line, " "); + successOrFailColoredStringToStream(!rb.m_failed, rb.m_at); + + fulltext_log_assert_to_stream(s, rb); + + log_contexts(); +} + +void ConsoleReporter::log_message(const MessageData &mb) { + if (tc->m_no_output) + return; + + DOCTEST_LOCK_MUTEX(mutex) + + logTestStart(); + + file_line_to_stream(mb.m_file, mb.m_line, " "); + s << getSuccessOrFailColor(false, mb.m_severity) + << getSuccessOrFailString(mb.m_severity & assertType::is_warn, mb.m_severity, "MESSAGE") << ": "; + s << Color::None << mb.m_string << "\n"; + log_contexts(); +} + +void ConsoleReporter::test_case_skipped(const TestCaseData &) {} + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +#ifdef DOCTEST_PLATFORM_WINDOWS +#define DOCTEST_OUTPUT_DEBUG_STRING(text) ::OutputDebugStringA(text) +#endif // Platform + +#ifdef DOCTEST_PLATFORM_WINDOWS + +DOCTEST_THREAD_LOCAL std::ostringstream DebugOutputWindowReporter::oss; + +DebugOutputWindowReporter::DebugOutputWindowReporter(const ContextOptions &co) + : ConsoleReporter(co, oss) {} + +#define DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(func, type, arg) \ + void DebugOutputWindowReporter::func(type arg) { \ + using detail::g_no_colors; \ + bool with_col = g_no_colors; \ + g_no_colors = false; \ + ConsoleReporter::func(arg); \ + if (oss.tellp() != std::streampos{}) { \ + DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \ + oss.str(""); \ + } \ + g_no_colors = with_col; \ + } + +DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_start, DOCTEST_EMPTY, DOCTEST_EMPTY) +DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_run_end, const TestRunStats &, in) +DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_start, const TestCaseData &, in) +DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_reenter, const TestCaseData &, in) +DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_end, const CurrentTestCaseStats &, in) +DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_exception, const TestCaseException &, in) +DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_start, const SubcaseSignature &, in) +DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(subcase_end, DOCTEST_EMPTY, DOCTEST_EMPTY) +DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_assert, const AssertData &, in) +DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(log_message, const MessageData &, in) +DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(test_case_skipped, const TestCaseData &, in) + +#endif // DOCTEST_PLATFORM_WINDOWS + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { + +std::string JUnitReporter::JUnitTestCaseData::getCurrentTimestamp() { + // Beware, this is not reentrant because of backward compatibility issues + // Also, UTC only, again because of backward compatibility (%z is C++11) + time_t rawtime{}; + static_cast(std::time(&rawtime)); + const auto timeStampSize = sizeof("2017-01-16T17:06:45Z"); + + std::tm timeInfo; +#if defined(DOCTEST_PLATFORM_WINDOWS) + gmtime_s(&timeInfo, &rawtime); +#elif defined(__STDC_LIB_EXT1__) + gmtime_s(&rawtime, &timeInfo); +#else // DOCTEST_PLATFORM_WINDOWS + gmtime_r(&rawtime, &timeInfo); +#endif // DOCTEST_PLATFORM_WINDOWS + + char timeStamp[timeStampSize]; + const char *const fmt = "%Y-%m-%dT%H:%M:%SZ"; + + static_cast(std::strftime(timeStamp, timeStampSize, fmt, &timeInfo)); + return std::string(timeStamp); +} + +JUnitReporter::JUnitTestCaseData::JUnitTestMessage::JUnitTestMessage( + const std::string &_message, const std::string &_type, const std::string &_details +) + : message(_message), type(_type), details(_details) {} + +JUnitReporter::JUnitTestCaseData::JUnitTestMessage::JUnitTestMessage( + const std::string &_message, const std::string &_details +) + : message(_message), type(), details(_details) {} + +JUnitReporter::JUnitTestCaseData::JUnitTestCase::JUnitTestCase(const std::string &_classname, const std::string &_name) + : classname(_classname), name(_name), time(0), failures(), errors() {} + +void JUnitReporter::JUnitTestCaseData::add(const std::string &classname, const std::string &name) { + testcases.emplace_back(classname, name); +} + +void JUnitReporter::JUnitTestCaseData::appendSubcaseNamesToLastTestcase(std::vector nameStack) { + for (auto &curr: nameStack) + if (curr.size()) + testcases.back().name += std::string("/") + curr.c_str(); +} + +void JUnitReporter::JUnitTestCaseData::addTime(double time) { + if (time < 1e-4) + time = 0; + testcases.back().time = time; + totalSeconds += time; +} + +void JUnitReporter::JUnitTestCaseData::addFailure( + const std::string &message, const std::string &type, const std::string &details +) { + testcases.back().failures.emplace_back(message, type, details); + ++totalFailures; +} + +void JUnitReporter::JUnitTestCaseData::addError(const std::string &message, const std::string &details) { + testcases.back().errors.emplace_back(message, details); + ++totalErrors; +} + +JUnitReporter::JUnitReporter(const ContextOptions &co) + : xml(*co.cout), opt(co) {} + +unsigned JUnitReporter::line(unsigned l) const { + return opt.no_line_numbers ? 0 : l; +} + +void JUnitReporter::report_query(const QueryData &) { + xml.writeDeclaration(); +} + +void JUnitReporter::test_run_start() { + xml.writeDeclaration(); +} + +void JUnitReporter::test_run_end(const TestRunStats &p) { + // remove .exe extension - mainly to have the same output on UNIX and Windows + // NOLINTNEXTLINE(misc-const-correctness) + std::string binary_name = skipPathFromFilename(opt.binary_name.c_str()); +#ifdef DOCTEST_PLATFORM_WINDOWS + if (binary_name.rfind(".exe") != std::string::npos) + binary_name = binary_name.substr(0, binary_name.length() - 4); +#endif // DOCTEST_PLATFORM_WINDOWS + + xml.startElement("testsuites"); + xml.startElement("testsuite") + .writeAttribute("name", binary_name) + .writeAttribute("errors", testCaseData.totalErrors) + .writeAttribute("failures", testCaseData.totalFailures) + .writeAttribute("tests", p.numAsserts); + if (opt.no_time_in_output == false) { + xml.writeAttribute("time", testCaseData.totalSeconds); + xml.writeAttribute("timestamp", JUnitTestCaseData::getCurrentTimestamp()); + } + if (opt.no_version == false) + xml.writeAttribute("doctest_version", DOCTEST_VERSION_STR); + + for (const auto &testCase: testCaseData.testcases) { + xml.startElement("testcase") + .writeAttribute("classname", testCase.classname) + .writeAttribute("name", testCase.name); + if (opt.no_time_in_output == false) + xml.writeAttribute("time", testCase.time); + // This is not ideal, but it should be enough to mimic gtest's junit output. + xml.writeAttribute("status", "run"); + + for (const auto &failure: testCase.failures) { + xml.scopedElement("failure") + .writeAttribute("message", failure.message) + .writeAttribute("type", failure.type) + .writeText(failure.details, false); + } + + for (const auto &error: testCase.errors) { + xml.scopedElement("error").writeAttribute("message", error.message).writeText(error.details); + } + + xml.endElement(); + } + xml.endElement(); + xml.endElement(); +} + +void JUnitReporter::test_case_start(const TestCaseData &in) { + DOCTEST_LOCK_MUTEX(mutex) + testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); + timer.start(); + tc = ∈ +} + +void JUnitReporter::test_case_reenter(const TestCaseData &in) { + DOCTEST_LOCK_MUTEX(mutex) + testCaseData.addTime(timer.getElapsedSeconds()); + testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); + deepestSubcaseStackNames.clear(); + + timer.start(); + testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); + tc = ∈ +} + +void JUnitReporter::test_case_end(const CurrentTestCaseStats &st) { + DOCTEST_LOCK_MUTEX(mutex) + testCaseData.addTime(timer.getElapsedSeconds()); + testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); + deepestSubcaseStackNames.clear(); + + if (st.failure_flags & TestCaseFailureReason::Timeout) { + auto *stream = detail::tlssPush(); + *stream << "Test case exceeded time limit of " << std::setprecision(6) << std::fixed << tc->m_timeout; + testCaseData.addError("timeout", detail::tlssPop().c_str()); + } + + if (st.failure_flags & TestCaseFailureReason::ShouldHaveFailedButDidnt) { + testCaseData.addError("should_fail", "Should have failed, but didn't"); + } else if (st.failure_flags & TestCaseFailureReason::DidntFailExactlyNumTimes) { + auto *stream = detail::tlssPush(); + *stream << "Should have failed exactly " << tc->m_expected_failures << " times, but didn't"; + testCaseData.addError("should_fail", detail::tlssPop().c_str()); + } + + if (st.failure_flags & TestCaseFailureReason::TooManyFailedAsserts) { + testCaseData.addError("abort_after", "Too many failed asserts"); + } + + tc = nullptr; +} + +void JUnitReporter::test_case_exception(const TestCaseException &e) { + DOCTEST_LOCK_MUTEX(mutex) + testCaseData.addError("exception", e.error_string.c_str()); +} + +void JUnitReporter::subcase_start(const SubcaseSignature &in) { + DOCTEST_LOCK_MUTEX(mutex) + deepestSubcaseStackNames.push_back(in.m_name); +} + +void JUnitReporter::subcase_end() {} + +void JUnitReporter::log_assert(const AssertData &rb) { + if (!rb.m_failed) // report only failures & ignore the `success` option + return; + + DOCTEST_LOCK_MUTEX(mutex) + + std::ostringstream os; + os << skipPathFromFilename(rb.m_file) << (opt.gnu_file_line ? ":" : "(") << line(rb.m_line) + << (opt.gnu_file_line ? ":" : "):") << std::endl; + + fulltext_log_assert_to_stream(os, rb); + log_contexts(os); + testCaseData.addFailure(rb.m_decomp.c_str(), assertString(rb.m_at), os.str()); +} + +void JUnitReporter::log_message(const MessageData &mb) { + if (mb.m_severity & assertType::is_warn) // report only failures + return; + + DOCTEST_LOCK_MUTEX(mutex) + + std::ostringstream os; + os << skipPathFromFilename(mb.m_file) << (opt.gnu_file_line ? ":" : "(") << line(mb.m_line) + << (opt.gnu_file_line ? ":" : "):") << std::endl; + + os << mb.m_string.c_str() << "\n"; + log_contexts(os); + + testCaseData.addFailure( + mb.m_string.c_str(), mb.m_severity & assertType::is_check ? "FAIL_CHECK" : "FAIL", os.str() + ); +} + +void JUnitReporter::test_case_skipped(const TestCaseData &) {} + +void JUnitReporter::log_contexts(std::ostringstream &s) { + const int num_contexts = get_num_active_contexts(); + if (num_contexts) { + auto contexts = get_active_contexts(); + + s << " logged: "; + for (int i = 0; i < num_contexts; ++i) { + s << (i == 0 ? "" : " "); + contexts[i]->stringify(&s); + s << std::endl; + } + } +} + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { + +XmlReporter::XmlReporter(const ContextOptions &co) + : xml(*co.cout), opt(co) {} + +void XmlReporter::log_contexts() { + const int num_contexts = get_num_active_contexts(); + if (num_contexts) { + auto contexts = get_active_contexts(); + std::stringstream ss; + for (int i = 0; i < num_contexts; ++i) { + contexts[i]->stringify(&ss); + xml.scopedElement("Info").writeText(ss.str()); + ss.str(""); + } + } +} + +unsigned XmlReporter::line(unsigned l) const { + return opt.no_line_numbers ? 0 : l; +} + +void XmlReporter::test_case_start_impl(const TestCaseData &in) { + bool open_ts_tag = false; + if (tc != nullptr) { // we have already opened a test suite + if (std::strcmp(tc->m_test_suite, in.m_test_suite) != 0) { + xml.endElement(); + open_ts_tag = true; + } + } else { + open_ts_tag = true; // first test case ==> first test suite + } + + if (open_ts_tag) { + xml.startElement("TestSuite"); + xml.writeAttribute("name", in.m_test_suite); + } + + tc = ∈ + xml.startElement("TestCase") + .writeAttribute("name", in.m_name) + .writeAttribute("filename", skipPathFromFilename(in.m_file.c_str())) + .writeAttribute("line", line(in.m_line)) + .writeAttribute("description", in.m_description); + + if (Approx(in.m_timeout) != 0) + xml.writeAttribute("timeout", in.m_timeout); + if (in.m_may_fail) + xml.writeAttribute("may_fail", true); + if (in.m_should_fail) + xml.writeAttribute("should_fail", true); +} + +void XmlReporter::report_query(const QueryData &in) { + test_run_start(); + if (opt.list_reporters) { + for (auto &curr: detail::getListeners()) + xml.scopedElement("Listener") + .writeAttribute("priority", curr.first.first) + .writeAttribute("name", curr.first.second); + for (auto &curr: detail::getReporters()) + xml.scopedElement("Reporter") + .writeAttribute("priority", curr.first.first) + .writeAttribute("name", curr.first.second); + } else if (opt.count || opt.list_test_cases) { + for (unsigned i = 0; i < in.num_data; ++i) { + xml.scopedElement("TestCase") + .writeAttribute("name", in.data[i]->m_name) + .writeAttribute("testsuite", in.data[i]->m_test_suite) + .writeAttribute("filename", skipPathFromFilename(in.data[i]->m_file.c_str())) + .writeAttribute("line", line(in.data[i]->m_line)) + .writeAttribute("skipped", in.data[i]->m_skip); + } + xml.scopedElement("OverallResultsTestCases") + .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); + } else if (opt.list_test_suites) { + for (unsigned i = 0; i < in.num_data; ++i) + xml.scopedElement("TestSuite").writeAttribute("name", in.data[i]->m_test_suite); + xml.scopedElement("OverallResultsTestCases") + .writeAttribute("unskipped", in.run_stats->numTestCasesPassingFilters); + xml.scopedElement("OverallResultsTestSuites") + .writeAttribute("unskipped", in.run_stats->numTestSuitesPassingFilters); + } + xml.endElement(); +} + +void XmlReporter::test_run_start() { + xml.writeDeclaration(); + + // remove .exe extension - mainly to have the same output on UNIX and Windows + // NOLINTNEXTLINE(misc-const-correctness) + std::string binary_name = skipPathFromFilename(opt.binary_name.c_str()); +#ifdef DOCTEST_PLATFORM_WINDOWS + if (binary_name.rfind(".exe") != std::string::npos) + binary_name = binary_name.substr(0, binary_name.length() - 4); +#endif // DOCTEST_PLATFORM_WINDOWS + + xml.startElement("doctest").writeAttribute("binary", binary_name); + if (opt.no_version == false) + xml.writeAttribute("version", DOCTEST_VERSION_STR); + + // only the consequential ones (TODO: filters) + xml.scopedElement("Options") + .writeAttribute("order_by", opt.order_by.c_str()) + .writeAttribute("rand_seed", opt.rand_seed) + .writeAttribute("first", opt.first) + .writeAttribute("last", opt.last) + .writeAttribute("abort_after", opt.abort_after) + .writeAttribute("subcase_filter_levels", opt.subcase_filter_levels) + .writeAttribute("case_sensitive", opt.case_sensitive) + .writeAttribute("no_throw", opt.no_throw) + .writeAttribute("no_skip", opt.no_skip); +} + +void XmlReporter::test_run_end(const TestRunStats &p) { + if (tc) // the TestSuite tag - only if there has been at least 1 test case + xml.endElement(); + + xml.scopedElement("OverallResultsAsserts") + .writeAttribute("successes", p.numAsserts - p.numAssertsFailed) + .writeAttribute("failures", p.numAssertsFailed); + + xml.startElement("OverallResultsTestCases") + .writeAttribute("successes", p.numTestCasesPassingFilters - p.numTestCasesFailed) + .writeAttribute("failures", p.numTestCasesFailed); + if (opt.no_skipped_summary == false) + xml.writeAttribute("skipped", p.numTestCases - p.numTestCasesPassingFilters); + xml.endElement(); + + xml.endElement(); +} + +void XmlReporter::test_case_start(const TestCaseData &in) { + DOCTEST_LOCK_MUTEX(mutex) + test_case_start_impl(in); + xml.ensureTagClosed(); +} + +void XmlReporter::test_case_reenter(const TestCaseData &) {} + +void XmlReporter::test_case_end(const CurrentTestCaseStats &st) { + DOCTEST_LOCK_MUTEX(mutex) + xml.startElement("OverallResultsAsserts") + .writeAttribute("successes", st.numAssertsCurrentTest - st.numAssertsFailedCurrentTest) + .writeAttribute("failures", st.numAssertsFailedCurrentTest) + .writeAttribute("test_case_success", st.testCaseSuccess); + if (opt.duration) + xml.writeAttribute("duration", st.seconds); + if (tc->m_expected_failures) + xml.writeAttribute("expected_failures", tc->m_expected_failures); + xml.endElement(); + + xml.endElement(); +} + +void XmlReporter::test_case_exception(const TestCaseException &e) { + DOCTEST_LOCK_MUTEX(mutex) + + xml.scopedElement("Exception").writeAttribute("crash", e.is_crash).writeText(e.error_string.c_str()); +} + +void XmlReporter::subcase_start(const SubcaseSignature &in) { + DOCTEST_LOCK_MUTEX(mutex) + xml.startElement("SubCase") + .writeAttribute("name", in.m_name) + .writeAttribute("filename", skipPathFromFilename(in.m_file)) + .writeAttribute("line", line(in.m_line)); + xml.ensureTagClosed(); +} + +void XmlReporter::subcase_end() { + DOCTEST_LOCK_MUTEX(mutex) + xml.endElement(); +} + +void XmlReporter::log_assert(const AssertData &rb) { + if (!rb.m_failed && !opt.success) + return; + + DOCTEST_LOCK_MUTEX(mutex) + + xml.startElement("Expression") + .writeAttribute("success", !rb.m_failed) + .writeAttribute("type", assertString(rb.m_at)) + .writeAttribute("filename", skipPathFromFilename(rb.m_file)) + .writeAttribute("line", line(rb.m_line)); + + xml.scopedElement("Original").writeText(rb.m_expr); + + if (rb.m_threw) + xml.scopedElement("Exception").writeText(rb.m_exception.c_str()); + + if (rb.m_at & assertType::is_throws_as) + xml.scopedElement("ExpectedException").writeText(rb.m_exception_type); + if (rb.m_at & assertType::is_throws_with) + xml.scopedElement("ExpectedExceptionString").writeText(rb.m_exception_string.c_str()); + if ((rb.m_at & assertType::is_normal) && !rb.m_threw) + xml.scopedElement("Expanded").writeText(rb.m_decomp.c_str()); + + log_contexts(); + + xml.endElement(); +} + +void XmlReporter::log_message(const MessageData &mb) { + DOCTEST_LOCK_MUTEX(mutex) + + xml.startElement("Message") + .writeAttribute("type", failureString(mb.m_severity)) + .writeAttribute("filename", skipPathFromFilename(mb.m_file)) + .writeAttribute("line", line(mb.m_line)); + + xml.scopedElement("Text").writeText(mb.m_string.c_str()); + + log_contexts(); + + xml.endElement(); +} + +void XmlReporter::test_case_skipped(const TestCaseData &in) { + if (opt.no_skipped_summary == false) { + DOCTEST_LOCK_MUTEX(mutex) + test_case_start_impl(in); + xml.writeAttribute("skipped", "true"); + xml.endElement(); + } +} + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +#if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH) +void FatalConditionHandler::reset() {} +void FatalConditionHandler::allocateAltStackMem() {} +void FatalConditionHandler::freeAltStackMem() {} +#else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + +#ifdef DOCTEST_PLATFORM_WINDOWS + +// There is no 1-1 mapping between signals and windows exceptions. +// Windows can easily distinguish between SO and SigSegV, +// but SigInt, SigTerm, etc are handled differently. +SignalDefs signalDefs[] = { + {static_cast(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal"}, + {static_cast(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow"}, + {static_cast(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal"}, + {static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error"}, +}; + +LONG CALLBACK FatalConditionHandler::handleException(PEXCEPTION_POINTERS ExceptionInfo) { + // Multiple threads may enter this filter/handler at once. We want the error message to be + // printed on the console just once no matter how many threads have crashed. + DOCTEST_DECLARE_STATIC_MUTEX(mutex) + static bool execute = true; + { + DOCTEST_LOCK_MUTEX(mutex) + if (execute) { + bool reported = false; + for (size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { + reportFatal(signalDefs[i].name); + reported = true; + break; + } + } + if (reported == false) + reportFatal("Unhandled SEH exception caught"); + if (isDebuggerActive() && !g_cs->no_breaks) + DOCTEST_BREAK_INTO_DEBUGGER(); + } + execute = false; + } + std::exit(EXIT_FAILURE); +} + +void FatalConditionHandler::allocateAltStackMem() {} +void FatalConditionHandler::freeAltStackMem() {} + +FatalConditionHandler::FatalConditionHandler() { + isSet = true; + // 32k seems enough for doctest to handle stack overflow, + // but the value was found experimentally, so there is no strong guarantee + guaranteeSize = 32 * 1024; + // Register an unhandled exception filter + previousTop = SetUnhandledExceptionFilter(handleException); + // Pass in guarantee size to be filled + SetThreadStackGuarantee(&guaranteeSize); + + // On Windows uncaught exceptions from another thread, exceptions from + // destructors, or calls to std::terminate are not a SEH exception + + // The terminal handler gets called when: + // - std::terminate is called FROM THE TEST RUNNER THREAD + // - an exception is thrown from a destructor FROM THE TEST RUNNER THREAD + original_terminate_handler = std::get_terminate(); + std::set_terminate([]() DOCTEST_NOEXCEPT { + reportFatal("Terminate handler called"); + if (isDebuggerActive() && !g_cs->no_breaks) + DOCTEST_BREAK_INTO_DEBUGGER(); + std::exit(EXIT_FAILURE); // explicitly exit - otherwise the SIGABRT handler may be called as well + }); + + // SIGABRT is raised when: + // - std::terminate is called FROM A DIFFERENT THREAD + // - an exception is thrown from a destructor FROM A DIFFERENT THREAD + // - an uncaught exception is thrown FROM A DIFFERENT THREAD + prev_sigabrt_handler = std::signal(SIGABRT, [](int signal) DOCTEST_NOEXCEPT { + if (signal == SIGABRT) { + reportFatal("SIGABRT - Abort (abnormal termination) signal"); + if (isDebuggerActive() && !g_cs->no_breaks) + DOCTEST_BREAK_INTO_DEBUGGER(); + std::exit(EXIT_FAILURE); + } + }); + + // The following settings are taken from google test, and more + // specifically from UnitTest::Run() inside of gtest.cc + + // the user does not want to see pop-up dialogs about crashes + prev_error_mode_1 = SetErrorMode( + SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX + ); + // This forces the abort message to go to stderr in all circumstances. + prev_error_mode_2 = _set_error_mode(_OUT_TO_STDERR); + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program - we want to disable that. + prev_abort_behavior = _set_abort_behavior(0x0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); + // In debug mode, the Windows CRT can crash with an assertion over invalid + // input (e.g. passing an invalid file descriptor). The default handling + // for these assertions is to pop up a dialog and wait for user input. + // Instead ask the CRT to dump such assertions to stderr non-interactively. + prev_report_mode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + prev_report_file = _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); +} + +void FatalConditionHandler::reset() { + if (isSet) { + // Unregister handler and restore the old guarantee + SetUnhandledExceptionFilter(previousTop); + SetThreadStackGuarantee(&guaranteeSize); + std::set_terminate(original_terminate_handler); + std::signal(SIGABRT, prev_sigabrt_handler); + SetErrorMode(prev_error_mode_1); + _set_error_mode(prev_error_mode_2); + _set_abort_behavior(prev_abort_behavior, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); + static_cast(_CrtSetReportMode(_CRT_ASSERT, prev_report_mode)); + static_cast(_CrtSetReportFile(_CRT_ASSERT, prev_report_file)); + isSet = false; + } +} + +FatalConditionHandler::~FatalConditionHandler() { + reset(); +} + +UINT FatalConditionHandler::prev_error_mode_1; +int FatalConditionHandler::prev_error_mode_2; +unsigned int FatalConditionHandler::prev_abort_behavior; +int FatalConditionHandler::prev_report_mode; +_HFILE FatalConditionHandler::prev_report_file; +void(DOCTEST_CDECL *FatalConditionHandler::prev_sigabrt_handler)(int); +std::terminate_handler FatalConditionHandler::original_terminate_handler; +bool FatalConditionHandler::isSet = false; +ULONG FatalConditionHandler::guaranteeSize = 0; +LPTOP_LEVEL_EXCEPTION_FILTER FatalConditionHandler::previousTop = nullptr; + +#else // DOCTEST_PLATFORM_WINDOWS + +SignalDefs signalDefs[] = { + {SIGINT, "SIGINT - Terminal interrupt signal"}, + {SIGILL, "SIGILL - Illegal instruction signal"}, + {SIGFPE, "SIGFPE - Floating point error signal"}, + {SIGSEGV, "SIGSEGV - Segmentation violation signal"}, + {SIGTERM, "SIGTERM - Termination request signal"}, + {SIGABRT, "SIGABRT - Abort (abnormal termination) signal"} +}; +static_assert( + DOCTEST_COUNTOF(signalDefs) == DOCTEST_COUNTOF(FatalConditionHandler::oldSigActions), "arrays should match in size" +); + +void FatalConditionHandler::handleSignal(int sig) { + const char *name = ""; + for (std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + const SignalDefs &def = signalDefs[i]; + if (sig == def.id) { + name = def.name; + break; + } + } + reset(); + reportFatal(name); + static_cast(raise(sig)); +} + +void FatalConditionHandler::allocateAltStackMem() { + altStackMem = new char[altStackSize]; +} + +void FatalConditionHandler::freeAltStackMem() { + delete[] altStackMem; +} + +FatalConditionHandler::FatalConditionHandler() { + isSet = true; + stack_t sigStack; + sigStack.ss_sp = altStackMem; + sigStack.ss_size = altStackSize; + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = {}; + sa.sa_handler = handleSignal; + sa.sa_flags = SA_ONSTACK; + for (std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); + } +} + +FatalConditionHandler::~FatalConditionHandler() { + reset(); +} + +void FatalConditionHandler::reset() { + if (isSet) { + // Set signals back to previous values -- hopefully nobody overwrote them in the meantime + for (std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); + } + // Return the old stack + sigaltstack(&oldSigStack, nullptr); + isSet = false; + } +} + +bool FatalConditionHandler::isSet = false; +struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {}; +stack_t FatalConditionHandler::oldSigStack = {}; +size_t FatalConditionHandler::altStackSize = 4 * SIGSTKSZ; +char *FatalConditionHandler::altStackMem = nullptr; + +#endif // DOCTEST_PLATFORM_WINDOWS +#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +namespace doctest { +namespace detail { + +DOCTEST_THREAD_LOCAL class oss { + std::vector stack; + std::stringstream ss; + +public: + std::ostream *push() { + stack.push_back(ss.tellp()); + return &ss; + } + + String pop() { + if (stack.empty()) + DOCTEST_INTERNAL_ERROR("TLSS was empty when trying to pop!"); + + const std::streampos pos = stack.back(); + stack.pop_back(); + const unsigned sz = static_cast(ss.tellp() - pos); + ss.rdbuf()->pubseekpos(pos, std::ios::in | std::ios::out); + return String(ss, sz); + } +} g_oss; // NOLINT(bugprone-throwing-static-initialization, cert-err58-cpp) + +std::ostream *tlssPush() { + return g_oss.push(); +} + +String tlssPop() { + return g_oss.pop(); +} + +} // namespace detail + +// case insensitive strcmp +static int stricmp(const char *a, const char *b) { + for (;; a++, b++) { + const int d = tolower(*a) - tolower(*b); + if (d != 0 || !*a) + return d; + } +} + +// NOLINTBEGIN(cppcoreguidelines-pro-type-union-access) + +char *String::allocate(size_type sz) { + if (sz <= last) { + buf[sz] = '\0'; + setLast(last - sz); + return buf; + } else { + setOnHeap(); + data.size = sz; + data.capacity = data.size + 1; + data.ptr = new char[data.capacity]; + data.ptr[sz] = '\0'; + return data.ptr; + } +} + +void String::setOnHeap() noexcept { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + *reinterpret_cast(&buf[last]) = 128; +} + +void String::setLast(size_type in) noexcept { + buf[last] = static_cast(in); +} + +void String::setSize(size_type sz) noexcept { + if (isOnStack()) { + buf[sz] = '\0'; + setLast(last - sz); + } else { + data.ptr[sz] = '\0'; + data.size = sz; + } +} + +void String::copy(const String &other) { + if (other.isOnStack()) { + memcpy(buf, other.buf, len); + } else { + memcpy(allocate(other.data.size), other.data.ptr, other.data.size); + } +} // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + +String::String() noexcept { + buf[0] = '\0'; + setLast(); +} + +String::~String() { + if (!isOnStack()) + delete[] data.ptr; +} // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks) + +String::String(const char *in) + : String(in, strlen(in)) {} + +String::String(const char *in, size_type in_size) { + memcpy(allocate(in_size), in, in_size); +} + +String::String(std::istream &in, size_type in_size) { + in.read(allocate(in_size), in_size); +} + +String::String(const String &other) { + copy(other); +} + +String &String::operator=(const String &other) { + if (this != &other) { + if (!isOnStack()) + delete[] data.ptr; + + copy(other); + } + + return *this; +} + +String &String::operator+=(const String &other) { + const size_type my_old_size = size(); + const size_type other_size = other.size(); + const size_type total_size = my_old_size + other_size; + if (isOnStack()) { + if (total_size < len) { + // append to the current stack space + memcpy(buf + my_old_size, other.c_str(), other_size + 1); + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) + setLast(last - total_size); + } else { + // alloc new chunk + char *temp = new char[total_size + 1]; + // copy current data to new location before writing in the union + memcpy(temp, buf, my_old_size); // skip the +1 ('\0') for speed + // update data in union + setOnHeap(); + data.size = total_size; + data.capacity = data.size + 1; + data.ptr = temp; + // transfer the rest of the data + memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); + } + } else { + if (data.capacity > total_size) { + // append to the current heap block + data.size = total_size; + memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); + } else { + // resize + data.capacity *= 2; + if (data.capacity <= total_size) + data.capacity = total_size + 1; + // alloc new chunk + char *temp = new char[data.capacity]; + // copy current data to new location before releasing it + memcpy(temp, data.ptr, my_old_size); // skip the +1 ('\0') for speed + // release old chunk + delete[] data.ptr; + // update the rest of the union members + data.size = total_size; + data.ptr = temp; + // transfer the rest of the data + memcpy(data.ptr + my_old_size, other.c_str(), other_size + 1); + } + } + + return *this; +} + +String::String(String &&other) noexcept { + memcpy(buf, other.buf, len); + other.buf[0] = '\0'; + other.setLast(); +} + +String &String::operator=(String &&other) noexcept { + if (this != &other) { + if (!isOnStack()) + delete[] data.ptr; + memcpy(buf, other.buf, len); + other.buf[0] = '\0'; + other.setLast(); + } + return *this; +} + +char String::operator[](size_type i) const { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + return const_cast(this)->operator[](i); +} + +char &String::operator[](size_type i) { + if (isOnStack()) + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) + return reinterpret_cast(buf)[i]; + return data.ptr[i]; +} + +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmaybe-uninitialized") +String::size_type String::size() const { + if (isOnStack()) + return last - (static_cast(buf[last]) & 31); // using "last" would work only if "len" is 32 + return data.size; +} +DOCTEST_GCC_SUPPRESS_WARNING_POP + +String::size_type String::capacity() const { + if (isOnStack()) + return len; + return data.capacity; +} + +String String::substr(size_type pos, size_type cnt) && { + cnt = std::min(cnt, size() - pos); + char *cptr = c_str(); + memmove(cptr, cptr + pos, cnt); + setSize(cnt); + return std::move(*this); +} + +String String::substr(size_type pos, size_type cnt) const & { + cnt = std::min(cnt, size() - pos); + return String{c_str() + pos, cnt}; +} + +String::size_type String::find(char ch, size_type pos) const { + const char *begin = c_str(); + const char *end = begin + size(); + const char *it = begin + pos; + for (; it < end && *it != ch; it++) {} + if (it < end) { + return static_cast(it - begin); + } else { + return npos; + } +} + +String::size_type String::rfind(char ch, size_type pos) const { + if (size() == 0) { + return npos; + } + + const char *begin = c_str(); + const char *it = begin + std::min(pos, size() - 1); + for (; it >= begin && *it != ch; it--) {} + if (it >= begin) { + return static_cast(it - begin); + } else { + return npos; + } +} + +int String::compare(const char *other, bool no_case) const { + if (no_case) + return doctest::stricmp(c_str(), other); + return std::strcmp(c_str(), other); +} + +int String::compare(const String &other, bool no_case) const { + return compare(other.c_str(), no_case); +} + +String operator+(const String &lhs, const String &rhs) { + return String(lhs) += rhs; +} + +bool operator==(const String &lhs, const String &rhs) { + return lhs.compare(rhs) == 0; +} + +bool operator!=(const String &lhs, const String &rhs) { + return lhs.compare(rhs) != 0; +} + +bool operator<(const String &lhs, const String &rhs) { + return lhs.compare(rhs) < 0; +} + +bool operator>(const String &lhs, const String &rhs) { + return lhs.compare(rhs) > 0; +} + +bool operator<=(const String &lhs, const String &rhs) { + return (lhs != rhs) ? lhs.compare(rhs) < 0 : true; +} + +bool operator>=(const String &lhs, const String &rhs) { + return (lhs != rhs) ? lhs.compare(rhs) > 0 : true; +} + +std::ostream &operator<<(std::ostream &s, const String &in) { + return s << in.c_str(); +} + +namespace detail { + +void filldata::fill(std::ostream *stream, const void *in) { + filldata::fill(stream, in); +} + +void filldata::fill(std::ostream *stream, const volatile void *in) { + if (in) { + *stream << in; + } else { + *stream << "nullptr"; + } +} + +template +String toStreamLit(T t) { + // NOLINTNEXTLINE(misc-const-correctness) + std::ostream *os = tlssPush(); + os->operator<<(t); + return tlssPop(); +} +} // namespace detail + +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +String toString(const char *in) { + return String("\"") + (in ? in : "{null string}") + "\""; +} +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + +#if DOCTEST_MSVC >= DOCTEST_COMPILER(19, 20, 0) +// see this issue on why this is needed: https://github.com/doctest/doctest/issues/183 +String toString(const std::string &in) { + return in.c_str(); +} +#endif // VS 2019 + +String toString(const String &in) { + return in; +} + +String toString(std::nullptr_t) { + return "nullptr"; +} + +String toString(bool in) { + return in ? "true" : "false"; +} + +String toString(float in) { + return detail::toStreamLit(in); +} +String toString(double in) { + return detail::toStreamLit(in); +} +String toString(double long in) { + return detail::toStreamLit(in); +} + +String toString(char in) { + return detail::toStreamLit(static_cast(in)); +} +String toString(char signed in) { + return detail::toStreamLit(static_cast(in)); +} +String toString(char unsigned in) { + return detail::toStreamLit(static_cast(in)); +} +String toString(short in) { + return detail::toStreamLit(in); +} +String toString(short unsigned in) { + return detail::toStreamLit(in); +} +String toString(signed in) { + return detail::toStreamLit(in); +} +String toString(unsigned in) { + return detail::toStreamLit(in); +} +String toString(long in) { + return detail::toStreamLit(in); +} +String toString(long unsigned in) { + return detail::toStreamLit(in); +} +String toString(long long in) { + return detail::toStreamLit(in); +} +String toString(long long unsigned in) { + return detail::toStreamLit(in); +} + +// NOLINTEND(cppcoreguidelines-pro-type-union-access) + +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +namespace doctest { + +bool SubcaseSignature::operator==(const SubcaseSignature &other) const { + return m_line == other.m_line && std::strcmp(m_file, other.m_file) == 0 && m_name == other.m_name; +} + +bool SubcaseSignature::operator<(const SubcaseSignature &other) const { + if (m_line != other.m_line) + return m_line < other.m_line; + if (std::strcmp(m_file, other.m_file) != 0) + return std::strcmp(m_file, other.m_file) < 0; + return m_name.compare(other.m_name) < 0; +} + +#ifndef DOCTEST_CONFIG_DISABLE +namespace detail { + +bool Subcase::checkFilters() { + if (g_cs->traversal.activeSubcaseDepth() < static_cast(g_cs->subcase_filter_levels)) { + if (!matchesAny(m_signature.m_name.c_str(), g_cs->filters[6], true, g_cs->case_sensitive)) + return true; + if (matchesAny(m_signature.m_name.c_str(), g_cs->filters[7], false, g_cs->case_sensitive)) + return true; + } + return false; +} + +Subcase::Subcase(const String &name, const char *file, int line) + : m_signature({name, file, line}) { + if (checkFilters()) + return; + + if (!g_cs->traversal.tryEnterSubcase(m_signature)) + return; + + m_entered = true; + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature); +} + +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4996) // std::uncaught_exception is deprecated in C++17 +DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wdeprecated-declarations") + +Subcase::~Subcase() { + if (m_entered) { + g_cs->traversal.leaveSubcase(); + +#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && \ + (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) + if (std::uncaught_exceptions() > 0 +#else + if (std::uncaught_exception() +#endif + && g_cs->shouldLogCurrentException) { + DOCTEST_ITERATE_THROUGH_REPORTERS( + test_case_exception, + {"exception thrown in subcase - will translate later " + "when the whole test case has been exited (cannot " + "translate while there is an active exception)", + false} + ); + g_cs->shouldLogCurrentException = false; + } + + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_end, DOCTEST_EMPTY); + } +} + +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP +DOCTEST_MSVC_SUPPRESS_WARNING_POP + +Subcase::operator bool() const { + return m_entered; +} + +} // namespace detail +#endif // DOCTEST_CONFIG_DISABLE + +} // namespace doctest + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +std::set &getRegisteredTests() { + static std::set data; + return data; +} + +TestCase::TestCase( + funcType test, const char *file, unsigned line, const TestSuite &test_suite, const String &type, int template_id +) noexcept { + m_file = file; + m_line = line; + m_name = nullptr; // will be later overridden in operator* + m_test_suite = test_suite.m_test_suite; + m_description = test_suite.m_description; + m_skip = test_suite.m_skip; + m_no_breaks = test_suite.m_no_breaks; + m_no_output = test_suite.m_no_output; + m_may_fail = test_suite.m_may_fail; + m_should_fail = test_suite.m_should_fail; + m_expected_failures = test_suite.m_expected_failures; + m_timeout = test_suite.m_timeout; + + m_test = test; + m_type = type; + m_template_id = template_id; +} + +TestCase::TestCase(const TestCase &other) noexcept // NOLINT(bugprone-copy-constructor-init) + : TestCaseData() { + *this = other; +} + +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function +TestCase &TestCase::operator=(const TestCase &other) noexcept { // NOLINT(cert-oop54-cpp) + TestCaseData::operator=(other); + m_test = other.m_test; + m_type = other.m_type; + m_template_id = other.m_template_id; + m_full_name = other.m_full_name; + + if (m_template_id != -1) + m_name = m_full_name.c_str(); + return *this; +} +DOCTEST_MSVC_SUPPRESS_WARNING_POP + +TestCase &TestCase::operator*(const char *in) noexcept { + m_name = in; + // make a new name with an appended type for templated test case + if (m_template_id != -1) { + m_full_name = String(m_name) + "<" + m_type + ">"; + // redirect the name to point to the newly constructed full name + m_name = m_full_name.c_str(); + } + return *this; +} + +bool TestCase::operator<(const TestCase &other) const noexcept { + // this will be used only to differentiate between test cases - not relevant for sorting + if (m_line != other.m_line) + return m_line < other.m_line; + const int name_cmp = strcmp(m_name, other.m_name); + if (name_cmp != 0) + return name_cmp < 0; + const int file_cmp = m_file.compare(other.m_file); + if (file_cmp != 0) + return file_cmp < 0; + return m_template_id < other.m_template_id; +} + +// used by the macros for registering tests +int regTest(const TestCase &tc) noexcept { + getRegisteredTests().insert(tc); + return 0; +} + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +TestSuite &TestSuite::operator*(const char *in) noexcept { + m_test_suite = in; + return *this; +} + +// sets the current test suite +int setTestSuite(const TestSuite &ts) noexcept { + doctest_detail_test_suite_ns::getCurrentTestSuite() = ts; + return 0; +} + +} // namespace detail +} // namespace doctest + +namespace doctest_detail_test_suite_ns { +// holds the current test suite +doctest::detail::TestSuite &getCurrentTestSuite() noexcept { + static doctest::detail::TestSuite data{}; + return data; +} +} // namespace doctest_detail_test_suite_ns + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +#ifdef DOCTEST_CONFIG_GETCURRENTTICKS +ticks_t getCurrentTicks() { + return DOCTEST_CONFIG_GETCURRENTTICKS(); +} +#elif defined(DOCTEST_PLATFORM_WINDOWS) +ticks_t getCurrentTicks() { + static LARGE_INTEGER hz = {{0}}, hzo = {{0}}; + if (!hz.QuadPart) { + QueryPerformanceFrequency(&hz); + QueryPerformanceCounter(&hzo); + } + LARGE_INTEGER t; + QueryPerformanceCounter(&t); + return ((t.QuadPart - hzo.QuadPart) * LONGLONG(1000000)) / hz.QuadPart; +} +#else // DOCTEST_PLATFORM_WINDOWS +ticks_t getCurrentTicks() { + timeval t; + gettimeofday(&t, nullptr); + return static_cast(t.tv_sec) * 1000000 + static_cast(t.tv_usec); +} +#endif // DOCTEST_PLATFORM_WINDOWS + +void Timer::start() { + m_ticks = getCurrentTicks(); +} + +unsigned int Timer::getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); +} + +// unsigned int Timer::getElapsedMilliseconds() const { +// return static_cast(getElapsedMicroseconds() / 1000); +// } + +double Timer::getElapsedSeconds() const { + return static_cast(getCurrentTicks() - m_ticks) / 1000000.0; +} + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + + +#include + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +DOCTEST_NOINLINE DecisionPoint &TraversalState::ensureDecisionPointAtCurrentDepth() { + const size_t depth = m_decisionDepth; + + if (m_discoveredDecisionPath.size() == depth) { + m_discoveredDecisionPath.emplace_back(); + + if (m_decisionPath.size() == depth) + m_decisionPath.push_back(0); + } + + return m_discoveredDecisionPath[depth]; +} + +void TraversalState::resetForTestCase() { + m_decisionPath.clear(); + m_discoveredDecisionPath.clear(); + m_enteredSubcaseDepths.clear(); + m_activeSubcaseDepth = 0; + m_decisionDepth = 0; +} + +void TraversalState::resetForRun() { + m_activeSubcaseDepth = 0; + m_discoveredDecisionPath.clear(); + m_decisionDepth = 0; + m_enteredSubcaseDepths.clear(); +} + +bool TraversalState::advance() { + const size_t maxDepth = std::min(m_decisionPath.size(), m_discoveredDecisionPath.size()); + for (size_t depth = maxDepth; depth > 0; --depth) { + const size_t index = depth - 1; + if (m_decisionPath[index] + 1 < m_discoveredDecisionPath[index].branch_count) { + ++m_decisionPath[index]; + m_decisionPath.resize(index + 1); + return true; + } + } + + return false; +} + +bool TraversalState::tryEnterSubcase(const SubcaseSignature &signature) { + DecisionPoint &point = ensureDecisionPointAtCurrentDepth(); + std::vector &subcases = point.subcases; + size_t siblingIndex = 0; + + for (; siblingIndex < subcases.size(); ++siblingIndex) { + if (subcases[siblingIndex] == signature) + break; + } + + if (siblingIndex == subcases.size()) + subcases.push_back(signature); + + point.branch_count = subcases.size(); + + if (siblingIndex != m_decisionPath[m_decisionDepth]) + return false; + + m_enteredSubcaseDepths.push_back(m_decisionDepth); + m_activeSubcaseDepth++; + m_decisionDepth++; + return true; +} + +void TraversalState::leaveSubcase() { + m_decisionDepth = m_enteredSubcaseDepths.back(); + m_enteredSubcaseDepths.pop_back(); + m_activeSubcaseDepth--; +} + +size_t TraversalState::unwindActiveSubcases() { + const size_t activeSubcaseCount = m_activeSubcaseDepth; + + while (m_activeSubcaseDepth > 0) + leaveSubcase(); + + return activeSubcaseCount; +} + +size_t TraversalState::acquireGeneratorIndex(size_t count) { + DecisionPoint &point = ensureDecisionPointAtCurrentDepth(); + point.branch_count = count; + + const size_t index = m_decisionPath[m_decisionDepth]; + m_decisionDepth++; + return index < count ? index : 0; +} + +size_t acquireGeneratorDecisionIndex(size_t count) { + return g_cs->traversal.acquireGeneratorIndex(count); +} +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace doctest { +namespace detail { + +// ================================================================================================= +// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.cpp +// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. +// ================================================================================================= +/* clang-format off */ /* NOLINTBEGIN */ + +using uchar = unsigned char; + + size_t trailingBytes(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return 2; + } + if ((c & 0xF0) == 0xE0) { + return 3; + } + if ((c & 0xF8) == 0xF0) { + return 4; + } + DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + uint32_t headerValue(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return c & 0x1F; + } + if ((c & 0xF0) == 0xE0) { + return c & 0x0F; + } + if ((c & 0xF8) == 0xF0) { + return c & 0x07; + } + DOCTEST_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + void hexEscapeChar(std::ostream& os, unsigned char c) { + std::ios_base::fmtflags f(os.flags()); + os << "\\x" + << std::uppercase << std::hex << std::setfill('0') << std::setw(2) + << static_cast(c); + os.flags(f); + } + + XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void XmlEncode::encodeTo( std::ostream& os ) const { + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: https://www.w3.org/TR/xml/#syntax) + + for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { + uchar c = m_str[idx]; + switch (c) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: https://www.w3.org/TR/xml/#syntax + if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') + os << ">"; + else + os << c; + break; + + case '\"': + if (m_forWhat == ForAttributes) + os << """; + else + os << c; + break; + + default: + // Check for control characters and invalid utf-8 + + // Escape control characters in standard ascii + // see https://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { + hexEscapeChar(os, c); + break; + } + + // Plain ASCII: Write it to stream + if (c < 0x7F) { + os << c; + break; + } + + // UTF-8 territory + // Check if the encoding is valid and if it is not, hex escape bytes. + // Important: We do not check the exact decoded values for validity, only the encoding format + // First check that this bytes is a valid lead byte: + // This means that it is not encoded as 1111 1XXX + // Or as 10XX XXXX + if (c < 0xC0 || + c >= 0xF8) { + hexEscapeChar(os, c); + break; + } + + auto encBytes = trailingBytes(c); + // Are there enough bytes left to avoid accessing out-of-bounds memory? + if (idx + encBytes - 1 >= m_str.size()) { + hexEscapeChar(os, c); + break; + } + // The header is valid, check data + // The next encBytes bytes must together be a valid utf-8 + // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) + bool valid = true; + uint32_t value = headerValue(c); + for (std::size_t n = 1; n < encBytes; ++n) { + uchar nc = m_str[idx + n]; + valid &= ((nc & 0xC0) == 0x80); + value = (value << 6) | (nc & 0x3F); + } + + if ( + // Wrong bit pattern of following bytes + (!valid) || + // Overlong encodings + (value < 0x80) || + ( value < 0x800 && encBytes > 2) || // removed "0x80 <= value &&" because redundant + (0x800 < value && value < 0x10000 && encBytes > 3) || + // Encoded value out of range + (value >= 0x110000) + ) { + hexEscapeChar(os, c); + break; + } + + // If we got here, this is in fact a valid(ish) utf-8 sequence + for (std::size_t n = 0; n < encBytes; ++n) { + os << m_str[idx + n]; + } + idx += encBytes - 1; + break; + } + } + } + + std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) DOCTEST_NOEXCEPT + : m_writer( other.m_writer ){ + other.m_writer = nullptr; + } + XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) DOCTEST_NOEXCEPT { + if ( m_writer ) { + m_writer->endElement(); + } + m_writer = other.m_writer; + other.m_writer = nullptr; + return *this; + } + + + XmlWriter::ScopedElement::~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { + m_writer->writeText( text, indent ); + return *this; + } + + XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) + { + // writeDeclaration(); // called explicitly by the reporters that use the writer class - see issue #627 + } + + XmlWriter::~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& XmlWriter::startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + m_os << m_indent << '<' << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& XmlWriter::endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + m_os << "/>"; + m_tagIsOpen = false; + } + else { + m_os << m_indent << ""; + } + m_os << std::endl; + m_tags.pop_back(); + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, const char* attribute ) { + if( !name.empty() && attribute && attribute[0] != '\0' ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { + m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + m_os << m_indent; + m_os << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + //XmlWriter& XmlWriter::writeComment( std::string const& text ) { + // ensureTagClosed(); + // m_os << m_indent << ""; + // m_needsNewline = true; + // return *this; + //} + + //void XmlWriter::writeStylesheetRef( std::string const& url ) { + // m_os << "\n"; + //} + + //XmlWriter& XmlWriter::writeBlankLine() { + // ensureTagClosed(); + // m_os << '\n'; + // return *this; + //} + + void XmlWriter::ensureTagClosed() { + if( m_tagIsOpen ) { + m_os << ">" << std::endl; + m_tagIsOpen = false; + } + } + + void XmlWriter::writeDeclaration() { + m_os << "\n"; + } + + void XmlWriter::newlineIfNecessary() { + if( m_needsNewline ) { + m_os << std::endl; + m_needsNewline = false; + } + } + +/* clang-format on */ /* NOLINTEND */ +// ================================================================================================= +// End of copy-pasted code from Catch +// ================================================================================================= + +} // namespace detail +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP + +#endif // defined(DOCTEST_CONFIG_IMPLEMENT) && !defined(DOCTEST_LIBRARY_IMPLEMENTATION) From 9c9c7c4c43fc08417f4dcf4f2ab0720af21834af Mon Sep 17 00:00:00 2001 From: Juuso Piippo Date: Mon, 25 May 2026 23:11:47 +0300 Subject: [PATCH 6/8] Run CI script and update CI msvc version --- .github/workflows/main.yml | 5 ++++- README.md | 7 +++---- run_ci.bat | 2 ++ 3 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 run_ci.bat diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3e4f8c1..d35b927 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,5 +1,6 @@ # To run locally: # act -P windows-latest=-self-hosted +# run_ci.bat # Worked fine name: Run tests @@ -16,7 +17,9 @@ jobs: - uses: actions/checkout@v6 - name: Setup MSVC - uses: ilammy/msvc-dev-cmd@v1 + # TODO: Check version and explore updated versions + # Specifically for using VS 2026 + uses: ilammy/msvc-dev-cmd@v1.13.0 with: arch: x64 diff --git a/README.md b/README.md index 37e299c..5a3744a 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,8 @@ Version used: 8.1 The easiest way to get FFmpeg on Windows: from the git master or release builds section of https://www.gyan.dev/ffmpeg/builds/ Download a full_build of any kind, such as -ffmpeg-2026-04-26-git-4867d251ad-full_build.7z. Make a folder next to compress.exe named "vendor" -and inside that named "ffmpeg". Then copy all the contents of the downloaded zip "bin" folder (10 -items) to "vendor/ffmpeg" +ffmpeg-2026-04-26-git-4867d251ad-full_build.7z. Make a folder inside named "ffmpeg" inside "vendor". +Then copy all the contents of the downloaded zip "bin" folder (10 items) to "vendor/ffmpeg" ### ImGui @@ -41,7 +40,7 @@ build.bat ### Tests -[Doctest](https://github.com/doctest/doctest), version used 2.5.2. Put doctest.h into "vendor" +[Doctest](https://github.com/doctest/doctest), version used 2.5.2. Included in the repo already ## Notes / limits diff --git a/run_ci.bat b/run_ci.bat new file mode 100644 index 0000000..e3d4cd0 --- /dev/null +++ b/run_ci.bat @@ -0,0 +1,2 @@ +@echo off +act -P windows-latest=-self-hosted From 97442df583b5b8ca016ffb41da0e22053a9aea19 Mon Sep 17 00:00:00 2001 From: Juuso Piippo Date: Mon, 25 May 2026 23:39:49 +0300 Subject: [PATCH 7/8] Get toolset info in CI --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d35b927..7c43069 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,6 +23,9 @@ jobs: with: arch: x64 + - name: Get toolset info + run: cl + - name: Build and run only tests shell: cmd run: build.bat test-only From 1c2c2024279394aa9b69ccc6245e4aeae463821e Mon Sep 17 00:00:00 2001 From: Juuso Piippo Date: Tue, 26 May 2026 00:07:04 +0300 Subject: [PATCH 8/8] Use VS2026 in CI --- .github/workflows/main.yml | 5 +++-- run_ci.bat | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7c43069..1dd7c6d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,5 +1,5 @@ # To run locally: -# act -P windows-latest=-self-hosted +# act -P windows-2025-vs2026=-self-hosted # run_ci.bat # Worked fine @@ -11,7 +11,7 @@ on: jobs: build-and-test: - runs-on: windows-latest + runs-on: windows-2025-vs2026 steps: - uses: actions/checkout@v6 @@ -23,6 +23,7 @@ jobs: with: arch: x64 + # 19.44.35227 currently (25-5-2026) - name: Get toolset info run: cl diff --git a/run_ci.bat b/run_ci.bat index e3d4cd0..bd3cd80 100644 --- a/run_ci.bat +++ b/run_ci.bat @@ -1,2 +1,2 @@ @echo off -act -P windows-latest=-self-hosted +act -P windows-2025-vs2026=-self-hosted