The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

src/external: Update to Catch2 version 2.13.7

authored by

Ryan Pavlik and committed by
Jakob Bornecrantz
1a556740 cbc01823

+515 -262
+515 -262
src/external/Catch2/catch/catch.hpp
··· 1 1 /* 2 - * Catch v2.12.2 3 - * Generated: 2020-05-25 15:09:23.791719 2 + * Catch v2.13.7 3 + * Generated: 2021-07-28 20:29:27.753164 4 4 * ---------------------------------------------------------- 5 5 * This file has been merged from multiple headers. Please don't edit it directly 6 - * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. 6 + * Copyright (c) 2021 Two Blue Cubes Ltd. All rights reserved. 7 7 * 8 8 * Distributed under the Boost Software License, Version 1.0. (See accompanying 9 9 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ··· 14 14 15 15 16 16 #define CATCH_VERSION_MAJOR 2 17 - #define CATCH_VERSION_MINOR 12 18 - #define CATCH_VERSION_PATCH 2 17 + #define CATCH_VERSION_MINOR 13 18 + #define CATCH_VERSION_PATCH 7 19 19 20 20 #ifdef __clang__ 21 21 # pragma clang system_header ··· 66 66 #if !defined(CATCH_CONFIG_IMPL_ONLY) 67 67 // start catch_platform.h 68 68 69 + // See e.g.: 70 + // https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html 69 71 #ifdef __APPLE__ 70 - # include <TargetConditionals.h> 71 - # if TARGET_OS_OSX == 1 72 - # define CATCH_PLATFORM_MAC 73 - # elif TARGET_OS_IPHONE == 1 74 - # define CATCH_PLATFORM_IPHONE 75 - # endif 72 + # include <TargetConditionals.h> 73 + # if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ 74 + (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) 75 + # define CATCH_PLATFORM_MAC 76 + # elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) 77 + # define CATCH_PLATFORM_IPHONE 78 + # endif 76 79 77 80 #elif defined(linux) || defined(__linux) || defined(__linux__) 78 81 # define CATCH_PLATFORM_LINUX ··· 132 135 133 136 #endif 134 137 135 - #if defined(__cpp_lib_uncaught_exceptions) 136 - # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS 137 - #endif 138 - 139 - // We have to avoid both ICC and Clang, because they try to mask themselves 140 - // as gcc, and we want only GCC in this block 141 - #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) 138 + // Only GCC compiler should be used in this block, so other compilers trying to 139 + // mask themselves as GCC should be ignored. 140 + #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) 142 141 # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) 143 142 # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) 144 143 ··· 162 161 // ``` 163 162 // 164 163 // Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. 165 - # if !defined(__ibmxl__) 164 + # if !defined(__ibmxl__) && !defined(__CUDACC__) 166 165 # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ 167 166 # endif 168 167 ··· 244 243 # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) 245 244 # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) 246 245 247 - # if _MSC_VER >= 1900 // Visual Studio 2015 or newer 248 - # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS 249 - # endif 250 - 251 246 // Universal Windows platform does not support SEH 252 247 // Or console colours (or console at all...) 253 248 # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) ··· 330 325 331 326 // Check if byte is available and usable 332 327 # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) 333 - # define CATCH_INTERNAL_CONFIG_CPP17_BYTE 328 + # include <cstddef> 329 + # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) 330 + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE 331 + # endif 334 332 # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) 335 333 336 334 // Check if variant is available and usable ··· 373 371 # define CATCH_CONFIG_CPP17_OPTIONAL 374 372 #endif 375 373 376 - #if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) 377 - # define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS 378 - #endif 379 - 380 374 #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) 381 375 # define CATCH_CONFIG_CPP17_STRING_VIEW 382 376 #endif ··· 775 769 #define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) 776 770 #define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) 777 771 #define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) 778 - #define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) 772 + #define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) 779 773 #define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) 780 774 #define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) 781 775 #define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) ··· 1105 1099 int index = 0; \ 1106 1100 constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ 1107 1101 using expander = int[];\ 1108 - (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \ 1102 + (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ 1109 1103 }\ 1110 1104 };\ 1111 1105 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ ··· 1151 1145 constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ 1152 1146 constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ 1153 1147 constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ 1154 - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */\ 1148 + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */\ 1155 1149 } \ 1156 1150 }; \ 1157 1151 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ ··· 1195 1189 void reg_tests() { \ 1196 1190 int index = 0; \ 1197 1191 using expander = int[]; \ 1198 - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */\ 1192 + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\ 1199 1193 } \ 1200 1194 };\ 1201 1195 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ ··· 1229 1223 int index = 0; \ 1230 1224 constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ 1231 1225 using expander = int[];\ 1232 - (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \ 1226 + (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ 1233 1227 }\ 1234 1228 };\ 1235 1229 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ ··· 1278 1272 constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ 1279 1273 constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ 1280 1274 constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ 1281 - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */ \ 1275 + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */ \ 1282 1276 }\ 1283 1277 };\ 1284 1278 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ ··· 1325 1319 void reg_tests(){\ 1326 1320 int index = 0;\ 1327 1321 using expander = int[];\ 1328 - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */ \ 1322 + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \ 1329 1323 }\ 1330 1324 };\ 1331 1325 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ ··· 1829 1823 #endif 1830 1824 1831 1825 namespace Detail { 1832 - template<typename InputIterator> 1833 - std::string rangeToString(InputIterator first, InputIterator last) { 1826 + template<typename InputIterator, typename Sentinel = InputIterator> 1827 + std::string rangeToString(InputIterator first, Sentinel last) { 1834 1828 ReusableStringStream rss; 1835 1829 rss << "{ "; 1836 1830 if (first != last) { ··· 2468 2462 virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; 2469 2463 virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; 2470 2464 2471 - virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; 2465 + virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; 2472 2466 2473 2467 #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) 2474 2468 virtual void benchmarkPreparing( std::string const& name ) = 0; ··· 4080 4074 return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... ); 4081 4075 } 4082 4076 4083 - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; 4077 + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; 4084 4078 4085 4079 template<typename L> 4086 4080 // Note: The type after -> is weird, because VS2015 cannot parse 4087 4081 // the expression used in the typedef inside, when it is in 4088 4082 // return type. Yeah. 4089 - auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) { 4083 + auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) { 4090 4084 using UnderlyingType = typename decltype(generatorExpression())::type; 4091 4085 4092 - IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); 4086 + IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo ); 4093 4087 if (!tracker.hasGenerator()) { 4094 4088 tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression())); 4095 4089 } ··· 4102 4096 } // namespace Catch 4103 4097 4104 4098 #define GENERATE( ... ) \ 4105 - Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) 4099 + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ 4100 + CATCH_INTERNAL_LINEINFO, \ 4101 + [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) 4106 4102 #define GENERATE_COPY( ... ) \ 4107 - Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) 4103 + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ 4104 + CATCH_INTERNAL_LINEINFO, \ 4105 + [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) 4108 4106 #define GENERATE_REF( ... ) \ 4109 - Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) 4107 + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ 4108 + CATCH_INTERNAL_LINEINFO, \ 4109 + [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) 4110 4110 4111 4111 // end catch_generators.hpp 4112 4112 // start catch_generators_generic.hpp ··· 4516 4516 virtual int abortAfter() const = 0; 4517 4517 virtual bool showInvisibles() const = 0; 4518 4518 virtual ShowDurations::OrNot showDurations() const = 0; 4519 + virtual double minDuration() const = 0; 4519 4520 virtual TestSpec const& testSpec() const = 0; 4520 4521 virtual bool hasTestFilters() const = 0; 4521 4522 virtual std::vector<std::string> const& getTestsOrTags() const = 0; ··· 5288 5289 Verbosity verbosity = Verbosity::Normal; 5289 5290 WarnAbout::What warnings = WarnAbout::Nothing; 5290 5291 ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; 5292 + double minDuration = -1; 5291 5293 RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; 5292 5294 UseColour::YesOrNo useColour = UseColour::Auto; 5293 5295 WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; ··· 5338 5340 bool warnAboutMissingAssertions() const override; 5339 5341 bool warnAboutNoTests() const override; 5340 5342 ShowDurations::OrNot showDurations() const override; 5343 + double minDuration() const override; 5341 5344 RunTests::InWhatOrder runOrder() const override; 5342 5345 unsigned int rngSeed() const override; 5343 5346 UseColour::YesOrNo useColour() const override; ··· 5455 5458 } // namespace Catch 5456 5459 5457 5460 // end catch_outlier_classification.hpp 5461 + 5462 + #include <iterator> 5458 5463 #endif // CATCH_CONFIG_ENABLE_BENCHMARKING 5459 5464 5460 5465 #include <string> ··· 5714 5719 5715 5720 // Returns double formatted as %.3f (format expected on output) 5716 5721 std::string getFormattedDuration( double duration ); 5722 + 5723 + //! Should the reporter show 5724 + bool shouldShowDuration( IConfig const& config, double duration ); 5717 5725 5718 5726 std::string serializeFilters( std::vector<std::string> const& container ); 5719 5727 ··· 6107 6115 ~CompactReporter() override; 6108 6116 6109 6117 static std::string getDescription(); 6110 - 6111 - ReporterPreferences getPreferences() const override; 6112 6118 6113 6119 void noMatchingTestCases(std::string const& spec) override; 6114 6120 ··· 6338 6344 6339 6345 void writeTestCase(TestCaseNode const& testCaseNode); 6340 6346 6341 - void writeSection(std::string const& className, 6342 - std::string const& rootName, 6343 - SectionNode const& sectionNode); 6347 + void writeSection( std::string const& className, 6348 + std::string const& rootName, 6349 + SectionNode const& sectionNode, 6350 + bool testOkToFail ); 6344 6351 6345 6352 void writeAssertions(SectionNode const& sectionNode); 6346 6353 void writeAssertion(AssertionStats const& stats); ··· 6875 6882 } 6876 6883 iters *= 2; 6877 6884 } 6878 - throw optimized_away_error{}; 6885 + Catch::throw_exception(optimized_away_error{}); 6879 6886 } 6880 6887 } // namespace Detail 6881 6888 } // namespace Benchmark ··· 6883 6890 6884 6891 // end catch_run_for_at_least.hpp 6885 6892 #include <algorithm> 6893 + #include <iterator> 6886 6894 6887 6895 namespace Catch { 6888 6896 namespace Benchmark { ··· 7053 7061 double b2 = bias - z1; 7054 7062 double a1 = a(b1); 7055 7063 double a2 = a(b2); 7056 - auto lo = std::max(cumn(a1), 0); 7057 - auto hi = std::min(cumn(a2), n - 1); 7064 + auto lo = (std::max)(cumn(a1), 0); 7065 + auto hi = (std::min)(cumn(a2), n - 1); 7058 7066 7059 7067 return { point, resample[lo], resample[hi], confidence_level }; 7060 7068 } ··· 7123 7131 } 7124 7132 template <typename Clock> 7125 7133 EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) { 7126 - auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration<Clock>(clock_cost_estimation_time_limit)); 7134 + auto time_limit = (std::min)( 7135 + resolution * clock_cost_estimation_tick_limit, 7136 + FloatDuration<Clock>(clock_cost_estimation_time_limit)); 7127 7137 auto time_clock = [](int k) { 7128 7138 return Detail::measure<Clock>([k] { 7129 7139 for (int i = 0; i < k; ++i) { ··· 7463 7473 SourceLineInfo location; 7464 7474 7465 7475 NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); 7476 + friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) { 7477 + return lhs.name == rhs.name 7478 + && lhs.location == rhs.location; 7479 + } 7466 7480 }; 7467 7481 7468 - struct ITracker; 7482 + class ITracker; 7469 7483 7470 7484 using ITrackerPtr = std::shared_ptr<ITracker>; 7471 7485 7472 - struct ITracker { 7473 - virtual ~ITracker(); 7486 + class ITracker { 7487 + NameAndLocation m_nameAndLocation; 7488 + 7489 + public: 7490 + ITracker(NameAndLocation const& nameAndLoc) : 7491 + m_nameAndLocation(nameAndLoc) 7492 + {} 7474 7493 7475 7494 // static queries 7476 - virtual NameAndLocation const& nameAndLocation() const = 0; 7495 + NameAndLocation const& nameAndLocation() const { 7496 + return m_nameAndLocation; 7497 + } 7498 + 7499 + virtual ~ITracker(); 7477 7500 7478 7501 // dynamic queries 7479 7502 virtual bool isComplete() const = 0; // Successfully completed or failed 7480 7503 virtual bool isSuccessfullyCompleted() const = 0; 7481 7504 virtual bool isOpen() const = 0; // Started but not complete 7482 7505 virtual bool hasChildren() const = 0; 7506 + virtual bool hasStarted() const = 0; 7483 7507 7484 7508 virtual ITracker& parent() = 0; 7485 7509 ··· 7534 7558 }; 7535 7559 7536 7560 using Children = std::vector<ITrackerPtr>; 7537 - NameAndLocation m_nameAndLocation; 7538 7561 TrackerContext& m_ctx; 7539 7562 ITracker* m_parent; 7540 7563 Children m_children; ··· 7543 7566 public: 7544 7567 TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); 7545 7568 7546 - NameAndLocation const& nameAndLocation() const override; 7547 7569 bool isComplete() const override; 7548 7570 bool isSuccessfullyCompleted() const override; 7549 7571 bool isOpen() const override; 7550 7572 bool hasChildren() const override; 7573 + bool hasStarted() const override { 7574 + return m_runState != NotStarted; 7575 + } 7551 7576 7552 7577 void addChild( ITrackerPtr const& child ) override; 7553 7578 ··· 7586 7611 7587 7612 void addInitialFilters( std::vector<std::string> const& filters ); 7588 7613 void addNextFilters( std::vector<std::string> const& filters ); 7614 + //! Returns filters active in this tracker 7615 + std::vector<std::string> const& getFilters() const; 7616 + //! Returns whitespace-trimmed name of the tracked section 7617 + std::string const& trimmedName() const; 7589 7618 }; 7590 7619 7591 7620 } // namespace TestCaseTracking ··· 7751 7780 double sb = stddev.point; 7752 7781 double mn = mean.point / n; 7753 7782 double mg_min = mn / 2.; 7754 - double sg = std::min(mg_min / 4., sb / std::sqrt(n)); 7783 + double sg = (std::min)(mg_min / 4., sb / std::sqrt(n)); 7755 7784 double sg2 = sg * sg; 7756 7785 double sb2 = sb * sb; 7757 7786 ··· 7770 7799 return (nc / n) * (sb2 - nc * sg2); 7771 7800 }; 7772 7801 7773 - return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2; 7802 + return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2; 7774 7803 } 7775 7804 7776 7805 bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) { ··· 7910 7939 7911 7940 #ifdef CATCH_PLATFORM_MAC 7912 7941 7913 - #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ 7942 + #if defined(__i386__) || defined(__x86_64__) 7943 + #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ 7944 + #elif defined(__aarch64__) 7945 + #define CATCH_TRAP() __asm__(".inst 0xd4200000") 7946 + #endif 7914 7947 7915 7948 #elif defined(CATCH_PLATFORM_IPHONE) 7916 7949 ··· 7956 7989 7957 7990 // start catch_fatal_condition.h 7958 7991 7959 - // start catch_windows_h_proxy.h 7960 - 7961 - 7962 - #if defined(CATCH_PLATFORM_WINDOWS) 7963 - 7964 - #if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) 7965 - # define CATCH_DEFINED_NOMINMAX 7966 - # define NOMINMAX 7967 - #endif 7968 - #if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) 7969 - # define CATCH_DEFINED_WIN32_LEAN_AND_MEAN 7970 - # define WIN32_LEAN_AND_MEAN 7971 - #endif 7972 - 7973 - #ifdef __AFXDLL 7974 - #include <AfxWin.h> 7975 - #else 7976 - #include <windows.h> 7977 - #endif 7978 - 7979 - #ifdef CATCH_DEFINED_NOMINMAX 7980 - # undef NOMINMAX 7981 - #endif 7982 - #ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN 7983 - # undef WIN32_LEAN_AND_MEAN 7984 - #endif 7985 - 7986 - #endif // defined(CATCH_PLATFORM_WINDOWS) 7987 - 7988 - // end catch_windows_h_proxy.h 7989 - #if defined( CATCH_CONFIG_WINDOWS_SEH ) 7992 + #include <cassert> 7990 7993 7991 7994 namespace Catch { 7992 7995 7993 - struct FatalConditionHandler { 7996 + // Wrapper for platform-specific fatal error (signals/SEH) handlers 7997 + // 7998 + // Tries to be cooperative with other handlers, and not step over 7999 + // other handlers. This means that unknown structured exceptions 8000 + // are passed on, previous signal handlers are called, and so on. 8001 + // 8002 + // Can only be instantiated once, and assumes that once a signal 8003 + // is caught, the binary will end up terminating. Thus, there 8004 + class FatalConditionHandler { 8005 + bool m_started = false; 7994 8006 7995 - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); 8007 + // Install/disengage implementation for specific platform. 8008 + // Should be if-defed to work on current platform, can assume 8009 + // engage-disengage 1:1 pairing. 8010 + void engage_platform(); 8011 + void disengage_platform(); 8012 + public: 8013 + // Should also have platform-specific implementations as needed 7996 8014 FatalConditionHandler(); 7997 - static void reset(); 7998 8015 ~FatalConditionHandler(); 7999 8016 8000 - private: 8001 - static bool isSet; 8002 - static ULONG guaranteeSize; 8003 - static PVOID exceptionHandlerHandle; 8004 - }; 8017 + void engage() { 8018 + assert(!m_started && "Handler cannot be installed twice."); 8019 + m_started = true; 8020 + engage_platform(); 8021 + } 8005 8022 8006 - } // namespace Catch 8007 - 8008 - #elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) 8009 - 8010 - #include <signal.h> 8011 - 8012 - namespace Catch { 8013 - 8014 - struct FatalConditionHandler { 8015 - 8016 - static bool isSet; 8017 - static struct sigaction oldSigActions[]; 8018 - static stack_t oldSigStack; 8019 - static char altStackMem[]; 8020 - 8021 - static void handleSignal( int sig ); 8022 - 8023 - FatalConditionHandler(); 8024 - ~FatalConditionHandler(); 8025 - static void reset(); 8023 + void disengage() { 8024 + assert(m_started && "Handler cannot be uninstalled without being installed first"); 8025 + m_started = false; 8026 + disengage_platform(); 8027 + } 8026 8028 }; 8027 8029 8028 - } // namespace Catch 8029 - 8030 - #else 8031 - 8032 - namespace Catch { 8033 - struct FatalConditionHandler { 8034 - void reset(); 8030 + //! Simple RAII guard for (dis)engaging the FatalConditionHandler 8031 + class FatalConditionHandlerGuard { 8032 + FatalConditionHandler* m_handler; 8033 + public: 8034 + FatalConditionHandlerGuard(FatalConditionHandler* handler): 8035 + m_handler(handler) { 8036 + m_handler->engage(); 8037 + } 8038 + ~FatalConditionHandlerGuard() { 8039 + m_handler->disengage(); 8040 + } 8035 8041 }; 8036 - } 8037 8042 8038 - #endif 8043 + } // end namespace Catch 8039 8044 8040 8045 // end catch_fatal_condition.h 8041 8046 #include <string> ··· 8095 8100 void sectionEnded( SectionEndInfo const& endInfo ) override; 8096 8101 void sectionEndedEarly( SectionEndInfo const& endInfo ) override; 8097 8102 8098 - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; 8103 + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; 8099 8104 8100 8105 #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) 8101 8106 void benchmarkPreparing( std::string const& name ) override; ··· 8161 8166 std::vector<SectionEndInfo> m_unfinishedSections; 8162 8167 std::vector<ITracker*> m_activeSections; 8163 8168 TrackerContext m_trackerContext; 8169 + FatalConditionHandler m_fatalConditionhandler; 8164 8170 bool m_lastAssertionPassed = false; 8165 8171 bool m_shouldReportUnexpected = true; 8166 8172 bool m_includeSuccessfulResults; ··· 9071 9077 } 9072 9078 inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { 9073 9079 std::string srcLC = source; 9074 - std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( std::tolower(c) ); } ); 9080 + std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } ); 9075 9081 if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") 9076 9082 target = true; 9077 9083 else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") ··· 9840 9846 | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) 9841 9847 ["-d"]["--durations"] 9842 9848 ( "show test durations" ) 9849 + | Opt( config.minDuration, "seconds" ) 9850 + ["-D"]["--min-duration"] 9851 + ( "show test durations for tests taking at least the given number of seconds" ) 9843 9852 | Opt( loadTestNamesFromFile, "filename" ) 9844 9853 ["-f"]["--input-file"] 9845 9854 ( "load test names to run from a file" ) ··· 9987 9996 bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } 9988 9997 bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } 9989 9998 ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } 9999 + double Config::minDuration() const { return m_data.minDuration; } 9990 10000 RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } 9991 10001 unsigned int Config::rngSeed() const { return m_data.rngSeed; } 9992 10002 UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } ··· 10029 10039 } 10030 10040 10031 10041 // end catch_errno_guard.h 10042 + // start catch_windows_h_proxy.h 10043 + 10044 + 10045 + #if defined(CATCH_PLATFORM_WINDOWS) 10046 + 10047 + #if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) 10048 + # define CATCH_DEFINED_NOMINMAX 10049 + # define NOMINMAX 10050 + #endif 10051 + #if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) 10052 + # define CATCH_DEFINED_WIN32_LEAN_AND_MEAN 10053 + # define WIN32_LEAN_AND_MEAN 10054 + #endif 10055 + 10056 + #ifdef __AFXDLL 10057 + #include <AfxWin.h> 10058 + #else 10059 + #include <windows.h> 10060 + #endif 10061 + 10062 + #ifdef CATCH_DEFINED_NOMINMAX 10063 + # undef NOMINMAX 10064 + #endif 10065 + #ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN 10066 + # undef WIN32_LEAN_AND_MEAN 10067 + #endif 10068 + 10069 + #endif // defined(CATCH_PLATFORM_WINDOWS) 10070 + 10071 + // end catch_windows_h_proxy.h 10032 10072 #include <sstream> 10033 10073 10034 10074 namespace Catch { ··· 10545 10585 // Extracts the actual name part of an enum instance 10546 10586 // In other words, it returns the Blue part of Bikeshed::Colour::Blue 10547 10587 StringRef extractInstanceName(StringRef enumInstance) { 10548 - // Find last occurence of ":" 10588 + // Find last occurrence of ":" 10549 10589 size_t name_start = enumInstance.size(); 10550 10590 while (name_start > 0 && enumInstance[name_start - 1] != ':') { 10551 10591 --name_start; ··· 10707 10747 // end catch_exception_translator_registry.cpp 10708 10748 // start catch_fatal_condition.cpp 10709 10749 10710 - #if defined(__GNUC__) 10711 - # pragma GCC diagnostic push 10712 - # pragma GCC diagnostic ignored "-Wmissing-field-initializers" 10713 - #endif 10750 + #include <algorithm> 10751 + 10752 + #if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS ) 10753 + 10754 + namespace Catch { 10755 + 10756 + // If neither SEH nor signal handling is required, the handler impls 10757 + // do not have to do anything, and can be empty. 10758 + void FatalConditionHandler::engage_platform() {} 10759 + void FatalConditionHandler::disengage_platform() {} 10760 + FatalConditionHandler::FatalConditionHandler() = default; 10761 + FatalConditionHandler::~FatalConditionHandler() = default; 10762 + 10763 + } // end namespace Catch 10764 + 10765 + #endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS 10766 + 10767 + #if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS ) 10768 + #error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time" 10769 + #endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS 10714 10770 10715 10771 #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) 10716 10772 10717 10773 namespace { 10718 - // Report the error condition 10774 + //! Signals fatal error message to the run context 10719 10775 void reportFatal( char const * const message ) { 10720 10776 Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); 10721 10777 } 10722 - } 10778 + 10779 + //! Minimal size Catch2 needs for its own fatal error handling. 10780 + //! Picked anecdotally, so it might not be sufficient on all 10781 + //! platforms, and for all configurations. 10782 + constexpr std::size_t minStackSizeForErrors = 32 * 1024; 10783 + } // end unnamed namespace 10723 10784 10724 - #endif // signals/SEH handling 10785 + #endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS 10725 10786 10726 10787 #if defined( CATCH_CONFIG_WINDOWS_SEH ) 10727 10788 10728 10789 namespace Catch { 10790 + 10729 10791 struct SignalDefs { DWORD id; const char* name; }; 10730 10792 10731 10793 // There is no 1-1 mapping between signals and windows exceptions. ··· 10738 10800 { static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, 10739 10801 }; 10740 10802 10741 - LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { 10803 + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { 10742 10804 for (auto const& def : signalDefs) { 10743 10805 if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { 10744 10806 reportFatal(def.name); ··· 10749 10811 return EXCEPTION_CONTINUE_SEARCH; 10750 10812 } 10751 10813 10814 + // Since we do not support multiple instantiations, we put these 10815 + // into global variables and rely on cleaning them up in outlined 10816 + // constructors/destructors 10817 + static PVOID exceptionHandlerHandle = nullptr; 10818 + 10819 + // For MSVC, we reserve part of the stack memory for handling 10820 + // memory overflow structured exception. 10752 10821 FatalConditionHandler::FatalConditionHandler() { 10753 - isSet = true; 10754 - // 32k seems enough for Catch to handle stack overflow, 10755 - // but the value was found experimentally, so there is no strong guarantee 10756 - guaranteeSize = 32 * 1024; 10757 - exceptionHandlerHandle = nullptr; 10822 + ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors); 10823 + if (!SetThreadStackGuarantee(&guaranteeSize)) { 10824 + // We do not want to fully error out, because needing 10825 + // the stack reserve should be rare enough anyway. 10826 + Catch::cerr() 10827 + << "Failed to reserve piece of stack." 10828 + << " Stack overflows will not be reported successfully."; 10829 + } 10830 + } 10831 + 10832 + // We do not attempt to unset the stack guarantee, because 10833 + // Windows does not support lowering the stack size guarantee. 10834 + FatalConditionHandler::~FatalConditionHandler() = default; 10835 + 10836 + void FatalConditionHandler::engage_platform() { 10758 10837 // Register as first handler in current chain 10759 10838 exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); 10760 - // Pass in guarantee size to be filled 10761 - SetThreadStackGuarantee(&guaranteeSize); 10839 + if (!exceptionHandlerHandle) { 10840 + CATCH_RUNTIME_ERROR("Could not register vectored exception handler"); 10841 + } 10762 10842 } 10763 10843 10764 - void FatalConditionHandler::reset() { 10765 - if (isSet) { 10766 - RemoveVectoredExceptionHandler(exceptionHandlerHandle); 10767 - SetThreadStackGuarantee(&guaranteeSize); 10768 - exceptionHandlerHandle = nullptr; 10769 - isSet = false; 10844 + void FatalConditionHandler::disengage_platform() { 10845 + if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) { 10846 + CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler"); 10770 10847 } 10848 + exceptionHandlerHandle = nullptr; 10771 10849 } 10772 10850 10773 - FatalConditionHandler::~FatalConditionHandler() { 10774 - reset(); 10775 - } 10851 + } // end namespace Catch 10776 10852 10777 - bool FatalConditionHandler::isSet = false; 10778 - ULONG FatalConditionHandler::guaranteeSize = 0; 10779 - PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; 10853 + #endif // CATCH_CONFIG_WINDOWS_SEH 10780 10854 10781 - } // namespace Catch 10855 + #if defined( CATCH_CONFIG_POSIX_SIGNALS ) 10782 10856 10783 - #elif defined( CATCH_CONFIG_POSIX_SIGNALS ) 10857 + #include <signal.h> 10784 10858 10785 10859 namespace Catch { 10786 10860 ··· 10788 10862 int id; 10789 10863 const char* name; 10790 10864 }; 10791 - 10792 - // 32kb for the alternate stack seems to be sufficient. However, this value 10793 - // is experimentally determined, so that's not guaranteed. 10794 - static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; 10795 10865 10796 10866 static SignalDefs signalDefs[] = { 10797 10867 { SIGINT, "SIGINT - Terminal interrupt signal" }, ··· 10802 10872 { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } 10803 10873 }; 10804 10874 10805 - void FatalConditionHandler::handleSignal( int sig ) { 10875 + // Older GCCs trigger -Wmissing-field-initializers for T foo = {} 10876 + // which is zero initialization, but not explicit. We want to avoid 10877 + // that. 10878 + #if defined(__GNUC__) 10879 + # pragma GCC diagnostic push 10880 + # pragma GCC diagnostic ignored "-Wmissing-field-initializers" 10881 + #endif 10882 + 10883 + static char* altStackMem = nullptr; 10884 + static std::size_t altStackSize = 0; 10885 + static stack_t oldSigStack{}; 10886 + static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{}; 10887 + 10888 + static void restorePreviousSignalHandlers() { 10889 + // We set signal handlers back to the previous ones. Hopefully 10890 + // nobody overwrote them in the meantime, and doesn't expect 10891 + // their signal handlers to live past ours given that they 10892 + // installed them after ours.. 10893 + for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { 10894 + sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); 10895 + } 10896 + // Return the old stack 10897 + sigaltstack(&oldSigStack, nullptr); 10898 + } 10899 + 10900 + static void handleSignal( int sig ) { 10806 10901 char const * name = "<unknown signal>"; 10807 10902 for (auto const& def : signalDefs) { 10808 10903 if (sig == def.id) { ··· 10810 10905 break; 10811 10906 } 10812 10907 } 10813 - reset(); 10814 - reportFatal(name); 10908 + // We need to restore previous signal handlers and let them do 10909 + // their thing, so that the users can have the debugger break 10910 + // when a signal is raised, and so on. 10911 + restorePreviousSignalHandlers(); 10912 + reportFatal( name ); 10815 10913 raise( sig ); 10816 10914 } 10817 10915 10818 10916 FatalConditionHandler::FatalConditionHandler() { 10819 - isSet = true; 10917 + assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists"); 10918 + if (altStackSize == 0) { 10919 + altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors); 10920 + } 10921 + altStackMem = new char[altStackSize](); 10922 + } 10923 + 10924 + FatalConditionHandler::~FatalConditionHandler() { 10925 + delete[] altStackMem; 10926 + // We signal that another instance can be constructed by zeroing 10927 + // out the pointer. 10928 + altStackMem = nullptr; 10929 + } 10930 + 10931 + void FatalConditionHandler::engage_platform() { 10820 10932 stack_t sigStack; 10821 10933 sigStack.ss_sp = altStackMem; 10822 - sigStack.ss_size = sigStackSize; 10934 + sigStack.ss_size = altStackSize; 10823 10935 sigStack.ss_flags = 0; 10824 10936 sigaltstack(&sigStack, &oldSigStack); 10825 10937 struct sigaction sa = { }; ··· 10831 10943 } 10832 10944 } 10833 10945 10834 - FatalConditionHandler::~FatalConditionHandler() { 10835 - reset(); 10836 - } 10946 + #if defined(__GNUC__) 10947 + # pragma GCC diagnostic pop 10948 + #endif 10837 10949 10838 - void FatalConditionHandler::reset() { 10839 - if( isSet ) { 10840 - // Set signals back to previous values -- hopefully nobody overwrote them in the meantime 10841 - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { 10842 - sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); 10843 - } 10844 - // Return the old stack 10845 - sigaltstack(&oldSigStack, nullptr); 10846 - isSet = false; 10847 - } 10950 + void FatalConditionHandler::disengage_platform() { 10951 + restorePreviousSignalHandlers(); 10848 10952 } 10849 10953 10850 - bool FatalConditionHandler::isSet = false; 10851 - struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; 10852 - stack_t FatalConditionHandler::oldSigStack = {}; 10853 - char FatalConditionHandler::altStackMem[sigStackSize] = {}; 10854 - 10855 - } // namespace Catch 10856 - 10857 - #else 10858 - 10859 - namespace Catch { 10860 - void FatalConditionHandler::reset() {} 10861 - } 10862 - 10863 - #endif // signals/SEH handling 10954 + } // end namespace Catch 10864 10955 10865 - #if defined(__GNUC__) 10866 - # pragma GCC diagnostic pop 10867 - #endif 10956 + #endif // CATCH_CONFIG_POSIX_SIGNALS 10868 10957 // end catch_fatal_condition.cpp 10869 10958 // start catch_generators.cpp 10870 10959 ··· 10883 10972 10884 10973 GeneratorUntypedBase::~GeneratorUntypedBase() {} 10885 10974 10886 - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { 10887 - return getResultCapture().acquireGeneratorTracker( lineInfo ); 10975 + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { 10976 + return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo ); 10888 10977 } 10889 10978 10890 10979 } // namespace Generators ··· 11419 11508 return lhs == rhs; 11420 11509 } 11421 11510 11422 - auto ulpDiff = std::abs(lc - rc); 11511 + // static cast as a workaround for IBM XLC 11512 + auto ulpDiff = std::abs(static_cast<FP>(lc - rc)); 11423 11513 return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff; 11424 11514 } 11425 11515 ··· 11593 11683 11594 11684 } // namespace Matchers 11595 11685 } // namespace Catch 11596 - 11597 11686 // end catch_matchers_floating.cpp 11598 11687 // start catch_matchers_generic.cpp 11599 11688 ··· 12009 12098 if (tmpnam_s(m_buffer)) { 12010 12099 CATCH_RUNTIME_ERROR("Could not get a temp filename"); 12011 12100 } 12012 - if (fopen_s(&m_file, m_buffer, "w")) { 12101 + if (fopen_s(&m_file, m_buffer, "w+")) { 12013 12102 char buffer[100]; 12014 12103 if (strerror_s(buffer, errno)) { 12015 12104 CATCH_RUNTIME_ERROR("Could not translate errno to a string"); ··· 12304 12393 namespace Catch { 12305 12394 12306 12395 class StartupExceptionRegistry { 12396 + #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) 12307 12397 public: 12308 12398 void add(std::exception_ptr const& exception) noexcept; 12309 12399 std::vector<std::exception_ptr> const& getExceptions() const noexcept; 12310 12400 private: 12311 12401 std::vector<std::exception_ptr> m_exceptions; 12402 + #endif 12312 12403 }; 12313 12404 12314 12405 } // end namespace Catch ··· 12391 12482 m_tagAliasRegistry.add( alias, tag, lineInfo ); 12392 12483 } 12393 12484 void registerStartupException() noexcept override { 12485 + #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) 12394 12486 m_exceptionRegistry.add(std::current_exception()); 12487 + #else 12488 + CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); 12489 + #endif 12395 12490 } 12396 12491 IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override { 12397 12492 return m_enumValuesRegistry; ··· 12495 12590 std::shared_ptr<GeneratorTracker> tracker; 12496 12591 12497 12592 ITracker& currentTracker = ctx.currentTracker(); 12498 - if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { 12593 + // Under specific circumstances, the generator we want 12594 + // to acquire is also the current tracker. If this is 12595 + // the case, we have to avoid looking through current 12596 + // tracker's children, and instead return the current 12597 + // tracker. 12598 + // A case where this check is important is e.g. 12599 + // for (int i = 0; i < 5; ++i) { 12600 + // int n = GENERATE(1, 2); 12601 + // } 12602 + // 12603 + // without it, the code above creates 5 nested generators. 12604 + if (currentTracker.nameAndLocation() == nameAndLocation) { 12605 + auto thisTracker = currentTracker.parent().findChild(nameAndLocation); 12606 + assert(thisTracker); 12607 + assert(thisTracker->isGeneratorTracker()); 12608 + tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker); 12609 + } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { 12499 12610 assert( childTracker ); 12500 12611 assert( childTracker->isGeneratorTracker() ); 12501 12612 tracker = std::static_pointer_cast<GeneratorTracker>( childTracker ); 12502 - } 12503 - else { 12613 + } else { 12504 12614 tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, &currentTracker ); 12505 12615 currentTracker.addChild( tracker ); 12506 12616 } 12507 12617 12508 - if( !ctx.completedCycle() && !tracker->isComplete() ) { 12618 + if( !tracker->isComplete() ) { 12509 12619 tracker->open(); 12510 12620 } 12511 12621 ··· 12519 12629 } 12520 12630 void close() override { 12521 12631 TrackerBase::close(); 12522 - // Generator interface only finds out if it has another item on atual move 12523 - if (m_runState == CompletedSuccessfully && m_generator->next()) { 12632 + // If a generator has a child (it is followed by a section) 12633 + // and none of its children have started, then we must wait 12634 + // until later to start consuming its values. 12635 + // This catches cases where `GENERATE` is placed between two 12636 + // `SECTION`s. 12637 + // **The check for m_children.empty cannot be removed**. 12638 + // doing so would break `GENERATE` _not_ followed by `SECTION`s. 12639 + const bool should_wait_for_child = [&]() { 12640 + // No children -> nobody to wait for 12641 + if ( m_children.empty() ) { 12642 + return false; 12643 + } 12644 + // If at least one child started executing, don't wait 12645 + if ( std::find_if( 12646 + m_children.begin(), 12647 + m_children.end(), 12648 + []( TestCaseTracking::ITrackerPtr tracker ) { 12649 + return tracker->hasStarted(); 12650 + } ) != m_children.end() ) { 12651 + return false; 12652 + } 12653 + 12654 + // No children have started. We need to check if they _can_ 12655 + // start, and thus we should wait for them, or they cannot 12656 + // start (due to filters), and we shouldn't wait for them 12657 + auto* parent = m_parent; 12658 + // This is safe: there is always at least one section 12659 + // tracker in a test case tracking tree 12660 + while ( !parent->isSectionTracker() ) { 12661 + parent = &( parent->parent() ); 12662 + } 12663 + assert( parent && 12664 + "Missing root (test case) level section" ); 12665 + 12666 + auto const& parentSection = 12667 + static_cast<SectionTracker&>( *parent ); 12668 + auto const& filters = parentSection.getFilters(); 12669 + // No filters -> no restrictions on running sections 12670 + if ( filters.empty() ) { 12671 + return true; 12672 + } 12673 + 12674 + for ( auto const& child : m_children ) { 12675 + if ( child->isSectionTracker() && 12676 + std::find( filters.begin(), 12677 + filters.end(), 12678 + static_cast<SectionTracker&>( *child ) 12679 + .trimmedName() ) != 12680 + filters.end() ) { 12681 + return true; 12682 + } 12683 + } 12684 + return false; 12685 + }(); 12686 + 12687 + // This check is a bit tricky, because m_generator->next() 12688 + // has a side-effect, where it consumes generator's current 12689 + // value, but we do not want to invoke the side-effect if 12690 + // this generator is still waiting for any child to start. 12691 + if ( should_wait_for_child || 12692 + ( m_runState == CompletedSuccessfully && 12693 + m_generator->next() ) ) { 12524 12694 m_children.clear(); 12525 12695 m_runState = Executing; 12526 12696 } ··· 12656 12826 12657 12827 return true; 12658 12828 } 12659 - auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { 12829 + auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { 12660 12830 using namespace Generators; 12661 - GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) ); 12662 - assert( tracker.isOpen() ); 12831 + GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext, 12832 + TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) ); 12663 12833 m_lastAssertionInfo.lineInfo = lineInfo; 12664 12834 return tracker; 12665 12835 } ··· 12702 12872 12703 12873 #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) 12704 12874 void RunContext::benchmarkPreparing(std::string const& name) { 12705 - m_reporter->benchmarkPreparing(name); 12706 - } 12875 + m_reporter->benchmarkPreparing(name); 12876 + } 12707 12877 void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { 12708 12878 m_reporter->benchmarkStarting( info ); 12709 12879 } 12710 12880 void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) { 12711 12881 m_reporter->benchmarkEnded( stats ); 12712 12882 } 12713 - void RunContext::benchmarkFailed(std::string const & error) { 12714 - m_reporter->benchmarkFailed(error); 12715 - } 12883 + void RunContext::benchmarkFailed(std::string const & error) { 12884 + m_reporter->benchmarkFailed(error); 12885 + } 12716 12886 #endif // CATCH_CONFIG_ENABLE_BENCHMARKING 12717 12887 12718 12888 void RunContext::pushScopedMessage(MessageInfo const & message) { ··· 12846 13016 } 12847 13017 12848 13018 void RunContext::invokeActiveTestCase() { 12849 - FatalConditionHandler fatalConditionHandler; // Handle signals 13019 + FatalConditionHandlerGuard _(&m_fatalConditionhandler); 12850 13020 m_activeTestCase->invoke(); 12851 - fatalConditionHandler.reset(); 12852 13021 } 12853 13022 12854 13023 void RunContext::handleUnfinishedSections() { ··· 13433 13602 // end catch_singletons.cpp 13434 13603 // start catch_startup_exception_registry.cpp 13435 13604 13605 + #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) 13436 13606 namespace Catch { 13437 13607 void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { 13438 13608 CATCH_TRY { ··· 13448 13618 } 13449 13619 13450 13620 } // end namespace Catch 13621 + #endif 13451 13622 // end catch_startup_exception_registry.cpp 13452 13623 // start catch_stream.cpp 13453 13624 ··· 13632 13803 13633 13804 namespace { 13634 13805 char toLowerCh(char c) { 13635 - return static_cast<char>( std::tolower( c ) ); 13806 + return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) ); 13636 13807 } 13637 13808 } 13638 13809 ··· 14015 14186 14016 14187 namespace { 14017 14188 struct TestHasher { 14018 - explicit TestHasher(Catch::SimplePcg32& rng) { 14019 - basis = rng(); 14020 - basis <<= 32; 14021 - basis |= rng(); 14022 - } 14189 + using hash_t = uint64_t; 14023 14190 14024 - uint64_t basis; 14191 + explicit TestHasher( hash_t hashSuffix ): 14192 + m_hashSuffix{ hashSuffix } {} 14025 14193 14026 - uint64_t operator()(TestCase const& t) const { 14027 - // Modified FNV-1a hash 14028 - static constexpr uint64_t prime = 1099511628211; 14029 - uint64_t hash = basis; 14030 - for (const char c : t.name) { 14194 + uint32_t operator()( TestCase const& t ) const { 14195 + // FNV-1a hash with multiplication fold. 14196 + const hash_t prime = 1099511628211u; 14197 + hash_t hash = 14695981039346656037u; 14198 + for ( const char c : t.name ) { 14031 14199 hash ^= c; 14032 14200 hash *= prime; 14033 14201 } 14034 - return hash; 14202 + hash ^= m_hashSuffix; 14203 + hash *= prime; 14204 + const uint32_t low{ static_cast<uint32_t>( hash ) }; 14205 + const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) }; 14206 + return low * high; 14035 14207 } 14208 + 14209 + private: 14210 + hash_t m_hashSuffix; 14036 14211 }; 14037 14212 } // end unnamed namespace 14038 14213 ··· 14050 14225 14051 14226 case RunTests::InRandomOrder: { 14052 14227 seedRng( config ); 14053 - TestHasher h( rng() ); 14228 + TestHasher h{ config.rngSeed() }; 14054 14229 14055 - using hashedTest = std::pair<uint64_t, TestCase const*>; 14230 + using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>; 14056 14231 std::vector<hashedTest> indexed_tests; 14057 14232 indexed_tests.reserve( unsortedTestCases.size() ); 14058 14233 ··· 14215 14390 m_currentTracker = tracker; 14216 14391 } 14217 14392 14218 - TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) 14219 - : m_nameAndLocation( nameAndLocation ), 14393 + TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ): 14394 + ITracker(nameAndLocation), 14220 14395 m_ctx( ctx ), 14221 14396 m_parent( parent ) 14222 14397 {} 14223 14398 14224 - NameAndLocation const& TrackerBase::nameAndLocation() const { 14225 - return m_nameAndLocation; 14226 - } 14227 14399 bool TrackerBase::isComplete() const { 14228 14400 return m_runState == CompletedSuccessfully || m_runState == Failed; 14229 14401 } ··· 14339 14511 bool SectionTracker::isComplete() const { 14340 14512 bool complete = true; 14341 14513 14342 - if ((m_filters.empty() || m_filters[0] == "") 14514 + if (m_filters.empty() 14515 + || m_filters[0] == "" 14343 14516 || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { 14344 14517 complete = TrackerBase::isComplete(); 14345 14518 } ··· 14382 14555 void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) { 14383 14556 if( filters.size() > 1 ) 14384 14557 m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); 14558 + } 14559 + 14560 + std::vector<std::string> const& SectionTracker::getFilters() const { 14561 + return m_filters; 14562 + } 14563 + 14564 + std::string const& SectionTracker::trimmedName() const { 14565 + return m_trimmed_name; 14385 14566 } 14386 14567 14387 14568 } // namespace TestCaseTracking ··· 15118 15299 // end catch_totals.cpp 15119 15300 // start catch_uncaught_exceptions.cpp 15120 15301 15302 + // start catch_config_uncaught_exceptions.hpp 15303 + 15304 + // Copyright Catch2 Authors 15305 + // Distributed under the Boost Software License, Version 1.0. 15306 + // (See accompanying file LICENSE_1_0.txt or copy at 15307 + // https://www.boost.org/LICENSE_1_0.txt) 15308 + 15309 + // SPDX-License-Identifier: BSL-1.0 15310 + 15311 + #ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP 15312 + #define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP 15313 + 15314 + #if defined(_MSC_VER) 15315 + # if _MSC_VER >= 1900 // Visual Studio 2015 or newer 15316 + # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS 15317 + # endif 15318 + #endif 15319 + 15320 + #include <exception> 15321 + 15322 + #if defined(__cpp_lib_uncaught_exceptions) \ 15323 + && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) 15324 + 15325 + # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS 15326 + #endif // __cpp_lib_uncaught_exceptions 15327 + 15328 + #if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \ 15329 + && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \ 15330 + && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) 15331 + 15332 + # define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS 15333 + #endif 15334 + 15335 + #endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP 15336 + // end catch_config_uncaught_exceptions.hpp 15121 15337 #include <exception> 15122 15338 15123 15339 namespace Catch { 15124 15340 bool uncaught_exceptions() { 15125 - #if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) 15341 + #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) 15342 + return false; 15343 + #elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) 15126 15344 return std::uncaught_exceptions() > 0; 15127 15345 #else 15128 15346 return std::uncaught_exception(); ··· 15162 15380 } 15163 15381 15164 15382 Version const& libraryVersion() { 15165 - static Version version( 2, 12, 2, "", 0 ); 15383 + static Version version( 2, 13, 7, "", 0 ); 15166 15384 return version; 15167 15385 } 15168 15386 ··· 15564 15782 return std::string(buffer); 15565 15783 } 15566 15784 15785 + bool shouldShowDuration( IConfig const& config, double duration ) { 15786 + if ( config.showDurations() == ShowDurations::Always ) { 15787 + return true; 15788 + } 15789 + if ( config.showDurations() == ShowDurations::Never ) { 15790 + return false; 15791 + } 15792 + const double min = config.minDuration(); 15793 + return min >= 0 && duration >= min; 15794 + } 15795 + 15567 15796 std::string serializeFilters( std::vector<std::string> const& container ) { 15568 15797 ReusableStringStream oss; 15569 15798 bool first = true; ··· 15830 16059 return "Reports test results on a single line, suitable for IDEs"; 15831 16060 } 15832 16061 15833 - ReporterPreferences CompactReporter::getPreferences() const { 15834 - return m_reporterPrefs; 15835 - } 15836 - 15837 16062 void CompactReporter::noMatchingTestCases( std::string const& spec ) { 15838 16063 stream << "No test cases matched '" << spec << '\'' << std::endl; 15839 16064 } ··· 15860 16085 } 15861 16086 15862 16087 void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { 15863 - if (m_config->showDurations() == ShowDurations::Always) { 15864 - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; 16088 + double dur = _sectionStats.durationInSeconds; 16089 + if ( shouldShowDuration( *m_config, dur ) ) { 16090 + stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl; 15865 16091 } 15866 16092 } 15867 16093 ··· 16281 16507 stream << "\nNo assertions in test case"; 16282 16508 stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; 16283 16509 } 16284 - if (m_config->showDurations() == ShowDurations::Always) { 16285 - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; 16510 + double dur = _sectionStats.durationInSeconds; 16511 + if (shouldShowDuration(*m_config, dur)) { 16512 + stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl; 16286 16513 } 16287 16514 if (m_headerPrinted) { 16288 16515 m_headerPrinted = false; ··· 16566 16793 #include <sstream> 16567 16794 #include <ctime> 16568 16795 #include <algorithm> 16796 + #include <iomanip> 16569 16797 16570 16798 namespace Catch { 16571 16799 ··· 16593 16821 #else 16594 16822 std::strftime(timeStamp, timeStampSize, fmt, timeInfo); 16595 16823 #endif 16596 - return std::string(timeStamp); 16824 + return std::string(timeStamp, timeStampSize-1); 16597 16825 } 16598 16826 16599 16827 std::string fileNameTag(const std::vector<std::string> &tags) { ··· 16604 16832 return it->substr(1); 16605 16833 return std::string(); 16606 16834 } 16835 + 16836 + // Formats the duration in seconds to 3 decimal places. 16837 + // This is done because some genius defined Maven Surefire schema 16838 + // in a way that only accepts 3 decimal places, and tools like 16839 + // Jenkins use that schema for validation JUnit reporter output. 16840 + std::string formatDuration( double seconds ) { 16841 + ReusableStringStream rss; 16842 + rss << std::fixed << std::setprecision( 3 ) << seconds; 16843 + return rss.str(); 16844 + } 16845 + 16607 16846 } // anonymous namespace 16608 16847 16609 16848 JunitReporter::JunitReporter( ReporterConfig const& _config ) ··· 16673 16912 if( m_config->showDurations() == ShowDurations::Never ) 16674 16913 xml.writeAttribute( "time", "" ); 16675 16914 else 16676 - xml.writeAttribute( "time", suiteTime ); 16915 + xml.writeAttribute( "time", formatDuration( suiteTime ) ); 16677 16916 xml.writeAttribute( "timestamp", getCurrentTimestamp() ); 16678 16917 16679 16918 // Write properties if there are any ··· 16718 16957 if ( !m_config->name().empty() ) 16719 16958 className = m_config->name() + "." + className; 16720 16959 16721 - writeSection( className, "", rootSection ); 16960 + writeSection( className, "", rootSection, stats.testInfo.okToFail() ); 16722 16961 } 16723 16962 16724 - void JunitReporter::writeSection( std::string const& className, 16725 - std::string const& rootName, 16726 - SectionNode const& sectionNode ) { 16963 + void JunitReporter::writeSection( std::string const& className, 16964 + std::string const& rootName, 16965 + SectionNode const& sectionNode, 16966 + bool testOkToFail) { 16727 16967 std::string name = trim( sectionNode.stats.sectionInfo.name ); 16728 16968 if( !rootName.empty() ) 16729 16969 name = rootName + '/' + name; ··· 16740 16980 xml.writeAttribute( "classname", className ); 16741 16981 xml.writeAttribute( "name", name ); 16742 16982 } 16743 - xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); 16983 + xml.writeAttribute( "time", formatDuration( sectionNode.stats.durationInSeconds ) ); 16744 16984 // This is not ideal, but it should be enough to mimic gtest's 16745 16985 // junit output. 16746 16986 // Ideally the JUnit reporter would also handle `skipTest` 16747 16987 // events and write those out appropriately. 16748 16988 xml.writeAttribute( "status", "run" ); 16749 16989 16990 + if (sectionNode.stats.assertions.failedButOk) { 16991 + xml.scopedElement("skipped") 16992 + .writeAttribute("message", "TEST_CASE tagged with !mayfail"); 16993 + } 16994 + 16750 16995 writeAssertions( sectionNode ); 16751 16996 16752 16997 if( !sectionNode.stdOut.empty() ) ··· 16756 17001 } 16757 17002 for( auto const& childNode : sectionNode.childSections ) 16758 17003 if( className.empty() ) 16759 - writeSection( name, "", *childNode ); 17004 + writeSection( name, "", *childNode, testOkToFail ); 16760 17005 else 16761 - writeSection( className, name, *childNode ); 17006 + writeSection( className, name, *childNode, testOkToFail ); 16762 17007 } 16763 17008 16764 17009 void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { ··· 17180 17425 .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) 17181 17426 .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) 17182 17427 .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); 17428 + m_xml.scopedElement( "OverallResultsCases") 17429 + .writeAttribute( "successes", testGroupStats.totals.testCases.passed ) 17430 + .writeAttribute( "failures", testGroupStats.totals.testCases.failed ) 17431 + .writeAttribute( "expectedFailures", testGroupStats.totals.testCases.failedButOk ); 17183 17432 m_xml.endElement(); 17184 17433 } 17185 17434 ··· 17189 17438 .writeAttribute( "successes", testRunStats.totals.assertions.passed ) 17190 17439 .writeAttribute( "failures", testRunStats.totals.assertions.failed ) 17191 17440 .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); 17441 + m_xml.scopedElement( "OverallResultsCases") 17442 + .writeAttribute( "successes", testRunStats.totals.testCases.passed ) 17443 + .writeAttribute( "failures", testRunStats.totals.testCases.failed ) 17444 + .writeAttribute( "expectedFailures", testRunStats.totals.testCases.failedButOk ); 17192 17445 m_xml.endElement(); 17193 17446 } 17194 17447