Author: Mason Wright
Email:
[email protected]
Date: Tue, 24 Jun 2025 20:44:14 -0600
tests/catch_amalgamated.cpp
e50ea9e1356a74af18fdd171337ef9dc931e1f4e
Added tests to parser
Clone
A
.gitignore
M
Makefile
-
include/grim.h
-
include/parser.h
M
index.html
-
main.cc
-
src/adapter.cc
-
src/events.cc
-
src/grim.cc
-
src/parser.cc
-
style.css
A
tests/catch_amalgamated.cpp
A
tests/catch_amalgamated.hpp
A
tests/main.cc
Commits
b966b2a517365074e5c381dbdea05b3221dc0198
e840f1eeb0ae26af69e1ae146ea9938e28e9f1af
e4e05418a640eaed08cd1ec7cd8644eb1dbcca50
4e01ba8ad2c3361fa4be3d896288020948b58b5e
aae562ac1350480e4889aabb35899f776c5b59e9
6c3ae0e31eb0893f20e3872117f92cc6b9a942af
350e7d88bb2feb9db00c6e032cc6623f215b7adf
95e6c70d23e99ffcf70e5bbe12503496e5d8f232
e188783659b9bc3b9993a647e93ed110e7f41db6
5e4c38ff3c212cdd9881427ef3f8c2706539a190
e50ea9e1356a74af18fdd171337ef9dc931e1f4e
8f2e83556d12aaebe8e8597ea6923804b0eb7a43
1627c585128af263181053ab2cf1a4cdcd14ee21
def3513f75b325464ad88a33c741c4ca80572b77
a21501590980a905fa9b902897d700a42a08b7f0
56074a6bfe4498d092f3a227297c8c20e2bb962c
d9cf1485b7ae0614130494f0e73237921323b9a1
80f04b134ae32ad8a9d526007b33dd02f6600f05
23d6c65f9368d3c622a55a3068a6b2f1efa0c8d4
09c195df02536b6a796bd648fce9669397b96109
f2b5c8202fbc904e2ed78260e3fdbd55164799d2
4bfba076120f389994fc46a98e8b7a2622314400
e36ac5417e10ee9b9f94f340e1ccf28afc5705ea
d00dc89a86dd7e2fcfd4618bc3a1c8cfba9e3c3d
d9eef16adaf292f3748db5fb5aa98463de10d712
18ff2ec1bfc1cf9fcd17c1acb05c3b41f8f0ed83
9e7fd2980d723437ea621b78d395fa72ca3f4922
Diff
diff --git a/tests/catch_amalgamated.cpp b/tests/catch_amalgamated.cpp deleted file mode 100644 index 6aa6788..0000000 --- a/tests/catch_amalgamated.cpp +++ /dev/null @@ -1,11520 +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.5.4 -// Generated: 2024-04-10 12:03:46.281848 -// ---------------------------------------------------------- -// 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 - - -// Adapted from donated nonius code. - - -#include
- -namespace Catch { - namespace Benchmark { - namespace Detail { - SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last) { - if (!cfg.benchmarkNoAnalysis()) { - std::vector
samples; - samples.reserve(static_cast
(last - first)); - for (auto current = first; current != last; ++current) { - samples.push_back( current->count() ); - } - - auto analysis = Catch::Benchmark::Detail::analyse_samples( - cfg.benchmarkConfidenceInterval(), - cfg.benchmarkResamples(), - samples.data(), - samples.data() + samples.size() ); - auto outliers = Catch::Benchmark::Detail::classify_outliers( - samples.data(), samples.data() + samples.size() ); - - auto wrap_estimate = [](Estimate
e) { - return Estimate
{ - FDuration(e.point), - FDuration(e.lower_bound), - FDuration(e.upper_bound), - e.confidence_interval, - }; - }; - std::vector
samples2; - samples2.reserve(samples.size()); - for (auto s : samples) { - samples2.push_back( FDuration( s ) ); - } - - 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)); - - FDuration mean = FDuration(0); - int i = 0; - for (auto it = first; it < last; ++it, ++i) { - samples.push_back(*it); - mean += *it; - } - mean /= i; - - return SampleAnalysis{ - CATCH_MOVE(samples), - Estimate
{ mean, mean, mean, 0.0 }, - Estimate
{ FDuration( 0 ), - FDuration( 0 ), - FDuration( 0 ), - 0.0 }, - OutlierClassification{}, - 0.0 - }; - } - } - } // 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
-#include
-#include
- - -#if defined(CATCH_CONFIG_USE_ASYNC) -#include
-#endif - -namespace Catch { - namespace Benchmark { - namespace Detail { - namespace { - - template
- static sample - resample( URng& rng, - unsigned int resamples, - double const* first, - double const* last, - Estimator& estimator ) { - auto n = static_cast
( last - first ); - Catch::uniform_integer_distribution
dist( 0, n - 1 ); - - sample out; - out.reserve( resamples ); - std::vector
resampled; - resampled.reserve( n ); - for ( size_t i = 0; i < resamples; ++i ) { - resampled.clear(); - for ( size_t s = 0; s < n; ++s ) { - resampled.push_back( first[dist( rng )] ); - } - const auto estimate = - estimator( resampled.data(), resampled.data() + resampled.size() ); - out.push_back( estimate ); - } - std::sort( out.begin(), out.end() ); - return out; - } - - static 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; - } - - static 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; - } - - static double - standard_deviation( double const* first, double const* 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 ); - } - - static sample jackknife( double ( *estimator )( double const*, - double const* ), - double* first, - double* last ) { - const auto second = first + 1; - sample results; - results.reserve( static_cast
( last - first ) ); - - for ( auto it = first; it != last; ++it ) { - std::iter_swap( it, first ); - results.push_back( estimator( second, last ) ); - } - - return results; - } - - - } // namespace - } // namespace Detail - } // namespace Benchmark -} // namespace Catch - -namespace Catch { - namespace Benchmark { - namespace Detail { - - double weighted_average_quantile( int k, - int q, - double* first, - double* 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 ( Catch::Detail::directCompare( g, 0 ) ) { - return xj; - } - - auto xj1 = *std::min_element(first + (j + 1), last); - return xj + g * (xj1 - xj); - } - - OutlierClassification - classify_outliers( double const* first, double const* last ) { - std::vector
copy( first, last ); - - auto q1 = weighted_average_quantile( 1, 4, copy.data(), copy.data() + copy.size() ); - auto q3 = weighted_average_quantile( 3, 4, copy.data(), copy.data() + copy.size() ); - 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 ) { - const double 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; - } - - double mean( double const* first, double const* last ) { - auto count = last - first; - double sum = 0.; - while (first != last) { - sum += *first; - ++first; - } - return sum / static_cast
(count); - } - - double normal_cdf( double x ) { - return std::erfc( -x / std::sqrt( 2.0 ) ) / 2.0; - } - - 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; - } - - Estimate
- bootstrap( double confidence_level, - double* first, - double* last, - sample const& resample, - double ( *estimator )( double const*, double const* ) ) { - 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.data(), jack.data() + jack.size() ); - double sum_squares = 0, sum_cubes = 0; - for ( double x : jack ) { - auto difference = jack_mean - x; - auto square = difference * difference; - auto cube = square * difference; - sum_squares += square; - sum_cubes += cube; - } - - 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 ( Catch::Detail::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 }; - } - - bootstrap_analysis analyse_samples(double confidence_level, - unsigned int n_resamples, - double* first, - double* last) { - auto mean = &Detail::mean; - auto stddev = &standard_deviation; - -#if defined(CATCH_CONFIG_USE_ASYNC) - auto Estimate = [=](double(*f)(double const*, double const*)) { - std::random_device rd; - auto seed = rd(); - return std::async(std::launch::async, [=] { - SimplePcg32 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)(double const* , double const*)) { - std::random_device rd; - auto seed = rd(); - SimplePcg32 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 - - auto n = static_cast
(last - first); // seriously, one can't use integral types without hell in C++ - 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( static_cast
(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 specific one - if ( m_data.reporterSpecifications.empty() ) { -#if defined( CATCH_CONFIG_DEFAULT_REPORTER ) - const auto default_spec = CATCH_CONFIG_DEFAULT_REPORTER; -#else - const auto default_spec = "console"; -#endif - auto parsed = parseReporterSpec(default_spec); - CATCH_ENFORCE( parsed, - "Cannot parse the provided default reporter spec: '" - << default_spec << '\'' ); - m_data.reporterSpecifications.push_back( std::move( *parsed ) ); - } - - 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 ): - m_resultCapture( getResultCapture() ) { - 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; - } - default:; // noop - } - } - 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 - - - - -#include
- -namespace Catch { - - namespace { - - class RegistryHub : public IRegistryHub, - public IMutableRegistryHub, - private Detail::NonCopyable { - - public: // IRegistryHub - RegistryHub() = default; - ReporterRegistry 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
-#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; - } - // In theory we could have filename without any extension in it - if ( lastDot == 0 ) { return StringRef(); } - - --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 == '[') { - CATCH_ENFORCE( - !inTag, - "Found '[' inside a tag while registering test case '" - << _nameAndTags.name << "' at " << _lineInfo ); - - inTag = true; - tagStart = idx; - } - if (c == ']') { - CATCH_ENFORCE( - inTag, - "Found unmatched ']' while registering test case '" - << _nameAndTags.name << "' at " << _lineInfo ); - - 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(), - "Found an empty tag while registering test case '" - << _nameAndTags.name << "' at " - << _lineInfo ); - - 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); - } - } - CATCH_ENFORCE( !inTag, - "Found an unclosed tag while registering test case '" - << _nameAndTags.name << "' at " << _lineInfo ); - - - // 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; - matches.reserve( m_filters.size() ); - for ( auto const& filter : m_filters ) { - std::vector
currentMatches; - for ( auto const& test : testCases ) - if ( isThrowSafe( test, config ) && - filter.matches( test.getTestCaseInfo() ) ) - currentMatches.emplace_back( &test ); - matches.push_back( - 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 escapeInvisibles) { - 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 (!escapeInvisibles) { - 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) { // NOLINT(readability-non-const-parameter) - 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 value) { - return ::Catch::Detail::stringify(static_cast
(value)); -} - -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; - } - -} - - - - -namespace Catch { - namespace Detail { - void registerTranslatorImpl( - Detail::unique_ptr
&& translator ) { - getMutableRegistryHub().registerTranslator( - CATCH_MOVE( translator ) ); - } - } // namespace Detail -} // namespace Catch - - -#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, 5, 4, "", 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 - - - - -#include
- -namespace Catch { - namespace Generators { - namespace Detail { - std::uint32_t getSeed() { return sharedRng()(); } - } // namespace Detail - - struct RandomFloatingGenerator
::PImpl { - PImpl( long double a, long double b, uint32_t seed ): - rng( seed ), dist( a, b ) {} - - Catch::SimplePcg32 rng; - std::uniform_real_distribution
dist; - }; - - RandomFloatingGenerator
::RandomFloatingGenerator( - long double a, long double b, std::uint32_t seed) : - m_pimpl(Catch::Detail::make_unique
(a, b, seed)) { - static_cast
( next() ); - } - - RandomFloatingGenerator
::~RandomFloatingGenerator() = - default; - bool RandomFloatingGenerator
::next() { - m_current_number = m_pimpl->dist( m_pimpl->rng ); - return true; - } - } // namespace Generators -} // namespace Catch - - - - -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
- -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 ) - { - 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 { - 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() ) - { - m_resultCapture.notifyAssertionStarted( m_assertionInfo ); - } - - 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() { - m_completed = true; - 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 ) { - throw_test_skip_exception(); - } - } - - 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 - ; - } - - Catch::StringRef normaliseOpt( Catch::StringRef optName ) { - if ( optName[0] == '-' -#if defined(CATCH_PLATFORM_WINDOWS) - || optName[0] == '/' -#endif - ) { - return optName.substr( 1, optName.size() ); - } - - return optName; - } - - static size_t find_first_separator(Catch::StringRef sr) { - auto is_separator = []( char c ) { - return c == ' ' || c == ':' || c == '='; - }; - size_t pos = 0; - while (pos < sr.size()) { - if (is_separator(sr[pos])) { return pos; } - ++pos; - } - - return Catch::StringRef::npos; - } - -} // 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 ) { - StringRef next = *it; - if ( isOptPrefix( next[0] ) ) { - auto delimiterPos = find_first_separator(next); - if ( delimiterPos != StringRef::npos ) { - m_tokenBuffer.push_back( - { TokenType::Option, - next.substr( 0, delimiterPos ) } ); - m_tokenBuffer.push_back( - { TokenType::Argument, - next.substr( delimiterPos + 1, next.size() ) } ); - } else { - if ( next[1] != '-' && next.size() > 2 ) { - // Combined short args, e.g. "-ab" for "-a -b" - for ( size_t i = 1; i < next.size(); ++i ) { - m_tokenBuffer.push_back( - { TokenType::Option, - next.substr( i, 1 ) } ); - } - } 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( static_cast
(args.exeName()), TokenStream( args ) ); - } - - ParseState::ParseState( ParseResultType type, - TokenStream remainingTokens ): - m_type( type ), m_remainingTokens( CATCH_MOVE(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 tokens) const { - auto validationResult = validate(); - if (!validationResult) - return Detail::InternalParseResult(validationResult); - - auto token = *tokens; - if (token.type != Detail::TokenType::Argument) - return Detail::InternalParseResult::ok(Detail::ParseState( - ParseResultType::NoMatch, CATCH_MOVE(tokens))); - - assert(!m_ref->isFlag()); - auto valueRef = - static_cast
(m_ref.get()); - - auto result = valueRef->setValue(static_cast
(token.token)); - if ( !result ) - return Detail::InternalParseResult( result ); - else - return Detail::InternalParseResult::ok( - Detail::ParseState( ParseResultType::Matched, - CATCH_MOVE( ++tokens ) ) ); - } - - Opt::Opt(bool& ref) : - ParserRefImpl(std::make_shared
(ref)) {} - - Detail::HelpColumns Opt::getHelpColumns() const { - ReusableStringStream 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(StringRef 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 tokens) const { - auto validationResult = validate(); - if (!validationResult) - return Detail::InternalParseResult(validationResult); - - if (tokens && - tokens->type == Detail::TokenType::Option) { - auto const& token = *tokens; - 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(), CATCH_MOVE(tokens))); - } else { - auto valueRef = - static_cast
( - m_ref.get()); - ++tokens; - if (!tokens) - return Detail::InternalParseResult::runtimeError( - "Expected argument following " + - token.token); - auto const& argToken = *tokens; - if (argToken.type != Detail::TokenType::Argument) - return Detail::InternalParseResult::runtimeError( - "Expected argument following " + - token.token); - const auto result = valueRef->setValue(static_cast
(argToken.token)); - if (!result) - return Detail::InternalParseResult(result); - if (result.value() == - ParseResultType::ShortCircuitAll) - return Detail::InternalParseResult::ok(Detail::ParseState( - result.value(), CATCH_MOVE(tokens))); - } - return Detail::InternalParseResult::ok(Detail::ParseState( - ParseResultType::Matched, CATCH_MOVE(++tokens))); - } - } - return Detail::InternalParseResult::ok( - Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(tokens))); - } - - 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 tokens) const { - return Detail::InternalParseResult::ok( - Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(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; - cols.reserve( m_options.size() ); - for ( auto const& o : m_options ) { - cols.push_back(o.getHelpColumns()); - } - 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& cols : rows ) { - auto row = TextFlow::Column( CATCH_MOVE(cols.left) ) - .width( optWidth ) - .indent( 2 ) + - TextFlow::Spacer( 4 ) + - TextFlow::Column( static_cast
(cols.descriptions) ) - .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 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, CATCH_MOVE(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, CATCH_MOVE(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 = '"' + CATCH_MOVE(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; - - auto 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 final : 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 final : 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 final : 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 colourSelection, - IStream* stream ) { -#if defined( CATCH_CONFIG_COLOUR_WIN32 ) - if ( colourSelection == ColourMode::Win32 ) { - return Detail::make_unique
( stream ); - } -#endif - if ( colourSelection == ColourMode::ANSI ) { - return Detail::make_unique
( stream ); - } - if ( colourSelection == ColourMode::None ) { - return Detail::make_unique
( stream ); - } - - if ( colourSelection == 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
(colourSelection) ); - } - - 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 { - - Context* Context::currentContext = nullptr; - - void cleanUpContext() { - delete Context::currentContext; - Context::currentContext = nullptr; - } - void Context::createContext() { - currentContext = new Context(); - } - - Context& getCurrentMutableContext() { - if ( !Context::currentContext ) { Context::createContext(); } - // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) - return *Context::currentContext; - } - - void Context::setResultCapture( IResultCapture* resultCapture ) { - m_resultCapture = resultCapture; - } - - void Context::setConfig( IConfig const* config ) { m_config = config; } - - 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 { - - void ITransientExpression::streamReconstructedExpression( - std::ostream& os ) const { - // We can't make this function pure virtual to keep ITransientExpression - // constexpr, so we write error message instead - os << "Some class derived from ITransientExpression without overriding streamReconstructedExpression"; - } - - 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() = default; - - 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; } -} - - - -#include
- -namespace Catch { - -#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - namespace { - static std::string tryTranslators( - std::vector< - Detail::unique_ptr
> const& translators ) { - if ( translators.empty() ) { - std::rethrow_exception( std::current_exception() ); - } else { - return translators[0]->translate( translators.begin() + 1, - translators.end() ); - } - } - - } -#endif //!defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) - - ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() = default; - - 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(m_translators); - } - // 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"; - } - } - -#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!"); - } -#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; - } - -#if defined( __GNUC__ ) || defined( __clang__ ) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - bool directCompare( float lhs, float rhs ) { return lhs == rhs; } - bool directCompare( double lhs, double rhs ) { return lhs == rhs; } -#if defined( __GNUC__ ) || defined( __clang__ ) -# pragma GCC diagnostic pop -#endif - - - } // 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 final : 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 final : 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; - } - public: // IStream - std::ostream& stream() override { - return m_ofs; - } - }; - - /////////////////////////////////////////////////////////////////////////// - - class CoutStream final : 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() ) {} - - 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() ) {} - - public: // IStream - std::ostream& stream() override { return m_os; } - bool isConsole() const override { return true; } - }; - - /////////////////////////////////////////////////////////////////////////// - - class DebugOutStream final : public IStream { - Detail::unique_ptr
> m_streamBuf; - std::ostream m_os; - public: - DebugOutStream() - : m_streamBuf( Detail::make_unique
>() ), - m_os( m_streamBuf.get() ) - {} - - 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 { - void JsonUtils::indent( std::ostream& os, std::uint64_t level ) { - for ( std::uint64_t i = 0; i < level; ++i ) { - os << " "; - } - } - void JsonUtils::appendCommaNewline( std::ostream& os, - bool& should_comma, - std::uint64_t level ) { - if ( should_comma ) { os << ','; } - should_comma = true; - os << '\n'; - indent( os, level ); - } - - JsonObjectWriter::JsonObjectWriter( std::ostream& os ): - JsonObjectWriter{ os, 0 } {} - - JsonObjectWriter::JsonObjectWriter( std::ostream& os, - std::uint64_t indent_level ): - m_os{ os }, m_indent_level{ indent_level } { - m_os << '{'; - } - JsonObjectWriter::JsonObjectWriter( JsonObjectWriter&& source ) noexcept: - m_os{ source.m_os }, - m_indent_level{ source.m_indent_level }, - m_should_comma{ source.m_should_comma }, - m_active{ source.m_active } { - source.m_active = false; - } - - JsonObjectWriter::~JsonObjectWriter() { - if ( !m_active ) { return; } - - m_os << '\n'; - JsonUtils::indent( m_os, m_indent_level ); - m_os << '}'; - } - - JsonValueWriter JsonObjectWriter::write( StringRef key ) { - JsonUtils::appendCommaNewline( - m_os, m_should_comma, m_indent_level + 1 ); - - m_os << '"' << key << "\": "; - return JsonValueWriter{ m_os, m_indent_level + 1 }; - } - - JsonArrayWriter::JsonArrayWriter( std::ostream& os ): - JsonArrayWriter{ os, 0 } {} - JsonArrayWriter::JsonArrayWriter( std::ostream& os, - std::uint64_t indent_level ): - m_os{ os }, m_indent_level{ indent_level } { - m_os << '['; - } - JsonArrayWriter::JsonArrayWriter( JsonArrayWriter&& source ) noexcept: - m_os{ source.m_os }, - m_indent_level{ source.m_indent_level }, - m_should_comma{ source.m_should_comma }, - m_active{ source.m_active } { - source.m_active = false; - } - JsonArrayWriter::~JsonArrayWriter() { - if ( !m_active ) { return; } - - m_os << '\n'; - JsonUtils::indent( m_os, m_indent_level ); - m_os << ']'; - } - - JsonObjectWriter JsonArrayWriter::writeObject() { - JsonUtils::appendCommaNewline( - m_os, m_should_comma, m_indent_level + 1 ); - return JsonObjectWriter{ m_os, m_indent_level + 1 }; - } - - JsonArrayWriter JsonArrayWriter::writeArray() { - JsonUtils::appendCommaNewline( - m_os, m_should_comma, m_indent_level + 1 ); - return JsonArrayWriter{ m_os, m_indent_level + 1 }; - } - - JsonArrayWriter& JsonArrayWriter::write( bool value ) { - return writeImpl( value ); - } - - JsonValueWriter::JsonValueWriter( std::ostream& os ): - JsonValueWriter{ os, 0 } {} - - JsonValueWriter::JsonValueWriter( std::ostream& os, - std::uint64_t indent_level ): - m_os{ os }, m_indent_level{ indent_level } {} - - JsonObjectWriter JsonValueWriter::writeObject() && { - return JsonObjectWriter{ m_os, m_indent_level }; - } - - JsonArrayWriter JsonValueWriter::writeArray() && { - return JsonArrayWriter{ m_os, m_indent_level }; - } - - void JsonValueWriter::write( Catch::StringRef value ) && { - writeImpl( value, true ); - } - - void JsonValueWriter::write( bool value ) && { - writeImpl( value ? "true"_sr : "false"_sr, false ); - } - - void JsonValueWriter::writeImpl( Catch::StringRef value, bool quote ) { - if ( quote ) { m_os << '"'; } - for (char c : value) { - // Escape list taken from https://www.json.org/json-en.html, - // string definition. - // Note that while forward slash _can_ be escaped, it does - // not have to be, if JSON is not further embedded somewhere - // where forward slash is meaningful. - if ( c == '"' ) { - m_os << "\\\""; - } else if ( c == '\\' ) { - m_os << "\\\\"; - } else if ( c == '\b' ) { - m_os << "\\b"; - } else if ( c == '\f' ) { - m_os << "\\f"; - } else if ( c == '\n' ) { - m_os << "\\n"; - } else if ( c == '\r' ) { - m_os << "\\r"; - } else if ( c == '\t' ) { - m_os << "\\t"; - } else { - m_os << c; - } - } - if ( quote ) { m_os << '"'; } - } - -} // namespace Catch - - - - -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() = default; - -#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; - - auto 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