From 1c6ab281a2ff932a236065416765736340db4b7f Mon Sep 17 00:00:00 2001 From: AdamYuan Date: Sun, 14 May 2023 20:58:44 +0800 Subject: [PATCH] Use doctest --- block/CMakeLists.txt | 2 +- block/test/catch_amalgamated.cpp | 10655 ----------------------- block/test/catch_amalgamated.hpp | 12972 ----------------------------- block/test/doctest.h | 7106 ++++++++++++++++ block/test/test_block.cpp | 82 +- 5 files changed, 7155 insertions(+), 23662 deletions(-) delete mode 100644 block/test/catch_amalgamated.cpp delete mode 100644 block/test/catch_amalgamated.hpp create mode 100644 block/test/doctest.h diff --git a/block/CMakeLists.txt b/block/CMakeLists.txt index 08a84c2..7913337 100644 --- a/block/CMakeLists.txt +++ b/block/CMakeLists.txt @@ -36,5 +36,5 @@ target_include_directories(HyperCraft_block ) target_link_libraries(HyperCraft_block PUBLIC hc::texture::block hc::dep) -add_executable(HyperCraft_block_test test/test_block.cpp test/catch_amalgamated.cpp) +add_executable(HyperCraft_block_test test/test_block.cpp) target_link_libraries(HyperCraft_block_test PRIVATE hc::block) \ No newline at end of file diff --git a/block/test/catch_amalgamated.cpp b/block/test/catch_amalgamated.cpp deleted file mode 100644 index a81b1b6..0000000 --- a/block/test/catch_amalgamated.cpp +++ /dev/null @@ -1,10655 +0,0 @@ -// Copyright Catch2 Authors -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.txt or copy at -// https://www.boost.org/LICENSE_1_0.txt) - -// SPDX-License-Identifier: BSL-1.0 - -// Catch v3.3.2 -// Generated: 2023-02-26 10:28:48.270752 -// ---------------------------------------------------------- -// This file is an amalgamation of multiple different files. -// You probably shouldn't edit it directly. -// ---------------------------------------------------------- - -#include "catch_amalgamated.hpp" - - -#ifndef CATCH_WINDOWS_H_PROXY_HPP_INCLUDED -#define CATCH_WINDOWS_H_PROXY_HPP_INCLUDED - - -#if defined(CATCH_PLATFORM_WINDOWS) - -// We might end up with the define made globally through the compiler, -// and we don't want to trigger warnings for this -#if !defined(NOMINMAX) -# define NOMINMAX -#endif -#if !defined(WIN32_LEAN_AND_MEAN) -# define WIN32_LEAN_AND_MEAN -#endif - -#include - -#endif // defined(CATCH_PLATFORM_WINDOWS) - -#endif // CATCH_WINDOWS_H_PROXY_HPP_INCLUDED - - - - -namespace Catch { - namespace Benchmark { - namespace Detail { - ChronometerConcept::~ChronometerConcept() = default; - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - - - - -namespace Catch { - namespace Benchmark { - namespace Detail { - BenchmarkFunction::callable::~callable() = default; - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - - - -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - struct optimized_away_error : std::exception { - const char* what() const noexcept override; - }; - - const char* optimized_away_error::what() const noexcept { - return "could not measure benchmark, maybe it was optimized away"; - } - - void throw_optimized_away_error() { - Catch::throw_exception(optimized_away_error{}); - } - - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - - -// Adapted from donated nonius code. - - - -#include -#include -#include -#include - - -#if defined(CATCH_CONFIG_USE_ASYNC) -#include -#endif - -namespace { - -using Catch::Benchmark::Detail::sample; - - template - sample resample(URng& rng, unsigned int resamples, std::vector::iterator first, std::vector::iterator last, Estimator& estimator) { - auto n = static_cast(last - first); - std::uniform_int_distribution dist(0, n - 1); - - sample out; - out.reserve(resamples); - std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] { - std::vector resampled; - resampled.reserve(n); - std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[static_cast(dist(rng))]; }); - return estimator(resampled.begin(), resampled.end()); - }); - std::sort(out.begin(), out.end()); - return out; - } - - - double erf_inv(double x) { - // Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2 - double w, p; - - w = -log((1.0 - x) * (1.0 + x)); - - if (w < 6.250000) { - w = w - 3.125000; - p = -3.6444120640178196996e-21; - p = -1.685059138182016589e-19 + p * w; - p = 1.2858480715256400167e-18 + p * w; - p = 1.115787767802518096e-17 + p * w; - p = -1.333171662854620906e-16 + p * w; - p = 2.0972767875968561637e-17 + p * w; - p = 6.6376381343583238325e-15 + p * w; - p = -4.0545662729752068639e-14 + p * w; - p = -8.1519341976054721522e-14 + p * w; - p = 2.6335093153082322977e-12 + p * w; - p = -1.2975133253453532498e-11 + p * w; - p = -5.4154120542946279317e-11 + p * w; - p = 1.051212273321532285e-09 + p * w; - p = -4.1126339803469836976e-09 + p * w; - p = -2.9070369957882005086e-08 + p * w; - p = 4.2347877827932403518e-07 + p * w; - p = -1.3654692000834678645e-06 + p * w; - p = -1.3882523362786468719e-05 + p * w; - p = 0.0001867342080340571352 + p * w; - p = -0.00074070253416626697512 + p * w; - p = -0.0060336708714301490533 + p * w; - p = 0.24015818242558961693 + p * w; - p = 1.6536545626831027356 + p * w; - } else if (w < 16.000000) { - w = sqrt(w) - 3.250000; - p = 2.2137376921775787049e-09; - p = 9.0756561938885390979e-08 + p * w; - p = -2.7517406297064545428e-07 + p * w; - p = 1.8239629214389227755e-08 + p * w; - p = 1.5027403968909827627e-06 + p * w; - p = -4.013867526981545969e-06 + p * w; - p = 2.9234449089955446044e-06 + p * w; - p = 1.2475304481671778723e-05 + p * w; - p = -4.7318229009055733981e-05 + p * w; - p = 6.8284851459573175448e-05 + p * w; - p = 2.4031110387097893999e-05 + p * w; - p = -0.0003550375203628474796 + p * w; - p = 0.00095328937973738049703 + p * w; - p = -0.0016882755560235047313 + p * w; - p = 0.0024914420961078508066 + p * w; - p = -0.0037512085075692412107 + p * w; - p = 0.005370914553590063617 + p * w; - p = 1.0052589676941592334 + p * w; - p = 3.0838856104922207635 + p * w; - } else { - w = sqrt(w) - 5.000000; - p = -2.7109920616438573243e-11; - p = -2.5556418169965252055e-10 + p * w; - p = 1.5076572693500548083e-09 + p * w; - p = -3.7894654401267369937e-09 + p * w; - p = 7.6157012080783393804e-09 + p * w; - p = -1.4960026627149240478e-08 + p * w; - p = 2.9147953450901080826e-08 + p * w; - p = -6.7711997758452339498e-08 + p * w; - p = 2.2900482228026654717e-07 + p * w; - p = -9.9298272942317002539e-07 + p * w; - p = 4.5260625972231537039e-06 + p * w; - p = -1.9681778105531670567e-05 + p * w; - p = 7.5995277030017761139e-05 + p * w; - p = -0.00021503011930044477347 + p * w; - p = -0.00013871931833623122026 + p * w; - p = 1.0103004648645343977 + p * w; - p = 4.8499064014085844221 + p * w; - } - return p * x; - } - - double standard_deviation(std::vector::iterator first, std::vector::iterator last) { - auto m = Catch::Benchmark::Detail::mean(first, last); - double variance = std::accumulate( first, - last, - 0., - [m]( double a, double b ) { - double diff = b - m; - return a + diff * diff; - } ) / - ( last - first ); - return std::sqrt( variance ); - } - -} - -namespace Catch { - namespace Benchmark { - namespace Detail { - -#if defined( __GNUC__ ) || defined( __clang__ ) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - bool directCompare( double lhs, double rhs ) { return lhs == rhs; } -#if defined( __GNUC__ ) || defined( __clang__ ) -# pragma GCC diagnostic pop -#endif - - double weighted_average_quantile(int k, int q, std::vector::iterator first, std::vector::iterator last) { - auto count = last - first; - double idx = (count - 1) * k / static_cast(q); - int j = static_cast(idx); - double g = idx - j; - std::nth_element(first, first + j, last); - auto xj = first[j]; - if ( directCompare( g, 0 ) ) { - return xj; - } - - auto xj1 = *std::min_element(first + (j + 1), last); - return xj + g * (xj1 - xj); - } - - - double erfc_inv(double x) { - return erf_inv(1.0 - x); - } - - double normal_quantile(double p) { - static const double ROOT_TWO = std::sqrt(2.0); - - double result = 0.0; - assert(p >= 0 && p <= 1); - if (p < 0 || p > 1) { - return result; - } - - result = -erfc_inv(2.0 * p); - // result *= normal distribution standard deviation (1.0) * sqrt(2) - result *= /*sd * */ ROOT_TWO; - // result += normal disttribution mean (0) - return result; - } - - - double outlier_variance(Estimate mean, Estimate stddev, int n) { - double sb = stddev.point; - double mn = mean.point / n; - double mg_min = mn / 2.; - double sg = (std::min)(mg_min / 4., sb / std::sqrt(n)); - double sg2 = sg * sg; - double sb2 = sb * sb; - - auto c_max = [n, mn, sb2, sg2](double x) -> double { - double k = mn - x; - double d = k * k; - double nd = n * d; - double k0 = -n * nd; - double k1 = sb2 - n * sg2 + nd; - double det = k1 * k1 - 4 * sg2 * k0; - return static_cast(-2. * k0 / (k1 + std::sqrt(det))); - }; - - auto var_out = [n, sb2, sg2](double c) { - double nc = n - c; - return (nc / n) * (sb2 - nc * sg2); - }; - - return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2; - } - - - bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector::iterator first, std::vector::iterator last) { - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS - static std::random_device entropy; - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION - - auto n = static_cast(last - first); // seriously, one can't use integral types without hell in C++ - - auto mean = &Detail::mean::iterator>; - auto stddev = &standard_deviation; - -#if defined(CATCH_CONFIG_USE_ASYNC) - auto Estimate = [=](double(*f)(std::vector::iterator, std::vector::iterator)) { - auto seed = entropy(); - return std::async(std::launch::async, [=] { - std::mt19937 rng(seed); - auto resampled = resample(rng, n_resamples, first, last, f); - return bootstrap(confidence_level, first, last, resampled, f); - }); - }; - - auto mean_future = Estimate(mean); - auto stddev_future = Estimate(stddev); - - auto mean_estimate = mean_future.get(); - auto stddev_estimate = stddev_future.get(); -#else - auto Estimate = [=](double(*f)(std::vector::iterator, std::vector::iterator)) { - auto seed = entropy(); - std::mt19937 rng(seed); - auto resampled = resample(rng, n_resamples, first, last, f); - return bootstrap(confidence_level, first, last, resampled, f); - }; - - auto mean_estimate = Estimate(mean); - auto stddev_estimate = Estimate(stddev); -#endif // CATCH_USE_ASYNC - - double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n); - - return { mean_estimate, stddev_estimate, outlier_variance }; - } - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - - - -#include -#include - -namespace { - -// Performs equivalent check of std::fabs(lhs - rhs) <= margin -// But without the subtraction to allow for INFINITY in comparison -bool marginComparison(double lhs, double rhs, double margin) { - return (lhs + margin >= rhs) && (rhs + margin >= lhs); -} - -} - -namespace Catch { - - Approx::Approx ( double value ) - : m_epsilon( std::numeric_limits::epsilon()*100. ), - m_margin( 0.0 ), - m_scale( 0.0 ), - m_value( value ) - {} - - Approx Approx::custom() { - return Approx( 0 ); - } - - Approx Approx::operator-() const { - auto temp(*this); - temp.m_value = -temp.m_value; - return temp; - } - - - std::string Approx::toString() const { - ReusableStringStream rss; - rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; - return rss.str(); - } - - bool Approx::equalityComparisonImpl(const double other) const { - // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value - // Thanks to Richard Harris for his help refining the scaled margin value - return marginComparison(m_value, other, m_margin) - || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value))); - } - - void Approx::setMargin(double newMargin) { - CATCH_ENFORCE(newMargin >= 0, - "Invalid Approx::margin: " << newMargin << '.' - << " Approx::Margin has to be non-negative."); - m_margin = newMargin; - } - - void Approx::setEpsilon(double newEpsilon) { - CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0, - "Invalid Approx::epsilon: " << newEpsilon << '.' - << " Approx::epsilon has to be in [0, 1]"); - m_epsilon = newEpsilon; - } - -namespace literals { - Approx operator "" _a(long double val) { - return Approx(val); - } - Approx operator "" _a(unsigned long long val) { - return Approx(val); - } -} // end namespace literals - -std::string StringMaker::convert(Catch::Approx const& value) { - return value.toString(); -} - -} // end namespace Catch - - - -namespace Catch { - - AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): - lazyExpression(_lazyExpression), - resultType(_resultType) {} - - std::string AssertionResultData::reconstructExpression() const { - - if( reconstructedExpression.empty() ) { - if( lazyExpression ) { - ReusableStringStream rss; - rss << lazyExpression; - reconstructedExpression = rss.str(); - } - } - return reconstructedExpression; - } - - AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData&& data ) - : m_info( info ), - m_resultData( CATCH_MOVE(data) ) - {} - - // Result was a success - bool AssertionResult::succeeded() const { - return Catch::isOk( m_resultData.resultType ); - } - - // Result was a success, or failure is suppressed - bool AssertionResult::isOk() const { - return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); - } - - ResultWas::OfType AssertionResult::getResultType() const { - return m_resultData.resultType; - } - - bool AssertionResult::hasExpression() const { - return !m_info.capturedExpression.empty(); - } - - bool AssertionResult::hasMessage() const { - return !m_resultData.message.empty(); - } - - std::string AssertionResult::getExpression() const { - // Possibly overallocating by 3 characters should be basically free - std::string expr; expr.reserve(m_info.capturedExpression.size() + 3); - if (isFalseTest(m_info.resultDisposition)) { - expr += "!("; - } - expr += m_info.capturedExpression; - if (isFalseTest(m_info.resultDisposition)) { - expr += ')'; - } - return expr; - } - - std::string AssertionResult::getExpressionInMacro() const { - if ( m_info.macroName.empty() ) { - return static_cast( m_info.capturedExpression ); - } - std::string expr; - expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); - expr += m_info.macroName; - expr += "( "; - expr += m_info.capturedExpression; - expr += " )"; - return expr; - } - - bool AssertionResult::hasExpandedExpression() const { - return hasExpression() && getExpandedExpression() != getExpression(); - } - - std::string AssertionResult::getExpandedExpression() const { - std::string expr = m_resultData.reconstructExpression(); - return expr.empty() - ? getExpression() - : expr; - } - - StringRef AssertionResult::getMessage() const { - return m_resultData.message; - } - SourceLineInfo AssertionResult::getSourceInfo() const { - return m_info.lineInfo; - } - - StringRef AssertionResult::getTestMacroName() const { - return m_info.macroName; - } - -} // end namespace Catch - - - -#include - -namespace Catch { - - namespace { - static bool enableBazelEnvSupport() { -#if defined( CATCH_CONFIG_BAZEL_SUPPORT ) - return true; -#else - return Detail::getEnv( "BAZEL_TEST" ) != nullptr; -#endif - } - - struct bazelShardingOptions { - unsigned int shardIndex, shardCount; - std::string shardFilePath; - }; - - static Optional readBazelShardingOptions() { - const auto bazelShardIndex = Detail::getEnv( "TEST_SHARD_INDEX" ); - const auto bazelShardTotal = Detail::getEnv( "TEST_TOTAL_SHARDS" ); - const auto bazelShardInfoFile = Detail::getEnv( "TEST_SHARD_STATUS_FILE" ); - - - const bool has_all = - bazelShardIndex && bazelShardTotal && bazelShardInfoFile; - if ( !has_all ) { - // We provide nice warning message if the input is - // misconfigured. - auto warn = []( const char* env_var ) { - Catch::cerr() - << "Warning: Bazel shard configuration is missing '" - << env_var << "'. Shard configuration is skipped.\n"; - }; - if ( !bazelShardIndex ) { - warn( "TEST_SHARD_INDEX" ); - } - if ( !bazelShardTotal ) { - warn( "TEST_TOTAL_SHARDS" ); - } - if ( !bazelShardInfoFile ) { - warn( "TEST_SHARD_STATUS_FILE" ); - } - return {}; - } - - auto shardIndex = parseUInt( bazelShardIndex ); - if ( !shardIndex ) { - Catch::cerr() - << "Warning: could not parse 'TEST_SHARD_INDEX' ('" << bazelShardIndex - << "') as unsigned int.\n"; - return {}; - } - auto shardTotal = parseUInt( bazelShardTotal ); - if ( !shardTotal ) { - Catch::cerr() - << "Warning: could not parse 'TEST_TOTAL_SHARD' ('" - << bazelShardTotal << "') as unsigned int.\n"; - return {}; - } - - return bazelShardingOptions{ - *shardIndex, *shardTotal, bazelShardInfoFile }; - - } - } // end namespace - - - bool operator==( ProcessedReporterSpec const& lhs, - ProcessedReporterSpec const& rhs ) { - return lhs.name == rhs.name && - lhs.outputFilename == rhs.outputFilename && - lhs.colourMode == rhs.colourMode && - lhs.customOptions == rhs.customOptions; - } - - Config::Config( ConfigData const& data ): - m_data( data ) { - // We need to trim filter specs to avoid trouble with superfluous - // whitespace (esp. important for bdd macros, as those are manually - // aligned with whitespace). - - for (auto& elem : m_data.testsOrTags) { - elem = trim(elem); - } - for (auto& elem : m_data.sectionsToRun) { - elem = trim(elem); - } - - // Insert the default reporter if user hasn't asked for a specfic one - if ( m_data.reporterSpecifications.empty() ) { - m_data.reporterSpecifications.push_back( { -#if defined( CATCH_CONFIG_DEFAULT_REPORTER ) - CATCH_CONFIG_DEFAULT_REPORTER, -#else - "console", -#endif - {}, {}, {} - } ); - } - - if ( enableBazelEnvSupport() ) { - readBazelEnvVars(); - } - - // Bazel support can modify the test specs, so parsing has to happen - // after reading Bazel env vars. - TestSpecParser parser( ITagAliasRegistry::get() ); - if ( !m_data.testsOrTags.empty() ) { - m_hasTestFilters = true; - for ( auto const& testOrTags : m_data.testsOrTags ) { - parser.parse( testOrTags ); - } - } - m_testSpec = parser.testSpec(); - - - // We now fixup the reporter specs to handle default output spec, - // default colour spec, etc - bool defaultOutputUsed = false; - for ( auto const& reporterSpec : m_data.reporterSpecifications ) { - // We do the default-output check separately, while always - // using the default output below to make the code simpler - // and avoid superfluous copies. - if ( reporterSpec.outputFile().none() ) { - CATCH_ENFORCE( !defaultOutputUsed, - "Internal error: cannot use default output for " - "multiple reporters" ); - defaultOutputUsed = true; - } - - m_processedReporterSpecs.push_back( ProcessedReporterSpec{ - reporterSpec.name(), - reporterSpec.outputFile() ? *reporterSpec.outputFile() - : data.defaultOutputFilename, - reporterSpec.colourMode().valueOr( data.defaultColourMode ), - reporterSpec.customOptions() } ); - } - } - - Config::~Config() = default; - - - bool Config::listTests() const { return m_data.listTests; } - bool Config::listTags() const { return m_data.listTags; } - bool Config::listReporters() const { return m_data.listReporters; } - bool Config::listListeners() const { return m_data.listListeners; } - - std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; } - std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } - - std::vector const& Config::getReporterSpecs() const { - return m_data.reporterSpecifications; - } - - std::vector const& - Config::getProcessedReporterSpecs() const { - return m_processedReporterSpecs; - } - - TestSpec const& Config::testSpec() const { return m_testSpec; } - bool Config::hasTestFilters() const { return m_hasTestFilters; } - - bool Config::showHelp() const { return m_data.showHelp; } - - // IConfig interface - bool Config::allowThrows() const { return !m_data.noThrow; } - StringRef Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } - bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } - bool Config::warnAboutMissingAssertions() const { - return !!( m_data.warnings & WarnAbout::NoAssertions ); - } - bool Config::warnAboutUnmatchedTestSpecs() const { - return !!( m_data.warnings & WarnAbout::UnmatchedTestSpec ); - } - bool Config::zeroTestsCountAsSuccess() const { return m_data.allowZeroTests; } - ShowDurations Config::showDurations() const { return m_data.showDurations; } - double Config::minDuration() const { return m_data.minDuration; } - TestRunOrder Config::runOrder() const { return m_data.runOrder; } - uint32_t Config::rngSeed() const { return m_data.rngSeed; } - unsigned int Config::shardCount() const { return m_data.shardCount; } - unsigned int Config::shardIndex() const { return m_data.shardIndex; } - ColourMode Config::defaultColourMode() const { return m_data.defaultColourMode; } - bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } - int Config::abortAfter() const { return m_data.abortAfter; } - bool Config::showInvisibles() const { return m_data.showInvisibles; } - Verbosity Config::verbosity() const { return m_data.verbosity; } - - bool Config::skipBenchmarks() const { return m_data.skipBenchmarks; } - bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; } - unsigned int Config::benchmarkSamples() const { return m_data.benchmarkSamples; } - double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; } - unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; } - std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); } - - void Config::readBazelEnvVars() { - // Register a JUnit reporter for Bazel. Bazel sets an environment - // variable with the path to XML output. If this file is written to - // during test, Bazel will not generate a default XML output. - // This allows the XML output file to contain higher level of detail - // than what is possible otherwise. - const auto bazelOutputFile = Detail::getEnv( "XML_OUTPUT_FILE" ); - - if ( bazelOutputFile ) { - m_data.reporterSpecifications.push_back( - { "junit", std::string( bazelOutputFile ), {}, {} } ); - } - - const auto bazelTestSpec = Detail::getEnv( "TESTBRIDGE_TEST_ONLY" ); - if ( bazelTestSpec ) { - // Presumably the test spec from environment should overwrite - // the one we got from CLI (if we got any) - m_data.testsOrTags.clear(); - m_data.testsOrTags.push_back( bazelTestSpec ); - } - - const auto bazelShardOptions = readBazelShardingOptions(); - if ( bazelShardOptions ) { - std::ofstream f( bazelShardOptions->shardFilePath, - std::ios_base::out | std::ios_base::trunc ); - if ( f.is_open() ) { - f << ""; - m_data.shardIndex = bazelShardOptions->shardIndex; - m_data.shardCount = bazelShardOptions->shardCount; - } - } - } - -} // end namespace Catch - - - - - -namespace Catch { - std::uint32_t getSeed() { - return getCurrentContext().getConfig()->rngSeed(); - } -} - - - -#include -#include - -namespace Catch { - - //////////////////////////////////////////////////////////////////////////// - - - ScopedMessage::ScopedMessage( MessageBuilder&& builder ): - m_info( CATCH_MOVE(builder.m_info) ) { - m_info.message = builder.m_stream.str(); - getResultCapture().pushScopedMessage( m_info ); - } - - ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept: - m_info( CATCH_MOVE( old.m_info ) ) { - old.m_moved = true; - } - - ScopedMessage::~ScopedMessage() { - if ( !uncaught_exceptions() && !m_moved ){ - getResultCapture().popScopedMessage(m_info); - } - } - - - Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { - auto trimmed = [&] (size_t start, size_t end) { - while (names[start] == ',' || isspace(static_cast(names[start]))) { - ++start; - } - while (names[end] == ',' || isspace(static_cast(names[end]))) { - --end; - } - return names.substr(start, end - start + 1); - }; - auto skipq = [&] (size_t start, char quote) { - for (auto i = start + 1; i < names.size() ; ++i) { - if (names[i] == quote) - return i; - if (names[i] == '\\') - ++i; - } - CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote"); - }; - - size_t start = 0; - std::stack openings; - for (size_t pos = 0; pos < names.size(); ++pos) { - char c = names[pos]; - switch (c) { - case '[': - case '{': - case '(': - // It is basically impossible to disambiguate between - // comparison and start of template args in this context -// case '<': - openings.push(c); - break; - case ']': - case '}': - case ')': -// case '>': - openings.pop(); - break; - case '"': - case '\'': - pos = skipq(pos, c); - break; - case ',': - if (start != pos && openings.empty()) { - m_messages.emplace_back(macroName, lineInfo, resultType); - m_messages.back().message = static_cast(trimmed(start, pos)); - m_messages.back().message += " := "; - start = pos; - } - } - } - assert(openings.empty() && "Mismatched openings"); - m_messages.emplace_back(macroName, lineInfo, resultType); - m_messages.back().message = static_cast(trimmed(start, names.size() - 1)); - m_messages.back().message += " := "; - } - Capturer::~Capturer() { - if ( !uncaught_exceptions() ){ - assert( m_captured == m_messages.size() ); - for( size_t i = 0; i < m_captured; ++i ) - m_resultCapture.popScopedMessage( m_messages[i] ); - } - } - - void Capturer::captureValue( size_t index, std::string const& value ) { - assert( index < m_messages.size() ); - m_messages[index].message += value; - m_resultCapture.pushScopedMessage( m_messages[index] ); - m_captured++; - } - -} // end namespace Catch - - - - -namespace Catch { - - namespace { - - class RegistryHub : public IRegistryHub, - public IMutableRegistryHub, - private Detail::NonCopyable { - - public: // IRegistryHub - RegistryHub() = default; - IReporterRegistry const& getReporterRegistry() const override { - return m_reporterRegistry; - } - ITestCaseRegistry const& getTestCaseRegistry() const override { - return m_testCaseRegistry; - } - IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override { - return m_exceptionTranslatorRegistry; - } - ITagAliasRegistry const& getTagAliasRegistry() const override { - return m_tagAliasRegistry; - } - StartupExceptionRegistry const& getStartupExceptionRegistry() const override { - return m_exceptionRegistry; - } - - public: // IMutableRegistryHub - void registerReporter( std::string const& name, IReporterFactoryPtr factory ) override { - m_reporterRegistry.registerReporter( name, CATCH_MOVE(factory) ); - } - void registerListener( Detail::unique_ptr factory ) override { - m_reporterRegistry.registerListener( CATCH_MOVE(factory) ); - } - void registerTest( Detail::unique_ptr&& testInfo, Detail::unique_ptr&& invoker ) override { - m_testCaseRegistry.registerTest( CATCH_MOVE(testInfo), CATCH_MOVE(invoker) ); - } - void registerTranslator( Detail::unique_ptr&& translator ) override { - m_exceptionTranslatorRegistry.registerTranslator( CATCH_MOVE(translator) ); - } - void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { - m_tagAliasRegistry.add( alias, tag, lineInfo ); - } - void registerStartupException() noexcept override { -#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - m_exceptionRegistry.add(std::current_exception()); -#else - CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); -#endif - } - IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override { - return m_enumValuesRegistry; - } - - private: - TestRegistry m_testCaseRegistry; - ReporterRegistry m_reporterRegistry; - ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; - TagAliasRegistry m_tagAliasRegistry; - StartupExceptionRegistry m_exceptionRegistry; - Detail::EnumValuesRegistry m_enumValuesRegistry; - }; - } - - using RegistryHubSingleton = Singleton; - - IRegistryHub const& getRegistryHub() { - return RegistryHubSingleton::get(); - } - IMutableRegistryHub& getMutableRegistryHub() { - return RegistryHubSingleton::getMutable(); - } - void cleanUp() { - cleanupSingletons(); - cleanUpContext(); - } - std::string translateActiveException() { - return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); - } - - -} // end namespace Catch - - - -#include -#include -#include -#include - -namespace Catch { - - namespace { - const int MaxExitCode = 255; - - IEventListenerPtr createReporter(std::string const& reporterName, ReporterConfig&& config) { - auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, CATCH_MOVE(config)); - CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << '\''); - - return reporter; - } - - IEventListenerPtr prepareReporters(Config const* config) { - if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty() - && config->getProcessedReporterSpecs().size() == 1) { - auto const& spec = config->getProcessedReporterSpecs()[0]; - return createReporter( - spec.name, - ReporterConfig( config, - makeStream( spec.outputFilename ), - spec.colourMode, - spec.customOptions ) ); - } - - auto multi = Detail::make_unique(config); - - auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); - for (auto const& listener : listeners) { - multi->addListener(listener->create(config)); - } - - for ( auto const& reporterSpec : config->getProcessedReporterSpecs() ) { - multi->addReporter( createReporter( - reporterSpec.name, - ReporterConfig( config, - makeStream( reporterSpec.outputFilename ), - reporterSpec.colourMode, - reporterSpec.customOptions ) ) ); - } - - return multi; - } - - class TestGroup { - public: - explicit TestGroup(IEventListenerPtr&& reporter, Config const* config): - m_reporter(reporter.get()), - m_config{config}, - m_context{config, CATCH_MOVE(reporter)} { - - assert( m_config->testSpec().getInvalidSpecs().empty() && - "Invalid test specs should be handled before running tests" ); - - auto const& allTestCases = getAllTestCasesSorted(*m_config); - auto const& testSpec = m_config->testSpec(); - if ( !testSpec.hasFilters() ) { - for ( auto const& test : allTestCases ) { - if ( !test.getTestCaseInfo().isHidden() ) { - m_tests.emplace( &test ); - } - } - } else { - m_matches = - testSpec.matchesByFilter( allTestCases, *m_config ); - for ( auto const& match : m_matches ) { - m_tests.insert( match.tests.begin(), - match.tests.end() ); - } - } - - m_tests = createShard(m_tests, m_config->shardCount(), m_config->shardIndex()); - } - - Totals execute() { - Totals totals; - for (auto const& testCase : m_tests) { - if (!m_context.aborting()) - totals += m_context.runTest(*testCase); - else - m_reporter->skipTest(testCase->getTestCaseInfo()); - } - - for (auto const& match : m_matches) { - if (match.tests.empty()) { - m_unmatchedTestSpecs = true; - m_reporter->noMatchingTestCases( match.name ); - } - } - - return totals; - } - - bool hadUnmatchedTestSpecs() const { - return m_unmatchedTestSpecs; - } - - - private: - IEventListener* m_reporter; - Config const* m_config; - RunContext m_context; - std::set m_tests; - TestSpec::Matches m_matches; - bool m_unmatchedTestSpecs = false; - }; - - void applyFilenamesAsTags() { - for (auto const& testInfo : getRegistryHub().getTestCaseRegistry().getAllInfos()) { - testInfo->addFilenameTag(); - } - } - - } // anon namespace - - Session::Session() { - static bool alreadyInstantiated = false; - if( alreadyInstantiated ) { - CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } - CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); } - } - - // There cannot be exceptions at startup in no-exception mode. -#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); - if ( !exceptions.empty() ) { - config(); - getCurrentMutableContext().setConfig(m_config.get()); - - m_startupExceptions = true; - auto errStream = makeStream( "%stderr" ); - auto colourImpl = makeColourImpl( - ColourMode::PlatformDefault, errStream.get() ); - auto guard = colourImpl->guardColour( Colour::Red ); - errStream->stream() << "Errors occurred during startup!" << '\n'; - // iterate over all exceptions and notify user - for ( const auto& ex_ptr : exceptions ) { - try { - std::rethrow_exception(ex_ptr); - } catch ( std::exception const& ex ) { - errStream->stream() << TextFlow::Column( ex.what() ).indent(2) << '\n'; - } - } - } -#endif - - alreadyInstantiated = true; - m_cli = makeCommandLineParser( m_configData ); - } - Session::~Session() { - Catch::cleanUp(); - } - - void Session::showHelp() const { - Catch::cout() - << "\nCatch2 v" << libraryVersion() << '\n' - << m_cli << '\n' - << "For more detailed usage please see the project docs\n\n" << std::flush; - } - void Session::libIdentify() { - Catch::cout() - << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n" - << std::left << std::setw(16) << "category: " << "testframework\n" - << std::left << std::setw(16) << "framework: " << "Catch2\n" - << std::left << std::setw(16) << "version: " << libraryVersion() << '\n' << std::flush; - } - - int Session::applyCommandLine( int argc, char const * const * argv ) { - if( m_startupExceptions ) - return 1; - - auto result = m_cli.parse( Clara::Args( argc, argv ) ); - - if( !result ) { - config(); - getCurrentMutableContext().setConfig(m_config.get()); - auto errStream = makeStream( "%stderr" ); - auto colour = makeColourImpl( ColourMode::PlatformDefault, errStream.get() ); - - errStream->stream() - << colour->guardColour( Colour::Red ) - << "\nError(s) in input:\n" - << TextFlow::Column( result.errorMessage() ).indent( 2 ) - << "\n\n"; - errStream->stream() << "Run with -? for usage\n\n" << std::flush; - return MaxExitCode; - } - - if( m_configData.showHelp ) - showHelp(); - if( m_configData.libIdentify ) - libIdentify(); - - m_config.reset(); - return 0; - } - -#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) - int Session::applyCommandLine( int argc, wchar_t const * const * argv ) { - - char **utf8Argv = new char *[ argc ]; - - for ( int i = 0; i < argc; ++i ) { - int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr ); - - utf8Argv[ i ] = new char[ bufSize ]; - - WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr ); - } - - int returnCode = applyCommandLine( argc, utf8Argv ); - - for ( int i = 0; i < argc; ++i ) - delete [] utf8Argv[ i ]; - - delete [] utf8Argv; - - return returnCode; - } -#endif - - void Session::useConfigData( ConfigData const& configData ) { - m_configData = configData; - m_config.reset(); - } - - int Session::run() { - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before starting\n" << std::flush; - static_cast(std::getchar()); - } - int exitCode = runInternal(); - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << '\n' << std::flush; - static_cast(std::getchar()); - } - return exitCode; - } - - Clara::Parser const& Session::cli() const { - return m_cli; - } - void Session::cli( Clara::Parser const& newParser ) { - m_cli = newParser; - } - ConfigData& Session::configData() { - return m_configData; - } - Config& Session::config() { - if( !m_config ) - m_config = Detail::make_unique( m_configData ); - return *m_config; - } - - int Session::runInternal() { - if( m_startupExceptions ) - return 1; - - if (m_configData.showHelp || m_configData.libIdentify) { - return 0; - } - - if ( m_configData.shardIndex >= m_configData.shardCount ) { - Catch::cerr() << "The shard count (" << m_configData.shardCount - << ") must be greater than the shard index (" - << m_configData.shardIndex << ")\n" - << std::flush; - return 1; - } - - CATCH_TRY { - config(); // Force config to be constructed - - seedRng( *m_config ); - - if (m_configData.filenamesAsTags) { - applyFilenamesAsTags(); - } - - // Set up global config instance before we start calling into other functions - getCurrentMutableContext().setConfig(m_config.get()); - - // Create reporter(s) so we can route listings through them - auto reporter = prepareReporters(m_config.get()); - - auto const& invalidSpecs = m_config->testSpec().getInvalidSpecs(); - if ( !invalidSpecs.empty() ) { - for ( auto const& spec : invalidSpecs ) { - reporter->reportInvalidTestSpec( spec ); - } - return 1; - } - - - // Handle list request - if (list(*reporter, *m_config)) { - return 0; - } - - TestGroup tests { CATCH_MOVE(reporter), m_config.get() }; - auto const totals = tests.execute(); - - if ( tests.hadUnmatchedTestSpecs() - && m_config->warnAboutUnmatchedTestSpecs() ) { - return 3; - } - - if ( totals.testCases.total() == 0 - && !m_config->zeroTestsCountAsSuccess() ) { - return 2; - } - - if ( totals.testCases.total() > 0 && - totals.testCases.total() == totals.testCases.skipped - && !m_config->zeroTestsCountAsSuccess() ) { - return 4; - } - - // Note that on unices only the lower 8 bits are usually used, clamping - // the return value to 255 prevents false negative when some multiple - // of 256 tests has failed - return (std::min) (MaxExitCode, static_cast(totals.assertions.failed)); - } -#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - catch( std::exception& ex ) { - Catch::cerr() << ex.what() << '\n' << std::flush; - return MaxExitCode; - } -#endif - } - -} // end namespace Catch - - - - -namespace Catch { - - RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { - CATCH_TRY { - getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); - } CATCH_CATCH_ALL { - // Do not throw when constructing global objects, instead register the exception to be processed later - getMutableRegistryHub().registerStartupException(); - } - } - -} - - - -#include -#include -#include - -namespace Catch { - - namespace { - using TCP_underlying_type = uint8_t; - static_assert(sizeof(TestCaseProperties) == sizeof(TCP_underlying_type), - "The size of the TestCaseProperties is different from the assumed size"); - - TestCaseProperties operator|(TestCaseProperties lhs, TestCaseProperties rhs) { - return static_cast( - static_cast(lhs) | static_cast(rhs) - ); - } - - TestCaseProperties& operator|=(TestCaseProperties& lhs, TestCaseProperties rhs) { - lhs = static_cast( - static_cast(lhs) | static_cast(rhs) - ); - return lhs; - } - - TestCaseProperties operator&(TestCaseProperties lhs, TestCaseProperties rhs) { - return static_cast( - static_cast(lhs) & static_cast(rhs) - ); - } - - bool applies(TestCaseProperties tcp) { - static_assert(static_cast(TestCaseProperties::None) == 0, - "TestCaseProperties::None must be equal to 0"); - return tcp != TestCaseProperties::None; - } - - TestCaseProperties parseSpecialTag( StringRef tag ) { - if( !tag.empty() && tag[0] == '.' ) - return TestCaseProperties::IsHidden; - else if( tag == "!throws"_sr ) - return TestCaseProperties::Throws; - else if( tag == "!shouldfail"_sr ) - return TestCaseProperties::ShouldFail; - else if( tag == "!mayfail"_sr ) - return TestCaseProperties::MayFail; - else if( tag == "!nonportable"_sr ) - return TestCaseProperties::NonPortable; - else if( tag == "!benchmark"_sr ) - return TestCaseProperties::Benchmark | TestCaseProperties::IsHidden; - else - return TestCaseProperties::None; - } - bool isReservedTag( StringRef tag ) { - return parseSpecialTag( tag ) == TestCaseProperties::None - && tag.size() > 0 - && !std::isalnum( static_cast(tag[0]) ); - } - void enforceNotReservedTag( StringRef tag, SourceLineInfo const& _lineInfo ) { - CATCH_ENFORCE( !isReservedTag(tag), - "Tag name: [" << tag << "] is not allowed.\n" - << "Tag names starting with non alphanumeric characters are reserved\n" - << _lineInfo ); - } - - std::string makeDefaultName() { - static size_t counter = 0; - return "Anonymous test case " + std::to_string(++counter); - } - - StringRef extractFilenamePart(StringRef filename) { - size_t lastDot = filename.size(); - while (lastDot > 0 && filename[lastDot - 1] != '.') { - --lastDot; - } - --lastDot; - - size_t nameStart = lastDot; - while (nameStart > 0 && filename[nameStart - 1] != '/' && filename[nameStart - 1] != '\\') { - --nameStart; - } - - return filename.substr(nameStart, lastDot - nameStart); - } - - // Returns the upper bound on size of extra tags ([#file]+[.]) - size_t sizeOfExtraTags(StringRef filepath) { - // [.] is 3, [#] is another 3 - const size_t extras = 3 + 3; - return extractFilenamePart(filepath).size() + extras; - } - } // end unnamed namespace - - bool operator<( Tag const& lhs, Tag const& rhs ) { - Detail::CaseInsensitiveLess cmp; - return cmp( lhs.original, rhs.original ); - } - bool operator==( Tag const& lhs, Tag const& rhs ) { - Detail::CaseInsensitiveEqualTo cmp; - return cmp( lhs.original, rhs.original ); - } - - Detail::unique_ptr - makeTestCaseInfo(StringRef _className, - NameAndTags const& nameAndTags, - SourceLineInfo const& _lineInfo ) { - return Detail::make_unique(_className, nameAndTags, _lineInfo); - } - - TestCaseInfo::TestCaseInfo(StringRef _className, - NameAndTags const& _nameAndTags, - SourceLineInfo const& _lineInfo): - name( _nameAndTags.name.empty() ? makeDefaultName() : _nameAndTags.name ), - className( _className ), - lineInfo( _lineInfo ) - { - StringRef originalTags = _nameAndTags.tags; - // We need to reserve enough space to store all of the tags - // (including optional hidden tag and filename tag) - auto requiredSize = originalTags.size() + sizeOfExtraTags(_lineInfo.file); - backingTags.reserve(requiredSize); - - // We cannot copy the tags directly, as we need to normalize - // some tags, so that [.foo] is copied as [.][foo]. - size_t tagStart = 0; - size_t tagEnd = 0; - bool inTag = false; - for (size_t idx = 0; idx < originalTags.size(); ++idx) { - auto c = originalTags[idx]; - if (c == '[') { - assert(!inTag); - inTag = true; - tagStart = idx; - } - if (c == ']') { - assert(inTag); - inTag = false; - tagEnd = idx; - assert(tagStart < tagEnd); - - // We need to check the tag for special meanings, copy - // it over to backing storage and actually reference the - // backing storage in the saved tags - StringRef tagStr = originalTags.substr(tagStart+1, tagEnd - tagStart - 1); - CATCH_ENFORCE(!tagStr.empty(), "Empty tags are not allowed"); - enforceNotReservedTag(tagStr, lineInfo); - properties |= parseSpecialTag(tagStr); - // When copying a tag to the backing storage, we need to - // check if it is a merged hide tag, such as [.foo], and - // if it is, we need to handle it as if it was [foo]. - if (tagStr.size() > 1 && tagStr[0] == '.') { - tagStr = tagStr.substr(1, tagStr.size() - 1); - } - // We skip over dealing with the [.] tag, as we will add - // it later unconditionally and then sort and unique all - // the tags. - internalAppendTag(tagStr); - } - (void)inTag; // Silence "set-but-unused" warning in release mode. - } - // Add [.] if relevant - if (isHidden()) { - internalAppendTag("."_sr); - } - - // Sort and prepare tags - std::sort(begin(tags), end(tags)); - tags.erase(std::unique(begin(tags), end(tags)), - end(tags)); - } - - bool TestCaseInfo::isHidden() const { - return applies( properties & TestCaseProperties::IsHidden ); - } - bool TestCaseInfo::throws() const { - return applies( properties & TestCaseProperties::Throws ); - } - bool TestCaseInfo::okToFail() const { - return applies( properties & (TestCaseProperties::ShouldFail | TestCaseProperties::MayFail ) ); - } - bool TestCaseInfo::expectedToFail() const { - return applies( properties & (TestCaseProperties::ShouldFail) ); - } - - void TestCaseInfo::addFilenameTag() { - std::string combined("#"); - combined += extractFilenamePart(lineInfo.file); - internalAppendTag(combined); - } - - std::string TestCaseInfo::tagsAsString() const { - std::string ret; - // '[' and ']' per tag - std::size_t full_size = 2 * tags.size(); - for (const auto& tag : tags) { - full_size += tag.original.size(); - } - ret.reserve(full_size); - for (const auto& tag : tags) { - ret.push_back('['); - ret += tag.original; - ret.push_back(']'); - } - - return ret; - } - - void TestCaseInfo::internalAppendTag(StringRef tagStr) { - backingTags += '['; - const auto backingStart = backingTags.size(); - backingTags += tagStr; - const auto backingEnd = backingTags.size(); - backingTags += ']'; - tags.emplace_back(StringRef(backingTags.c_str() + backingStart, backingEnd - backingStart)); - } - - bool operator<( TestCaseInfo const& lhs, TestCaseInfo const& rhs ) { - // We want to avoid redoing the string comparisons multiple times, - // so we store the result of a three-way comparison before using - // it in the actual comparison logic. - const auto cmpName = lhs.name.compare( rhs.name ); - if ( cmpName != 0 ) { - return cmpName < 0; - } - const auto cmpClassName = lhs.className.compare( rhs.className ); - if ( cmpClassName != 0 ) { - return cmpClassName < 0; - } - return lhs.tags < rhs.tags; - } - - TestCaseInfo const& TestCaseHandle::getTestCaseInfo() const { - return *m_info; - } - -} // end namespace Catch - - - -#include -#include -#include -#include - -namespace Catch { - - TestSpec::Pattern::Pattern( std::string const& name ) - : m_name( name ) - {} - - TestSpec::Pattern::~Pattern() = default; - - std::string const& TestSpec::Pattern::name() const { - return m_name; - } - - - TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString ) - : Pattern( filterString ) - , m_wildcardPattern( toLower( name ), CaseSensitive::No ) - {} - - bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { - return m_wildcardPattern.matches( testCase.name ); - } - - void TestSpec::NamePattern::serializeTo( std::ostream& out ) const { - out << '"' << name() << '"'; - } - - - TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString ) - : Pattern( filterString ) - , m_tag( tag ) - {} - - bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { - return std::find( begin( testCase.tags ), - end( testCase.tags ), - Tag( m_tag ) ) != end( testCase.tags ); - } - - void TestSpec::TagPattern::serializeTo( std::ostream& out ) const { - out << name(); - } - - bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { - bool should_use = !testCase.isHidden(); - for (auto const& pattern : m_required) { - should_use = true; - if (!pattern->matches(testCase)) { - return false; - } - } - for (auto const& pattern : m_forbidden) { - if (pattern->matches(testCase)) { - return false; - } - } - return should_use; - } - - void TestSpec::Filter::serializeTo( std::ostream& out ) const { - bool first = true; - for ( auto const& pattern : m_required ) { - if ( !first ) { - out << ' '; - } - out << *pattern; - first = false; - } - for ( auto const& pattern : m_forbidden ) { - if ( !first ) { - out << ' '; - } - out << *pattern; - first = false; - } - } - - - std::string TestSpec::extractFilterName( Filter const& filter ) { - Catch::ReusableStringStream sstr; - sstr << filter; - return sstr.str(); - } - - bool TestSpec::hasFilters() const { - return !m_filters.empty(); - } - - bool TestSpec::matches( TestCaseInfo const& testCase ) const { - return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } ); - } - - TestSpec::Matches TestSpec::matchesByFilter( std::vector const& testCases, IConfig const& config ) const - { - Matches matches( m_filters.size() ); - std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){ - std::vector currentMatches; - for( auto const& test : testCases ) - if( isThrowSafe( test, config ) && filter.matches( test.getTestCaseInfo() ) ) - currentMatches.emplace_back( &test ); - return FilterMatch{ extractFilterName(filter), currentMatches }; - } ); - return matches; - } - - const TestSpec::vectorStrings& TestSpec::getInvalidSpecs() const { - return m_invalidSpecs; - } - - void TestSpec::serializeTo( std::ostream& out ) const { - bool first = true; - for ( auto const& filter : m_filters ) { - if ( !first ) { - out << ','; - } - out << filter; - first = false; - } - } - -} - - - -#include - -namespace Catch { - - namespace { - static auto getCurrentNanosecondsSinceEpoch() -> uint64_t { - return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); - } - } // end unnamed namespace - - void Timer::start() { - m_nanoseconds = getCurrentNanosecondsSinceEpoch(); - } - auto Timer::getElapsedNanoseconds() const -> uint64_t { - return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; - } - auto Timer::getElapsedMicroseconds() const -> uint64_t { - return getElapsedNanoseconds()/1000; - } - auto Timer::getElapsedMilliseconds() const -> unsigned int { - return static_cast(getElapsedMicroseconds()/1000); - } - auto Timer::getElapsedSeconds() const -> double { - return getElapsedMicroseconds()/1000000.0; - } - - -} // namespace Catch - - - - -#include -#include - -namespace Catch { - -namespace Detail { - - namespace { - const int hexThreshold = 255; - - struct Endianness { - enum Arch { Big, Little }; - - static Arch which() { - int one = 1; - // If the lowest byte we read is non-zero, we can assume - // that little endian format is used. - auto value = *reinterpret_cast(&one); - return value ? Little : Big; - } - }; - - template - std::string fpToString(T value, int precision) { - if (Catch::isnan(value)) { - return "nan"; - } - - ReusableStringStream rss; - rss << std::setprecision(precision) - << std::fixed - << value; - std::string d = rss.str(); - std::size_t i = d.find_last_not_of('0'); - if (i != std::string::npos && i != d.size() - 1) { - if (d[i] == '.') - i++; - d = d.substr(0, i + 1); - } - return d; - } - } // end unnamed namespace - - std::string convertIntoString(StringRef string, bool escape_invisibles) { - std::string ret; - // This is enough for the "don't escape invisibles" case, and a good - // lower bound on the "escape invisibles" case. - ret.reserve(string.size() + 2); - - if (!escape_invisibles) { - ret += '"'; - ret += string; - ret += '"'; - return ret; - } - - ret += '"'; - for (char c : string) { - switch (c) { - case '\r': - ret.append("\\r"); - break; - case '\n': - ret.append("\\n"); - break; - case '\t': - ret.append("\\t"); - break; - case '\f': - ret.append("\\f"); - break; - default: - ret.push_back(c); - break; - } - } - ret += '"'; - - return ret; - } - - std::string convertIntoString(StringRef string) { - return convertIntoString(string, getCurrentContext().getConfig()->showInvisibles()); - } - - std::string rawMemoryToString( const void *object, std::size_t size ) { - // Reverse order for little endian architectures - int i = 0, end = static_cast( size ), inc = 1; - if( Endianness::which() == Endianness::Little ) { - i = end-1; - end = inc = -1; - } - - unsigned char const *bytes = static_cast(object); - ReusableStringStream rss; - rss << "0x" << std::setfill('0') << std::hex; - for( ; i != end; i += inc ) - rss << std::setw(2) << static_cast(bytes[i]); - return rss.str(); - } -} // end Detail namespace - - - -//// ======================================================= //// -// -// Out-of-line defs for full specialization of StringMaker -// -//// ======================================================= //// - -std::string StringMaker::convert(const std::string& str) { - return Detail::convertIntoString( str ); -} - -#ifdef CATCH_CONFIG_CPP17_STRING_VIEW -std::string StringMaker::convert(std::string_view str) { - return Detail::convertIntoString( StringRef( str.data(), str.size() ) ); -} -#endif - -std::string StringMaker::convert(char const* str) { - if (str) { - return Detail::convertIntoString( str ); - } else { - return{ "{null string}" }; - } -} -std::string StringMaker::convert(char* str) { - if (str) { - return Detail::convertIntoString( str ); - } else { - return{ "{null string}" }; - } -} - -#ifdef CATCH_CONFIG_WCHAR -std::string StringMaker::convert(const std::wstring& wstr) { - std::string s; - s.reserve(wstr.size()); - for (auto c : wstr) { - s += (c <= 0xff) ? static_cast(c) : '?'; - } - return ::Catch::Detail::stringify(s); -} - -# ifdef CATCH_CONFIG_CPP17_STRING_VIEW -std::string StringMaker::convert(std::wstring_view str) { - return StringMaker::convert(std::wstring(str)); -} -# endif - -std::string StringMaker::convert(wchar_t const * str) { - if (str) { - return ::Catch::Detail::stringify(std::wstring{ str }); - } else { - return{ "{null string}" }; - } -} -std::string StringMaker::convert(wchar_t * str) { - if (str) { - return ::Catch::Detail::stringify(std::wstring{ str }); - } else { - return{ "{null string}" }; - } -} -#endif - -#if defined(CATCH_CONFIG_CPP17_BYTE) -#include -std::string StringMaker::convert(std::byte value) { - return ::Catch::Detail::stringify(std::to_integer(value)); -} -#endif // defined(CATCH_CONFIG_CPP17_BYTE) - -std::string StringMaker::convert(int value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(long value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(long long value) { - ReusableStringStream rss; - rss << value; - if (value > Detail::hexThreshold) { - rss << " (0x" << std::hex << value << ')'; - } - return rss.str(); -} - -std::string StringMaker::convert(unsigned int value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(unsigned long value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(unsigned long long value) { - ReusableStringStream rss; - rss << value; - if (value > Detail::hexThreshold) { - rss << " (0x" << std::hex << value << ')'; - } - return rss.str(); -} - -std::string StringMaker::convert(signed char value) { - if (value == '\r') { - return "'\\r'"; - } else if (value == '\f') { - return "'\\f'"; - } else if (value == '\n') { - return "'\\n'"; - } else if (value == '\t') { - return "'\\t'"; - } else if ('\0' <= value && value < ' ') { - return ::Catch::Detail::stringify(static_cast(value)); - } else { - char chstr[] = "' '"; - chstr[1] = value; - return chstr; - } -} -std::string StringMaker::convert(char c) { - return ::Catch::Detail::stringify(static_cast(c)); -} -std::string StringMaker::convert(unsigned char c) { - return ::Catch::Detail::stringify(static_cast(c)); -} - -int StringMaker::precision = 5; - -std::string StringMaker::convert(float value) { - return Detail::fpToString(value, precision) + 'f'; -} - -int StringMaker::precision = 10; - -std::string StringMaker::convert(double value) { - return Detail::fpToString(value, precision); -} - -} // end namespace Catch - - - -namespace Catch { - - Counts Counts::operator - ( Counts const& other ) const { - Counts diff; - diff.passed = passed - other.passed; - diff.failed = failed - other.failed; - diff.failedButOk = failedButOk - other.failedButOk; - diff.skipped = skipped - other.skipped; - return diff; - } - - Counts& Counts::operator += ( Counts const& other ) { - passed += other.passed; - failed += other.failed; - failedButOk += other.failedButOk; - skipped += other.skipped; - return *this; - } - - std::uint64_t Counts::total() const { - return passed + failed + failedButOk + skipped; - } - bool Counts::allPassed() const { - return failed == 0 && failedButOk == 0 && skipped == 0; - } - bool Counts::allOk() const { - return failed == 0; - } - - Totals Totals::operator - ( Totals const& other ) const { - Totals diff; - diff.assertions = assertions - other.assertions; - diff.testCases = testCases - other.testCases; - return diff; - } - - Totals& Totals::operator += ( Totals const& other ) { - assertions += other.assertions; - testCases += other.testCases; - return *this; - } - - Totals Totals::delta( Totals const& prevTotals ) const { - Totals diff = *this - prevTotals; - if( diff.assertions.failed > 0 ) - ++diff.testCases.failed; - else if( diff.assertions.failedButOk > 0 ) - ++diff.testCases.failedButOk; - else if ( diff.assertions.skipped > 0 ) - ++ diff.testCases.skipped; - else - ++diff.testCases.passed; - return diff; - } - -} - - -#include - -namespace Catch { - - Version::Version - ( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - char const * const _branchName, - unsigned int _buildNumber ) - : majorVersion( _majorVersion ), - minorVersion( _minorVersion ), - patchNumber( _patchNumber ), - branchName( _branchName ), - buildNumber( _buildNumber ) - {} - - std::ostream& operator << ( std::ostream& os, Version const& version ) { - os << version.majorVersion << '.' - << version.minorVersion << '.' - << version.patchNumber; - // branchName is never null -> 0th char is \0 if it is empty - if (version.branchName[0]) { - os << '-' << version.branchName - << '.' << version.buildNumber; - } - return os; - } - - Version const& libraryVersion() { - static Version version( 3, 3, 2, "", 0 ); - return version; - } - -} - - - - -namespace Catch { - - const char* GeneratorException::what() const noexcept { - return m_msg; - } - -} // end namespace Catch - - - - -namespace Catch { - - IGeneratorTracker::~IGeneratorTracker() = default; - -namespace Generators { - -namespace Detail { - - [[noreturn]] - void throw_generator_exception(char const* msg) { - Catch::throw_exception(GeneratorException{ msg }); - } -} // end namespace Detail - - GeneratorUntypedBase::~GeneratorUntypedBase() = default; - - IGeneratorTracker* acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) { - return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo ); - } - - IGeneratorTracker* createGeneratorTracker( StringRef generatorName, - SourceLineInfo lineInfo, - GeneratorBasePtr&& generator ) { - return getResultCapture().createGeneratorTracker( - generatorName, lineInfo, CATCH_MOVE( generator ) ); - } - -} // namespace Generators -} // namespace Catch - - - - - -std::uint32_t Catch::Generators::Detail::getSeed() { return sharedRng()(); } - - - - -namespace Catch { - IResultCapture::~IResultCapture() = default; -} - - - - -namespace Catch { - IConfig::~IConfig() = default; -} - - - - -namespace Catch { - IExceptionTranslator::~IExceptionTranslator() = default; - IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; -} - - - -#include - -namespace Catch { - namespace Generators { - - bool GeneratorUntypedBase::countedNext() { - auto ret = next(); - if ( ret ) { - m_stringReprCache.clear(); - ++m_currentElementIndex; - } - return ret; - } - - StringRef GeneratorUntypedBase::currentElementAsString() const { - if ( m_stringReprCache.empty() ) { - m_stringReprCache = stringifyImpl(); - } - return m_stringReprCache; - } - - } // namespace Generators -} // namespace Catch - - - - -namespace Catch { - IRegistryHub::~IRegistryHub() = default; - IMutableRegistryHub::~IMutableRegistryHub() = default; -} - - - -#include -#include -#include - -namespace Catch { - - ReporterConfig::ReporterConfig( - IConfig const* _fullConfig, - Detail::unique_ptr _stream, - ColourMode colourMode, - std::map customOptions ): - m_stream( CATCH_MOVE(_stream) ), - m_fullConfig( _fullConfig ), - m_colourMode( colourMode ), - m_customOptions( CATCH_MOVE( customOptions ) ) {} - - Detail::unique_ptr ReporterConfig::takeStream() && { - assert( m_stream ); - return CATCH_MOVE( m_stream ); - } - IConfig const * ReporterConfig::fullConfig() const { return m_fullConfig; } - ColourMode ReporterConfig::colourMode() const { return m_colourMode; } - - std::map const& - ReporterConfig::customOptions() const { - return m_customOptions; - } - - ReporterConfig::~ReporterConfig() = default; - - AssertionStats::AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ) - : assertionResult( _assertionResult ), - infoMessages( _infoMessages ), - totals( _totals ) - { - assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; - - if( assertionResult.hasMessage() ) { - // Copy message into messages list. - // !TBD This should have been done earlier, somewhere - MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); - builder.m_info.message = static_cast(assertionResult.getMessage()); - - infoMessages.push_back( CATCH_MOVE(builder.m_info) ); - } - } - - SectionStats::SectionStats( SectionInfo&& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ) - : sectionInfo( CATCH_MOVE(_sectionInfo) ), - assertions( _assertions ), - durationInSeconds( _durationInSeconds ), - missingAssertions( _missingAssertions ) - {} - - - TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string&& _stdOut, - std::string&& _stdErr, - bool _aborting ) - : testInfo( &_testInfo ), - totals( _totals ), - stdOut( CATCH_MOVE(_stdOut) ), - stdErr( CATCH_MOVE(_stdErr) ), - aborting( _aborting ) - {} - - - TestRunStats::TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ) - : runInfo( _runInfo ), - totals( _totals ), - aborting( _aborting ) - {} - - IEventListener::~IEventListener() = default; - -} // end namespace Catch - - - - -namespace Catch { - IReporterFactory::~IReporterFactory() = default; - EventListenerFactory::~EventListenerFactory() = default; -} - - - - -namespace Catch { - IReporterRegistry::~IReporterRegistry() = default; -} - - - - -namespace Catch { - ITestInvoker::~ITestInvoker() = default; - ITestCaseRegistry::~ITestCaseRegistry() = default; -} - - - -namespace Catch { - - AssertionHandler::AssertionHandler - ( StringRef macroName, - SourceLineInfo const& lineInfo, - StringRef capturedExpression, - ResultDisposition::Flags resultDisposition ) - : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, - m_resultCapture( getResultCapture() ) - {} - - void AssertionHandler::handleExpr( ITransientExpression const& expr ) { - m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); - } - void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef message) { - m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); - } - - auto AssertionHandler::allowThrows() const -> bool { - return getCurrentContext().getConfig()->allowThrows(); - } - - void AssertionHandler::complete() { - setCompleted(); - if( m_reaction.shouldDebugBreak ) { - - // If you find your debugger stopping you here then go one level up on the - // call-stack for the code that caused it (typically a failed assertion) - - // (To go back to the test and change execution, jump over the throw, next) - CATCH_BREAK_INTO_DEBUGGER(); - } - if (m_reaction.shouldThrow) { - throw_test_failure_exception(); - } - if ( m_reaction.shouldSkip ) { -#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) - throw Catch::TestSkipException(); -#else - CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" ); -#endif - } - } - void AssertionHandler::setCompleted() { - m_completed = true; - } - - void AssertionHandler::handleUnexpectedInflightException() { - m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); - } - - void AssertionHandler::handleExceptionThrownAsExpected() { - m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); - } - void AssertionHandler::handleExceptionNotThrownAsExpected() { - m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); - } - - void AssertionHandler::handleUnexpectedExceptionNotThrown() { - m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); - } - - void AssertionHandler::handleThrowingCallSkipped() { - m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); - } - - // This is the overload that takes a string and infers the Equals matcher from it - // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp - void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str ) { - handleExceptionMatchExpr( handler, Matchers::Equals( str ) ); - } - -} // namespace Catch - - - - -#include - -namespace Catch { - namespace Detail { - - bool CaseInsensitiveLess::operator()( StringRef lhs, - StringRef rhs ) const { - return std::lexicographical_compare( - lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - []( char l, char r ) { return toLower( l ) < toLower( r ); } ); - } - - bool - CaseInsensitiveEqualTo::operator()( StringRef lhs, - StringRef rhs ) const { - return std::equal( - lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - []( char l, char r ) { return toLower( l ) == toLower( r ); } ); - } - - } // namespace Detail -} // namespace Catch - - - - -#include -#include - -namespace { - bool isOptPrefix( char c ) { - return c == '-' -#ifdef CATCH_PLATFORM_WINDOWS - || c == '/' -#endif - ; - } - - std::string normaliseOpt( std::string const& optName ) { -#ifdef CATCH_PLATFORM_WINDOWS - if ( optName[0] == '/' ) - return "-" + optName.substr( 1 ); - else -#endif - return optName; - } - -} // namespace - -namespace Catch { - namespace Clara { - namespace Detail { - - void TokenStream::loadBuffer() { - m_tokenBuffer.clear(); - - // Skip any empty strings - while ( it != itEnd && it->empty() ) { - ++it; - } - - if ( it != itEnd ) { - auto const& next = *it; - if ( isOptPrefix( next[0] ) ) { - auto delimiterPos = next.find_first_of( " :=" ); - if ( delimiterPos != std::string::npos ) { - m_tokenBuffer.push_back( - { TokenType::Option, - next.substr( 0, delimiterPos ) } ); - m_tokenBuffer.push_back( - { TokenType::Argument, - next.substr( delimiterPos + 1 ) } ); - } else { - if ( next[1] != '-' && next.size() > 2 ) { - std::string opt = "- "; - for ( size_t i = 1; i < next.size(); ++i ) { - opt[1] = next[i]; - m_tokenBuffer.push_back( - { TokenType::Option, opt } ); - } - } else { - m_tokenBuffer.push_back( - { TokenType::Option, next } ); - } - } - } else { - m_tokenBuffer.push_back( - { TokenType::Argument, next } ); - } - } - } - - TokenStream::TokenStream( Args const& args ): - TokenStream( args.m_args.begin(), args.m_args.end() ) {} - - TokenStream::TokenStream( Iterator it_, Iterator itEnd_ ): - it( it_ ), itEnd( itEnd_ ) { - loadBuffer(); - } - - TokenStream& TokenStream::operator++() { - if ( m_tokenBuffer.size() >= 2 ) { - m_tokenBuffer.erase( m_tokenBuffer.begin() ); - } else { - if ( it != itEnd ) - ++it; - loadBuffer(); - } - return *this; - } - - ParserResult convertInto( std::string const& source, - std::string& target ) { - target = source; - return ParserResult::ok( ParseResultType::Matched ); - } - - ParserResult convertInto( std::string const& source, - bool& target ) { - std::string srcLC = toLower( source ); - - if ( srcLC == "y" || srcLC == "1" || srcLC == "true" || - srcLC == "yes" || srcLC == "on" ) { - target = true; - } else if ( srcLC == "n" || srcLC == "0" || srcLC == "false" || - srcLC == "no" || srcLC == "off" ) { - target = false; - } else { - return ParserResult::runtimeError( - "Expected a boolean value but did not recognise: '" + - source + '\'' ); - } - return ParserResult::ok( ParseResultType::Matched ); - } - - size_t ParserBase::cardinality() const { return 1; } - - InternalParseResult ParserBase::parse( Args const& args ) const { - return parse( args.exeName(), TokenStream( args ) ); - } - - ParseState::ParseState( ParseResultType type, - TokenStream const& remainingTokens ): - m_type( type ), m_remainingTokens( remainingTokens ) {} - - ParserResult BoundFlagRef::setFlag( bool flag ) { - m_ref = flag; - return ParserResult::ok( ParseResultType::Matched ); - } - - ResultBase::~ResultBase() = default; - - bool BoundRef::isContainer() const { return false; } - - bool BoundRef::isFlag() const { return false; } - - bool BoundFlagRefBase::isFlag() const { return true; } - -} // namespace Detail - - Detail::InternalParseResult Arg::parse(std::string const&, - Detail::TokenStream const& tokens) const { - auto validationResult = validate(); - if (!validationResult) - return Detail::InternalParseResult(validationResult); - - auto remainingTokens = tokens; - auto const& token = *remainingTokens; - if (token.type != Detail::TokenType::Argument) - return Detail::InternalParseResult::ok(Detail::ParseState( - ParseResultType::NoMatch, remainingTokens)); - - assert(!m_ref->isFlag()); - auto valueRef = - static_cast(m_ref.get()); - - auto result = valueRef->setValue(remainingTokens->token); - if (!result) - return Detail::InternalParseResult(result); - else - return Detail::InternalParseResult::ok(Detail::ParseState( - ParseResultType::Matched, ++remainingTokens)); - } - - Opt::Opt(bool& ref) : - ParserRefImpl(std::make_shared(ref)) {} - - std::vector Opt::getHelpColumns() const { - std::ostringstream oss; - bool first = true; - for (auto const& opt : m_optNames) { - if (first) - first = false; - else - oss << ", "; - oss << opt; - } - if (!m_hint.empty()) - oss << " <" << m_hint << '>'; - return { { oss.str(), m_description } }; - } - - bool Opt::isMatch(std::string const& optToken) const { - auto normalisedToken = normaliseOpt(optToken); - for (auto const& name : m_optNames) { - if (normaliseOpt(name) == normalisedToken) - return true; - } - return false; - } - - Detail::InternalParseResult Opt::parse(std::string const&, - Detail::TokenStream const& tokens) const { - auto validationResult = validate(); - if (!validationResult) - return Detail::InternalParseResult(validationResult); - - auto remainingTokens = tokens; - if (remainingTokens && - remainingTokens->type == Detail::TokenType::Option) { - auto const& token = *remainingTokens; - if (isMatch(token.token)) { - if (m_ref->isFlag()) { - auto flagRef = - static_cast( - m_ref.get()); - auto result = flagRef->setFlag(true); - if (!result) - return Detail::InternalParseResult(result); - if (result.value() == - ParseResultType::ShortCircuitAll) - return Detail::InternalParseResult::ok(Detail::ParseState( - result.value(), remainingTokens)); - } else { - auto valueRef = - static_cast( - m_ref.get()); - ++remainingTokens; - if (!remainingTokens) - return Detail::InternalParseResult::runtimeError( - "Expected argument following " + - token.token); - auto const& argToken = *remainingTokens; - if (argToken.type != Detail::TokenType::Argument) - return Detail::InternalParseResult::runtimeError( - "Expected argument following " + - token.token); - const auto result = valueRef->setValue(argToken.token); - if (!result) - return Detail::InternalParseResult(result); - if (result.value() == - ParseResultType::ShortCircuitAll) - return Detail::InternalParseResult::ok(Detail::ParseState( - result.value(), remainingTokens)); - } - return Detail::InternalParseResult::ok(Detail::ParseState( - ParseResultType::Matched, ++remainingTokens)); - } - } - return Detail::InternalParseResult::ok( - Detail::ParseState(ParseResultType::NoMatch, remainingTokens)); - } - - Detail::Result Opt::validate() const { - if (m_optNames.empty()) - return Detail::Result::logicError("No options supplied to Opt"); - for (auto const& name : m_optNames) { - if (name.empty()) - return Detail::Result::logicError( - "Option name cannot be empty"); -#ifdef CATCH_PLATFORM_WINDOWS - if (name[0] != '-' && name[0] != '/') - return Detail::Result::logicError( - "Option name must begin with '-' or '/'"); -#else - if (name[0] != '-') - return Detail::Result::logicError( - "Option name must begin with '-'"); -#endif - } - return ParserRefImpl::validate(); - } - - ExeName::ExeName() : - m_name(std::make_shared("")) {} - - ExeName::ExeName(std::string& ref) : ExeName() { - m_ref = std::make_shared>(ref); - } - - Detail::InternalParseResult - ExeName::parse(std::string const&, - Detail::TokenStream const& tokens) const { - return Detail::InternalParseResult::ok( - Detail::ParseState(ParseResultType::NoMatch, tokens)); - } - - ParserResult ExeName::set(std::string const& newName) { - auto lastSlash = newName.find_last_of("\\/"); - auto filename = (lastSlash == std::string::npos) - ? newName - : newName.substr(lastSlash + 1); - - *m_name = filename; - if (m_ref) - return m_ref->setValue(filename); - else - return ParserResult::ok(ParseResultType::Matched); - } - - - - - Parser& Parser::operator|=( Parser const& other ) { - m_options.insert( m_options.end(), - other.m_options.begin(), - other.m_options.end() ); - m_args.insert( - m_args.end(), other.m_args.begin(), other.m_args.end() ); - return *this; - } - - std::vector Parser::getHelpColumns() const { - std::vector cols; - for ( auto const& o : m_options ) { - auto childCols = o.getHelpColumns(); - cols.insert( cols.end(), childCols.begin(), childCols.end() ); - } - return cols; - } - - void Parser::writeToStream( std::ostream& os ) const { - if ( !m_exeName.name().empty() ) { - os << "usage:\n" - << " " << m_exeName.name() << ' '; - bool required = true, first = true; - for ( auto const& arg : m_args ) { - if ( first ) - first = false; - else - os << ' '; - if ( arg.isOptional() && required ) { - os << '['; - required = false; - } - os << '<' << arg.hint() << '>'; - if ( arg.cardinality() == 0 ) - os << " ... "; - } - if ( !required ) - os << ']'; - if ( !m_options.empty() ) - os << " options"; - os << "\n\nwhere options are:\n"; - } - - auto rows = getHelpColumns(); - size_t consoleWidth = CATCH_CONFIG_CONSOLE_WIDTH; - size_t optWidth = 0; - for ( auto const& cols : rows ) - optWidth = ( std::max )( optWidth, cols.left.size() + 2 ); - - optWidth = ( std::min )( optWidth, consoleWidth / 2 ); - - for ( auto const& cols : rows ) { - auto row = TextFlow::Column( cols.left ) - .width( optWidth ) - .indent( 2 ) + - TextFlow::Spacer( 4 ) + - TextFlow::Column( cols.right ) - .width( consoleWidth - 7 - optWidth ); - os << row << '\n'; - } - } - - Detail::Result Parser::validate() const { - for ( auto const& opt : m_options ) { - auto result = opt.validate(); - if ( !result ) - return result; - } - for ( auto const& arg : m_args ) { - auto result = arg.validate(); - if ( !result ) - return result; - } - return Detail::Result::ok(); - } - - Detail::InternalParseResult - Parser::parse( std::string const& exeName, - Detail::TokenStream const& tokens ) const { - - struct ParserInfo { - ParserBase const* parser = nullptr; - size_t count = 0; - }; - std::vector parseInfos; - parseInfos.reserve( m_options.size() + m_args.size() ); - for ( auto const& opt : m_options ) { - parseInfos.push_back( { &opt, 0 } ); - } - for ( auto const& arg : m_args ) { - parseInfos.push_back( { &arg, 0 } ); - } - - m_exeName.set( exeName ); - - auto result = Detail::InternalParseResult::ok( - Detail::ParseState( ParseResultType::NoMatch, tokens ) ); - while ( result.value().remainingTokens() ) { - bool tokenParsed = false; - - for ( auto& parseInfo : parseInfos ) { - if ( parseInfo.parser->cardinality() == 0 || - parseInfo.count < parseInfo.parser->cardinality() ) { - result = parseInfo.parser->parse( - exeName, result.value().remainingTokens() ); - if ( !result ) - return result; - if ( result.value().type() != - ParseResultType::NoMatch ) { - tokenParsed = true; - ++parseInfo.count; - break; - } - } - } - - if ( result.value().type() == ParseResultType::ShortCircuitAll ) - return result; - if ( !tokenParsed ) - return Detail::InternalParseResult::runtimeError( - "Unrecognised token: " + - result.value().remainingTokens()->token ); - } - // !TBD Check missing required options - return result; - } - - Args::Args(int argc, char const* const* argv) : - m_exeName(argv[0]), m_args(argv + 1, argv + argc) {} - - Args::Args(std::initializer_list args) : - m_exeName(*args.begin()), - m_args(args.begin() + 1, args.end()) {} - - - Help::Help( bool& showHelpFlag ): - Opt( [&]( bool flag ) { - showHelpFlag = flag; - return ParserResult::ok( ParseResultType::ShortCircuitAll ); - } ) { - static_cast ( *this )( - "display usage information" )["-?"]["-h"]["--help"] - .optional(); - } - - } // namespace Clara -} // namespace Catch - - - - -#include -#include - -namespace Catch { - - Clara::Parser makeCommandLineParser( ConfigData& config ) { - - using namespace Clara; - - auto const setWarning = [&]( std::string const& warning ) { - if ( warning == "NoAssertions" ) { - config.warnings = static_cast(config.warnings | WarnAbout::NoAssertions); - return ParserResult::ok( ParseResultType::Matched ); - } else if ( warning == "UnmatchedTestSpec" ) { - config.warnings = static_cast(config.warnings | WarnAbout::UnmatchedTestSpec); - return ParserResult::ok( ParseResultType::Matched ); - } - - return ParserResult ::runtimeError( - "Unrecognised warning option: '" + warning + '\'' ); - }; - auto const loadTestNamesFromFile = [&]( std::string const& filename ) { - std::ifstream f( filename.c_str() ); - if( !f.is_open() ) - return ParserResult::runtimeError( "Unable to load input file: '" + filename + '\'' ); - - std::string line; - while( std::getline( f, line ) ) { - line = trim(line); - if( !line.empty() && !startsWith( line, '#' ) ) { - if( !startsWith( line, '"' ) ) - line = '"' + line + '"'; - config.testsOrTags.push_back( line ); - config.testsOrTags.emplace_back( "," ); - } - } - //Remove comma in the end - if(!config.testsOrTags.empty()) - config.testsOrTags.erase( config.testsOrTags.end()-1 ); - - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setTestOrder = [&]( std::string const& order ) { - if( startsWith( "declared", order ) ) - config.runOrder = TestRunOrder::Declared; - else if( startsWith( "lexical", order ) ) - config.runOrder = TestRunOrder::LexicographicallySorted; - else if( startsWith( "random", order ) ) - config.runOrder = TestRunOrder::Randomized; - else - return ParserResult::runtimeError( "Unrecognised ordering: '" + order + '\'' ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setRngSeed = [&]( std::string const& seed ) { - if( seed == "time" ) { - config.rngSeed = generateRandomSeed(GenerateFrom::Time); - return ParserResult::ok(ParseResultType::Matched); - } else if (seed == "random-device") { - config.rngSeed = generateRandomSeed(GenerateFrom::RandomDevice); - return ParserResult::ok(ParseResultType::Matched); - } - - // TODO: ideally we should be parsing uint32_t directly - // fix this later when we add new parse overload - auto parsedSeed = parseUInt( seed, 0 ); - if ( !parsedSeed ) { - return ParserResult::runtimeError( "Could not parse '" + seed + "' as seed" ); - } - config.rngSeed = *parsedSeed; - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setDefaultColourMode = [&]( std::string const& colourMode ) { - Optional maybeMode = Catch::Detail::stringToColourMode(toLower( colourMode )); - if ( !maybeMode ) { - return ParserResult::runtimeError( - "colour mode must be one of: default, ansi, win32, " - "or none. '" + - colourMode + "' is not recognised" ); - } - auto mode = *maybeMode; - if ( !isColourImplAvailable( mode ) ) { - return ParserResult::runtimeError( - "colour mode '" + colourMode + - "' is not supported in this binary" ); - } - config.defaultColourMode = mode; - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setWaitForKeypress = [&]( std::string const& keypress ) { - auto keypressLc = toLower( keypress ); - if (keypressLc == "never") - config.waitForKeypress = WaitForKeypress::Never; - else if( keypressLc == "start" ) - config.waitForKeypress = WaitForKeypress::BeforeStart; - else if( keypressLc == "exit" ) - config.waitForKeypress = WaitForKeypress::BeforeExit; - else if( keypressLc == "both" ) - config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; - else - return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setVerbosity = [&]( std::string const& verbosity ) { - auto lcVerbosity = toLower( verbosity ); - if( lcVerbosity == "quiet" ) - config.verbosity = Verbosity::Quiet; - else if( lcVerbosity == "normal" ) - config.verbosity = Verbosity::Normal; - else if( lcVerbosity == "high" ) - config.verbosity = Verbosity::High; - else - return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + '\'' ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setReporter = [&]( std::string const& userReporterSpec ) { - if ( userReporterSpec.empty() ) { - return ParserResult::runtimeError( "Received empty reporter spec." ); - } - - Optional parsed = - parseReporterSpec( userReporterSpec ); - if ( !parsed ) { - return ParserResult::runtimeError( - "Could not parse reporter spec '" + userReporterSpec + - "'" ); - } - - auto const& reporterSpec = *parsed; - - IReporterRegistry::FactoryMap const& factories = - getRegistryHub().getReporterRegistry().getFactories(); - auto result = factories.find( reporterSpec.name() ); - - if ( result == factories.end() ) { - return ParserResult::runtimeError( - "Unrecognized reporter, '" + reporterSpec.name() + - "'. Check available with --list-reporters" ); - } - - - const bool hadOutputFile = reporterSpec.outputFile().some(); - config.reporterSpecifications.push_back( CATCH_MOVE( *parsed ) ); - // It would be enough to check this only once at the very end, but - // there is not a place where we could call this check, so do it - // every time it could fail. For valid inputs, this is still called - // at most once. - if (!hadOutputFile) { - int n_reporters_without_file = 0; - for (auto const& spec : config.reporterSpecifications) { - if (spec.outputFile().none()) { - n_reporters_without_file++; - } - } - if (n_reporters_without_file > 1) { - return ParserResult::runtimeError( "Only one reporter may have unspecified output file." ); - } - } - - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setShardCount = [&]( std::string const& shardCount ) { - auto parsedCount = parseUInt( shardCount ); - if ( !parsedCount ) { - return ParserResult::runtimeError( - "Could not parse '" + shardCount + "' as shard count" ); - } - if ( *parsedCount == 0 ) { - return ParserResult::runtimeError( - "Shard count must be positive" ); - } - config.shardCount = *parsedCount; - return ParserResult::ok( ParseResultType::Matched ); - }; - - auto const setShardIndex = [&](std::string const& shardIndex) { - auto parsedIndex = parseUInt( shardIndex ); - if ( !parsedIndex ) { - return ParserResult::runtimeError( - "Could not parse '" + shardIndex + "' as shard index" ); - } - config.shardIndex = *parsedIndex; - return ParserResult::ok( ParseResultType::Matched ); - }; - - auto cli - = ExeName( config.processName ) - | Help( config.showHelp ) - | Opt( config.showSuccessfulTests ) - ["-s"]["--success"] - ( "include successful tests in output" ) - | Opt( config.shouldDebugBreak ) - ["-b"]["--break"] - ( "break into debugger on failure" ) - | Opt( config.noThrow ) - ["-e"]["--nothrow"] - ( "skip exception tests" ) - | Opt( config.showInvisibles ) - ["-i"]["--invisibles"] - ( "show invisibles (tabs, newlines)" ) - | Opt( config.defaultOutputFilename, "filename" ) - ["-o"]["--out"] - ( "default output filename" ) - | Opt( accept_many, setReporter, "name[::key=value]*" ) - ["-r"]["--reporter"] - ( "reporter to use (defaults to console)" ) - | Opt( config.name, "name" ) - ["-n"]["--name"] - ( "suite name" ) - | Opt( [&]( bool ){ config.abortAfter = 1; } ) - ["-a"]["--abort"] - ( "abort at first failure" ) - | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) - ["-x"]["--abortx"] - ( "abort after x failures" ) - | Opt( accept_many, setWarning, "warning name" ) - ["-w"]["--warn"] - ( "enable warnings" ) - | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) - ["-d"]["--durations"] - ( "show test durations" ) - | Opt( config.minDuration, "seconds" ) - ["-D"]["--min-duration"] - ( "show test durations for tests taking at least the given number of seconds" ) - | Opt( loadTestNamesFromFile, "filename" ) - ["-f"]["--input-file"] - ( "load test names to run from a file" ) - | Opt( config.filenamesAsTags ) - ["-#"]["--filenames-as-tags"] - ( "adds a tag for the filename" ) - | Opt( config.sectionsToRun, "section name" ) - ["-c"]["--section"] - ( "specify section to run" ) - | Opt( setVerbosity, "quiet|normal|high" ) - ["-v"]["--verbosity"] - ( "set output verbosity" ) - | Opt( config.listTests ) - ["--list-tests"] - ( "list all/matching test cases" ) - | Opt( config.listTags ) - ["--list-tags"] - ( "list all/matching tags" ) - | Opt( config.listReporters ) - ["--list-reporters"] - ( "list all available reporters" ) - | Opt( config.listListeners ) - ["--list-listeners"] - ( "list all listeners" ) - | Opt( setTestOrder, "decl|lex|rand" ) - ["--order"] - ( "test case order (defaults to decl)" ) - | Opt( setRngSeed, "'time'|'random-device'|number" ) - ["--rng-seed"] - ( "set a specific seed for random numbers" ) - | Opt( setDefaultColourMode, "ansi|win32|none|default" ) - ["--colour-mode"] - ( "what color mode should be used as default" ) - | Opt( config.libIdentify ) - ["--libidentify"] - ( "report name and version according to libidentify standard" ) - | Opt( setWaitForKeypress, "never|start|exit|both" ) - ["--wait-for-keypress"] - ( "waits for a keypress before exiting" ) - | Opt( config.skipBenchmarks) - ["--skip-benchmarks"] - ( "disable running benchmarks") - | Opt( config.benchmarkSamples, "samples" ) - ["--benchmark-samples"] - ( "number of samples to collect (default: 100)" ) - | Opt( config.benchmarkResamples, "resamples" ) - ["--benchmark-resamples"] - ( "number of resamples for the bootstrap (default: 100000)" ) - | Opt( config.benchmarkConfidenceInterval, "confidence interval" ) - ["--benchmark-confidence-interval"] - ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" ) - | Opt( config.benchmarkNoAnalysis ) - ["--benchmark-no-analysis"] - ( "perform only measurements; do not perform any analysis" ) - | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" ) - ["--benchmark-warmup-time"] - ( "amount of time in milliseconds spent on warming up each test (default: 100)" ) - | Opt( setShardCount, "shard count" ) - ["--shard-count"] - ( "split the tests to execute into this many groups" ) - | Opt( setShardIndex, "shard index" ) - ["--shard-index"] - ( "index of the group of tests to execute (see --shard-count)" ) | - Opt( config.allowZeroTests ) - ["--allow-running-no-tests"] - ( "Treat 'No tests run' as a success" ) - | Arg( config.testsOrTags, "test name|pattern|tags" ) - ( "which test or tests to use" ); - - return cli; - } - -} // end namespace Catch - - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - - - -#include -#include -#include - -namespace Catch { - - ColourImpl::~ColourImpl() = default; - - ColourImpl::ColourGuard ColourImpl::guardColour( Colour::Code colourCode ) { - return ColourGuard(colourCode, this ); - } - - void ColourImpl::ColourGuard::engageImpl( std::ostream& stream ) { - assert( &stream == &m_colourImpl->m_stream->stream() && - "Engaging colour guard for different stream than used by the " - "parent colour implementation" ); - static_cast( stream ); - - m_engaged = true; - m_colourImpl->use( m_code ); - } - - ColourImpl::ColourGuard::ColourGuard( Colour::Code code, - ColourImpl const* colour ): - m_colourImpl( colour ), m_code( code ) { - } - ColourImpl::ColourGuard::ColourGuard( ColourGuard&& rhs ) noexcept: - m_colourImpl( rhs.m_colourImpl ), - m_code( rhs.m_code ), - m_engaged( rhs.m_engaged ) { - rhs.m_engaged = false; - } - ColourImpl::ColourGuard& - ColourImpl::ColourGuard::operator=( ColourGuard&& rhs ) noexcept { - using std::swap; - swap( m_colourImpl, rhs.m_colourImpl ); - swap( m_code, rhs.m_code ); - swap( m_engaged, rhs.m_engaged ); - - return *this; - } - ColourImpl::ColourGuard::~ColourGuard() { - if ( m_engaged ) { - m_colourImpl->use( Colour::None ); - } - } - - ColourImpl::ColourGuard& - ColourImpl::ColourGuard::engage( std::ostream& stream ) & { - engageImpl( stream ); - return *this; - } - - ColourImpl::ColourGuard&& - ColourImpl::ColourGuard::engage( std::ostream& stream ) && { - engageImpl( stream ); - return CATCH_MOVE(*this); - } - - namespace { - //! A do-nothing implementation of colour, used as fallback for unknown - //! platforms, and when the user asks to deactivate all colours. - class NoColourImpl : public ColourImpl { - public: - NoColourImpl( IStream* stream ): ColourImpl( stream ) {} - - private: - void use( Colour::Code ) const override {} - }; - } // namespace - - -} // namespace Catch - - -#if defined ( CATCH_CONFIG_COLOUR_WIN32 ) ///////////////////////////////////////// - -namespace Catch { -namespace { - - class Win32ColourImpl : public ColourImpl { - public: - Win32ColourImpl(IStream* stream): - ColourImpl(stream) { - CONSOLE_SCREEN_BUFFER_INFO csbiInfo; - GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), - &csbiInfo ); - originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); - originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); - } - - static bool useImplementationForStream(IStream const& stream) { - // Win32 text colour APIs can only be used on console streams - // We cannot check that the output hasn't been redirected, - // so we just check that the original stream is console stream. - return stream.isConsole(); - } - - private: - void use( Colour::Code _colourCode ) const override { - switch( _colourCode ) { - case Colour::None: return setTextAttribute( originalForegroundAttributes ); - case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); - case Colour::Red: return setTextAttribute( FOREGROUND_RED ); - case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); - case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); - case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); - case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); - case Colour::Grey: return setTextAttribute( 0 ); - - case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); - case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); - case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); - case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); - case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); - - case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); - - default: - CATCH_ERROR( "Unknown colour requested" ); - } - } - - void setTextAttribute( WORD _textAttribute ) const { - SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ), - _textAttribute | - originalBackgroundAttributes ); - } - WORD originalForegroundAttributes; - WORD originalBackgroundAttributes; - }; - -} // end anon namespace -} // end namespace Catch - -#endif // Windows/ ANSI/ None - - -#if defined( CATCH_PLATFORM_LINUX ) || defined( CATCH_PLATFORM_MAC ) -# define CATCH_INTERNAL_HAS_ISATTY -# include -#endif - -namespace Catch { -namespace { - - class ANSIColourImpl : public ColourImpl { - public: - ANSIColourImpl( IStream* stream ): ColourImpl( stream ) {} - - static bool useImplementationForStream(IStream const& stream) { - // This is kinda messy due to trying to support a bunch of - // different platforms at once. - // The basic idea is that if we are asked to do autodetection (as - // opposed to being told to use posixy colours outright), then we - // only want to use the colours if we are writing to console. - // However, console might be redirected, so we make an attempt at - // checking for that on platforms where we know how to do that. - bool useColour = stream.isConsole(); -#if defined( CATCH_INTERNAL_HAS_ISATTY ) && \ - !( defined( __DJGPP__ ) && defined( __STRICT_ANSI__ ) ) - ErrnoGuard _; // for isatty - useColour = useColour && isatty( STDOUT_FILENO ); -# endif -# if defined( CATCH_PLATFORM_MAC ) || defined( CATCH_PLATFORM_IPHONE ) - useColour = useColour && !isDebuggerActive(); -# endif - - return useColour; - } - - private: - void use( Colour::Code _colourCode ) const override { - auto setColour = [&out = - m_stream->stream()]( char const* escapeCode ) { - // The escape sequence must be flushed to console, otherwise - // if stdin and stderr are intermixed, we'd get accidentally - // coloured output. - out << '\033' << escapeCode << std::flush; - }; - switch( _colourCode ) { - case Colour::None: - case Colour::White: return setColour( "[0m" ); - case Colour::Red: return setColour( "[0;31m" ); - case Colour::Green: return setColour( "[0;32m" ); - case Colour::Blue: return setColour( "[0;34m" ); - case Colour::Cyan: return setColour( "[0;36m" ); - case Colour::Yellow: return setColour( "[0;33m" ); - case Colour::Grey: return setColour( "[1;30m" ); - - case Colour::LightGrey: return setColour( "[0;37m" ); - case Colour::BrightRed: return setColour( "[1;31m" ); - case Colour::BrightGreen: return setColour( "[1;32m" ); - case Colour::BrightWhite: return setColour( "[1;37m" ); - case Colour::BrightYellow: return setColour( "[1;33m" ); - - case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); - default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); - } - } - }; - -} // end anon namespace -} // end namespace Catch - -namespace Catch { - - Detail::unique_ptr makeColourImpl( ColourMode implSelection, - IStream* stream ) { -#if defined( CATCH_CONFIG_COLOUR_WIN32 ) - if ( implSelection == ColourMode::Win32 ) { - return Detail::make_unique( stream ); - } -#endif - if ( implSelection == ColourMode::ANSI ) { - return Detail::make_unique( stream ); - } - if ( implSelection == ColourMode::None ) { - return Detail::make_unique( stream ); - } - - if ( implSelection == ColourMode::PlatformDefault) { -#if defined( CATCH_CONFIG_COLOUR_WIN32 ) - if ( Win32ColourImpl::useImplementationForStream( *stream ) ) { - return Detail::make_unique( stream ); - } -#endif - if ( ANSIColourImpl::useImplementationForStream( *stream ) ) { - return Detail::make_unique( stream ); - } - return Detail::make_unique( stream ); - } - - CATCH_ERROR( "Could not create colour impl for selection " << static_cast(implSelection) ); - } - - bool isColourImplAvailable( ColourMode colourSelection ) { - switch ( colourSelection ) { -#if defined( CATCH_CONFIG_COLOUR_WIN32 ) - case ColourMode::Win32: -#endif - case ColourMode::ANSI: - case ColourMode::None: - case ColourMode::PlatformDefault: - return true; - default: - return false; - } - } - - -} // end namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - - - - -namespace Catch { - - class Context : public IMutableContext, private Detail::NonCopyable { - - public: // IContext - IResultCapture* getResultCapture() override { - return m_resultCapture; - } - - IConfig const* getConfig() const override { - return m_config; - } - - ~Context() override; - - public: // IMutableContext - void setResultCapture( IResultCapture* resultCapture ) override { - m_resultCapture = resultCapture; - } - void setConfig( IConfig const* config ) override { - m_config = config; - } - - friend IMutableContext& getCurrentMutableContext(); - - private: - IConfig const* m_config = nullptr; - IResultCapture* m_resultCapture = nullptr; - }; - - IMutableContext *IMutableContext::currentContext = nullptr; - - void IMutableContext::createContext() - { - currentContext = new Context(); - } - - void cleanUpContext() { - delete IMutableContext::currentContext; - IMutableContext::currentContext = nullptr; - } - IContext::~IContext() = default; - IMutableContext::~IMutableContext() = default; - Context::~Context() = default; - - - SimplePcg32& sharedRng() { - static SimplePcg32 s_rng; - return s_rng; - } - -} - - - - - -#include - -#if defined(CATCH_CONFIG_ANDROID_LOGWRITE) -#include - - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() ); - } - } - -#elif defined(CATCH_PLATFORM_WINDOWS) - - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - ::OutputDebugStringA( text.c_str() ); - } - } - -#else - - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - // !TBD: Need a version for Mac/ XCode and other IDEs - Catch::cout() << text; - } - } - -#endif // Platform - - - -#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) - -# include -# include -# include -# include -# include - -#ifdef __apple_build_version__ - // These headers will only compile with AppleClang (XCode) - // For other compilers (Clang, GCC, ... ) we need to exclude them -# include -#endif - - namespace Catch { - #ifdef __apple_build_version__ - // 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]; - struct kinfo_proc info; - std::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, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { - Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n\n" << std::flush; - return false; - } - - // We're being debugged if the P_TRACED flag is set. - - return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); - } - #else - bool isDebuggerActive() { - // We need to find another way to determine this for non-appleclang compilers on macOS - return false; - } - #endif - } // namespace Catch - -#elif defined(CATCH_PLATFORM_LINUX) - #include - #include - - namespace Catch{ - // The standard POSIX way of detecting a debugger is to attempt to - // ptrace() the process, but this needs to be done from a child and not - // this process itself to still allow attaching to this process later - // if wanted, so is rather heavy. Under Linux we have the PID of the - // "debugger" (which doesn't need to be gdb, of course, it could also - // be strace, for example) in /proc/$PID/status, so just get it from - // there instead. - bool isDebuggerActive(){ - // Libstdc++ has a bug, where std::ifstream sets errno to 0 - // This way our users can properly assert over errno values - 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 ) { - // We're traced if the PID is not 0 and no other PID starts - // with 0 digit, so it's enough to check for just a single - // character. - return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; - } - } - - return false; - } - } // namespace Catch -#elif defined(_MSC_VER) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; - } - } -#elif defined(__MINGW32__) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; - } - } -#else - namespace Catch { - bool isDebuggerActive() { return false; } - } -#endif // Platform - - - - -namespace Catch { - - ITransientExpression::~ITransientExpression() = default; - - void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { - if( lhs.size() + rhs.size() < 40 && - lhs.find('\n') == std::string::npos && - rhs.find('\n') == std::string::npos ) - os << lhs << ' ' << op << ' ' << rhs; - else - os << lhs << '\n' << op << '\n' << rhs; - } -} - - - -#include - - -namespace Catch { -#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) - [[noreturn]] - void throw_exception(std::exception const& e) { - Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n" - << "The message was: " << e.what() << '\n'; - std::terminate(); - } -#endif - - [[noreturn]] - void throw_logic_error(std::string const& msg) { - throw_exception(std::logic_error(msg)); - } - - [[noreturn]] - void throw_domain_error(std::string const& msg) { - throw_exception(std::domain_error(msg)); - } - - [[noreturn]] - void throw_runtime_error(std::string const& msg) { - throw_exception(std::runtime_error(msg)); - } - - - -} // namespace Catch; - - - -#include - -namespace Catch { - - IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() = default; - - namespace Detail { - - namespace { - // Extracts the actual name part of an enum instance - // In other words, it returns the Blue part of Bikeshed::Colour::Blue - StringRef extractInstanceName(StringRef enumInstance) { - // Find last occurrence of ":" - size_t name_start = enumInstance.size(); - while (name_start > 0 && enumInstance[name_start - 1] != ':') { - --name_start; - } - return enumInstance.substr(name_start, enumInstance.size() - name_start); - } - } - - std::vector parseEnums( StringRef enums ) { - auto enumValues = splitStringRef( enums, ',' ); - std::vector parsed; - parsed.reserve( enumValues.size() ); - for( auto const& enumValue : enumValues ) { - parsed.push_back(trim(extractInstanceName(enumValue))); - } - return parsed; - } - - EnumInfo::~EnumInfo() {} - - StringRef EnumInfo::lookup( int value ) const { - for( auto const& valueToName : m_values ) { - if( valueToName.first == value ) - return valueToName.second; - } - return "{** unexpected enum value **}"_sr; - } - - Catch::Detail::unique_ptr makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector const& values ) { - auto enumInfo = Catch::Detail::make_unique(); - enumInfo->m_name = enumName; - enumInfo->m_values.reserve( values.size() ); - - const auto valueNames = Catch::Detail::parseEnums( allValueNames ); - assert( valueNames.size() == values.size() ); - std::size_t i = 0; - for( auto value : values ) - enumInfo->m_values.emplace_back(value, valueNames[i++]); - - return enumInfo; - } - - EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector const& values ) { - m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values)); - return *m_enumInfos.back(); - } - - } // Detail -} // Catch - - - - - -#include - -namespace Catch { - ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} - ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } -} - - - -namespace Catch { - - ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { - } - - void ExceptionTranslatorRegistry::registerTranslator( Detail::unique_ptr&& translator ) { - m_translators.push_back( CATCH_MOVE( translator ) ); - } - -#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - std::string ExceptionTranslatorRegistry::translateActiveException() const { - // Compiling a mixed mode project with MSVC means that CLR - // exceptions will be caught in (...) as well. However, these do - // do not fill-in std::current_exception and thus lead to crash - // when attempting rethrow. - // /EHa switch also causes structured exceptions to be caught - // here, but they fill-in current_exception properly, so - // at worst the output should be a little weird, instead of - // causing a crash. - if ( std::current_exception() == nullptr ) { - return "Non C++ exception. Possibly a CLR exception."; - } - - // First we try user-registered translators. If none of them can - // handle the exception, it will be rethrown handled by our defaults. - try { - return tryTranslators(); - } - // To avoid having to handle TFE explicitly everywhere, we just - // rethrow it so that it goes back up the caller. - catch( TestFailureException& ) { - std::rethrow_exception(std::current_exception()); - } - catch( TestSkipException& ) { - std::rethrow_exception(std::current_exception()); - } - catch( std::exception const& ex ) { - return ex.what(); - } - catch( std::string const& msg ) { - return msg; - } - catch( const char* msg ) { - return msg; - } - catch(...) { - return "Unknown exception"; - } - } - - std::string ExceptionTranslatorRegistry::tryTranslators() const { - if (m_translators.empty()) { - std::rethrow_exception(std::current_exception()); - } else { - return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end()); - } - } - -#else // ^^ Exceptions are enabled // Exceptions are disabled vv - std::string ExceptionTranslatorRegistry::translateActiveException() const { - CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); - } - - std::string ExceptionTranslatorRegistry::tryTranslators() const { - CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); - } -#endif - - -} - - - -/** \file - * This file provides platform specific implementations of FatalConditionHandler - * - * This means that there is a lot of conditional compilation, and platform - * specific code. Currently, Catch2 supports a dummy handler (if no - * handler is desired), and 2 platform specific handlers: - * * Windows' SEH - * * POSIX signals - * - * Consequently, various pieces of code below are compiled if either of - * the platform specific handlers is enabled, or if none of them are - * enabled. It is assumed that both cannot be enabled at the same time, - * and doing so should cause a compilation error. - * - * If another platform specific handler is added, the compile guards - * below will need to be updated taking these assumptions into account. - */ - - - -#include - -#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS ) - -namespace Catch { - - // If neither SEH nor signal handling is required, the handler impls - // do not have to do anything, and can be empty. - void FatalConditionHandler::engage_platform() {} - void FatalConditionHandler::disengage_platform() noexcept {} - FatalConditionHandler::FatalConditionHandler() = default; - FatalConditionHandler::~FatalConditionHandler() = default; - -} // end namespace Catch - -#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS - -#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS ) -#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time" -#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS - -#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) - -namespace { - //! Signals fatal error message to the run context - void reportFatal( char const * const message ) { - Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); - } - - //! Minimal size Catch2 needs for its own fatal error handling. - //! Picked empirically, so it might not be sufficient on all - //! platforms, and for all configurations. - constexpr std::size_t minStackSizeForErrors = 32 * 1024; -} // end unnamed namespace - -#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS - -#if defined( CATCH_CONFIG_WINDOWS_SEH ) - -namespace Catch { - - 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. - static SignalDefs signalDefs[] = { - { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, - { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, - { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, - { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, - }; - - static LONG CALLBACK topLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) { - for (auto const& def : signalDefs) { - if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { - reportFatal(def.name); - } - } - // If its not an exception we care about, pass it along. - // This stops us from eating debugger breaks etc. - return EXCEPTION_CONTINUE_SEARCH; - } - - // Since we do not support multiple instantiations, we put these - // into global variables and rely on cleaning them up in outlined - // constructors/destructors - static LPTOP_LEVEL_EXCEPTION_FILTER previousTopLevelExceptionFilter = nullptr; - - - // For MSVC, we reserve part of the stack memory for handling - // memory overflow structured exception. - FatalConditionHandler::FatalConditionHandler() { - ULONG guaranteeSize = static_cast(minStackSizeForErrors); - if (!SetThreadStackGuarantee(&guaranteeSize)) { - // We do not want to fully error out, because needing - // the stack reserve should be rare enough anyway. - Catch::cerr() - << "Failed to reserve piece of stack." - << " Stack overflows will not be reported successfully."; - } - } - - // We do not attempt to unset the stack guarantee, because - // Windows does not support lowering the stack size guarantee. - FatalConditionHandler::~FatalConditionHandler() = default; - - - void FatalConditionHandler::engage_platform() { - // Register as a the top level exception filter. - previousTopLevelExceptionFilter = SetUnhandledExceptionFilter(topLevelExceptionFilter); - } - - void FatalConditionHandler::disengage_platform() noexcept { - if (SetUnhandledExceptionFilter(previousTopLevelExceptionFilter) != topLevelExceptionFilter) { - Catch::cerr() - << "Unexpected SEH unhandled exception filter on disengage." - << " The filter was restored, but might be rolled back unexpectedly."; - } - previousTopLevelExceptionFilter = nullptr; - } - -} // end namespace Catch - -#endif // CATCH_CONFIG_WINDOWS_SEH - -#if defined( CATCH_CONFIG_POSIX_SIGNALS ) - -#include - -namespace Catch { - - struct SignalDefs { - int id; - const char* name; - }; - - static 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" } - }; - -// Older GCCs trigger -Wmissing-field-initializers for T foo = {} -// which is zero initialization, but not explicit. We want to avoid -// that. -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif - - static char* altStackMem = nullptr; - static std::size_t altStackSize = 0; - static stack_t oldSigStack{}; - static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{}; - - static void restorePreviousSignalHandlers() noexcept { - // We set signal handlers back to the previous ones. Hopefully - // nobody overwrote them in the meantime, and doesn't expect - // their signal handlers to live past ours given that they - // installed them after ours.. - for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { - sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); - } - // Return the old stack - sigaltstack(&oldSigStack, nullptr); - } - - static void handleSignal( int sig ) { - char const * name = ""; - for (auto const& def : signalDefs) { - if (sig == def.id) { - name = def.name; - break; - } - } - // We need to restore previous signal handlers and let them do - // their thing, so that the users can have the debugger break - // when a signal is raised, and so on. - restorePreviousSignalHandlers(); - reportFatal( name ); - raise( sig ); - } - - FatalConditionHandler::FatalConditionHandler() { - assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists"); - if (altStackSize == 0) { - altStackSize = std::max(static_cast(SIGSTKSZ), minStackSizeForErrors); - } - altStackMem = new char[altStackSize](); - } - - FatalConditionHandler::~FatalConditionHandler() { - delete[] altStackMem; - // We signal that another instance can be constructed by zeroing - // out the pointer. - altStackMem = nullptr; - } - - void FatalConditionHandler::engage_platform() { - 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 < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { - sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); - } - } - -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#endif - - - void FatalConditionHandler::disengage_platform() noexcept { - restorePreviousSignalHandlers(); - } - -} // end namespace Catch - -#endif // CATCH_CONFIG_POSIX_SIGNALS - - - - -#include - -namespace Catch { - namespace Detail { - - uint32_t convertToBits(float f) { - static_assert(sizeof(float) == sizeof(uint32_t), "Important ULP matcher assumption violated"); - uint32_t i; - std::memcpy(&i, &f, sizeof(f)); - return i; - } - - uint64_t convertToBits(double d) { - static_assert(sizeof(double) == sizeof(uint64_t), "Important ULP matcher assumption violated"); - uint64_t i; - std::memcpy(&i, &d, sizeof(d)); - return i; - } - - } // end namespace Detail -} // end namespace Catch - - - - - - -#include - -namespace Catch { - namespace Detail { - -#if !defined (CATCH_CONFIG_GETENV) - char const* getEnv( char const* ) { return nullptr; } -#else - - char const* getEnv( char const* varName ) { -# if defined( _MSC_VER ) -# pragma warning( push ) -# pragma warning( disable : 4996 ) // use getenv_s instead of getenv -# endif - - return std::getenv( varName ); - -# if defined( _MSC_VER ) -# pragma warning( pop ) -# endif - } -#endif -} // namespace Detail -} // namespace Catch - - - - -#include -#include -#include -#include - -namespace Catch { - - Catch::IStream::~IStream() = default; - -namespace Detail { - namespace { - template - class StreamBufImpl : public std::streambuf { - char data[bufferSize]; - WriterF m_writer; - - public: - StreamBufImpl() { - setp( data, data + sizeof(data) ); - } - - ~StreamBufImpl() noexcept override { - StreamBufImpl::sync(); - } - - private: - int overflow( int c ) override { - sync(); - - if( c != EOF ) { - if( pbase() == epptr() ) - m_writer( std::string( 1, static_cast( c ) ) ); - else - sputc( static_cast( c ) ); - } - return 0; - } - - int sync() override { - if( pbase() != pptr() ) { - m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); - setp( pbase(), epptr() ); - } - return 0; - } - }; - - /////////////////////////////////////////////////////////////////////////// - - struct OutputDebugWriter { - - void operator()( std::string const& str ) { - if ( !str.empty() ) { - writeToDebugConsole( str ); - } - } - }; - - /////////////////////////////////////////////////////////////////////////// - - class FileStream : public IStream { - std::ofstream m_ofs; - public: - FileStream( std::string const& filename ) { - m_ofs.open( filename.c_str() ); - CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << '\'' ); - m_ofs << std::unitbuf; - } - ~FileStream() override = default; - public: // IStream - std::ostream& stream() override { - return m_ofs; - } - }; - - /////////////////////////////////////////////////////////////////////////// - - class CoutStream : public IStream { - std::ostream m_os; - public: - // Store the streambuf from cout up-front because - // cout may get redirected when running tests - CoutStream() : m_os( Catch::cout().rdbuf() ) {} - ~CoutStream() override = default; - - public: // IStream - std::ostream& stream() override { return m_os; } - bool isConsole() const override { return true; } - }; - - class CerrStream : public IStream { - std::ostream m_os; - - public: - // Store the streambuf from cerr up-front because - // cout may get redirected when running tests - CerrStream(): m_os( Catch::cerr().rdbuf() ) {} - ~CerrStream() override = default; - - public: // IStream - std::ostream& stream() override { return m_os; } - bool isConsole() const override { return true; } - }; - - /////////////////////////////////////////////////////////////////////////// - - class DebugOutStream : public IStream { - Detail::unique_ptr> m_streamBuf; - std::ostream m_os; - public: - DebugOutStream() - : m_streamBuf( Detail::make_unique>() ), - m_os( m_streamBuf.get() ) - {} - - ~DebugOutStream() override = default; - - public: // IStream - std::ostream& stream() override { return m_os; } - }; - - } // unnamed namespace -} // namespace Detail - - /////////////////////////////////////////////////////////////////////////// - - auto makeStream( std::string const& filename ) -> Detail::unique_ptr { - if ( filename.empty() || filename == "-" ) { - return Detail::make_unique(); - } - if( filename[0] == '%' ) { - if ( filename == "%debug" ) { - return Detail::make_unique(); - } else if ( filename == "%stderr" ) { - return Detail::make_unique(); - } else if ( filename == "%stdout" ) { - return Detail::make_unique(); - } else { - CATCH_ERROR( "Unrecognised stream: '" << filename << '\'' ); - } - } - return Detail::make_unique( filename ); - } - -} - - - - -namespace Catch { - - auto operator << (std::ostream& os, LazyExpression const& lazyExpr) -> std::ostream& { - if (lazyExpr.m_isNegated) - os << '!'; - - if (lazyExpr) { - if (lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression()) - os << '(' << *lazyExpr.m_transientExpression << ')'; - else - os << *lazyExpr.m_transientExpression; - } else { - os << "{** error - unchecked empty expression requested **}"; - } - return os; - } - -} // namespace Catch - - - - -#ifdef CATCH_CONFIG_WINDOWS_CRTDBG -#include - -namespace Catch { - - LeakDetector::LeakDetector() { - int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); - flag |= _CRTDBG_LEAK_CHECK_DF; - flag |= _CRTDBG_ALLOC_MEM_DF; - _CrtSetDbgFlag(flag); - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); - _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); - // Change this to leaking allocation's number to break there - _CrtSetBreakAlloc(-1); - } -} - -#else // ^^ Windows crt debug heap enabled // Windows crt debug heap disabled vv - - Catch::LeakDetector::LeakDetector() {} - -#endif // CATCH_CONFIG_WINDOWS_CRTDBG - -Catch::LeakDetector::~LeakDetector() { - Catch::cleanUp(); -} - - - - - -namespace Catch { - namespace { - - void listTests(IEventListener& reporter, IConfig const& config) { - auto const& testSpec = config.testSpec(); - auto matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config); - reporter.listTests(matchedTestCases); - } - - void listTags(IEventListener& reporter, IConfig const& config) { - auto const& testSpec = config.testSpec(); - std::vector matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config); - - std::map tagCounts; - for (auto const& testCase : matchedTestCases) { - for (auto const& tagName : testCase.getTestCaseInfo().tags) { - auto it = tagCounts.find(tagName.original); - if (it == tagCounts.end()) - it = tagCounts.insert(std::make_pair(tagName.original, TagInfo())).first; - it->second.add(tagName.original); - } - } - - std::vector infos; infos.reserve(tagCounts.size()); - for (auto& tagc : tagCounts) { - infos.push_back(CATCH_MOVE(tagc.second)); - } - - reporter.listTags(infos); - } - - void listReporters(IEventListener& reporter) { - std::vector descriptions; - - IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); - descriptions.reserve(factories.size()); - for (auto const& fac : factories) { - descriptions.push_back({ fac.first, fac.second->getDescription() }); - } - - reporter.listReporters(descriptions); - } - - void listListeners(IEventListener& reporter) { - std::vector descriptions; - - auto const& factories = - getRegistryHub().getReporterRegistry().getListeners(); - descriptions.reserve( factories.size() ); - for ( auto const& fac : factories ) { - descriptions.push_back( { fac->getName(), fac->getDescription() } ); - } - - reporter.listListeners( descriptions ); - } - - } // end anonymous namespace - - void TagInfo::add( StringRef spelling ) { - ++count; - spellings.insert( spelling ); - } - - std::string TagInfo::all() const { - // 2 per tag for brackets '[' and ']' - size_t size = spellings.size() * 2; - for (auto const& spelling : spellings) { - size += spelling.size(); - } - - std::string out; out.reserve(size); - for (auto const& spelling : spellings) { - out += '['; - out += spelling; - out += ']'; - } - return out; - } - - bool list( IEventListener& reporter, Config const& config ) { - bool listed = false; - if (config.listTests()) { - listed = true; - listTests(reporter, config); - } - if (config.listTags()) { - listed = true; - listTags(reporter, config); - } - if (config.listReporters()) { - listed = true; - listReporters(reporter); - } - if ( config.listListeners() ) { - listed = true; - listListeners( reporter ); - } - return listed; - } - -} // end namespace Catch - - - -namespace Catch { - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS - static LeakDetector leakDetector; - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -} - -// Allow users of amalgamated .cpp file to remove our main and provide their own. -#if !defined(CATCH_AMALGAMATED_CUSTOM_MAIN) - -#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) -// Standard C/C++ Win32 Unicode wmain entry point -extern "C" int __cdecl wmain (int argc, wchar_t * argv[], wchar_t * []) { -#else -// Standard C/C++ main entry point -int main (int argc, char * argv[]) { -#endif - - // We want to force the linker not to discard the global variable - // and its constructor, as it (optionally) registers leak detector - (void)&Catch::leakDetector; - - return Catch::Session().run( argc, argv ); -} - -#endif // !defined(CATCH_AMALGAMATED_CUSTOM_MAIN - - - - -namespace Catch { - - MessageInfo::MessageInfo( StringRef _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ) - : macroName( _macroName ), - lineInfo( _lineInfo ), - type( _type ), - sequence( ++globalCount ) - {} - - // This may need protecting if threading support is added - unsigned int MessageInfo::globalCount = 0; - -} // end namespace Catch - - - -#include -#include -#include - -#if defined(CATCH_CONFIG_NEW_CAPTURE) - #if defined(_MSC_VER) - #include //_dup and _dup2 - #define dup _dup - #define dup2 _dup2 - #define fileno _fileno - #else - #include // dup and dup2 - #endif -#endif - - -namespace Catch { - - RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) - : m_originalStream( originalStream ), - m_redirectionStream( redirectionStream ), - m_prevBuf( m_originalStream.rdbuf() ) - { - m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); - } - - RedirectedStream::~RedirectedStream() { - m_originalStream.rdbuf( m_prevBuf ); - } - - RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} - auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } - - RedirectedStdErr::RedirectedStdErr() - : m_cerr( Catch::cerr(), m_rss.get() ), - m_clog( Catch::clog(), m_rss.get() ) - {} - auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } - - RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr) - : m_redirectedCout(redirectedCout), - m_redirectedCerr(redirectedCerr) - {} - - RedirectedStreams::~RedirectedStreams() { - m_redirectedCout += m_redirectedStdOut.str(); - m_redirectedCerr += m_redirectedStdErr.str(); - } - -#if defined(CATCH_CONFIG_NEW_CAPTURE) - -#if defined(_MSC_VER) - TempFile::TempFile() { - if (tmpnam_s(m_buffer)) { - CATCH_RUNTIME_ERROR("Could not get a temp filename"); - } - if (fopen_s(&m_file, m_buffer, "w+")) { - char buffer[100]; - if (strerror_s(buffer, errno)) { - CATCH_RUNTIME_ERROR("Could not translate errno to a string"); - } - CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer); - } - } -#else - TempFile::TempFile() { - m_file = std::tmpfile(); - if (!m_file) { - CATCH_RUNTIME_ERROR("Could not create a temp file."); - } - } - -#endif - - TempFile::~TempFile() { - // TBD: What to do about errors here? - std::fclose(m_file); - // We manually create the file on Windows only, on Linux - // it will be autodeleted -#if defined(_MSC_VER) - std::remove(m_buffer); -#endif - } - - - FILE* TempFile::getFile() { - return m_file; - } - - std::string TempFile::getContents() { - std::stringstream sstr; - char buffer[100] = {}; - std::rewind(m_file); - while (std::fgets(buffer, sizeof(buffer), m_file)) { - sstr << buffer; - } - return sstr.str(); - } - - OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : - m_originalStdout(dup(1)), - m_originalStderr(dup(2)), - m_stdoutDest(stdout_dest), - m_stderrDest(stderr_dest) { - dup2(fileno(m_stdoutFile.getFile()), 1); - dup2(fileno(m_stderrFile.getFile()), 2); - } - - OutputRedirect::~OutputRedirect() { - Catch::cout() << std::flush; - fflush(stdout); - // Since we support overriding these streams, we flush cerr - // even though std::cerr is unbuffered - Catch::cerr() << std::flush; - Catch::clog() << std::flush; - fflush(stderr); - - dup2(m_originalStdout, 1); - dup2(m_originalStderr, 2); - - m_stdoutDest += m_stdoutFile.getContents(); - m_stderrDest += m_stderrFile.getContents(); - } - -#endif // CATCH_CONFIG_NEW_CAPTURE - -} // namespace Catch - -#if defined(CATCH_CONFIG_NEW_CAPTURE) - #if defined(_MSC_VER) - #undef dup - #undef dup2 - #undef fileno - #endif -#endif - - - - -#include -#include - -namespace Catch { - - Optional parseUInt(std::string const& input, int base) { - auto trimmed = trim( input ); - // std::stoull is annoying and accepts numbers starting with '-', - // it just negates them into unsigned int - if ( trimmed.empty() || trimmed[0] == '-' ) { - return {}; - } - - CATCH_TRY { - size_t pos = 0; - const auto ret = std::stoull( trimmed, &pos, base ); - - // We did not consume the whole input, so there is an issue - // This can be bunch of different stuff, like multiple numbers - // in the input, or invalid digits/characters and so on. Either - // way, we do not want to return the partially parsed result. - if ( pos != trimmed.size() ) { - return {}; - } - // Too large - if ( ret > std::numeric_limits::max() ) { - return {}; - } - return static_cast(ret); - } - CATCH_CATCH_ANON( std::invalid_argument const& ) { - // no conversion could be performed - } - CATCH_CATCH_ANON( std::out_of_range const& ) { - // the input does not fit into an unsigned long long - } - return {}; - } - -} // namespace Catch - - - - -#include - -namespace Catch { - -#if !defined(CATCH_CONFIG_POLYFILL_ISNAN) - bool isnan(float f) { - return std::isnan(f); - } - bool isnan(double d) { - return std::isnan(d); - } -#else - // For now we only use this for embarcadero - bool isnan(float f) { - return std::_isnan(f); - } - bool isnan(double d) { - return std::_isnan(d); - } -#endif - -} // end namespace Catch - - - -namespace Catch { - -namespace { - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4146) // we negate uint32 during the rotate -#endif - // Safe rotr implementation thanks to John Regehr - uint32_t rotate_right(uint32_t val, uint32_t count) { - const uint32_t mask = 31; - count &= mask; - return (val >> count) | (val << (-count & mask)); - } - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -} - - - SimplePcg32::SimplePcg32(result_type seed_) { - seed(seed_); - } - - - void SimplePcg32::seed(result_type seed_) { - m_state = 0; - (*this)(); - m_state += seed_; - (*this)(); - } - - void SimplePcg32::discard(uint64_t skip) { - // We could implement this to run in O(log n) steps, but this - // should suffice for our use case. - for (uint64_t s = 0; s < skip; ++s) { - static_cast((*this)()); - } - } - - SimplePcg32::result_type SimplePcg32::operator()() { - // prepare the output value - const uint32_t xorshifted = static_cast(((m_state >> 18u) ^ m_state) >> 27u); - const auto output = rotate_right(xorshifted, m_state >> 59u); - - // advance state - m_state = m_state * 6364136223846793005ULL + s_inc; - - return output; - } - - bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { - return lhs.m_state == rhs.m_state; - } - - bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { - return lhs.m_state != rhs.m_state; - } -} - - - - - -#include -#include - -namespace Catch { - - std::uint32_t generateRandomSeed( GenerateFrom from ) { - switch ( from ) { - case GenerateFrom::Time: - return static_cast( std::time( nullptr ) ); - - case GenerateFrom::Default: - case GenerateFrom::RandomDevice: - // In theory, a platform could have random_device that returns just - // 16 bits. That is still some randomness, so we don't care too much - return static_cast( std::random_device{}() ); - - default: - CATCH_ERROR("Unknown generation method"); - } - } - -} // end namespace Catch - - - - -namespace Catch { - - ReporterRegistry::ReporterRegistry() { - // Because it is impossible to move out of initializer list, - // we have to add the elements manually - m_factories["Automake"] = Detail::make_unique>(); - m_factories["compact"] = Detail::make_unique>(); - m_factories["console"] = Detail::make_unique>(); - m_factories["JUnit"] = Detail::make_unique>(); - m_factories["SonarQube"] = Detail::make_unique>(); - m_factories["TAP"] = Detail::make_unique>(); - m_factories["TeamCity"] = Detail::make_unique>(); - m_factories["XML"] = Detail::make_unique>(); - } - - ReporterRegistry::~ReporterRegistry() = default; - - - IEventListenerPtr ReporterRegistry::create( std::string const& name, ReporterConfig&& config ) const { - auto it = m_factories.find( name ); - if( it == m_factories.end() ) - return nullptr; - return it->second->create( CATCH_MOVE(config) ); - } - - void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr factory ) { - CATCH_ENFORCE( name.find( "::" ) == name.npos, - "'::' is not allowed in reporter name: '" + name + '\'' ); - auto ret = m_factories.emplace(name, CATCH_MOVE(factory)); - CATCH_ENFORCE( ret.second, "reporter using '" + name + "' as name was already registered" ); - } - void ReporterRegistry::registerListener( - Detail::unique_ptr factory ) { - m_listeners.push_back( CATCH_MOVE(factory) ); - } - - IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { - return m_factories; - } - IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { - return m_listeners; - } - -} - - - - - -#include - -namespace Catch { - - namespace { - struct kvPair { - StringRef key, value; - }; - - kvPair splitKVPair(StringRef kvString) { - auto splitPos = static_cast( std::distance( - kvString.begin(), - std::find( kvString.begin(), kvString.end(), '=' ) ) ); - - return { kvString.substr( 0, splitPos ), - kvString.substr( splitPos + 1, kvString.size() ) }; - } - } - - namespace Detail { - std::vector splitReporterSpec( StringRef reporterSpec ) { - static constexpr auto separator = "::"; - static constexpr size_t separatorSize = 2; - - size_t separatorPos = 0; - auto findNextSeparator = [&reporterSpec]( size_t startPos ) { - static_assert( - separatorSize == 2, - "The code below currently assumes 2 char separator" ); - - auto currentPos = startPos; - do { - while ( currentPos < reporterSpec.size() && - reporterSpec[currentPos] != separator[0] ) { - ++currentPos; - } - if ( currentPos + 1 < reporterSpec.size() && - reporterSpec[currentPos + 1] == separator[1] ) { - return currentPos; - } - ++currentPos; - } while ( currentPos < reporterSpec.size() ); - - return static_cast( -1 ); - }; - - std::vector parts; - - while ( separatorPos < reporterSpec.size() ) { - const auto nextSeparator = findNextSeparator( separatorPos ); - parts.push_back( static_cast( reporterSpec.substr( - separatorPos, nextSeparator - separatorPos ) ) ); - - if ( nextSeparator == static_cast( -1 ) ) { - break; - } - separatorPos = nextSeparator + separatorSize; - } - - // Handle a separator at the end. - // This is not a valid spec, but we want to do validation in a - // centralized place - if ( separatorPos == reporterSpec.size() ) { - parts.emplace_back(); - } - - return parts; - } - - Optional stringToColourMode( StringRef colourMode ) { - if ( colourMode == "default" ) { - return ColourMode::PlatformDefault; - } else if ( colourMode == "ansi" ) { - return ColourMode::ANSI; - } else if ( colourMode == "win32" ) { - return ColourMode::Win32; - } else if ( colourMode == "none" ) { - return ColourMode::None; - } else { - return {}; - } - } - } // namespace Detail - - - bool operator==( ReporterSpec const& lhs, ReporterSpec const& rhs ) { - return lhs.m_name == rhs.m_name && - lhs.m_outputFileName == rhs.m_outputFileName && - lhs.m_colourMode == rhs.m_colourMode && - lhs.m_customOptions == rhs.m_customOptions; - } - - Optional parseReporterSpec( StringRef reporterSpec ) { - auto parts = Detail::splitReporterSpec( reporterSpec ); - - assert( parts.size() > 0 && "Split should never return empty vector" ); - - std::map kvPairs; - Optional outputFileName; - Optional colourMode; - - // First part is always reporter name, so we skip it - for ( size_t i = 1; i < parts.size(); ++i ) { - auto kv = splitKVPair( parts[i] ); - auto key = kv.key, value = kv.value; - - if ( key.empty() || value.empty() ) { - return {}; - } else if ( key[0] == 'X' ) { - // This is a reporter-specific option, we don't check these - // apart from basic sanity checks - if ( key.size() == 1 ) { - return {}; - } - - auto ret = kvPairs.emplace( std::string(kv.key), std::string(kv.value) ); - if ( !ret.second ) { - // Duplicated key. We might want to handle this differently, - // e.g. by overwriting the existing value? - return {}; - } - } else if ( key == "out" ) { - // Duplicated key - if ( outputFileName ) { - return {}; - } - outputFileName = static_cast( value ); - } else if ( key == "colour-mode" ) { - // Duplicated key - if ( colourMode ) { - return {}; - } - colourMode = Detail::stringToColourMode( value ); - // Parsing failed - if ( !colourMode ) { - return {}; - } - } else { - // Unrecognized option - return {}; - } - } - - return ReporterSpec{ CATCH_MOVE( parts[0] ), - CATCH_MOVE( outputFileName ), - CATCH_MOVE( colourMode ), - CATCH_MOVE( kvPairs ) }; - } - -ReporterSpec::ReporterSpec( - std::string name, - Optional outputFileName, - Optional colourMode, - std::map customOptions ): - m_name( CATCH_MOVE( name ) ), - m_outputFileName( CATCH_MOVE( outputFileName ) ), - m_colourMode( CATCH_MOVE( colourMode ) ), - m_customOptions( CATCH_MOVE( customOptions ) ) {} - -} // namespace Catch - - - -namespace Catch { - - bool isOk( ResultWas::OfType resultType ) { - return ( resultType & ResultWas::FailureBit ) == 0; - } - bool isJustInfo( int flags ) { - return flags == ResultWas::Info; - } - - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { - return static_cast( static_cast( lhs ) | static_cast( rhs ) ); - } - - bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } - bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } - -} // end namespace Catch - - - -#include -#include -#include - -namespace Catch { - - // This class encapsulates the idea of a pool of ostringstreams that can be reused. - struct StringStreams { - std::vector> m_streams; - std::vector m_unused; - std::ostringstream m_referenceStream; // Used for copy state/ flags from - - auto add() -> std::size_t { - if( m_unused.empty() ) { - m_streams.push_back( Detail::make_unique() ); - return m_streams.size()-1; - } - else { - auto index = m_unused.back(); - m_unused.pop_back(); - return index; - } - } - - void release( std::size_t index ) { - m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state - m_unused.push_back(index); - } - }; - - ReusableStringStream::ReusableStringStream() - : m_index( Singleton::getMutable().add() ), - m_oss( Singleton::getMutable().m_streams[m_index].get() ) - {} - - ReusableStringStream::~ReusableStringStream() { - static_cast( m_oss )->str(""); - m_oss->clear(); - Singleton::getMutable().release( m_index ); - } - - std::string ReusableStringStream::str() const { - return static_cast( m_oss )->str(); - } - - void ReusableStringStream::str( std::string const& str ) { - static_cast( m_oss )->str( str ); - } - - -} - - - - -#include -#include - -namespace Catch { - - namespace Generators { - struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { - GeneratorBasePtr m_generator; - - GeneratorTracker( TestCaseTracking::NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ) - {} - ~GeneratorTracker() override; - - static GeneratorTracker* acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocationRef const& nameAndLocation ) { - GeneratorTracker* tracker; - - ITracker& currentTracker = ctx.currentTracker(); - // Under specific circumstances, the generator we want - // to acquire is also the current tracker. If this is - // the case, we have to avoid looking through current - // tracker's children, and instead return the current - // tracker. - // A case where this check is important is e.g. - // for (int i = 0; i < 5; ++i) { - // int n = GENERATE(1, 2); - // } - // - // without it, the code above creates 5 nested generators. - if ( currentTracker.nameAndLocation() == nameAndLocation ) { - auto thisTracker = - currentTracker.parent()->findChild( nameAndLocation ); - assert( thisTracker ); - assert( thisTracker->isGeneratorTracker() ); - tracker = static_cast( thisTracker ); - } else if ( ITracker* childTracker = - currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isGeneratorTracker() ); - tracker = static_cast( childTracker ); - } else { - return nullptr; - } - - if( !tracker->isComplete() ) { - tracker->open(); - } - - return tracker; - } - - // TrackerBase interface - bool isGeneratorTracker() const override { return true; } - auto hasGenerator() const -> bool override { - return !!m_generator; - } - void close() override { - TrackerBase::close(); - // If a generator has a child (it is followed by a section) - // and none of its children have started, then we must wait - // until later to start consuming its values. - // This catches cases where `GENERATE` is placed between two - // `SECTION`s. - // **The check for m_children.empty cannot be removed**. - // doing so would break `GENERATE` _not_ followed by `SECTION`s. - const bool should_wait_for_child = [&]() { - // No children -> nobody to wait for - if ( m_children.empty() ) { - return false; - } - // If at least one child started executing, don't wait - if ( std::find_if( - m_children.begin(), - m_children.end(), - []( TestCaseTracking::ITrackerPtr const& tracker ) { - return tracker->hasStarted(); - } ) != m_children.end() ) { - return false; - } - - // No children have started. We need to check if they _can_ - // start, and thus we should wait for them, or they cannot - // start (due to filters), and we shouldn't wait for them - ITracker* parent = m_parent; - // This is safe: there is always at least one section - // tracker in a test case tracking tree - while ( !parent->isSectionTracker() ) { - parent = parent->parent(); - } - assert( parent && - "Missing root (test case) level section" ); - - auto const& parentSection = - static_cast( *parent ); - auto const& filters = parentSection.getFilters(); - // No filters -> no restrictions on running sections - if ( filters.empty() ) { - return true; - } - - for ( auto const& child : m_children ) { - if ( child->isSectionTracker() && - std::find( - filters.begin(), - filters.end(), - static_cast( *child ) - .trimmedName() ) != filters.end() ) { - return true; - } - } - return false; - }(); - - // This check is a bit tricky, because m_generator->next() - // has a side-effect, where it consumes generator's current - // value, but we do not want to invoke the side-effect if - // this generator is still waiting for any child to start. - assert( m_generator && "Tracker without generator" ); - if ( should_wait_for_child || - ( m_runState == CompletedSuccessfully && - m_generator->countedNext() ) ) { - m_children.clear(); - m_runState = Executing; - } - } - - // IGeneratorTracker interface - auto getGenerator() const -> GeneratorBasePtr const& override { - return m_generator; - } - void setGenerator( GeneratorBasePtr&& generator ) override { - m_generator = CATCH_MOVE( generator ); - } - }; - GeneratorTracker::~GeneratorTracker() = default; - } - - RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter) - : m_runInfo(_config->name()), - m_context(getCurrentMutableContext()), - m_config(_config), - m_reporter(CATCH_MOVE(reporter)), - m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, - m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) - { - m_context.setResultCapture(this); - m_reporter->testRunStarting(m_runInfo); - } - - RunContext::~RunContext() { - m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); - } - - Totals RunContext::runTest(TestCaseHandle const& testCase) { - const Totals prevTotals = m_totals; - - auto const& testInfo = testCase.getTestCaseInfo(); - m_reporter->testCaseStarting(testInfo); - m_activeTestCase = &testCase; - - - ITracker& rootTracker = m_trackerContext.startRun(); - assert(rootTracker.isSectionTracker()); - static_cast(rootTracker).addInitialFilters(m_config->getSectionsToRun()); - - // We intentionally only seed the internal RNG once per test case, - // before it is first invoked. The reason for that is a complex - // interplay of generator/section implementation details and the - // Random*Generator types. - // - // The issue boils down to us needing to seed the Random*Generators - // with different seed each, so that they return different sequences - // of random numbers. We do this by giving them a number from the - // shared RNG instance as their seed. - // - // However, this runs into an issue if the reseeding happens each - // time the test case is entered (as opposed to first time only), - // because multiple generators could get the same seed, e.g. in - // ```cpp - // TEST_CASE() { - // auto i = GENERATE(take(10, random(0, 100)); - // SECTION("A") { - // auto j = GENERATE(take(10, random(0, 100)); - // } - // SECTION("B") { - // auto k = GENERATE(take(10, random(0, 100)); - // } - // } - // ``` - // `i` and `j` would properly return values from different sequences, - // but `i` and `k` would return the same sequence, because their seed - // would be the same. - // (The reason their seeds would be the same is that the generator - // for k would be initialized when the test case is entered the second - // time, after the shared RNG instance was reset to the same value - // it had when the generator for i was initialized.) - seedRng( *m_config ); - - uint64_t testRuns = 0; - std::string redirectedCout; - std::string redirectedCerr; - do { - m_trackerContext.startCycle(); - m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo)); - - m_reporter->testCasePartialStarting(testInfo, testRuns); - - const auto beforeRunTotals = m_totals; - std::string oneRunCout, oneRunCerr; - runCurrentTest(oneRunCout, oneRunCerr); - redirectedCout += oneRunCout; - redirectedCerr += oneRunCerr; - - const auto singleRunTotals = m_totals.delta(beforeRunTotals); - auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting()); - - m_reporter->testCasePartialEnded(statsForOneRun, testRuns); - ++testRuns; - } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); - - Totals deltaTotals = m_totals.delta(prevTotals); - if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { - deltaTotals.assertions.failed++; - deltaTotals.testCases.passed--; - deltaTotals.testCases.failed++; - } - m_totals.testCases += deltaTotals.testCases; - m_reporter->testCaseEnded(TestCaseStats(testInfo, - deltaTotals, - CATCH_MOVE(redirectedCout), - CATCH_MOVE(redirectedCerr), - aborting())); - - m_activeTestCase = nullptr; - m_testCaseTracker = nullptr; - - return deltaTotals; - } - - - void RunContext::assertionEnded(AssertionResult const & result) { - if (result.getResultType() == ResultWas::Ok) { - m_totals.assertions.passed++; - m_lastAssertionPassed = true; - } else if (result.getResultType() == ResultWas::ExplicitSkip) { - m_totals.assertions.skipped++; - m_lastAssertionPassed = true; - } else if (!result.succeeded()) { - m_lastAssertionPassed = false; - if (result.isOk()) { - } - else if( m_activeTestCase->getTestCaseInfo().okToFail() ) - m_totals.assertions.failedButOk++; - else - m_totals.assertions.failed++; - } - else { - m_lastAssertionPassed = true; - } - - m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)); - - if (result.getResultType() != ResultWas::Warning) - m_messageScopes.clear(); - - // Reset working state - resetAssertionInfo(); - m_lastResult = result; - } - void RunContext::resetAssertionInfo() { - m_lastAssertionInfo.macroName = StringRef(); - m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; - } - - bool RunContext::sectionStarted(StringRef sectionName, SourceLineInfo const& sectionLineInfo, Counts & assertions) { - ITracker& sectionTracker = - SectionTracker::acquire( m_trackerContext, - TestCaseTracking::NameAndLocationRef( - sectionName, sectionLineInfo ) ); - - if (!sectionTracker.isOpen()) - return false; - m_activeSections.push_back(§ionTracker); - - SectionInfo sectionInfo( sectionLineInfo, static_cast(sectionName) ); - m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; - - m_reporter->sectionStarting(sectionInfo); - - assertions = m_totals.assertions; - - return true; - } - IGeneratorTracker* - RunContext::acquireGeneratorTracker( StringRef generatorName, - SourceLineInfo const& lineInfo ) { - using namespace Generators; - GeneratorTracker* tracker = GeneratorTracker::acquire( - m_trackerContext, - TestCaseTracking::NameAndLocationRef( - generatorName, lineInfo ) ); - m_lastAssertionInfo.lineInfo = lineInfo; - return tracker; - } - - IGeneratorTracker* RunContext::createGeneratorTracker( - StringRef generatorName, - SourceLineInfo lineInfo, - Generators::GeneratorBasePtr&& generator ) { - - auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast( generatorName ), lineInfo ); - auto& currentTracker = m_trackerContext.currentTracker(); - assert( - currentTracker.nameAndLocation() != nameAndLoc && - "Trying to create tracker for a genreator that already has one" ); - - auto newTracker = Catch::Detail::make_unique( - CATCH_MOVE(nameAndLoc), m_trackerContext, ¤tTracker ); - auto ret = newTracker.get(); - currentTracker.addChild( CATCH_MOVE( newTracker ) ); - - ret->setGenerator( CATCH_MOVE( generator ) ); - ret->open(); - return ret; - } - - bool RunContext::testForMissingAssertions(Counts& assertions) { - if (assertions.total() != 0) - return false; - if (!m_config->warnAboutMissingAssertions()) - return false; - if (m_trackerContext.currentTracker().hasChildren()) - return false; - m_totals.assertions.failed++; - assertions.failed++; - return true; - } - - void RunContext::sectionEnded(SectionEndInfo&& endInfo) { - Counts assertions = m_totals.assertions - endInfo.prevAssertions; - bool missingAssertions = testForMissingAssertions(assertions); - - if (!m_activeSections.empty()) { - m_activeSections.back()->close(); - m_activeSections.pop_back(); - } - - m_reporter->sectionEnded(SectionStats(CATCH_MOVE(endInfo.sectionInfo), assertions, endInfo.durationInSeconds, missingAssertions)); - m_messages.clear(); - m_messageScopes.clear(); - } - - void RunContext::sectionEndedEarly(SectionEndInfo&& endInfo) { - if ( m_unfinishedSections.empty() ) { - m_activeSections.back()->fail(); - } else { - m_activeSections.back()->close(); - } - m_activeSections.pop_back(); - - m_unfinishedSections.push_back(CATCH_MOVE(endInfo)); - } - - void RunContext::benchmarkPreparing( StringRef name ) { - m_reporter->benchmarkPreparing(name); - } - void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { - m_reporter->benchmarkStarting( info ); - } - void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) { - m_reporter->benchmarkEnded( stats ); - } - void RunContext::benchmarkFailed( StringRef error ) { - m_reporter->benchmarkFailed( error ); - } - - void RunContext::pushScopedMessage(MessageInfo const & message) { - m_messages.push_back(message); - } - - void RunContext::popScopedMessage(MessageInfo const & message) { - m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); - } - - void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) { - m_messageScopes.emplace_back( CATCH_MOVE(builder) ); - } - - std::string RunContext::getCurrentTestName() const { - return m_activeTestCase - ? m_activeTestCase->getTestCaseInfo().name - : std::string(); - } - - const AssertionResult * RunContext::getLastResult() const { - return &(*m_lastResult); - } - - void RunContext::exceptionEarlyReported() { - m_shouldReportUnexpected = false; - } - - void RunContext::handleFatalErrorCondition( StringRef message ) { - // First notify reporter that bad things happened - m_reporter->fatalErrorEncountered(message); - - // Don't rebuild the result -- the stringification itself can cause more fatal errors - // Instead, fake a result data. - AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); - tempResult.message = static_cast(message); - AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult)); - - assertionEnded(result); - - handleUnfinishedSections(); - - // Recreate section for test case (as we will lose the one that was in scope) - auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); - - Counts assertions; - assertions.failed = 1; - SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, 0, false); - m_reporter->sectionEnded(testCaseSectionStats); - - auto const& testInfo = m_activeTestCase->getTestCaseInfo(); - - Totals deltaTotals; - deltaTotals.testCases.failed = 1; - deltaTotals.assertions.failed = 1; - m_reporter->testCaseEnded(TestCaseStats(testInfo, - deltaTotals, - std::string(), - std::string(), - false)); - m_totals.testCases.failed++; - m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); - } - - bool RunContext::lastAssertionPassed() { - return m_lastAssertionPassed; - } - - void RunContext::assertionPassed() { - m_lastAssertionPassed = true; - ++m_totals.assertions.passed; - resetAssertionInfo(); - m_messageScopes.clear(); - } - - bool RunContext::aborting() const { - return m_totals.assertions.failed >= static_cast(m_config->abortAfter()); - } - - void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { - auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); - m_reporter->sectionStarting(testCaseSection); - Counts prevAssertions = m_totals.assertions; - double duration = 0; - m_shouldReportUnexpected = true; - m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; - - Timer timer; - CATCH_TRY { - if (m_reporter->getPreferences().shouldRedirectStdOut) { -#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) - RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr); - - timer.start(); - invokeActiveTestCase(); -#else - OutputRedirect r(redirectedCout, redirectedCerr); - timer.start(); - invokeActiveTestCase(); -#endif - } else { - timer.start(); - invokeActiveTestCase(); - } - duration = timer.getElapsedSeconds(); - } CATCH_CATCH_ANON (TestFailureException&) { - // This just means the test was aborted due to failure - } CATCH_CATCH_ANON (TestSkipException&) { - // This just means the test was explicitly skipped - } CATCH_CATCH_ALL { - // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions - // are reported without translation at the point of origin. - if( m_shouldReportUnexpected ) { - AssertionReaction dummyReaction; - handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); - } - } - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions(assertions); - - m_testCaseTracker->close(); - handleUnfinishedSections(); - m_messages.clear(); - m_messageScopes.clear(); - - SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions); - m_reporter->sectionEnded(testCaseSectionStats); - } - - void RunContext::invokeActiveTestCase() { - // We need to engage a handler for signals/structured exceptions - // before running the tests themselves, or the binary can crash - // without failed test being reported. - FatalConditionHandlerGuard _(&m_fatalConditionhandler); - // We keep having issue where some compilers warn about an unused - // variable, even though the type has non-trivial constructor and - // destructor. This is annoying and ugly, but it makes them stfu. - (void)_; - - m_activeTestCase->invoke(); - } - - void RunContext::handleUnfinishedSections() { - // If sections ended prematurely due to an exception we stored their - // infos here so we can tear them down outside the unwind process. - for (auto it = m_unfinishedSections.rbegin(), - itEnd = m_unfinishedSections.rend(); - it != itEnd; - ++it) - sectionEnded(CATCH_MOVE(*it)); - m_unfinishedSections.clear(); - } - - void RunContext::handleExpr( - AssertionInfo const& info, - ITransientExpression const& expr, - AssertionReaction& reaction - ) { - m_reporter->assertionStarting( info ); - - bool negated = isFalseTest( info.resultDisposition ); - bool result = expr.getResult() != negated; - - if( result ) { - if (!m_includeSuccessfulResults) { - assertionPassed(); - } - else { - reportExpr(info, ResultWas::Ok, &expr, negated); - } - } - else { - reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); - populateReaction( reaction ); - } - } - void RunContext::reportExpr( - AssertionInfo const &info, - ResultWas::OfType resultType, - ITransientExpression const *expr, - bool negated ) { - - m_lastAssertionInfo = info; - AssertionResultData data( resultType, LazyExpression( negated ) ); - - AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; - assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; - - assertionEnded( assertionResult ); - } - - void RunContext::handleMessage( - AssertionInfo const& info, - ResultWas::OfType resultType, - StringRef message, - AssertionReaction& reaction - ) { - m_reporter->assertionStarting( info ); - - m_lastAssertionInfo = info; - - AssertionResultData data( resultType, LazyExpression( false ) ); - data.message = static_cast(message); - AssertionResult assertionResult{ m_lastAssertionInfo, - CATCH_MOVE( data ) }; - assertionEnded( assertionResult ); - if ( !assertionResult.isOk() ) { - populateReaction( reaction ); - } else if ( resultType == ResultWas::ExplicitSkip ) { - // TODO: Need to handle this explicitly, as ExplicitSkip is - // considered "OK" - reaction.shouldSkip = true; - } - } - void RunContext::handleUnexpectedExceptionNotThrown( - AssertionInfo const& info, - AssertionReaction& reaction - ) { - handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); - } - - void RunContext::handleUnexpectedInflightException( - AssertionInfo const& info, - std::string const& message, - AssertionReaction& reaction - ) { - m_lastAssertionInfo = info; - - AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); - data.message = message; - AssertionResult assertionResult{ info, CATCH_MOVE(data) }; - assertionEnded( assertionResult ); - populateReaction( reaction ); - } - - void RunContext::populateReaction( AssertionReaction& reaction ) { - reaction.shouldDebugBreak = m_config->shouldDebugBreak(); - reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); - } - - void RunContext::handleIncomplete( - AssertionInfo const& info - ) { - using namespace std::string_literals; - m_lastAssertionInfo = info; - - AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); - data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s; - AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; - assertionEnded( assertionResult ); - } - void RunContext::handleNonExpr( - AssertionInfo const &info, - ResultWas::OfType resultType, - AssertionReaction &reaction - ) { - m_lastAssertionInfo = info; - - AssertionResultData data( resultType, LazyExpression( false ) ); - AssertionResult assertionResult{ info, CATCH_MOVE( data ) }; - assertionEnded( assertionResult ); - - if( !assertionResult.isOk() ) - populateReaction( reaction ); - } - - - IResultCapture& getResultCapture() { - if (auto* capture = getCurrentContext().getResultCapture()) - return *capture; - else - CATCH_INTERNAL_ERROR("No result capture instance"); - } - - void seedRng(IConfig const& config) { - sharedRng().seed(config.rngSeed()); - } - - unsigned int rngSeed() { - return getCurrentContext().getConfig()->rngSeed(); - } - -} - - - -namespace Catch { - - Section::Section( SectionInfo&& info ): - m_info( CATCH_MOVE( info ) ), - m_sectionIncluded( - getResultCapture().sectionStarted( m_info.name, m_info.lineInfo, m_assertions ) ) { - // Non-"included" sections will not use the timing information - // anyway, so don't bother with the potential syscall. - if (m_sectionIncluded) { - m_timer.start(); - } - } - - Section::Section( SourceLineInfo const& _lineInfo, - StringRef _name, - const char* const ): - m_info( { "invalid", static_cast( -1 ) }, std::string{} ), - m_sectionIncluded( - getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) { - // We delay initialization the SectionInfo member until we know - // this section needs it, so we avoid allocating std::string for name. - // We also delay timer start to avoid the potential syscall unless we - // will actually use the result. - if ( m_sectionIncluded ) { - m_info.name = static_cast( _name ); - m_info.lineInfo = _lineInfo; - m_timer.start(); - } - } - - Section::~Section() { - if( m_sectionIncluded ) { - SectionEndInfo endInfo{ CATCH_MOVE(m_info), m_assertions, m_timer.getElapsedSeconds() }; - if ( uncaught_exceptions() ) { - getResultCapture().sectionEndedEarly( CATCH_MOVE(endInfo) ); - } else { - getResultCapture().sectionEnded( CATCH_MOVE( endInfo ) ); - } - } - } - - // This indicates whether the section should be executed or not - Section::operator bool() const { - return m_sectionIncluded; - } - - -} // end namespace Catch - - - -#include - -namespace Catch { - - namespace { - static auto getSingletons() -> std::vector*& { - static std::vector* g_singletons = nullptr; - if( !g_singletons ) - g_singletons = new std::vector(); - return g_singletons; - } - } - - ISingleton::~ISingleton() = default; - - void addSingleton(ISingleton* singleton ) { - getSingletons()->push_back( singleton ); - } - void cleanupSingletons() { - auto& singletons = getSingletons(); - for( auto singleton : *singletons ) - delete singleton; - delete singletons; - singletons = nullptr; - } - -} // namespace Catch - - - -#include -#include - -namespace Catch { - - bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { - return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); - } - bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { - // We can assume that the same file will usually have the same pointer. - // Thus, if the pointers are the same, there is no point in calling the strcmp - return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0)); - } - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { -#ifndef __GNUG__ - os << info.file << '(' << info.line << ')'; -#else - os << info.file << ':' << info.line; -#endif - return os; - } - -} // end namespace Catch - - - - -namespace Catch { -#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { - CATCH_TRY { - m_exceptions.push_back(exception); - } CATCH_CATCH_ALL { - // If we run out of memory during start-up there's really not a lot more we can do about it - std::terminate(); - } - } - - std::vector const& StartupExceptionRegistry::getExceptions() const noexcept { - return m_exceptions; - } -#endif - -} // end namespace Catch - - - - - -#include - -namespace Catch { - -// If you #define this you must implement these functions -#if !defined( CATCH_CONFIG_NOSTDOUT ) - std::ostream& cout() { return std::cout; } - std::ostream& cerr() { return std::cerr; } - std::ostream& clog() { return std::clog; } -#endif - -} // namespace Catch - - - -#include -#include -#include -#include -#include - -namespace Catch { - - bool startsWith( std::string const& s, std::string const& prefix ) { - return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); - } - bool startsWith( StringRef s, char prefix ) { - return !s.empty() && s[0] == prefix; - } - bool endsWith( std::string const& s, std::string const& suffix ) { - return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); - } - bool endsWith( std::string const& s, char suffix ) { - return !s.empty() && s[s.size()-1] == suffix; - } - bool contains( std::string const& s, std::string const& infix ) { - return s.find( infix ) != std::string::npos; - } - void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), []( char c ) { - return toLower( c ); - } ); - } - std::string toLower( std::string const& s ) { - std::string lc = s; - toLowerInPlace( lc ); - return lc; - } - char toLower(char c) { - return static_cast(std::tolower(static_cast(c))); - } - - std::string trim( std::string const& str ) { - static char const* whitespaceChars = "\n\r\t "; - std::string::size_type start = str.find_first_not_of( whitespaceChars ); - std::string::size_type end = str.find_last_not_of( whitespaceChars ); - - return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); - } - - StringRef trim(StringRef ref) { - const auto is_ws = [](char c) { - return c == ' ' || c == '\t' || c == '\n' || c == '\r'; - }; - size_t real_begin = 0; - while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; } - size_t real_end = ref.size(); - while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; } - - return ref.substr(real_begin, real_end - real_begin); - } - - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { - bool replaced = false; - std::size_t i = str.find( replaceThis ); - while( i != std::string::npos ) { - replaced = true; - str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); - if( i < str.size()-withThis.size() ) - i = str.find( replaceThis, i+withThis.size() ); - else - i = std::string::npos; - } - return replaced; - } - - std::vector splitStringRef( StringRef str, char delimiter ) { - std::vector subStrings; - std::size_t start = 0; - for(std::size_t pos = 0; pos < str.size(); ++pos ) { - if( str[pos] == delimiter ) { - if( pos - start > 1 ) - subStrings.push_back( str.substr( start, pos-start ) ); - start = pos+1; - } - } - if( start < str.size() ) - subStrings.push_back( str.substr( start, str.size()-start ) ); - return subStrings; - } - - std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { - os << pluraliser.m_count << ' ' << pluraliser.m_label; - if( pluraliser.m_count != 1 ) - os << 's'; - return os; - } - -} - - - -#include -#include -#include -#include - -namespace Catch { - StringRef::StringRef( char const* rawChars ) noexcept - : StringRef( rawChars, std::strlen(rawChars) ) - {} - - - bool StringRef::operator<(StringRef rhs) const noexcept { - if (m_size < rhs.m_size) { - return strncmp(m_start, rhs.m_start, m_size) <= 0; - } - return strncmp(m_start, rhs.m_start, rhs.m_size) < 0; - } - - int StringRef::compare( StringRef rhs ) const { - auto cmpResult = - strncmp( m_start, rhs.m_start, std::min( m_size, rhs.m_size ) ); - - // This means that strncmp found a difference before the strings - // ended, and we can return it directly - if ( cmpResult != 0 ) { - return cmpResult; - } - - // If strings are equal up to length, then their comparison results on - // their size - if ( m_size < rhs.m_size ) { - return -1; - } else if ( m_size > rhs.m_size ) { - return 1; - } else { - return 0; - } - } - - auto operator << ( std::ostream& os, StringRef str ) -> std::ostream& { - return os.write(str.data(), static_cast(str.size())); - } - - std::string operator+(StringRef lhs, StringRef rhs) { - std::string ret; - ret.reserve(lhs.size() + rhs.size()); - ret += lhs; - ret += rhs; - return ret; - } - - auto operator+=( std::string& lhs, StringRef rhs ) -> std::string& { - lhs.append(rhs.data(), rhs.size()); - return lhs; - } - -} // namespace Catch - - - -namespace Catch { - - TagAliasRegistry::~TagAliasRegistry() {} - - TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { - auto it = m_registry.find( alias ); - if( it != m_registry.end() ) - return &(it->second); - else - return nullptr; - } - - std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { - std::string expandedTestSpec = unexpandedTestSpec; - for( auto const& registryKvp : m_registry ) { - std::size_t pos = expandedTestSpec.find( registryKvp.first ); - if( pos != std::string::npos ) { - expandedTestSpec = expandedTestSpec.substr( 0, pos ) + - registryKvp.second.tag + - expandedTestSpec.substr( pos + registryKvp.first.size() ); - } - } - return expandedTestSpec; - } - - void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { - CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), - "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); - - CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, - "error: tag alias, '" << alias << "' already registered.\n" - << "\tFirst seen at: " << find(alias)->lineInfo << "\n" - << "\tRedefined at: " << lineInfo ); - } - - ITagAliasRegistry::~ITagAliasRegistry() = default; - - ITagAliasRegistry const& ITagAliasRegistry::get() { - return getRegistryHub().getTagAliasRegistry(); - } - -} // end namespace Catch - - - - -namespace Catch { - TestCaseInfoHasher::TestCaseInfoHasher( hash_t seed ): m_seed( seed ) {} - - uint32_t TestCaseInfoHasher::operator()( TestCaseInfo const& t ) const { - // FNV-1a hash algorithm that is designed for uniqueness: - const hash_t prime = 1099511628211u; - hash_t hash = 14695981039346656037u; - for ( const char c : t.name ) { - hash ^= c; - hash *= prime; - } - for ( const char c : t.className ) { - hash ^= c; - hash *= prime; - } - for ( const Tag& tag : t.tags ) { - for ( const char c : tag.original ) { - hash ^= c; - hash *= prime; - } - } - hash ^= m_seed; - hash *= prime; - const uint32_t low{ static_cast( hash ) }; - const uint32_t high{ static_cast( hash >> 32 ) }; - return low * high; - } -} // namespace Catch - - - - -#include -#include - -namespace Catch { - - std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { - switch (config.runOrder()) { - case TestRunOrder::Declared: - return unsortedTestCases; - - case TestRunOrder::LexicographicallySorted: { - std::vector sorted = unsortedTestCases; - std::sort( - sorted.begin(), - sorted.end(), - []( TestCaseHandle const& lhs, TestCaseHandle const& rhs ) { - return lhs.getTestCaseInfo() < rhs.getTestCaseInfo(); - } - ); - return sorted; - } - case TestRunOrder::Randomized: { - seedRng(config); - using TestWithHash = std::pair; - - TestCaseInfoHasher h{ config.rngSeed() }; - std::vector indexed_tests; - indexed_tests.reserve(unsortedTestCases.size()); - - for (auto const& handle : unsortedTestCases) { - indexed_tests.emplace_back(h(handle.getTestCaseInfo()), handle); - } - - std::sort( indexed_tests.begin(), - indexed_tests.end(), - []( TestWithHash const& lhs, TestWithHash const& rhs ) { - if ( lhs.first == rhs.first ) { - return lhs.second.getTestCaseInfo() < - rhs.second.getTestCaseInfo(); - } - return lhs.first < rhs.first; - } ); - - std::vector randomized; - randomized.reserve(indexed_tests.size()); - - for (auto const& indexed : indexed_tests) { - randomized.push_back(indexed.second); - } - - return randomized; - } - } - - CATCH_INTERNAL_ERROR("Unknown test order value!"); - } - - bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ) { - return !testCase.getTestCaseInfo().throws() || config.allowThrows(); - } - - bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ) { - return testSpec.matches( testCase.getTestCaseInfo() ) && isThrowSafe( testCase, config ); - } - - void - enforceNoDuplicateTestCases( std::vector const& tests ) { - auto testInfoCmp = []( TestCaseInfo const* lhs, - TestCaseInfo const* rhs ) { - return *lhs < *rhs; - }; - std::set seenTests(testInfoCmp); - for ( auto const& test : tests ) { - const auto infoPtr = &test.getTestCaseInfo(); - const auto prev = seenTests.insert( infoPtr ); - CATCH_ENFORCE( - prev.second, - "error: test case \"" << infoPtr->name << "\", with tags \"" - << infoPtr->tagsAsString() << "\" already defined.\n" - << "\tFirst seen at " << ( *prev.first )->lineInfo << "\n" - << "\tRedefined at " << infoPtr->lineInfo ); - } - } - - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { - std::vector filtered; - filtered.reserve( testCases.size() ); - for (auto const& testCase : testCases) { - if ((!testSpec.hasFilters() && !testCase.getTestCaseInfo().isHidden()) || - (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) { - filtered.push_back(testCase); - } - } - return createShard(filtered, config.shardCount(), config.shardIndex()); - } - std::vector const& getAllTestCasesSorted( IConfig const& config ) { - return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); - } - - void TestRegistry::registerTest(Detail::unique_ptr testInfo, Detail::unique_ptr testInvoker) { - m_handles.emplace_back(testInfo.get(), testInvoker.get()); - m_viewed_test_infos.push_back(testInfo.get()); - m_owned_test_infos.push_back(CATCH_MOVE(testInfo)); - m_invokers.push_back(CATCH_MOVE(testInvoker)); - } - - std::vector const& TestRegistry::getAllInfos() const { - return m_viewed_test_infos; - } - - std::vector const& TestRegistry::getAllTests() const { - return m_handles; - } - std::vector const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { - if( m_sortedFunctions.empty() ) - enforceNoDuplicateTestCases( m_handles ); - - if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { - m_sortedFunctions = sortTests( config, m_handles ); - m_currentSortOrder = config.runOrder(); - } - return m_sortedFunctions; - } - - - - /////////////////////////////////////////////////////////////////////////// - void TestInvokerAsFunction::invoke() const { - m_testAsFunction(); - } - -} // end namespace Catch - - - - -#include -#include - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - -namespace Catch { -namespace TestCaseTracking { - - NameAndLocation::NameAndLocation( std::string&& _name, SourceLineInfo const& _location ) - : name( CATCH_MOVE(_name) ), - location( _location ) - {} - - - ITracker::~ITracker() = default; - - void ITracker::markAsNeedingAnotherRun() { - m_runState = NeedsAnotherRun; - } - - void ITracker::addChild( ITrackerPtr&& child ) { - m_children.push_back( CATCH_MOVE(child) ); - } - - ITracker* ITracker::findChild( NameAndLocationRef const& nameAndLocation ) { - auto it = std::find_if( - m_children.begin(), - m_children.end(), - [&nameAndLocation]( ITrackerPtr const& tracker ) { - auto const& tnameAndLoc = tracker->nameAndLocation(); - if ( tnameAndLoc.location.line != - nameAndLocation.location.line ) { - return false; - } - return tnameAndLoc == nameAndLocation; - } ); - return ( it != m_children.end() ) ? it->get() : nullptr; - } - - bool ITracker::isSectionTracker() const { return false; } - bool ITracker::isGeneratorTracker() const { return false; } - - bool ITracker::isOpen() const { - return m_runState != NotStarted && !isComplete(); - } - - bool ITracker::hasStarted() const { return m_runState != NotStarted; } - - void ITracker::openChild() { - if (m_runState != ExecutingChildren) { - m_runState = ExecutingChildren; - if (m_parent) { - m_parent->openChild(); - } - } - } - - ITracker& TrackerContext::startRun() { - using namespace std::string_literals; - m_rootTracker = Catch::Detail::make_unique( - NameAndLocation( "{root}"s, CATCH_INTERNAL_LINEINFO ), - *this, - nullptr ); - m_currentTracker = nullptr; - m_runState = Executing; - return *m_rootTracker; - } - - void TrackerContext::completeCycle() { - m_runState = CompletedCycle; - } - - bool TrackerContext::completedCycle() const { - return m_runState == CompletedCycle; - } - void TrackerContext::setCurrentTracker( ITracker* tracker ) { - m_currentTracker = tracker; - } - - - TrackerBase::TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ): - ITracker(CATCH_MOVE(nameAndLocation), parent), - m_ctx( ctx ) - {} - - bool TrackerBase::isComplete() const { - return m_runState == CompletedSuccessfully || m_runState == Failed; - } - - void TrackerBase::open() { - m_runState = Executing; - moveToThis(); - if( m_parent ) - m_parent->openChild(); - } - - void TrackerBase::close() { - - // Close any still open children (e.g. generators) - while( &m_ctx.currentTracker() != this ) - m_ctx.currentTracker().close(); - - switch( m_runState ) { - case NeedsAnotherRun: - break; - - case Executing: - m_runState = CompletedSuccessfully; - break; - case ExecutingChildren: - if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) ) - m_runState = CompletedSuccessfully; - break; - - case NotStarted: - case CompletedSuccessfully: - case Failed: - CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); - - default: - CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); - } - moveToParent(); - m_ctx.completeCycle(); - } - void TrackerBase::fail() { - m_runState = Failed; - if( m_parent ) - m_parent->markAsNeedingAnotherRun(); - moveToParent(); - m_ctx.completeCycle(); - } - - void TrackerBase::moveToParent() { - assert( m_parent ); - m_ctx.setCurrentTracker( m_parent ); - } - void TrackerBase::moveToThis() { - m_ctx.setCurrentTracker( this ); - } - - SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ), - m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name))) - { - if( parent ) { - while ( !parent->isSectionTracker() ) { - parent = parent->parent(); - } - - SectionTracker& parentSection = static_cast( *parent ); - addNextFilters( parentSection.m_filters ); - } - } - - bool SectionTracker::isComplete() const { - bool complete = true; - - if (m_filters.empty() - || m_filters[0].empty() - || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { - complete = TrackerBase::isComplete(); - } - return complete; - } - - bool SectionTracker::isSectionTracker() const { return true; } - - SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ) { - SectionTracker* tracker; - - ITracker& currentTracker = ctx.currentTracker(); - if ( ITracker* childTracker = - currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isSectionTracker() ); - tracker = static_cast( childTracker ); - } else { - auto newTracker = Catch::Detail::make_unique( - NameAndLocation{ static_cast(nameAndLocation.name), - nameAndLocation.location }, - ctx, - ¤tTracker ); - tracker = newTracker.get(); - currentTracker.addChild( CATCH_MOVE( newTracker ) ); - } - - if ( !ctx.completedCycle() ) { - tracker->tryOpen(); - } - - return *tracker; - } - - void SectionTracker::tryOpen() { - if( !isComplete() ) - open(); - } - - void SectionTracker::addInitialFilters( std::vector const& filters ) { - if( !filters.empty() ) { - m_filters.reserve( m_filters.size() + filters.size() + 2 ); - m_filters.emplace_back(StringRef{}); // Root - should never be consulted - m_filters.emplace_back(StringRef{}); // Test Case - not a section filter - m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); - } - } - void SectionTracker::addNextFilters( std::vector const& filters ) { - if( filters.size() > 1 ) - m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); - } - - StringRef SectionTracker::trimmedName() const { - return m_trimmed_name; - } - -} // namespace TestCaseTracking - -} // namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - - - - -namespace Catch { - - void throw_test_failure_exception() { -#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) - throw TestFailureException{}; -#else - CATCH_ERROR( "Test failure requires aborting test!" ); -#endif - } - -} // namespace Catch - - - -#include -#include - -namespace Catch { - - namespace { - StringRef extractClassName( StringRef classOrMethodName ) { - if ( !startsWith( classOrMethodName, '&' ) ) { - return classOrMethodName; - } - - // Remove the leading '&' to avoid having to special case it later - const auto methodName = - classOrMethodName.substr( 1, classOrMethodName.size() ); - - auto reverseStart = std::make_reverse_iterator( methodName.end() ); - auto reverseEnd = std::make_reverse_iterator( methodName.begin() ); - - // We make a simplifying assumption that ":" is only present - // in the input as part of "::" from C++ typenames (this is - // relatively safe assumption because the input is generated - // as stringification of type through preprocessor). - auto lastColons = std::find( reverseStart, reverseEnd, ':' ) + 1; - auto secondLastColons = - std::find( lastColons + 1, reverseEnd, ':' ); - - auto const startIdx = reverseEnd - secondLastColons; - auto const classNameSize = secondLastColons - lastColons - 1; - - return methodName.substr( - static_cast( startIdx ), - static_cast( classNameSize ) ); - } - } // namespace - - Detail::unique_ptr makeTestInvoker( void(*testAsFunction)() ) { - return Detail::make_unique( testAsFunction ); - } - - AutoReg::AutoReg( Detail::unique_ptr invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept { - CATCH_TRY { - getMutableRegistryHub() - .registerTest( - makeTestCaseInfo( - extractClassName( classOrMethod ), - nameAndTags, - lineInfo), - CATCH_MOVE(invoker) - ); - } CATCH_CATCH_ALL { - // Do not throw when constructing global objects, instead register the exception to be processed later - getMutableRegistryHub().registerStartupException(); - } - } -} - - - - - -namespace Catch { - - TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} - - TestSpecParser& TestSpecParser::parse( std::string const& arg ) { - m_mode = None; - m_exclusion = false; - m_arg = m_tagAliases->expandAliases( arg ); - m_escapeChars.clear(); - m_substring.reserve(m_arg.size()); - m_patternName.reserve(m_arg.size()); - m_realPatternPos = 0; - - for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) - //if visitChar fails - if( !visitChar( m_arg[m_pos] ) ){ - m_testSpec.m_invalidSpecs.push_back(arg); - break; - } - endMode(); - return *this; - } - TestSpec TestSpecParser::testSpec() { - addFilter(); - return CATCH_MOVE(m_testSpec); - } - bool TestSpecParser::visitChar( char c ) { - if( (m_mode != EscapedName) && (c == '\\') ) { - escape(); - addCharToPattern(c); - return true; - }else if((m_mode != EscapedName) && (c == ',') ) { - return separate(); - } - - switch( m_mode ) { - case None: - if( processNoneChar( c ) ) - return true; - break; - case Name: - processNameChar( c ); - break; - case EscapedName: - endMode(); - addCharToPattern(c); - return true; - default: - case Tag: - case QuotedName: - if( processOtherChar( c ) ) - return true; - break; - } - - m_substring += c; - if( !isControlChar( c ) ) { - m_patternName += c; - m_realPatternPos++; - } - return true; - } - // Two of the processing methods return true to signal the caller to return - // without adding the given character to the current pattern strings - bool TestSpecParser::processNoneChar( char c ) { - switch( c ) { - case ' ': - return true; - case '~': - m_exclusion = true; - return false; - case '[': - startNewMode( Tag ); - return false; - case '"': - startNewMode( QuotedName ); - return false; - default: - startNewMode( Name ); - return false; - } - } - void TestSpecParser::processNameChar( char c ) { - if( c == '[' ) { - if( m_substring == "exclude:" ) - m_exclusion = true; - else - endMode(); - startNewMode( Tag ); - } - } - bool TestSpecParser::processOtherChar( char c ) { - if( !isControlChar( c ) ) - return false; - m_substring += c; - endMode(); - return true; - } - void TestSpecParser::startNewMode( Mode mode ) { - m_mode = mode; - } - void TestSpecParser::endMode() { - switch( m_mode ) { - case Name: - case QuotedName: - return addNamePattern(); - case Tag: - return addTagPattern(); - case EscapedName: - revertBackToLastMode(); - return; - case None: - default: - return startNewMode( None ); - } - } - void TestSpecParser::escape() { - saveLastMode(); - m_mode = EscapedName; - m_escapeChars.push_back(m_realPatternPos); - } - bool TestSpecParser::isControlChar( char c ) const { - switch( m_mode ) { - default: - return false; - case None: - return c == '~'; - case Name: - return c == '['; - case EscapedName: - return true; - case QuotedName: - return c == '"'; - case Tag: - return c == '[' || c == ']'; - } - } - - void TestSpecParser::addFilter() { - if( !m_currentFilter.m_required.empty() || !m_currentFilter.m_forbidden.empty() ) { - m_testSpec.m_filters.push_back( CATCH_MOVE(m_currentFilter) ); - m_currentFilter = TestSpec::Filter(); - } - } - - void TestSpecParser::saveLastMode() { - lastMode = m_mode; - } - - void TestSpecParser::revertBackToLastMode() { - m_mode = lastMode; - } - - bool TestSpecParser::separate() { - if( (m_mode==QuotedName) || (m_mode==Tag) ){ - //invalid argument, signal failure to previous scope. - m_mode = None; - m_pos = m_arg.size(); - m_substring.clear(); - m_patternName.clear(); - m_realPatternPos = 0; - return false; - } - endMode(); - addFilter(); - return true; //success - } - - std::string TestSpecParser::preprocessPattern() { - std::string token = m_patternName; - for (std::size_t i = 0; i < m_escapeChars.size(); ++i) - token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1); - m_escapeChars.clear(); - if (startsWith(token, "exclude:")) { - m_exclusion = true; - token = token.substr(8); - } - - m_patternName.clear(); - m_realPatternPos = 0; - - return token; - } - - void TestSpecParser::addNamePattern() { - auto token = preprocessPattern(); - - if (!token.empty()) { - if (m_exclusion) { - m_currentFilter.m_forbidden.emplace_back(Detail::make_unique(token, m_substring)); - } else { - m_currentFilter.m_required.emplace_back(Detail::make_unique(token, m_substring)); - } - } - m_substring.clear(); - m_exclusion = false; - m_mode = None; - } - - void TestSpecParser::addTagPattern() { - auto token = preprocessPattern(); - - if (!token.empty()) { - // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo]) - // we have to create a separate hide tag and shorten the real one - if (token.size() > 1 && token[0] == '.') { - token.erase(token.begin()); - if (m_exclusion) { - m_currentFilter.m_forbidden.emplace_back(Detail::make_unique(".", m_substring)); - } else { - m_currentFilter.m_required.emplace_back(Detail::make_unique(".", m_substring)); - } - } - if (m_exclusion) { - m_currentFilter.m_forbidden.emplace_back(Detail::make_unique(token, m_substring)); - } else { - m_currentFilter.m_required.emplace_back(Detail::make_unique(token, m_substring)); - } - } - m_substring.clear(); - m_exclusion = false; - m_mode = None; - } - -} // namespace Catch - - - -#include -#include -#include - -namespace { - bool isWhitespace( char c ) { - return c == ' ' || c == '\t' || c == '\n' || c == '\r'; - } - - bool isBreakableBefore( char c ) { - static const char chars[] = "[({<|"; - return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr; - } - - bool isBreakableAfter( char c ) { - static const char chars[] = "])}>.,:;*+-=&/\\"; - return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr; - } - - bool isBoundary( std::string const& line, size_t at ) { - assert( at > 0 ); - assert( at <= line.size() ); - - return at == line.size() || - ( isWhitespace( line[at] ) && !isWhitespace( line[at - 1] ) ) || - isBreakableBefore( line[at] ) || - isBreakableAfter( line[at - 1] ); - } - -} // namespace - -namespace Catch { - namespace TextFlow { - - void Column::const_iterator::calcLength() { - m_addHyphen = false; - m_parsedTo = m_lineStart; - - std::string const& current_line = m_column.m_string; - if ( current_line[m_lineStart] == '\n' ) { - ++m_parsedTo; - } - - const auto maxLineLength = m_column.m_width - indentSize(); - const auto maxParseTo = std::min(current_line.size(), m_lineStart + maxLineLength); - while ( m_parsedTo < maxParseTo && - current_line[m_parsedTo] != '\n' ) { - ++m_parsedTo; - } - - // If we encountered a newline before the column is filled, - // then we linebreak at the newline and consider this line - // finished. - if ( m_parsedTo < m_lineStart + maxLineLength ) { - m_lineLength = m_parsedTo - m_lineStart; - } else { - // Look for a natural linebreak boundary in the column - // (We look from the end, so that the first found boundary is - // the right one) - size_t newLineLength = maxLineLength; - while ( newLineLength > 0 && !isBoundary( current_line, m_lineStart + newLineLength ) ) { - --newLineLength; - } - while ( newLineLength > 0 && - isWhitespace( current_line[m_lineStart + newLineLength - 1] ) ) { - --newLineLength; - } - - // If we found one, then that is where we linebreak - if ( newLineLength > 0 ) { - m_lineLength = newLineLength; - } else { - // Otherwise we have to split text with a hyphen - m_addHyphen = true; - m_lineLength = maxLineLength - 1; - } - } - } - - size_t Column::const_iterator::indentSize() const { - auto initial = - m_lineStart == 0 ? m_column.m_initialIndent : std::string::npos; - return initial == std::string::npos ? m_column.m_indent : initial; - } - - std::string - Column::const_iterator::addIndentAndSuffix( size_t position, - size_t length ) const { - std::string ret; - const auto desired_indent = indentSize(); - ret.reserve( desired_indent + length + m_addHyphen ); - ret.append( desired_indent, ' ' ); - ret.append( m_column.m_string, position, length ); - if ( m_addHyphen ) { - ret.push_back( '-' ); - } - - return ret; - } - - Column::const_iterator::const_iterator( Column const& column ): m_column( column ) { - assert( m_column.m_width > m_column.m_indent ); - assert( m_column.m_initialIndent == std::string::npos || - m_column.m_width > m_column.m_initialIndent ); - calcLength(); - if ( m_lineLength == 0 ) { - m_lineStart = m_column.m_string.size(); - } - } - - std::string Column::const_iterator::operator*() const { - assert( m_lineStart <= m_parsedTo ); - return addIndentAndSuffix( m_lineStart, m_lineLength ); - } - - Column::const_iterator& Column::const_iterator::operator++() { - m_lineStart += m_lineLength; - std::string const& current_line = m_column.m_string; - if ( m_lineStart < current_line.size() && current_line[m_lineStart] == '\n' ) { - m_lineStart += 1; - } else { - while ( m_lineStart < current_line.size() && - isWhitespace( current_line[m_lineStart] ) ) { - ++m_lineStart; - } - } - - if ( m_lineStart != current_line.size() ) { - calcLength(); - } - return *this; - } - - Column::const_iterator Column::const_iterator::operator++( int ) { - const_iterator prev( *this ); - operator++(); - return prev; - } - - std::ostream& operator<<( std::ostream& os, Column const& col ) { - bool first = true; - for ( auto line : col ) { - if ( first ) { - first = false; - } else { - os << '\n'; - } - os << line; - } - return os; - } - - Column Spacer( size_t spaceWidth ) { - Column ret{ "" }; - ret.width( spaceWidth ); - return ret; - } - - Columns::iterator::iterator( Columns const& columns, EndTag ): - m_columns( columns.m_columns ), m_activeIterators( 0 ) { - - m_iterators.reserve( m_columns.size() ); - for ( auto const& col : m_columns ) { - m_iterators.push_back( col.end() ); - } - } - - Columns::iterator::iterator( Columns const& columns ): - m_columns( columns.m_columns ), - m_activeIterators( m_columns.size() ) { - - m_iterators.reserve( m_columns.size() ); - for ( auto const& col : m_columns ) { - m_iterators.push_back( col.begin() ); - } - } - - std::string Columns::iterator::operator*() const { - std::string row, padding; - - for ( size_t i = 0; i < m_columns.size(); ++i ) { - const auto width = m_columns[i].width(); - if ( m_iterators[i] != m_columns[i].end() ) { - std::string col = *m_iterators[i]; - row += padding; - row += col; - - padding.clear(); - if ( col.size() < width ) { - padding.append( width - col.size(), ' ' ); - } - } else { - padding.append( width, ' ' ); - } - } - return row; - } - - Columns::iterator& Columns::iterator::operator++() { - for ( size_t i = 0; i < m_columns.size(); ++i ) { - if ( m_iterators[i] != m_columns[i].end() ) { - ++m_iterators[i]; - } - } - return *this; - } - - Columns::iterator Columns::iterator::operator++( int ) { - iterator prev( *this ); - operator++(); - return prev; - } - - std::ostream& operator<<( std::ostream& os, Columns const& cols ) { - bool first = true; - for ( auto line : cols ) { - if ( first ) { - first = false; - } else { - os << '\n'; - } - os << line; - } - return os; - } - - Columns Column::operator+( Column const& other ) { - Columns cols; - cols += *this; - cols += other; - return cols; - } - - Columns& Columns::operator+=( Column const& col ) { - m_columns.push_back( col ); - return *this; - } - - Columns Columns::operator+( Column const& col ) { - Columns combined = *this; - combined += col; - return combined; - } - - } // namespace TextFlow -} // namespace Catch - - - - -#include - -namespace Catch { - bool uncaught_exceptions() { -#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - return false; -#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) - return std::uncaught_exceptions() > 0; -#else - return std::uncaught_exception(); -#endif - } -} // end namespace Catch - - - -namespace Catch { - - WildcardPattern::WildcardPattern( std::string const& pattern, - CaseSensitive caseSensitivity ) - : m_caseSensitivity( caseSensitivity ), - m_pattern( normaliseString( pattern ) ) - { - if( startsWith( m_pattern, '*' ) ) { - m_pattern = m_pattern.substr( 1 ); - m_wildcard = WildcardAtStart; - } - if( endsWith( m_pattern, '*' ) ) { - m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); - m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); - } - } - - bool WildcardPattern::matches( std::string const& str ) const { - switch( m_wildcard ) { - case NoWildcard: - return m_pattern == normaliseString( str ); - case WildcardAtStart: - return endsWith( normaliseString( str ), m_pattern ); - case WildcardAtEnd: - return startsWith( normaliseString( str ), m_pattern ); - case WildcardAtBothEnds: - return contains( normaliseString( str ), m_pattern ); - default: - CATCH_INTERNAL_ERROR( "Unknown enum" ); - } - } - - std::string WildcardPattern::normaliseString( std::string const& str ) const { - return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str ); - } -} - - -// Note: swapping these two includes around causes MSVC to error out -// while in /permissive- mode. No, I don't know why. -// Tested on VS 2019, 18.{3, 4}.x - -#include -#include -#include - -namespace Catch { - -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; - } - CATCH_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; - } - CATCH_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); - } - - bool shouldNewline(XmlFormatting fmt) { - return !!(static_cast>(fmt & XmlFormatting::Newline)); - } - - bool shouldIndent(XmlFormatting fmt) { - return !!(static_cast>(fmt & XmlFormatting::Indent)); - } - -} // anonymous namespace - - XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) { - return static_cast( - static_cast>(lhs) | - static_cast>(rhs) - ); - } - - XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) { - return static_cast( - static_cast>(lhs) & - static_cast>(rhs) - ); - } - - - XmlEncode::XmlEncode( StringRef 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: http://www.w3.org/TR/xml/#syntax) - - for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { - unsigned char c = static_cast(m_str[idx]); - switch (c) { - case '<': os << "<"; break; - case '&': os << "&"; break; - - case '>': - // See: http://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 http://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) { - unsigned char nc = static_cast(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) || - (0x80 <= value && value < 0x800 && encBytes > 2) || - (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, XmlFormatting fmt ) - : m_writer( writer ), - m_fmt(fmt) - {} - - XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept - : m_writer( other.m_writer ), - m_fmt(other.m_fmt) - { - other.m_writer = nullptr; - other.m_fmt = XmlFormatting::None; - } - XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { - if ( m_writer ) { - m_writer->endElement(); - } - m_writer = other.m_writer; - other.m_writer = nullptr; - m_fmt = other.m_fmt; - other.m_fmt = XmlFormatting::None; - return *this; - } - - - XmlWriter::ScopedElement::~ScopedElement() { - if (m_writer) { - m_writer->endElement(m_fmt); - } - } - - XmlWriter::ScopedElement& - XmlWriter::ScopedElement::writeText( StringRef text, XmlFormatting fmt ) { - m_writer->writeText( text, fmt ); - return *this; - } - - XmlWriter::ScopedElement& - XmlWriter::ScopedElement::writeAttribute( StringRef name, - StringRef attribute ) { - m_writer->writeAttribute( name, attribute ); - return *this; - } - - - XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) - { - writeDeclaration(); - } - - XmlWriter::~XmlWriter() { - while (!m_tags.empty()) { - endElement(); - } - newlineIfNecessary(); - } - - XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) { - ensureTagClosed(); - newlineIfNecessary(); - if (shouldIndent(fmt)) { - m_os << m_indent; - m_indent += " "; - } - m_os << '<' << name; - m_tags.push_back( name ); - m_tagIsOpen = true; - applyFormatting(fmt); - return *this; - } - - XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) { - ScopedElement scoped( this, fmt ); - startElement( name, fmt ); - return scoped; - } - - XmlWriter& XmlWriter::endElement(XmlFormatting fmt) { - m_indent = m_indent.substr(0, m_indent.size() - 2); - - if( m_tagIsOpen ) { - m_os << "/>"; - m_tagIsOpen = false; - } else { - newlineIfNecessary(); - if (shouldIndent(fmt)) { - m_os << m_indent; - } - m_os << "'; - } - m_os << std::flush; - applyFormatting(fmt); - m_tags.pop_back(); - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( StringRef name, - StringRef attribute ) { - if( !name.empty() && !attribute.empty() ) - m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( StringRef name, bool attribute ) { - writeAttribute(name, (attribute ? "true"_sr : "false"_sr)); - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( StringRef name, - char const* attribute ) { - writeAttribute( name, StringRef( attribute ) ); - return *this; - } - - XmlWriter& XmlWriter::writeText( StringRef text, XmlFormatting fmt ) { - CATCH_ENFORCE(!m_tags.empty(), "Cannot write text as top level element"); - if( !text.empty() ){ - bool tagWasOpen = m_tagIsOpen; - ensureTagClosed(); - if (tagWasOpen && shouldIndent(fmt)) { - m_os << m_indent; - } - m_os << XmlEncode( text, XmlEncode::ForTextNodes ); - applyFormatting(fmt); - } - return *this; - } - - XmlWriter& XmlWriter::writeComment( StringRef text, XmlFormatting fmt ) { - ensureTagClosed(); - if (shouldIndent(fmt)) { - m_os << m_indent; - } - m_os << ""; - applyFormatting(fmt); - return *this; - } - - void XmlWriter::writeStylesheetRef( StringRef url ) { - m_os << R"()" << '\n'; - } - - void XmlWriter::ensureTagClosed() { - if( m_tagIsOpen ) { - m_os << '>' << std::flush; - newlineIfNecessary(); - m_tagIsOpen = false; - } - } - - void XmlWriter::applyFormatting(XmlFormatting fmt) { - m_needsNewline = shouldNewline(fmt); - } - - void XmlWriter::writeDeclaration() { - m_os << R"()" << '\n'; - } - - void XmlWriter::newlineIfNecessary() { - if( m_needsNewline ) { - m_os << '\n' << std::flush; - m_needsNewline = false; - } - } -} - - - - - -namespace Catch { -namespace Matchers { - - std::string MatcherUntypedBase::toString() const { - if (m_cachedToString.empty()) { - m_cachedToString = describe(); - } - return m_cachedToString; - } - - MatcherUntypedBase::~MatcherUntypedBase() = default; - -} // namespace Matchers -} // namespace Catch - - - - -namespace Catch { -namespace Matchers { - - std::string IsEmptyMatcher::describe() const { - return "is empty"; - } - - std::string HasSizeMatcher::describe() const { - ReusableStringStream sstr; - sstr << "has size == " << m_target_size; - return sstr.str(); - } - - IsEmptyMatcher IsEmpty() { - return {}; - } - - HasSizeMatcher SizeIs(std::size_t sz) { - return HasSizeMatcher{ sz }; - } - -} // end namespace Matchers -} // end namespace Catch - - - -namespace Catch { -namespace Matchers { - -bool ExceptionMessageMatcher::match(std::exception const& ex) const { - return ex.what() == m_message; -} - -std::string ExceptionMessageMatcher::describe() const { - return "exception message matches \"" + m_message + '"'; -} - -ExceptionMessageMatcher Message(std::string const& message) { - return ExceptionMessageMatcher(message); -} - -} // namespace Matchers -} // namespace Catch - - - -#include -#include -#include -#include -#include -#include -#include - - -namespace Catch { -namespace { - - template - bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) { - // Comparison with NaN should always be false. - // This way we can rule it out before getting into the ugly details - if (Catch::isnan(lhs) || Catch::isnan(rhs)) { - return false; - } - - // This should also handle positive and negative zeros, infinities - const auto ulpDist = ulpDistance(lhs, rhs); - - return ulpDist <= maxUlpDiff; - } - -#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) - - float nextafter(float x, float y) { - return ::nextafterf(x, y); - } - - double nextafter(double x, double y) { - return ::nextafter(x, y); - } - -#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^ - -template -FP step(FP start, FP direction, uint64_t steps) { - for (uint64_t i = 0; i < steps; ++i) { -#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) - start = Catch::nextafter(start, direction); -#else - start = std::nextafter(start, direction); -#endif - } - return start; -} - -// Performs equivalent check of std::fabs(lhs - rhs) <= margin -// But without the subtraction to allow for INFINITY in comparison -bool marginComparison(double lhs, double rhs, double margin) { - return (lhs + margin >= rhs) && (rhs + margin >= lhs); -} - -template -void write(std::ostream& out, FloatingPoint num) { - out << std::scientific - << std::setprecision(std::numeric_limits::max_digits10 - 1) - << num; -} - -} // end anonymous namespace - -namespace Matchers { -namespace Detail { - - enum class FloatingPointKind : uint8_t { - Float, - Double - }; - -} // end namespace Detail - - - WithinAbsMatcher::WithinAbsMatcher(double target, double margin) - :m_target{ target }, m_margin{ margin } { - CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.' - << " Margin has to be non-negative."); - } - - // Performs equivalent check of std::fabs(lhs - rhs) <= margin - // But without the subtraction to allow for INFINITY in comparison - bool WithinAbsMatcher::match(double const& matchee) const { - return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); - } - - std::string WithinAbsMatcher::describe() const { - return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); - } - - - WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, Detail::FloatingPointKind baseType) - :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { - CATCH_ENFORCE(m_type == Detail::FloatingPointKind::Double - || m_ulps < (std::numeric_limits::max)(), - "Provided ULP is impossibly large for a float comparison."); - CATCH_ENFORCE( std::numeric_limits::is_iec559, - "WithinUlp matcher only supports platforms with " - "IEEE-754 compatible floating point representation" ); - } - -#if defined(__clang__) -#pragma clang diagnostic push -// Clang <3.5 reports on the default branch in the switch below -#pragma clang diagnostic ignored "-Wunreachable-code" -#endif - - bool WithinUlpsMatcher::match(double const& matchee) const { - switch (m_type) { - case Detail::FloatingPointKind::Float: - return almostEqualUlps(static_cast(matchee), static_cast(m_target), m_ulps); - case Detail::FloatingPointKind::Double: - return almostEqualUlps(matchee, m_target, m_ulps); - default: - CATCH_INTERNAL_ERROR( "Unknown Detail::FloatingPointKind value" ); - } - } - -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - - std::string WithinUlpsMatcher::describe() const { - std::stringstream ret; - - ret << "is within " << m_ulps << " ULPs of "; - - if (m_type == Detail::FloatingPointKind::Float) { - write(ret, static_cast(m_target)); - ret << 'f'; - } else { - write(ret, m_target); - } - - ret << " (["; - if (m_type == Detail::FloatingPointKind::Double) { - write( ret, - step( m_target, - -std::numeric_limits::infinity(), - m_ulps ) ); - ret << ", "; - write( ret, - step( m_target, - std::numeric_limits::infinity(), - m_ulps ) ); - } else { - // We have to cast INFINITY to float because of MinGW, see #1782 - write( ret, - step( static_cast( m_target ), - -std::numeric_limits::infinity(), - m_ulps ) ); - ret << ", "; - write( ret, - step( static_cast( m_target ), - std::numeric_limits::infinity(), - m_ulps ) ); - } - ret << "])"; - - return ret.str(); - } - - WithinRelMatcher::WithinRelMatcher(double target, double epsilon): - m_target(target), - m_epsilon(epsilon){ - CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense."); - CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense."); - } - - bool WithinRelMatcher::match(double const& matchee) const { - const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target)); - return marginComparison(matchee, m_target, - std::isinf(relMargin)? 0 : relMargin); - } - - std::string WithinRelMatcher::describe() const { - Catch::ReusableStringStream sstr; - sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other"; - return sstr.str(); - } - - -WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) { - return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Double); -} - -WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) { - return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Float); -} - -WithinAbsMatcher WithinAbs(double target, double margin) { - return WithinAbsMatcher(target, margin); -} - -WithinRelMatcher WithinRel(double target, double eps) { - return WithinRelMatcher(target, eps); -} - -WithinRelMatcher WithinRel(double target) { - return WithinRelMatcher(target, std::numeric_limits::epsilon() * 100); -} - -WithinRelMatcher WithinRel(float target, float eps) { - return WithinRelMatcher(target, eps); -} - -WithinRelMatcher WithinRel(float target) { - return WithinRelMatcher(target, std::numeric_limits::epsilon() * 100); -} - - - -bool IsNaNMatcher::match( double const& matchee ) const { - return std::isnan( matchee ); -} - -std::string IsNaNMatcher::describe() const { - using namespace std::string_literals; - return "is NaN"s; -} - -IsNaNMatcher IsNaN() { return IsNaNMatcher(); } - - } // namespace Matchers -} // namespace Catch - - - - -std::string Catch::Matchers::Detail::finalizeDescription(const std::string& desc) { - if (desc.empty()) { - return "matches undescribed predicate"; - } else { - return "matches predicate: \"" + desc + '"'; - } -} - - - -namespace Catch { - namespace Matchers { - std::string AllTrueMatcher::describe() const { return "contains only true"; } - - AllTrueMatcher AllTrue() { return AllTrueMatcher{}; } - - std::string NoneTrueMatcher::describe() const { return "contains no true"; } - - NoneTrueMatcher NoneTrue() { return NoneTrueMatcher{}; } - - std::string AnyTrueMatcher::describe() const { return "contains at least one true"; } - - AnyTrueMatcher AnyTrue() { return AnyTrueMatcher{}; } - } // namespace Matchers -} // namespace Catch - - - -#include - -namespace Catch { -namespace Matchers { - - CasedString::CasedString( std::string const& str, CaseSensitive caseSensitivity ) - : m_caseSensitivity( caseSensitivity ), - m_str( adjustString( str ) ) - {} - std::string CasedString::adjustString( std::string const& str ) const { - return m_caseSensitivity == CaseSensitive::No - ? toLower( str ) - : str; - } - StringRef CasedString::caseSensitivitySuffix() const { - return m_caseSensitivity == CaseSensitive::Yes - ? StringRef() - : " (case insensitive)"_sr; - } - - - StringMatcherBase::StringMatcherBase( StringRef operation, CasedString const& comparator ) - : m_comparator( comparator ), - m_operation( operation ) { - } - - std::string StringMatcherBase::describe() const { - std::string description; - description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + - m_comparator.caseSensitivitySuffix().size()); - description += m_operation; - description += ": \""; - description += m_comparator.m_str; - description += '"'; - description += m_comparator.caseSensitivitySuffix(); - return description; - } - - StringEqualsMatcher::StringEqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals"_sr, comparator ) {} - - bool StringEqualsMatcher::match( std::string const& source ) const { - return m_comparator.adjustString( source ) == m_comparator.m_str; - } - - - StringContainsMatcher::StringContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains"_sr, comparator ) {} - - bool StringContainsMatcher::match( std::string const& source ) const { - return contains( m_comparator.adjustString( source ), m_comparator.m_str ); - } - - - StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with"_sr, comparator ) {} - - bool StartsWithMatcher::match( std::string const& source ) const { - return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); - } - - - EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with"_sr, comparator ) {} - - bool EndsWithMatcher::match( std::string const& source ) const { - return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); - } - - - - RegexMatcher::RegexMatcher(std::string regex, CaseSensitive caseSensitivity): m_regex(CATCH_MOVE(regex)), m_caseSensitivity(caseSensitivity) {} - - bool RegexMatcher::match(std::string const& matchee) const { - auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway - if (m_caseSensitivity == CaseSensitive::No) { - flags |= std::regex::icase; - } - auto reg = std::regex(m_regex, flags); - return std::regex_match(matchee, reg); - } - - std::string RegexMatcher::describe() const { - return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Yes)? " case sensitively" : " case insensitively"); - } - - - StringEqualsMatcher Equals( std::string const& str, CaseSensitive caseSensitivity ) { - return StringEqualsMatcher( CasedString( str, caseSensitivity) ); - } - StringContainsMatcher ContainsSubstring( std::string const& str, CaseSensitive caseSensitivity ) { - return StringContainsMatcher( CasedString( str, caseSensitivity) ); - } - EndsWithMatcher EndsWith( std::string const& str, CaseSensitive caseSensitivity ) { - return EndsWithMatcher( CasedString( str, caseSensitivity) ); - } - StartsWithMatcher StartsWith( std::string const& str, CaseSensitive caseSensitivity ) { - return StartsWithMatcher( CasedString( str, caseSensitivity) ); - } - - RegexMatcher Matches(std::string const& regex, CaseSensitive caseSensitivity) { - return RegexMatcher(regex, caseSensitivity); - } - -} // namespace Matchers -} // namespace Catch - - - -namespace Catch { -namespace Matchers { - MatcherGenericBase::~MatcherGenericBase() = default; - - namespace Detail { - - std::string describe_multi_matcher(StringRef combine, std::string const* descriptions_begin, std::string const* descriptions_end) { - std::string description; - std::size_t combined_size = 4; - for ( auto desc = descriptions_begin; desc != descriptions_end; ++desc ) { - combined_size += desc->size(); - } - combined_size += static_cast(descriptions_end - descriptions_begin - 1) * combine.size(); - - description.reserve(combined_size); - - description += "( "; - bool first = true; - for( auto desc = descriptions_begin; desc != descriptions_end; ++desc ) { - if( first ) - first = false; - else - description += combine; - description += *desc; - } - description += " )"; - return description; - } - - } // namespace Detail -} // namespace Matchers -} // namespace Catch - - - - -namespace Catch { - - // This is the general overload that takes a any string matcher - // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers - // the Equals matcher (so the header does not mention matchers) - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher ) { - std::string exceptionMessage = Catch::translateActiveException(); - MatchExpr expr( CATCH_MOVE(exceptionMessage), matcher ); - handler.handleExpr( expr ); - } - -} // namespace Catch - - - -#include - -namespace Catch { - - AutomakeReporter::~AutomakeReporter() {} - - void AutomakeReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { - // Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR. - m_stream << ":test-result: "; - if ( _testCaseStats.totals.testCases.skipped > 0 ) { - m_stream << "SKIP"; - } else if (_testCaseStats.totals.assertions.allPassed()) { - m_stream << "PASS"; - } else if (_testCaseStats.totals.assertions.allOk()) { - m_stream << "XFAIL"; - } else { - m_stream << "FAIL"; - } - m_stream << ' ' << _testCaseStats.testInfo->name << '\n'; - StreamingReporterBase::testCaseEnded(_testCaseStats); - } - - void AutomakeReporter::skipTest(TestCaseInfo const& testInfo) { - m_stream << ":test-result: SKIP " << testInfo.name << '\n'; - } - -} // end namespace Catch - - - - - - -namespace Catch { - ReporterBase::ReporterBase( ReporterConfig&& config ): - IEventListener( config.fullConfig() ), - m_wrapped_stream( CATCH_MOVE(config).takeStream() ), - m_stream( m_wrapped_stream->stream() ), - m_colour( makeColourImpl( config.colourMode(), m_wrapped_stream.get() ) ), - m_customOptions( config.customOptions() ) - {} - - ReporterBase::~ReporterBase() = default; - - void ReporterBase::listReporters( - std::vector const& descriptions ) { - defaultListReporters(m_stream, descriptions, m_config->verbosity()); - } - - void ReporterBase::listListeners( - std::vector const& descriptions ) { - defaultListListeners( m_stream, descriptions ); - } - - void ReporterBase::listTests(std::vector const& tests) { - defaultListTests(m_stream, - m_colour.get(), - tests, - m_config->hasTestFilters(), - m_config->verbosity()); - } - - void ReporterBase::listTags(std::vector const& tags) { - defaultListTags( m_stream, tags, m_config->hasTestFilters() ); - } - -} // namespace Catch - - - - -#include - -namespace Catch { -namespace { - - // Colour::LightGrey - static constexpr Colour::Code compactDimColour = Colour::FileName; - -#ifdef CATCH_PLATFORM_MAC - static constexpr Catch::StringRef compactFailedString = "FAILED"_sr; - static constexpr Catch::StringRef compactPassedString = "PASSED"_sr; -#else - static constexpr Catch::StringRef compactFailedString = "failed"_sr; - static constexpr Catch::StringRef compactPassedString = "passed"_sr; -#endif - -// Implementation of CompactReporter formatting -class AssertionPrinter { -public: - AssertionPrinter& operator= (AssertionPrinter const&) = delete; - AssertionPrinter(AssertionPrinter const&) = delete; - AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages, ColourImpl* colourImpl_) - : stream(_stream) - , result(_stats.assertionResult) - , messages(_stats.infoMessages) - , itMessage(_stats.infoMessages.begin()) - , printInfoMessages(_printInfoMessages) - , colourImpl(colourImpl_) - {} - - void print() { - printSourceInfo(); - - itMessage = messages.begin(); - - switch (result.getResultType()) { - case ResultWas::Ok: - printResultType(Colour::ResultSuccess, compactPassedString); - printOriginalExpression(); - printReconstructedExpression(); - if (!result.hasExpression()) - printRemainingMessages(Colour::None); - else - printRemainingMessages(); - break; - case ResultWas::ExpressionFailed: - if (result.isOk()) - printResultType(Colour::ResultSuccess, compactFailedString + " - but was ok"_sr); - else - printResultType(Colour::Error, compactFailedString); - printOriginalExpression(); - printReconstructedExpression(); - printRemainingMessages(); - break; - case ResultWas::ThrewException: - printResultType(Colour::Error, compactFailedString); - printIssue("unexpected exception with message:"); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::FatalErrorCondition: - printResultType(Colour::Error, compactFailedString); - printIssue("fatal error condition with message:"); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::DidntThrowException: - printResultType(Colour::Error, compactFailedString); - printIssue("expected exception, got none"); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::Info: - printResultType(Colour::None, "info"_sr); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::Warning: - printResultType(Colour::None, "warning"_sr); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::ExplicitFailure: - printResultType(Colour::Error, compactFailedString); - printIssue("explicitly"); - printRemainingMessages(Colour::None); - break; - case ResultWas::ExplicitSkip: - printResultType(Colour::Skip, "skipped"_sr); - printMessage(); - printRemainingMessages(); - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - printResultType(Colour::Error, "** internal error **"); - break; - } - } - -private: - void printSourceInfo() const { - stream << colourImpl->guardColour( Colour::FileName ) - << result.getSourceInfo() << ':'; - } - - void printResultType(Colour::Code colour, StringRef passOrFail) const { - if (!passOrFail.empty()) { - stream << colourImpl->guardColour(colour) << ' ' << passOrFail; - stream << ':'; - } - } - - void printIssue(char const* issue) const { - stream << ' ' << issue; - } - - void printExpressionWas() { - if (result.hasExpression()) { - stream << ';'; - { - stream << colourImpl->guardColour(compactDimColour) << " expression was:"; - } - printOriginalExpression(); - } - } - - void printOriginalExpression() const { - if (result.hasExpression()) { - stream << ' ' << result.getExpression(); - } - } - - void printReconstructedExpression() const { - if (result.hasExpandedExpression()) { - stream << colourImpl->guardColour(compactDimColour) << " for: "; - stream << result.getExpandedExpression(); - } - } - - void printMessage() { - if (itMessage != messages.end()) { - stream << " '" << itMessage->message << '\''; - ++itMessage; - } - } - - void printRemainingMessages(Colour::Code colour = compactDimColour) { - if (itMessage == messages.end()) - return; - - const auto itEnd = messages.cend(); - const auto N = static_cast(std::distance(itMessage, itEnd)); - - stream << colourImpl->guardColour( colour ) << " with " - << pluralise( N, "message"_sr ) << ':'; - - while (itMessage != itEnd) { - // If this assertion is a warning ignore any INFO messages - if (printInfoMessages || itMessage->type != ResultWas::Info) { - printMessage(); - if (itMessage != itEnd) { - stream << colourImpl->guardColour(compactDimColour) << " and"; - } - continue; - } - ++itMessage; - } - } - -private: - std::ostream& stream; - AssertionResult const& result; - std::vector const& messages; - std::vector::const_iterator itMessage; - bool printInfoMessages; - ColourImpl* colourImpl; -}; - -} // anon namespace - - std::string CompactReporter::getDescription() { - return "Reports test results on a single line, suitable for IDEs"; - } - - void CompactReporter::noMatchingTestCases( StringRef unmatchedSpec ) { - m_stream << "No test cases matched '" << unmatchedSpec << "'\n"; - } - - void CompactReporter::testRunStarting( TestRunInfo const& ) { - if ( m_config->testSpec().hasFilters() ) { - m_stream << m_colour->guardColour( Colour::BrightYellow ) - << "Filters: " - << m_config->testSpec() - << '\n'; - } - m_stream << "RNG seed: " << getSeed() << '\n'; - } - - void CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { - AssertionResult const& result = _assertionStats.assertionResult; - - bool printInfoMessages = true; - - // Drop out if result was successful and we're not printing those - if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip ) - return; - printInfoMessages = false; - } - - AssertionPrinter printer( m_stream, _assertionStats, printInfoMessages, m_colour.get() ); - printer.print(); - - m_stream << '\n' << std::flush; - } - - void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { - double dur = _sectionStats.durationInSeconds; - if ( shouldShowDuration( *m_config, dur ) ) { - m_stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush; - } - } - - void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { - printTestRunTotals( m_stream, *m_colour, _testRunStats.totals ); - m_stream << "\n\n" << std::flush; - StreamingReporterBase::testRunEnded( _testRunStats ); - } - - CompactReporter::~CompactReporter() {} - -} // end namespace Catch - - - - -#include - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled and default is missing) is enabled -#endif - -#if defined(__clang__) -# pragma clang diagnostic push -// For simplicity, benchmarking-only helpers are always enabled -# pragma clang diagnostic ignored "-Wunused-function" -#endif - - - -namespace Catch { - -namespace { - -// Formatter impl for ConsoleReporter -class ConsoleAssertionPrinter { -public: - ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; - ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; - ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, ColourImpl* colourImpl_, bool _printInfoMessages) - : stream(_stream), - stats(_stats), - result(_stats.assertionResult), - colour(Colour::None), - messages(_stats.infoMessages), - colourImpl(colourImpl_), - printInfoMessages(_printInfoMessages) { - switch (result.getResultType()) { - case ResultWas::Ok: - colour = Colour::Success; - passOrFail = "PASSED"_sr; - //if( result.hasMessage() ) - if (messages.size() == 1) - messageLabel = "with message"_sr; - if (messages.size() > 1) - messageLabel = "with messages"_sr; - break; - case ResultWas::ExpressionFailed: - if (result.isOk()) { - colour = Colour::Success; - passOrFail = "FAILED - but was ok"_sr; - } else { - colour = Colour::Error; - passOrFail = "FAILED"_sr; - } - if (messages.size() == 1) - messageLabel = "with message"_sr; - if (messages.size() > 1) - messageLabel = "with messages"_sr; - break; - case ResultWas::ThrewException: - colour = Colour::Error; - passOrFail = "FAILED"_sr; - // todo switch - switch (messages.size()) { case 0: - messageLabel = "due to unexpected exception with "_sr; - break; - case 1: - messageLabel = "due to unexpected exception with message"_sr; - break; - default: - messageLabel = "due to unexpected exception with messages"_sr; - break; - } - break; - case ResultWas::FatalErrorCondition: - colour = Colour::Error; - passOrFail = "FAILED"_sr; - messageLabel = "due to a fatal error condition"_sr; - break; - case ResultWas::DidntThrowException: - colour = Colour::Error; - passOrFail = "FAILED"_sr; - messageLabel = "because no exception was thrown where one was expected"_sr; - break; - case ResultWas::Info: - messageLabel = "info"_sr; - break; - case ResultWas::Warning: - messageLabel = "warning"_sr; - break; - case ResultWas::ExplicitFailure: - passOrFail = "FAILED"_sr; - colour = Colour::Error; - if (messages.size() == 1) - messageLabel = "explicitly with message"_sr; - if (messages.size() > 1) - messageLabel = "explicitly with messages"_sr; - break; - case ResultWas::ExplicitSkip: - colour = Colour::Skip; - passOrFail = "SKIPPED"_sr; - if (messages.size() == 1) - messageLabel = "explicitly with message"_sr; - if (messages.size() > 1) - messageLabel = "explicitly with messages"_sr; - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - passOrFail = "** internal error **"_sr; - colour = Colour::Error; - break; - } - } - - void print() const { - printSourceInfo(); - if (stats.totals.assertions.total() > 0) { - printResultType(); - printOriginalExpression(); - printReconstructedExpression(); - } else { - stream << '\n'; - } - printMessage(); - } - -private: - void printResultType() const { - if (!passOrFail.empty()) { - stream << colourImpl->guardColour(colour) << passOrFail << ":\n"; - } - } - void printOriginalExpression() const { - if (result.hasExpression()) { - stream << colourImpl->guardColour( Colour::OriginalExpression ) - << " " << result.getExpressionInMacro() << '\n'; - } - } - void printReconstructedExpression() const { - if (result.hasExpandedExpression()) { - stream << "with expansion:\n"; - stream << colourImpl->guardColour( Colour::ReconstructedExpression ) - << TextFlow::Column( result.getExpandedExpression() ) - .indent( 2 ) - << '\n'; - } - } - void printMessage() const { - if (!messageLabel.empty()) - stream << messageLabel << ':' << '\n'; - for (auto const& msg : messages) { - // If this assertion is a warning ignore any INFO messages - if (printInfoMessages || msg.type != ResultWas::Info) - stream << TextFlow::Column(msg.message).indent(2) << '\n'; - } - } - void printSourceInfo() const { - stream << colourImpl->guardColour( Colour::FileName ) - << result.getSourceInfo() << ": "; - } - - std::ostream& stream; - AssertionStats const& stats; - AssertionResult const& result; - Colour::Code colour; - StringRef passOrFail; - StringRef messageLabel; - std::vector const& messages; - ColourImpl* colourImpl; - bool printInfoMessages; -}; - -std::size_t makeRatio( std::uint64_t number, std::uint64_t total ) { - const auto ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; - return (ratio == 0 && number > 0) ? 1 : static_cast(ratio); -} - -std::size_t& -findMax( std::size_t& i, std::size_t& j, std::size_t& k, std::size_t& l ) { - if (i > j && i > k && i > l) - return i; - else if (j > k && j > l) - return j; - else if (k > l) - return k; - else - return l; -} - -enum class Justification { Left, Right }; - -struct ColumnInfo { - std::string name; - std::size_t width; - Justification justification; -}; -struct ColumnBreak {}; -struct RowBreak {}; - -class Duration { - enum class Unit { - Auto, - Nanoseconds, - Microseconds, - Milliseconds, - Seconds, - Minutes - }; - static const uint64_t s_nanosecondsInAMicrosecond = 1000; - static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; - static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; - static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; - - double m_inNanoseconds; - Unit m_units; - -public: - explicit Duration(double inNanoseconds, Unit units = Unit::Auto) - : m_inNanoseconds(inNanoseconds), - m_units(units) { - if (m_units == Unit::Auto) { - if (m_inNanoseconds < s_nanosecondsInAMicrosecond) - m_units = Unit::Nanoseconds; - else if (m_inNanoseconds < s_nanosecondsInAMillisecond) - m_units = Unit::Microseconds; - else if (m_inNanoseconds < s_nanosecondsInASecond) - m_units = Unit::Milliseconds; - else if (m_inNanoseconds < s_nanosecondsInAMinute) - m_units = Unit::Seconds; - else - m_units = Unit::Minutes; - } - - } - - auto value() const -> double { - switch (m_units) { - case Unit::Microseconds: - return m_inNanoseconds / static_cast(s_nanosecondsInAMicrosecond); - case Unit::Milliseconds: - return m_inNanoseconds / static_cast(s_nanosecondsInAMillisecond); - case Unit::Seconds: - return m_inNanoseconds / static_cast(s_nanosecondsInASecond); - case Unit::Minutes: - return m_inNanoseconds / static_cast(s_nanosecondsInAMinute); - default: - return m_inNanoseconds; - } - } - StringRef unitsAsString() const { - switch (m_units) { - case Unit::Nanoseconds: - return "ns"_sr; - case Unit::Microseconds: - return "us"_sr; - case Unit::Milliseconds: - return "ms"_sr; - case Unit::Seconds: - return "s"_sr; - case Unit::Minutes: - return "m"_sr; - default: - return "** internal error **"_sr; - } - - } - friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { - return os << duration.value() << ' ' << duration.unitsAsString(); - } -}; -} // end anon namespace - -class TablePrinter { - std::ostream& m_os; - std::vector m_columnInfos; - ReusableStringStream m_oss; - int m_currentColumn = -1; - bool m_isOpen = false; - -public: - TablePrinter( std::ostream& os, std::vector columnInfos ) - : m_os( os ), - m_columnInfos( CATCH_MOVE( columnInfos ) ) {} - - auto columnInfos() const -> std::vector const& { - return m_columnInfos; - } - - void open() { - if (!m_isOpen) { - m_isOpen = true; - *this << RowBreak(); - - TextFlow::Columns headerCols; - auto spacer = TextFlow::Spacer(2); - for (auto const& info : m_columnInfos) { - assert(info.width > 2); - headerCols += TextFlow::Column(info.name).width(info.width - 2); - headerCols += spacer; - } - m_os << headerCols << '\n'; - - m_os << lineOfChars('-') << '\n'; - } - } - void close() { - if (m_isOpen) { - *this << RowBreak(); - m_os << '\n' << std::flush; - m_isOpen = false; - } - } - - template - friend TablePrinter& operator << (TablePrinter& tp, T const& value) { - tp.m_oss << value; - return tp; - } - - friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { - auto colStr = tp.m_oss.str(); - const auto strSize = colStr.size(); - tp.m_oss.str(""); - tp.open(); - if (tp.m_currentColumn == static_cast(tp.m_columnInfos.size() - 1)) { - tp.m_currentColumn = -1; - tp.m_os << '\n'; - } - tp.m_currentColumn++; - - auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; - auto padding = (strSize + 1 < colInfo.width) - ? std::string(colInfo.width - (strSize + 1), ' ') - : std::string(); - if (colInfo.justification == Justification::Left) - tp.m_os << colStr << padding << ' '; - else - tp.m_os << padding << colStr << ' '; - return tp; - } - - friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { - if (tp.m_currentColumn > 0) { - tp.m_os << '\n'; - tp.m_currentColumn = -1; - } - return tp; - } -}; - -ConsoleReporter::ConsoleReporter(ReporterConfig&& config): - StreamingReporterBase( CATCH_MOVE( config ) ), - m_tablePrinter(Detail::make_unique(m_stream, - [&config]() -> std::vector { - if (config.fullConfig()->benchmarkNoAnalysis()) - { - return{ - { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left }, - { " samples", 14, Justification::Right }, - { " iterations", 14, Justification::Right }, - { " mean", 14, Justification::Right } - }; - } - else - { - return{ - { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left }, - { "samples mean std dev", 14, Justification::Right }, - { "iterations low mean low std dev", 14, Justification::Right }, - { "estimated high mean high std dev", 14, Justification::Right } - }; - } - }())) {} -ConsoleReporter::~ConsoleReporter() = default; - -std::string ConsoleReporter::getDescription() { - return "Reports test results as plain lines of text"; -} - -void ConsoleReporter::noMatchingTestCases( StringRef unmatchedSpec ) { - m_stream << "No test cases matched '" << unmatchedSpec << "'\n"; -} - -void ConsoleReporter::reportInvalidTestSpec( StringRef arg ) { - m_stream << "Invalid Filter: " << arg << '\n'; -} - -void ConsoleReporter::assertionStarting(AssertionInfo const&) {} - -void ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { - AssertionResult const& result = _assertionStats.assertionResult; - - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - - // Drop out if result was successful but we're not printing them. - // TODO: Make configurable whether skips should be printed - if (!includeResults && result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip) - return; - - lazyPrint(); - - ConsoleAssertionPrinter printer(m_stream, _assertionStats, m_colour.get(), includeResults); - printer.print(); - m_stream << '\n' << std::flush; -} - -void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { - m_tablePrinter->close(); - m_headerPrinted = false; - StreamingReporterBase::sectionStarting(_sectionInfo); -} -void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { - m_tablePrinter->close(); - if (_sectionStats.missingAssertions) { - lazyPrint(); - auto guard = - m_colour->guardColour( Colour::ResultError ).engage( m_stream ); - if (m_sectionStack.size() > 1) - m_stream << "\nNo assertions in section"; - else - m_stream << "\nNo assertions in test case"; - m_stream << " '" << _sectionStats.sectionInfo.name << "'\n\n" << std::flush; - } - double dur = _sectionStats.durationInSeconds; - if (shouldShowDuration(*m_config, dur)) { - m_stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush; - } - if (m_headerPrinted) { - m_headerPrinted = false; - } - StreamingReporterBase::sectionEnded(_sectionStats); -} - -void ConsoleReporter::benchmarkPreparing( StringRef name ) { - lazyPrintWithoutClosingBenchmarkTable(); - - auto nameCol = TextFlow::Column( static_cast( name ) ) - .width( m_tablePrinter->columnInfos()[0].width - 2 ); - - bool firstLine = true; - for (auto line : nameCol) { - if (!firstLine) - (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); - else - firstLine = false; - - (*m_tablePrinter) << line << ColumnBreak(); - } -} - -void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { - (*m_tablePrinter) << info.samples << ColumnBreak() - << info.iterations << ColumnBreak(); - if (!m_config->benchmarkNoAnalysis()) - (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak(); -} -void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) { - if (m_config->benchmarkNoAnalysis()) - { - (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak(); - } - else - { - (*m_tablePrinter) << ColumnBreak() - << Duration(stats.mean.point.count()) << ColumnBreak() - << Duration(stats.mean.lower_bound.count()) << ColumnBreak() - << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak() - << Duration(stats.standardDeviation.point.count()) << ColumnBreak() - << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak() - << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak(); - } -} - -void ConsoleReporter::benchmarkFailed( StringRef error ) { - auto guard = m_colour->guardColour( Colour::Red ).engage( m_stream ); - (*m_tablePrinter) - << "Benchmark failed (" << error << ')' - << ColumnBreak() << RowBreak(); -} - -void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { - m_tablePrinter->close(); - StreamingReporterBase::testCaseEnded(_testCaseStats); - m_headerPrinted = false; -} -void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { - printTotalsDivider(_testRunStats.totals); - printTestRunTotals( m_stream, *m_colour, _testRunStats.totals ); - m_stream << '\n' << std::flush; - StreamingReporterBase::testRunEnded(_testRunStats); -} -void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) { - StreamingReporterBase::testRunStarting(_testInfo); - if ( m_config->testSpec().hasFilters() ) { - m_stream << m_colour->guardColour( Colour::BrightYellow ) << "Filters: " - << m_config->testSpec() << '\n'; - } - m_stream << "Randomness seeded to: " << getSeed() << '\n'; -} - -void ConsoleReporter::lazyPrint() { - - m_tablePrinter->close(); - lazyPrintWithoutClosingBenchmarkTable(); -} - -void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { - - if ( !m_testRunInfoPrinted ) { - lazyPrintRunInfo(); - } - if (!m_headerPrinted) { - printTestCaseAndSectionHeader(); - m_headerPrinted = true; - } -} -void ConsoleReporter::lazyPrintRunInfo() { - m_stream << '\n' - << lineOfChars( '~' ) << '\n' - << m_colour->guardColour( Colour::SecondaryText ) - << currentTestRunInfo.name << " is a Catch2 v" << libraryVersion() - << " host application.\n" - << "Run with -? for options\n\n"; - - m_testRunInfoPrinted = true; -} -void ConsoleReporter::printTestCaseAndSectionHeader() { - assert(!m_sectionStack.empty()); - printOpenHeader(currentTestCaseInfo->name); - - if (m_sectionStack.size() > 1) { - auto guard = m_colour->guardColour( Colour::Headers ).engage( m_stream ); - - auto - it = m_sectionStack.begin() + 1, // Skip first section (test case) - itEnd = m_sectionStack.end(); - for (; it != itEnd; ++it) - printHeaderString(it->name, 2); - } - - SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; - - - m_stream << lineOfChars( '-' ) << '\n' - << m_colour->guardColour( Colour::FileName ) << lineInfo << '\n' - << lineOfChars( '.' ) << "\n\n" - << std::flush; -} - -void ConsoleReporter::printClosedHeader(std::string const& _name) { - printOpenHeader(_name); - m_stream << lineOfChars('.') << '\n'; -} -void ConsoleReporter::printOpenHeader(std::string const& _name) { - m_stream << lineOfChars('-') << '\n'; - { - auto guard = m_colour->guardColour( Colour::Headers ).engage( m_stream ); - printHeaderString(_name); - } -} - -void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { - // We want to get a bit fancy with line breaking here, so that subsequent - // lines start after ":" if one is present, e.g. - // ``` - // blablabla: Fancy - // linebreaking - // ``` - // but we also want to avoid problems with overly long indentation causing - // the text to take up too many lines, e.g. - // ``` - // blablabla: F - // a - // n - // c - // y - // . - // . - // . - // ``` - // So we limit the prefix indentation check to first quarter of the possible - // width - std::size_t idx = _string.find( ": " ); - if ( idx != std::string::npos && idx < CATCH_CONFIG_CONSOLE_WIDTH / 4 ) { - idx += 2; - } else { - idx = 0; - } - m_stream << TextFlow::Column( _string ) - .indent( indent + idx ) - .initialIndent( indent ) - << '\n'; -} - -void ConsoleReporter::printTotalsDivider(Totals const& totals) { - if (totals.testCases.total() > 0) { - std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); - std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); - std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); - std::size_t skippedRatio = makeRatio(totals.testCases.skipped, totals.testCases.total()); - while (failedRatio + failedButOkRatio + passedRatio + skippedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) - findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)++; - while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) - findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)--; - - m_stream << m_colour->guardColour( Colour::Error ) - << std::string( failedRatio, '=' ) - << m_colour->guardColour( Colour::ResultExpectedFailure ) - << std::string( failedButOkRatio, '=' ); - if ( totals.testCases.allPassed() ) { - m_stream << m_colour->guardColour( Colour::ResultSuccess ) - << std::string( passedRatio, '=' ); - } else { - m_stream << m_colour->guardColour( Colour::Success ) - << std::string( passedRatio, '=' ); - } - m_stream << m_colour->guardColour( Colour::Skip ) - << std::string( skippedRatio, '=' ); - } else { - m_stream << m_colour->guardColour( Colour::Warning ) - << std::string( CATCH_CONFIG_CONSOLE_WIDTH - 1, '=' ); - } - m_stream << '\n'; -} - -} // end namespace Catch - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - - - - -#include -#include - -namespace Catch { - namespace { - struct BySectionInfo { - BySectionInfo( SectionInfo const& other ): m_other( other ) {} - BySectionInfo( BySectionInfo const& other ): - m_other( other.m_other ) {} - bool operator()( - Detail::unique_ptr const& - node ) const { - return ( - ( node->stats.sectionInfo.name == m_other.name ) && - ( node->stats.sectionInfo.lineInfo == m_other.lineInfo ) ); - } - void operator=( BySectionInfo const& ) = delete; - - private: - SectionInfo const& m_other; - }; - - } // namespace - - namespace Detail { - AssertionOrBenchmarkResult::AssertionOrBenchmarkResult( - AssertionStats const& assertion ): - m_assertion( assertion ) {} - - AssertionOrBenchmarkResult::AssertionOrBenchmarkResult( - BenchmarkStats<> const& benchmark ): - m_benchmark( benchmark ) {} - - bool AssertionOrBenchmarkResult::isAssertion() const { - return m_assertion.some(); - } - bool AssertionOrBenchmarkResult::isBenchmark() const { - return m_benchmark.some(); - } - - AssertionStats const& AssertionOrBenchmarkResult::asAssertion() const { - assert(m_assertion.some()); - - return *m_assertion; - } - BenchmarkStats<> const& AssertionOrBenchmarkResult::asBenchmark() const { - assert(m_benchmark.some()); - - return *m_benchmark; - } - - } - - CumulativeReporterBase::~CumulativeReporterBase() = default; - - void CumulativeReporterBase::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { - m_sectionStack.back()->assertionsAndBenchmarks.emplace_back(benchmarkStats); - } - - void - CumulativeReporterBase::sectionStarting( SectionInfo const& sectionInfo ) { - // We need a copy, because SectionStats expect to take ownership - SectionStats incompleteStats( SectionInfo(sectionInfo), Counts(), 0, false ); - SectionNode* node; - if ( m_sectionStack.empty() ) { - if ( !m_rootSection ) { - m_rootSection = - Detail::make_unique( incompleteStats ); - } - node = m_rootSection.get(); - } else { - SectionNode& parentNode = *m_sectionStack.back(); - auto it = std::find_if( parentNode.childSections.begin(), - parentNode.childSections.end(), - BySectionInfo( sectionInfo ) ); - if ( it == parentNode.childSections.end() ) { - auto newNode = - Detail::make_unique( incompleteStats ); - node = newNode.get(); - parentNode.childSections.push_back( CATCH_MOVE( newNode ) ); - } else { - node = it->get(); - } - } - - m_deepestSection = node; - m_sectionStack.push_back( node ); - } - - void CumulativeReporterBase::assertionEnded( - AssertionStats const& assertionStats ) { - assert( !m_sectionStack.empty() ); - // AssertionResult holds a pointer to a temporary DecomposedExpression, - // which getExpandedExpression() calls to build the expression string. - // Our section stack copy of the assertionResult will likely outlive the - // temporary, so it must be expanded or discarded now to avoid calling - // a destroyed object later. - if ( m_shouldStoreFailedAssertions && - !assertionStats.assertionResult.isOk() ) { - static_cast( - assertionStats.assertionResult.getExpandedExpression() ); - } - if ( m_shouldStoreSuccesfulAssertions && - assertionStats.assertionResult.isOk() ) { - static_cast( - assertionStats.assertionResult.getExpandedExpression() ); - } - SectionNode& sectionNode = *m_sectionStack.back(); - sectionNode.assertionsAndBenchmarks.emplace_back( assertionStats ); - } - - void CumulativeReporterBase::sectionEnded( SectionStats const& sectionStats ) { - assert( !m_sectionStack.empty() ); - SectionNode& node = *m_sectionStack.back(); - node.stats = sectionStats; - m_sectionStack.pop_back(); - } - - void CumulativeReporterBase::testCaseEnded( - TestCaseStats const& testCaseStats ) { - auto node = Detail::make_unique( testCaseStats ); - assert( m_sectionStack.size() == 0 ); - node->children.push_back( CATCH_MOVE(m_rootSection) ); - m_testCases.push_back( CATCH_MOVE(node) ); - - assert( m_deepestSection ); - m_deepestSection->stdOut = testCaseStats.stdOut; - m_deepestSection->stdErr = testCaseStats.stdErr; - } - - - void CumulativeReporterBase::testRunEnded( TestRunStats const& testRunStats ) { - assert(!m_testRun && "CumulativeReporterBase assumes there can only be one test run"); - m_testRun = Detail::make_unique( testRunStats ); - m_testRun->children.swap( m_testCases ); - testRunEndedCumulative(); - } - - bool CumulativeReporterBase::SectionNode::hasAnyAssertions() const { - return std::any_of( - assertionsAndBenchmarks.begin(), - assertionsAndBenchmarks.end(), - []( Detail::AssertionOrBenchmarkResult const& res ) { - return res.isAssertion(); - } ); - } - -} // end namespace Catch - - - - -namespace Catch { - - void EventListenerBase::fatalErrorEncountered( StringRef ) {} - - void EventListenerBase::benchmarkPreparing( StringRef ) {} - void EventListenerBase::benchmarkStarting( BenchmarkInfo const& ) {} - void EventListenerBase::benchmarkEnded( BenchmarkStats<> const& ) {} - void EventListenerBase::benchmarkFailed( StringRef ) {} - - void EventListenerBase::assertionStarting( AssertionInfo const& ) {} - - void EventListenerBase::assertionEnded( AssertionStats const& ) {} - void EventListenerBase::listReporters( - std::vector const& ) {} - void EventListenerBase::listListeners( - std::vector const& ) {} - void EventListenerBase::listTests( std::vector const& ) {} - void EventListenerBase::listTags( std::vector const& ) {} - void EventListenerBase::noMatchingTestCases( StringRef ) {} - void EventListenerBase::reportInvalidTestSpec( StringRef ) {} - void EventListenerBase::testRunStarting( TestRunInfo const& ) {} - void EventListenerBase::testCaseStarting( TestCaseInfo const& ) {} - void EventListenerBase::testCasePartialStarting(TestCaseInfo const&, uint64_t) {} - void EventListenerBase::sectionStarting( SectionInfo const& ) {} - void EventListenerBase::sectionEnded( SectionStats const& ) {} - void EventListenerBase::testCasePartialEnded(TestCaseStats const&, uint64_t) {} - void EventListenerBase::testCaseEnded( TestCaseStats const& ) {} - void EventListenerBase::testRunEnded( TestRunStats const& ) {} - void EventListenerBase::skipTest( TestCaseInfo const& ) {} -} // namespace Catch - - - - -#include -#include -#include -#include -#include - -namespace Catch { - - namespace { - void listTestNamesOnly(std::ostream& out, - std::vector const& tests) { - for (auto const& test : tests) { - auto const& testCaseInfo = test.getTestCaseInfo(); - - if (startsWith(testCaseInfo.name, '#')) { - out << '"' << testCaseInfo.name << '"'; - } else { - out << testCaseInfo.name; - } - - out << '\n'; - } - out << std::flush; - } - } // end unnamed namespace - - - // Because formatting using c++ streams is stateful, drop down to C is - // required Alternatively we could use stringstream, but its performance - // is... not good. - std::string getFormattedDuration( double duration ) { - // Max exponent + 1 is required to represent the whole part - // + 1 for decimal point - // + 3 for the 3 decimal places - // + 1 for null terminator - const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; - char buffer[maxDoubleSize]; - - // Save previous errno, to prevent sprintf from overwriting it - ErrnoGuard guard; -#ifdef _MSC_VER - size_t printedLength = static_cast( - sprintf_s( buffer, "%.3f", duration ) ); -#else - size_t printedLength = static_cast( - std::snprintf( buffer, maxDoubleSize, "%.3f", duration ) ); -#endif - return std::string( buffer, printedLength ); - } - - bool shouldShowDuration( IConfig const& config, double duration ) { - if ( config.showDurations() == ShowDurations::Always ) { - return true; - } - if ( config.showDurations() == ShowDurations::Never ) { - return false; - } - const double min = config.minDuration(); - return min >= 0 && duration >= min; - } - - std::string serializeFilters( std::vector const& filters ) { - // We add a ' ' separator between each filter - size_t serialized_size = filters.size() - 1; - for (auto const& filter : filters) { - serialized_size += filter.size(); - } - - std::string serialized; - serialized.reserve(serialized_size); - bool first = true; - - for (auto const& filter : filters) { - if (!first) { - serialized.push_back(' '); - } - first = false; - serialized.append(filter); - } - - return serialized; - } - - std::ostream& operator<<( std::ostream& out, lineOfChars value ) { - for ( size_t idx = 0; idx < CATCH_CONFIG_CONSOLE_WIDTH - 1; ++idx ) { - out.put( value.c ); - } - return out; - } - - void - defaultListReporters( std::ostream& out, - std::vector const& descriptions, - Verbosity verbosity ) { - out << "Available reporters:\n"; - const auto maxNameLen = - std::max_element( descriptions.begin(), - descriptions.end(), - []( ReporterDescription const& lhs, - ReporterDescription const& rhs ) { - return lhs.name.size() < rhs.name.size(); - } ) - ->name.size(); - - for ( auto const& desc : descriptions ) { - if ( verbosity == Verbosity::Quiet ) { - out << TextFlow::Column( desc.name ) - .indent( 2 ) - .width( 5 + maxNameLen ) - << '\n'; - } else { - out << TextFlow::Column( desc.name + ':' ) - .indent( 2 ) - .width( 5 + maxNameLen ) + - TextFlow::Column( desc.description ) - .initialIndent( 0 ) - .indent( 2 ) - .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 ) - << '\n'; - } - } - out << '\n' << std::flush; - } - - void defaultListListeners( std::ostream& out, - std::vector const& descriptions ) { - out << "Registered listeners:\n"; - - if(descriptions.empty()) { - return; - } - - const auto maxNameLen = - std::max_element( descriptions.begin(), - descriptions.end(), - []( ListenerDescription const& lhs, - ListenerDescription const& rhs ) { - return lhs.name.size() < rhs.name.size(); - } ) - ->name.size(); - - for ( auto const& desc : descriptions ) { - out << TextFlow::Column( static_cast( desc.name ) + - ':' ) - .indent( 2 ) - .width( maxNameLen + 5 ) + - TextFlow::Column( desc.description ) - .initialIndent( 0 ) - .indent( 2 ) - .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 ) - << '\n'; - } - - out << '\n' << std::flush; - } - - void defaultListTags( std::ostream& out, - std::vector const& tags, - bool isFiltered ) { - if ( isFiltered ) { - out << "Tags for matching test cases:\n"; - } else { - out << "All available tags:\n"; - } - - for ( auto const& tagCount : tags ) { - ReusableStringStream rss; - rss << " " << std::setw( 2 ) << tagCount.count << " "; - auto str = rss.str(); - auto wrapper = TextFlow::Column( tagCount.all() ) - .initialIndent( 0 ) - .indent( str.size() ) - .width( CATCH_CONFIG_CONSOLE_WIDTH - 10 ); - out << str << wrapper << '\n'; - } - out << pluralise(tags.size(), "tag"_sr) << "\n\n" << std::flush; - } - - void defaultListTests(std::ostream& out, ColourImpl* streamColour, std::vector const& tests, bool isFiltered, Verbosity verbosity) { - // We special case this to provide the equivalent of old - // `--list-test-names-only`, which could then be used by the - // `--input-file` option. - if (verbosity == Verbosity::Quiet) { - listTestNamesOnly(out, tests); - return; - } - - if (isFiltered) { - out << "Matching test cases:\n"; - } else { - out << "All available test cases:\n"; - } - - for (auto const& test : tests) { - auto const& testCaseInfo = test.getTestCaseInfo(); - Colour::Code colour = testCaseInfo.isHidden() - ? Colour::SecondaryText - : Colour::None; - auto colourGuard = streamColour->guardColour( colour ).engage( out ); - - out << TextFlow::Column(testCaseInfo.name).indent(2) << '\n'; - if (verbosity >= Verbosity::High) { - out << TextFlow::Column(Catch::Detail::stringify(testCaseInfo.lineInfo)).indent(4) << '\n'; - } - if (!testCaseInfo.tags.empty() && - verbosity > Verbosity::Quiet) { - out << TextFlow::Column(testCaseInfo.tagsAsString()).indent(6) << '\n'; - } - } - - if (isFiltered) { - out << pluralise(tests.size(), "matching test case"_sr); - } else { - out << pluralise(tests.size(), "test case"_sr); - } - out << "\n\n" << std::flush; - } - - namespace { - class SummaryColumn { - public: - SummaryColumn( std::string suffix, Colour::Code colour ): - m_suffix( CATCH_MOVE( suffix ) ), m_colour( colour ) {} - - SummaryColumn&& addRow( std::uint64_t count ) && { - std::string row = std::to_string(count); - auto const new_width = std::max( m_width, row.size() ); - if ( new_width > m_width ) { - for ( auto& oldRow : m_rows ) { - oldRow.insert( 0, new_width - m_width, ' ' ); - } - } else { - row.insert( 0, m_width - row.size(), ' ' ); - } - m_width = new_width; - m_rows.push_back( row ); - return std::move( *this ); - } - - std::string const& getSuffix() const { return m_suffix; } - Colour::Code getColour() const { return m_colour; } - std::string const& getRow( std::size_t index ) const { - return m_rows[index]; - } - - private: - std::string m_suffix; - Colour::Code m_colour; - std::size_t m_width = 0; - std::vector m_rows; - }; - - void printSummaryRow( std::ostream& stream, - ColourImpl& colour, - StringRef label, - std::vector const& cols, - std::size_t row ) { - for ( auto const& col : cols ) { - auto const& value = col.getRow( row ); - auto const& suffix = col.getSuffix(); - if ( suffix.empty() ) { - stream << label << ": "; - if ( value != "0" ) { - stream << value; - } else { - stream << colour.guardColour( Colour::Warning ) - << "- none -"; - } - } else if ( value != "0" ) { - stream << colour.guardColour( Colour::LightGrey ) << " | " - << colour.guardColour( col.getColour() ) << value - << ' ' << suffix; - } - } - stream << '\n'; - } - } // namespace - - void printTestRunTotals( std::ostream& stream, - ColourImpl& streamColour, - Totals const& totals ) { - if ( totals.testCases.total() == 0 ) { - stream << streamColour.guardColour( Colour::Warning ) - << "No tests ran\n"; - return; - } - - if ( totals.assertions.total() > 0 && totals.testCases.allPassed() ) { - stream << streamColour.guardColour( Colour::ResultSuccess ) - << "All tests passed"; - stream << " (" - << pluralise( totals.assertions.passed, "assertion"_sr ) - << " in " - << pluralise( totals.testCases.passed, "test case"_sr ) - << ')' << '\n'; - return; - } - - std::vector columns; - // Don't include "skipped assertions" in total count - const auto totalAssertionCount = - totals.assertions.total() - totals.assertions.skipped; - columns.push_back( SummaryColumn( "", Colour::None ) - .addRow( totals.testCases.total() ) - .addRow( totalAssertionCount ) ); - columns.push_back( SummaryColumn( "passed", Colour::Success ) - .addRow( totals.testCases.passed ) - .addRow( totals.assertions.passed ) ); - columns.push_back( SummaryColumn( "failed", Colour::ResultError ) - .addRow( totals.testCases.failed ) - .addRow( totals.assertions.failed ) ); - columns.push_back( SummaryColumn( "skipped", Colour::Skip ) - .addRow( totals.testCases.skipped ) - // Don't print "skipped assertions" - .addRow( 0 ) ); - columns.push_back( - SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) - .addRow( totals.testCases.failedButOk ) - .addRow( totals.assertions.failedButOk ) ); - printSummaryRow( stream, streamColour, "test cases"_sr, columns, 0 ); - printSummaryRow( stream, streamColour, "assertions"_sr, columns, 1 ); - } - -} // namespace Catch - - - - -#include -#include -#include -#include - -namespace Catch { - - namespace { - std::string getCurrentTimestamp() { - time_t rawtime; - std::time(&rawtime); - - std::tm timeInfo = {}; -#if defined (_MSC_VER) || defined (__MINGW32__) - gmtime_s(&timeInfo, &rawtime); -#elif defined (CATCH_PLATFORM_PLAYSTATION) - gmtime_s(&rawtime, &timeInfo); -#else - gmtime_r(&rawtime, &timeInfo); -#endif - - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); - char timeStamp[timeStampSize]; - const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; - - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); - - return std::string(timeStamp, timeStampSize - 1); - } - - std::string fileNameTag(std::vector const& tags) { - auto it = std::find_if(begin(tags), - end(tags), - [] (Tag const& tag) { - return tag.original.size() > 0 - && tag.original[0] == '#'; }); - if (it != tags.end()) { - return static_cast( - it->original.substr(1, it->original.size() - 1) - ); - } - return std::string(); - } - - // Formats the duration in seconds to 3 decimal places. - // This is done because some genius defined Maven Surefire schema - // in a way that only accepts 3 decimal places, and tools like - // Jenkins use that schema for validation JUnit reporter output. - std::string formatDuration( double seconds ) { - ReusableStringStream rss; - rss << std::fixed << std::setprecision( 3 ) << seconds; - return rss.str(); - } - - static void normalizeNamespaceMarkers(std::string& str) { - std::size_t pos = str.find( "::" ); - while ( pos != str.npos ) { - str.replace( pos, 2, "." ); - pos += 1; - pos = str.find( "::", pos ); - } - } - - } // anonymous namespace - - JunitReporter::JunitReporter( ReporterConfig&& _config ) - : CumulativeReporterBase( CATCH_MOVE(_config) ), - xml( m_stream ) - { - m_preferences.shouldRedirectStdOut = true; - m_preferences.shouldReportAllAssertions = true; - m_shouldStoreSuccesfulAssertions = false; - } - - std::string JunitReporter::getDescription() { - return "Reports test results in an XML format that looks like Ant's junitreport target"; - } - - void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { - CumulativeReporterBase::testRunStarting( runInfo ); - xml.startElement( "testsuites" ); - suiteTimer.start(); - stdOutForSuite.clear(); - stdErrForSuite.clear(); - unexpectedExceptions = 0; - } - - void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { - m_okToFail = testCaseInfo.okToFail(); - } - - void JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { - if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) - unexpectedExceptions++; - CumulativeReporterBase::assertionEnded( assertionStats ); - } - - void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { - stdOutForSuite += testCaseStats.stdOut; - stdErrForSuite += testCaseStats.stdErr; - CumulativeReporterBase::testCaseEnded( testCaseStats ); - } - - void JunitReporter::testRunEndedCumulative() { - const auto suiteTime = suiteTimer.getElapsedSeconds(); - writeRun( *m_testRun, suiteTime ); - xml.endElement(); - } - - void JunitReporter::writeRun( TestRunNode const& testRunNode, double suiteTime ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); - - TestRunStats const& stats = testRunNode.value; - xml.writeAttribute( "name"_sr, stats.runInfo.name ); - xml.writeAttribute( "errors"_sr, unexpectedExceptions ); - xml.writeAttribute( "failures"_sr, stats.totals.assertions.failed-unexpectedExceptions ); - xml.writeAttribute( "skipped"_sr, stats.totals.assertions.skipped ); - xml.writeAttribute( "tests"_sr, stats.totals.assertions.total() ); - xml.writeAttribute( "hostname"_sr, "tbd"_sr ); // !TBD - if( m_config->showDurations() == ShowDurations::Never ) - xml.writeAttribute( "time"_sr, ""_sr ); - else - xml.writeAttribute( "time"_sr, formatDuration( suiteTime ) ); - xml.writeAttribute( "timestamp"_sr, getCurrentTimestamp() ); - - // Write properties - { - auto properties = xml.scopedElement("properties"); - xml.scopedElement("property") - .writeAttribute("name"_sr, "random-seed"_sr) - .writeAttribute("value"_sr, m_config->rngSeed()); - if (m_config->testSpec().hasFilters()) { - xml.scopedElement("property") - .writeAttribute("name"_sr, "filters"_sr) - .writeAttribute("value"_sr, m_config->testSpec()); - } - } - - // Write test cases - for( auto const& child : testRunNode.children ) - writeTestCase( *child ); - - xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline ); - xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline ); - } - - void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { - TestCaseStats const& stats = testCaseNode.value; - - // All test cases have exactly one section - which represents the - // test case itself. That section may have 0-n nested sections - assert( testCaseNode.children.size() == 1 ); - SectionNode const& rootSection = *testCaseNode.children.front(); - - std::string className = - static_cast( stats.testInfo->className ); - - if( className.empty() ) { - className = fileNameTag(stats.testInfo->tags); - if ( className.empty() ) { - className = "global"; - } - } - - if ( !m_config->name().empty() ) - className = static_cast(m_config->name()) + '.' + className; - - normalizeNamespaceMarkers(className); - - writeSection( className, "", rootSection, stats.testInfo->okToFail() ); - } - - void JunitReporter::writeSection( std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode, - bool testOkToFail) { - std::string name = trim( sectionNode.stats.sectionInfo.name ); - if( !rootName.empty() ) - name = rootName + '/' + name; - - if( sectionNode.hasAnyAssertions() - || !sectionNode.stdOut.empty() - || !sectionNode.stdErr.empty() ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); - if( className.empty() ) { - xml.writeAttribute( "classname"_sr, name ); - xml.writeAttribute( "name"_sr, "root"_sr ); - } - else { - xml.writeAttribute( "classname"_sr, className ); - xml.writeAttribute( "name"_sr, name ); - } - xml.writeAttribute( "time"_sr, formatDuration( sectionNode.stats.durationInSeconds ) ); - // This is not ideal, but it should be enough to mimic gtest's - // junit output. - // Ideally the JUnit reporter would also handle `skipTest` - // events and write those out appropriately. - xml.writeAttribute( "status"_sr, "run"_sr ); - - if (sectionNode.stats.assertions.failedButOk) { - xml.scopedElement("skipped") - .writeAttribute("message", "TEST_CASE tagged with !mayfail"); - } - - writeAssertions( sectionNode ); - - - if( !sectionNode.stdOut.empty() ) - xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline ); - if( !sectionNode.stdErr.empty() ) - xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline ); - } - for( auto const& childNode : sectionNode.childSections ) - if( className.empty() ) - writeSection( name, "", *childNode, testOkToFail ); - else - writeSection( className, name, *childNode, testOkToFail ); - } - - void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { - for (auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) { - if (assertionOrBenchmark.isAssertion()) { - writeAssertion(assertionOrBenchmark.asAssertion()); - } - } - } - - void JunitReporter::writeAssertion( AssertionStats const& stats ) { - AssertionResult const& result = stats.assertionResult; - if ( !result.isOk() || - result.getResultType() == ResultWas::ExplicitSkip ) { - std::string elementName; - switch( result.getResultType() ) { - case ResultWas::ThrewException: - case ResultWas::FatalErrorCondition: - elementName = "error"; - break; - case ResultWas::ExplicitFailure: - case ResultWas::ExpressionFailed: - case ResultWas::DidntThrowException: - elementName = "failure"; - break; - case ResultWas::ExplicitSkip: - elementName = "skipped"; - break; - // We should never see these here: - case ResultWas::Info: - case ResultWas::Warning: - case ResultWas::Ok: - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - elementName = "internalError"; - break; - } - - XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - - xml.writeAttribute( "message"_sr, result.getExpression() ); - xml.writeAttribute( "type"_sr, result.getTestMacroName() ); - - ReusableStringStream rss; - if ( result.getResultType() == ResultWas::ExplicitSkip ) { - rss << "SKIPPED\n"; - } else { - rss << "FAILED" << ":\n"; - if (result.hasExpression()) { - rss << " "; - rss << result.getExpressionInMacro(); - rss << '\n'; - } - if (result.hasExpandedExpression()) { - rss << "with expansion:\n"; - rss << TextFlow::Column(result.getExpandedExpression()).indent(2) << '\n'; - } - } - - if( !result.getMessage().empty() ) - rss << result.getMessage() << '\n'; - for( auto const& msg : stats.infoMessages ) - if( msg.type == ResultWas::Info ) - rss << msg.message << '\n'; - - rss << "at " << result.getSourceInfo(); - xml.writeText( rss.str(), XmlFormatting::Newline ); - } - } - -} // end namespace Catch - - - - -#include - -namespace Catch { - void MultiReporter::updatePreferences(IEventListener const& reporterish) { - m_preferences.shouldRedirectStdOut |= - reporterish.getPreferences().shouldRedirectStdOut; - m_preferences.shouldReportAllAssertions |= - reporterish.getPreferences().shouldReportAllAssertions; - } - - void MultiReporter::addListener( IEventListenerPtr&& listener ) { - updatePreferences(*listener); - m_reporterLikes.insert(m_reporterLikes.begin() + m_insertedListeners, CATCH_MOVE(listener) ); - ++m_insertedListeners; - } - - void MultiReporter::addReporter( IEventListenerPtr&& reporter ) { - updatePreferences(*reporter); - - // We will need to output the captured stdout if there are reporters - // that do not want it captured. - // We do not consider listeners, because it is generally assumed that - // listeners are output-transparent, even though they can ask for stdout - // capture to do something with it. - m_haveNoncapturingReporters |= !reporter->getPreferences().shouldRedirectStdOut; - - // Reporters can always be placed to the back without breaking the - // reporting order - m_reporterLikes.push_back( CATCH_MOVE( reporter ) ); - } - - void MultiReporter::noMatchingTestCases( StringRef unmatchedSpec ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->noMatchingTestCases( unmatchedSpec ); - } - } - - void MultiReporter::fatalErrorEncountered( StringRef error ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->fatalErrorEncountered( error ); - } - } - - void MultiReporter::reportInvalidTestSpec( StringRef arg ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->reportInvalidTestSpec( arg ); - } - } - - void MultiReporter::benchmarkPreparing( StringRef name ) { - for (auto& reporterish : m_reporterLikes) { - reporterish->benchmarkPreparing(name); - } - } - void MultiReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->benchmarkStarting( benchmarkInfo ); - } - } - void MultiReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->benchmarkEnded( benchmarkStats ); - } - } - - void MultiReporter::benchmarkFailed( StringRef error ) { - for (auto& reporterish : m_reporterLikes) { - reporterish->benchmarkFailed(error); - } - } - - void MultiReporter::testRunStarting( TestRunInfo const& testRunInfo ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->testRunStarting( testRunInfo ); - } - } - - void MultiReporter::testCaseStarting( TestCaseInfo const& testInfo ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->testCaseStarting( testInfo ); - } - } - - void - MultiReporter::testCasePartialStarting( TestCaseInfo const& testInfo, - uint64_t partNumber ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->testCasePartialStarting( testInfo, partNumber ); - } - } - - void MultiReporter::sectionStarting( SectionInfo const& sectionInfo ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->sectionStarting( sectionInfo ); - } - } - - void MultiReporter::assertionStarting( AssertionInfo const& assertionInfo ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->assertionStarting( assertionInfo ); - } - } - - // The return value indicates if the messages buffer should be cleared: - void MultiReporter::assertionEnded( AssertionStats const& assertionStats ) { - const bool reportByDefault = - assertionStats.assertionResult.getResultType() != ResultWas::Ok || - m_config->includeSuccessfulResults(); - - for ( auto & reporterish : m_reporterLikes ) { - if ( reportByDefault || - reporterish->getPreferences().shouldReportAllAssertions ) { - reporterish->assertionEnded( assertionStats ); - } - } - } - - void MultiReporter::sectionEnded( SectionStats const& sectionStats ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->sectionEnded( sectionStats ); - } - } - - void MultiReporter::testCasePartialEnded( TestCaseStats const& testStats, - uint64_t partNumber ) { - if ( m_preferences.shouldRedirectStdOut && - m_haveNoncapturingReporters ) { - if ( !testStats.stdOut.empty() ) { - Catch::cout() << testStats.stdOut << std::flush; - } - if ( !testStats.stdErr.empty() ) { - Catch::cerr() << testStats.stdErr << std::flush; - } - } - - for ( auto& reporterish : m_reporterLikes ) { - reporterish->testCasePartialEnded( testStats, partNumber ); - } - } - - void MultiReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->testCaseEnded( testCaseStats ); - } - } - - void MultiReporter::testRunEnded( TestRunStats const& testRunStats ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->testRunEnded( testRunStats ); - } - } - - - void MultiReporter::skipTest( TestCaseInfo const& testInfo ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->skipTest( testInfo ); - } - } - - void MultiReporter::listReporters(std::vector const& descriptions) { - for (auto& reporterish : m_reporterLikes) { - reporterish->listReporters(descriptions); - } - } - - void MultiReporter::listListeners( - std::vector const& descriptions ) { - for ( auto& reporterish : m_reporterLikes ) { - reporterish->listListeners( descriptions ); - } - } - - void MultiReporter::listTests(std::vector const& tests) { - for (auto& reporterish : m_reporterLikes) { - reporterish->listTests(tests); - } - } - - void MultiReporter::listTags(std::vector const& tags) { - for (auto& reporterish : m_reporterLikes) { - reporterish->listTags(tags); - } - } - -} // end namespace Catch - - - - - -namespace Catch { - namespace Detail { - - void registerReporterImpl( std::string const& name, - IReporterFactoryPtr reporterPtr ) { - CATCH_TRY { - getMutableRegistryHub().registerReporter( - name, CATCH_MOVE( reporterPtr ) ); - } - CATCH_CATCH_ALL { - // Do not throw when constructing global objects, instead - // register the exception to be processed later - getMutableRegistryHub().registerStartupException(); - } - } - - } // namespace Detail -} // namespace Catch - - - - -#include - -namespace Catch { - - namespace { - std::string createMetadataString(IConfig const& config) { - ReusableStringStream sstr; - if ( config.testSpec().hasFilters() ) { - sstr << "filters='" - << config.testSpec() - << "' "; - } - sstr << "rng-seed=" << config.rngSeed(); - return sstr.str(); - } - } - - void SonarQubeReporter::testRunStarting(TestRunInfo const& testRunInfo) { - CumulativeReporterBase::testRunStarting(testRunInfo); - - xml.writeComment( createMetadataString( *m_config ) ); - xml.startElement("testExecutions"); - xml.writeAttribute("version"_sr, '1'); - } - - void SonarQubeReporter::writeRun( TestRunNode const& runNode ) { - std::map> testsPerFile; - - for ( auto const& child : runNode.children ) { - testsPerFile[child->value.testInfo->lineInfo.file].push_back( - child.get() ); - } - - for ( auto const& kv : testsPerFile ) { - writeTestFile( kv.first, kv.second ); - } - } - - void SonarQubeReporter::writeTestFile(StringRef filename, std::vector const& testCaseNodes) { - XmlWriter::ScopedElement e = xml.scopedElement("file"); - xml.writeAttribute("path"_sr, filename); - - for (auto const& child : testCaseNodes) - writeTestCase(*child); - } - - void SonarQubeReporter::writeTestCase(TestCaseNode const& testCaseNode) { - // All test cases have exactly one section - which represents the - // test case itself. That section may have 0-n nested sections - assert(testCaseNode.children.size() == 1); - SectionNode const& rootSection = *testCaseNode.children.front(); - writeSection("", rootSection, testCaseNode.value.testInfo->okToFail()); - } - - void SonarQubeReporter::writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) { - std::string name = trim(sectionNode.stats.sectionInfo.name); - if (!rootName.empty()) - name = rootName + '/' + name; - - if ( sectionNode.hasAnyAssertions() - || !sectionNode.stdOut.empty() - || !sectionNode.stdErr.empty() ) { - XmlWriter::ScopedElement e = xml.scopedElement("testCase"); - xml.writeAttribute("name"_sr, name); - xml.writeAttribute("duration"_sr, static_cast(sectionNode.stats.durationInSeconds * 1000)); - - writeAssertions(sectionNode, okToFail); - } - - for (auto const& childNode : sectionNode.childSections) - writeSection(name, *childNode, okToFail); - } - - void SonarQubeReporter::writeAssertions(SectionNode const& sectionNode, bool okToFail) { - for (auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) { - if (assertionOrBenchmark.isAssertion()) { - writeAssertion(assertionOrBenchmark.asAssertion(), okToFail); - } - } - } - - void SonarQubeReporter::writeAssertion(AssertionStats const& stats, bool okToFail) { - AssertionResult const& result = stats.assertionResult; - if ( !result.isOk() || - result.getResultType() == ResultWas::ExplicitSkip ) { - std::string elementName; - if (okToFail) { - elementName = "skipped"; - } else { - switch (result.getResultType()) { - case ResultWas::ThrewException: - case ResultWas::FatalErrorCondition: - elementName = "error"; - break; - case ResultWas::ExplicitFailure: - case ResultWas::ExpressionFailed: - case ResultWas::DidntThrowException: - elementName = "failure"; - break; - case ResultWas::ExplicitSkip: - elementName = "skipped"; - break; - // We should never see these here: - case ResultWas::Info: - case ResultWas::Warning: - case ResultWas::Ok: - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - elementName = "internalError"; - break; - } - } - - XmlWriter::ScopedElement e = xml.scopedElement(elementName); - - ReusableStringStream messageRss; - messageRss << result.getTestMacroName() << '(' << result.getExpression() << ')'; - xml.writeAttribute("message"_sr, messageRss.str()); - - ReusableStringStream textRss; - if ( result.getResultType() == ResultWas::ExplicitSkip ) { - textRss << "SKIPPED\n"; - } else { - textRss << "FAILED:\n"; - if (result.hasExpression()) { - textRss << '\t' << result.getExpressionInMacro() << '\n'; - } - if (result.hasExpandedExpression()) { - textRss << "with expansion:\n\t" << result.getExpandedExpression() << '\n'; - } - } - - if (!result.getMessage().empty()) - textRss << result.getMessage() << '\n'; - - for (auto const& msg : stats.infoMessages) - if (msg.type == ResultWas::Info) - textRss << msg.message << '\n'; - - textRss << "at " << result.getSourceInfo(); - xml.writeText(textRss.str(), XmlFormatting::Newline); - } - } - -} // end namespace Catch - - - -namespace Catch { - - StreamingReporterBase::~StreamingReporterBase() = default; - - void - StreamingReporterBase::testRunStarting( TestRunInfo const& _testRunInfo ) { - currentTestRunInfo = _testRunInfo; - } - - void StreamingReporterBase::testRunEnded( TestRunStats const& ) { - currentTestCaseInfo = nullptr; - } - -} // end namespace Catch - - - -#include -#include -#include - -namespace Catch { - - namespace { - // Yes, this has to be outside the class and namespaced by naming. - // Making older compiler happy is hard. - static constexpr StringRef tapFailedString = "not ok"_sr; - static constexpr StringRef tapPassedString = "ok"_sr; - static constexpr Colour::Code tapDimColour = Colour::FileName; - - class TapAssertionPrinter { - public: - TapAssertionPrinter& operator= (TapAssertionPrinter const&) = delete; - TapAssertionPrinter(TapAssertionPrinter const&) = delete; - TapAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter, ColourImpl* colour_) - : stream(_stream) - , result(_stats.assertionResult) - , messages(_stats.infoMessages) - , itMessage(_stats.infoMessages.begin()) - , printInfoMessages(true) - , counter(_counter) - , colourImpl( colour_ ) {} - - void print() { - itMessage = messages.begin(); - - switch (result.getResultType()) { - case ResultWas::Ok: - printResultType(tapPassedString); - printOriginalExpression(); - printReconstructedExpression(); - if (!result.hasExpression()) - printRemainingMessages(Colour::None); - else - printRemainingMessages(); - break; - case ResultWas::ExpressionFailed: - if (result.isOk()) { - printResultType(tapPassedString); - } else { - printResultType(tapFailedString); - } - printOriginalExpression(); - printReconstructedExpression(); - if (result.isOk()) { - printIssue(" # TODO"); - } - printRemainingMessages(); - break; - case ResultWas::ThrewException: - printResultType(tapFailedString); - printIssue("unexpected exception with message:"_sr); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::FatalErrorCondition: - printResultType(tapFailedString); - printIssue("fatal error condition with message:"_sr); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::DidntThrowException: - printResultType(tapFailedString); - printIssue("expected exception, got none"_sr); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::Info: - printResultType("info"_sr); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::Warning: - printResultType("warning"_sr); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::ExplicitFailure: - printResultType(tapFailedString); - printIssue("explicitly"_sr); - printRemainingMessages(Colour::None); - break; - case ResultWas::ExplicitSkip: - printResultType(tapPassedString); - printIssue(" # SKIP"_sr); - printMessage(); - printRemainingMessages(); - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - printResultType("** internal error **"_sr); - break; - } - } - - private: - void printResultType(StringRef passOrFail) const { - if (!passOrFail.empty()) { - stream << passOrFail << ' ' << counter << " -"; - } - } - - void printIssue(StringRef issue) const { - stream << ' ' << issue; - } - - void printExpressionWas() { - if (result.hasExpression()) { - stream << ';'; - stream << colourImpl->guardColour( tapDimColour ) - << " expression was:"; - printOriginalExpression(); - } - } - - void printOriginalExpression() const { - if (result.hasExpression()) { - stream << ' ' << result.getExpression(); - } - } - - void printReconstructedExpression() const { - if (result.hasExpandedExpression()) { - stream << colourImpl->guardColour( tapDimColour ) << " for: "; - - std::string expr = result.getExpandedExpression(); - std::replace(expr.begin(), expr.end(), '\n', ' '); - stream << expr; - } - } - - void printMessage() { - if (itMessage != messages.end()) { - stream << " '" << itMessage->message << '\''; - ++itMessage; - } - } - - void printRemainingMessages(Colour::Code colour = tapDimColour) { - if (itMessage == messages.end()) { - return; - } - - // using messages.end() directly (or auto) yields compilation error: - std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast(std::distance(itMessage, itEnd)); - - stream << colourImpl->guardColour( colour ) << " with " - << pluralise( N, "message"_sr ) << ':'; - - for (; itMessage != itEnd; ) { - // If this assertion is a warning ignore any INFO messages - if (printInfoMessages || itMessage->type != ResultWas::Info) { - stream << " '" << itMessage->message << '\''; - if (++itMessage != itEnd) { - stream << colourImpl->guardColour(tapDimColour) << " and"; - } - } - } - } - - private: - std::ostream& stream; - AssertionResult const& result; - std::vector const& messages; - std::vector::const_iterator itMessage; - bool printInfoMessages; - std::size_t counter; - ColourImpl* colourImpl; - }; - - } // End anonymous namespace - - void TAPReporter::testRunStarting( TestRunInfo const& ) { - if ( m_config->testSpec().hasFilters() ) { - m_stream << "# filters: " << m_config->testSpec() << '\n'; - } - m_stream << "# rng-seed: " << m_config->rngSeed() << '\n'; - } - - void TAPReporter::noMatchingTestCases( StringRef unmatchedSpec ) { - m_stream << "# No test cases matched '" << unmatchedSpec << "'\n"; - } - - void TAPReporter::assertionEnded(AssertionStats const& _assertionStats) { - ++counter; - - m_stream << "# " << currentTestCaseInfo->name << '\n'; - TapAssertionPrinter printer(m_stream, _assertionStats, counter, m_colour.get()); - printer.print(); - - m_stream << '\n' << std::flush; - } - - void TAPReporter::testRunEnded(TestRunStats const& _testRunStats) { - m_stream << "1.." << _testRunStats.totals.assertions.total(); - if (_testRunStats.totals.testCases.total() == 0) { - m_stream << " # Skipped: No tests ran."; - } - m_stream << "\n\n" << std::flush; - StreamingReporterBase::testRunEnded(_testRunStats); - } - - - - -} // end namespace Catch - - - - -#include -#include - -namespace Catch { - - namespace { - // if string has a : in first line will set indent to follow it on - // subsequent lines - void printHeaderString(std::ostream& os, std::string const& _string, std::size_t indent = 0) { - std::size_t i = _string.find(": "); - if (i != std::string::npos) - i += 2; - else - i = 0; - os << TextFlow::Column(_string) - .indent(indent + i) - .initialIndent(indent) << '\n'; - } - - std::string escape(StringRef str) { - std::string escaped = static_cast(str); - replaceInPlace(escaped, "|", "||"); - replaceInPlace(escaped, "'", "|'"); - replaceInPlace(escaped, "\n", "|n"); - replaceInPlace(escaped, "\r", "|r"); - replaceInPlace(escaped, "[", "|["); - replaceInPlace(escaped, "]", "|]"); - return escaped; - } - } // end anonymous namespace - - - TeamCityReporter::~TeamCityReporter() {} - - void TeamCityReporter::testRunStarting( TestRunInfo const& runInfo ) { - m_stream << "##teamcity[testSuiteStarted name='" << escape( runInfo.name ) - << "']\n"; - } - - void TeamCityReporter::testRunEnded( TestRunStats const& runStats ) { - m_stream << "##teamcity[testSuiteFinished name='" - << escape( runStats.runInfo.name ) << "']\n"; - } - - void TeamCityReporter::assertionEnded(AssertionStats const& assertionStats) { - AssertionResult const& result = assertionStats.assertionResult; - if ( !result.isOk() || - result.getResultType() == ResultWas::ExplicitSkip ) { - - ReusableStringStream msg; - if (!m_headerPrintedForThisSection) - printSectionHeader(msg.get()); - m_headerPrintedForThisSection = true; - - msg << result.getSourceInfo() << '\n'; - - switch (result.getResultType()) { - case ResultWas::ExpressionFailed: - msg << "expression failed"; - break; - case ResultWas::ThrewException: - msg << "unexpected exception"; - break; - case ResultWas::FatalErrorCondition: - msg << "fatal error condition"; - break; - case ResultWas::DidntThrowException: - msg << "no exception was thrown where one was expected"; - break; - case ResultWas::ExplicitFailure: - msg << "explicit failure"; - break; - case ResultWas::ExplicitSkip: - msg << "explicit skip"; - break; - - // We shouldn't get here because of the isOk() test - case ResultWas::Ok: - case ResultWas::Info: - case ResultWas::Warning: - CATCH_ERROR("Internal error in TeamCity reporter"); - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - CATCH_ERROR("Not implemented"); - } - if (assertionStats.infoMessages.size() == 1) - msg << " with message:"; - if (assertionStats.infoMessages.size() > 1) - msg << " with messages:"; - for (auto const& messageInfo : assertionStats.infoMessages) - msg << "\n \"" << messageInfo.message << '"'; - - - if (result.hasExpression()) { - msg << - "\n " << result.getExpressionInMacro() << "\n" - "with expansion:\n" - " " << result.getExpandedExpression() << '\n'; - } - - if ( result.getResultType() == ResultWas::ExplicitSkip ) { - m_stream << "##teamcity[testIgnored"; - } else if ( currentTestCaseInfo->okToFail() ) { - msg << "- failure ignore as test marked as 'ok to fail'\n"; - m_stream << "##teamcity[testIgnored"; - } else { - m_stream << "##teamcity[testFailed"; - } - m_stream << " name='" << escape( currentTestCaseInfo->name ) << '\'' - << " message='" << escape( msg.str() ) << '\'' << "]\n"; - } - m_stream.flush(); - } - - void TeamCityReporter::testCaseStarting(TestCaseInfo const& testInfo) { - m_testTimer.start(); - StreamingReporterBase::testCaseStarting(testInfo); - m_stream << "##teamcity[testStarted name='" - << escape(testInfo.name) << "']\n"; - m_stream.flush(); - } - - void TeamCityReporter::testCaseEnded(TestCaseStats const& testCaseStats) { - StreamingReporterBase::testCaseEnded(testCaseStats); - auto const& testCaseInfo = *testCaseStats.testInfo; - if (!testCaseStats.stdOut.empty()) - m_stream << "##teamcity[testStdOut name='" - << escape(testCaseInfo.name) - << "' out='" << escape(testCaseStats.stdOut) << "']\n"; - if (!testCaseStats.stdErr.empty()) - m_stream << "##teamcity[testStdErr name='" - << escape(testCaseInfo.name) - << "' out='" << escape(testCaseStats.stdErr) << "']\n"; - m_stream << "##teamcity[testFinished name='" - << escape(testCaseInfo.name) << "' duration='" - << m_testTimer.getElapsedMilliseconds() << "']\n"; - m_stream.flush(); - } - - void TeamCityReporter::printSectionHeader(std::ostream& os) { - assert(!m_sectionStack.empty()); - - if (m_sectionStack.size() > 1) { - os << lineOfChars('-') << '\n'; - - std::vector::const_iterator - it = m_sectionStack.begin() + 1, // Skip first section (test case) - itEnd = m_sectionStack.end(); - for (; it != itEnd; ++it) - printHeaderString(os, it->name); - os << lineOfChars('-') << '\n'; - } - - SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; - - os << lineInfo << '\n'; - os << lineOfChars('.') << "\n\n"; - } - -} // end namespace Catch - - - - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled - // and default is missing) is enabled -#endif - -namespace Catch { - XmlReporter::XmlReporter( ReporterConfig&& _config ) - : StreamingReporterBase( CATCH_MOVE(_config) ), - m_xml(m_stream) - { - m_preferences.shouldRedirectStdOut = true; - m_preferences.shouldReportAllAssertions = true; - } - - XmlReporter::~XmlReporter() = default; - - std::string XmlReporter::getDescription() { - return "Reports test results as an XML document"; - } - - std::string XmlReporter::getStylesheetRef() const { - return std::string(); - } - - void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { - m_xml - .writeAttribute( "filename"_sr, sourceInfo.file ) - .writeAttribute( "line"_sr, sourceInfo.line ); - } - - void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { - StreamingReporterBase::testRunStarting( testInfo ); - std::string stylesheetRef = getStylesheetRef(); - if( !stylesheetRef.empty() ) - m_xml.writeStylesheetRef( stylesheetRef ); - m_xml.startElement("Catch2TestRun") - .writeAttribute("name"_sr, m_config->name()) - .writeAttribute("rng-seed"_sr, m_config->rngSeed()) - .writeAttribute("xml-format-version"_sr, 2) - .writeAttribute("catch2-version"_sr, libraryVersion()); - if ( m_config->testSpec().hasFilters() ) { - m_xml.writeAttribute( "filters"_sr, m_config->testSpec() ); - } - } - - void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { - StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ) - .writeAttribute( "name"_sr, trim( StringRef(testInfo.name) ) ) - .writeAttribute( "tags"_sr, testInfo.tagsAsString() ); - - writeSourceInfo( testInfo.lineInfo ); - - if ( m_config->showDurations() == ShowDurations::Always ) - m_testCaseTimer.start(); - m_xml.ensureTagClosed(); - } - - void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { - StreamingReporterBase::sectionStarting( sectionInfo ); - if( m_sectionDepth++ > 0 ) { - m_xml.startElement( "Section" ) - .writeAttribute( "name"_sr, trim( StringRef(sectionInfo.name) ) ); - writeSourceInfo( sectionInfo.lineInfo ); - m_xml.ensureTagClosed(); - } - } - - void XmlReporter::assertionStarting( AssertionInfo const& ) { } - - void XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { - - AssertionResult const& result = assertionStats.assertionResult; - - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - - if( includeResults || result.getResultType() == ResultWas::Warning ) { - // Print any info messages in tags. - for( auto const& msg : assertionStats.infoMessages ) { - if( msg.type == ResultWas::Info && includeResults ) { - m_xml.scopedElement( "Info" ) - .writeText( msg.message ); - } else if ( msg.type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( msg.message ); - } - } - } - - // Drop out if result was successful but we're not printing them. - if ( !includeResults && result.getResultType() != ResultWas::Warning && - result.getResultType() != ResultWas::ExplicitSkip ) { - return; - } - - // Print the expression if there is one. - if( result.hasExpression() ) { - m_xml.startElement( "Expression" ) - .writeAttribute( "success"_sr, result.succeeded() ) - .writeAttribute( "type"_sr, result.getTestMacroName() ); - - writeSourceInfo( result.getSourceInfo() ); - - m_xml.scopedElement( "Original" ) - .writeText( result.getExpression() ); - m_xml.scopedElement( "Expanded" ) - .writeText( result.getExpandedExpression() ); - } - - // And... Print a result applicable to each result type. - switch( result.getResultType() ) { - case ResultWas::ThrewException: - m_xml.startElement( "Exception" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::FatalErrorCondition: - m_xml.startElement( "FatalErrorCondition" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::Info: - m_xml.scopedElement( "Info" ) - .writeText( result.getMessage() ); - break; - case ResultWas::Warning: - // Warning will already have been written - break; - case ResultWas::ExplicitFailure: - m_xml.startElement( "Failure" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::ExplicitSkip: - m_xml.startElement( "Skip" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - default: - break; - } - - if( result.hasExpression() ) - m_xml.endElement(); - } - - void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { - StreamingReporterBase::sectionEnded( sectionStats ); - if ( --m_sectionDepth > 0 ) { - { - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); - e.writeAttribute( "successes"_sr, sectionStats.assertions.passed ); - e.writeAttribute( "failures"_sr, sectionStats.assertions.failed ); - e.writeAttribute( "expectedFailures"_sr, sectionStats.assertions.failedButOk ); - e.writeAttribute( "skipped"_sr, sectionStats.assertions.skipped > 0 ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds"_sr, sectionStats.durationInSeconds ); - } - // Ends assertion tag - m_xml.endElement(); - } - } - - void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { - StreamingReporterBase::testCaseEnded( testCaseStats ); - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); - e.writeAttribute( "success"_sr, testCaseStats.totals.assertions.allOk() ); - e.writeAttribute( "skips"_sr, testCaseStats.totals.assertions.skipped ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() ); - if( !testCaseStats.stdOut.empty() ) - m_xml.scopedElement( "StdOut" ).writeText( trim( StringRef(testCaseStats.stdOut) ), XmlFormatting::Newline ); - if( !testCaseStats.stdErr.empty() ) - m_xml.scopedElement( "StdErr" ).writeText( trim( StringRef(testCaseStats.stdErr) ), XmlFormatting::Newline ); - - m_xml.endElement(); - } - - void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { - StreamingReporterBase::testRunEnded( testRunStats ); - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes"_sr, testRunStats.totals.assertions.passed ) - .writeAttribute( "failures"_sr, testRunStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures"_sr, testRunStats.totals.assertions.failedButOk ) - .writeAttribute( "skips"_sr, testRunStats.totals.assertions.skipped ); - m_xml.scopedElement( "OverallResultsCases") - .writeAttribute( "successes"_sr, testRunStats.totals.testCases.passed ) - .writeAttribute( "failures"_sr, testRunStats.totals.testCases.failed ) - .writeAttribute( "expectedFailures"_sr, testRunStats.totals.testCases.failedButOk ) - .writeAttribute( "skips"_sr, testRunStats.totals.testCases.skipped ); - m_xml.endElement(); - } - - void XmlReporter::benchmarkPreparing( StringRef name ) { - m_xml.startElement("BenchmarkResults") - .writeAttribute("name"_sr, name); - } - - void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) { - m_xml.writeAttribute("samples"_sr, info.samples) - .writeAttribute("resamples"_sr, info.resamples) - .writeAttribute("iterations"_sr, info.iterations) - .writeAttribute("clockResolution"_sr, info.clockResolution) - .writeAttribute("estimatedDuration"_sr, info.estimatedDuration) - .writeComment("All values in nano seconds"_sr); - } - - void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { - m_xml.startElement("mean") - .writeAttribute("value"_sr, benchmarkStats.mean.point.count()) - .writeAttribute("lowerBound"_sr, benchmarkStats.mean.lower_bound.count()) - .writeAttribute("upperBound"_sr, benchmarkStats.mean.upper_bound.count()) - .writeAttribute("ci"_sr, benchmarkStats.mean.confidence_interval); - m_xml.endElement(); - m_xml.startElement("standardDeviation") - .writeAttribute("value"_sr, benchmarkStats.standardDeviation.point.count()) - .writeAttribute("lowerBound"_sr, benchmarkStats.standardDeviation.lower_bound.count()) - .writeAttribute("upperBound"_sr, benchmarkStats.standardDeviation.upper_bound.count()) - .writeAttribute("ci"_sr, benchmarkStats.standardDeviation.confidence_interval); - m_xml.endElement(); - m_xml.startElement("outliers") - .writeAttribute("variance"_sr, benchmarkStats.outlierVariance) - .writeAttribute("lowMild"_sr, benchmarkStats.outliers.low_mild) - .writeAttribute("lowSevere"_sr, benchmarkStats.outliers.low_severe) - .writeAttribute("highMild"_sr, benchmarkStats.outliers.high_mild) - .writeAttribute("highSevere"_sr, benchmarkStats.outliers.high_severe); - m_xml.endElement(); - m_xml.endElement(); - } - - void XmlReporter::benchmarkFailed(StringRef error) { - m_xml.scopedElement("failed"). - writeAttribute("message"_sr, error); - m_xml.endElement(); - } - - void XmlReporter::listReporters(std::vector const& descriptions) { - auto outerTag = m_xml.scopedElement("AvailableReporters"); - for (auto const& reporter : descriptions) { - auto inner = m_xml.scopedElement("Reporter"); - m_xml.startElement("Name", XmlFormatting::Indent) - .writeText(reporter.name, XmlFormatting::None) - .endElement(XmlFormatting::Newline); - m_xml.startElement("Description", XmlFormatting::Indent) - .writeText(reporter.description, XmlFormatting::None) - .endElement(XmlFormatting::Newline); - } - } - - void XmlReporter::listListeners(std::vector const& descriptions) { - auto outerTag = m_xml.scopedElement( "RegisteredListeners" ); - for ( auto const& listener : descriptions ) { - auto inner = m_xml.scopedElement( "Listener" ); - m_xml.startElement( "Name", XmlFormatting::Indent ) - .writeText( listener.name, XmlFormatting::None ) - .endElement( XmlFormatting::Newline ); - m_xml.startElement( "Description", XmlFormatting::Indent ) - .writeText( listener.description, XmlFormatting::None ) - .endElement( XmlFormatting::Newline ); - } - } - - void XmlReporter::listTests(std::vector const& tests) { - auto outerTag = m_xml.scopedElement("MatchingTests"); - for (auto const& test : tests) { - auto innerTag = m_xml.scopedElement("TestCase"); - auto const& testInfo = test.getTestCaseInfo(); - m_xml.startElement("Name", XmlFormatting::Indent) - .writeText(testInfo.name, XmlFormatting::None) - .endElement(XmlFormatting::Newline); - m_xml.startElement("ClassName", XmlFormatting::Indent) - .writeText(testInfo.className, XmlFormatting::None) - .endElement(XmlFormatting::Newline); - m_xml.startElement("Tags", XmlFormatting::Indent) - .writeText(testInfo.tagsAsString(), XmlFormatting::None) - .endElement(XmlFormatting::Newline); - - auto sourceTag = m_xml.scopedElement("SourceInfo"); - m_xml.startElement("File", XmlFormatting::Indent) - .writeText(testInfo.lineInfo.file, XmlFormatting::None) - .endElement(XmlFormatting::Newline); - m_xml.startElement("Line", XmlFormatting::Indent) - .writeText(std::to_string(testInfo.lineInfo.line), XmlFormatting::None) - .endElement(XmlFormatting::Newline); - } - } - - void XmlReporter::listTags(std::vector const& tags) { - auto outerTag = m_xml.scopedElement("TagsFromMatchingTests"); - for (auto const& tag : tags) { - auto innerTag = m_xml.scopedElement("Tag"); - m_xml.startElement("Count", XmlFormatting::Indent) - .writeText(std::to_string(tag.count), XmlFormatting::None) - .endElement(XmlFormatting::Newline); - auto aliasTag = m_xml.scopedElement("Aliases"); - for (auto const& alias : tag.spellings) { - m_xml.startElement("Alias", XmlFormatting::Indent) - .writeText(alias, XmlFormatting::None) - .endElement(XmlFormatting::Newline); - } - } - } - -} // end namespace Catch - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif diff --git a/block/test/catch_amalgamated.hpp b/block/test/catch_amalgamated.hpp deleted file mode 100644 index 321cec5..0000000 --- a/block/test/catch_amalgamated.hpp +++ /dev/null @@ -1,12972 +0,0 @@ -// Copyright Catch2 Authors -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.txt or copy at -// https://www.boost.org/LICENSE_1_0.txt) - -// SPDX-License-Identifier: BSL-1.0 - -// Catch v3.3.2 -// Generated: 2023-02-26 10:28:46.785908 -// ---------------------------------------------------------- -// This file is an amalgamation of multiple different files. -// You probably shouldn't edit it directly. -// ---------------------------------------------------------- -#ifndef CATCH_AMALGAMATED_HPP_INCLUDED -#define CATCH_AMALGAMATED_HPP_INCLUDED - - -/** \file - * This is a convenience header for Catch2. It includes **all** of Catch2 headers. - * - * Generally the Catch2 users should use specific includes they need, - * but this header can be used instead for ease-of-experimentation, or - * just plain convenience, at the cost of (significantly) increased - * compilation times. - * - * When a new header is added to either the top level folder, or to the - * corresponding internal subfolder, it should be added here. Headers - * added to the various subparts (e.g. matchers, generators, etc...), - * should go their respective catch-all headers. - */ - -#ifndef CATCH_ALL_HPP_INCLUDED -#define CATCH_ALL_HPP_INCLUDED - - - -/** \file - * This is a convenience header for Catch2's benchmarking. It includes - * **all** of Catch2 headers related to benchmarking. - * - * Generally the Catch2 users should use specific includes they need, - * but this header can be used instead for ease-of-experimentation, or - * just plain convenience, at the cost of (significantly) increased - * compilation times. - * - * When a new header is added to either the `benchmark` folder, or to - * the corresponding internal (detail) subfolder, it should be added here. - */ - -#ifndef CATCH_BENCHMARK_ALL_HPP_INCLUDED -#define CATCH_BENCHMARK_ALL_HPP_INCLUDED - - - -// Adapted from donated nonius code. - -#ifndef CATCH_BENCHMARK_HPP_INCLUDED -#define CATCH_BENCHMARK_HPP_INCLUDED - - - -#ifndef CATCH_INTERFACES_CONFIG_HPP_INCLUDED -#define CATCH_INTERFACES_CONFIG_HPP_INCLUDED - - - -#ifndef CATCH_NONCOPYABLE_HPP_INCLUDED -#define CATCH_NONCOPYABLE_HPP_INCLUDED - -namespace Catch { - namespace Detail { - - //! Deriving classes become noncopyable and nonmovable - class NonCopyable { - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable&& ) = delete; - NonCopyable& operator=( NonCopyable const& ) = delete; - NonCopyable& operator=( NonCopyable&& ) = delete; - - protected: - NonCopyable() noexcept = default; - }; - - } // namespace Detail -} // namespace Catch - -#endif // CATCH_NONCOPYABLE_HPP_INCLUDED - - -#ifndef CATCH_STRINGREF_HPP_INCLUDED -#define CATCH_STRINGREF_HPP_INCLUDED - -#include -#include -#include -#include - -#include - -namespace Catch { - - /// A non-owning string class (similar to the forthcoming std::string_view) - /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. - class StringRef { - public: - using size_type = std::size_t; - using const_iterator = const char*; - - private: - static constexpr char const* const s_empty = ""; - - char const* m_start = s_empty; - size_type m_size = 0; - - public: // construction - constexpr StringRef() noexcept = default; - - StringRef( char const* rawChars ) noexcept; - - constexpr StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - {} - - StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) - {} - - explicit operator std::string() const { - return std::string(m_start, m_size); - } - - public: // operators - auto operator == ( StringRef other ) const noexcept -> bool { - return m_size == other.m_size - && (std::memcmp( m_start, other.m_start, m_size ) == 0); - } - auto operator != (StringRef other) const noexcept -> bool { - return !(*this == other); - } - - constexpr auto operator[] ( size_type index ) const noexcept -> char { - assert(index < m_size); - return m_start[index]; - } - - bool operator<(StringRef rhs) const noexcept; - - public: // named queries - constexpr auto empty() const noexcept -> bool { - return m_size == 0; - } - constexpr auto size() const noexcept -> size_type { - return m_size; - } - - // Returns a substring of [start, start + length). - // If start + length > size(), then the substring is [start, start + size()). - // If start > size(), then the substring is empty. - constexpr StringRef substr(size_type start, size_type length) const noexcept { - if (start < m_size) { - const auto shortened_size = m_size - start; - return StringRef(m_start + start, (shortened_size < length) ? shortened_size : length); - } else { - return StringRef(); - } - } - - // Returns the current start pointer. May not be null-terminated. - constexpr char const* data() const noexcept { - return m_start; - } - - constexpr const_iterator begin() const { return m_start; } - constexpr const_iterator end() const { return m_start + m_size; } - - - friend std::string& operator += (std::string& lhs, StringRef sr); - friend std::ostream& operator << (std::ostream& os, StringRef sr); - friend std::string operator+(StringRef lhs, StringRef rhs); - - /** - * Provides a three-way comparison with rhs - * - * Returns negative number if lhs < rhs, 0 if lhs == rhs, and a positive - * number if lhs > rhs - */ - int compare( StringRef rhs ) const; - }; - - - constexpr auto operator ""_sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { - return StringRef( rawChars, size ); - } -} // namespace Catch - -constexpr auto operator ""_catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { - return Catch::StringRef( rawChars, size ); -} - -#endif // CATCH_STRINGREF_HPP_INCLUDED - -#include -#include -#include -#include - -namespace Catch { - - enum class Verbosity { - Quiet = 0, - Normal, - High - }; - - struct WarnAbout { enum What { - Nothing = 0x00, - //! A test case or leaf section did not run any assertions - NoAssertions = 0x01, - //! A command line test spec matched no test cases - UnmatchedTestSpec = 0x02, - }; }; - - enum class ShowDurations { - DefaultForReporter, - Always, - Never - }; - enum class TestRunOrder { - Declared, - LexicographicallySorted, - Randomized - }; - enum class ColourMode : std::uint8_t { - //! Let Catch2 pick implementation based on platform detection - PlatformDefault, - //! Use ANSI colour code escapes - ANSI, - //! Use Win32 console colour API - Win32, - //! Don't use any colour - None - }; - struct WaitForKeypress { enum When { - Never, - BeforeStart = 1, - BeforeExit = 2, - BeforeStartAndExit = BeforeStart | BeforeExit - }; }; - - class TestSpec; - class IStream; - - class IConfig : public Detail::NonCopyable { - public: - virtual ~IConfig(); - - virtual bool allowThrows() const = 0; - virtual StringRef name() const = 0; - virtual bool includeSuccessfulResults() const = 0; - virtual bool shouldDebugBreak() const = 0; - virtual bool warnAboutMissingAssertions() const = 0; - virtual bool warnAboutUnmatchedTestSpecs() const = 0; - virtual bool zeroTestsCountAsSuccess() const = 0; - virtual int abortAfter() const = 0; - virtual bool showInvisibles() const = 0; - virtual ShowDurations showDurations() const = 0; - virtual double minDuration() const = 0; - virtual TestSpec const& testSpec() const = 0; - virtual bool hasTestFilters() const = 0; - virtual std::vector const& getTestsOrTags() const = 0; - virtual TestRunOrder runOrder() const = 0; - virtual uint32_t rngSeed() const = 0; - virtual unsigned int shardCount() const = 0; - virtual unsigned int shardIndex() const = 0; - virtual ColourMode defaultColourMode() const = 0; - virtual std::vector const& getSectionsToRun() const = 0; - virtual Verbosity verbosity() const = 0; - - virtual bool skipBenchmarks() const = 0; - virtual bool benchmarkNoAnalysis() const = 0; - virtual unsigned int benchmarkSamples() const = 0; - virtual double benchmarkConfidenceInterval() const = 0; - virtual unsigned int benchmarkResamples() const = 0; - virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0; - }; -} - -#endif // CATCH_INTERFACES_CONFIG_HPP_INCLUDED - - -#ifndef CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED -#define CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED - -// Detect a number of compiler features - by compiler -// The following features are defined: -// -// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? -// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? -// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? -// **************** -// Note to maintainers: if new toggles are added please document them -// in configuration.md, too -// **************** - -// In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. -// Many features, at point of detection, define an _INTERNAL_ macro, so they -// can be combined, en-mass, with the _NO_ forms later. - - - -#ifndef CATCH_PLATFORM_HPP_INCLUDED -#define CATCH_PLATFORM_HPP_INCLUDED - -// See e.g.: -// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html -#ifdef __APPLE__ -# include -# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ - (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) -# define CATCH_PLATFORM_MAC -# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) -# define CATCH_PLATFORM_IPHONE -# endif - -#elif defined(linux) || defined(__linux) || defined(__linux__) -# define CATCH_PLATFORM_LINUX - -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) -# define CATCH_PLATFORM_WINDOWS - -# if defined( WINAPI_FAMILY ) && ( WINAPI_FAMILY == WINAPI_FAMILY_APP ) -# define CATCH_PLATFORM_WINDOWS_UWP -# endif - -#elif defined(__ORBIS__) || defined(__PROSPERO__) -# define CATCH_PLATFORM_PLAYSTATION - -#endif - -#endif // CATCH_PLATFORM_HPP_INCLUDED - -#ifdef __cplusplus - -# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) -# define CATCH_CPP14_OR_GREATER -# endif - -# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) -# define CATCH_CPP17_OR_GREATER -# endif - -#endif - -// Only GCC compiler should be used in this block, so other compilers trying to -// mask themselves as GCC should be ignored. -#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) && !defined(__NVCOMPILER) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) - -// This only works on GCC 9+. so we have to also add a global suppression of Wparentheses -// for older versions of GCC. -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - _Pragma( "GCC diagnostic ignored \"-Wunused-variable\"" ) - -# define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ - _Pragma( "GCC diagnostic ignored \"-Wuseless-cast\"" ) - -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) - -#endif - -#if defined(__NVCOMPILER) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "diag push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "diag pop" ) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress declared_but_not_referenced" ) -#endif - -#if defined(__CUDACC__) && !defined(__clang__) -# ifdef __NVCC_DIAG_PRAGMA_SUPPORT__ -// New pragmas introduced in CUDA 11.5+ -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic pop" ) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "nv_diag_suppress 177" ) -# else -# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress 177" ) -# endif -#endif - -// clang-cl defines _MSC_VER as well as __clang__, which could cause the -// start/stop internal suppression macros to be double defined. -#if defined(__clang__) && !defined(_MSC_VER) - -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) - -#endif // __clang__ && !_MSC_VER - -#if defined(__clang__) - -// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug -// which results in calls to destructors being emitted for each temporary, -// without a matching initialization. In practice, this can result in something -// like `std::string::~string` being called on an uninitialized value. -// -// For example, this code will likely segfault under IBM XL: -// ``` -// REQUIRE(std::string("12") + "34" == "1234") -// ``` -// -// Similarly, NVHPC's implementation of `__builtin_constant_p` has a bug which -// results in calls to the immediately evaluated lambda expressions to be -// reported as unevaluated lambdas. -// https://developer.nvidia.com/nvidia_bug/3321845. -// -// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. -# if !defined(__ibmxl__) && !defined(__CUDACC__) && !defined( __NVCOMPILER ) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ -# endif - - -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") - -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) - -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) - -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) - -# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \ - _Pragma( "clang diagnostic ignored \"-Wcomma\"" ) - -#endif // __clang__ - - -//////////////////////////////////////////////////////////////////////////////// -// We know some environments not to support full POSIX signals -#if defined( CATCH_PLATFORM_WINDOWS ) || \ - defined( CATCH_PLATFORM_PLAYSTATION ) || \ - defined( __CYGWIN__ ) || \ - defined( __QNX__ ) || \ - defined( __EMSCRIPTEN__ ) || \ - defined( __DJGPP__ ) || \ - defined( __OS400__ ) -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -#else -# define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Assume that some platforms do not support getenv. -#if defined(CATCH_PLATFORM_WINDOWS_UWP) || defined(CATCH_PLATFORM_PLAYSTATION) -# define CATCH_INTERNAL_CONFIG_NO_GETENV -#else -# define CATCH_INTERNAL_CONFIG_GETENV -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Android somehow still does not support std::to_string -#if defined(__ANDROID__) -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Not all Windows environments support SEH properly -#if defined(__MINGW32__) -# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH -#endif - -//////////////////////////////////////////////////////////////////////////////// -// PS4 -#if defined(__ORBIS__) -# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Cygwin -#ifdef __CYGWIN__ - -// Required for some versions of Cygwin to declare gettimeofday -// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin -# define _BSD_SOURCE -// some versions of cygwin (most) do not support std::to_string. Use the libstd check. -// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 -# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ - && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) - -# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING - -# endif -#endif // __CYGWIN__ - -//////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#if defined(_MSC_VER) - -// We want to defer to nvcc-specific warning suppression if we are compiled -// with nvcc masquerading for MSVC. -# if !defined( __CUDACC__ ) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - __pragma( warning( push ) ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ - __pragma( warning( pop ) ) -# endif - -// Universal Windows platform does not support SEH -// Or console colours (or console at all...) -# if defined(CATCH_PLATFORM_WINDOWS_UWP) -# define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 -# else -# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH -# endif - -// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ -// _MSVC_TRADITIONAL == 0 means new conformant preprocessor -// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor -# if !defined(__clang__) // Handle Clang masquerading for msvc -# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) -# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -# endif // MSVC_TRADITIONAL -# endif // __clang__ - -#endif // _MSC_VER - -#if defined(_REENTRANT) || defined(_MSC_VER) -// Enable async processing, as -pthread is specified or no additional linking is required -# define CATCH_INTERNAL_CONFIG_USE_ASYNC -#endif // _MSC_VER - -//////////////////////////////////////////////////////////////////////////////// -// Check if we are compiled with -fno-exceptions or equivalent -#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) -# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED -#endif - - -//////////////////////////////////////////////////////////////////////////////// -// Embarcadero C++Build -#if defined(__BORLANDC__) - #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN -#endif - -//////////////////////////////////////////////////////////////////////////////// - -// RTX is a special version of Windows that is real time. -// This means that it is detected as Windows, but does not provide -// the same set of capabilities as real Windows does. -#if defined(UNDER_RTSS) || defined(RTX64_BUILD) - #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH - #define CATCH_INTERNAL_CONFIG_NO_ASYNC - #define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 -#endif - -#if !defined(_GLIBCXX_USE_C99_MATH_TR1) -#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER -#endif - -// Various stdlib support checks that require __has_include -#if defined(__has_include) - // Check if string_view is available and usable - #if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW - #endif - - // Check if optional is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) - - // Check if byte is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # include - # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) - # define CATCH_INTERNAL_CONFIG_CPP17_BYTE - # endif - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) - - // Check if variant is available and usable - # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # if defined(__clang__) && (__clang_major__ < 8) - // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 - // fix should be in clang 8, workaround in libstdc++ 8.2 - # include - # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) - # define CATCH_CONFIG_NO_CPP17_VARIANT - # else - # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT - # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) - # else - # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT - # endif // defined(__clang__) && (__clang_major__ < 8) - # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) -#endif // defined(__has_include) - - -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) -# define CATCH_CONFIG_WINDOWS_SEH -#endif -// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_CONFIG_POSIX_SIGNALS -#endif - -#if defined(CATCH_INTERNAL_CONFIG_GETENV) && !defined(CATCH_INTERNAL_CONFIG_NO_GETENV) && !defined(CATCH_CONFIG_NO_GETENV) && !defined(CATCH_CONFIG_GETENV) -# define CATCH_CONFIG_GETENV -#endif - -#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) -# define CATCH_CONFIG_CPP11_TO_STRING -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) -# define CATCH_CONFIG_CPP17_OPTIONAL -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) -# define CATCH_CONFIG_CPP17_STRING_VIEW -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) -# define CATCH_CONFIG_CPP17_VARIANT -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) -# define CATCH_CONFIG_CPP17_BYTE -#endif - - -#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) -# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE -#endif - -#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) -# define CATCH_CONFIG_NEW_CAPTURE -#endif - -#if !defined( CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED ) && \ - !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) && \ - !defined( CATCH_CONFIG_NO_DISABLE_EXCEPTIONS ) -# define CATCH_CONFIG_DISABLE_EXCEPTIONS -#endif - -#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) -# define CATCH_CONFIG_POLYFILL_ISNAN -#endif - -#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) -# define CATCH_CONFIG_USE_ASYNC -#endif - -#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) -# define CATCH_CONFIG_GLOBAL_NEXTAFTER -#endif - - -// Even if we do not think the compiler has that warning, we still have -// to provide a macro that can be used by the code. -#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION -#endif -#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS -#endif - -// The goal of this macro is to avoid evaluation of the arguments, but -// still have the compiler warn on problems inside... -#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) -# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) -#endif - -#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) -# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#elif defined(__clang__) && (__clang_major__ < 5) -# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#endif - -#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS -#endif - -#if !defined(CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS -#endif - -#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) -#define CATCH_TRY if ((true)) -#define CATCH_CATCH_ALL if ((false)) -#define CATCH_CATCH_ANON(type) if ((false)) -#else -#define CATCH_TRY try -#define CATCH_CATCH_ALL catch (...) -#define CATCH_CATCH_ANON(type) catch (type) -#endif - -#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) -#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#endif - -#if defined( CATCH_PLATFORM_WINDOWS ) && \ - !defined( CATCH_CONFIG_COLOUR_WIN32 ) && \ - !defined( CATCH_CONFIG_NO_COLOUR_WIN32 ) && \ - !defined( CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 ) -# define CATCH_CONFIG_COLOUR_WIN32 -#endif - -#if defined( CATCH_CONFIG_SHARED_LIBRARY ) && defined( _MSC_VER ) && \ - !defined( CATCH_CONFIG_STATIC ) -# ifdef Catch2_EXPORTS -# define CATCH_EXPORT //__declspec( dllexport ) // not needed -# else -# define CATCH_EXPORT __declspec( dllimport ) -# endif -#else -# define CATCH_EXPORT -#endif - -#endif // CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED - - -#ifndef CATCH_CONTEXT_HPP_INCLUDED -#define CATCH_CONTEXT_HPP_INCLUDED - - -namespace Catch { - - class IResultCapture; - class IConfig; - - class IContext { - public: - virtual ~IContext(); // = default - - virtual IResultCapture* getResultCapture() = 0; - virtual IConfig const* getConfig() const = 0; - }; - - class IMutableContext : public IContext { - public: - ~IMutableContext() override; // = default - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setConfig( IConfig const* config ) = 0; - - private: - CATCH_EXPORT static IMutableContext* currentContext; - friend IMutableContext& getCurrentMutableContext(); - friend void cleanUpContext(); - static void createContext(); - }; - - inline IMutableContext& getCurrentMutableContext() - { - if( !IMutableContext::currentContext ) - IMutableContext::createContext(); - // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) - return *IMutableContext::currentContext; - } - - inline IContext& getCurrentContext() - { - return getCurrentMutableContext(); - } - - void cleanUpContext(); - - class SimplePcg32; - SimplePcg32& sharedRng(); -} - -#endif // CATCH_CONTEXT_HPP_INCLUDED - - -#ifndef CATCH_INTERFACES_REPORTER_HPP_INCLUDED -#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED - - - -#ifndef CATCH_SECTION_INFO_HPP_INCLUDED -#define CATCH_SECTION_INFO_HPP_INCLUDED - - - -#ifndef CATCH_MOVE_AND_FORWARD_HPP_INCLUDED -#define CATCH_MOVE_AND_FORWARD_HPP_INCLUDED - -#include - -//! Replacement for std::move with better compile time performance -#define CATCH_MOVE(...) static_cast&&>(__VA_ARGS__) - -//! Replacement for std::forward with better compile time performance -#define CATCH_FORWARD(...) static_cast(__VA_ARGS__) - -#endif // CATCH_MOVE_AND_FORWARD_HPP_INCLUDED - - -#ifndef CATCH_SOURCE_LINE_INFO_HPP_INCLUDED -#define CATCH_SOURCE_LINE_INFO_HPP_INCLUDED - -#include -#include - -namespace Catch { - - struct SourceLineInfo { - - SourceLineInfo() = delete; - constexpr SourceLineInfo( char const* _file, std::size_t _line ) noexcept: - file( _file ), - line( _line ) - {} - - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; - - char const* file; - std::size_t line; - - friend std::ostream& operator << (std::ostream& os, SourceLineInfo const& info); - }; -} - -#define CATCH_INTERNAL_LINEINFO \ - ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) - -#endif // CATCH_SOURCE_LINE_INFO_HPP_INCLUDED - - -#ifndef CATCH_TOTALS_HPP_INCLUDED -#define CATCH_TOTALS_HPP_INCLUDED - -#include - -namespace Catch { - - struct Counts { - Counts operator - ( Counts const& other ) const; - Counts& operator += ( Counts const& other ); - - std::uint64_t total() const; - bool allPassed() const; - bool allOk() const; - - std::uint64_t passed = 0; - std::uint64_t failed = 0; - std::uint64_t failedButOk = 0; - std::uint64_t skipped = 0; - }; - - struct Totals { - - Totals operator - ( Totals const& other ) const; - Totals& operator += ( Totals const& other ); - - Totals delta( Totals const& prevTotals ) const; - - Counts assertions; - Counts testCases; - }; -} - -#endif // CATCH_TOTALS_HPP_INCLUDED - -#include - -namespace Catch { - - struct SectionInfo { - // The last argument is ignored, so that people can write - // SECTION("ShortName", "Proper description that is long") and - // still use the `-c` flag comfortably. - SectionInfo( SourceLineInfo const& _lineInfo, std::string _name, - const char* const = nullptr ): - name(CATCH_MOVE(_name)), - lineInfo(_lineInfo) - {} - - std::string name; - SourceLineInfo lineInfo; - }; - - struct SectionEndInfo { - SectionInfo sectionInfo; - Counts prevAssertions; - double durationInSeconds; - }; - -} // end namespace Catch - -#endif // CATCH_SECTION_INFO_HPP_INCLUDED - - -#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED -#define CATCH_ASSERTION_RESULT_HPP_INCLUDED - - - -#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED -#define CATCH_ASSERTION_INFO_HPP_INCLUDED - - - -#ifndef CATCH_RESULT_TYPE_HPP_INCLUDED -#define CATCH_RESULT_TYPE_HPP_INCLUDED - -namespace Catch { - - // ResultWas::OfType enum - struct ResultWas { enum OfType { - Unknown = -1, - Ok = 0, - Info = 1, - Warning = 2, - // TODO: Should explicit skip be considered "not OK" (cf. isOk)? I.e., should it have the failure bit? - ExplicitSkip = 4, - - FailureBit = 0x10, - - ExpressionFailed = FailureBit | 1, - ExplicitFailure = FailureBit | 2, - - Exception = 0x100 | FailureBit, - - ThrewException = Exception | 1, - DidntThrowException = Exception | 2, - - FatalErrorCondition = 0x200 | FailureBit - - }; }; - - bool isOk( ResultWas::OfType resultType ); - bool isJustInfo( int flags ); - - - // ResultDisposition::Flags enum - struct ResultDisposition { enum Flags { - Normal = 0x01, - - ContinueOnFailure = 0x02, // Failures fail test, but execution continues - FalseTest = 0x04, // Prefix expression with ! - SuppressFail = 0x08 // Failures are reported but do not fail the test - }; }; - - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); - - bool shouldContinueOnFailure( int flags ); - inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } - bool shouldSuppressFailure( int flags ); - -} // end namespace Catch - -#endif // CATCH_RESULT_TYPE_HPP_INCLUDED - -namespace Catch { - - struct AssertionInfo { - // AssertionInfo() = delete; - - StringRef macroName; - SourceLineInfo lineInfo; - StringRef capturedExpression; - ResultDisposition::Flags resultDisposition; - }; - -} // end namespace Catch - -#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED - - -#ifndef CATCH_LAZY_EXPR_HPP_INCLUDED -#define CATCH_LAZY_EXPR_HPP_INCLUDED - -#include - -namespace Catch { - - class ITransientExpression; - - class LazyExpression { - friend class AssertionHandler; - friend struct AssertionStats; - friend class RunContext; - - ITransientExpression const* m_transientExpression = nullptr; - bool m_isNegated; - public: - LazyExpression( bool isNegated ): - m_isNegated(isNegated) - {} - LazyExpression(LazyExpression const& other) = default; - LazyExpression& operator = ( LazyExpression const& ) = delete; - - explicit operator bool() const { - return m_transientExpression != nullptr; - } - - friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; - }; - -} // namespace Catch - -#endif // CATCH_LAZY_EXPR_HPP_INCLUDED - -#include - -namespace Catch { - - struct AssertionResultData - { - AssertionResultData() = delete; - - AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); - - std::string message; - mutable std::string reconstructedExpression; - LazyExpression lazyExpression; - ResultWas::OfType resultType; - - std::string reconstructExpression() const; - }; - - class AssertionResult { - public: - AssertionResult() = delete; - AssertionResult( AssertionInfo const& info, AssertionResultData&& data ); - - bool isOk() const; - bool succeeded() const; - ResultWas::OfType getResultType() const; - bool hasExpression() const; - bool hasMessage() const; - std::string getExpression() const; - std::string getExpressionInMacro() const; - bool hasExpandedExpression() const; - std::string getExpandedExpression() const; - StringRef getMessage() const; - SourceLineInfo getSourceInfo() const; - StringRef getTestMacroName() const; - - //protected: - AssertionInfo m_info; - AssertionResultData m_resultData; - }; - -} // end namespace Catch - -#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED - - -#ifndef CATCH_MESSAGE_INFO_HPP_INCLUDED -#define CATCH_MESSAGE_INFO_HPP_INCLUDED - - - -#ifndef CATCH_INTERFACES_CAPTURE_HPP_INCLUDED -#define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED - -#include -#include - - - -#ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED -#define CATCH_UNIQUE_PTR_HPP_INCLUDED - -#include -#include - - -namespace Catch { -namespace Detail { - /** - * A reimplementation of `std::unique_ptr` for improved compilation performance - * - * Does not support arrays nor custom deleters. - */ - template - class unique_ptr { - T* m_ptr; - public: - constexpr unique_ptr(std::nullptr_t = nullptr): - m_ptr{} - {} - explicit constexpr unique_ptr(T* ptr): - m_ptr(ptr) - {} - - template ::value>> - unique_ptr(unique_ptr&& from): - m_ptr(from.release()) - {} - - template ::value>> - unique_ptr& operator=(unique_ptr&& from) { - reset(from.release()); - - return *this; - } - - unique_ptr(unique_ptr const&) = delete; - unique_ptr& operator=(unique_ptr const&) = delete; - - unique_ptr(unique_ptr&& rhs) noexcept: - m_ptr(rhs.m_ptr) { - rhs.m_ptr = nullptr; - } - unique_ptr& operator=(unique_ptr&& rhs) noexcept { - reset(rhs.release()); - - return *this; - } - - ~unique_ptr() { - delete m_ptr; - } - - T& operator*() { - assert(m_ptr); - return *m_ptr; - } - T const& operator*() const { - assert(m_ptr); - return *m_ptr; - } - T* operator->() noexcept { - assert(m_ptr); - return m_ptr; - } - T const* operator->() const noexcept { - assert(m_ptr); - return m_ptr; - } - - T* get() { return m_ptr; } - T const* get() const { return m_ptr; } - - void reset(T* ptr = nullptr) { - delete m_ptr; - m_ptr = ptr; - } - - T* release() { - auto temp = m_ptr; - m_ptr = nullptr; - return temp; - } - - explicit operator bool() const { - return m_ptr; - } - - friend void swap(unique_ptr& lhs, unique_ptr& rhs) { - auto temp = lhs.m_ptr; - lhs.m_ptr = rhs.m_ptr; - rhs.m_ptr = temp; - } - }; - - //! Specialization to cause compile-time error for arrays - template - class unique_ptr; - - template - unique_ptr make_unique(Args&&... args) { - return unique_ptr(new T(CATCH_FORWARD(args)...)); - } - - -} // end namespace Detail -} // end namespace Catch - -#endif // CATCH_UNIQUE_PTR_HPP_INCLUDED - -namespace Catch { - - class AssertionResult; - struct AssertionInfo; - struct SectionInfo; - struct SectionEndInfo; - struct MessageInfo; - struct MessageBuilder; - struct Counts; - struct AssertionReaction; - struct SourceLineInfo; - - class ITransientExpression; - class IGeneratorTracker; - - struct BenchmarkInfo; - template > - struct BenchmarkStats; - - namespace Generators { - class GeneratorUntypedBase; - using GeneratorBasePtr = Catch::Detail::unique_ptr; - } - - - class IResultCapture { - public: - virtual ~IResultCapture(); - - virtual bool sectionStarted( StringRef sectionName, - SourceLineInfo const& sectionLineInfo, - Counts& assertions ) = 0; - virtual void sectionEnded( SectionEndInfo&& endInfo ) = 0; - virtual void sectionEndedEarly( SectionEndInfo&& endInfo ) = 0; - - virtual IGeneratorTracker* - acquireGeneratorTracker( StringRef generatorName, - SourceLineInfo const& lineInfo ) = 0; - virtual IGeneratorTracker* - createGeneratorTracker( StringRef generatorName, - SourceLineInfo lineInfo, - Generators::GeneratorBasePtr&& generator ) = 0; - - virtual void benchmarkPreparing( StringRef name ) = 0; - virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; - virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0; - virtual void benchmarkFailed( StringRef error ) = 0; - - virtual void pushScopedMessage( MessageInfo const& message ) = 0; - virtual void popScopedMessage( MessageInfo const& message ) = 0; - - virtual void emplaceUnscopedMessage( MessageBuilder&& builder ) = 0; - - virtual void handleFatalErrorCondition( StringRef message ) = 0; - - virtual void handleExpr - ( AssertionInfo const& info, - ITransientExpression const& expr, - AssertionReaction& reaction ) = 0; - virtual void handleMessage - ( AssertionInfo const& info, - ResultWas::OfType resultType, - StringRef message, - AssertionReaction& reaction ) = 0; - virtual void handleUnexpectedExceptionNotThrown - ( AssertionInfo const& info, - AssertionReaction& reaction ) = 0; - virtual void handleUnexpectedInflightException - ( AssertionInfo const& info, - std::string const& message, - AssertionReaction& reaction ) = 0; - virtual void handleIncomplete - ( AssertionInfo const& info ) = 0; - virtual void handleNonExpr - ( AssertionInfo const &info, - ResultWas::OfType resultType, - AssertionReaction &reaction ) = 0; - - - - virtual bool lastAssertionPassed() = 0; - virtual void assertionPassed() = 0; - - // Deprecated, do not use: - virtual std::string getCurrentTestName() const = 0; - virtual const AssertionResult* getLastResult() const = 0; - virtual void exceptionEarlyReported() = 0; - }; - - IResultCapture& getResultCapture(); -} - -#endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED - -#include - -namespace Catch { - - struct MessageInfo { - MessageInfo( StringRef _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ); - - StringRef macroName; - std::string message; - SourceLineInfo lineInfo; - ResultWas::OfType type; - unsigned int sequence; - - bool operator == (MessageInfo const& other) const { - return sequence == other.sequence; - } - bool operator < (MessageInfo const& other) const { - return sequence < other.sequence; - } - private: - static unsigned int globalCount; - }; - -} // end namespace Catch - -#endif // CATCH_MESSAGE_INFO_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_ESTIMATE_HPP_INCLUDED -#define CATCH_ESTIMATE_HPP_INCLUDED - -namespace Catch { - namespace Benchmark { - template - struct Estimate { - Duration point; - Duration lower_bound; - Duration upper_bound; - double confidence_interval; - - template - operator Estimate() const { - return { point, lower_bound, upper_bound, confidence_interval }; - } - }; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_ESTIMATE_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED -#define CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED - -namespace Catch { - namespace Benchmark { - struct OutlierClassification { - int samples_seen = 0; - int low_severe = 0; // more than 3 times IQR below Q1 - int low_mild = 0; // 1.5 to 3 times IQR below Q1 - int high_mild = 0; // 1.5 to 3 times IQR above Q3 - int high_severe = 0; // more than 3 times IQR above Q3 - - int total() const { - return low_severe + low_mild + high_mild + high_severe; - } - }; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED - - -#include -#include -#include -#include - -namespace Catch { - - struct ReporterDescription; - struct ListenerDescription; - struct TagInfo; - struct TestCaseInfo; - class TestCaseHandle; - class IConfig; - class IStream; - enum class ColourMode : std::uint8_t; - - struct ReporterConfig { - ReporterConfig( IConfig const* _fullConfig, - Detail::unique_ptr _stream, - ColourMode colourMode, - std::map customOptions ); - - ReporterConfig( ReporterConfig&& ) = default; - ReporterConfig& operator=( ReporterConfig&& ) = default; - ~ReporterConfig(); // = default - - Detail::unique_ptr takeStream() &&; - IConfig const* fullConfig() const; - ColourMode colourMode() const; - std::map const& customOptions() const; - - private: - Detail::unique_ptr m_stream; - IConfig const* m_fullConfig; - ColourMode m_colourMode; - std::map m_customOptions; - }; - - struct TestRunInfo { - constexpr TestRunInfo(StringRef _name) : name(_name) {} - StringRef name; - }; - - struct AssertionStats { - AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ); - - AssertionStats( AssertionStats const& ) = default; - AssertionStats( AssertionStats && ) = default; - AssertionStats& operator = ( AssertionStats const& ) = delete; - AssertionStats& operator = ( AssertionStats && ) = delete; - - AssertionResult assertionResult; - std::vector infoMessages; - Totals totals; - }; - - struct SectionStats { - SectionStats( SectionInfo&& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ); - - SectionInfo sectionInfo; - Counts assertions; - double durationInSeconds; - bool missingAssertions; - }; - - struct TestCaseStats { - TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string&& _stdOut, - std::string&& _stdErr, - bool _aborting ); - - TestCaseInfo const * testInfo; - Totals totals; - std::string stdOut; - std::string stdErr; - bool aborting; - }; - - struct TestRunStats { - TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ); - - TestRunInfo runInfo; - Totals totals; - bool aborting; - }; - - - struct BenchmarkInfo { - std::string name; - double estimatedDuration; - int iterations; - unsigned int samples; - unsigned int resamples; - double clockResolution; - double clockCost; - }; - - template - struct BenchmarkStats { - BenchmarkInfo info; - - std::vector samples; - Benchmark::Estimate mean; - Benchmark::Estimate standardDeviation; - Benchmark::OutlierClassification outliers; - double outlierVariance; - - template - operator BenchmarkStats() const { - std::vector samples2; - samples2.reserve(samples.size()); - for (auto const& sample : samples) { - samples2.push_back(Duration2(sample)); - } - return { - info, - CATCH_MOVE(samples2), - mean, - standardDeviation, - outliers, - outlierVariance, - }; - } - }; - - //! By setting up its preferences, a reporter can modify Catch2's behaviour - //! in some regards, e.g. it can request Catch2 to capture writes to - //! stdout/stderr during test execution, and pass them to the reporter. - struct ReporterPreferences { - //! Catch2 should redirect writes to stdout and pass them to the - //! reporter - bool shouldRedirectStdOut = false; - //! Catch2 should call `Reporter::assertionEnded` even for passing - //! assertions - bool shouldReportAllAssertions = false; - }; - - /** - * The common base for all reporters and event listeners - * - * Implementing classes must also implement: - * - * //! User-friendly description of the reporter/listener type - * static std::string getDescription() - * - * Generally shouldn't be derived from by users of Catch2 directly, - * instead they should derive from one of the utility bases that - * derive from this class. - */ - class IEventListener { - protected: - //! Derived classes can set up their preferences here - ReporterPreferences m_preferences; - //! The test run's config as filled in from CLI and defaults - IConfig const* m_config; - - public: - IEventListener( IConfig const* config ): m_config( config ) {} - - virtual ~IEventListener(); // = default; - - // Implementing class must also provide the following static methods: - // static std::string getDescription(); - - ReporterPreferences const& getPreferences() const { - return m_preferences; - } - - //! Called when no test cases match provided test spec - virtual void noMatchingTestCases( StringRef unmatchedSpec ) = 0; - //! Called for all invalid test specs from the cli - virtual void reportInvalidTestSpec( StringRef invalidArgument ) = 0; - - /** - * Called once in a testing run before tests are started - * - * Not called if tests won't be run (e.g. only listing will happen) - */ - virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; - - //! Called _once_ for each TEST_CASE, no matter how many times it is entered - virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; - //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections) - virtual void testCasePartialStarting( TestCaseInfo const& testInfo, uint64_t partNumber ) = 0; - //! Called when a `SECTION` is being entered. Not called for skipped sections - virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; - - //! Called when user-code is being probed before the actual benchmark runs - virtual void benchmarkPreparing( StringRef benchmarkName ) = 0; - //! Called after probe but before the user-code is being benchmarked - virtual void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) = 0; - //! Called with the benchmark results if benchmark successfully finishes - virtual void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) = 0; - //! Called if running the benchmarks fails for any reason - virtual void benchmarkFailed( StringRef benchmarkName ) = 0; - - //! Called before assertion success/failure is evaluated - virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; - - //! Called after assertion was fully evaluated - virtual void assertionEnded( AssertionStats const& assertionStats ) = 0; - - //! Called after a `SECTION` has finished running - virtual void sectionEnded( SectionStats const& sectionStats ) = 0; - //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections) - virtual void testCasePartialEnded(TestCaseStats const& testCaseStats, uint64_t partNumber ) = 0; - //! Called _once_ for each TEST_CASE, no matter how many times it is entered - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; - /** - * Called once after all tests in a testing run are finished - * - * Not called if tests weren't run (e.g. only listings happened) - */ - virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; - - /** - * Called with test cases that are skipped due to the test run aborting. - * NOT called for test cases that are explicitly skipped using the `SKIP` macro. - * - * Deprecated - will be removed in the next major release. - */ - virtual void skipTest( TestCaseInfo const& testInfo ) = 0; - - //! Called if a fatal error (signal/structured exception) occured - virtual void fatalErrorEncountered( StringRef error ) = 0; - - //! Writes out information about provided reporters using reporter-specific format - virtual void listReporters(std::vector const& descriptions) = 0; - //! Writes out the provided listeners descriptions using reporter-specific format - virtual void listListeners(std::vector const& descriptions) = 0; - //! Writes out information about provided tests using reporter-specific format - virtual void listTests(std::vector const& tests) = 0; - //! Writes out information about the provided tags using reporter-specific format - virtual void listTags(std::vector const& tags) = 0; - }; - using IEventListenerPtr = Detail::unique_ptr; - -} // end namespace Catch - -#endif // CATCH_INTERFACES_REPORTER_HPP_INCLUDED - - -#ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED -#define CATCH_UNIQUE_NAME_HPP_INCLUDED - - - - -/** \file - * Wrapper for the CONFIG configuration option - * - * When generating internal unique names, there are two options. Either - * we mix in the current line number, or mix in an incrementing number. - * We prefer the latter, using `__COUNTER__`, but users might want to - * use the former. - */ - -#ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED -#define CATCH_CONFIG_COUNTER_HPP_INCLUDED - -#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER -#endif - -#if defined( CATCH_INTERNAL_CONFIG_COUNTER ) && \ - !defined( CATCH_CONFIG_NO_COUNTER ) && \ - !defined( CATCH_CONFIG_COUNTER ) -# define CATCH_CONFIG_COUNTER -#endif - - -#endif // CATCH_CONFIG_COUNTER_HPP_INCLUDED -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#ifdef CATCH_CONFIG_COUNTER -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) -#else -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) -#endif - -#endif // CATCH_UNIQUE_NAME_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_CHRONOMETER_HPP_INCLUDED -#define CATCH_CHRONOMETER_HPP_INCLUDED - - - -// Adapted from donated nonius code. - -#ifndef CATCH_CLOCK_HPP_INCLUDED -#define CATCH_CLOCK_HPP_INCLUDED - -#include -#include - -namespace Catch { - namespace Benchmark { - template - using ClockDuration = typename Clock::duration; - template - using FloatDuration = std::chrono::duration; - - template - using TimePoint = typename Clock::time_point; - - using default_clock = std::chrono::steady_clock; - - template - struct now { - TimePoint operator()() const { - return Clock::now(); - } - }; - - using fp_seconds = std::chrono::duration>; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_CLOCK_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_OPTIMIZER_HPP_INCLUDED -#define CATCH_OPTIMIZER_HPP_INCLUDED - -#if defined(_MSC_VER) -# include // atomic_thread_fence -#endif - - -#include - -namespace Catch { - namespace Benchmark { -#if defined(__GNUC__) || defined(__clang__) - template - inline void keep_memory(T* p) { - asm volatile("" : : "g"(p) : "memory"); - } - inline void keep_memory() { - asm volatile("" : : : "memory"); - } - - namespace Detail { - inline void optimizer_barrier() { keep_memory(); } - } // namespace Detail -#elif defined(_MSC_VER) - -#pragma optimize("", off) - template - inline void keep_memory(T* p) { - // thanks @milleniumbug - *reinterpret_cast(p) = *reinterpret_cast(p); - } - // TODO equivalent keep_memory() -#pragma optimize("", on) - - namespace Detail { - inline void optimizer_barrier() { - std::atomic_thread_fence(std::memory_order_seq_cst); - } - } // namespace Detail - -#endif - - template - inline void deoptimize_value(T&& x) { - keep_memory(&x); - } - - template - inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t::value> { - deoptimize_value(CATCH_FORWARD(fn) (CATCH_FORWARD(args)...)); - } - - template - inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t::value> { - CATCH_FORWARD(fn) (CATCH_FORWARD(args)...); - } - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_OPTIMIZER_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED -#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED - - - -#ifndef CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED -#define CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED - -namespace Catch { - - //! Used to signal that an assertion macro failed - struct TestFailureException{}; - - /** - * Outlines throwing of `TestFailureException` into a single TU - * - * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers. - */ - [[noreturn]] void throw_test_failure_exception(); - - //! Used to signal that the remainder of a test should be skipped - struct TestSkipException{}; - -} // namespace Catch - -#endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED - - -#ifndef CATCH_META_HPP_INCLUDED -#define CATCH_META_HPP_INCLUDED - -#include - -namespace Catch { - template - struct true_given : std::true_type {}; - - struct is_callable_tester { - template - static true_given()(std::declval()...))> test(int); - template - static std::false_type test(...); - }; - - template - struct is_callable; - - template - struct is_callable : decltype(is_callable_tester::test(0)) {}; - - -#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703 - // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is - // replaced with std::invoke_result here. - template - using FunctionReturnType = std::remove_reference_t>>; -#else - template - using FunctionReturnType = std::remove_reference_t>>; -#endif - -} // namespace Catch - -namespace mpl_{ - struct na; -} - -#endif // CATCH_META_HPP_INCLUDED - - -#ifndef CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED -#define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED - - -#include - -namespace Catch { - - class TestCaseHandle; - struct TestCaseInfo; - class ITestCaseRegistry; - class IExceptionTranslatorRegistry; - class IExceptionTranslator; - class IReporterRegistry; - class IReporterFactory; - class ITagAliasRegistry; - class ITestInvoker; - class IMutableEnumValuesRegistry; - struct SourceLineInfo; - - class StartupExceptionRegistry; - class EventListenerFactory; - - using IReporterFactoryPtr = Detail::unique_ptr; - - class IRegistryHub { - public: - virtual ~IRegistryHub(); // = default - - virtual IReporterRegistry const& getReporterRegistry() const = 0; - virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; - virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; - virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; - - - virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; - }; - - class IMutableRegistryHub { - public: - virtual ~IMutableRegistryHub(); // = default - virtual void registerReporter( std::string const& name, IReporterFactoryPtr factory ) = 0; - virtual void registerListener( Detail::unique_ptr factory ) = 0; - virtual void registerTest(Detail::unique_ptr&& testInfo, Detail::unique_ptr&& invoker) = 0; - virtual void registerTranslator( Detail::unique_ptr&& translator ) = 0; - virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; - virtual void registerStartupException() noexcept = 0; - virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0; - }; - - IRegistryHub const& getRegistryHub(); - IMutableRegistryHub& getMutableRegistryHub(); - void cleanUp(); - std::string translateActiveException(); - -} - -#endif // CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED - -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - template - struct CompleteType { using type = T; }; - template <> - struct CompleteType { struct type {}; }; - - template - using CompleteType_t = typename CompleteType::type; - - template - struct CompleteInvoker { - template - static Result invoke(Fun&& fun, Args&&... args) { - return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); - } - }; - template <> - struct CompleteInvoker { - template - static CompleteType_t invoke(Fun&& fun, Args&&... args) { - CATCH_FORWARD(fun)(CATCH_FORWARD(args)...); - return {}; - } - }; - - // invoke and not return void :( - template - CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { - return CompleteInvoker>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...); - } - - } // namespace Detail - - template - Detail::CompleteType_t> user_code(Fun&& fun) { - return Detail::complete_invoke(CATCH_FORWARD(fun)); - } - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED - -namespace Catch { - namespace Benchmark { - namespace Detail { - struct ChronometerConcept { - virtual void start() = 0; - virtual void finish() = 0; - virtual ~ChronometerConcept(); // = default; - - ChronometerConcept() = default; - ChronometerConcept(ChronometerConcept const&) = default; - ChronometerConcept& operator=(ChronometerConcept const&) = default; - }; - template - struct ChronometerModel final : public ChronometerConcept { - void start() override { started = Clock::now(); } - void finish() override { finished = Clock::now(); } - - ClockDuration elapsed() const { return finished - started; } - - TimePoint started; - TimePoint finished; - }; - } // namespace Detail - - struct Chronometer { - public: - template - void measure(Fun&& fun) { measure(CATCH_FORWARD(fun), is_callable()); } - - int runs() const { return repeats; } - - Chronometer(Detail::ChronometerConcept& meter, int repeats_) - : impl(&meter) - , repeats(repeats_) {} - - private: - template - void measure(Fun&& fun, std::false_type) { - measure([&fun](int) { return fun(); }, std::true_type()); - } - - template - void measure(Fun&& fun, std::true_type) { - Detail::optimizer_barrier(); - impl->start(); - for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i); - impl->finish(); - Detail::optimizer_barrier(); - } - - Detail::ChronometerConcept* impl; - int repeats; - }; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_CHRONOMETER_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED -#define CATCH_ENVIRONMENT_HPP_INCLUDED - - -namespace Catch { - namespace Benchmark { - template - struct EnvironmentEstimate { - Duration mean; - OutlierClassification outliers; - - template - operator EnvironmentEstimate() const { - return { mean, outliers }; - } - }; - template - struct Environment { - using clock_type = Clock; - EnvironmentEstimate> clock_resolution; - EnvironmentEstimate> clock_cost; - }; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_ENVIRONMENT_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED -#define CATCH_EXECUTION_PLAN_HPP_INCLUDED - - - -// Adapted from donated nonius code. - -#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED -#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED - - -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - template - struct is_related - : std::is_same, std::decay_t> {}; - - /// We need to reinvent std::function because every piece of code that might add overhead - /// in a measurement context needs to have consistent performance characteristics so that we - /// can account for it in the measurement. - /// Implementations of std::function with optimizations that aren't always applicable, like - /// small buffer optimizations, are not uncommon. - /// This is effectively an implementation of std::function without any such optimizations; - /// it may be slow, but it is consistently slow. - struct BenchmarkFunction { - private: - struct callable { - virtual void call(Chronometer meter) const = 0; - virtual Catch::Detail::unique_ptr clone() const = 0; - virtual ~callable(); // = default; - - callable() = default; - callable(callable const&) = default; - callable& operator=(callable const&) = default; - }; - template - struct model : public callable { - model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {} - model(Fun const& fun_) : fun(fun_) {} - - Catch::Detail::unique_ptr clone() const override { - return Catch::Detail::make_unique>( *this ); - } - - void call(Chronometer meter) const override { - call(meter, is_callable()); - } - void call(Chronometer meter, std::true_type) const { - fun(meter); - } - void call(Chronometer meter, std::false_type) const { - meter.measure(fun); - } - - Fun fun; - }; - - struct do_nothing { void operator()() const {} }; - - template - BenchmarkFunction(model* c) : f(c) {} - - public: - BenchmarkFunction() - : f(new model{ {} }) {} - - template ::value, int> = 0> - BenchmarkFunction(Fun&& fun) - : f(new model>(CATCH_FORWARD(fun))) {} - - BenchmarkFunction( BenchmarkFunction&& that ) noexcept: - f( CATCH_MOVE( that.f ) ) {} - - BenchmarkFunction(BenchmarkFunction const& that) - : f(that.f->clone()) {} - - BenchmarkFunction& - operator=( BenchmarkFunction&& that ) noexcept { - f = CATCH_MOVE( that.f ); - return *this; - } - - BenchmarkFunction& operator=(BenchmarkFunction const& that) { - f = that.f->clone(); - return *this; - } - - void operator()(Chronometer meter) const { f->call(meter); } - - private: - Catch::Detail::unique_ptr f; - }; - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_REPEAT_HPP_INCLUDED -#define CATCH_REPEAT_HPP_INCLUDED - -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - template - struct repeater { - void operator()(int k) const { - for (int i = 0; i < k; ++i) { - fun(); - } - } - Fun fun; - }; - template - repeater> repeat(Fun&& fun) { - return { CATCH_FORWARD(fun) }; - } - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_REPEAT_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED -#define CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED - - - -// Adapted from donated nonius code. - -#ifndef CATCH_MEASURE_HPP_INCLUDED -#define CATCH_MEASURE_HPP_INCLUDED - - - -// Adapted from donated nonius code. - -#ifndef CATCH_TIMING_HPP_INCLUDED -#define CATCH_TIMING_HPP_INCLUDED - - -#include - -namespace Catch { - namespace Benchmark { - template - struct Timing { - Duration elapsed; - Result result; - int iterations; - }; - template - using TimingOf = Timing, Detail::CompleteType_t>>; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_TIMING_HPP_INCLUDED - -namespace Catch { - namespace Benchmark { - namespace Detail { - template - TimingOf measure(Fun&& fun, Args&&... args) { - auto start = Clock::now(); - auto&& r = Detail::complete_invoke(fun, CATCH_FORWARD(args)...); - auto end = Clock::now(); - auto delta = end - start; - return { delta, CATCH_FORWARD(r), 1 }; - } - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_MEASURE_HPP_INCLUDED - -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - template - TimingOf measure_one(Fun&& fun, int iters, std::false_type) { - return Detail::measure(fun, iters); - } - template - TimingOf measure_one(Fun&& fun, int iters, std::true_type) { - Detail::ChronometerModel meter; - auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); - - return { meter.elapsed(), CATCH_MOVE(result), iters }; - } - - template - using run_for_at_least_argument_t = std::conditional_t::value, Chronometer, int>; - - - [[noreturn]] - void throw_optimized_away_error(); - - template - TimingOf> - run_for_at_least(ClockDuration how_long, - const int initial_iterations, - Fun&& fun) { - auto iters = initial_iterations; - while (iters < (1 << 30)) { - auto&& Timing = measure_one(fun, iters, is_callable()); - - if (Timing.elapsed >= how_long) { - return { Timing.elapsed, CATCH_MOVE(Timing.result), iters }; - } - iters *= 2; - } - throw_optimized_away_error(); - } - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED - -#include -#include - -namespace Catch { - namespace Benchmark { - template - struct ExecutionPlan { - int iterations_per_sample; - Duration estimated_duration; - Detail::BenchmarkFunction benchmark; - Duration warmup_time; - int warmup_iterations; - - template - operator ExecutionPlan() const { - return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations }; - } - - template - std::vector> run(const IConfig &cfg, Environment> env) const { - // warmup a bit - Detail::run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_iterations, Detail::repeat(now{})); - - std::vector> times; - times.reserve(cfg.benchmarkSamples()); - std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { - Detail::ChronometerModel model; - this->benchmark(Chronometer(model, iterations_per_sample)); - auto sample_time = model.elapsed() - env.clock_cost.mean; - if (sample_time < FloatDuration::zero()) sample_time = FloatDuration::zero(); - return sample_time / iterations_per_sample; - }); - return times; - } - }; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_EXECUTION_PLAN_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_ESTIMATE_CLOCK_HPP_INCLUDED -#define CATCH_ESTIMATE_CLOCK_HPP_INCLUDED - - - -// Adapted from donated nonius code. - -#ifndef CATCH_STATS_HPP_INCLUDED -#define CATCH_STATS_HPP_INCLUDED - - -#include -#include -#include -#include -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - using sample = std::vector; - - // Used when we know we want == comparison of two doubles - // to centralize warning suppression - bool directCompare( double lhs, double rhs ); - - double weighted_average_quantile(int k, int q, std::vector::iterator first, std::vector::iterator last); - - template - OutlierClassification classify_outliers(Iterator first, Iterator last) { - std::vector copy(first, last); - - auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end()); - auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end()); - auto iqr = q3 - q1; - auto los = q1 - (iqr * 3.); - auto lom = q1 - (iqr * 1.5); - auto him = q3 + (iqr * 1.5); - auto his = q3 + (iqr * 3.); - - OutlierClassification o; - for (; first != last; ++first) { - auto&& t = *first; - if (t < los) ++o.low_severe; - else if (t < lom) ++o.low_mild; - else if (t > his) ++o.high_severe; - else if (t > him) ++o.high_mild; - ++o.samples_seen; - } - return o; - } - - template - double mean(Iterator first, Iterator last) { - auto count = last - first; - double sum = std::accumulate(first, last, 0.); - return sum / static_cast(count); - } - - template - sample jackknife(Estimator&& estimator, Iterator first, Iterator last) { - auto n = static_cast(last - first); - auto second = first; - ++second; - sample results; - results.reserve(n); - - for (auto it = first; it != last; ++it) { - std::iter_swap(it, first); - results.push_back(estimator(second, last)); - } - - return results; - } - - inline double normal_cdf(double x) { - return std::erfc(-x / std::sqrt(2.0)) / 2.0; - } - - double erfc_inv(double x); - - double normal_quantile(double p); - - template - Estimate bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) { - auto n_samples = last - first; - - double point = estimator(first, last); - // Degenerate case with a single sample - if (n_samples == 1) return { point, point, point, confidence_level }; - - sample jack = jackknife(estimator, first, last); - double jack_mean = mean(jack.begin(), jack.end()); - double sum_squares, sum_cubes; - std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair sqcb, double x) -> std::pair { - auto d = jack_mean - x; - auto d2 = d * d; - auto d3 = d2 * d; - return { sqcb.first + d2, sqcb.second + d3 }; - }); - - double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); - long n = static_cast(resample.size()); - double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / static_cast(n); - // degenerate case with uniform samples - if ( directCompare( prob_n, 0. ) ) { - return { point, point, point, confidence_level }; - } - - double bias = normal_quantile(prob_n); - double z1 = normal_quantile((1. - confidence_level) / 2.); - - auto cumn = [n]( double x ) -> long { - return std::lround( normal_cdf( x ) * static_cast(n) ); - }; - auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); }; - double b1 = bias + z1; - double b2 = bias - z1; - double a1 = a(b1); - double a2 = a(b2); - auto lo = static_cast((std::max)(cumn(a1), 0l)); - auto hi = static_cast((std::min)(cumn(a2), n - 1)); - - return { point, resample[lo], resample[hi], confidence_level }; - } - - double outlier_variance(Estimate mean, Estimate stddev, int n); - - struct bootstrap_analysis { - Estimate mean; - Estimate standard_deviation; - double outlier_variance; - }; - - bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector::iterator first, std::vector::iterator last); - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_STATS_HPP_INCLUDED - -#include -#include -#include -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - template - std::vector resolution(int k) { - std::vector> times; - times.reserve(static_cast(k + 1)); - std::generate_n(std::back_inserter(times), k + 1, now{}); - - std::vector deltas; - deltas.reserve(static_cast(k)); - std::transform(std::next(times.begin()), times.end(), times.begin(), - std::back_inserter(deltas), - [](TimePoint a, TimePoint b) { return static_cast((a - b).count()); }); - - return deltas; - } - - const auto warmup_iterations = 10000; - const auto warmup_time = std::chrono::milliseconds(100); - const auto minimum_ticks = 1000; - const auto warmup_seed = 10000; - const auto clock_resolution_estimation_time = std::chrono::milliseconds(500); - const auto clock_cost_estimation_time_limit = std::chrono::seconds(1); - const auto clock_cost_estimation_tick_limit = 100000; - const auto clock_cost_estimation_time = std::chrono::milliseconds(10); - const auto clock_cost_estimation_iterations = 10000; - - template - int warmup() { - return run_for_at_least(std::chrono::duration_cast>(warmup_time), warmup_seed, &resolution) - .iterations; - } - template - EnvironmentEstimate> estimate_clock_resolution(int iterations) { - auto r = run_for_at_least(std::chrono::duration_cast>(clock_resolution_estimation_time), iterations, &resolution) - .result; - return { - FloatDuration(mean(r.begin(), r.end())), - classify_outliers(r.begin(), r.end()), - }; - } - template - EnvironmentEstimate> estimate_clock_cost(FloatDuration resolution) { - auto time_limit = (std::min)( - resolution * clock_cost_estimation_tick_limit, - FloatDuration(clock_cost_estimation_time_limit)); - auto time_clock = [](int k) { - return Detail::measure([k] { - for (int i = 0; i < k; ++i) { - volatile auto ignored = Clock::now(); - (void)ignored; - } - }).elapsed; - }; - time_clock(1); - int iters = clock_cost_estimation_iterations; - auto&& r = run_for_at_least(std::chrono::duration_cast>(clock_cost_estimation_time), iters, time_clock); - std::vector times; - int nsamples = static_cast(std::ceil(time_limit / r.elapsed)); - times.reserve(static_cast(nsamples)); - std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { - return static_cast((time_clock(r.iterations) / r.iterations).count()); - }); - return { - FloatDuration(mean(times.begin(), times.end())), - classify_outliers(times.begin(), times.end()), - }; - } - - template - Environment> measure_environment() { -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - static Catch::Detail::unique_ptr>> env; -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - if (env) { - return *env; - } - - auto iters = Detail::warmup(); - auto resolution = Detail::estimate_clock_resolution(iters); - auto cost = Detail::estimate_clock_cost(resolution.mean); - - env = Catch::Detail::make_unique>>( Environment>{resolution, cost} ); - return *env; - } - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_ESTIMATE_CLOCK_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_ANALYSE_HPP_INCLUDED -#define CATCH_ANALYSE_HPP_INCLUDED - - - -// Adapted from donated nonius code. - -#ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED -#define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED - - -#include -#include -#include - -namespace Catch { - namespace Benchmark { - template - struct SampleAnalysis { - std::vector samples; - Estimate mean; - Estimate standard_deviation; - OutlierClassification outliers; - double outlier_variance; - - template - operator SampleAnalysis() const { - std::vector samples2; - samples2.reserve(samples.size()); - std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); - return { - CATCH_MOVE(samples2), - mean, - standard_deviation, - outliers, - outlier_variance, - }; - } - }; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED - -#include -#include -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - template - SampleAnalysis analyse(const IConfig &cfg, Environment, Iterator first, Iterator last) { - if (!cfg.benchmarkNoAnalysis()) { - std::vector samples; - samples.reserve(static_cast(last - first)); - std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); }); - - auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end()); - auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end()); - - auto wrap_estimate = [](Estimate e) { - return Estimate { - Duration(e.point), - Duration(e.lower_bound), - Duration(e.upper_bound), - e.confidence_interval, - }; - }; - std::vector samples2; - samples2.reserve(samples.size()); - std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); - return { - CATCH_MOVE(samples2), - wrap_estimate(analysis.mean), - wrap_estimate(analysis.standard_deviation), - outliers, - analysis.outlier_variance, - }; - } else { - std::vector samples; - samples.reserve(static_cast(last - first)); - - Duration mean = Duration(0); - int i = 0; - for (auto it = first; it < last; ++it, ++i) { - samples.push_back(Duration(*it)); - mean += Duration(*it); - } - mean /= i; - - return { - CATCH_MOVE(samples), - Estimate{mean, mean, mean, 0.0}, - Estimate{Duration(0), Duration(0), Duration(0), 0.0}, - OutlierClassification{}, - 0.0 - }; - } - } - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_ANALYSE_HPP_INCLUDED - -#include -#include -#include -#include -#include - -namespace Catch { - namespace Benchmark { - struct Benchmark { - Benchmark(std::string&& benchmarkName) - : name(CATCH_MOVE(benchmarkName)) {} - - template - Benchmark(std::string&& benchmarkName , FUN &&func) - : fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {} - - template - ExecutionPlan> prepare(const IConfig &cfg, Environment> env) const { - auto min_time = env.clock_resolution.mean * Detail::minimum_ticks; - auto run_time = std::max(min_time, std::chrono::duration_cast(cfg.benchmarkWarmupTime())); - auto&& test = Detail::run_for_at_least(std::chrono::duration_cast>(run_time), 1, fun); - int new_iters = static_cast(std::ceil(min_time * test.iterations / test.elapsed)); - return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations }; - } - - template - void run() { - auto const* cfg = getCurrentContext().getConfig(); - - auto env = Detail::measure_environment(); - - getResultCapture().benchmarkPreparing(name); - CATCH_TRY{ - auto plan = user_code([&] { - return prepare(*cfg, env); - }); - - BenchmarkInfo info { - CATCH_MOVE(name), - plan.estimated_duration.count(), - plan.iterations_per_sample, - cfg->benchmarkSamples(), - cfg->benchmarkResamples(), - env.clock_resolution.mean.count(), - env.clock_cost.mean.count() - }; - - getResultCapture().benchmarkStarting(info); - - auto samples = user_code([&] { - return plan.template run(*cfg, env); - }); - - auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end()); - BenchmarkStats> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance }; - getResultCapture().benchmarkEnded(stats); - } CATCH_CATCH_ANON (TestFailureException) { - getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr); - } CATCH_CATCH_ALL{ - getResultCapture().benchmarkFailed(translateActiveException()); - // We let the exception go further up so that the - // test case is marked as failed. - std::rethrow_exception(std::current_exception()); - } - } - - // sets lambda to be used in fun *and* executes benchmark! - template ::value, int> = 0> - Benchmark & operator=(Fun func) { - auto const* cfg = getCurrentContext().getConfig(); - if (!cfg->skipBenchmarks()) { - fun = Detail::BenchmarkFunction(func); - run(); - } - return *this; - } - - explicit operator bool() { - return true; - } - - private: - Detail::BenchmarkFunction fun; - std::string name; - }; - } -} // namespace Catch - -#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1 -#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2 - -#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\ - if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ - BenchmarkName = [&](int benchmarkIndex) - -#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\ - if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ - BenchmarkName = [&] - -#if defined(CATCH_CONFIG_PREFIX_ALL) - -#define CATCH_BENCHMARK(...) \ - INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) -#define CATCH_BENCHMARK_ADVANCED(name) \ - INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name) - -#else - -#define BENCHMARK(...) \ - INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) -#define BENCHMARK_ADVANCED(name) \ - INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name) - -#endif - -#endif // CATCH_BENCHMARK_HPP_INCLUDED - - -// Adapted from donated nonius code. - -#ifndef CATCH_CONSTRUCTOR_HPP_INCLUDED -#define CATCH_CONSTRUCTOR_HPP_INCLUDED - - -#include - -namespace Catch { - namespace Benchmark { - namespace Detail { - template - struct ObjectStorage - { - ObjectStorage() = default; - - ObjectStorage(const ObjectStorage& other) - { - new(&data) T(other.stored_object()); - } - - ObjectStorage(ObjectStorage&& other) - { - new(data) T(CATCH_MOVE(other.stored_object())); - } - - ~ObjectStorage() { destruct_on_exit(); } - - template - void construct(Args&&... args) - { - new (data) T(CATCH_FORWARD(args)...); - } - - template - std::enable_if_t destruct() - { - stored_object().~T(); - } - - private: - // If this is a constructor benchmark, destruct the underlying object - template - void destruct_on_exit(std::enable_if_t* = nullptr) { destruct(); } - // Otherwise, don't - template - void destruct_on_exit(std::enable_if_t* = nullptr) { } - -#if defined( __GNUC__ ) && __GNUC__ <= 6 -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wstrict-aliasing" -#endif - T& stored_object() { return *reinterpret_cast( data ); } - - T const& stored_object() const { - return *reinterpret_cast( data ); - } -#if defined( __GNUC__ ) && __GNUC__ <= 6 -# pragma GCC diagnostic pop -#endif - - alignas( T ) unsigned char data[sizeof( T )]{}; - }; - } // namespace Detail - - template - using storage_for = Detail::ObjectStorage; - - template - using destructable_object = Detail::ObjectStorage; - } // namespace Benchmark -} // namespace Catch - -#endif // CATCH_CONSTRUCTOR_HPP_INCLUDED - -#endif // CATCH_BENCHMARK_ALL_HPP_INCLUDED - - -#ifndef CATCH_APPROX_HPP_INCLUDED -#define CATCH_APPROX_HPP_INCLUDED - - - -#ifndef CATCH_TOSTRING_HPP_INCLUDED -#define CATCH_TOSTRING_HPP_INCLUDED - - -#include -#include -#include -#include - - - - -/** \file - * Wrapper for the WCHAR configuration option - * - * We want to support platforms that do not provide `wchar_t`, so we - * sometimes have to disable providing wchar_t overloads through Catch2, - * e.g. the StringMaker specialization for `std::wstring`. - */ - -#ifndef CATCH_CONFIG_WCHAR_HPP_INCLUDED -#define CATCH_CONFIG_WCHAR_HPP_INCLUDED - -// We assume that WCHAR should be enabled by default, and only disabled -// for a shortlist (so far only DJGPP) of compilers. - -#if defined(__DJGPP__) -# define CATCH_INTERNAL_CONFIG_NO_WCHAR -#endif // __DJGPP__ - -#if !defined( CATCH_INTERNAL_CONFIG_NO_WCHAR ) && \ - !defined( CATCH_CONFIG_NO_WCHAR ) && \ - !defined( CATCH_CONFIG_WCHAR ) -# define CATCH_CONFIG_WCHAR -#endif - -#endif // CATCH_CONFIG_WCHAR_HPP_INCLUDED - - -#ifndef CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED -#define CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED - - -#include -#include -#include -#include - -namespace Catch { - - class ReusableStringStream : Detail::NonCopyable { - std::size_t m_index; - std::ostream* m_oss; - public: - ReusableStringStream(); - ~ReusableStringStream(); - - //! Returns the serialized state - std::string str() const; - //! Sets internal state to `str` - void str(std::string const& str); - -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -// Old versions of GCC do not understand -Wnonnull-compare -#pragma GCC diagnostic ignored "-Wpragmas" -// Streaming a function pointer triggers Waddress and Wnonnull-compare -// on GCC, because it implicitly converts it to bool and then decides -// that the check it uses (a? true : false) is tautological and cannot -// be null... -#pragma GCC diagnostic ignored "-Waddress" -#pragma GCC diagnostic ignored "-Wnonnull-compare" -#endif - - template - auto operator << ( T const& value ) -> ReusableStringStream& { - *m_oss << value; - return *this; - } - -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif - auto get() -> std::ostream& { return *m_oss; } - }; -} - -#endif // CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED - - -#ifndef CATCH_VOID_TYPE_HPP_INCLUDED -#define CATCH_VOID_TYPE_HPP_INCLUDED - - -namespace Catch { - namespace Detail { - - template - struct make_void { using type = void; }; - - template - using void_t = typename make_void::type; - - } // namespace Detail -} // namespace Catch - - -#endif // CATCH_VOID_TYPE_HPP_INCLUDED - - -#ifndef CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED -#define CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED - - -#include - -namespace Catch { - - namespace Detail { - struct EnumInfo { - StringRef m_name; - std::vector> m_values; - - ~EnumInfo(); - - StringRef lookup( int value ) const; - }; - } // namespace Detail - - class IMutableEnumValuesRegistry { - public: - virtual ~IMutableEnumValuesRegistry(); // = default; - - virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector const& values ) = 0; - - template - Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list values ) { - static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int"); - std::vector intValues; - intValues.reserve( values.size() ); - for( auto enumValue : values ) - intValues.push_back( static_cast( enumValue ) ); - return registerEnum( enumName, allEnums, intValues ); - } - }; - -} // Catch - -#endif // CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED - -#ifdef CATCH_CONFIG_CPP17_STRING_VIEW -#include -#endif - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless -#endif - -// We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy{}; -std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); - -namespace Catch { - // Bring in global namespace operator<< for ADL lookup in - // `IsStreamInsertable` below. - using ::operator<<; - - namespace Detail { - - inline std::size_t catch_strnlen(const char *str, std::size_t n) { - auto ret = std::char_traits::find(str, n, '\0'); - if (ret != nullptr) { - return static_cast(ret - str); - } - return n; - } - - constexpr StringRef unprintableString = "{?}"_sr; - - //! Encases `string in quotes, and optionally escapes invisibles - std::string convertIntoString( StringRef string, bool escapeInvisibles ); - - //! Encases `string` in quotes, and escapes invisibles if user requested - //! it via CLI - std::string convertIntoString( StringRef string ); - - std::string rawMemoryToString( const void *object, std::size_t size ); - - template - std::string rawMemoryToString( const T& object ) { - return rawMemoryToString( &object, sizeof(object) ); - } - - template - class IsStreamInsertable { - template - static auto test(int) - -> decltype(std::declval() << std::declval(), std::true_type()); - - template - static auto test(...)->std::false_type; - - public: - static const bool value = decltype(test(0))::value; - }; - - template - std::string convertUnknownEnumToString( E e ); - - template - std::enable_if_t< - !std::is_enum::value && !std::is_base_of::value, - std::string> convertUnstreamable( T const& ) { - return std::string(Detail::unprintableString); - } - template - std::enable_if_t< - !std::is_enum::value && std::is_base_of::value, - std::string> convertUnstreamable(T const& ex) { - return ex.what(); - } - - - template - std::enable_if_t< - std::is_enum::value, - std::string> convertUnstreamable( T const& value ) { - return convertUnknownEnumToString( value ); - } - -#if defined(_MANAGED) - //! Convert a CLR string to a utf8 std::string - template - std::string clrReferenceToString( T^ ref ) { - if (ref == nullptr) - return std::string("null"); - auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); - cli::pin_ptr p = &bytes[0]; - return std::string(reinterpret_cast(p), bytes->Length); - } -#endif - - } // namespace Detail - - - // If we decide for C++14, change these to enable_if_ts - template - struct StringMaker { - template - static - std::enable_if_t<::Catch::Detail::IsStreamInsertable::value, std::string> - convert(const Fake& value) { - ReusableStringStream rss; - // NB: call using the function-like syntax to avoid ambiguity with - // user-defined templated operator<< under clang. - rss.operator<<(value); - return rss.str(); - } - - template - static - std::enable_if_t::value, std::string> - convert( const Fake& value ) { -#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) - return Detail::convertUnstreamable(value); -#else - return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); -#endif - } - }; - - namespace Detail { - - // This function dispatches all stringification requests inside of Catch. - // Should be preferably called fully qualified, like ::Catch::Detail::stringify - template - std::string stringify(const T& e) { - return ::Catch::StringMaker>>::convert(e); - } - - template - std::string convertUnknownEnumToString( E e ) { - return ::Catch::Detail::stringify(static_cast>(e)); - } - -#if defined(_MANAGED) - template - std::string stringify( T^ e ) { - return ::Catch::StringMaker::convert(e); - } -#endif - - } // namespace Detail - - // Some predefined specializations - - template<> - struct StringMaker { - static std::string convert(const std::string& str); - }; - -#ifdef CATCH_CONFIG_CPP17_STRING_VIEW - template<> - struct StringMaker { - static std::string convert(std::string_view str); - }; -#endif - - template<> - struct StringMaker { - static std::string convert(char const * str); - }; - template<> - struct StringMaker { - static std::string convert(char * str); - }; - -#if defined(CATCH_CONFIG_WCHAR) - template<> - struct StringMaker { - static std::string convert(const std::wstring& wstr); - }; - -# ifdef CATCH_CONFIG_CPP17_STRING_VIEW - template<> - struct StringMaker { - static std::string convert(std::wstring_view str); - }; -# endif - - template<> - struct StringMaker { - static std::string convert(wchar_t const * str); - }; - template<> - struct StringMaker { - static std::string convert(wchar_t * str); - }; -#endif // CATCH_CONFIG_WCHAR - - template - struct StringMaker { - static std::string convert(char const* str) { - return Detail::convertIntoString( - StringRef( str, Detail::catch_strnlen( str, SZ ) ) ); - } - }; - template - struct StringMaker { - static std::string convert(signed char const* str) { - auto reinterpreted = reinterpret_cast(str); - return Detail::convertIntoString( - StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ))); - } - }; - template - struct StringMaker { - static std::string convert(unsigned char const* str) { - auto reinterpreted = reinterpret_cast(str); - return Detail::convertIntoString( - StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ))); - } - }; - -#if defined(CATCH_CONFIG_CPP17_BYTE) - template<> - struct StringMaker { - static std::string convert(std::byte value); - }; -#endif // defined(CATCH_CONFIG_CPP17_BYTE) - template<> - struct StringMaker { - static std::string convert(int value); - }; - template<> - struct StringMaker { - static std::string convert(long value); - }; - template<> - struct StringMaker { - static std::string convert(long long value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned int value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned long value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned long long value); - }; - - template<> - struct StringMaker { - static std::string convert(bool b) { - using namespace std::string_literals; - return b ? "true"s : "false"s; - } - }; - - template<> - struct StringMaker { - static std::string convert(char c); - }; - template<> - struct StringMaker { - static std::string convert(signed char c); - }; - template<> - struct StringMaker { - static std::string convert(unsigned char c); - }; - - template<> - struct StringMaker { - static std::string convert(std::nullptr_t) { - using namespace std::string_literals; - return "nullptr"s; - } - }; - - template<> - struct StringMaker { - static std::string convert(float value); - CATCH_EXPORT static int precision; - }; - - template<> - struct StringMaker { - static std::string convert(double value); - CATCH_EXPORT static int precision; - }; - - template - struct StringMaker { - template - static std::string convert(U* p) { - if (p) { - return ::Catch::Detail::rawMemoryToString(p); - } else { - return "nullptr"; - } - } - }; - - template - struct StringMaker { - static std::string convert(R C::* p) { - if (p) { - return ::Catch::Detail::rawMemoryToString(p); - } else { - return "nullptr"; - } - } - }; - -#if defined(_MANAGED) - template - struct StringMaker { - static std::string convert( T^ ref ) { - return ::Catch::Detail::clrReferenceToString(ref); - } - }; -#endif - - namespace Detail { - template - std::string rangeToString(InputIterator first, Sentinel last) { - ReusableStringStream rss; - rss << "{ "; - if (first != last) { - rss << ::Catch::Detail::stringify(*first); - for (++first; first != last; ++first) - rss << ", " << ::Catch::Detail::stringify(*first); - } - rss << " }"; - return rss.str(); - } - } - -} // namespace Catch - -////////////////////////////////////////////////////// -// Separate std-lib types stringification, so it can be selectively enabled -// This means that we do not bring in their headers - -#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) -# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER -# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER -# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER -# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER -#endif - -// Separate std::pair specialization -#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) -#include -namespace Catch { - template - struct StringMaker > { - static std::string convert(const std::pair& pair) { - ReusableStringStream rss; - rss << "{ " - << ::Catch::Detail::stringify(pair.first) - << ", " - << ::Catch::Detail::stringify(pair.second) - << " }"; - return rss.str(); - } - }; -} -#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER - -#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL) -#include -namespace Catch { - template - struct StringMaker > { - static std::string convert(const std::optional& optional) { - if (optional.has_value()) { - return ::Catch::Detail::stringify(*optional); - } else { - return "{ }"; - } - } - }; -} -#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER - -// Separate std::tuple specialization -#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) -#include -namespace Catch { - namespace Detail { - template< - typename Tuple, - std::size_t N = 0, - bool = (N < std::tuple_size::value) - > - struct TupleElementPrinter { - static void print(const Tuple& tuple, std::ostream& os) { - os << (N ? ", " : " ") - << ::Catch::Detail::stringify(std::get(tuple)); - TupleElementPrinter::print(tuple, os); - } - }; - - template< - typename Tuple, - std::size_t N - > - struct TupleElementPrinter { - static void print(const Tuple&, std::ostream&) {} - }; - - } - - - template - struct StringMaker> { - static std::string convert(const std::tuple& tuple) { - ReusableStringStream rss; - rss << '{'; - Detail::TupleElementPrinter>::print(tuple, rss.get()); - rss << " }"; - return rss.str(); - } - }; -} -#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER - -#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT) -#include -namespace Catch { - template<> - struct StringMaker { - static std::string convert(const std::monostate&) { - return "{ }"; - } - }; - - template - struct StringMaker> { - static std::string convert(const std::variant& variant) { - if (variant.valueless_by_exception()) { - return "{valueless variant}"; - } else { - return std::visit( - [](const auto& value) { - return ::Catch::Detail::stringify(value); - }, - variant - ); - } - } - }; -} -#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER - -namespace Catch { - // Import begin/ end from std here - using std::begin; - using std::end; - - namespace Detail { - template - struct is_range_impl : std::false_type {}; - - template - struct is_range_impl()))>> : std::true_type {}; - } // namespace Detail - - template - struct is_range : Detail::is_range_impl {}; - -#if defined(_MANAGED) // Managed types are never ranges - template - struct is_range { - static const bool value = false; - }; -#endif - - template - std::string rangeToString( Range const& range ) { - return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); - } - - // Handle vector specially - template - std::string rangeToString( std::vector const& v ) { - ReusableStringStream rss; - rss << "{ "; - bool first = true; - for( bool b : v ) { - if( first ) - first = false; - else - rss << ", "; - rss << ::Catch::Detail::stringify( b ); - } - rss << " }"; - return rss.str(); - } - - template - struct StringMaker::value && !::Catch::Detail::IsStreamInsertable::value>> { - static std::string convert( R const& range ) { - return rangeToString( range ); - } - }; - - template - struct StringMaker { - static std::string convert(T const(&arr)[SZ]) { - return rangeToString(arr); - } - }; - - -} // namespace Catch - -// Separate std::chrono::duration specialization -#include -#include -#include - - -namespace Catch { - -template -struct ratio_string { - static std::string symbol() { - Catch::ReusableStringStream rss; - rss << '[' << Ratio::num << '/' - << Ratio::den << ']'; - return rss.str(); - } -}; - -template <> -struct ratio_string { - static char symbol() { return 'a'; } -}; -template <> -struct ratio_string { - static char symbol() { return 'f'; } -}; -template <> -struct ratio_string { - static char symbol() { return 'p'; } -}; -template <> -struct ratio_string { - static char symbol() { return 'n'; } -}; -template <> -struct ratio_string { - static char symbol() { return 'u'; } -}; -template <> -struct ratio_string { - static char symbol() { return 'm'; } -}; - - //////////// - // std::chrono::duration specializations - template - struct StringMaker> { - static std::string convert(std::chrono::duration const& duration) { - ReusableStringStream rss; - rss << duration.count() << ' ' << ratio_string::symbol() << 's'; - return rss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - ReusableStringStream rss; - rss << duration.count() << " s"; - return rss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - ReusableStringStream rss; - rss << duration.count() << " m"; - return rss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - ReusableStringStream rss; - rss << duration.count() << " h"; - return rss.str(); - } - }; - - //////////// - // std::chrono::time_point specialization - // Generic time_point cannot be specialized, only std::chrono::time_point - template - struct StringMaker> { - static std::string convert(std::chrono::time_point const& time_point) { - return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; - } - }; - // std::chrono::time_point specialization - template - struct StringMaker> { - static std::string convert(std::chrono::time_point const& time_point) { - auto converted = std::chrono::system_clock::to_time_t(time_point); - -#ifdef _MSC_VER - std::tm timeInfo = {}; - gmtime_s(&timeInfo, &converted); -#else - std::tm* timeInfo = std::gmtime(&converted); -#endif - - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); - char timeStamp[timeStampSize]; - const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; - -#ifdef _MSC_VER - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); -#else - std::strftime(timeStamp, timeStampSize, fmt, timeInfo); -#endif - return std::string(timeStamp, timeStampSize - 1); - } - }; -} - - -#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \ -namespace Catch { \ - template<> struct StringMaker { \ - static std::string convert( enumName value ) { \ - static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \ - return static_cast(enumInfo.lookup( static_cast( value ) )); \ - } \ - }; \ -} - -#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ ) - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#endif // CATCH_TOSTRING_HPP_INCLUDED - -#include - -namespace Catch { - - class Approx { - private: - bool equalityComparisonImpl(double other) const; - // Sets and validates the new margin (margin >= 0) - void setMargin(double margin); - // Sets and validates the new epsilon (0 < epsilon < 1) - void setEpsilon(double epsilon); - - public: - explicit Approx ( double value ); - - static Approx custom(); - - Approx operator-() const; - - template ::value>> - Approx operator()( T const& value ) const { - Approx approx( static_cast(value) ); - approx.m_epsilon = m_epsilon; - approx.m_margin = m_margin; - approx.m_scale = m_scale; - return approx; - } - - template ::value>> - explicit Approx( T const& value ): Approx(static_cast(value)) - {} - - - template ::value>> - friend bool operator == ( const T& lhs, Approx const& rhs ) { - auto lhs_v = static_cast(lhs); - return rhs.equalityComparisonImpl(lhs_v); - } - - template ::value>> - friend bool operator == ( Approx const& lhs, const T& rhs ) { - return operator==( rhs, lhs ); - } - - template ::value>> - friend bool operator != ( T const& lhs, Approx const& rhs ) { - return !operator==( lhs, rhs ); - } - - template ::value>> - friend bool operator != ( Approx const& lhs, T const& rhs ) { - return !operator==( rhs, lhs ); - } - - template ::value>> - friend bool operator <= ( T const& lhs, Approx const& rhs ) { - return static_cast(lhs) < rhs.m_value || lhs == rhs; - } - - template ::value>> - friend bool operator <= ( Approx const& lhs, T const& rhs ) { - return lhs.m_value < static_cast(rhs) || lhs == rhs; - } - - template ::value>> - friend bool operator >= ( T const& lhs, Approx const& rhs ) { - return static_cast(lhs) > rhs.m_value || lhs == rhs; - } - - template ::value>> - friend bool operator >= ( Approx const& lhs, T const& rhs ) { - return lhs.m_value > static_cast(rhs) || lhs == rhs; - } - - template ::value>> - Approx& epsilon( T const& newEpsilon ) { - const auto epsilonAsDouble = static_cast(newEpsilon); - setEpsilon(epsilonAsDouble); - return *this; - } - - template ::value>> - Approx& margin( T const& newMargin ) { - const auto marginAsDouble = static_cast(newMargin); - setMargin(marginAsDouble); - return *this; - } - - template ::value>> - Approx& scale( T const& newScale ) { - m_scale = static_cast(newScale); - return *this; - } - - std::string toString() const; - - private: - double m_epsilon; - double m_margin; - double m_scale; - double m_value; - }; - -namespace literals { - Approx operator ""_a(long double val); - Approx operator ""_a(unsigned long long val); -} // end namespace literals - -template<> -struct StringMaker { - static std::string convert(Catch::Approx const& value); -}; - -} // end namespace Catch - -#endif // CATCH_APPROX_HPP_INCLUDED - - -#ifndef CATCH_CONFIG_HPP_INCLUDED -#define CATCH_CONFIG_HPP_INCLUDED - - - -#ifndef CATCH_TEST_SPEC_HPP_INCLUDED -#define CATCH_TEST_SPEC_HPP_INCLUDED - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - - - -#ifndef CATCH_WILDCARD_PATTERN_HPP_INCLUDED -#define CATCH_WILDCARD_PATTERN_HPP_INCLUDED - - - -#ifndef CATCH_CASE_SENSITIVE_HPP_INCLUDED -#define CATCH_CASE_SENSITIVE_HPP_INCLUDED - -namespace Catch { - - enum class CaseSensitive { Yes, No }; - -} // namespace Catch - -#endif // CATCH_CASE_SENSITIVE_HPP_INCLUDED - -#include - -namespace Catch -{ - class WildcardPattern { - enum WildcardPosition { - NoWildcard = 0, - WildcardAtStart = 1, - WildcardAtEnd = 2, - WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd - }; - - public: - - WildcardPattern( std::string const& pattern, CaseSensitive caseSensitivity ); - bool matches( std::string const& str ) const; - - private: - std::string normaliseString( std::string const& str ) const; - CaseSensitive m_caseSensitivity; - WildcardPosition m_wildcard = NoWildcard; - std::string m_pattern; - }; -} - -#endif // CATCH_WILDCARD_PATTERN_HPP_INCLUDED - -#include -#include -#include - -namespace Catch { - - class IConfig; - struct TestCaseInfo; - class TestCaseHandle; - - class TestSpec { - - class Pattern { - public: - explicit Pattern( std::string const& name ); - virtual ~Pattern(); - virtual bool matches( TestCaseInfo const& testCase ) const = 0; - std::string const& name() const; - private: - virtual void serializeTo( std::ostream& out ) const = 0; - // Writes string that would be reparsed into the pattern - friend std::ostream& operator<<(std::ostream& out, - Pattern const& pattern) { - pattern.serializeTo( out ); - return out; - } - - std::string const m_name; - }; - - class NamePattern : public Pattern { - public: - explicit NamePattern( std::string const& name, std::string const& filterString ); - bool matches( TestCaseInfo const& testCase ) const override; - private: - void serializeTo( std::ostream& out ) const override; - - WildcardPattern m_wildcardPattern; - }; - - class TagPattern : public Pattern { - public: - explicit TagPattern( std::string const& tag, std::string const& filterString ); - bool matches( TestCaseInfo const& testCase ) const override; - private: - void serializeTo( std::ostream& out ) const override; - - std::string m_tag; - }; - - struct Filter { - std::vector> m_required; - std::vector> m_forbidden; - - //! Serializes this filter into a string that would be parsed into - //! an equivalent filter - void serializeTo( std::ostream& out ) const; - friend std::ostream& operator<<(std::ostream& out, Filter const& f) { - f.serializeTo( out ); - return out; - } - - bool matches( TestCaseInfo const& testCase ) const; - }; - - static std::string extractFilterName( Filter const& filter ); - - public: - struct FilterMatch { - std::string name; - std::vector tests; - }; - using Matches = std::vector; - using vectorStrings = std::vector; - - bool hasFilters() const; - bool matches( TestCaseInfo const& testCase ) const; - Matches matchesByFilter( std::vector const& testCases, IConfig const& config ) const; - const vectorStrings & getInvalidSpecs() const; - - private: - std::vector m_filters; - std::vector m_invalidSpecs; - - friend class TestSpecParser; - //! Serializes this test spec into a string that would be parsed into - //! equivalent test spec - void serializeTo( std::ostream& out ) const; - friend std::ostream& operator<<(std::ostream& out, - TestSpec const& spec) { - spec.serializeTo( out ); - return out; - } - }; -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#endif // CATCH_TEST_SPEC_HPP_INCLUDED - - -#ifndef CATCH_OPTIONAL_HPP_INCLUDED -#define CATCH_OPTIONAL_HPP_INCLUDED - -#include - -namespace Catch { - - // An optional type - template - class Optional { - public: - Optional() : nullableValue( nullptr ) {} - Optional( T const& _value ) - : nullableValue( new( storage ) T( _value ) ) - {} - Optional( Optional const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) - {} - - ~Optional() { - reset(); - } - - Optional& operator= ( Optional const& _other ) { - if( &_other != this ) { - reset(); - if( _other ) - nullableValue = new( storage ) T( *_other ); - } - return *this; - } - Optional& operator = ( T const& _value ) { - reset(); - nullableValue = new( storage ) T( _value ); - return *this; - } - - void reset() { - if( nullableValue ) - nullableValue->~T(); - nullableValue = nullptr; - } - - T& operator*() { - assert(nullableValue); - return *nullableValue; - } - T const& operator*() const { - assert(nullableValue); - return *nullableValue; - } - T* operator->() { - assert(nullableValue); - return nullableValue; - } - const T* operator->() const { - assert(nullableValue); - return nullableValue; - } - - T valueOr( T const& defaultValue ) const { - return nullableValue ? *nullableValue : defaultValue; - } - - bool some() const { return nullableValue != nullptr; } - bool none() const { return nullableValue == nullptr; } - - bool operator !() const { return nullableValue == nullptr; } - explicit operator bool() const { - return some(); - } - - friend bool operator==(Optional const& a, Optional const& b) { - if (a.none() && b.none()) { - return true; - } else if (a.some() && b.some()) { - return *a == *b; - } else { - return false; - } - } - friend bool operator!=(Optional const& a, Optional const& b) { - return !( a == b ); - } - - private: - T *nullableValue; - alignas(alignof(T)) char storage[sizeof(T)]; - }; - -} // end namespace Catch - -#endif // CATCH_OPTIONAL_HPP_INCLUDED - - -#ifndef CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED -#define CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED - -#include - -namespace Catch { - - enum class GenerateFrom { - Time, - RandomDevice, - //! Currently equivalent to RandomDevice, but can change at any point - Default - }; - - std::uint32_t generateRandomSeed(GenerateFrom from); - -} // end namespace Catch - -#endif // CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED - - -#ifndef CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED -#define CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED - - - -#ifndef CATCH_CONSOLE_COLOUR_HPP_INCLUDED -#define CATCH_CONSOLE_COLOUR_HPP_INCLUDED - - -#include -#include - -namespace Catch { - - enum class ColourMode : std::uint8_t; - class IStream; - - struct Colour { - enum Code { - None = 0, - - White, - Red, - Green, - Blue, - Cyan, - Yellow, - Grey, - - Bright = 0x10, - - BrightRed = Bright | Red, - BrightGreen = Bright | Green, - LightGrey = Bright | Grey, - BrightWhite = Bright | White, - BrightYellow = Bright | Yellow, - - // By intention - FileName = LightGrey, - Warning = BrightYellow, - ResultError = BrightRed, - ResultSuccess = BrightGreen, - ResultExpectedFailure = Warning, - - Error = BrightRed, - Success = Green, - Skip = LightGrey, - - OriginalExpression = Cyan, - ReconstructedExpression = BrightYellow, - - SecondaryText = LightGrey, - Headers = White - }; - }; - - class ColourImpl { - protected: - //! The associated stream of this ColourImpl instance - IStream* m_stream; - public: - ColourImpl( IStream* stream ): m_stream( stream ) {} - - //! RAII wrapper around writing specific colour of text using specific - //! colour impl into a stream. - class ColourGuard { - ColourImpl const* m_colourImpl; - Colour::Code m_code; - bool m_engaged = false; - - public: - //! Does **not** engage the guard/start the colour - ColourGuard( Colour::Code code, - ColourImpl const* colour ); - - ColourGuard( ColourGuard const& rhs ) = delete; - ColourGuard& operator=( ColourGuard const& rhs ) = delete; - - ColourGuard( ColourGuard&& rhs ) noexcept; - ColourGuard& operator=( ColourGuard&& rhs ) noexcept; - - //! Removes colour _if_ the guard was engaged - ~ColourGuard(); - - /** - * Explicitly engages colour for given stream. - * - * The API based on operator<< should be preferred. - */ - ColourGuard& engage( std::ostream& stream ) &; - /** - * Explicitly engages colour for given stream. - * - * The API based on operator<< should be preferred. - */ - ColourGuard&& engage( std::ostream& stream ) &&; - - private: - //! Engages the guard and starts using colour - friend std::ostream& operator<<( std::ostream& lhs, - ColourGuard& guard ) { - guard.engageImpl( lhs ); - return lhs; - } - //! Engages the guard and starts using colour - friend std::ostream& operator<<( std::ostream& lhs, - ColourGuard&& guard) { - guard.engageImpl( lhs ); - return lhs; - } - - void engageImpl( std::ostream& stream ); - - }; - - virtual ~ColourImpl(); // = default - /** - * Creates a guard object for given colour and this colour impl - * - * **Important:** - * the guard starts disengaged, and has to be engaged explicitly. - */ - ColourGuard guardColour( Colour::Code colourCode ); - - private: - virtual void use( Colour::Code colourCode ) const = 0; - }; - - //! Provides ColourImpl based on global config and target compilation platform - Detail::unique_ptr makeColourImpl( ColourMode colourSelection, - IStream* stream ); - - //! Checks if specific colour impl has been compiled into the binary - bool isColourImplAvailable( ColourMode colourSelection ); - -} // end namespace Catch - -#endif // CATCH_CONSOLE_COLOUR_HPP_INCLUDED - -#include -#include -#include - -namespace Catch { - - enum class ColourMode : std::uint8_t; - - namespace Detail { - //! Splits the reporter spec into reporter name and kv-pair options - std::vector splitReporterSpec( StringRef reporterSpec ); - - Optional stringToColourMode( StringRef colourMode ); - } - - /** - * Structured reporter spec that a reporter can be created from - * - * Parsing has been validated, but semantics have not. This means e.g. - * that the colour mode is known to Catch2, but it might not be - * compiled into the binary, and the output filename might not be - * openable. - */ - class ReporterSpec { - std::string m_name; - Optional m_outputFileName; - Optional m_colourMode; - std::map m_customOptions; - - friend bool operator==( ReporterSpec const& lhs, - ReporterSpec const& rhs ); - friend bool operator!=( ReporterSpec const& lhs, - ReporterSpec const& rhs ) { - return !( lhs == rhs ); - } - - public: - ReporterSpec( - std::string name, - Optional outputFileName, - Optional colourMode, - std::map customOptions ); - - std::string const& name() const { return m_name; } - - Optional const& outputFile() const { - return m_outputFileName; - } - - Optional const& colourMode() const { return m_colourMode; } - - std::map const& customOptions() const { - return m_customOptions; - } - }; - - /** - * Parses provided reporter spec string into - * - * Returns empty optional on errors, e.g. - * * field that is not first and not a key+value pair - * * duplicated keys in kv pair - * * unknown catch reporter option - * * empty key/value in an custom kv pair - * * ... - */ - Optional parseReporterSpec( StringRef reporterSpec ); - -} - -#endif // CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED - -#include -#include -#include -#include - -namespace Catch { - - class IStream; - - /** - * `ReporterSpec` but with the defaults filled in. - * - * Like `ReporterSpec`, the semantics are unchecked. - */ - struct ProcessedReporterSpec { - std::string name; - std::string outputFilename; - ColourMode colourMode; - std::map customOptions; - friend bool operator==( ProcessedReporterSpec const& lhs, - ProcessedReporterSpec const& rhs ); - friend bool operator!=( ProcessedReporterSpec const& lhs, - ProcessedReporterSpec const& rhs ) { - return !( lhs == rhs ); - } - }; - - struct ConfigData { - - bool listTests = false; - bool listTags = false; - bool listReporters = false; - bool listListeners = false; - - bool showSuccessfulTests = false; - bool shouldDebugBreak = false; - bool noThrow = false; - bool showHelp = false; - bool showInvisibles = false; - bool filenamesAsTags = false; - bool libIdentify = false; - bool allowZeroTests = false; - - int abortAfter = -1; - uint32_t rngSeed = generateRandomSeed(GenerateFrom::Default); - - unsigned int shardCount = 1; - unsigned int shardIndex = 0; - - bool skipBenchmarks = false; - bool benchmarkNoAnalysis = false; - unsigned int benchmarkSamples = 100; - double benchmarkConfidenceInterval = 0.95; - unsigned int benchmarkResamples = 100000; - std::chrono::milliseconds::rep benchmarkWarmupTime = 100; - - Verbosity verbosity = Verbosity::Normal; - WarnAbout::What warnings = WarnAbout::Nothing; - ShowDurations showDurations = ShowDurations::DefaultForReporter; - double minDuration = -1; - TestRunOrder runOrder = TestRunOrder::Declared; - ColourMode defaultColourMode = ColourMode::PlatformDefault; - WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; - - std::string defaultOutputFilename; - std::string name; - std::string processName; - std::vector reporterSpecifications; - - std::vector testsOrTags; - std::vector sectionsToRun; - }; - - - class Config : public IConfig { - public: - - Config() = default; - Config( ConfigData const& data ); - ~Config() override; // = default in the cpp file - - bool listTests() const; - bool listTags() const; - bool listReporters() const; - bool listListeners() const; - - std::vector const& getReporterSpecs() const; - std::vector const& - getProcessedReporterSpecs() const; - - std::vector const& getTestsOrTags() const override; - std::vector const& getSectionsToRun() const override; - - TestSpec const& testSpec() const override; - bool hasTestFilters() const override; - - bool showHelp() const; - - // IConfig interface - bool allowThrows() const override; - StringRef name() const override; - bool includeSuccessfulResults() const override; - bool warnAboutMissingAssertions() const override; - bool warnAboutUnmatchedTestSpecs() const override; - bool zeroTestsCountAsSuccess() const override; - ShowDurations showDurations() const override; - double minDuration() const override; - TestRunOrder runOrder() const override; - uint32_t rngSeed() const override; - unsigned int shardCount() const override; - unsigned int shardIndex() const override; - ColourMode defaultColourMode() const override; - bool shouldDebugBreak() const override; - int abortAfter() const override; - bool showInvisibles() const override; - Verbosity verbosity() const override; - bool skipBenchmarks() const override; - bool benchmarkNoAnalysis() const override; - unsigned int benchmarkSamples() const override; - double benchmarkConfidenceInterval() const override; - unsigned int benchmarkResamples() const override; - std::chrono::milliseconds benchmarkWarmupTime() const override; - - private: - // Reads Bazel env vars and applies them to the config - void readBazelEnvVars(); - - ConfigData m_data; - std::vector m_processedReporterSpecs; - TestSpec m_testSpec; - bool m_hasTestFilters = false; - }; -} // end namespace Catch - -#endif // CATCH_CONFIG_HPP_INCLUDED - - -#ifndef CATCH_GET_RANDOM_SEED_HPP_INCLUDED -#define CATCH_GET_RANDOM_SEED_HPP_INCLUDED - -#include - -namespace Catch { - //! Returns Catch2's current RNG seed. - std::uint32_t getSeed(); -} - -#endif // CATCH_GET_RANDOM_SEED_HPP_INCLUDED - - -#ifndef CATCH_MESSAGE_HPP_INCLUDED -#define CATCH_MESSAGE_HPP_INCLUDED - - - -#ifndef CATCH_STREAM_END_STOP_HPP_INCLUDED -#define CATCH_STREAM_END_STOP_HPP_INCLUDED - - -namespace Catch { - - // Use this in variadic streaming macros to allow - // << +StreamEndStop - // as well as - // << stuff +StreamEndStop - struct StreamEndStop { - StringRef operator+() const { return StringRef(); } - - template - friend T const& operator+( T const& value, StreamEndStop ) { - return value; - } - }; - -} // namespace Catch - -#endif // CATCH_STREAM_END_STOP_HPP_INCLUDED - -#include -#include - -namespace Catch { - - struct SourceLineInfo; - - struct MessageStream { - - template - MessageStream& operator << ( T const& value ) { - m_stream << value; - return *this; - } - - ReusableStringStream m_stream; - }; - - struct MessageBuilder : MessageStream { - MessageBuilder( StringRef macroName, - SourceLineInfo const& lineInfo, - ResultWas::OfType type ): - m_info(macroName, lineInfo, type) {} - - template - MessageBuilder&& operator << ( T const& value ) && { - m_stream << value; - return CATCH_MOVE(*this); - } - - MessageInfo m_info; - }; - - class ScopedMessage { - public: - explicit ScopedMessage( MessageBuilder&& builder ); - ScopedMessage( ScopedMessage& duplicate ) = delete; - ScopedMessage( ScopedMessage&& old ) noexcept; - ~ScopedMessage(); - - MessageInfo m_info; - bool m_moved = false; - }; - - class Capturer { - std::vector m_messages; - IResultCapture& m_resultCapture = getResultCapture(); - size_t m_captured = 0; - public: - Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); - - Capturer(Capturer const&) = delete; - Capturer& operator=(Capturer const&) = delete; - - ~Capturer(); - - void captureValue( size_t index, std::string const& value ); - - template - void captureValues( size_t index, T const& value ) { - captureValue( index, Catch::Detail::stringify( value ) ); - } - - template - void captureValues( size_t index, T const& value, Ts const&... values ) { - captureValue( index, Catch::Detail::stringify(value) ); - captureValues( index+1, values... ); - } - }; - -} // end namespace Catch - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \ - catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \ - Catch::Capturer varName( macroName##_catch_sr, \ - CATCH_INTERNAL_LINEINFO, \ - Catch::ResultWas::Info, \ - #__VA_ARGS__##_catch_sr ); \ - varName.captureValues( 0, __VA_ARGS__ ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_INFO( macroName, log ) \ - const Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \ - Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) - - -#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) - - #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) - #define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg ) - #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) - #define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE", __VA_ARGS__ ) - -#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) - - #define CATCH_INFO( msg ) (void)(0) - #define CATCH_UNSCOPED_INFO( msg ) (void)(0) - #define CATCH_WARN( msg ) (void)(0) - #define CATCH_CAPTURE( ... ) (void)(0) - -#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) - - #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) - #define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg ) - #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) - #define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE", __VA_ARGS__ ) - -#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) - - #define INFO( msg ) (void)(0) - #define UNSCOPED_INFO( msg ) (void)(0) - #define WARN( msg ) (void)(0) - #define CAPTURE( ... ) (void)(0) - -#endif // end of user facing macro declarations - - - - -#endif // CATCH_MESSAGE_HPP_INCLUDED - - -#ifndef CATCH_SESSION_HPP_INCLUDED -#define CATCH_SESSION_HPP_INCLUDED - - - -#ifndef CATCH_COMMANDLINE_HPP_INCLUDED -#define CATCH_COMMANDLINE_HPP_INCLUDED - - - -#ifndef CATCH_CLARA_HPP_INCLUDED -#define CATCH_CLARA_HPP_INCLUDED - -#if defined( __clang__ ) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wweak-vtables" -# pragma clang diagnostic ignored "-Wshadow" -# pragma clang diagnostic ignored "-Wdeprecated" -#endif - -#if defined( __GNUC__ ) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wsign-conversion" -#endif - -#ifndef CLARA_CONFIG_OPTIONAL_TYPE -# ifdef __has_include -# if __has_include( ) && __cplusplus >= 201703L -# include -# define CLARA_CONFIG_OPTIONAL_TYPE std::optional -# endif -# endif -#endif - - -#include -#include -#include -#include -#include -#include -#include - -namespace Catch { - namespace Clara { - - class Args; - class Parser; - - // enum of result types from a parse - enum class ParseResultType { - Matched, - NoMatch, - ShortCircuitAll, - ShortCircuitSame - }; - - struct accept_many_t {}; - constexpr accept_many_t accept_many {}; - - namespace Detail { - struct fake_arg { - template - operator T(); - }; - - template - struct is_unary_function : std::false_type {}; - - template - struct is_unary_function< - F, - Catch::Detail::void_t()( fake_arg() ) ) - > - > : std::true_type {}; - - // Traits for extracting arg and return type of lambdas (for single - // argument lambdas) - template - struct UnaryLambdaTraits - : UnaryLambdaTraits {}; - - template - struct UnaryLambdaTraits { - static const bool isValid = false; - }; - - template - struct UnaryLambdaTraits { - static const bool isValid = true; - using ArgType = std::remove_const_t>; - using ReturnType = ReturnT; - }; - - class TokenStream; - - // Wraps a token coming from a token stream. These may not directly - // correspond to strings as a single string may encode an option + - // its argument if the : or = form is used - enum class TokenType { Option, Argument }; - struct Token { - TokenType type; - std::string token; - }; - - // Abstracts iterators into args as a stream of tokens, with option - // arguments uniformly handled - class TokenStream { - using Iterator = std::vector::const_iterator; - Iterator it; - Iterator itEnd; - std::vector m_tokenBuffer; - - void loadBuffer(); - - public: - explicit TokenStream( Args const& args ); - TokenStream( Iterator it, Iterator itEnd ); - - explicit operator bool() const { - return !m_tokenBuffer.empty() || it != itEnd; - } - - size_t count() const { - return m_tokenBuffer.size() + ( itEnd - it ); - } - - Token operator*() const { - assert( !m_tokenBuffer.empty() ); - return m_tokenBuffer.front(); - } - - Token const* operator->() const { - assert( !m_tokenBuffer.empty() ); - return &m_tokenBuffer.front(); - } - - TokenStream& operator++(); - }; - - //! Denotes type of a parsing result - enum class ResultType { - Ok, ///< No errors - LogicError, ///< Error in user-specified arguments for - ///< construction - RuntimeError ///< Error in parsing inputs - }; - - class ResultBase { - protected: - ResultBase( ResultType type ): m_type( type ) {} - virtual ~ResultBase(); // = default; - - - ResultBase(ResultBase const&) = default; - ResultBase& operator=(ResultBase const&) = default; - ResultBase(ResultBase&&) = default; - ResultBase& operator=(ResultBase&&) = default; - - virtual void enforceOk() const = 0; - - ResultType m_type; - }; - - template class ResultValueBase : public ResultBase { - public: - auto value() const -> T const& { - enforceOk(); - return m_value; - } - - protected: - ResultValueBase( ResultType type ): ResultBase( type ) {} - - ResultValueBase( ResultValueBase const& other ): - ResultBase( other ) { - if ( m_type == ResultType::Ok ) - new ( &m_value ) T( other.m_value ); - } - - ResultValueBase( ResultType, T const& value ): ResultBase( ResultType::Ok ) { - new ( &m_value ) T( value ); - } - - auto operator=( ResultValueBase const& other ) - -> ResultValueBase& { - if ( m_type == ResultType::Ok ) - m_value.~T(); - ResultBase::operator=( other ); - if ( m_type == ResultType::Ok ) - new ( &m_value ) T( other.m_value ); - return *this; - } - - ~ResultValueBase() override { - if ( m_type == ResultType::Ok ) - m_value.~T(); - } - - union { - T m_value; - }; - }; - - template <> class ResultValueBase : public ResultBase { - protected: - using ResultBase::ResultBase; - }; - - template - class BasicResult : public ResultValueBase { - public: - template - explicit BasicResult( BasicResult const& other ): - ResultValueBase( other.type() ), - m_errorMessage( other.errorMessage() ) { - assert( type() != ResultType::Ok ); - } - - template - static auto ok( U const& value ) -> BasicResult { - return { ResultType::Ok, value }; - } - static auto ok() -> BasicResult { return { ResultType::Ok }; } - static auto logicError( std::string&& message ) - -> BasicResult { - return { ResultType::LogicError, CATCH_MOVE(message) }; - } - static auto runtimeError( std::string&& message ) - -> BasicResult { - return { ResultType::RuntimeError, CATCH_MOVE(message) }; - } - - explicit operator bool() const { - return m_type == ResultType::Ok; - } - auto type() const -> ResultType { return m_type; } - auto errorMessage() const -> std::string const& { - return m_errorMessage; - } - - protected: - void enforceOk() const override { - - // Errors shouldn't reach this point, but if they do - // the actual error message will be in m_errorMessage - assert( m_type != ResultType::LogicError ); - assert( m_type != ResultType::RuntimeError ); - if ( m_type != ResultType::Ok ) - std::abort(); - } - - std::string - m_errorMessage; // Only populated if resultType is an error - - BasicResult( ResultType type, - std::string&& message ): - ResultValueBase( type ), m_errorMessage( CATCH_MOVE(message) ) { - assert( m_type != ResultType::Ok ); - } - - using ResultValueBase::ResultValueBase; - using ResultBase::m_type; - }; - - class ParseState { - public: - ParseState( ParseResultType type, - TokenStream const& remainingTokens ); - - ParseResultType type() const { return m_type; } - TokenStream const& remainingTokens() const { - return m_remainingTokens; - } - - private: - ParseResultType m_type; - TokenStream m_remainingTokens; - }; - - using Result = BasicResult; - using ParserResult = BasicResult; - using InternalParseResult = BasicResult; - - struct HelpColumns { - std::string left; - std::string right; - }; - - template - ParserResult convertInto( std::string const& source, T& target ) { - std::stringstream ss( source ); - ss >> target; - if ( ss.fail() ) { - return ParserResult::runtimeError( - "Unable to convert '" + source + - "' to destination type" ); - } else { - return ParserResult::ok( ParseResultType::Matched ); - } - } - ParserResult convertInto( std::string const& source, - std::string& target ); - ParserResult convertInto( std::string const& source, bool& target ); - -#ifdef CLARA_CONFIG_OPTIONAL_TYPE - template - auto convertInto( std::string const& source, - CLARA_CONFIG_OPTIONAL_TYPE& target ) - -> ParserResult { - T temp; - auto result = convertInto( source, temp ); - if ( result ) - target = CATCH_MOVE( temp ); - return result; - } -#endif // CLARA_CONFIG_OPTIONAL_TYPE - - struct BoundRef : Catch::Detail::NonCopyable { - virtual ~BoundRef() = default; - virtual bool isContainer() const; - virtual bool isFlag() const; - }; - struct BoundValueRefBase : BoundRef { - virtual auto setValue( std::string const& arg ) - -> ParserResult = 0; - }; - struct BoundFlagRefBase : BoundRef { - virtual auto setFlag( bool flag ) -> ParserResult = 0; - bool isFlag() const override; - }; - - template struct BoundValueRef : BoundValueRefBase { - T& m_ref; - - explicit BoundValueRef( T& ref ): m_ref( ref ) {} - - ParserResult setValue( std::string const& arg ) override { - return convertInto( arg, m_ref ); - } - }; - - template - struct BoundValueRef> : BoundValueRefBase { - std::vector& m_ref; - - explicit BoundValueRef( std::vector& ref ): m_ref( ref ) {} - - auto isContainer() const -> bool override { return true; } - - auto setValue( std::string const& arg ) - -> ParserResult override { - T temp; - auto result = convertInto( arg, temp ); - if ( result ) - m_ref.push_back( temp ); - return result; - } - }; - - struct BoundFlagRef : BoundFlagRefBase { - bool& m_ref; - - explicit BoundFlagRef( bool& ref ): m_ref( ref ) {} - - ParserResult setFlag( bool flag ) override; - }; - - template struct LambdaInvoker { - static_assert( - std::is_same::value, - "Lambda must return void or clara::ParserResult" ); - - template - static auto invoke( L const& lambda, ArgType const& arg ) - -> ParserResult { - return lambda( arg ); - } - }; - - template <> struct LambdaInvoker { - template - static auto invoke( L const& lambda, ArgType const& arg ) - -> ParserResult { - lambda( arg ); - return ParserResult::ok( ParseResultType::Matched ); - } - }; - - template - auto invokeLambda( L const& lambda, std::string const& arg ) - -> ParserResult { - ArgType temp{}; - auto result = convertInto( arg, temp ); - return !result ? result - : LambdaInvoker::ReturnType>::invoke( lambda, temp ); - } - - template struct BoundLambda : BoundValueRefBase { - L m_lambda; - - static_assert( - UnaryLambdaTraits::isValid, - "Supplied lambda must take exactly one argument" ); - explicit BoundLambda( L const& lambda ): m_lambda( lambda ) {} - - auto setValue( std::string const& arg ) - -> ParserResult override { - return invokeLambda::ArgType>( - m_lambda, arg ); - } - }; - - template struct BoundManyLambda : BoundLambda { - explicit BoundManyLambda( L const& lambda ): BoundLambda( lambda ) {} - bool isContainer() const override { return true; } - }; - - template struct BoundFlagLambda : BoundFlagRefBase { - L m_lambda; - - static_assert( - UnaryLambdaTraits::isValid, - "Supplied lambda must take exactly one argument" ); - static_assert( - std::is_same::ArgType, - bool>::value, - "flags must be boolean" ); - - explicit BoundFlagLambda( L const& lambda ): - m_lambda( lambda ) {} - - auto setFlag( bool flag ) -> ParserResult override { - return LambdaInvoker::ReturnType>::invoke( m_lambda, flag ); - } - }; - - enum class Optionality { Optional, Required }; - - class ParserBase { - public: - virtual ~ParserBase() = default; - virtual auto validate() const -> Result { return Result::ok(); } - virtual auto parse( std::string const& exeName, - TokenStream const& tokens ) const - -> InternalParseResult = 0; - virtual size_t cardinality() const; - - InternalParseResult parse( Args const& args ) const; - }; - - template - class ComposableParserImpl : public ParserBase { - public: - template - auto operator|( T const& other ) const -> Parser; - }; - - // Common code and state for Args and Opts - template - class ParserRefImpl : public ComposableParserImpl { - protected: - Optionality m_optionality = Optionality::Optional; - std::shared_ptr m_ref; - std::string m_hint; - std::string m_description; - - explicit ParserRefImpl( std::shared_ptr const& ref ): - m_ref( ref ) {} - - public: - template - ParserRefImpl( accept_many_t, - LambdaT const& ref, - std::string const& hint ): - m_ref( std::make_shared>( ref ) ), - m_hint( hint ) {} - - template ::value>> - ParserRefImpl( T& ref, std::string const& hint ): - m_ref( std::make_shared>( ref ) ), - m_hint( hint ) {} - - template ::value>> - ParserRefImpl( LambdaT const& ref, std::string const& hint ): - m_ref( std::make_shared>( ref ) ), - m_hint( hint ) {} - - auto operator()( std::string const& description ) -> DerivedT& { - m_description = description; - return static_cast( *this ); - } - - auto optional() -> DerivedT& { - m_optionality = Optionality::Optional; - return static_cast( *this ); - } - - auto required() -> DerivedT& { - m_optionality = Optionality::Required; - return static_cast( *this ); - } - - auto isOptional() const -> bool { - return m_optionality == Optionality::Optional; - } - - auto cardinality() const -> size_t override { - if ( m_ref->isContainer() ) - return 0; - else - return 1; - } - - std::string const& hint() const { return m_hint; } - }; - - } // namespace detail - - - // A parser for arguments - class Arg : public Detail::ParserRefImpl { - public: - using ParserRefImpl::ParserRefImpl; - using ParserBase::parse; - - Detail::InternalParseResult - parse(std::string const&, - Detail::TokenStream const& tokens) const override; - }; - - // A parser for options - class Opt : public Detail::ParserRefImpl { - protected: - std::vector m_optNames; - - public: - template - explicit Opt(LambdaT const& ref) : - ParserRefImpl( - std::make_shared>(ref)) {} - - explicit Opt(bool& ref); - - template ::value>> - Opt( LambdaT const& ref, std::string const& hint ): - ParserRefImpl( ref, hint ) {} - - template - Opt( accept_many_t, LambdaT const& ref, std::string const& hint ): - ParserRefImpl( accept_many, ref, hint ) {} - - template ::value>> - Opt( T& ref, std::string const& hint ): - ParserRefImpl( ref, hint ) {} - - auto operator[](std::string const& optName) -> Opt& { - m_optNames.push_back(optName); - return *this; - } - - std::vector getHelpColumns() const; - - bool isMatch(std::string const& optToken) const; - - using ParserBase::parse; - - Detail::InternalParseResult - parse(std::string const&, - Detail::TokenStream const& tokens) const override; - - Detail::Result validate() const override; - }; - - // Specifies the name of the executable - class ExeName : public Detail::ComposableParserImpl { - std::shared_ptr m_name; - std::shared_ptr m_ref; - - public: - ExeName(); - explicit ExeName(std::string& ref); - - template - explicit ExeName(LambdaT const& lambda) : ExeName() { - m_ref = std::make_shared>(lambda); - } - - // The exe name is not parsed out of the normal tokens, but is - // handled specially - Detail::InternalParseResult - parse(std::string const&, - Detail::TokenStream const& tokens) const override; - - std::string const& name() const { return *m_name; } - Detail::ParserResult set(std::string const& newName); - }; - - - // A Combined parser - class Parser : Detail::ParserBase { - mutable ExeName m_exeName; - std::vector m_options; - std::vector m_args; - - public: - - auto operator|=(ExeName const& exeName) -> Parser& { - m_exeName = exeName; - return *this; - } - - auto operator|=(Arg const& arg) -> Parser& { - m_args.push_back(arg); - return *this; - } - - auto operator|=(Opt const& opt) -> Parser& { - m_options.push_back(opt); - return *this; - } - - Parser& operator|=(Parser const& other); - - template - auto operator|(T const& other) const -> Parser { - return Parser(*this) |= other; - } - - std::vector getHelpColumns() const; - - void writeToStream(std::ostream& os) const; - - friend auto operator<<(std::ostream& os, Parser const& parser) - -> std::ostream& { - parser.writeToStream(os); - return os; - } - - Detail::Result validate() const override; - - using ParserBase::parse; - Detail::InternalParseResult - parse(std::string const& exeName, - Detail::TokenStream const& tokens) const override; - }; - - // Transport for raw args (copied from main args, or supplied via - // init list for testing) - class Args { - friend Detail::TokenStream; - std::string m_exeName; - std::vector m_args; - - public: - Args(int argc, char const* const* argv); - Args(std::initializer_list args); - - std::string const& exeName() const { return m_exeName; } - }; - - - // Convenience wrapper for option parser that specifies the help option - struct Help : Opt { - Help(bool& showHelpFlag); - }; - - // Result type for parser operation - using Detail::ParserResult; - - namespace Detail { - template - template - Parser - ComposableParserImpl::operator|(T const& other) const { - return Parser() | static_cast(*this) | other; - } - } - - } // namespace Clara -} // namespace Catch - -#if defined( __clang__ ) -# pragma clang diagnostic pop -#endif - -#if defined( __GNUC__ ) -# pragma GCC diagnostic pop -#endif - -#endif // CATCH_CLARA_HPP_INCLUDED - -namespace Catch { - - struct ConfigData; - - Clara::Parser makeCommandLineParser( ConfigData& config ); - -} // end namespace Catch - -#endif // CATCH_COMMANDLINE_HPP_INCLUDED - -namespace Catch { - - class Session : Detail::NonCopyable { - public: - - Session(); - ~Session(); - - void showHelp() const; - void libIdentify(); - - int applyCommandLine( int argc, char const * const * argv ); - #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) - int applyCommandLine( int argc, wchar_t const * const * argv ); - #endif - - void useConfigData( ConfigData const& configData ); - - template - int run(int argc, CharT const * const argv[]) { - if (m_startupExceptions) - return 1; - int returnCode = applyCommandLine(argc, argv); - if (returnCode == 0) - returnCode = run(); - return returnCode; - } - - int run(); - - Clara::Parser const& cli() const; - void cli( Clara::Parser const& newParser ); - ConfigData& configData(); - Config& config(); - private: - int runInternal(); - - Clara::Parser m_cli; - ConfigData m_configData; - Detail::unique_ptr m_config; - bool m_startupExceptions = false; - }; - -} // end namespace Catch - -#endif // CATCH_SESSION_HPP_INCLUDED - - -#ifndef CATCH_TAG_ALIAS_HPP_INCLUDED -#define CATCH_TAG_ALIAS_HPP_INCLUDED - - -#include - -namespace Catch { - - struct TagAlias { - TagAlias(std::string const& _tag, SourceLineInfo _lineInfo): - tag(_tag), - lineInfo(_lineInfo) - {} - - std::string tag; - SourceLineInfo lineInfo; - }; - -} // end namespace Catch - -#endif // CATCH_TAG_ALIAS_HPP_INCLUDED - - -#ifndef CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED -#define CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED - - -namespace Catch { - - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; - -} // end namespace Catch - -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION - -#endif // CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED - - -#ifndef CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED -#define CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED - -// We need this suppression to leak, because it took until GCC 10 -// for the front end to handle local suppression via _Pragma properly -// inside templates (so `TEMPLATE_TEST_CASE` and co). -// **THIS IS DIFFERENT FOR STANDARD TESTS, WHERE GCC 9 IS SUFFICIENT** -#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ < 10 -#pragma GCC diagnostic ignored "-Wparentheses" -#endif - - - - -#ifndef CATCH_TEST_MACROS_HPP_INCLUDED -#define CATCH_TEST_MACROS_HPP_INCLUDED - - - -#ifndef CATCH_TEST_MACRO_IMPL_HPP_INCLUDED -#define CATCH_TEST_MACRO_IMPL_HPP_INCLUDED - - - -#ifndef CATCH_ASSERTION_HANDLER_HPP_INCLUDED -#define CATCH_ASSERTION_HANDLER_HPP_INCLUDED - - - -#ifndef CATCH_DECOMPOSER_HPP_INCLUDED -#define CATCH_DECOMPOSER_HPP_INCLUDED - - - -#ifndef CATCH_COMPARE_TRAITS_HPP_INCLUDED -#define CATCH_COMPARE_TRAITS_HPP_INCLUDED - - -#include - -namespace Catch { - namespace Detail { - -#if defined( __GNUC__ ) && !defined( __clang__ ) -# pragma GCC diagnostic push - // GCC likes to complain about comparing bool with 0, in the decltype() - // that defines the comparable traits below. -# pragma GCC diagnostic ignored "-Wbool-compare" - // "ordered comparison of pointer with integer zero" same as above, - // but it does not have a separate warning flag to suppress -# pragma GCC diagnostic ignored "-Wextra" - // Did you know that comparing floats with `0` directly - // is super-duper dangerous in unevaluated context? -# pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - -#if defined( __clang__ ) -# pragma clang diagnostic push - // Did you know that comparing floats with `0` directly - // is super-duper dangerous in unevaluated context? -# pragma clang diagnostic ignored "-Wfloat-equal" -#endif - -#define CATCH_DEFINE_COMPARABLE_TRAIT( id, op ) \ - template \ - struct is_##id##_comparable : std::false_type {}; \ - template \ - struct is_##id##_comparable< \ - T, \ - U, \ - void_t() op std::declval() )>> \ - : std::true_type {}; \ - template \ - struct is_##id##_0_comparable : std::false_type {}; \ - template \ - struct is_##id##_0_comparable() op 0 )>> \ - : std::true_type {}; - - // We need all 6 pre-spaceship comparison ops: <, <=, >, >=, ==, != - CATCH_DEFINE_COMPARABLE_TRAIT( lt, < ) - CATCH_DEFINE_COMPARABLE_TRAIT( le, <= ) - CATCH_DEFINE_COMPARABLE_TRAIT( gt, > ) - CATCH_DEFINE_COMPARABLE_TRAIT( ge, >= ) - CATCH_DEFINE_COMPARABLE_TRAIT( eq, == ) - CATCH_DEFINE_COMPARABLE_TRAIT( ne, != ) - -#undef CATCH_DEFINE_COMPARABLE_TRAIT - -#if defined( __GNUC__ ) && !defined( __clang__ ) -# pragma GCC diagnostic pop -#endif -#if defined( __clang__ ) -# pragma clang diagnostic pop -#endif - - - } // namespace Detail -} // namespace Catch - -#endif // CATCH_COMPARE_TRAITS_HPP_INCLUDED - - -#ifndef CATCH_LOGICAL_TRAITS_HPP_INCLUDED -#define CATCH_LOGICAL_TRAITS_HPP_INCLUDED - -#include - -namespace Catch { -namespace Detail { - -#if defined( __cpp_lib_logical_traits ) && __cpp_lib_logical_traits >= 201510 - - using std::conjunction; - using std::disjunction; - using std::negation; - -#else - - template struct conjunction : std::true_type {}; - template struct conjunction : B1 {}; - template - struct conjunction - : std::conditional_t, B1> {}; - - template struct disjunction : std::false_type {}; - template struct disjunction : B1 {}; - template - struct disjunction - : std::conditional_t> {}; - - template - struct negation : std::integral_constant {}; - -#endif - -} // namespace Detail -} // namespace Catch - -#endif // CATCH_LOGICAL_TRAITS_HPP_INCLUDED - -#include -#include - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4389) // '==' : signed/unsigned mismatch -#pragma warning(disable:4018) // more "signed/unsigned mismatch" -#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) -#pragma warning(disable:4180) // qualifier applied to function type has no meaning -#pragma warning(disable:4800) // Forcing result to true or false -#endif - -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wsign-compare" -#elif defined __GNUC__ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wsign-compare" -#endif - -namespace Catch { - - template - struct always_false : std::false_type {}; - - class ITransientExpression { - bool m_isBinaryExpression; - bool m_result; - - public: - auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } - auto getResult() const -> bool { return m_result; } - virtual void streamReconstructedExpression( std::ostream &os ) const = 0; - - ITransientExpression( bool isBinaryExpression, bool result ) - : m_isBinaryExpression( isBinaryExpression ), - m_result( result ) - {} - - ITransientExpression() = default; - ITransientExpression(ITransientExpression const&) = default; - ITransientExpression& operator=(ITransientExpression const&) = default; - - // We don't actually need a virtual destructor, but many static analysers - // complain if it's not here :-( - virtual ~ITransientExpression(); // = default; - - friend std::ostream& operator<<(std::ostream& out, ITransientExpression const& expr) { - expr.streamReconstructedExpression(out); - return out; - } - }; - - void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); - - template - class BinaryExpr : public ITransientExpression { - LhsT m_lhs; - StringRef m_op; - RhsT m_rhs; - - void streamReconstructedExpression( std::ostream &os ) const override { - formatReconstructedExpression - ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); - } - - public: - BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) - : ITransientExpression{ true, comparisonResult }, - m_lhs( lhs ), - m_op( op ), - m_rhs( rhs ) - {} - - template - auto operator && ( T ) const -> BinaryExpr const { - static_assert(always_false::value, - "chained comparisons are not supported inside assertions, " - "wrap the expression inside parentheses, or decompose it"); - } - - template - auto operator || ( T ) const -> BinaryExpr const { - static_assert(always_false::value, - "chained comparisons are not supported inside assertions, " - "wrap the expression inside parentheses, or decompose it"); - } - - template - auto operator == ( T ) const -> BinaryExpr const { - static_assert(always_false::value, - "chained comparisons are not supported inside assertions, " - "wrap the expression inside parentheses, or decompose it"); - } - - template - auto operator != ( T ) const -> BinaryExpr const { - static_assert(always_false::value, - "chained comparisons are not supported inside assertions, " - "wrap the expression inside parentheses, or decompose it"); - } - - template - auto operator > ( T ) const -> BinaryExpr const { - static_assert(always_false::value, - "chained comparisons are not supported inside assertions, " - "wrap the expression inside parentheses, or decompose it"); - } - - template - auto operator < ( T ) const -> BinaryExpr const { - static_assert(always_false::value, - "chained comparisons are not supported inside assertions, " - "wrap the expression inside parentheses, or decompose it"); - } - - template - auto operator >= ( T ) const -> BinaryExpr const { - static_assert(always_false::value, - "chained comparisons are not supported inside assertions, " - "wrap the expression inside parentheses, or decompose it"); - } - - template - auto operator <= ( T ) const -> BinaryExpr const { - static_assert(always_false::value, - "chained comparisons are not supported inside assertions, " - "wrap the expression inside parentheses, or decompose it"); - } - }; - - template - class UnaryExpr : public ITransientExpression { - LhsT m_lhs; - - void streamReconstructedExpression( std::ostream &os ) const override { - os << Catch::Detail::stringify( m_lhs ); - } - - public: - explicit UnaryExpr( LhsT lhs ) - : ITransientExpression{ false, static_cast(lhs) }, - m_lhs( lhs ) - {} - }; - - - template - class ExprLhs { - LhsT m_lhs; - public: - explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} - -#define CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( id, op ) \ - template \ - friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \ - ->std::enable_if_t< \ - Detail::conjunction, \ - Detail::negation>>>::value, \ - BinaryExpr> { \ - return { \ - static_cast( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ - } \ - template \ - friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ - ->std::enable_if_t< \ - Detail::conjunction, \ - std::is_arithmetic>::value, \ - BinaryExpr> { \ - return { \ - static_cast( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ - } \ - template \ - friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ - ->std::enable_if_t< \ - Detail::conjunction< \ - Detail::negation>, \ - Detail::is_eq_0_comparable, \ - /* We allow long because we want `ptr op NULL` to be accepted */ \ - Detail::disjunction, \ - std::is_same>>::value, \ - BinaryExpr> { \ - if ( rhs != 0 ) { throw_test_failure_exception(); } \ - return { \ - static_cast( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \ - } \ - template \ - friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ - ->std::enable_if_t< \ - Detail::conjunction< \ - Detail::negation>, \ - Detail::is_eq_0_comparable, \ - /* We allow long because we want `ptr op NULL` to be accepted */ \ - Detail::disjunction, \ - std::is_same>>::value, \ - BinaryExpr> { \ - if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \ - return { static_cast( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ - } - - CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( eq, == ) - CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( ne, != ) - - #undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR - -#define CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( id, op ) \ - template \ - friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \ - ->std::enable_if_t< \ - Detail::conjunction, \ - Detail::negation>>>::value, \ - BinaryExpr> { \ - return { \ - static_cast( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ - } \ - template \ - friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ - ->std::enable_if_t< \ - Detail::conjunction, \ - std::is_arithmetic>::value, \ - BinaryExpr> { \ - return { \ - static_cast( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ - } \ - template \ - friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ - ->std::enable_if_t< \ - Detail::conjunction< \ - Detail::negation>, \ - Detail::is_##id##_0_comparable, \ - std::is_same>::value, \ - BinaryExpr> { \ - if ( rhs != 0 ) { throw_test_failure_exception(); } \ - return { \ - static_cast( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \ - } \ - template \ - friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ - ->std::enable_if_t< \ - Detail::conjunction< \ - Detail::negation>, \ - Detail::is_##id##_0_comparable, \ - std::is_same>::value, \ - BinaryExpr> { \ - if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \ - return { static_cast( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ - } - - CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( lt, < ) - CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( le, <= ) - CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( gt, > ) - CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( ge, >= ) - - #undef CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR - - -#define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR( op ) \ - template \ - friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \ - ->std::enable_if_t< \ - !std::is_arithmetic>::value, \ - BinaryExpr> { \ - return { \ - static_cast( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ - } \ - template \ - friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \ - ->std::enable_if_t::value, \ - BinaryExpr> { \ - return { \ - static_cast( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \ - } - - CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(|) - CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(&) - CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(^) - - #undef CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR - - template - friend auto operator && ( ExprLhs &&, RhsT && ) -> BinaryExpr { - static_assert(always_false::value, - "operator&& is not supported inside assertions, " - "wrap the expression inside parentheses, or decompose it"); - } - - template - friend auto operator || ( ExprLhs &&, RhsT && ) -> BinaryExpr { - static_assert(always_false::value, - "operator|| is not supported inside assertions, " - "wrap the expression inside parentheses, or decompose it"); - } - - auto makeUnaryExpr() const -> UnaryExpr { - return UnaryExpr{ m_lhs }; - } - }; - - struct Decomposer { - template>::value, int> = 0> - friend auto operator <= ( Decomposer &&, T && lhs ) -> ExprLhs { - return ExprLhs{ lhs }; - } - - template::value, int> = 0> - friend auto operator <= ( Decomposer &&, T value ) -> ExprLhs { - return ExprLhs{ value }; - } - }; - -} // end namespace Catch - -#ifdef _MSC_VER -#pragma warning(pop) -#endif -#ifdef __clang__ -# pragma clang diagnostic pop -#elif defined __GNUC__ -# pragma GCC diagnostic pop -#endif - -#endif // CATCH_DECOMPOSER_HPP_INCLUDED - -#include - -namespace Catch { - - class IResultCapture; - - struct AssertionReaction { - bool shouldDebugBreak = false; - bool shouldThrow = false; - bool shouldSkip = false; - }; - - class AssertionHandler { - AssertionInfo m_assertionInfo; - AssertionReaction m_reaction; - bool m_completed = false; - IResultCapture& m_resultCapture; - - public: - AssertionHandler - ( StringRef macroName, - SourceLineInfo const& lineInfo, - StringRef capturedExpression, - ResultDisposition::Flags resultDisposition ); - ~AssertionHandler() { - if ( !m_completed ) { - m_resultCapture.handleIncomplete( m_assertionInfo ); - } - } - - - template - void handleExpr( ExprLhs const& expr ) { - handleExpr( expr.makeUnaryExpr() ); - } - void handleExpr( ITransientExpression const& expr ); - - void handleMessage(ResultWas::OfType resultType, StringRef message); - - void handleExceptionThrownAsExpected(); - void handleUnexpectedExceptionNotThrown(); - void handleExceptionNotThrownAsExpected(); - void handleThrowingCallSkipped(); - void handleUnexpectedInflightException(); - - void complete(); - void setCompleted(); - - // query - auto allowThrows() const -> bool; - }; - - void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str ); - -} // namespace Catch - -#endif // CATCH_ASSERTION_HANDLER_HPP_INCLUDED - -// We need this suppression to leak, because it took until GCC 10 -// for the front end to handle local suppression via _Pragma properly -#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ <= 9 - #pragma GCC diagnostic ignored "-Wparentheses" -#endif - -#if !defined(CATCH_CONFIG_DISABLE) - -#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) - #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr -#else - #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr -#endif - -#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - -/////////////////////////////////////////////////////////////////////////////// -// Another way to speed-up compilation is to omit local try-catch for REQUIRE* -// macros. -#define INTERNAL_CATCH_TRY -#define INTERNAL_CATCH_CATCH( capturer ) - -#else // CATCH_CONFIG_FAST_COMPILE - -#define INTERNAL_CATCH_TRY try -#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } - -#endif - -#define INTERNAL_CATCH_REACT( handler ) handler.complete(); - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ - do { /* NOLINT(bugprone-infinite-loop) */ \ - /* The expression should not be evaluated, but warnings should hopefully be checked */ \ - CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ - INTERNAL_CATCH_TRY { \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ - } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( (void)0, (false) && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look - // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ - INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ - if( Catch::getResultCapture().lastAssertionPassed() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ - INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ - if( !Catch::getResultCapture().lastAssertionPassed() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ - try { \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ - static_cast(__VA_ARGS__); \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ - catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ - } \ - catch( ... ) { \ - catchAssertionHandler.handleUnexpectedInflightException(); \ - } \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ - static_cast(__VA_ARGS__); \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ - catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ - } \ - catch( ... ) { \ - catchAssertionHandler.handleExceptionThrownAsExpected(); \ - } \ - else \ - catchAssertionHandler.handleThrowingCallSkipped(); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ - static_cast(expr); \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ - catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ - } \ - catch( exceptionType const& ) { \ - catchAssertionHandler.handleExceptionThrownAsExpected(); \ - } \ - catch( ... ) { \ - catchAssertionHandler.handleUnexpectedInflightException(); \ - } \ - else \ - catchAssertionHandler.handleThrowingCallSkipped(); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - - - -/////////////////////////////////////////////////////////////////////////////// -// Although this is matcher-based, it can be used with just a string -#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \ - static_cast(__VA_ARGS__); \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ - catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ - } \ - catch( ... ) { \ - Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher ); \ - } \ - else \ - catchAssertionHandler.handleThrowingCallSkipped(); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -#endif // CATCH_CONFIG_DISABLE - -#endif // CATCH_TEST_MACRO_IMPL_HPP_INCLUDED - - -#ifndef CATCH_SECTION_HPP_INCLUDED -#define CATCH_SECTION_HPP_INCLUDED - - - -#ifndef CATCH_TIMER_HPP_INCLUDED -#define CATCH_TIMER_HPP_INCLUDED - -#include - -namespace Catch { - - class Timer { - uint64_t m_nanoseconds = 0; - public: - void start(); - auto getElapsedNanoseconds() const -> uint64_t; - auto getElapsedMicroseconds() const -> uint64_t; - auto getElapsedMilliseconds() const -> unsigned int; - auto getElapsedSeconds() const -> double; - }; - -} // namespace Catch - -#endif // CATCH_TIMER_HPP_INCLUDED - -namespace Catch { - - class Section : Detail::NonCopyable { - public: - Section( SectionInfo&& info ); - Section( SourceLineInfo const& _lineInfo, - StringRef _name, - const char* const = nullptr ); - ~Section(); - - // This indicates whether the section should be executed or not - explicit operator bool() const; - - private: - SectionInfo m_info; - - Counts m_assertions; - bool m_sectionIncluded; - Timer m_timer; - }; - -} // end namespace Catch - -#define INTERNAL_CATCH_SECTION( ... ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION - -#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION - -#endif // CATCH_SECTION_HPP_INCLUDED - - -#ifndef CATCH_TEST_REGISTRY_HPP_INCLUDED -#define CATCH_TEST_REGISTRY_HPP_INCLUDED - - - -#ifndef CATCH_INTERFACES_TESTCASE_HPP_INCLUDED -#define CATCH_INTERFACES_TESTCASE_HPP_INCLUDED - -#include - -namespace Catch { - - class TestSpec; - struct TestCaseInfo; - - class ITestInvoker { - public: - virtual void invoke () const = 0; - virtual ~ITestInvoker(); // = default - }; - - class TestCaseHandle; - class IConfig; - - class ITestCaseRegistry { - public: - virtual ~ITestCaseRegistry(); // = default - // TODO: this exists only for adding filenames to test cases -- let's expose this in a saner way later - virtual std::vector const& getAllInfos() const = 0; - virtual std::vector const& getAllTests() const = 0; - virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; - }; - - bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ); - bool matchTest( TestCaseHandle const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - -} - -#endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED - - -#ifndef CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED -#define CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED - -#define INTERNAL_CATCH_EXPAND1( param ) INTERNAL_CATCH_EXPAND2( param ) -#define INTERNAL_CATCH_EXPAND2( ... ) INTERNAL_CATCH_NO##__VA_ARGS__ -#define INTERNAL_CATCH_DEF( ... ) INTERNAL_CATCH_DEF __VA_ARGS__ -#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF - -#define INTERNAL_CATCH_REMOVE_PARENS( ... ) \ - INTERNAL_CATCH_EXPAND1( INTERNAL_CATCH_DEF __VA_ARGS__ ) - -#endif // CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED - -// GCC 5 and older do not properly handle disabling unused-variable warning -// with a _Pragma. This means that we have to leak the suppression to the -// user code as well :-( -#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5 -#pragma GCC diagnostic ignored "-Wunused-variable" -#endif - - - -namespace Catch { - -template -class TestInvokerAsMethod : public ITestInvoker { - void (C::*m_testAsMethod)(); -public: - TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} - - void invoke() const override { - C obj; - (obj.*m_testAsMethod)(); - } -}; - -Detail::unique_ptr makeTestInvoker( void(*testAsFunction)() ); - -template -Detail::unique_ptr makeTestInvoker( void (C::*testAsMethod)() ) { - return Detail::make_unique>( testAsMethod ); -} - -struct NameAndTags { - constexpr NameAndTags( StringRef name_ = StringRef(), - StringRef tags_ = StringRef() ) noexcept: - name( name_ ), tags( tags_ ) {} - StringRef name; - StringRef tags; -}; - -struct AutoReg : Detail::NonCopyable { - AutoReg( Detail::unique_ptr invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept; -}; - -} // end namespace Catch - -#if defined(CATCH_CONFIG_DISABLE) - #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ - static inline void TestName() - #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ - namespace{ \ - struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ - void test(); \ - }; \ - } \ - void TestName::test() -#endif - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ - static void TestName(); \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - namespace{ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ - static void TestName() - #define INTERNAL_CATCH_TESTCASE( ... ) \ - INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__ ) - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - namespace { \ - const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \ - Catch::makeTestInvoker( &QualifiedMethod ), \ - CATCH_INTERNAL_LINEINFO, \ - "&" #QualifiedMethod##_catch_sr, \ - Catch::NameAndTags{ __VA_ARGS__ } ); \ - } /* NOLINT */ \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - namespace{ \ - struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ - void test(); \ - }; \ - const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \ - Catch::makeTestInvoker( &TestName::test ), \ - CATCH_INTERNAL_LINEINFO, \ - #ClassName##_catch_sr, \ - Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ - } \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ - void TestName::test() - #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ - INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ ) - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ - do { \ - CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ - CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ - } while(false) - - -#endif // CATCH_TEST_REGISTRY_HPP_INCLUDED - - -// All of our user-facing macros support configuration toggle, that -// forces them to be defined prefixed with CATCH_. We also like to -// support another toggle that can minimize (disable) their implementation. -// Given this, we have 4 different configuration options below - -#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) - - #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) - #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) - - #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) - #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) - #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) - - #define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - #define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) - #define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) - #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) - #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) - - #define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) - #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - - #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) - #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) - #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) - #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) - #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) - #define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) - #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) - #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - #define CATCH_SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ ) - - - #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) - #define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ ) - #define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ ) - #define CATCH_STATIC_CHECK( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ ) - #define CATCH_STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ ) - #else - #define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ ) - #define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ ) - #define CATCH_STATIC_CHECK( ... ) CATCH_CHECK( __VA_ARGS__ ) - #define CATCH_STATIC_CHECK_FALSE( ... ) CATCH_CHECK_FALSE( __VA_ARGS__ ) - #endif - - - // "BDD-style" convenience wrappers - #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) - #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) - #define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) - #define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) - #define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) - #define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) - #define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) - #define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) - -#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, implemented | vv prefixed, disabled - - #define CATCH_REQUIRE( ... ) (void)(0) - #define CATCH_REQUIRE_FALSE( ... ) (void)(0) - - #define CATCH_REQUIRE_THROWS( ... ) (void)(0) - #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) - #define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) - - #define CATCH_CHECK( ... ) (void)(0) - #define CATCH_CHECK_FALSE( ... ) (void)(0) - #define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) - #define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) - #define CATCH_CHECK_NOFAIL( ... ) (void)(0) - - #define CATCH_CHECK_THROWS( ... ) (void)(0) - #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) - #define CATCH_CHECK_NOTHROW( ... ) (void)(0) - - #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ )) - #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ )) - #define CATCH_METHOD_AS_TEST_CASE( method, ... ) - #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) - #define CATCH_SECTION( ... ) - #define CATCH_DYNAMIC_SECTION( ... ) - #define CATCH_FAIL( ... ) (void)(0) - #define CATCH_FAIL_CHECK( ... ) (void)(0) - #define CATCH_SUCCEED( ... ) (void)(0) - #define CATCH_SKIP( ... ) (void)(0) - - #define CATCH_STATIC_REQUIRE( ... ) (void)(0) - #define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0) - #define CATCH_STATIC_CHECK( ... ) (void)(0) - #define CATCH_STATIC_CHECK_FALSE( ... ) (void)(0) - - // "BDD-style" convenience wrappers - #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ )) - #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className ) - #define CATCH_GIVEN( desc ) - #define CATCH_AND_GIVEN( desc ) - #define CATCH_WHEN( desc ) - #define CATCH_AND_WHEN( desc ) - #define CATCH_THEN( desc ) - #define CATCH_AND_THEN( desc ) - -#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, disabled | vv unprefixed, implemented - - #define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) - #define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) - - #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) - #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) - #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) - - #define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - #define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) - #define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) - #define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) - #define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) - - #define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) - #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - - #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) - #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) - #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) - #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) - #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) - #define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) - #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) - #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - #define SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ ) - - - #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) - #define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ ) - #define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" ) - #define STATIC_CHECK( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ ) - #define STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" ) - #else - #define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ ) - #define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ ) - #define STATIC_CHECK( ... ) CHECK( __VA_ARGS__ ) - #define STATIC_CHECK_FALSE( ... ) CHECK_FALSE( __VA_ARGS__ ) - #endif - - // "BDD-style" convenience wrappers - #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) - #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) - #define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) - #define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) - #define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) - #define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) - #define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) - #define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) - -#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ unprefixed, implemented | vv unprefixed, disabled - - #define REQUIRE( ... ) (void)(0) - #define REQUIRE_FALSE( ... ) (void)(0) - - #define REQUIRE_THROWS( ... ) (void)(0) - #define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) - #define REQUIRE_NOTHROW( ... ) (void)(0) - - #define CHECK( ... ) (void)(0) - #define CHECK_FALSE( ... ) (void)(0) - #define CHECKED_IF( ... ) if (__VA_ARGS__) - #define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) - #define CHECK_NOFAIL( ... ) (void)(0) - - #define CHECK_THROWS( ... ) (void)(0) - #define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) - #define CHECK_NOTHROW( ... ) (void)(0) - - #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__) - #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ )) - #define METHOD_AS_TEST_CASE( method, ... ) - #define REGISTER_TEST_CASE( Function, ... ) (void)(0) - #define SECTION( ... ) - #define DYNAMIC_SECTION( ... ) - #define FAIL( ... ) (void)(0) - #define FAIL_CHECK( ... ) (void)(0) - #define SUCCEED( ... ) (void)(0) - #define SKIP( ... ) (void)(0) - - #define STATIC_REQUIRE( ... ) (void)(0) - #define STATIC_REQUIRE_FALSE( ... ) (void)(0) - #define STATIC_CHECK( ... ) (void)(0) - #define STATIC_CHECK_FALSE( ... ) (void)(0) - - // "BDD-style" convenience wrappers - #define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ) ) - #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className ) - - #define GIVEN( desc ) - #define AND_GIVEN( desc ) - #define WHEN( desc ) - #define AND_WHEN( desc ) - #define THEN( desc ) - #define AND_THEN( desc ) - -#endif // ^^ unprefixed, disabled - -// end of user facing macros - -#endif // CATCH_TEST_MACROS_HPP_INCLUDED - - -#ifndef CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED -#define CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED - - - -#ifndef CATCH_PREPROCESSOR_HPP_INCLUDED -#define CATCH_PREPROCESSOR_HPP_INCLUDED - - -#if defined(__GNUC__) -// We need to silence "empty __VA_ARGS__ warning", and using just _Pragma does not work -#pragma GCC system_header -#endif - - -#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ -#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) -#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) - -#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ -// MSVC needs more evaluations -#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) -#else -#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) -#endif - -#define CATCH_REC_END(...) -#define CATCH_REC_OUT - -#define CATCH_EMPTY() -#define CATCH_DEFER(id) id CATCH_EMPTY() - -#define CATCH_REC_GET_END2() 0, CATCH_REC_END -#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 -#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 -#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT -#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) -#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) - -#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) - -#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) -#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) - -// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, -// and passes userdata as the first parameter to each invocation, -// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) -#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) - -#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) -#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ -#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) -#else -// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF -#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) -#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ -#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) -#endif - -#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ -#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) - -#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR -#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) -#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) -#else -#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) -#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) -#endif - -#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ - CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) - -#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) -#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) -#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) -#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) -#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) -#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) -#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) -#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) -#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) -#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) -#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) - -#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N - -#define INTERNAL_CATCH_TYPE_GEN\ - template struct TypeList {};\ - template\ - constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ - template class...> struct TemplateTypeList{};\ - template class...Cs>\ - constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ - template\ - struct append;\ - template\ - struct rewrap;\ - template class, typename...>\ - struct create;\ - template class, typename>\ - struct convert;\ - \ - template \ - struct append { using type = T; };\ - template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ - struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ - template< template class L1, typename...E1, typename...Rest>\ - struct append, TypeList, Rest...> { using type = L1; };\ - \ - template< template class Container, template class List, typename...elems>\ - struct rewrap, List> { using type = TypeList>; };\ - template< template class Container, template class List, class...Elems, typename...Elements>\ - struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ - \ - template