From 85196b5d849e57566b2c6c3b23d53231f59b7f67 Mon Sep 17 00:00:00 2001 From: Asher Date: Mon, 23 Jun 2025 06:33:40 +0100 Subject: [PATCH] Added first few tests and mt19937 --- .DS_Store | Bin 0 -> 6148 bytes rng/.DS_Store | Bin 0 -> 6148 bytes rng/rng.xcodeproj/project.pbxproj | 284 + .../contents.xcworkspacedata | 7 + .../UserInterfaceState.xcuserstate | Bin 0 -> 51335 bytes .../xcshareddata/xcschemes/rng.xcscheme | 80 + .../xcschemes/xcschememanagement.plist | 22 + rng/rng/.DS_Store | Bin 0 -> 6148 bytes rng/rng/.vscode/settings.json | 63 + rng/rng/a.out | Bin 0 -> 729208 bytes rng/rng/code_tests/doctest.h | 7134 +++++++++++++++++ rng/rng/code_tests/test.cpp | 201 + rng/rng/codetest.sh | 3 + rng/rng/generators/LCG/lehmer.cpp | 43 + rng/rng/generators/mt19937.cpp | 95 + rng/rng/main.cpp | 52 + rng/rng/math/incomplete_gamma.cpp | 114 + rng/rng/plot_data.py | 20 + rng/rng/randomness_tests/frequency_block.cpp | 51 + .../randomness_tests/frequency_monobit.cpp | 35 + rng/rng/randomness_tests/runs.cpp | 26 + rng/rng/rng.h | 16 + rng/rng/run.sh | 3 + 23 files changed, 8249 insertions(+) create mode 100644 .DS_Store create mode 100644 rng/.DS_Store create mode 100644 rng/rng.xcodeproj/project.pbxproj create mode 100644 rng/rng.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 rng/rng.xcodeproj/project.xcworkspace/xcuserdata/asher.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 rng/rng.xcodeproj/xcshareddata/xcschemes/rng.xcscheme create mode 100644 rng/rng.xcodeproj/xcuserdata/asher.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 rng/rng/.DS_Store create mode 100644 rng/rng/.vscode/settings.json create mode 100755 rng/rng/a.out create mode 100644 rng/rng/code_tests/doctest.h create mode 100644 rng/rng/code_tests/test.cpp create mode 100755 rng/rng/codetest.sh create mode 100644 rng/rng/generators/LCG/lehmer.cpp create mode 100644 rng/rng/generators/mt19937.cpp create mode 100644 rng/rng/main.cpp create mode 100644 rng/rng/math/incomplete_gamma.cpp create mode 100644 rng/rng/plot_data.py create mode 100644 rng/rng/randomness_tests/frequency_block.cpp create mode 100644 rng/rng/randomness_tests/frequency_monobit.cpp create mode 100644 rng/rng/randomness_tests/runs.cpp create mode 100644 rng/rng/rng.h create mode 100755 rng/rng/run.sh diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4680748129fe0a2e1a70f51af9d641382fd133a2 GIT binary patch literal 6148 zcmeHK%SyvQ6rE|SCKMqHg)Rr&7VJZX;wHrU14eYAQWH{YFlI{9nnfvOtv}?K_&we` zGXaZPi`aW%=G^B@=0N7b7~|eD>NDmr#w=)v9F-bDcWtO)k`XzMkD^{aHuPaW5 zXX~|X9UdK@UrnBqmsGxKIytbdWZz%~@1U5~y!u(1$aDstD!a-eBnF59Vt^RfZU)S` zV70fK23kEaKn&C{fct}hhUgkBHL9%xI=nt(yoHDYI=&?kg+bR~sSzR|T$cjsQf{6Y zT$h7im^{~DsZp0Ru4aaD%*@r}g{#@YFH}0?u14yK0b*d2fu=ScJpV7@m#KZ^ZAfRtt0>Hq1q@#j5E>MR&*I=m;M?t?T Q2c(ODB7{0(;1?M90s#a`g8%>k literal 0 HcmV?d00001 diff --git a/rng/.DS_Store b/rng/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..29b1e361bcbd94c02d3bf78b4d6e32e66581d6c9 GIT binary patch literal 6148 zcmeHKPiqrF6n~S%I!meKpwQz$uc0QX3dPGB;}>v64_4A_H>9hZosd692!TDfAID2? zJ^Bp_J@p%iS8u*I^IBTcDnbz{@4=hj%$xU{&HQ%Q$pZk@nkEf^DgbD7!cu_EHAeH~ zOIG5@3ZkMl#=|(XF^-Pn;Zn8){znDq-IZYkIrQV%<@cAR<4L`KqDtk;y_Ne~>s9?B z+PAZ4(w$7lt?uYOjow(B#pnHQ{5I{)I@O0SZ9eIyd2i$hY0|@#op))T*jdX?^JMI} zk)O~(5Ok{R^ZC>5X3aDkTZ@{RZ#U~T^JMGUViD*^8;_sA?tIDyxjpa_Dm-n@))>#> z5Iek^&(SE)Y~IHRWv}@?!X|uyJ+P2K4~7`C@GjxA~OouRkAr zKP!EE@h3*|myF^5p##4(H^W8o2J(3GbldaB|QLwP#J4d;c7g-1^Z#l?r>Co8T{lzTd^ zZ(KU4(4(}XfGBWPfwCV~>HdFpbNzpnBqLEk6u46gs7gC(w{S~*w=Qjt?plMsi%v#) og~tmDcHC8rxpWn;qdUX6p$=lmSa`$;n*0%PGDsr|{8I&f0r!7)zW@LL literal 0 HcmV?d00001 diff --git a/rng/rng.xcodeproj/project.pbxproj b/rng/rng.xcodeproj/project.pbxproj new file mode 100644 index 0000000..1fa8e2b --- /dev/null +++ b/rng/rng.xcodeproj/project.pbxproj @@ -0,0 +1,284 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXCopyFilesBuildPhase section */ + 4DD424762E01CCB60012A242 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 4DD424782E01CCB60012A242 /* rng */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rng; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + 4DD4247A2E01CCB60012A242 /* rng */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = rng; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + 4DD424752E01CCB60012A242 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 4DD4246F2E01CCB60012A242 = { + isa = PBXGroup; + children = ( + 4DD4247A2E01CCB60012A242 /* rng */, + 4DD424792E01CCB60012A242 /* Products */, + ); + sourceTree = ""; + }; + 4DD424792E01CCB60012A242 /* Products */ = { + isa = PBXGroup; + children = ( + 4DD424782E01CCB60012A242 /* rng */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 4DD424772E01CCB60012A242 /* rng */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4DD4247F2E01CCB60012A242 /* Build configuration list for PBXNativeTarget "rng" */; + buildPhases = ( + 4DD424742E01CCB60012A242 /* Sources */, + 4DD424752E01CCB60012A242 /* Frameworks */, + 4DD424762E01CCB60012A242 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + 4DD4247A2E01CCB60012A242 /* rng */, + ); + name = rng; + packageProductDependencies = ( + ); + productName = rng; + productReference = 4DD424782E01CCB60012A242 /* rng */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 4DD424702E01CCB60012A242 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1600; + TargetAttributes = { + 4DD424772E01CCB60012A242 = { + CreatedOnToolsVersion = 16.0; + }; + }; + }; + buildConfigurationList = 4DD424732E01CCB60012A242 /* Build configuration list for PBXProject "rng" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 4DD4246F2E01CCB60012A242; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + productRefGroup = 4DD424792E01CCB60012A242 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 4DD424772E01CCB60012A242 /* rng */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 4DD424742E01CCB60012A242 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 4DD4247D2E01CCB60012A242 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 4DD4247E2E01CCB60012A242 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + }; + name = Release; + }; + 4DD424802E01CCB60012A242 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 4DD424812E01CCB60012A242 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4DD424732E01CCB60012A242 /* Build configuration list for PBXProject "rng" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4DD4247D2E01CCB60012A242 /* Debug */, + 4DD4247E2E01CCB60012A242 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4DD4247F2E01CCB60012A242 /* Build configuration list for PBXNativeTarget "rng" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4DD424802E01CCB60012A242 /* Debug */, + 4DD424812E01CCB60012A242 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 4DD424702E01CCB60012A242 /* Project object */; +} diff --git a/rng/rng.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/rng/rng.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/rng/rng.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/rng/rng.xcodeproj/project.xcworkspace/xcuserdata/asher.xcuserdatad/UserInterfaceState.xcuserstate b/rng/rng.xcodeproj/project.xcworkspace/xcuserdata/asher.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..131ca841ccc66e3c93fd9027591b2e26305d5a8e GIT binary patch literal 51335 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 literal 0 HcmV?d00001 diff --git a/rng/rng.xcodeproj/xcshareddata/xcschemes/rng.xcscheme b/rng/rng.xcodeproj/xcshareddata/xcschemes/rng.xcscheme new file mode 100644 index 0000000..9857c6e --- /dev/null +++ b/rng/rng.xcodeproj/xcshareddata/xcschemes/rng.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rng/rng.xcodeproj/xcuserdata/asher.xcuserdatad/xcschemes/xcschememanagement.plist b/rng/rng.xcodeproj/xcuserdata/asher.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..437624a --- /dev/null +++ b/rng/rng.xcodeproj/xcuserdata/asher.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + rng.xcscheme_^#shared#^_ + + orderHint + 0 + + + SuppressBuildableAutocreation + + 4DD424772E01CCB60012A242 + + primary + + + + + diff --git a/rng/rng/.DS_Store b/rng/rng/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 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

Ym4;gozN7x&<_0B49+7AQ56x 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

ZVSo?YFvJv~zuuY885Kj%ZB3w$oK1DmB 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 Dct+JT literal 0 HcmV?d00001 diff --git a/rng/rng/code_tests/doctest.h b/rng/rng/code_tests/doctest.h new file mode 100644 index 0000000..feb7202 --- /dev/null +++ b/rng/rng/code_tests/doctest.h @@ -0,0 +1,7134 @@ +// ====================================================================== lgtm [cpp/missing-header-guard] +// == DO NOT MODIFY THIS FILE BY HAND - IT IS AUTO GENERATED BY CMAKE! == +// ====================================================================== +// +// doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD +// +// Copyright (c) 2016-2023 Viktor Kirilov +// +// Distributed under the MIT Software License +// See accompanying file LICENSE.txt or copy at +// https://opensource.org/licenses/MIT +// +// The documentation can be found at the library's page: +// https://github.com/doctest/doctest/blob/master/doc/markdown/readme.md +// +// ================================================================================================= +// ================================================================================================= +// ================================================================================================= +// +// The library is heavily influenced by Catch - https://github.com/catchorg/Catch2 +// which uses the Boost Software License - Version 1.0 +// see here - https://github.com/catchorg/Catch2/blob/master/LICENSE.txt +// +// The concept of subcases (sections in Catch) and expression decomposition are from there. +// Some parts of the code are taken directly: +// - stringification - the detection of "ostream& operator<<(ostream&, const T&)" and StringMaker<> +// - 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 ====================================================================================== +// ================================================================================================= + +#define DOCTEST_VERSION_MAJOR 2 +#define DOCTEST_VERSION_MINOR 4 +#define DOCTEST_VERSION_PATCH 12 + +// util we need here +#define DOCTEST_TOSTR_IMPL(x) #x +#define DOCTEST_TOSTR(x) DOCTEST_TOSTR_IMPL(x) + +#define DOCTEST_VERSION_STR \ + DOCTEST_TOSTR(DOCTEST_VERSION_MAJOR) "." \ + DOCTEST_TOSTR(DOCTEST_VERSION_MINOR) "." \ + DOCTEST_TOSTR(DOCTEST_VERSION_PATCH) + +#define DOCTEST_VERSION \ + (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH) + +// ================================================================================================= +// == COMPILER VERSION ============================================================================= +// ================================================================================================= + +// 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 + +// ================================================================================================= +// == COMPILER WARNINGS HELPERS ==================================================================== +// ================================================================================================= + +#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("-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_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 + +DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH + +DOCTEST_CLANG_SUPPRESS_WARNING_PUSH +DOCTEST_CLANG_SUPPRESS_WARNING("-Wnon-virtual-dtor") +DOCTEST_CLANG_SUPPRESS_WARNING("-Wdeprecated") + +DOCTEST_GCC_SUPPRESS_WARNING_PUSH +DOCTEST_GCC_SUPPRESS_WARNING("-Wctor-dtor-privacy") +DOCTEST_GCC_SUPPRESS_WARNING("-Wnon-virtual-dtor") +DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-promo") + +DOCTEST_MSVC_SUPPRESS_WARNING_PUSH +DOCTEST_MSVC_SUPPRESS_WARNING(4623) // default constructor was implicitly defined as deleted + +#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 + +// ================================================================================================= +// == FEATURE DETECTION ============================================================================ +// ================================================================================================= + +// 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 + +// ================================================================================================= +// == FEATURE DETECTION END ======================================================================== +// ================================================================================================= + +#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; + +// 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) +#ifdef __COUNTER__ // not standard and may be missing for some compilers +#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __COUNTER__) +#else // __COUNTER__ +#define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __LINE__) +#endif // __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 + +// not using __APPLE__ because... this is how Catch does it +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +#define DOCTEST_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define DOCTEST_PLATFORM_IPHONE +#elif defined(_WIN32) +#define DOCTEST_PLATFORM_WINDOWS +#elif defined(__wasi__) +#define DOCTEST_PLATFORM_WASI +#else // DOCTEST_PLATFORM +#define DOCTEST_PLATFORM_LINUX +#endif // DOCTEST_PLATFORM + +namespace doctest { namespace detail { + static DOCTEST_CONSTEXPR int consume(const int*, int) noexcept { return 0; } +}} + +#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 + +#ifndef DOCTEST_BREAK_INTO_DEBUGGER +// should probably take a look at https://github.com/scottt/debugbreak +#ifdef 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 +#include +#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() __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n": : : "memory","r0","r3","r4") // NOLINT(hicpp-no-assembler) +#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 + +// 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 ciso646 (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 +#include +#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 +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) + +namespace std { // NOLINT(cert-dcl58-cpp) +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 + +DOCTEST_MSVC_SUPPRESS_WARNING_POP + +#endif // DOCTEST_CONFIG_USE_STD_HEADERS + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#include +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + +namespace doctest { + +using std::size_t; + +DOCTEST_INTERFACE extern bool is_running_in_test; + +#ifndef DOCTEST_CONFIG_STRING_SIZE_TYPE +#define DOCTEST_CONFIG_STRING_SIZE_TYPE unsigned +#endif + +// 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; //!OCLINT avoid private static members + static DOCTEST_CONSTEXPR size_type last = len - 1; //!OCLINT avoid private static members + + 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 { 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(); + + // cppcheck-suppress noExplicitConstructor + String(const char* in); + String(const char* in, size_type in_size); + + String(std::istream& in, size_type 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 + char* c_str() { + if (isOnStack()) { + return reinterpret_cast(buf); + } + return data.ptr; + } + + 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); + +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 Color { + enum Enum + { + 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 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); +DOCTEST_INTERFACE const char* skipPathFromFilename(const char* file); + +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; +}; + +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); +}; + +struct DOCTEST_INTERFACE MessageData +{ + String m_string; + const char* m_file; + int m_line; + assertType::Enum m_severity; +}; + +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; +}; + +struct DOCTEST_INTERFACE IContextScope +{ + DOCTEST_DECLARE_INTERFACE(IContextScope) + virtual void stringify(std::ostream*) const = 0; +}; + +namespace detail { + struct DOCTEST_INTERFACE TestCase; +} // namespace detail + +struct ContextOptions //!OCLINT too many fields +{ + 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 +}; + +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_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 + } + + // + template + T&& declval(); + + template + DOCTEST_CONSTEXPR_FUNC T&& forward(typename types::remove_reference::type& t) DOCTEST_NOEXCEPT { + return static_cast(t); + } + + template + DOCTEST_CONSTEXPR_FUNC T&& forward(typename types::remove_reference::type&& t) DOCTEST_NOEXCEPT { + return static_cast(t); + } + + template + struct deferred_false : types::false_type { }; + +// 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; + }; + + 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> +{}; + +#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 + String ret = __PRETTY_FUNCTION__; // doctest::String toString() [with T = TYPE] + String::size_type begin = ret.find('=') + 2; + return ret.substr(begin, ret.size() - begin - 1); +#endif +} + +template ::value, bool>::type = true> +String toString(const DOCTEST_REF_WRAP(T) value) { + return StringMaker::convert(value); +} + +#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(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 ::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 + } + }; + +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 { + static void fill(std::ostream* stream, const 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) + reinterpret_cast(in) +#else + *reinterpret_cast(&in) +#endif + ); +DOCTEST_CLANG_SUPPRESS_WARNING_POP + } + }; +} + +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); + +#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS +#define DOCTEST_APPROX_PREFIX \ + template friend typename std::enable_if::value, bool>::type + + 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; } +#undef DOCTEST_APPROX_PREFIX +#endif // DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS + + // clang-format on + + double m_epsilon; + double m_scale; + double m_value; +}; + +DOCTEST_INTERFACE String toString(const Approx& in); + +DOCTEST_INTERFACE const ContextOptions* getContextOptions(); + +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); + +#ifndef DOCTEST_CONFIG_DISABLE + +namespace detail { + // clang-format off +#ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + 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> {}; +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + // clang-format on + + 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(); + + 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(); + }; + + 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)); + } + +#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) \ + 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); \ + } + + // 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, |=) + }; + +#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 + + // clang-format off +#ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#define DOCTEST_COMPARISON_RETURN_TYPE bool +#else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING +#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); } +#endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING + // clang-format on + +#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 + + template + // cppcheck-suppress copyCtorAndEqOperator + struct Expression_lhs + { + L lhs; + assertType::Enum m_at; + + 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); +DOCTEST_MSVC_SUPPRESS_WARNING_POP + if(m_at & assertType::is_false) { //!OCLINT bitwise operator in conditional + 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) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>, " > ", DOCTEST_CMP_GT) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<, " < ", DOCTEST_CMP_LT) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(>=, " >= ", DOCTEST_CMP_GE) //!OCLINT bitwise operator in conditional + DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(<=, " <= ", DOCTEST_CMP_LE) //!OCLINT bitwise operator in conditional + // 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 ::value,void >::type* = nullptr> + Expression_lhs operator<<(const L &operand) { + return Expression_lhs(operand, m_at); + } + }; + + 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); + + template + TestSuite& operator*(const T& in) { + in.fill(*this); + return *this; + } + }; + + 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); + + TestCase(const TestCase& other); + TestCase(TestCase&&) = delete; + + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function + TestCase& operator=(const TestCase& other); + DOCTEST_MSVC_SUPPRESS_WARNING_POP + + TestCase& operator=(TestCase&&) = delete; + + TestCase& operator*(const char* in); + + template + TestCase& operator*(const T& in) { + in.fill(*this); + return *this; + } + + bool operator<(const TestCase& other) const; + + ~TestCase() = default; + }; + + // forward declarations of functions used by the macros + DOCTEST_INTERFACE int regTest(const TestCase& tc); + DOCTEST_INTERFACE int setTestSuite(const TestSuite& ts); + DOCTEST_INTERFACE bool isDebuggerActive(); + + template + int instantiationHelper(const T&) { return 0; } + + 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) + + 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) { //!OCLINT bitwise operator in conditional + 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 assertAction { + enum Enum + { + nothing = 0, + dbgbreak = 1, + shouldthrow = 2 + }; + } // namespace assertAction + + 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 { \ + 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) { + 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) //!OCLINT bitwise operator in conditional + 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; + } + + struct DOCTEST_INTERFACE IExceptionTranslator + { + DOCTEST_DECLARE_INTERFACE(IExceptionTranslator) + virtual bool translate(String&) const = 0; + }; + + template + class ExceptionTranslator : public IExceptionTranslator //!OCLINT destructor of virtual class + { + public: + explicit ExceptionTranslator(String (*translateFunction)(T)) + : m_translateFunction(translateFunction) {} + + bool translate(String& res) const override { +#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS + try { + throw; // lgtm [cpp/rethrow-no-exception] + // cppcheck-suppress catchExceptionByValue + } catch(const T& ex) { + res = m_translateFunction(ex); //!OCLINT parameter reassignment + return true; + } catch(...) {} //!OCLINT - empty catch statement +#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); + + // 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) {} + 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(); + } + } + }; + + 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(); + + // 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(); + }; + + template + ContextScope MakeContextScope(const L &lambda) { + return ContextScope(lambda); + } +} // namespace detail + +#define DOCTEST_DEFINE_DECORATOR(name, type, def) \ + struct name \ + { \ + type data; \ + name(type in = def) \ + : data(in) {} \ + void fill(detail::TestCase& state) const { state.DOCTEST_CAT(m_, name) = data; } \ + void fill(detail::TestSuite& state) const { 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); + +template +int registerExceptionTranslator(String (*translateFunction)(T)) { + DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") + static detail::ExceptionTranslator exceptionTranslator(translateFunction); + DOCTEST_CLANG_SUPPRESS_WARNING_POP + detail::registerExceptionTranslatorImpl(&exceptionTranslator); + return 0; +} + +} // 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(); +} // namespace doctest_detail_test_suite_ns + +namespace doctest { +#else // DOCTEST_CONFIG_DISABLE +template +int registerExceptionTranslator(String (*)(T)) { + return 0; +} +#endif // DOCTEST_CONFIG_DISABLE + +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 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); + + template + IReporter* reporterCreator(const ContextOptions& o) { + return new Reporter(o); + } +} // namespace detail + +template +int registerReporter(const char* name, int priority, bool isReporter) { + detail::registerReporterImpl(name, priority, detail::reporterCreator, isReporter); + return 0; +} +} // namespace doctest + +#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 +#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) { \ + 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 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_), /* 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_), /* 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_), /* NOLINT(cert-err58-cpp) */ \ + doctest::registerReporter(name, priority, false)) \ + static_assert(true, "") + +// clang-format off +// for logging - disabling formatting because it's important to have these on 2 separate lines - see PR #557 +#define DOCTEST_INFO(...) \ + DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_), \ + DOCTEST_ANONYMOUS(DOCTEST_CAPTURE_OTHER_), \ + __VA_ARGS__) +// clang-format on + +#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 + +// clang-format off +#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__) +// clang-format on + +#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 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(,,) + +#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; } }() + +#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 + +// clang-format off +// 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__) +// clang-format on + +// 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_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_WHEN(name) DOCTEST_SUBCASE(" When: " name) +#define DOCTEST_AND_WHEN(name) DOCTEST_SUBCASE("And when: " 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 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__) + +#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__) + +#define SCENARIO(name) DOCTEST_SCENARIO(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 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 + +#ifndef DOCTEST_CONFIG_DISABLE + +// this is here to clear the 'current test suite' for the current translation unit - at the top +DOCTEST_TEST_SUITE_END(); + +#endif // DOCTEST_CONFIG_DISABLE + +DOCTEST_CLANG_SUPPRESS_WARNING_POP +DOCTEST_MSVC_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP + +DOCTEST_SUPPRESS_COMMON_WARNINGS_POP + +#endif // DOCTEST_LIBRARY_INCLUDED + +#ifndef DOCTEST_SINGLE_HEADER +#define DOCTEST_SINGLE_HEADER +#endif // DOCTEST_SINGLE_HEADER + +#if defined(DOCTEST_CONFIG_IMPLEMENT) || !defined(DOCTEST_SINGLE_HEADER) + +#ifndef DOCTEST_SINGLE_HEADER +#include "doctest_fwd.h" +#endif // DOCTEST_SINGLE_HEADER + +DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-macros") + +#ifndef DOCTEST_LIBRARY_IMPLEMENTATION +#define DOCTEST_LIBRARY_IMPLEMENTATION + +DOCTEST_CLANG_SUPPRESS_WARNING_POP + +DOCTEST_SUPPRESS_COMMON_WARNINGS_PUSH + +DOCTEST_CLANG_SUPPRESS_WARNING_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("-Wnonportable-system-include-path") + +DOCTEST_GCC_SUPPRESS_WARNING_PUSH +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_MSVC_SUPPRESS_WARNING_PUSH +DOCTEST_MSVC_SUPPRESS_WARNING(4267) // 'var' : conversion from 'x' to 'y', possible loss of data +DOCTEST_MSVC_SUPPRESS_WARNING(4530) // C++ exception handler used, but unwind semantics not enabled +DOCTEST_MSVC_SUPPRESS_WARNING(4577) // 'noexcept' used with no exception handling mode specified +DOCTEST_MSVC_SUPPRESS_WARNING(4774) // format string expected in argument is not a string literal +DOCTEST_MSVC_SUPPRESS_WARNING(4365) // conversion from 'int' to 'unsigned', signed/unsigned mismatch +DOCTEST_MSVC_SUPPRESS_WARNING(5039) // pointer to potentially throwing function passed to extern C +DOCTEST_MSVC_SUPPRESS_WARNING(4800) // forcing value to bool 'true' or 'false' (performance warning) +DOCTEST_MSVC_SUPPRESS_WARNING(5245) // unreferenced function with internal linkage has been removed + +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) 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 +#include +#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 + +#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_CONFIG_OPTIONS_PREFIX +#define DOCTEST_CONFIG_OPTIONS_PREFIX "dt-" +#endif + +#ifndef DOCTEST_CONFIG_OPTIONS_FILE_PREFIX_SEPARATOR +#define DOCTEST_CONFIG_OPTIONS_FILE_PREFIX_SEPARATOR ':' +#endif + +#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 + +#ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS +#define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX +#else +#define DOCTEST_OPTIONS_PREFIX_DISPLAY "" +#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 + +namespace doctest { + +bool is_running_in_test = false; + +namespace { + using namespace detail; + + template + DOCTEST_NORETURN void throw_exception(Ex const& 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) \ + throw_exception(std::logic_error( \ + __FILE__ ":" DOCTEST_TOSTR(__LINE__) ": Internal doctest error: " msg)) +#endif // DOCTEST_INTERNAL_ERROR + + // case insensitive strcmp + int stricmp(const char* a, const char* b) { + for(;; a++, b++) { + const int d = tolower(*a) - tolower(*b); + if(d != 0 || !*a) + return d; + } + } + + struct Endianness + { + enum Arch + { + Big, + Little + }; + + static Arch which() { + int x = 1; + // casting any data pointer to char* is allowed + auto ptr = reinterpret_cast(&x); + if(*ptr) + return Little; + return Big; + } + }; +} // namespace + +namespace detail { + DOCTEST_THREAD_LOCAL class + { + 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!"); + + std::streampos pos = stack.back(); + stack.pop_back(); + unsigned sz = static_cast(ss.tellp() - pos); + ss.rdbuf()->pubseekpos(pos, std::ios::in | std::ios::out); + return String(ss, sz); + } + } g_oss; + + std::ostream* tlssPush() { + return g_oss.push(); + } + + String tlssPop() { + return g_oss.pop(); + } + +#ifndef DOCTEST_CONFIG_DISABLE + +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 +} + +using ticks_t = timer_large_integer::type; + +#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 + + struct Timer + { + void start() { m_ticks = getCurrentTicks(); } + unsigned int getElapsedMicroseconds() const { + return static_cast(getCurrentTicks() - m_ticks); + } + //unsigned int getElapsedMilliseconds() const { + // return static_cast(getElapsedMicroseconds() / 1000); + //} + double getElapsedSeconds() const { return static_cast(getCurrentTicks() - m_ticks) / 1000000.0; } + + private: + ticks_t m_ticks = 0; + }; + +#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 { 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(auto const& c : m_atomics) { + result += c.atomic.load(order); + } + return result; + } + + T operator=(T desired) DOCTEST_NOEXCEPT { // lgtm [cpp/assignment-does-not-return-this] + 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 + + // 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 + + // stuff for subcases + bool reachedLeaf; + std::vector subcaseStack; + std::vector nextSubcaseStack; + std::unordered_set fullyTraversedSubcases; + size_t currentSubcaseDepth; + Atomic shouldLogCurrentException; + + void resetRunData() { + numTestCases = 0; + numTestCasesPassingFilters = 0; + numTestSuitesPassingFilters = 0; + numTestCasesFailed = 0; + numAsserts = 0; + numAssertsFailed = 0; + numAssertsCurrentTest = 0; + numAssertsFailedCurrentTest = 0; + } + + void 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; + } + } + + 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++; + } + }; + + ContextState* g_cs = nullptr; + + // 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 + DOCTEST_THREAD_LOCAL bool g_no_colors; + +#endif // DOCTEST_CONFIG_DISABLE +} // namespace detail + +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 { *reinterpret_cast(&buf[last]) = 128; } +void String::setLast(size_type in) noexcept { buf[last] = char(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); + } +} + +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 { + return const_cast(this)->operator[](i); +} + +char& String::operator[](size_type i) { + if(isOnStack()) + 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 - (size_type(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 { + 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(); } + +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 { + void color_to_stream(std::ostream&, Color::Enum) DOCTEST_BRANCH_ON_DISABLED({}, ;) +} // namespace + +namespace Color { + std::ostream& operator<<(std::ostream& s, Color::Enum code) { + color_to_stream(s, code); + return s; + } +} // namespace Color + +// clang-format off +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) + 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_MSVC_SUPPRESS_WARNING_POP +} +// clang-format on + +const char* failureString(assertType::Enum at) { + if(at & assertType::is_warn) //!OCLINT bitwise operator in conditional + return "WARNING"; + if(at & assertType::is_check) //!OCLINT bitwise operator in conditional + return "ERROR"; + if(at & assertType::is_require) //!OCLINT bitwise operator in conditional + return "FATAL ERROR"; + return ""; +} + +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 + +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; +} + +DOCTEST_DEFINE_INTERFACE(IContextScope) + +namespace detail { + void filldata::fill(std::ostream* stream, const void* in) { + if (in) { *stream << in; } + else { *stream << "nullptr"; } + } + + template + String toStreamLit(T t) { + std::ostream* os = tlssPush(); + os->operator<<(t); + return tlssPop(); + } +} + +#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(String in) { return in; } + +String toString(std::nullptr_t) { return "nullptr"; } + +String toString(bool in) { return in ? "true" : "false"; } + +String toString(float in) { return toStreamLit(in); } +String toString(double in) { return toStreamLit(in); } +String toString(double long in) { return toStreamLit(in); } + +String toString(char in) { return toStreamLit(static_cast(in)); } +String toString(char signed in) { return toStreamLit(static_cast(in)); } +String toString(char unsigned in) { return toStreamLit(static_cast(in)); } +String toString(short in) { return toStreamLit(in); } +String toString(short unsigned in) { return toStreamLit(in); } +String toString(signed in) { return toStreamLit(in); } +String toString(unsigned in) { return toStreamLit(in); } +String toString(long in) { return toStreamLit(in); } +String toString(long unsigned in) { return toStreamLit(in); } +String toString(long long in) { return toStreamLit(in); } +String toString(long long unsigned in) { return toStreamLit(in); } + +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) + " )"; +} +const ContextOptions* getContextOptions() { return DOCTEST_BRANCH_ON_DISABLED(nullptr, g_cs); } + +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 + +#ifdef DOCTEST_CONFIG_DISABLE +namespace doctest { +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; } + +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; } + +} // namespace doctest +#else // DOCTEST_CONFIG_DISABLE + +#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_detail_test_suite_ns { +// holds the current test suite +doctest::detail::TestSuite& getCurrentTestSuite() { + static doctest::detail::TestSuite data{}; + return data; +} +} // namespace doctest_detail_test_suite_ns + +namespace doctest { +namespace { + // 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, reporterCreatorFunc>; + + reporterMap& getReporters() { + static reporterMap data; + return data; + } + reporterMap& getListeners() { + static reporterMap data; + return data; + } +} // namespace +namespace detail { +#define DOCTEST_ITERATE_THROUGH_REPORTERS(function, ...) \ + for(auto& curr_rep : g_cs->reporters_currently_used) \ + curr_rep->function(__VA_ARGS__) + + bool checkIfShouldThrow(assertType::Enum at) { + if(at & assertType::is_require) //!OCLINT bitwise operator in conditional + return true; + + if((at & assertType::is_check) //!OCLINT bitwise operator in conditional + && 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 { + using 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) { + 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; //!OCLINT parameter reassignment + str = cp++; //!OCLINT parameter reassignment + } + } + + while(*wild == '*') { + wild++; + } + return !*wild; + } + + // 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) { + if (filters.empty() && matchEmpty) + return true; + for (auto& curr : filters) + if (wildcmp(name, curr.c_str(), caseSensitive)) + return true; + return false; + } + + DOCTEST_NO_SANITIZE_INTEGER + unsigned long long hash(unsigned long long a, unsigned long long b) { + return (a << 5) + b; + } + + // C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html + DOCTEST_NO_SANITIZE_INTEGER + unsigned long long hash(const char* str) { + unsigned long long hash = 5381; + char c; + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; // hash * 33 + c + return hash; + } + + unsigned long long hash(const SubcaseSignature& sig) { + return hash(hash(hash(sig.m_file), hash(sig.m_name.c_str())), sig.m_line); + } + + unsigned long long hash(const std::vector& sigs, size_t count) { + unsigned long long running = 0; + auto end = sigs.begin() + count; + for (auto it = sigs.begin(); it != end; it++) { + running = hash(running, hash(*it)); + } + return running; + } + + unsigned long long hash(const std::vector& sigs) { + unsigned long long running = 0; + for (const SubcaseSignature& sig : sigs) { + running = hash(running, hash(sig)); + } + return running; + } +} // namespace +namespace detail { + bool Subcase::checkFilters() { + if (g_cs->subcaseStack.size() < size_t(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 (!g_cs->reachedLeaf) { + if (g_cs->nextSubcaseStack.size() <= g_cs->subcaseStack.size() + || g_cs->nextSubcaseStack[g_cs->subcaseStack.size()] == m_signature) { + // Going down. + if (checkFilters()) { return; } + + g_cs->subcaseStack.push_back(m_signature); + g_cs->currentSubcaseDepth++; + m_entered = true; + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature); + } + } else { + if (g_cs->subcaseStack[g_cs->currentSubcaseDepth] == m_signature) { + // This subcase is reentered via control flow. + g_cs->currentSubcaseDepth++; + m_entered = true; + DOCTEST_ITERATE_THROUGH_REPORTERS(subcase_start, m_signature); + } else if (g_cs->nextSubcaseStack.size() <= g_cs->currentSubcaseDepth + && g_cs->fullyTraversedSubcases.find(hash(hash(g_cs->subcaseStack, g_cs->currentSubcaseDepth), hash(m_signature))) + == g_cs->fullyTraversedSubcases.end()) { + if (checkFilters()) { return; } + // This subcase is part of the one to be executed next. + g_cs->nextSubcaseStack.clear(); + g_cs->nextSubcaseStack.insert(g_cs->nextSubcaseStack.end(), + g_cs->subcaseStack.begin(), g_cs->subcaseStack.begin() + g_cs->currentSubcaseDepth); + g_cs->nextSubcaseStack.push_back(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->currentSubcaseDepth--; + + if (!g_cs->reachedLeaf) { + // Leaf. + g_cs->fullyTraversedSubcases.insert(hash(g_cs->subcaseStack)); + g_cs->nextSubcaseStack.clear(); + g_cs->reachedLeaf = true; + } else if (g_cs->nextSubcaseStack.empty()) { + // All children are finished. + g_cs->fullyTraversedSubcases.insert(hash(g_cs->subcaseStack)); + } + +#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; } + + Result::Result(bool passed, const String& decomposition) + : m_passed(passed) + , m_decomp(decomposition) {} + + ExpressionDecomposer::ExpressionDecomposer(assertType::Enum at) + : m_at(at) {} + + TestSuite& TestSuite::operator*(const char* in) { + m_test_suite = in; + return *this; + } + + TestCase::TestCase(funcType test, const char* file, unsigned line, const TestSuite& test_suite, + const String& type, int template_id) { + 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) + : TestCaseData() { + *this = other; + } + + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(26434) // hides a non-virtual function + TestCase& TestCase::operator=(const TestCase& other) { + 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) { + 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 { + // 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; + } + + // all the registered tests + std::set& getRegisteredTests() { + static std::set data; + return data; + } +} // namespace detail +namespace { + using 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, bool(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); + } + + 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 = ""; + // clang-format off + switch(code) { //!OCLINT missing break in switch statement / unnecessary default statement in covered switch statement + 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"; + } + // clang-format on + 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 + + std::vector& getExceptionTranslators() { + static std::vector data; + return data; + } + + String translateActiveException() { +#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 + +namespace detail { + // used by the macros for registering tests + int regTest(const TestCase& tc) { + getRegisteredTests().insert(tc); + return 0; + } + + // sets the current test suite + int setTestSuite(const TestSuite& ts) { + doctest_detail_test_suite_ns::getCurrentTestSuite() = ts; + return 0; + } + +#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() { + 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, 0, 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 + + void registerExceptionTranslatorImpl(const IExceptionTranslator* et) { + if(std::find(getExceptionTranslators().begin(), getExceptionTranslators().end(), et) == + getExceptionTranslators().end()) + getExceptionTranslators().push_back(et); + } + + 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.push_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 +namespace { + using 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 + + void reportFatal(const std::string&); + +#ifdef DOCTEST_PLATFORM_WINDOWS + + struct SignalDefs + { + DWORD id; + const char* name; + }; + // 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"}, + }; + + struct FatalConditionHandler + { + static LONG CALLBACK 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); + } + + static void allocateAltStackMem() {} + static void freeAltStackMem() {} + + 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); + } + + static void 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() { reset(); } + + 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; + }; + + 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 + + struct SignalDefs + { + int id; + const char* name; + }; + 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"}}; + + struct FatalConditionHandler + { + static bool isSet; + static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)]; + static stack_t oldSigStack; + static size_t altStackSize; + static char* altStackMem; + + static void handleSignal(int sig) { + const char* name = ""; + for(std::size_t i = 0; i < DOCTEST_COUNTOF(signalDefs); ++i) { + SignalDefs& def = signalDefs[i]; + if(sig == def.id) { + name = def.name; + break; + } + } + reset(); + reportFatal(name); + raise(sig); + } + + static void allocateAltStackMem() { + altStackMem = new char[altStackSize]; + } + + static void freeAltStackMem() { + delete[] altStackMem; + } + + 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() { reset(); } + static void 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 + +namespace { + using namespace detail; + +#ifdef DOCTEST_PLATFORM_WINDOWS +#define DOCTEST_OUTPUT_DEBUG_STRING(text) ::OutputDebugStringA(text) +#else + // TODO: integration with XCode and other IDEs +#define DOCTEST_OUTPUT_DEBUG_STRING(text) +#endif // Platform + + void addAssert(assertType::Enum at) { + if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional + g_cs->numAssertsCurrentTest_atomic++; + } + + void addFailedAssert(assertType::Enum at) { + if((at & assertType::is_warn) == 0) //!OCLINT bitwise operator in conditional + 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}); + + while (g_cs->subcaseStack.size()) { + g_cs->subcaseStack.pop_back(); + 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 +} // namespace + +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 detail { + 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) { } + + 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) { //!OCLINT bitwise operator in conditional + m_failed = !m_threw; + } else if((m_at & assertType::is_throws_as) && (m_at & assertType::is_throws_with)) { //!OCLINT + m_failed = !m_threw_as || !m_exception_string.check(m_exception); + } else if(m_at & assertType::is_throws_as) { //!OCLINT bitwise operator in conditional + m_failed = !m_threw_as; + } else if(m_at & assertType::is_throws_with) { //!OCLINT bitwise operator in conditional + m_failed = !m_exception_string.check(m_exception); + } else if(m_at & assertType::is_nothrow) { //!OCLINT bitwise operator in conditional + 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(); + } + + 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) { + 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; + } + + MessageBuilder::MessageBuilder(const char* file, int line, assertType::Enum severity) { + m_stream = tlssPush(); + m_file = file; + m_line = line; + m_severity = severity; + } + + MessageBuilder::~MessageBuilder() { + if (!logged) + tlssPop(); + } + + DOCTEST_DEFINE_INTERFACE(IExceptionTranslator) + + 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) //!OCLINT bitwise operator in conditional + throwException(); + } +} // namespace detail +namespace { + using namespace detail; + + // clang-format off + +// ================================================================================================= +// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp +// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. +// ================================================================================================= + + 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; + }; + +// ================================================================================================= +// The following code has been taken verbatim from Catch2/include/internal/catch_xmlwriter.h/cpp +// This is done so cherry-picking bug fixes is trivial - even the style/formatting is untouched. +// ================================================================================================= + +using uchar = unsigned char; + +namespace { + + 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); + } + +} // anonymous namespace + + 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; + } + } + +// ================================================================================================= +// End of copy-pasted code from Catch +// ================================================================================================= + + // clang-format on + + struct XmlReporter : public IReporter + { + 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) + : xml(*co.cout) + , opt(co) {} + + void log_contexts() { + 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 line(unsigned l) const { return opt.no_line_numbers ? 0 : l; } + + void 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); + } + + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData& in) override { + test_run_start(); + if(opt.list_reporters) { + for(auto& curr : getListeners()) + xml.scopedElement("Listener") + .writeAttribute("priority", curr.first.first) + .writeAttribute("name", curr.first.second); + for(auto& curr : 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 test_run_start() override { + xml.writeDeclaration(); + + // remove .exe extension - mainly to have the same output on UNIX and Windows + 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 test_run_end(const TestRunStats& p) override { + 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 test_case_start(const TestCaseData& in) override { + test_case_start_impl(in); + xml.ensureTagClosed(); + } + + void test_case_reenter(const TestCaseData&) override {} + + void test_case_end(const CurrentTestCaseStats& st) override { + 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 test_case_exception(const TestCaseException& e) override { + DOCTEST_LOCK_MUTEX(mutex) + + xml.scopedElement("Exception") + .writeAttribute("crash", e.is_crash) + .writeText(e.error_string.c_str()); + } + + void subcase_start(const SubcaseSignature& in) override { + xml.startElement("SubCase") + .writeAttribute("name", in.m_name) + .writeAttribute("filename", skipPathFromFilename(in.m_file)) + .writeAttribute("line", line(in.m_line)); + xml.ensureTagClosed(); + } + + void subcase_end() override { xml.endElement(); } + + void log_assert(const AssertData& rb) override { + 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 log_message(const MessageData& mb) override { + 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 test_case_skipped(const TestCaseData& in) override { + if(opt.no_skipped_summary == false) { + test_case_start_impl(in); + xml.writeAttribute("skipped", "true"); + xml.endElement(); + } + } + }; + + DOCTEST_REGISTER_REPORTER("xml", 0, XmlReporter); + + void fulltext_log_assert_to_stream(std::ostream& s, const AssertData& rb) { + if((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) == + 0) //!OCLINT bitwise operator in conditional + s << Color::Cyan << assertString(rb.m_at) << "( " << rb.m_expr << " ) " + << Color::None; + + if(rb.m_at & assertType::is_throws) { //!OCLINT bitwise operator in conditional + 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)) { //!OCLINT + 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) { //!OCLINT bitwise operator in conditional + 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) { //!OCLINT bitwise operator in conditional + 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) { //!OCLINT bitwise operator in conditional + 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"; + } + } + + // TODO: + // - log_message() + // - respond to queries + // - honor remaining options + // - more attributes in tags + struct JUnitReporter : public IReporter + { + XmlWriter xml; + DOCTEST_DECLARE_MUTEX(mutex) + Timer timer; + std::vector deepestSubcaseStackNames; + + struct JUnitTestCaseData + { + static std::string 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; + std::time(&rawtime); + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); + + std::tm timeInfo; +#ifdef DOCTEST_PLATFORM_WINDOWS + gmtime_s(&timeInfo, &rawtime); +#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"; + + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); + return std::string(timeStamp); + } + + struct JUnitTestMessage + { + JUnitTestMessage(const std::string& _message, const std::string& _type, const std::string& _details) + : message(_message), type(_type), details(_details) {} + + JUnitTestMessage(const std::string& _message, const std::string& _details) + : message(_message), type(), details(_details) {} + + std::string message, type, details; + }; + + struct JUnitTestCase + { + JUnitTestCase(const std::string& _classname, const std::string& _name) + : classname(_classname), name(_name), time(0), failures() {} + + std::string classname, name; + double time; + std::vector failures, errors; + }; + + void add(const std::string& classname, const std::string& name) { + testcases.emplace_back(classname, name); + } + + void appendSubcaseNamesToLastTestcase(std::vector nameStack) { + for(auto& curr: nameStack) + if(curr.size()) + testcases.back().name += std::string("/") + curr.c_str(); + } + + void addTime(double time) { + if(time < 1e-4) + time = 0; + testcases.back().time = time; + totalSeconds += time; + } + + void addFailure(const std::string& message, const std::string& type, const std::string& details) { + testcases.back().failures.emplace_back(message, type, details); + ++totalFailures; + } + + void addError(const std::string& message, const std::string& details) { + testcases.back().errors.emplace_back(message, details); + ++totalErrors; + } + + 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) + : xml(*co.cout) + , opt(co) {} + + unsigned line(unsigned l) const { return opt.no_line_numbers ? 0 : l; } + + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData&) override { + xml.writeDeclaration(); + } + + void test_run_start() override { + xml.writeDeclaration(); + } + + void test_run_end(const TestRunStats& p) override { + // remove .exe extension - mainly to have the same output on UNIX and Windows + 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 test_case_start(const TestCaseData& in) override { + testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); + timer.start(); + } + + void test_case_reenter(const TestCaseData& in) override { + testCaseData.addTime(timer.getElapsedSeconds()); + testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); + deepestSubcaseStackNames.clear(); + + timer.start(); + testCaseData.add(skipPathFromFilename(in.m_file.c_str()), in.m_name); + } + + void test_case_end(const CurrentTestCaseStats&) override { + testCaseData.addTime(timer.getElapsedSeconds()); + testCaseData.appendSubcaseNamesToLastTestcase(deepestSubcaseStackNames); + deepestSubcaseStackNames.clear(); + } + + void test_case_exception(const TestCaseException& e) override { + DOCTEST_LOCK_MUTEX(mutex) + testCaseData.addError("exception", e.error_string.c_str()); + } + + void subcase_start(const SubcaseSignature& in) override { + deepestSubcaseStackNames.push_back(in.m_name); + } + + void subcase_end() override {} + + void log_assert(const AssertData& rb) override { + 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 log_message(const MessageData& mb) override { + 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 test_case_skipped(const TestCaseData&) override {} + + void log_contexts(std::ostringstream& s) { + 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; + } + } + } + }; + + DOCTEST_REGISTER_REPORTER("junit", 0, JUnitReporter); + + struct Whitespace + { + int nrSpaces; + explicit 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; + } + + 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) + : s(*co.cout) + , opt(co) {} + + ConsoleReporter(const ContextOptions& co, std::ostream& ostr) + : s(ostr) + , opt(co) {} + + // ========================================================================================= + // WHAT FOLLOWS ARE HELPERS USED BY THE OVERRIDES OF THE VIRTUAL METHODS OF THE INTERFACE + // ========================================================================================= + + void separator_to_stream() { + s << Color::Yellow + << "===============================================================================" + "\n"; + } + + const char* getSuccessOrFailString(bool success, assertType::Enum at, + const char* success_str) { + if(success) + return success_str; + return failureString(at); + } + + Color::Enum getSuccessOrFailColor(bool success, assertType::Enum at) { + return success ? Color::BrightGreen : + (at & assertType::is_warn) ? Color::Yellow : Color::Red; + } + + void successOrFailColoredStringToStream(bool success, assertType::Enum at, + const char* success_str = "SUCCESS") { + s << getSuccessOrFailColor(success, at) + << getSuccessOrFailString(success, at, success_str) << ": "; + } + + void log_contexts() { + 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 + virtual void 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 logTestStart() { + if(hasLoggedCurrentTestStart) + return; + + separator_to_stream(); + file_line_to_stream(tc->m_file.c_str(), 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 printVersion() { + if(opt.no_version == false) + s << Color::Cyan << "[doctest] " << Color::None << "doctest version is \"" + << DOCTEST_VERSION_STR << "\"\n"; + } + + void printIntro() { + if(opt.no_intro == false) { + printVersion(); + s << Color::Cyan << "[doctest] " << Color::None + << "run with \"--" DOCTEST_OPTIONS_PREFIX_DISPLAY "help\" for options\n"; + } + } + + void printHelp() { + 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 "spp, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "skip-path-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 printRegisteredReporters() { + printVersion(); + auto printReporters = [this] (const reporterMap& reporters, const char* type) { + if(reporters.size()) { + 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(getListeners(), "listeners"); + printReporters(getReporters(), "reporters"); + } + + // ========================================================================================= + // WHAT FOLLOWS ARE OVERRIDES OF THE VIRTUAL METHODS OF THE REPORTER INTERFACE + // ========================================================================================= + + void report_query(const QueryData& in) override { + 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 test_run_start() override { + if(!opt.minimal) + printIntro(); + } + + void test_run_end(const TestRunStats& p) override { + if(opt.minimal && p.numTestCasesFailed == 0) + return; + + separator_to_stream(); + s << std::dec; + + auto totwidth = int(std::ceil(log10(static_cast(std::max(p.numTestCasesPassingFilters, static_cast(p.numAsserts))) + 1))); + auto passwidth = int(std::ceil(log10(static_cast(std::max(p.numTestCasesPassingFilters - p.numTestCasesFailed, static_cast(p.numAsserts - p.numAssertsFailed))) + 1))); + auto failwidth = int(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 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 test_case_start(const TestCaseData& in) override { + hasLoggedCurrentTestStart = false; + tc = ∈ + subcasesStack.clear(); + currentSubcaseLevel = 0; + } + + void test_case_reenter(const TestCaseData&) override { + subcasesStack.clear(); + } + + void test_case_end(const CurrentTestCaseStats& st) override { + 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; // lgtm [cpp/useless-expression] + } + + void test_case_exception(const TestCaseException& e) override { + DOCTEST_LOCK_MUTEX(mutex) + if(tc->m_no_output) + return; + + logTestStart(); + + file_line_to_stream(tc->m_file.c_str(), 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: ") + << Color::Cyan << e.error_string << "\n"; + + 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 subcase_start(const SubcaseSignature& subc) override { + subcasesStack.push_back(subc); + ++currentSubcaseLevel; + hasLoggedCurrentTestStart = false; + } + + void subcase_end() override { + --currentSubcaseLevel; + hasLoggedCurrentTestStart = false; + } + + void log_assert(const AssertData& rb) override { + 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 log_message(const MessageData& mb) override { + 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 test_case_skipped(const TestCaseData&) override {} + }; + + DOCTEST_REGISTER_REPORTER("console", 0, ConsoleReporter); + +#ifdef DOCTEST_PLATFORM_WINDOWS + struct DebugOutputWindowReporter : public ConsoleReporter + { + DOCTEST_THREAD_LOCAL static std::ostringstream oss; + + DebugOutputWindowReporter(const ContextOptions& co) + : ConsoleReporter(co, oss) {} + +#define DOCTEST_DEBUG_OUTPUT_REPORTER_OVERRIDE(func, type, arg) \ + void func(type arg) override { \ + 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) + }; + + DOCTEST_THREAD_LOCAL std::ostringstream DebugOutputWindowReporter::oss; +#endif // DOCTEST_PLATFORM_WINDOWS + + // 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))) { //!OCLINT prefer early exits and continue + // 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.size() > 0) { + res.push_back(string.c_str()); + } + s.str(""); + }; + + bool seenBackslash = false; + const char* current = filtersString.c_str(); + const char* end = current + strlen(current); + while(current != end) { + 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... + int theInt = std::atoi(parsedValue.c_str()); + if (theInt != 0) { + res = theInt; //!OCLINT parameter reassignment + 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; //!OCLINT parameter reassignment + return true; + } + if (parsedValue.compare(negative[i], true) == 0) { + res = 0; //!OCLINT parameter reassignment + return true; + } + } + } + return false; + } +} // namespace + +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(g_cs == p) + 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 + + // clang-format off + 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); + // clang-format on + + 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() { 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() + : 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; + } 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].push_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[0]; + for(size_t i = testArray.size() - 1; i > 0; --i) { + int idxToSwap = 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; + + 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->fullyTraversedSubcases.clear(); + + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_start, tc); + + p->timer.start(); + + bool run_test = true; + + do { + // reset some of the fields for subcases (except for the set of fully passed ones) + p->reachedLeaf = false; + // May not be empty if previous subcase exited via exception. + p->subcaseStack.clear(); + p->currentSubcaseDepth = 0; + + 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 + FatalConditionHandler fatalConditionHandler; // Handle signals + // 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; + } + + if(!p->nextSubcaseStack.empty() && run_test) + DOCTEST_ITERATE_THROUGH_REPORTERS(test_case_reenter, tc); + if(p->nextSubcaseStack.empty()) + 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 = unsigned(queryResults.size()); + DOCTEST_ITERATE_THROUGH_REPORTERS(report_query, qdata); + } + + return cleanup_and_return(); +} + +DOCTEST_DEFINE_INTERFACE(IReporter) + +int IReporter::get_num_active_contexts() { return detail::g_infoContexts.size(); } +const IContextScope* const* IReporter::get_active_contexts() { + return get_num_active_contexts() ? &detail::g_infoContexts[0] : nullptr; +} + +int IReporter::get_num_stringified_contexts() { return detail::g_cs->stringifiedContexts.size(); } +const String* IReporter::get_stringified_contexts() { + return get_num_stringified_contexts() ? &detail::g_cs->stringifiedContexts[0] : nullptr; +} + +namespace detail { + void registerReporterImpl(const char* name, int priority, reporterCreatorFunc c, bool isReporter) { + 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 + +} // namespace doctest + +#endif // DOCTEST_CONFIG_DISABLE + +#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_CLANG_SUPPRESS_WARNING_POP +DOCTEST_MSVC_SUPPRESS_WARNING_POP +DOCTEST_GCC_SUPPRESS_WARNING_POP + +DOCTEST_SUPPRESS_COMMON_WARNINGS_POP + +#endif // DOCTEST_LIBRARY_IMPLEMENTATION +#endif // DOCTEST_CONFIG_IMPLEMENT + +#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 \ No newline at end of file diff --git a/rng/rng/code_tests/test.cpp b/rng/rng/code_tests/test.cpp new file mode 100644 index 0000000..33fbb47 --- /dev/null +++ b/rng/rng/code_tests/test.cpp @@ -0,0 +1,201 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "./doctest.h" + +#include "../math/incomplete_gamma.cpp" + +TEST_CASE("igam function"){ + +// generate igam tests with this python script + +// import scipy +// for i in range(1,10): +// for ii in range(20): +// print(f"igamtest({i/2}, {ii/2}, {scipy.special.gammainc(i/2,ii/2)});") + + + auto igamtest = [](double a, double x, double req) { + REQUIRE(igam(a,x)== doctest::Approx(req).epsilon(0.00000000000001)); + }; + { + igamtest(0.5, 0.0, 0.0); + igamtest(0.5, 0.5, 0.6826894921370859); + igamtest(0.5, 1.0, 0.8427007929497151); + igamtest(0.5, 1.5, 0.9167354833364495); + igamtest(0.5, 2.0, 0.9544997361036416); + igamtest(0.5, 2.5, 0.9746526813225318); + igamtest(0.5, 3.0, 0.9856941215645704); + igamtest(0.5, 3.5, 0.9918490284064974); + igamtest(0.5, 4.0, 0.9953222650189527); + igamtest(0.5, 4.5, 0.9973002039367398); + igamtest(0.5, 5.0, 0.9984345977419975); + igamtest(0.5, 5.5, 0.9990888811228463); + igamtest(0.5, 6.0, 0.9994679944948608); + igamtest(0.5, 6.5, 0.9996885090232326); + igamtest(0.5, 7.0, 0.9998171893670181); + igamtest(0.5, 7.5, 0.9998924888232705); + igamtest(0.5, 8.0, 0.9999366575163338); + igamtest(0.5, 8.5, 0.9999626201815983); + igamtest(0.5, 9.0, 0.9999779095030014); + igamtest(0.5, 9.5, 0.9999869281546332); + igamtest(1.0, 0.0, 0.0); + igamtest(1.0, 0.5, 0.3934693402873665); + igamtest(1.0, 1.0, 0.6321205588285577); + igamtest(1.0, 1.5, 0.7768698398515702); + igamtest(1.0, 2.0, 0.8646647167633873); + igamtest(1.0, 2.5, 0.9179150013761012); + igamtest(1.0, 3.0, 0.950212931632136); + igamtest(1.0, 3.5, 0.9698026165776815); + igamtest(1.0, 4.0, 0.9816843611112658); + igamtest(1.0, 4.5, 0.9888910034617577); + igamtest(1.0, 5.0, 0.9932620530009145); + igamtest(1.0, 5.5, 0.995913228561536); + igamtest(1.0, 6.0, 0.9975212478233336); + igamtest(1.0, 6.5, 0.9984965608070224); + igamtest(1.0, 7.0, 0.9990881180344455); + igamtest(1.0, 7.5, 0.9994469156298522); + igamtest(1.0, 8.0, 0.9996645373720975); + igamtest(1.0, 8.5, 0.9997965316309894); + igamtest(1.0, 9.0, 0.9998765901959134); + igamtest(1.0, 9.5, 0.9999251481701124); + igamtest(1.5, 0.0, 0.0); + igamtest(1.5, 0.5, 0.19874804309879915); + igamtest(1.5, 1.0, 0.42759329552912023); + igamtest(1.5, 1.5, 0.6083748237289109); + igamtest(1.5, 2.0, 0.7385358700508897); + igamtest(1.5, 2.5, 0.8282028557032668); + igamtest(1.5, 3.0, 0.8883897749052875); + igamtest(1.5, 3.5, 0.9281022275035349); + igamtest(1.5, 4.0, 0.9539882943107686); + igamtest(1.5, 4.5, 0.9707091134651118); + igamtest(1.5, 5.0, 0.9814338645369568); + igamtest(1.5, 5.5, 0.9882741244215786); + igamtest(1.5, 6.0, 0.9926168394946402); + igamtest(1.5, 6.5, 0.9953633945619583); + igamtest(1.5, 7.0, 0.9970948472257326); + igamtest(1.5, 7.5, 0.9981833510334277); + igamtest(1.5, 8.0, 0.9988660157102147); + igamtest(1.5, 8.5, 0.999293257607663); + igamtest(1.5, 9.0, 0.9995601503471612); + igamtest(1.5, 9.5, 0.9997266011125092); + igamtest(2.0, 0.0, 0.0); + igamtest(2.0, 0.5, 0.09020401043104986); + igamtest(2.0, 1.0, 0.2642411176571153); + igamtest(2.0, 1.5, 0.4421745996289252); + igamtest(2.0, 2.0, 0.5939941502901616); + igamtest(2.0, 2.5, 0.7127025048163542); + igamtest(2.0, 3.0, 0.8008517265285442); + igamtest(2.0, 3.5, 0.8641117745995668); + igamtest(2.0, 4.0, 0.9084218055563291); + igamtest(2.0, 4.5, 0.9389005190396673); + igamtest(2.0, 5.0, 0.9595723180054873); + igamtest(2.0, 5.5, 0.9734359856499836); + igamtest(2.0, 6.0, 0.9826487347633355); + igamtest(2.0, 6.5, 0.9887242060526682); + igamtest(2.0, 7.0, 0.9927049442755639); + igamtest(2.0, 7.5, 0.9952987828537434); + igamtest(2.0, 8.0, 0.9969808363488774); + igamtest(2.0, 8.5, 0.9980670504943989); + igamtest(2.0, 9.0, 0.9987659019591332); + igamtest(2.0, 9.5, 0.9992140557861792); + igamtest(2.5, 0.0, 0.0); + igamtest(2.5, 0.5, 0.03743422675270362); + igamtest(2.5, 1.0, 0.15085496391539038); + igamtest(2.5, 1.5, 0.3000141641213724); + igamtest(2.5, 2.0, 0.4505840486472197); + igamtest(2.5, 2.5, 0.5841198130044919); + igamtest(2.5, 3.0, 0.6937810815867218); + igamtest(2.5, 3.5, 0.7793596920632895); + igamtest(2.5, 4.0, 0.8437643724222776); + igamtest(2.5, 4.5, 0.8909358420502275); + igamtest(2.5, 5.0, 0.9247647538534879); + igamtest(2.5, 5.5, 0.9486200165169305); + igamtest(2.5, 6.0, 0.9652122194937581); + igamtest(2.5, 6.5, 0.9766212318964361); + igamtest(2.5, 7.0, 0.9843905838997331); + igamtest(2.5, 7.5, 0.9896376620842136); + igamtest(2.5, 8.0, 0.9931559260775795); + igamtest(2.5, 8.5, 0.9955002030220295); + igamtest(2.5, 9.0, 0.9970535954121197); + igamtest(2.5, 9.5, 0.998077863179057); + igamtest(3.0, 0.0, 0.0); + igamtest(3.0, 0.5, 0.01438767796697068); + igamtest(3.0, 1.0, 0.08030139707139418); + igamtest(3.0, 1.5, 0.19115316946194183); + igamtest(3.0, 2.0, 0.3233235838169364); + igamtest(3.0, 2.5, 0.4561868841166703); + igamtest(3.0, 3.0, 0.5768099188731565); + igamtest(3.0, 3.5, 0.6791528011378659); + igamtest(3.0, 4.0, 0.7618966944464557); + igamtest(3.0, 4.5, 0.8264219290899639); + igamtest(3.0, 5.0, 0.8753479805169189); + igamtest(3.0, 5.5, 0.9116235676432145); + igamtest(3.0, 6.0, 0.938031195583341); + igamtest(3.0, 6.5, 0.9569640531010171); + igamtest(3.0, 7.0, 0.9703638361194782); + igamtest(3.0, 7.5, 0.9797432849433356); + igamtest(3.0, 8.0, 0.986246032255997); + igamtest(3.0, 8.5, 0.9907167556638894); + igamtest(3.0, 9.0, 0.9937678048936227); + igamtest(3.0, 9.5, 0.9958363669624967); + igamtest(3.5, 0.0, 0.0); + igamtest(3.5, 0.5, 0.0051714634834845175); + igamtest(3.5, 1.0, 0.04015963126989843); + igamtest(3.5, 1.5, 0.11499776835684938); + igamtest(3.5, 2.0, 0.22022259152428406); + igamtest(3.5, 2.5, 0.34003677030571744); + igamtest(3.5, 3.0, 0.4602506496044427); + igamtest(3.5, 3.5, 0.5711201424469452); + igamtest(3.5, 4.0, 0.6674060974006921); + igamtest(3.5, 4.5, 0.7473439535034361); + igamtest(3.5, 5.0, 0.81142653248655); + igamtest(3.5, 5.5, 0.8613809791267045); + igamtest(3.5, 6.0, 0.8994411314916412); + igamtest(3.5, 6.5, 0.9278916089660787); + igamtest(3.5, 7.0, 0.9488186465869346); + igamtest(3.5, 7.5, 0.9640005952365712); + igamtest(3.5, 8.0, 0.9748836392531472); + igamtest(3.5, 8.5, 0.9826038174308754); + igamtest(3.5, 9.0, 0.9880299976459704); + igamtest(3.5, 9.5, 0.9918126590319385); + igamtest(4.0, 0.0, 0.0); + igamtest(4.0, 0.5, 0.001751622556290824); + igamtest(4.0, 1.0, 0.01898815687615381); + igamtest(4.0, 1.5, 0.06564245437845008); + igamtest(4.0, 2.0, 0.14287653950145296); + igamtest(4.0, 2.5, 0.2424238668669339); + igamtest(4.0, 3.0, 0.35276811121776874); + igamtest(4.0, 3.5, 0.463367332099215); + igamtest(4.0, 4.0, 0.566529879633291); + igamtest(4.0, 4.5, 0.657704044165409); + igamtest(4.0, 5.0, 0.7349740847026385); + igamtest(4.0, 5.5, 0.7983008012974713); + igamtest(4.0, 6.0, 0.8487961172233521); + igamtest(4.0, 6.5, 0.8881503883724394); + igamtest(4.0, 7.0, 0.9182345837552784); + igamtest(4.0, 7.5, 0.9408545401673161); + igamtest(4.0, 8.0, 0.957619888008316); + igamtest(4.0, 8.5, 0.9698909203107791); + igamtest(4.0, 9.0, 0.9787735136970911); + igamtest(4.0, 9.5, 0.9851403523541687); + igamtest(4.5, 0.0, 0.0); + igamtest(4.5, 0.5, 0.0005624973021675015); + igamtest(4.5, 1.0, 0.008532393371186466); + igamtest(4.5, 1.5, 0.035705027314910875); + igamtest(4.5, 2.0, 0.08858747316832083); + igamtest(4.5, 2.5, 0.16569173980659246); + igamtest(4.5, 3.0, 0.2600817079053462); + igamtest(4.5, 3.5, 0.36288059283060153); + igamtest(4.5, 4.0, 0.4658537830903085); + igamtest(4.5, 4.5, 0.5627258110861331); + igamtest(4.5, 5.0, 0.6495147876766386); + igamtest(4.5, 5.5, 0.724291063227778); + igamtest(4.5, 6.0, 0.7866906949165835); + igamtest(4.5, 6.5, 0.8373937378097005); + igamtest(4.5, 7.0, 0.8776747719613376); + igamtest(4.5, 7.5, 0.9090640234201949); + igamtest(4.5, 8.0, 0.9331184122258733); + igamtest(4.5, 8.5, 0.9512840238523587); + igamtest(4.5, 9.0, 0.9648264605330151); + igamtest(4.5, 9.5, 0.974807104918331); + } +} \ No newline at end of file diff --git a/rng/rng/codetest.sh b/rng/rng/codetest.sh new file mode 100755 index 0000000..2d812ae --- /dev/null +++ b/rng/rng/codetest.sh @@ -0,0 +1,3 @@ +g++ -std=c++11 code_tests/test.cpp -o testcode.o +./testcode.o +rm testcode.o \ No newline at end of file diff --git a/rng/rng/generators/LCG/lehmer.cpp b/rng/rng/generators/LCG/lehmer.cpp new file mode 100644 index 0000000..7dabe7c --- /dev/null +++ b/rng/rng/generators/LCG/lehmer.cpp @@ -0,0 +1,43 @@ +// +// lehmer.cpp +// rng +// +// Created by Asher Falcon on 20/06/2025. +// + +#include "../../rng.h" + +// parameters recommended by Nakazawa & Nakazawa +// https://en.wikipedia.org/wiki/Lehmer_random_number_generator + +uint64_t lehmer_minstd(uint64_t prev){ + uint64_t a = 7759097958782935LL; + uint64_t m = 18055400005099021LL; + + uint64_t result = (a * prev) % m; + + return result; +} + +class lehmer_generator { + uint64_t seed; + public: + uint32_t generate(){ + seed = lehmer_minstd(seed); + return seed; + } + lehmer_generator(uint64_t genSeed){ + seed = genSeed; + } +}; + +// std::vector> lehmer_generate(int seed, int amount){ +// std::vector> bits(amount); + +// for(int i=0; i mt19937_init(uint32_t seed){ + + std::array state; + + state[0] = seed; + + for(int i=1; i<624; i++){ + state[i]= 1812433253*(state[i-1] ^ (state[i-1] >> 30)) + i; + } + + return state; +} + +std::array mt19937_twist(std::array state){ + + std::array newstate; + + for(int i=0; i<624; i++){ + uint32_t x; + + // concating the MSB and LSB from next + if(i+1<624){ + x = (state[i] & 0x80000000) | (state[(i+1)] & 0x7FFFFFFF); + }else{ + x = (state[i] & 0x80000000) | (newstate[(i+1)%624] & 0x7FFFFFFF); + } + + // does the *A part + if(x&1){ + x = (x>>1) ^ 0x9908B0DFUL; + }else{ + x=x>>1; + } + + uint32_t y; + if(i+397<624){ + y = state[i+397] ^ x; + }else{ + y = newstate[(i+397) % 624] ^ x; + } + newstate[i] = y; + } + + return newstate; +} + +std::array mt19937_temper(std::array state){ + std::array tempered; + + for(int i=0; i<624; i++){ + + uint32_t y = state[i]; + y = y ^ (y >> 11); + y = y ^ ((y << 7) & 0x9D2C5680UL); + y = y ^ ((y << 15) & 0xEFC60000UL); + tempered[i] = y ^ (y >> 18); + } + + return tempered; +} + +class mt19937_generator { + public: + uint32_t seed; + uint32_t generate() { + uint32_t generated = random_values[position]; + position++; + if(position>=624){ + nextblock(); + } + return generated; + } + double generate_01(){ + return ((double)generate())/(4294967295); + } + mt19937_generator(uint32_t genSeed){ + seed = genSeed; + state = mt19937_init(seed); + nextblock(); + } + private: + std::array state; + std::array random_values; + int position; + // goes to next block of 624 values + void nextblock() { + state = mt19937_twist(state); + random_values = mt19937_temper(state); + position = 0; + } +}; diff --git a/rng/rng/main.cpp b/rng/rng/main.cpp new file mode 100644 index 0000000..fceac27 --- /dev/null +++ b/rng/rng/main.cpp @@ -0,0 +1,52 @@ +// +// main.cpp +// rng +// +// Created by Asher Falcon on 17/06/2025. +// + +#include "rng.h" +#include "generators/LCG/lehmer.cpp" +#include "generators/mt19937.cpp" +#include "randomness_tests/frequency_monobit.cpp" +#include "randomness_tests/frequency_block.cpp" +#include "randomness_tests/runs.cpp" + +int main(int argc, const char * argv[]) { + + int seed = 8898; + int blocksgenerated = 1000000; + + mt19937_generator mt2 = mt19937_generator(seed); + lehmer_generator lg = lehmer_generator(seed); + + std::vector> mtbits; + std::vector> lgbits; + + for(int i=0; i1.0 && x>a){ + // return 1.0 - igamc(a,x); + // } + + ax = a * std::log(x) - x - std::lgamma(a); + + if (ax < -maxlog){ + // std::cout << "max log error on incomplete gamma function\n"; + return 0.0; + } + + ax = std::exp(ax); + + r = a; + c = 1.0; + ans = 1.0; + do { + r+=1; + c*= x/r; + ans +=c; + }while(c/ans > machep); + + return ans * ax/a; +} + +// regularized left tail of incomplete gamma +// Q(s, x) = \frac{1}{\Gamma(s)} \int_x^\infty t^{s-1} e^{-t} \, dt +double igamc(double a, double x){ + return 1-igam(a,x); + // double maxlog = 7.09782712893383996732E2; + // double machep = 1.11022302462515654042E-16; + // double big = 4.503599627370496e15; + // double biginv = 2.22044604925031308085e-16; + + + // if(x<=0 || a<=0){ + // return 1.0; + // } + + // if( (x < 1.0 ) || ( x < a)){ + // std::cout << "bad\n"; + // return 1.0 - igam(a,x); + // } + + + // double ax = a * std::log(x) - std::lgamma(a); + + // // maxlog? + // if(ax < -maxlog){ + // std::cout << "max log error on incomplete gamma function\n"; + // return 0.0; + // } + + // ax = std::exp(ax); + + // double y = 1.0 - a; + // double z = x + y + 1.0; + // double c = 0.0; + // double pkm2 = 1.0; + // double qkm2 = x; + // double pkm1 = x + 1.0; + // double qkm1 = z * x; + // double ans = pkm1/qkm1; + + // double pk,qk,r,t,yc; + + // t = 1.0; + + // do { + // c+=1.0; + // y+=1.0; + // z+=2.0; + // yc = y*c; + // pk = pkm1 * z - pkm2 * yc; + // qk = qkm1 * z - qkm2 * yc; + // if (qk !=0){ + // r = pk/qk; + // t = std::fabs((ans-r)/r); + // ans = r; + // }else{ + // t = 1.0; + // } + // pkm2 = pkm1; + // pkm1 = pk; + // qkm2 = qkm1; + // qkm1 = qk; + // if(std::fabs(pk) > big){ + // pkm2 *= biginv; + // pkm1 *= biginv; + // qkm2 *= biginv; + // qkm1 *= biginv; + // } + // std::cout << ans << "-\n"; + // } while (t>machep); + + // return ans * ax; +} + diff --git a/rng/rng/plot_data.py b/rng/rng/plot_data.py new file mode 100644 index 0000000..7abfd63 --- /dev/null +++ b/rng/rng/plot_data.py @@ -0,0 +1,20 @@ +import matplotlib.pyplot as plt + +x_coords = [] +y_coords = [] + +with open("data.txt", "r") as file: + for line in file: + x_coords.append(float(line.split(",")[0])) + y_coords.append(float(line.split(",")[1])) + +plt.figure(figsize=(10, 8)) +plt.scatter(x_coords, y_coords, alpha=0.6, s=1) +plt.grid(True, alpha=0.3) + +plt.axis('equal') +plt.xlim(-0.05, 1.05) +plt.ylim(-0.05, 1.05) + +plt.tight_layout() +plt.show() \ No newline at end of file diff --git a/rng/rng/randomness_tests/frequency_block.cpp b/rng/rng/randomness_tests/frequency_block.cpp new file mode 100644 index 0000000..1d85114 --- /dev/null +++ b/rng/rng/randomness_tests/frequency_block.cpp @@ -0,0 +1,51 @@ +// +// frequency_monobit.cpp +// rng +// +// Created by Asher Falcon on 21/06/2025. +// + +#include "../rng.h" +#include "../math/incomplete_gamma.cpp" + +/** + * Returns the p value from the block frequency test + */ +double test_frequency_block(std::vector> data, u_long block_size){ + + // std::cout << "BLOCK SIZE: "<< block_size<<"\n"; + + long long bitcount = data.size() * 32; + long long chunks = bitcount / block_size; + + double x2stat = 0; + + for(int chunkIndex = 0; chunkIndex < chunks; chunkIndex++){ + // std::cout << "NEWCHUNK: "; + double onecount = 0; + for(int i=0; i .01n and N < 100. + */ +bool pass_frequency_monobit(std::vector> data, int chunkSize){ + double pv = test_frequency_block(data, chunkSize); + return pv >= 0.01; +} \ No newline at end of file diff --git a/rng/rng/randomness_tests/frequency_monobit.cpp b/rng/rng/randomness_tests/frequency_monobit.cpp new file mode 100644 index 0000000..f51470a --- /dev/null +++ b/rng/rng/randomness_tests/frequency_monobit.cpp @@ -0,0 +1,35 @@ +// +// frequency_monobit.cpp +// rng +// +// Created by Asher Falcon on 21/06/2025. +// + +#include "../rng.h" + + +double test_frequency_monobit(std::vector> data){ + + long long s = 0; + + for(auto bitset : data){ + for(int i=0; i<32; i++){ + s += (2*bitset[i])-1; + } + } + + // std::cout << " [sval: "<> data){ + double pv = test_frequency_monobit(data); + return pv >= 0.01; +} \ No newline at end of file diff --git a/rng/rng/randomness_tests/runs.cpp b/rng/rng/randomness_tests/runs.cpp new file mode 100644 index 0000000..a06b501 --- /dev/null +++ b/rng/rng/randomness_tests/runs.cpp @@ -0,0 +1,26 @@ +#include "../rng.h" + +double test_runs(std::vector> data){ + + long long totalSize = data.size() * 32; + + double vnobs = 1; + + double onesproportion = 0; + + for(int i=0; i +#include +#include +#include +#include +#include +#include diff --git a/rng/rng/run.sh b/rng/rng/run.sh new file mode 100755 index 0000000..acd9d33 --- /dev/null +++ b/rng/rng/run.sh @@ -0,0 +1,3 @@ +g++ -std=c++11 main.cpp -o main.o +./main.o +rm main.o \ No newline at end of file