15#include "catch_amalgamated.hpp" 
   18#ifndef CATCH_WINDOWS_H_PROXY_HPP_INCLUDED 
   19#define CATCH_WINDOWS_H_PROXY_HPP_INCLUDED 
   22#if defined(CATCH_PLATFORM_WINDOWS) 
   29#if !defined(WIN32_LEAN_AND_MEAN) 
   30#  define WIN32_LEAN_AND_MEAN 
   45            ChronometerConcept::~ChronometerConcept() = 
default;
 
 
 
 
   56            BenchmarkFunction::callable::~callable() = 
default;
 
   70                const char* 
what() 
const noexcept override;
 
 
   74                return "could not measure benchmark, maybe it was optimized away";
 
 
   96#if defined(CATCH_CONFIG_USE_ASYNC) 
  101    namespace Benchmark {
 
  105                template <
typename URng, 
typename Estimator>
 
  108                          unsigned int resamples,
 
  109                          std::vector<double>::const_iterator 
first,
 
  110                          std::vector<double>::const_iterator last,
 
  111                          Estimator& estimator ) {
 
  113                    std::uniform_int_distribution<
decltype( 
n )> dist( 0,
 
  117                    out.reserve( resamples );
 
  120                    std::vector<double> resampled;
 
  121                    resampled.reserve( 
n );
 
  122                    for ( 
size_t i = 0; 
i < resamples; ++
i ) {
 
  124                        for ( 
size_t s = 0; 
s < 
n; ++
s ) {
 
  126                                first[
static_cast<std::ptrdiff_t
>(
 
  129                        const auto estimate =
 
  130                            estimator( resampled.begin(), resampled.end() );
 
  131                        out.push_back( estimate );
 
  133                    std::sort( out.begin(), out.end() );
 
  137                static double outlier_variance( Estimate<double> 
mean,
 
  138                                                Estimate<double> stddev,
 
  140                    double sb = stddev.point;
 
  141                    double mn = 
mean.point / 
n;
 
  142                    double mg_min = mn / 2.;
 
  143                    double sg = (std::min)( mg_min / 4., sb / std::sqrt( 
n ) );
 
  144                    double sg2 = sg * sg;
 
  145                    double sb2 = sb * sb;
 
  147                    auto c_max = [
n, mn, sb2, sg2]( 
double x ) -> 
double {
 
  152                        double k1 = sb2 - 
n * sg2 + nd;
 
  153                        double det = 
k1 * 
k1 - 4 * sg2 * k0;
 
  154                        return static_cast<int>( -2. * k0 /
 
  155                                                 ( 
k1 + std::sqrt( det ) ) );
 
  158                    auto var_out = [
n, sb2, sg2]( 
double c ) {
 
  160                        return ( nc / 
n ) * ( sb2 - nc * sg2 );
 
  163                    return (std::min)( var_out( 1 ),
 
  165                                           (std::min)( c_max( 0. ),
 
  166                                                       c_max( mg_min ) ) ) ) /
 
  170                static double erf_inv( 
double x ) {
 
  175                    w = -log( ( 1.0 - 
x ) * ( 1.0 + 
x ) );
 
  177                    if ( 
w < 6.250000 ) {
 
  179                        p = -3.6444120640178196996e-21;
 
  180                        p = -1.685059138182016589e-19 + 
p * 
w;
 
  181                        p = 1.2858480715256400167e-18 + 
p * 
w;
 
  182                        p = 1.115787767802518096e-17 + 
p * 
w;
 
  183                        p = -1.333171662854620906e-16 + 
p * 
w;
 
  184                        p = 2.0972767875968561637e-17 + 
p * 
w;
 
  185                        p = 6.6376381343583238325e-15 + 
p * 
w;
 
  186                        p = -4.0545662729752068639e-14 + 
p * 
w;
 
  187                        p = -8.1519341976054721522e-14 + 
p * 
w;
 
  188                        p = 2.6335093153082322977e-12 + 
p * 
w;
 
  189                        p = -1.2975133253453532498e-11 + 
p * 
w;
 
  190                        p = -5.4154120542946279317e-11 + 
p * 
w;
 
  191                        p = 1.051212273321532285e-09 + 
p * 
w;
 
  192                        p = -4.1126339803469836976e-09 + 
p * 
w;
 
  193                        p = -2.9070369957882005086e-08 + 
p * 
w;
 
  194                        p = 4.2347877827932403518e-07 + 
p * 
w;
 
  195                        p = -1.3654692000834678645e-06 + 
p * 
w;
 
  196                        p = -1.3882523362786468719e-05 + 
p * 
w;
 
  197                        p = 0.0001867342080340571352 + 
p * 
w;
 
  198                        p = -0.00074070253416626697512 + 
p * 
w;
 
  199                        p = -0.0060336708714301490533 + 
p * 
w;
 
  200                        p = 0.24015818242558961693 + 
p * 
w;
 
  201                        p = 1.6536545626831027356 + 
p * 
w;
 
  202                    } 
else if ( 
w < 16.000000 ) {
 
  203                        w = sqrt( 
w ) - 3.250000;
 
  204                        p = 2.2137376921775787049e-09;
 
  205                        p = 9.0756561938885390979e-08 + 
p * 
w;
 
  206                        p = -2.7517406297064545428e-07 + 
p * 
w;
 
  207                        p = 1.8239629214389227755e-08 + 
p * 
w;
 
  208                        p = 1.5027403968909827627e-06 + 
p * 
w;
 
  209                        p = -4.013867526981545969e-06 + 
p * 
w;
 
  210                        p = 2.9234449089955446044e-06 + 
p * 
w;
 
  211                        p = 1.2475304481671778723e-05 + 
p * 
w;
 
  212                        p = -4.7318229009055733981e-05 + 
p * 
w;
 
  213                        p = 6.8284851459573175448e-05 + 
p * 
w;
 
  214                        p = 2.4031110387097893999e-05 + 
p * 
w;
 
  215                        p = -0.0003550375203628474796 + 
p * 
w;
 
  216                        p = 0.00095328937973738049703 + 
p * 
w;
 
  217                        p = -0.0016882755560235047313 + 
p * 
w;
 
  218                        p = 0.0024914420961078508066 + 
p * 
w;
 
  219                        p = -0.0037512085075692412107 + 
p * 
w;
 
  220                        p = 0.005370914553590063617 + 
p * 
w;
 
  221                        p = 1.0052589676941592334 + 
p * 
w;
 
  222                        p = 3.0838856104922207635 + 
p * 
w;
 
  224                        w = sqrt( 
w ) - 5.000000;
 
  225                        p = -2.7109920616438573243e-11;
 
  226                        p = -2.5556418169965252055e-10 + 
p * 
w;
 
  227                        p = 1.5076572693500548083e-09 + 
p * 
w;
 
  228                        p = -3.7894654401267369937e-09 + 
p * 
w;
 
  229                        p = 7.6157012080783393804e-09 + 
p * 
w;
 
  230                        p = -1.4960026627149240478e-08 + 
p * 
w;
 
  231                        p = 2.9147953450901080826e-08 + 
p * 
w;
 
  232                        p = -6.7711997758452339498e-08 + 
p * 
w;
 
  233                        p = 2.2900482228026654717e-07 + 
p * 
w;
 
  234                        p = -9.9298272942317002539e-07 + 
p * 
w;
 
  235                        p = 4.5260625972231537039e-06 + 
p * 
w;
 
  236                        p = -1.9681778105531670567e-05 + 
p * 
w;
 
  237                        p = 7.5995277030017761139e-05 + 
p * 
w;
 
  238                        p = -0.00021503011930044477347 + 
p * 
w;
 
  239                        p = -0.00013871931833623122026 + 
p * 
w;
 
  240                        p = 1.0103004648645343977 + 
p * 
w;
 
  241                        p = 4.8499064014085844221 + 
p * 
w;
 
  247                standard_deviation( std::vector<double>::const_iterator 
first,
 
  248                                    std::vector<double>::const_iterator last ) {
 
  251                        std::accumulate( 
first,
 
  254                                         [
m]( 
double a, 
double b ) {
 
  256                                             return a + diff * diff;
 
  259                    return std::sqrt( variance );
 
  268    namespace Benchmark {
 
  271#if defined( __GNUC__ ) || defined( __clang__ ) 
  272#    pragma GCC diagnostic push 
  273#    pragma GCC diagnostic ignored "-Wfloat-equal" 
  276#if defined( __GNUC__ ) || defined( __clang__ ) 
  277#    pragma GCC diagnostic pop 
  282                double idx = (
count - 1) * k / 
static_cast<double>(q);
 
  283                int j = 
static_cast<int>(idx);
 
  291                auto xj1 = *std::min_element(
first + (
j + 1), last);
 
  292                return xj + 
g * (xj1 - xj);
 
 
  295            OutlierClassification
 
  297                               std::vector<double>::const_iterator last ) {
 
  298                std::vector<double> copy( 
first, last );
 
  303                auto los = q1 - ( iqr * 3. );
 
  304                auto lom = q1 - ( iqr * 1.5 );
 
  305                auto him = q3 + ( iqr * 1.5 );
 
  306                auto his = q3 + ( iqr * 3. );
 
  308                OutlierClassification o;
 
  310                    const double t = *
first;
 
  313                    } 
else if ( t < lom ) {
 
  315                    } 
else if ( t > his ) {
 
  317                    } 
else if ( t > him ) {
 
 
  326                         std::vector<double>::const_iterator last ) {
 
  329                while (
first != last) {
 
  333                return sum / 
static_cast<double>(
count);
 
 
  338                return erf_inv(1.0 - 
x);
 
 
  342                static const double ROOT_TWO = std::sqrt(2.0);
 
  345                assert(p >= 0 && p <= 1);
 
  346                if (p < 0 || p > 1) {
 
 
  358                                               unsigned int n_resamples,
 
  359                                               std::vector<double>::iterator 
first,
 
  360                                               std::vector<double>::iterator last) {
 
  361                CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
 
  362                CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
 
  363                static std::random_device entropy;
 
  364                CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
 
  366                auto n = 
static_cast<int>(last - 
first); 
 
  369                auto stddev = &standard_deviation;
 
  371#if defined(CATCH_CONFIG_USE_ASYNC) 
  372                auto Estimate = [=](double(*
f)(std::vector<double>::const_iterator,
 
  373                                               std::vector<double>::const_iterator)) {
 
  374                    auto seed = entropy();
 
  375                    return std::async(std::launch::async, [=] {
 
  376                        std::mt19937 rng(seed);
 
  377                        auto resampled = resample(rng, n_resamples, 
first, last, 
f);
 
  378                        return bootstrap(confidence_level, 
first, last, resampled, 
f);
 
  382                auto mean_future = Estimate(
mean);
 
  383                auto stddev_future = Estimate(stddev);
 
  385                auto mean_estimate = mean_future.get();
 
  386                auto stddev_estimate = stddev_future.get();
 
  388                auto Estimate = [=](double(*
f)(std::vector<double>::const_iterator,
 
  389                                               std::vector<double>::const_iterator)) {
 
  390                    auto seed = entropy();
 
  391                    std::mt19937 rng(seed);
 
  392                    auto resampled = resample(rng, n_resamples, 
first, last, 
f);
 
  393                    return bootstrap(confidence_level, 
first, last, resampled, 
f);
 
  396                auto mean_estimate = Estimate(
mean);
 
  397                auto stddev_estimate = Estimate(stddev);
 
  400                double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, 
n);
 
  402                return { mean_estimate, stddev_estimate, outlier_variance };
 
 
  417bool marginComparison(
double lhs, 
double rhs, 
double margin) {
 
  418    return (lhs + margin >= rhs) && (
rhs + margin >= 
lhs);
 
  425    Approx::Approx ( 
double value )
 
  426    :   m_epsilon( 
std::numeric_limits<float>::epsilon()*100. ),
 
  432    Approx Approx::custom() {
 
  436    Approx Approx::operator-()
 const {
 
  438        temp.m_value = -temp.m_value;
 
  443    std::string Approx::toString()
 const {
 
  444        ReusableStringStream rss;
 
  445        rss << 
"Approx( " << ::Catch::Detail::stringify( m_value ) << 
" )";
 
  449    bool Approx::equalityComparisonImpl(
const double other)
 const {
 
  452        return marginComparison(m_value, 
other, m_margin)
 
  453            || marginComparison(m_value, 
other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
 
  456    void Approx::setMargin(
double newMargin) {
 
  457        CATCH_ENFORCE(newMargin >= 0,
 
  458            "Invalid Approx::margin: " << newMargin << 
'.' 
  459            << 
" Approx::Margin has to be non-negative.");
 
  460        m_margin = newMargin;
 
  463    void Approx::setEpsilon(
double newEpsilon) {
 
  464        CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
 
  465            "Invalid Approx::epsilon: " << newEpsilon << 
'.' 
  466            << 
" Approx::epsilon has to be in [0, 1]");
 
  467        m_epsilon = newEpsilon;
 
  471    Approx 
operator "" _a(
long double val) {
 
 
  474    Approx 
operator "" _a(
unsigned long long val) {
 
 
 
  479std::string StringMaker<Catch::Approx>::convert(Catch::Approx 
const& 
value) {
 
  480    return value.toString();
 
  489    AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression 
const & _lazyExpression):
 
  490        lazyExpression(_lazyExpression),
 
  491        resultType(_resultType) {}
 
  493    std::string AssertionResultData::reconstructExpression()
 const {
 
  495        if( reconstructedExpression.empty() ) {
 
  496            if( lazyExpression ) {
 
  497                ReusableStringStream rss;
 
  498                rss << lazyExpression;
 
  499                reconstructedExpression = rss.str();
 
  502        return reconstructedExpression;
 
  505    AssertionResult::AssertionResult( AssertionInfo 
const& info, AssertionResultData&& 
data )
 
  507        m_resultData( CATCH_MOVE(
data) )
 
  511    bool AssertionResult::succeeded()
 const {
 
  516    bool AssertionResult::isOk()
 const {
 
  520    ResultWas::OfType AssertionResult::getResultType()
 const {
 
  521        return m_resultData.resultType;
 
  524    bool AssertionResult::hasExpression()
 const {
 
  525        return !m_info.capturedExpression.empty();
 
  528    bool AssertionResult::hasMessage()
 const {
 
  529        return !m_resultData.message.empty();
 
  532    std::string AssertionResult::getExpression()
 const {
 
  534        std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
 
  535        if (isFalseTest(m_info.resultDisposition)) {
 
  538        expr += m_info.capturedExpression;
 
  539        if (isFalseTest(m_info.resultDisposition)) {
 
  545    std::string AssertionResult::getExpressionInMacro()
 const {
 
  546        if ( m_info.macroName.empty() ) {
 
  547            return static_cast<std::string
>( m_info.capturedExpression );
 
  550        expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
 
  551        expr += m_info.macroName;
 
  553        expr += m_info.capturedExpression;
 
  558    bool AssertionResult::hasExpandedExpression()
 const {
 
  559        return hasExpression() && getExpandedExpression() != getExpression();
 
  562    std::string AssertionResult::getExpandedExpression()
 const {
 
  563        std::string expr = m_resultData.reconstructExpression();
 
  569    StringRef AssertionResult::getMessage()
 const {
 
  570        return m_resultData.message;
 
  572    SourceLineInfo AssertionResult::getSourceInfo()
 const {
 
  573        return m_info.lineInfo;
 
  576    StringRef AssertionResult::getTestMacroName()
 const {
 
  577        return m_info.macroName;
 
  589        static bool enableBazelEnvSupport() {
 
  590#if defined( CATCH_CONFIG_BAZEL_SUPPORT ) 
  597        struct bazelShardingOptions {
 
  602        static Optional<bazelShardingOptions> readBazelShardingOptions() {
 
  603            const auto bazelShardIndex = 
Detail::getEnv( 
"TEST_SHARD_INDEX" );
 
  604            const auto bazelShardTotal = 
Detail::getEnv( 
"TEST_TOTAL_SHARDS" );
 
  605            const auto bazelShardInfoFile = 
Detail::getEnv( 
"TEST_SHARD_STATUS_FILE" );
 
  609                bazelShardIndex && bazelShardTotal && bazelShardInfoFile;
 
  613                auto warn = []( 
const char* env_var ) {
 
  615                        << 
"Warning: Bazel shard configuration is missing '" 
  616                        << env_var << 
"'. Shard configuration is skipped.\n";
 
  618                if ( !bazelShardIndex ) {
 
  619                    warn( 
"TEST_SHARD_INDEX" );
 
  621                if ( !bazelShardTotal ) {
 
  622                    warn( 
"TEST_TOTAL_SHARDS" );
 
  624                if ( !bazelShardInfoFile ) {
 
  625                    warn( 
"TEST_SHARD_STATUS_FILE" );
 
  633                    << 
"Warning: could not parse 'TEST_SHARD_INDEX' ('" << bazelShardIndex
 
  634                    << 
"') as unsigned int.\n";
 
  637            auto shardTotal = 
parseUInt( bazelShardTotal );
 
  640                    << 
"Warning: could not parse 'TEST_TOTAL_SHARD' ('" 
  641                    << bazelShardTotal << 
"') as unsigned int.\n";
 
  645            return bazelShardingOptions{
 
  646                *
shardIndex, *shardTotal, bazelShardInfoFile };
 
  653                     ProcessedReporterSpec 
const& rhs ) {
 
  654        return lhs.name == rhs.name &&
 
  655               lhs.outputFilename == rhs.outputFilename &&
 
  656               lhs.colourMode == rhs.colourMode &&
 
  657               lhs.customOptions == rhs.customOptions;
 
 
  660    Config::Config( ConfigData 
const& 
data ):
 
  666        for (
auto& elem : m_data.testsOrTags) {
 
  669        for (
auto& elem : m_data.sectionsToRun) {
 
  674        if ( m_data.reporterSpecifications.empty() ) {
 
  675            m_data.reporterSpecifications.push_back( {
 
  676#if defined( CATCH_CONFIG_DEFAULT_REPORTER ) 
  677                CATCH_CONFIG_DEFAULT_REPORTER,
 
  685        if ( enableBazelEnvSupport() ) {
 
  691        TestSpecParser parser( ITagAliasRegistry::get() );
 
  692        if ( !m_data.testsOrTags.empty() ) {
 
  693            m_hasTestFilters = 
true;
 
  694            for ( 
auto const& testOrTags : m_data.testsOrTags ) {
 
  695                parser.parse( testOrTags );
 
  698        m_testSpec = parser.testSpec();
 
  703        bool defaultOutputUsed = 
false;
 
  704        for ( 
auto const& reporterSpec : m_data.reporterSpecifications ) {
 
  708            if ( reporterSpec.outputFile().none() ) {
 
  709                CATCH_ENFORCE( !defaultOutputUsed,
 
  710                               "Internal error: cannot use default output for " 
  711                               "multiple reporters" );
 
  712                defaultOutputUsed = 
true;
 
  715            m_processedReporterSpecs.push_back( ProcessedReporterSpec{
 
  717                reporterSpec.outputFile() ? *reporterSpec.outputFile()
 
  718                                          : 
data.defaultOutputFilename,
 
  719                reporterSpec.colourMode().valueOr( 
data.defaultColourMode ),
 
  720                reporterSpec.customOptions() } );
 
  724    Config::~Config() = 
default;
 
  727    bool Config::listTests()
 const          { 
return m_data.listTests; }
 
  728    bool Config::listTags()
 const           { 
return m_data.listTags; }
 
  729    bool Config::listReporters()
 const      { 
return m_data.listReporters; }
 
  730    bool Config::listListeners()
 const      { 
return m_data.listListeners; }
 
  732    std::vector<std::string> 
const& Config::getTestsOrTags()
 const { 
return m_data.testsOrTags; }
 
  733    std::vector<std::string> 
const& Config::getSectionsToRun()
 const { 
return m_data.sectionsToRun; }
 
  735    std::vector<ReporterSpec> 
const& Config::getReporterSpecs()
 const {
 
  736        return m_data.reporterSpecifications;
 
  739    std::vector<ProcessedReporterSpec> 
const&
 
  740    Config::getProcessedReporterSpecs()
 const {
 
  741        return m_processedReporterSpecs;
 
  744    TestSpec 
const& Config::testSpec()
 const { 
return m_testSpec; }
 
  745    bool Config::hasTestFilters()
 const { 
return m_hasTestFilters; }
 
  747    bool Config::showHelp()
 const { 
return m_data.showHelp; }
 
  750    bool Config::allowThrows()
 const                   { 
return !m_data.noThrow; }
 
  751    StringRef Config::name()
 const { 
return m_data.name.empty() ? m_data.processName : m_data.name; }
 
  752    bool Config::includeSuccessfulResults()
 const      { 
return m_data.showSuccessfulTests; }
 
  753    bool Config::warnAboutMissingAssertions()
 const {
 
  754        return !!( m_data.warnings & WarnAbout::NoAssertions );
 
  756    bool Config::warnAboutUnmatchedTestSpecs()
 const {
 
  757        return !!( m_data.warnings & WarnAbout::UnmatchedTestSpec );
 
  759    bool Config::zeroTestsCountAsSuccess()
 const       { 
return m_data.allowZeroTests; }
 
  760    ShowDurations Config::showDurations()
 const        { 
return m_data.showDurations; }
 
  761    double Config::minDuration()
 const                 { 
return m_data.minDuration; }
 
  762    TestRunOrder Config::runOrder()
 const              { 
return m_data.runOrder; }
 
  763    uint32_t Config::rngSeed()
 const                   { 
return m_data.rngSeed; }
 
  764    unsigned int Config::shardCount()
 const            { 
return m_data.shardCount; }
 
  765    unsigned int Config::shardIndex()
 const            { 
return m_data.shardIndex; }
 
  766    ColourMode Config::defaultColourMode()
 const       { 
return m_data.defaultColourMode; }
 
  767    bool Config::shouldDebugBreak()
 const              { 
return m_data.shouldDebugBreak; }
 
  768    int Config::abortAfter()
 const                     { 
return m_data.abortAfter; }
 
  769    bool Config::showInvisibles()
 const                { 
return m_data.showInvisibles; }
 
  770    Verbosity Config::verbosity()
 const                { 
return m_data.verbosity; }
 
  772    bool Config::skipBenchmarks()
 const                           { 
return m_data.skipBenchmarks; }
 
  773    bool Config::benchmarkNoAnalysis()
 const                      { 
return m_data.benchmarkNoAnalysis; }
 
  774    unsigned int Config::benchmarkSamples()
 const                 { 
return m_data.benchmarkSamples; }
 
  775    double Config::benchmarkConfidenceInterval()
 const            { 
return m_data.benchmarkConfidenceInterval; }
 
  776    unsigned int Config::benchmarkResamples()
 const               { 
return m_data.benchmarkResamples; }
 
  777    std::chrono::milliseconds Config::benchmarkWarmupTime()
 const { 
return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
 
  779    void Config::readBazelEnvVars() {
 
  787        if ( bazelOutputFile ) {
 
  788            m_data.reporterSpecifications.push_back(
 
  789                { 
"junit", std::string( bazelOutputFile ), {}, {} } );
 
  792        const auto bazelTestSpec = 
Detail::getEnv( 
"TESTBRIDGE_TEST_ONLY" );
 
  793        if ( bazelTestSpec ) {
 
  796            m_data.testsOrTags.clear();
 
  797            m_data.testsOrTags.push_back( bazelTestSpec );
 
  800        const auto bazelShardOptions = readBazelShardingOptions();
 
  801        if ( bazelShardOptions ) {
 
  802            std::ofstream 
f( bazelShardOptions->shardFilePath,
 
  803                             std::ios_base::out | std::ios_base::trunc );
 
  806                m_data.shardIndex = bazelShardOptions->shardIndex;
 
  807                m_data.shardCount = bazelShardOptions->shardCount;
 
  820        return getCurrentContext().getConfig()->rngSeed();
 
 
  834    ScopedMessage::ScopedMessage( MessageBuilder&& builder ):
 
  835        m_info( CATCH_MOVE(builder.m_info) ) {
 
  836        m_info.message = builder.m_stream.str();
 
  840    ScopedMessage::ScopedMessage( ScopedMessage&& old ) 
noexcept:
 
  841        m_info( CATCH_MOVE( old.m_info ) ) {
 
  845    ScopedMessage::~ScopedMessage() {
 
  852    Capturer::Capturer( StringRef macroName,
 
  853                        SourceLineInfo 
const& lineInfo,
 
  854                        ResultWas::OfType resultType,
 
  857        auto trimmed = [&] (
size_t start, 
size_t end) {
 
  858            while (names[
start] == 
',' || isspace(
static_cast<unsigned char>(names[
start]))) {
 
  861            while (names[
end] == 
',' || isspace(
static_cast<unsigned char>(names[
end]))) {
 
  866        auto skipq = [&] (
size_t start, 
char quote) {
 
  867            for (
auto i = 
start + 1; 
i < names.size() ; ++
i) {
 
  868                if (names[
i] == quote)
 
  870                if (names[
i] == 
'\\')
 
  873            CATCH_INTERNAL_ERROR(
"CAPTURE parsing encountered unmatched quote");
 
  877        std::stack<char> openings;
 
  878        for (
size_t pos = 0; 
pos < names.size(); ++
pos) {
 
  900                if (
start != 
pos && openings.empty()) {
 
  901                    m_messages.emplace_back(macroName, lineInfo, resultType);
 
  902                    m_messages.back().message = 
static_cast<std::string
>(trimmed(
start, 
pos));
 
  903                    m_messages.back().message += 
" := ";
 
  908        assert(openings.empty() && 
"Mismatched openings");
 
  909        m_messages.emplace_back(macroName, lineInfo, resultType);
 
  910        m_messages.back().message = 
static_cast<std::string
>(trimmed(
start, names.size() - 1));
 
  911        m_messages.back().message += 
" := ";
 
  913    Capturer::~Capturer() {
 
  915            assert( m_captured == m_messages.size() );
 
  916            for( 
size_t i = 0; 
i < m_captured; ++
i  )
 
  917                m_resultCapture.popScopedMessage( m_messages[
i] );
 
  921    void Capturer::captureValue( 
size_t index, std::string 
const& 
value ) {
 
  922        assert( 
index < m_messages.size() );
 
  924        m_resultCapture.pushScopedMessage( m_messages[
index] );
 
  939        class RegistryHub : 
public IRegistryHub,
 
  940                            public IMutableRegistryHub,
 
  941                            private Detail::NonCopyable {
 
  944            RegistryHub() = 
default;
 
  945            ReporterRegistry 
const& getReporterRegistry()
 const override {
 
  946                return m_reporterRegistry;
 
  948            ITestCaseRegistry 
const& getTestCaseRegistry()
 const override {
 
  949                return m_testCaseRegistry;
 
  951            IExceptionTranslatorRegistry 
const& getExceptionTranslatorRegistry()
 const override {
 
  952                return m_exceptionTranslatorRegistry;
 
  954            ITagAliasRegistry 
const& getTagAliasRegistry()
 const override {
 
  955                return m_tagAliasRegistry;
 
  957            StartupExceptionRegistry 
const& getStartupExceptionRegistry()
 const override {
 
  958                return m_exceptionRegistry;
 
  962            void registerReporter( std::string 
const& 
name, IReporterFactoryPtr factory )
 override {
 
  963                m_reporterRegistry.registerReporter( 
name, CATCH_MOVE(factory) );
 
  965            void registerListener( Detail::unique_ptr<EventListenerFactory> factory )
 override {
 
  966                m_reporterRegistry.registerListener( CATCH_MOVE(factory) );
 
  968            void registerTest( Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker )
 override {
 
  969                m_testCaseRegistry.registerTest( CATCH_MOVE(testInfo), CATCH_MOVE(invoker) );
 
  971            void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator )
 override {
 
  972                m_exceptionTranslatorRegistry.registerTranslator( CATCH_MOVE(translator) );
 
  974            void registerTagAlias( std::string 
const& alias, std::string 
const& tag, SourceLineInfo 
const& lineInfo )
 override {
 
  975                m_tagAliasRegistry.add( alias, tag, lineInfo );
 
  977            void registerStartupException() noexcept
 override {
 
  978#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) 
  979                m_exceptionRegistry.add(std::current_exception());
 
  981                CATCH_INTERNAL_ERROR(
"Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
 
  984            IMutableEnumValuesRegistry& getMutableEnumValuesRegistry()
 override {
 
  985                return m_enumValuesRegistry;
 
  989            TestRegistry m_testCaseRegistry;
 
  990            ReporterRegistry m_reporterRegistry;
 
  991            ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
 
  992            TagAliasRegistry m_tagAliasRegistry;
 
  993            StartupExceptionRegistry m_exceptionRegistry;
 
  994            Detail::EnumValuesRegistry m_enumValuesRegistry;
 
 1001        return RegistryHubSingleton::get();
 
 
 1004        return RegistryHubSingleton::getMutable();
 
 
 1011        return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
 
 
 1028        const int MaxExitCode = 255;
 
 1030        IEventListenerPtr createReporter(std::string 
const& reporterName, ReporterConfig&& config) {
 
 1031            auto reporter = 
Catch::getRegistryHub().getReporterRegistry().create(reporterName, CATCH_MOVE(config));
 
 1032            CATCH_ENFORCE(reporter, 
"No reporter registered with name: '" << reporterName << 
'\'');
 
 1037        IEventListenerPtr prepareReporters(Config 
const* config) {
 
 1039                    && config->getProcessedReporterSpecs().size() == 1) {
 
 1040                auto const& spec = config->getProcessedReporterSpecs()[0];
 
 1041                return createReporter(
 
 1043                    ReporterConfig( config,
 
 1046                                    spec.customOptions ) );
 
 1049            auto multi = Detail::make_unique<MultiReporter>(config);
 
 1052            for (
auto const& listener : listeners) {
 
 1053                multi->addListener(listener->create(config));
 
 1056            for ( 
auto const& reporterSpec : config->getProcessedReporterSpecs() ) {
 
 1057                multi->addReporter( createReporter(
 
 1059                    ReporterConfig( config,
 
 1061                                    reporterSpec.colourMode,
 
 1062                                    reporterSpec.customOptions ) ) );
 
 1070            explicit TestGroup(IEventListenerPtr&& reporter, Config 
const* config):
 
 1071                m_reporter(reporter.
get()),
 
 1073                m_context{config, CATCH_MOVE(reporter)} {
 
 1075                assert( m_config->testSpec().getInvalidSpecs().empty() &&
 
 1076                        "Invalid test specs should be handled before running tests" );
 
 1079                auto const& testSpec = m_config->testSpec();
 
 1080                if ( !testSpec.hasFilters() ) {
 
 1081                    for ( 
auto const& 
test : allTestCases ) {
 
 1082                        if ( !
test.getTestCaseInfo().isHidden() ) {
 
 1083                            m_tests.emplace( &
test );
 
 1088                        testSpec.matchesByFilter( allTestCases, *m_config );
 
 1089                    for ( 
auto const& 
match : m_matches ) {
 
 1090                        m_tests.insert( 
match.tests.begin(),
 
 1091                                        match.tests.end() );
 
 1095                m_tests = createShard(m_tests, m_config->shardCount(), m_config->shardIndex());
 
 1100                for (
auto const& testCase : m_tests) {
 
 1101                    if (!m_context.aborting())
 
 1102                        totals += m_context.runTest(*testCase);
 
 1104                        m_reporter->skipTest(testCase->getTestCaseInfo());
 
 1107                for (
auto const& 
match : m_matches) {
 
 1108                    if (
match.tests.empty()) {
 
 1109                        m_unmatchedTestSpecs = 
true;
 
 1110                        m_reporter->noMatchingTestCases( 
match.name );
 
 1117            bool hadUnmatchedTestSpecs()
 const {
 
 1118                return m_unmatchedTestSpecs;
 
 1123            IEventListener* m_reporter;
 
 1125            RunContext m_context;
 
 1126            std::set<TestCaseHandle const*> m_tests;
 
 1127            TestSpec::Matches m_matches;
 
 1128            bool m_unmatchedTestSpecs = 
false;
 
 1131        void applyFilenamesAsTags() {
 
 1132            for (
auto const& testInfo : 
getRegistryHub().getTestCaseRegistry().getAllInfos()) {
 
 1133                testInfo->addFilenameTag();
 
 1139    Session::Session() {
 
 1140        static bool alreadyInstantiated = 
false;
 
 1141        if( alreadyInstantiated ) {
 
 1142            CATCH_TRY { CATCH_INTERNAL_ERROR( 
"Only one instance of Catch::Session can ever be used" ); }
 
 1147#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) 
 1148        const auto& exceptions = 
getRegistryHub().getStartupExceptionRegistry().getExceptions();
 
 1149        if ( !exceptions.empty() ) {
 
 1151            getCurrentMutableContext().setConfig(m_config.get());
 
 1153            m_startupExceptions = 
true;
 
 1155            auto colourImpl = makeColourImpl(
 
 1156                ColourMode::PlatformDefault, errStream.get() );
 
 1157            auto guard = colourImpl->guardColour( Colour::Red );
 
 1158            errStream->stream() << 
"Errors occurred during startup!" << 
'\n';
 
 1160            for ( 
const auto& ex_ptr : exceptions ) {
 
 1162                    std::rethrow_exception(ex_ptr);
 
 1163                } 
catch ( std::exception 
const& ex ) {
 
 1164                    errStream->stream() << TextFlow::Column( ex.what() ).indent(2) << 
'\n';
 
 1170        alreadyInstantiated = 
true;
 
 1173    Session::~Session() {
 
 1177    void Session::showHelp()
 const {
 
 1181                << 
"For more detailed usage please see the project docs\n\n" << std::flush;
 
 1183    void Session::libIdentify() {
 
 1185                << std::left << std::setw(16) << 
"description: " << 
"A Catch2 test executable\n" 
 1186                << std::left << std::setw(16) << 
"category: " << 
"testframework\n" 
 1187                << std::left << std::setw(16) << 
"framework: " << 
"Catch2\n" 
 1188                << std::left << std::setw(16) << 
"version: " << 
libraryVersion() << 
'\n' << std::flush;
 
 1191    int Session::applyCommandLine( 
int argc, 
char const * 
const * argv ) {
 
 1192        if( m_startupExceptions )
 
 1195        auto result = m_cli.parse( Clara::Args( argc, argv ) );
 
 1199            getCurrentMutableContext().setConfig(m_config.get());
 
 1201            auto colour = makeColourImpl( ColourMode::PlatformDefault, errStream.get() );
 
 1204                << colour->guardColour( Colour::Red )
 
 1205                << 
"\nError(s) in input:\n" 
 1206                << TextFlow::Column( 
result.errorMessage() ).indent( 2 )
 
 1208            errStream->stream() << 
"Run with -? for usage\n\n" << std::flush;
 
 1212        if( m_configData.showHelp )
 
 1214        if( m_configData.libIdentify )
 
 1221#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) 
 1222    int Session::applyCommandLine( 
int argc, 
wchar_t const * 
const * argv ) {
 
 1224        char **utf8Argv = 
new char *[ argc ];
 
 1226        for ( 
int i = 0; 
i < argc; ++
i ) {
 
 1227            int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[
i], -1, 
nullptr, 0, 
nullptr, 
nullptr );
 
 1229            utf8Argv[ 
i ] = 
new char[ 
bufSize ];
 
 1231            WideCharToMultiByte( CP_UTF8, 0, argv[
i], -1, utf8Argv[
i], 
bufSize, 
nullptr, 
nullptr );
 
 1234        int returnCode = applyCommandLine( argc, utf8Argv );
 
 1236        for ( 
int i = 0; 
i < argc; ++
i )
 
 1237            delete [] utf8Argv[ 
i ];
 
 1245    void Session::useConfigData( ConfigData 
const& configData ) {
 
 1246        m_configData = configData;
 
 1250    int Session::run() {
 
 1251        if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
 
 1252            Catch::cout() << 
"...waiting for enter/ return before starting\n" << std::flush;
 
 1253            static_cast<void>(std::getchar());
 
 1255        int exitCode = runInternal();
 
 1256        if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
 
 1257            Catch::cout() << 
"...waiting for enter/ return before exiting, with code: " << exitCode << 
'\n' << std::flush;
 
 1258            static_cast<void>(std::getchar());
 
 1263    Clara::Parser 
const& Session::cli()
 const {
 
 1266    void Session::cli( Clara::Parser 
const& newParser ) {
 
 1269    ConfigData& Session::configData() {
 
 1270        return m_configData;
 
 1272    Config& Session::config() {
 
 1274            m_config = Detail::make_unique<Config>( m_configData );
 
 1278    int Session::runInternal() {
 
 1279        if( m_startupExceptions )
 
 1282        if (m_configData.showHelp || m_configData.libIdentify) {
 
 1286        if ( m_configData.shardIndex >= m_configData.shardCount ) {
 
 1287            Catch::cerr() << 
"The shard count (" << m_configData.shardCount
 
 1288                          << 
") must be greater than the shard index (" 
 1289                          << m_configData.shardIndex << 
")\n" 
 1299            if (m_configData.filenamesAsTags) {
 
 1300                applyFilenamesAsTags();
 
 1304            getCurrentMutableContext().setConfig(m_config.get());
 
 1307            auto reporter = prepareReporters(m_config.get());
 
 1309            auto const& invalidSpecs = m_config->testSpec().getInvalidSpecs();
 
 1310            if ( !invalidSpecs.empty() ) {
 
 1311                for ( 
auto const& spec : invalidSpecs ) {
 
 1312                    reporter->reportInvalidTestSpec( spec );
 
 1319            if (
list(*reporter, *m_config)) {
 
 1323            TestGroup tests { CATCH_MOVE(reporter), m_config.get() };
 
 1324            auto const totals = tests.execute();
 
 1326            if ( tests.hadUnmatchedTestSpecs()
 
 1327                && m_config->warnAboutUnmatchedTestSpecs() ) {
 
 1331            if ( totals.testCases.total() == 0
 
 1332                && !m_config->zeroTestsCountAsSuccess() ) {
 
 1336            if ( totals.testCases.total() > 0 &&
 
 1337                 totals.testCases.total() == totals.testCases.skipped
 
 1338                && !m_config->zeroTestsCountAsSuccess() ) {
 
 1345            return (std::min) (MaxExitCode, 
static_cast<int>(totals.assertions.failed));
 
 1347#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) 
 1348        catch( std::exception& ex ) {
 
 1362    RegistrarForTagAliases::RegistrarForTagAliases(
char const* alias, 
char const* tag, SourceLineInfo 
const& lineInfo) {
 
 1382        using TCP_underlying_type = 
uint8_t;
 
 1383        static_assert(
sizeof(TestCaseProperties) == 
sizeof(TCP_underlying_type),
 
 1384                      "The size of the TestCaseProperties is different from the assumed size");
 
 1386        TestCaseProperties 
operator|(TestCaseProperties lhs, TestCaseProperties rhs) {
 
 1387            return static_cast<TestCaseProperties
>(
 
 1388                static_cast<TCP_underlying_type
>(
lhs) | 
static_cast<TCP_underlying_type
>(rhs)
 
 1392        TestCaseProperties& 
operator|=(TestCaseProperties& lhs, TestCaseProperties rhs) {
 
 1393            lhs = 
static_cast<TestCaseProperties
>(
 
 1394                static_cast<TCP_underlying_type
>(
lhs) | 
static_cast<TCP_underlying_type
>(rhs)
 
 1399        TestCaseProperties 
operator&(TestCaseProperties lhs, TestCaseProperties rhs) {
 
 1400            return static_cast<TestCaseProperties
>(
 
 1401                static_cast<TCP_underlying_type
>(
lhs) & 
static_cast<TCP_underlying_type
>(rhs)
 
 1405        bool applies(TestCaseProperties tcp) {
 
 1406            static_assert(
static_cast<TCP_underlying_type
>(TestCaseProperties::None) == 0,
 
 1407                          "TestCaseProperties::None must be equal to 0");
 
 1408            return tcp != TestCaseProperties::None;
 
 1411        TestCaseProperties parseSpecialTag( StringRef tag ) {
 
 1412            if( !tag.empty() && tag[0] == 
'.' )
 
 1413                return TestCaseProperties::IsHidden;
 
 1414            else if( tag == 
"!throws"_sr )
 
 1415                return TestCaseProperties::Throws;
 
 1416            else if( tag == 
"!shouldfail"_sr )
 
 1417                return TestCaseProperties::ShouldFail;
 
 1418            else if( tag == 
"!mayfail"_sr )
 
 1419                return TestCaseProperties::MayFail;
 
 1420            else if( tag == 
"!nonportable"_sr )
 
 1421                return TestCaseProperties::NonPortable;
 
 1422            else if( tag == 
"!benchmark"_sr )
 
 1423                return TestCaseProperties::Benchmark | TestCaseProperties::IsHidden;
 
 1425                return TestCaseProperties::None;
 
 1427        bool isReservedTag( StringRef tag ) {
 
 1428            return parseSpecialTag( tag ) == TestCaseProperties::None
 
 1430                && !std::isalnum( 
static_cast<unsigned char>(tag[0]) );
 
 1432        void enforceNotReservedTag( StringRef tag, SourceLineInfo 
const& _lineInfo ) {
 
 1433            CATCH_ENFORCE( !isReservedTag(tag),
 
 1434                          "Tag name: [" << tag << 
"] is not allowed.\n" 
 1435                          << 
"Tag names starting with non alphanumeric characters are reserved\n" 
 1439        std::string makeDefaultName() {
 
 1444        StringRef extractFilenamePart(StringRef 
filename) {
 
 1446            while (lastDot > 0 && 
filename[lastDot - 1] != 
'.') {
 
 1451            size_t nameStart = lastDot;
 
 1452            while (nameStart > 0 && 
filename[nameStart - 1] != 
'/' && 
filename[nameStart - 1] != 
'\\') {
 
 1456            return filename.substr(nameStart, lastDot - nameStart);
 
 1460        size_t sizeOfExtraTags(StringRef filepath) {
 
 1462            const size_t extras = 3 + 3;
 
 1463            return extractFilenamePart(filepath).size() + extras;
 
 1467    bool operator<(  Tag 
const& lhs, Tag 
const& rhs ) {
 
 1468        Detail::CaseInsensitiveLess 
cmp;
 
 1469        return cmp( 
lhs.original, 
rhs.original );
 
 1471    bool operator==( Tag 
const& lhs, Tag 
const& rhs ) {
 
 1472        Detail::CaseInsensitiveEqualTo 
cmp;
 
 1473        return cmp( 
lhs.original, 
rhs.original );
 
 1476    Detail::unique_ptr<TestCaseInfo>
 
 1477        makeTestCaseInfo(StringRef _className,
 
 1478                         NameAndTags 
const& nameAndTags,
 
 1479                         SourceLineInfo 
const& _lineInfo ) {
 
 1480        return Detail::make_unique<TestCaseInfo>(_className, nameAndTags, _lineInfo);
 
 1483    TestCaseInfo::TestCaseInfo(StringRef _className,
 
 1484                               NameAndTags 
const& _nameAndTags,
 
 1485                               SourceLineInfo 
const& _lineInfo):
 
 1487        className( _className ),
 
 1488        lineInfo( _lineInfo )
 
 1490        StringRef originalTags = _nameAndTags.tags;
 
 1493        auto requiredSize = originalTags.size() + sizeOfExtraTags(_lineInfo.file);
 
 1494        backingTags.reserve(requiredSize);
 
 1498        size_t tagStart = 0;
 
 1501        for (
size_t idx = 0; 
idx < originalTags.size(); ++
idx) {
 
 1502            auto c = originalTags[
idx];
 
 1506                    "Found '[' inside a tag while registering test case '" 
 1507                        << _nameAndTags.name << 
"' at " << _lineInfo );
 
 1515                    "Found unmatched ']' while registering test case '" 
 1516                        << _nameAndTags.name << 
"' at " << _lineInfo );
 
 1520                assert(tagStart < tagEnd);
 
 1525                StringRef tagStr = originalTags.substr(tagStart+1, tagEnd - tagStart - 1);
 
 1526                CATCH_ENFORCE( !tagStr.empty(),
 
 1527                               "Found an empty tag while registering test case '" 
 1528                                   << _nameAndTags.name << 
"' at " 
 1531                enforceNotReservedTag(tagStr, lineInfo);
 
 1532                properties |= parseSpecialTag(tagStr);
 
 1536                if (tagStr.size() > 1 && tagStr[0] == 
'.') {
 
 1537                    tagStr = tagStr.substr(1, tagStr.size() - 1);
 
 1542                internalAppendTag(tagStr);
 
 1545        CATCH_ENFORCE( !inTag,
 
 1546                       "Found an unclosed tag while registering test case '" 
 1547                           << _nameAndTags.name << 
"' at " << _lineInfo );
 
 1552            internalAppendTag(
"."_sr);
 
 1557        tags.erase(std::unique(
begin(tags), 
end(tags)),
 
 1561    bool TestCaseInfo::isHidden()
 const {
 
 1562        return applies( properties & TestCaseProperties::IsHidden );
 
 1564    bool TestCaseInfo::throws()
 const {
 
 1565        return applies( properties & TestCaseProperties::Throws );
 
 1567    bool TestCaseInfo::okToFail()
 const {
 
 1568        return applies( properties & (TestCaseProperties::ShouldFail | TestCaseProperties::MayFail ) );
 
 1570    bool TestCaseInfo::expectedToFail()
 const {
 
 1571        return applies( properties & (TestCaseProperties::ShouldFail) );
 
 1574    void TestCaseInfo::addFilenameTag() {
 
 1575        std::string combined(
"#");
 
 1576        combined += extractFilenamePart(lineInfo.file);
 
 1577        internalAppendTag(combined);
 
 1580    std::string TestCaseInfo::tagsAsString()
 const {
 
 1583        std::size_t full_size = 2 * tags.size();
 
 1584        for (
const auto& tag : tags) {
 
 1585            full_size += tag.original.size();
 
 1587        ret.reserve(full_size);
 
 1588        for (
const auto& tag : tags) {
 
 1590            ret += tag.original;
 
 1597    void TestCaseInfo::internalAppendTag(StringRef tagStr) {
 
 1599        const auto backingStart = backingTags.size();
 
 1600        backingTags += tagStr;
 
 1601        const auto backingEnd = backingTags.size();
 
 1603        tags.emplace_back(StringRef(backingTags.c_str() + backingStart, backingEnd - backingStart));
 
 1606    bool operator<( TestCaseInfo 
const& lhs, TestCaseInfo 
const& rhs ) {
 
 1610        const auto cmpName = 
lhs.name.compare( 
rhs.name );
 
 1611        if ( cmpName != 0 ) {
 
 1614        const auto cmpClassName = 
lhs.className.compare( 
rhs.className );
 
 1615        if ( cmpClassName != 0 ) {
 
 1616            return cmpClassName < 0;
 
 1618        return lhs.tags < 
rhs.tags;
 
 1621    TestCaseInfo 
const& TestCaseHandle::getTestCaseInfo()
 const {
 
 1636    TestSpec::Pattern::Pattern( std::string 
const& 
name )
 
 1640    TestSpec::Pattern::~Pattern() = 
default;
 
 1642    std::string 
const& TestSpec::Pattern::name()
 const {
 
 1647    TestSpec::NamePattern::NamePattern( std::string 
const& 
name, std::string 
const& filterString )
 
 1648    : Pattern( filterString )
 
 1652    bool TestSpec::NamePattern::matches( TestCaseInfo 
const& testCase )
 const {
 
 1653        return m_wildcardPattern.matches( testCase.name );
 
 1656    void TestSpec::NamePattern::serializeTo( std::ostream& out )
 const {
 
 1657        out << 
'"' << 
name() << 
'"';
 
 1661    TestSpec::TagPattern::TagPattern( std::string 
const& tag, std::string 
const& filterString )
 
 1662    : Pattern( filterString )
 
 1666    bool TestSpec::TagPattern::matches( TestCaseInfo 
const& testCase )
 const {
 
 1667        return std::find( 
begin( testCase.tags ),
 
 1668                          end( testCase.tags ),
 
 1669                          Tag( m_tag ) ) != 
end( testCase.tags );
 
 1672    void TestSpec::TagPattern::serializeTo( std::ostream& out )
 const {
 
 1676    bool TestSpec::Filter::matches( TestCaseInfo 
const& testCase )
 const {
 
 1677        bool should_use = !testCase.isHidden();
 
 1678        for (
auto const& 
pattern : m_required) {
 
 1680            if (!
pattern->matches(testCase)) {
 
 1684        for (
auto const& 
pattern : m_forbidden) {
 
 1685            if (
pattern->matches(testCase)) {
 
 1692    void TestSpec::Filter::serializeTo( std::ostream& out )
 const {
 
 1694        for ( 
auto const& 
pattern : m_required ) {
 
 1701        for ( 
auto const& 
pattern : m_forbidden ) {
 
 1711    std::string TestSpec::extractFilterName( Filter 
const& 
filter ) {
 
 1712        Catch::ReusableStringStream sstr;
 
 1717    bool TestSpec::hasFilters()
 const {
 
 1718        return !m_filters.empty();
 
 1721    bool TestSpec::matches( TestCaseInfo 
const& testCase )
 const {
 
 1722        return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter 
const& 
f ){ return f.matches( testCase ); } );
 
 1725    TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCaseHandle> 
const& testCases, IConfig 
const& config )
 const {
 
 1727        matches.reserve( m_filters.size() );
 
 1728        for ( 
auto const& 
filter : m_filters ) {
 
 1729            std::vector<TestCaseHandle const*> currentMatches;
 
 1730            for ( 
auto const& 
test : testCases )
 
 1733                    currentMatches.emplace_back( &
test );
 
 1735                FilterMatch{ extractFilterName( 
filter ), currentMatches } );
 
 1740    const TestSpec::vectorStrings& TestSpec::getInvalidSpecs()
 const {
 
 1741        return m_invalidSpecs;
 
 1744    void TestSpec::serializeTo( std::ostream& out )
 const {
 
 1746        for ( 
auto const& 
filter : m_filters ) {
 
 1764        static auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
 
 1765            return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
 
 1769    void Timer::start() {
 
 1770       m_nanoseconds = getCurrentNanosecondsSinceEpoch();
 
 1772    auto Timer::getElapsedNanoseconds() const -> uint64_t {
 
 1773        return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;
 
 1775    auto Timer::getElapsedMicroseconds() const -> uint64_t {
 
 1776        return getElapsedNanoseconds()/1000;
 
 1778    auto Timer::getElapsedMilliseconds() const -> 
unsigned int {
 
 1779        return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
 
 1781    auto Timer::getElapsedSeconds() const -> 
double {
 
 1782        return getElapsedMicroseconds()/1000000.0;
 
 1799        const int hexThreshold = 255;
 
 1802            enum Arch { Big, Little };
 
 1804            static Arch which() {
 
 1808                auto value = *
reinterpret_cast<char*
>(&
one);
 
 1809                return value ? Little : Big;
 
 1813        template<
typename T>
 
 1819            ReusableStringStream rss;
 
 1823            std::string d = rss.str();
 
 1824            std::size_t 
i = d.find_last_not_of(
'0');
 
 1825            if (
i != std::string::npos && 
i != d.size() - 1) {
 
 1828                d = d.substr(0, 
i + 1);
 
 1834    std::string convertIntoString(StringRef 
string, 
bool escape_invisibles) {
 
 1838        ret.reserve(
string.
size() + 2);
 
 1840        if (!escape_invisibles) {
 
 1872    std::string convertIntoString(StringRef 
string) {
 
 1873        return convertIntoString(
string, getCurrentContext().getConfig()->showInvisibles());
 
 1876    std::string rawMemoryToString( 
const void *
object, std::size_t 
size ) {
 
 1878        int i = 0, 
end = 
static_cast<int>( 
size ), inc = 1;
 
 1879        if( Endianness::which() == Endianness::Little ) {
 
 1884        unsigned char const *bytes = 
static_cast<unsigned char const *
>(
object);
 
 1885        ReusableStringStream rss;
 
 1886        rss << 
"0x" << std::setfill(
'0') << std::hex;
 
 1887        for( ; 
i != 
end; 
i += inc )
 
 1888             rss << std::setw(2) << 
static_cast<unsigned>(bytes[
i]);
 
 
 1901std::string StringMaker<std::string>::convert(
const std::string& 
str) {
 
 1902    return Detail::convertIntoString( 
str );
 
 1905#ifdef CATCH_CONFIG_CPP17_STRING_VIEW 
 1906std::string StringMaker<std::string_view>::convert(std::string_view 
str) {
 
 1907    return Detail::convertIntoString( StringRef( 
str.data(), 
str.size() ) );
 
 1911std::string StringMaker<char const*>::convert(
char const* 
str) {
 
 1913        return Detail::convertIntoString( 
str );
 
 1915        return{ 
"{null string}" };
 
 1918std::string StringMaker<char*>::convert(
char* 
str) {
 
 1920        return Detail::convertIntoString( 
str );
 
 1922        return{ 
"{null string}" };
 
 1926#ifdef CATCH_CONFIG_WCHAR 
 1927std::string StringMaker<std::wstring>::convert(
const std::wstring& wstr) {
 
 1929    s.reserve(wstr.size());
 
 1930    for (
auto c : wstr) {
 
 1931        s += (c <= 0xff) ? static_cast<char>(
c) : 
'?';
 
 1933    return ::Catch::Detail::stringify(s);
 
 1936# ifdef CATCH_CONFIG_CPP17_STRING_VIEW 
 1937std::string StringMaker<std::wstring_view>::convert(std::wstring_view 
str) {
 
 1938    return StringMaker<std::wstring>::convert(std::wstring(
str));
 
 1942std::string StringMaker<wchar_t const*>::convert(
wchar_t const * 
str) {
 
 1944        return ::Catch::Detail::stringify(std::wstring{ 
str });
 
 1946        return{ 
"{null string}" };
 
 1949std::string StringMaker<wchar_t *>::convert(
wchar_t * 
str) {
 
 1951        return ::Catch::Detail::stringify(std::wstring{ 
str });
 
 1953        return{ 
"{null string}" };
 
 1958#if defined(CATCH_CONFIG_CPP17_BYTE) 
 1960std::string StringMaker<std::byte>::convert(std::byte 
value) {
 
 1961    return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(
value));
 
 1965std::string StringMaker<int>::convert(
int value) {
 
 1966    return ::Catch::Detail::stringify(
static_cast<long long>(
value));
 
 1968std::string StringMaker<long>::convert(
long value) {
 
 1969    return ::Catch::Detail::stringify(
static_cast<long long>(
value));
 
 1971std::string StringMaker<long long>::convert(
long long value) {
 
 1972    ReusableStringStream rss;
 
 1974    if (
value > Detail::hexThreshold) {
 
 1975        rss << 
" (0x" << std::hex << 
value << 
')';
 
 1980std::string StringMaker<unsigned int>::convert(
unsigned int value) {
 
 1981    return ::Catch::Detail::stringify(
static_cast<unsigned long long>(
value));
 
 1983std::string StringMaker<unsigned long>::convert(
unsigned long value) {
 
 1984    return ::Catch::Detail::stringify(
static_cast<unsigned long long>(
value));
 
 1986std::string StringMaker<unsigned long long>::convert(
unsigned long long value) {
 
 1987    ReusableStringStream rss;
 
 1989    if (
value > Detail::hexThreshold) {
 
 1990        rss << 
" (0x" << std::hex << 
value << 
')';
 
 1995std::string StringMaker<signed char>::convert(
signed char value) {
 
 1996    if (
value == 
'\r') {
 
 1998    } 
else if (
value == 
'\f') {
 
 2000    } 
else if (
value == 
'\n') {
 
 2002    } 
else if (
value == 
'\t') {
 
 2005        return ::Catch::Detail::stringify(
static_cast<unsigned int>(
value));
 
 2007        char chstr[] = 
"' '";
 
 2012std::string StringMaker<char>::convert(
char c) {
 
 2013    return ::Catch::Detail::stringify(
static_cast<signed char>(
c));
 
 2015std::string StringMaker<unsigned char>::convert(
unsigned char c) {
 
 2016    return ::Catch::Detail::stringify(
static_cast<char>(
c));
 
 2019int StringMaker<float>::precision = 5;
 
 2021std::string StringMaker<float>::convert(
float value) {
 
 2025int StringMaker<double>::precision = 10;
 
 2027std::string StringMaker<double>::convert(
double value) {
 
 2037    Counts Counts::operator - ( Counts 
const& 
other )
 const {
 
 2039        diff.passed = passed - 
other.passed;
 
 2041        diff.failedButOk = failedButOk - 
other.failedButOk;
 
 2042        diff.skipped = skipped - 
other.skipped;
 
 2046    Counts& Counts::operator += ( Counts 
const& 
other ) {
 
 2047        passed += 
other.passed;
 
 2049        failedButOk += 
other.failedButOk;
 
 2050        skipped += 
other.skipped;
 
 2054    std::uint64_t Counts::total()
 const {
 
 2055        return passed + 
failed + failedButOk + skipped;
 
 2057    bool Counts::allPassed()
 const {
 
 2058        return failed == 0 && failedButOk == 0 && skipped == 0;
 
 2060    bool Counts::allOk()
 const {
 
 2064    Totals Totals::operator - ( Totals 
const& 
other )
 const {
 
 2066        diff.assertions = assertions - 
other.assertions;
 
 2067        diff.testCases = testCases - 
other.testCases;
 
 2071    Totals& Totals::operator += ( Totals 
const& 
other ) {
 
 2072        assertions += 
other.assertions;
 
 2073        testCases += 
other.testCases;
 
 2077    Totals Totals::delta( Totals 
const& prevTotals )
 const {
 
 2078        Totals diff = *
this - prevTotals;
 
 2079        if( diff.assertions.failed > 0 )
 
 2080            ++diff.testCases.failed;
 
 2081        else if( diff.assertions.failedButOk > 0 )
 
 2082            ++diff.testCases.failedButOk;
 
 2083        else if ( diff.assertions.skipped > 0 )
 
 2084            ++ diff.testCases.skipped;
 
 2086            ++diff.testCases.passed;
 
 2098            Detail::unique_ptr<IExceptionTranslator>&& translator ) {
 
 2100                CATCH_MOVE( translator ) );
 
 
 2111        (   
unsigned int _majorVersion,
 
 2112            unsigned int _minorVersion,
 
 2113            unsigned int _patchNumber,
 
 2114            char const * 
const _branchName,
 
 2115            unsigned int _buildNumber )
 
 2116    :   majorVersion( _majorVersion ),
 
 2117        minorVersion( _minorVersion ),
 
 2118        patchNumber( _patchNumber ),
 
 2119        branchName( _branchName ),
 
 2120        buildNumber( _buildNumber )
 
 2124        os  << 
version.majorVersion << 
'.' 
 2125            << 
version.minorVersion << 
'.' 
 2129            os << 
'-' << 
version.branchName
 
 2130               << 
'.' << 
version.buildNumber;
 
 
 2136        static Version 
version( 3, 4, 0, 
"", 0 );
 
 
 2147    const char* GeneratorException::what() const noexcept {
 
 2158    IGeneratorTracker::~IGeneratorTracker() = 
default;
 
 2160namespace Generators {
 
 2166        Catch::throw_exception(GeneratorException{ 
msg });
 
 
 
 2170    GeneratorUntypedBase::~GeneratorUntypedBase() = 
default;
 
 2173        return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
 
 
 2177                                 SourceLineInfo lineInfo,
 
 2178                                 GeneratorBasePtr&& generator ) {
 
 2180            generatorName, lineInfo, CATCH_MOVE( generator ) );
 
 
 
 2190std::uint32_t Catch::Generators::Detail::getSeed() { 
return sharedRng()(); }
 
 2196    IResultCapture::~IResultCapture() = 
default;
 
 2203    IConfig::~IConfig() = 
default;
 
 2210    IExceptionTranslator::~IExceptionTranslator() = 
default;
 
 2211    IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = 
default;
 
 2219    namespace Generators {
 
 2221        bool GeneratorUntypedBase::countedNext() {
 
 2224                m_stringReprCache.clear();
 
 2225                ++m_currentElementIndex;
 
 2230        StringRef GeneratorUntypedBase::currentElementAsString()
 const {
 
 2231            if ( m_stringReprCache.empty() ) {
 
 2232                m_stringReprCache = stringifyImpl();
 
 2234            return m_stringReprCache;
 
 2244    IRegistryHub::~IRegistryHub() = 
default;
 
 2245    IMutableRegistryHub::~IMutableRegistryHub() = 
default;
 
 2256    ReporterConfig::ReporterConfig(
 
 2257        IConfig 
const* _fullConfig,
 
 2258        Detail::unique_ptr<IStream> _stream,
 
 2259        ColourMode colourMode,
 
 2260        std::map<std::string, std::string> customOptions ):
 
 2261        m_stream( CATCH_MOVE(_stream) ),
 
 2262        m_fullConfig( _fullConfig ),
 
 2263        m_colourMode( colourMode ),
 
 2264        m_customOptions( CATCH_MOVE( customOptions ) ) {}
 
 2266    Detail::unique_ptr<IStream> ReporterConfig::takeStream() && {
 
 2268        return CATCH_MOVE( m_stream );
 
 2270    IConfig 
const * ReporterConfig::fullConfig()
 const { 
return m_fullConfig; }
 
 2271    ColourMode ReporterConfig::colourMode()
 const { 
return m_colourMode; }
 
 2273    std::map<std::string, std::string> 
const&
 
 2274    ReporterConfig::customOptions()
 const {
 
 2275        return m_customOptions;
 
 2278    ReporterConfig::~ReporterConfig() = 
default;
 
 2280    AssertionStats::AssertionStats( AssertionResult 
const& _assertionResult,
 
 2281                                    std::vector<MessageInfo> 
const& _infoMessages,
 
 2282                                    Totals 
const& _totals )
 
 2283    :   assertionResult( _assertionResult ),
 
 2284        infoMessages( _infoMessages ),
 
 2287        if( assertionResult.hasMessage() ) {
 
 2290            MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
 
 2291            builder.m_info.message = 
static_cast<std::string
>(assertionResult.getMessage());
 
 2293            infoMessages.push_back( CATCH_MOVE(builder.m_info) );
 
 2297    SectionStats::SectionStats(  SectionInfo&& _sectionInfo,
 
 2298                                 Counts 
const& _assertions,
 
 2299                                 double _durationInSeconds,
 
 2300                                 bool _missingAssertions )
 
 2301    :   sectionInfo( CATCH_MOVE(_sectionInfo) ),
 
 2302        assertions( _assertions ),
 
 2303        durationInSeconds( _durationInSeconds ),
 
 2304        missingAssertions( _missingAssertions )
 
 2308    TestCaseStats::TestCaseStats(  TestCaseInfo 
const& _testInfo,
 
 2309                                   Totals 
const& _totals,
 
 2310                                   std::string&& _stdOut,
 
 2311                                   std::string&& _stdErr,
 
 2313    : testInfo( &_testInfo ),
 
 2315        stdOut( CATCH_MOVE(_stdOut) ),
 
 2316        stdErr( CATCH_MOVE(_stdErr) ),
 
 2317        aborting( _aborting )
 
 2321    TestRunStats::TestRunStats(   TestRunInfo 
const& _runInfo,
 
 2322                    Totals 
const& _totals,
 
 2324    :   runInfo( _runInfo ),
 
 2326        aborting( _aborting )
 
 2329    IEventListener::~IEventListener() = 
default;
 
 2337    IReporterFactory::~IReporterFactory() = 
default;
 
 2338    EventListenerFactory::~EventListenerFactory() = 
default;
 
 2345    ITestCaseRegistry::~ITestCaseRegistry() = 
default;
 
 2352    AssertionHandler::AssertionHandler
 
 2353        (   StringRef macroName,
 
 2354            SourceLineInfo 
const& lineInfo,
 
 2355            StringRef capturedExpression,
 
 2356            ResultDisposition::Flags resultDisposition )
 
 2357    :   m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
 
 2360        m_resultCapture.notifyAssertionStarted( m_assertionInfo );
 
 2363    void AssertionHandler::handleExpr( ITransientExpression 
const& expr ) {
 
 2364        m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
 
 2366    void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef 
message) {
 
 2367        m_resultCapture.handleMessage( m_assertionInfo, resultType, 
message, m_reaction );
 
 2370    auto AssertionHandler::allowThrows() const -> 
bool {
 
 2371        return getCurrentContext().getConfig()->allowThrows();
 
 2374    void AssertionHandler::complete() {
 
 2376        if( m_reaction.shouldDebugBreak ) {
 
 2382            CATCH_BREAK_INTO_DEBUGGER();
 
 2384        if (m_reaction.shouldThrow) {
 
 2387        if ( m_reaction.shouldSkip ) {
 
 2392    void AssertionHandler::handleUnexpectedInflightException() {
 
 2396    void AssertionHandler::handleExceptionThrownAsExpected() {
 
 2397        m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
 
 2399    void AssertionHandler::handleExceptionNotThrownAsExpected() {
 
 2400        m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
 
 2403    void AssertionHandler::handleUnexpectedExceptionNotThrown() {
 
 2404        m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
 
 2407    void AssertionHandler::handleThrowingCallSkipped() {
 
 2408        m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
 
 2427        bool CaseInsensitiveLess::operator()( StringRef lhs,
 
 2428                                              StringRef rhs )
 const {
 
 2429            return std::lexicographical_compare(
 
 2432                []( 
char l, 
char r ) { return toLower( l ) < toLower( r ); } );
 
 2436        CaseInsensitiveEqualTo::operator()( StringRef lhs,
 
 2437                                            StringRef rhs )
 const {
 
 2441                []( 
char l, 
char r ) { return toLower( l ) == toLower( r ); } );
 
 2454    bool isOptPrefix( 
char c ) {
 
 2456#ifdef CATCH_PLATFORM_WINDOWS 
 2462    std::string normaliseOpt( std::string 
const& optName ) {
 
 2463#ifdef CATCH_PLATFORM_WINDOWS 
 2464        if ( optName[0] == 
'/' )
 
 2465            return "-" + optName.substr( 1 );
 
 2477            void TokenStream::loadBuffer() {
 
 2478                m_tokenBuffer.clear();
 
 2481                while ( it != itEnd && it->empty() ) {
 
 2485                if ( it != itEnd ) {
 
 2486                    auto const& next = *it;
 
 2487                    if ( isOptPrefix( next[0] ) ) {
 
 2488                        auto delimiterPos = next.find_first_of( 
" :=" );
 
 2489                        if ( delimiterPos != std::string::npos ) {
 
 2490                            m_tokenBuffer.push_back(
 
 2491                                { TokenType::Option,
 
 2492                                  next.substr( 0, delimiterPos ) } );
 
 2493                            m_tokenBuffer.push_back(
 
 2494                                { TokenType::Argument,
 
 2495                                  next.substr( delimiterPos + 1 ) } );
 
 2497                            if ( next[1] != 
'-' && next.size() > 2 ) {
 
 2498                                std::string opt = 
"- ";
 
 2499                                for ( 
size_t i = 1; 
i < next.size(); ++
i ) {
 
 2501                                    m_tokenBuffer.push_back(
 
 2502                                        { TokenType::Option, opt } );
 
 2505                                m_tokenBuffer.push_back(
 
 2506                                    { TokenType::Option, next } );
 
 2510                        m_tokenBuffer.push_back(
 
 2511                            { TokenType::Argument, next } );
 
 2516            TokenStream::TokenStream( Args 
const& args ):
 
 2517                TokenStream( args.m_args.begin(), args.m_args.end() ) {}
 
 2519            TokenStream::TokenStream( Iterator it_, Iterator itEnd_ ):
 
 2520                it( it_ ), itEnd( itEnd_ ) {
 
 2524            TokenStream& TokenStream::operator++() {
 
 2525                if ( m_tokenBuffer.size() >= 2 ) {
 
 2526                    m_tokenBuffer.erase( m_tokenBuffer.begin() );
 
 2538                return ParserResult::ok( ParseResultType::Matched );
 
 
 2545                if ( srcLC == 
"y" || srcLC == 
"1" || srcLC == 
"true" ||
 
 2546                     srcLC == 
"yes" || srcLC == 
"on" ) {
 
 2548                } 
else if ( srcLC == 
"n" || srcLC == 
"0" || srcLC == 
"false" ||
 
 2549                            srcLC == 
"no" || srcLC == 
"off" ) {
 
 2552                    return ParserResult::runtimeError(
 
 2553                        "Expected a boolean value but did not recognise: '" +
 
 2556                return ParserResult::ok( ParseResultType::Matched );
 
 
 2559            size_t ParserBase::cardinality()
 const { 
return 1; }
 
 2561            InternalParseResult ParserBase::parse( Args 
const& args )
 const {
 
 2562                return parse( args.exeName(), TokenStream( args ) );
 
 2565            ParseState::ParseState( ParseResultType 
type,
 
 2566                                    TokenStream 
const& remainingTokens ):
 
 2567                m_type( 
type ), m_remainingTokens( remainingTokens ) {}
 
 2569            ParserResult BoundFlagRef::setFlag( 
bool flag ) {
 
 2571                return ParserResult::ok( ParseResultType::Matched );
 
 2574            ResultBase::~ResultBase() = 
default;
 
 2576            bool BoundRef::isContainer()
 const { 
return false; }
 
 2578            bool BoundRef::isFlag()
 const { 
return false; }
 
 2580            bool BoundFlagRefBase::isFlag()
 const { 
return true; }
 
 
 2584        Detail::InternalParseResult Arg::parse(std::string 
const&,
 
 2585                                               Detail::TokenStream 
const& tokens)
 const {
 
 2586            auto validationResult = validate();
 
 2587            if (!validationResult)
 
 2588                return Detail::InternalParseResult(validationResult);
 
 2590            auto remainingTokens = tokens;
 
 2591            auto const& token = *remainingTokens;
 
 2592            if (token.type != Detail::TokenType::Argument)
 
 2593                return Detail::InternalParseResult::ok(Detail::ParseState(
 
 2594                    ParseResultType::NoMatch, remainingTokens));
 
 2596            assert(!m_ref->isFlag());
 
 2598                static_cast<Detail::BoundValueRefBase*
>(m_ref.get());
 
 2600            auto result = valueRef->setValue(remainingTokens->token);
 
 2602                return Detail::InternalParseResult(
result);
 
 2604                return Detail::InternalParseResult::ok(Detail::ParseState(
 
 2605                    ParseResultType::Matched, ++remainingTokens));
 
 2608        Opt::Opt(
bool& 
ref) :
 
 2609            ParserRefImpl(
std::make_shared<Detail::BoundFlagRef>(
ref)) {}
 
 2611        std::vector<Detail::HelpColumns> Opt::getHelpColumns()
 const {
 
 2612            std::ostringstream oss;
 
 2614            for (
auto const& opt : m_optNames) {
 
 2621            if (!m_hint.empty())
 
 2622                oss << 
" <" << m_hint << 
'>';
 
 2623            return { { oss.str(), m_description } };
 
 2626        bool Opt::isMatch(std::string 
const& optToken)
 const {
 
 2627            auto normalisedToken = normaliseOpt(optToken);
 
 2628            for (
auto const& 
name : m_optNames) {
 
 2629                if (normaliseOpt(
name) == normalisedToken)
 
 2635        Detail::InternalParseResult Opt::parse(std::string 
const&,
 
 2636                                       Detail::TokenStream 
const& tokens)
 const {
 
 2637            auto validationResult = validate();
 
 2638            if (!validationResult)
 
 2639                return Detail::InternalParseResult(validationResult);
 
 2641            auto remainingTokens = tokens;
 
 2642            if (remainingTokens &&
 
 2643                remainingTokens->type == Detail::TokenType::Option) {
 
 2644                auto const& token = *remainingTokens;
 
 2645                if (isMatch(token.token)) {
 
 2646                    if (m_ref->isFlag()) {
 
 2648                            static_cast<Detail::BoundFlagRefBase*
>(
 
 2650                        auto result = flagRef->setFlag(
true);
 
 2652                            return Detail::InternalParseResult(
result);
 
 2654                            ParseResultType::ShortCircuitAll)
 
 2655                            return Detail::InternalParseResult::ok(Detail::ParseState(
 
 2656                                result.value(), remainingTokens));
 
 2659                            static_cast<Detail::BoundValueRefBase*
>(
 
 2662                        if (!remainingTokens)
 
 2663                            return Detail::InternalParseResult::runtimeError(
 
 2664                                "Expected argument following " +
 
 2666                        auto const& argToken = *remainingTokens;
 
 2667                        if (argToken.type != Detail::TokenType::Argument)
 
 2668                            return Detail::InternalParseResult::runtimeError(
 
 2669                                "Expected argument following " +
 
 2671                        const auto result = valueRef->setValue(argToken.token);
 
 2673                            return Detail::InternalParseResult(
result);
 
 2675                            ParseResultType::ShortCircuitAll)
 
 2676                            return Detail::InternalParseResult::ok(Detail::ParseState(
 
 2677                                result.value(), remainingTokens));
 
 2679                    return Detail::InternalParseResult::ok(Detail::ParseState(
 
 2680                        ParseResultType::Matched, ++remainingTokens));
 
 2683            return Detail::InternalParseResult::ok(
 
 2684                Detail::ParseState(ParseResultType::NoMatch, remainingTokens));
 
 2687        Detail::Result Opt::validate()
 const {
 
 2688            if (m_optNames.empty())
 
 2689                return Detail::Result::logicError(
"No options supplied to Opt");
 
 2690            for (
auto const& 
name : m_optNames) {
 
 2692                    return Detail::Result::logicError(
 
 2693                        "Option name cannot be empty");
 
 2694#ifdef CATCH_PLATFORM_WINDOWS 
 2695                if (
name[0] != 
'-' && 
name[0] != 
'/')
 
 2696                    return Detail::Result::logicError(
 
 2697                        "Option name must begin with '-' or '/'");
 
 2700                    return Detail::Result::logicError(
 
 2701                        "Option name must begin with '-'");
 
 2704            return ParserRefImpl::validate();
 
 2707        ExeName::ExeName() :
 
 2708            m_name(
std::make_shared<
std::
string>(
"<executable>")) {}
 
 2710        ExeName::ExeName(std::string& 
ref) : ExeName() {
 
 2711            m_ref = std::make_shared<Detail::BoundValueRef<std::string>>(
ref);
 
 2714        Detail::InternalParseResult
 
 2715            ExeName::parse(std::string 
const&,
 
 2716                           Detail::TokenStream 
const& tokens)
 const {
 
 2717            return Detail::InternalParseResult::ok(
 
 2718                Detail::ParseState(ParseResultType::NoMatch, tokens));
 
 2721        ParserResult ExeName::set(std::string 
const& newName) {
 
 2722            auto lastSlash = newName.find_last_of(
"\\/");
 
 2723            auto filename = (lastSlash == std::string::npos)
 
 2725                : newName.substr(lastSlash + 1);
 
 2731                return ParserResult::ok(ParseResultType::Matched);
 
 2737        Parser& Parser::operator|=( Parser 
const& 
other ) {
 
 2738            m_options.insert( m_options.end(),
 
 2739                              other.m_options.begin(),
 
 2740                              other.m_options.end() );
 
 2742                m_args.end(), 
other.m_args.begin(), 
other.m_args.end() );
 
 2746        std::vector<Detail::HelpColumns> Parser::getHelpColumns()
 const {
 
 2747            std::vector<Detail::HelpColumns> 
cols;
 
 2748            for ( 
auto const& o : m_options ) {
 
 2749                auto childCols = o.getHelpColumns();
 
 2750                cols.insert( 
cols.end(), childCols.begin(), childCols.end() );
 
 2755        void Parser::writeToStream( std::ostream& os )
 const {
 
 2756            if ( !m_exeName.name().empty() ) {
 
 2758                   << 
"  " << m_exeName.name() << 
' ';
 
 2759                bool required = 
true, 
first = 
true;
 
 2760                for ( 
auto const& arg : m_args ) {
 
 2765                    if ( arg.isOptional() && required ) {
 
 2769                    os << 
'<' << arg.hint() << 
'>';
 
 2770                    if ( arg.cardinality() == 0 )
 
 2775                if ( !m_options.empty() )
 
 2777                os << 
"\n\nwhere options are:\n";
 
 2780            auto rows = getHelpColumns();
 
 2781            size_t consoleWidth = CATCH_CONFIG_CONSOLE_WIDTH;
 
 2782            size_t optWidth = 0;
 
 2786            optWidth = ( std::min )( optWidth, consoleWidth / 2 );
 
 2789                auto row = TextFlow::Column( 
cols.left )
 
 2793                           TextFlow::Column( 
cols.right )
 
 2794                               .width( consoleWidth - 7 - optWidth );
 
 2799        Detail::Result Parser::validate()
 const {
 
 2800            for ( 
auto const& opt : m_options ) {
 
 2801                auto result = opt.validate();
 
 2805            for ( 
auto const& arg : m_args ) {
 
 2806                auto result = arg.validate();
 
 2810            return Detail::Result::ok();
 
 2813        Detail::InternalParseResult
 
 2814        Parser::parse( std::string 
const& exeName,
 
 2815                       Detail::TokenStream 
const& tokens )
 const {
 
 2818                ParserBase 
const* parser = 
nullptr;
 
 2821            std::vector<ParserInfo> parseInfos;
 
 2822            parseInfos.reserve( m_options.size() + m_args.size() );
 
 2823            for ( 
auto const& opt : m_options ) {
 
 2824                parseInfos.push_back( { &opt, 0 } );
 
 2826            for ( 
auto const& arg : m_args ) {
 
 2827                parseInfos.push_back( { &arg, 0 } );
 
 2830            m_exeName.set( exeName );
 
 2832            auto result = Detail::InternalParseResult::ok(
 
 2833                Detail::ParseState( ParseResultType::NoMatch, tokens ) );
 
 2834            while ( 
result.value().remainingTokens() ) {
 
 2835                bool tokenParsed = 
false;
 
 2837                for ( 
auto& parseInfo : parseInfos ) {
 
 2838                    if ( parseInfo.parser->cardinality() == 0 ||
 
 2839                         parseInfo.count < parseInfo.parser->cardinality() ) {
 
 2840                        result = parseInfo.parser->parse(
 
 2841                            exeName, 
result.value().remainingTokens() );
 
 2844                        if ( 
result.value().type() !=
 
 2845                             ParseResultType::NoMatch ) {
 
 2853                if ( 
result.value().type() == ParseResultType::ShortCircuitAll )
 
 2856                    return Detail::InternalParseResult::runtimeError(
 
 2857                        "Unrecognised token: " +
 
 2858                        result.value().remainingTokens()->token );
 
 2864        Args::Args(
int argc, 
char const* 
const* argv) :
 
 2865            m_exeName(argv[0]), m_args(argv + 1, argv + argc) {}
 
 2867        Args::Args(std::initializer_list<std::string> args) :
 
 2868            m_exeName(*args.
begin()),
 
 2869            m_args(args.
begin() + 1, args.
end()) {}
 
 2872        Help::Help( 
bool& showHelpFlag ):
 
 2873            Opt( [&]( 
bool flag ) {
 
 2874                showHelpFlag = flag;
 
 2875                return ParserResult::ok( ParseResultType::ShortCircuitAll );
 
 2877            static_cast<Opt&
> ( *this )(
 
 2878                "display usage information" )[
"-?"][
"-h"][
"--help"]
 
 
 2895        using namespace Clara;
 
 2897        auto const setWarning = [&]( std::string 
const& warning ) {
 
 2898            if ( warning == 
"NoAssertions" ) {
 
 2899                config.warnings = 
static_cast<WarnAbout::What
>(config.warnings | WarnAbout::NoAssertions);
 
 2900                return ParserResult::ok( ParseResultType::Matched );
 
 2901            } 
else if ( warning == 
"UnmatchedTestSpec" ) {
 
 2902                config.warnings = 
static_cast<WarnAbout::What
>(config.warnings | WarnAbout::UnmatchedTestSpec);
 
 2903                return ParserResult::ok( ParseResultType::Matched );
 
 2906            return ParserResult ::runtimeError(
 
 2907                "Unrecognised warning option: '" + warning + 
'\'' );
 
 2909        auto const loadTestNamesFromFile = [&]( std::string 
const& 
filename ) {
 
 2912                    return ParserResult::runtimeError( 
"Unable to load input file: '" + 
filename + 
'\'' );
 
 2915                while( std::getline( 
f, line ) ) {
 
 2917                    if( !line.empty() && !
startsWith( line, 
'#' ) ) {
 
 2919                            line = 
'"' + line + 
'"';
 
 2920                        config.testsOrTags.push_back( line );
 
 2921                        config.testsOrTags.emplace_back( 
"," );
 
 2925                if(!config.testsOrTags.empty())
 
 2926                    config.testsOrTags.erase( config.testsOrTags.end()-1 );
 
 2928                return ParserResult::ok( ParseResultType::Matched );
 
 2930        auto const setTestOrder = [&]( std::string 
const& order ) {
 
 2932                    config.runOrder = TestRunOrder::Declared;
 
 2934                    config.runOrder = TestRunOrder::LexicographicallySorted;
 
 2936                    config.runOrder = TestRunOrder::Randomized;
 
 2938                    return ParserResult::runtimeError( 
"Unrecognised ordering: '" + order + 
'\'' );
 
 2939                return ParserResult::ok( ParseResultType::Matched );
 
 2941        auto const setRngSeed = [&]( std::string 
const& seed ) {
 
 2942                if( seed == 
"time" ) {
 
 2944                    return ParserResult::ok(ParseResultType::Matched);
 
 2945                } 
else if (seed == 
"random-device") {
 
 2947                    return ParserResult::ok(ParseResultType::Matched);
 
 2953                if ( !parsedSeed ) {
 
 2954                    return ParserResult::runtimeError( 
"Could not parse '" + seed + 
"' as seed" );
 
 2956                config.rngSeed = *parsedSeed;
 
 2957                return ParserResult::ok( ParseResultType::Matched );
 
 2959        auto const setDefaultColourMode = [&]( std::string 
const& colourMode ) {
 
 2962                return ParserResult::runtimeError(
 
 2963                    "colour mode must be one of: default, ansi, win32, " 
 2965                    colourMode + 
"' is not recognised" );
 
 2967            auto mode = *maybeMode;
 
 2968            if ( !isColourImplAvailable( 
mode ) ) {
 
 2969                return ParserResult::runtimeError(
 
 2970                    "colour mode '" + colourMode +
 
 2971                    "' is not supported in this binary" );
 
 2973            config.defaultColourMode = 
mode;
 
 2974            return ParserResult::ok( ParseResultType::Matched );
 
 2976        auto const setWaitForKeypress = [&]( std::string 
const& keypress ) {
 
 2977                auto keypressLc = 
toLower( keypress );
 
 2978                if (keypressLc == 
"never")
 
 2979                    config.waitForKeypress = WaitForKeypress::Never;
 
 2980                else if( keypressLc == 
"start" )
 
 2981                    config.waitForKeypress = WaitForKeypress::BeforeStart;
 
 2982                else if( keypressLc == 
"exit" )
 
 2983                    config.waitForKeypress = WaitForKeypress::BeforeExit;
 
 2984                else if( keypressLc == 
"both" )
 
 2985                    config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
 
 2987                    return ParserResult::runtimeError( 
"keypress argument must be one of: never, start, exit or both. '" + keypress + 
"' not recognised" );
 
 2988            return ParserResult::ok( ParseResultType::Matched );
 
 2990        auto const setVerbosity = [&]( std::string 
const& 
verbosity ) {
 
 2992            if( lcVerbosity == 
"quiet" )
 
 2993                config.verbosity = Verbosity::Quiet;
 
 2994            else if( lcVerbosity == 
"normal" )
 
 2995                config.verbosity = Verbosity::Normal;
 
 2996            else if( lcVerbosity == 
"high" )
 
 2997                config.verbosity = Verbosity::High;
 
 2999                return ParserResult::runtimeError( 
"Unrecognised verbosity, '" + 
verbosity + 
'\'' );
 
 3000            return ParserResult::ok( ParseResultType::Matched );
 
 3002        auto const setReporter = [&]( std::string 
const& userReporterSpec ) {
 
 3003            if ( userReporterSpec.empty() ) {
 
 3004                return ParserResult::runtimeError( 
"Received empty reporter spec." );
 
 3007            Optional<ReporterSpec> parsed =
 
 3010                return ParserResult::runtimeError(
 
 3011                    "Could not parse reporter spec '" + userReporterSpec +
 
 3015            auto const& reporterSpec = *parsed;
 
 3017            auto const& factories =
 
 3019            auto result = factories.find( reporterSpec.name() );
 
 3021            if ( 
result == factories.end() ) {
 
 3022                return ParserResult::runtimeError(
 
 3023                    "Unrecognized reporter, '" + reporterSpec.name() +
 
 3024                    "'. Check available with --list-reporters" );
 
 3028            const bool hadOutputFile = reporterSpec.outputFile().some();
 
 3029            config.reporterSpecifications.push_back( CATCH_MOVE( *parsed ) );
 
 3034            if (!hadOutputFile) {
 
 3035                int n_reporters_without_file = 0;
 
 3036                for (
auto const& spec : config.reporterSpecifications) {
 
 3037                    if (spec.outputFile().none()) {
 
 3038                        n_reporters_without_file++;
 
 3041                if (n_reporters_without_file > 1) {
 
 3042                    return ParserResult::runtimeError( 
"Only one reporter may have unspecified output file." );
 
 3046            return ParserResult::ok( ParseResultType::Matched );
 
 3048        auto const setShardCount = [&]( std::string 
const& 
shardCount ) {
 
 3050            if ( !parsedCount ) {
 
 3051                return ParserResult::runtimeError(
 
 3052                    "Could not parse '" + 
shardCount + 
"' as shard count" );
 
 3054            if ( *parsedCount == 0 ) {
 
 3055                return ParserResult::runtimeError(
 
 3056                    "Shard count must be positive" );
 
 3058            config.shardCount = *parsedCount;
 
 3059            return ParserResult::ok( ParseResultType::Matched );
 
 3062        auto const setShardIndex = [&](std::string 
const& 
shardIndex) {
 
 3064            if ( !parsedIndex ) {
 
 3065                return ParserResult::runtimeError(
 
 3066                    "Could not parse '" + 
shardIndex + 
"' as shard index" );
 
 3068            config.shardIndex = *parsedIndex;
 
 3069            return ParserResult::ok( ParseResultType::Matched );
 
 3073            = ExeName( config.processName )
 
 3074            | Help( config.showHelp )
 
 3075            | Opt( config.showSuccessfulTests )
 
 3077                ( 
"include successful tests in output" )
 
 3078            | Opt( config.shouldDebugBreak )
 
 3080                ( 
"break into debugger on failure" )
 
 3081            | Opt( config.noThrow )
 
 3083                ( 
"skip exception tests" )
 
 3084            | Opt( config.showInvisibles )
 
 3085                [
"-i"][
"--invisibles"]
 
 3086                ( 
"show invisibles (tabs, newlines)" )
 
 3087            | Opt( config.defaultOutputFilename, 
"filename" )
 
 3089                ( 
"default output filename" )
 
 3090            | Opt( accept_many, setReporter, 
"name[::key=value]*" )
 
 3091                [
"-r"][
"--reporter"]
 
 3092                ( 
"reporter to use (defaults to console)" )
 
 3093            | Opt( config.name, 
"name" )
 
 3096            | Opt( [&]( 
bool ){ config.abortAfter = 1; } )
 
 3098                ( 
"abort at first failure" )
 
 3099            | Opt( [&]( 
int x ){ config.abortAfter = 
x; }, 
"no. failures" )
 
 3101                ( 
"abort after x failures" )
 
 3102            | Opt( accept_many, setWarning, 
"warning name" )
 
 3104                ( 
"enable warnings" )
 
 3105            | Opt( [&]( 
bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, 
"yes|no" )
 
 3106                [
"-d"][
"--durations"]
 
 3107                ( 
"show test durations" )
 
 3108            | Opt( config.minDuration, 
"seconds" )
 
 3109                [
"-D"][
"--min-duration"]
 
 3110                ( 
"show test durations for tests taking at least the given number of seconds" )
 
 3111            | Opt( loadTestNamesFromFile, 
"filename" )
 
 3112                [
"-f"][
"--input-file"]
 
 3113                ( 
"load test names to run from a file" )
 
 3114            | Opt( config.filenamesAsTags )
 
 3115                [
"-#"][
"--filenames-as-tags"]
 
 3116                ( 
"adds a tag for the filename" )
 
 3117            | Opt( config.sectionsToRun, 
"section name" )
 
 3119                ( 
"specify section to run" )
 
 3120            | Opt( setVerbosity, 
"quiet|normal|high" )
 
 3121                [
"-v"][
"--verbosity"]
 
 3122                ( 
"set output verbosity" )
 
 3123            | Opt( config.listTests )
 
 3125                ( 
"list all/matching test cases" )
 
 3126            | Opt( config.listTags )
 
 3128                ( 
"list all/matching tags" )
 
 3129            | Opt( config.listReporters )
 
 3130                [
"--list-reporters"]
 
 3131                ( 
"list all available reporters" )
 
 3132            | Opt( config.listListeners )
 
 3133                [
"--list-listeners"]
 
 3134                ( 
"list all listeners" )
 
 3135            | Opt( setTestOrder, 
"decl|lex|rand" )
 
 3137                ( 
"test case order (defaults to decl)" )
 
 3138            | Opt( setRngSeed, 
"'time'|'random-device'|number" )
 
 3140                ( 
"set a specific seed for random numbers" )
 
 3141            | Opt( setDefaultColourMode, 
"ansi|win32|none|default" )
 
 3143                ( 
"what color mode should be used as default" )
 
 3144            | Opt( config.libIdentify )
 
 3146                ( 
"report name and version according to libidentify standard" )
 
 3147            | Opt( setWaitForKeypress, 
"never|start|exit|both" )
 
 3148                [
"--wait-for-keypress"]
 
 3149                ( 
"waits for a keypress before exiting" )
 
 3150            | Opt( config.skipBenchmarks)
 
 3151                [
"--skip-benchmarks"]
 
 3152                ( 
"disable running benchmarks")
 
 3153            | Opt( config.benchmarkSamples, 
"samples" )
 
 3154                [
"--benchmark-samples"]
 
 3155                ( 
"number of samples to collect (default: 100)" )
 
 3156            | Opt( config.benchmarkResamples, 
"resamples" )
 
 3157                [
"--benchmark-resamples"]
 
 3158                ( 
"number of resamples for the bootstrap (default: 100000)" )
 
 3159            | Opt( config.benchmarkConfidenceInterval, 
"confidence interval" )
 
 3160                [
"--benchmark-confidence-interval"]
 
 3161                ( 
"confidence interval for the bootstrap (between 0 and 1, default: 0.95)" )
 
 3162            | Opt( config.benchmarkNoAnalysis )
 
 3163                [
"--benchmark-no-analysis"]
 
 3164                ( 
"perform only measurements; do not perform any analysis" )
 
 3165            | Opt( config.benchmarkWarmupTime, 
"benchmarkWarmupTime" )
 
 3166                [
"--benchmark-warmup-time"]
 
 3167                ( 
"amount of time in milliseconds spent on warming up each test (default: 100)" )
 
 3168            | Opt( setShardCount, 
"shard count" )
 
 3170                ( 
"split the tests to execute into this many groups" )
 
 3171            | Opt( setShardIndex, 
"shard index" )
 
 3173                ( 
"index of the group of tests to execute (see --shard-count)" ) |
 
 3174            Opt( config.allowZeroTests )
 
 3175                [
"--allow-running-no-tests"]
 
 3176                ( 
"Treat 'No tests run' as a success" )
 
 3177            | Arg( config.testsOrTags, 
"test name|pattern|tags" )
 
 3178                ( 
"which test or tests to use" );
 
 
 3186#if defined(__clang__) 
 3187#    pragma clang diagnostic push 
 3188#    pragma clang diagnostic ignored "-Wexit-time-destructors" 
 3199    ColourImpl::~ColourImpl() = 
default;
 
 3201    ColourImpl::ColourGuard ColourImpl::guardColour( Colour::Code colourCode ) {
 
 3202        return ColourGuard(colourCode, 
this );
 
 3205    void ColourImpl::ColourGuard::engageImpl( std::ostream& 
stream ) {
 
 3206        assert( &
stream == &m_colourImpl->m_stream->stream() &&
 
 3207                "Engaging colour guard for different stream than used by the " 
 3208                "parent colour implementation" );
 
 3209        static_cast<void>( 
stream );
 
 3212        m_colourImpl->use( m_code );
 
 3215    ColourImpl::ColourGuard::ColourGuard( Colour::Code code,
 
 3216                                          ColourImpl 
const* colour ):
 
 3217        m_colourImpl( colour ), m_code( code ) {
 
 3219    ColourImpl::ColourGuard::ColourGuard( ColourGuard&& rhs ) 
noexcept:
 
 3220        m_colourImpl( 
rhs.m_colourImpl ),
 
 3221        m_code( 
rhs.m_code ),
 
 3222        m_engaged( 
rhs.m_engaged ) {
 
 3223        rhs.m_engaged = 
false;
 
 3225    ColourImpl::ColourGuard&
 
 3226    ColourImpl::ColourGuard::operator=( ColourGuard&& rhs ) 
noexcept {
 
 3228        swap( m_colourImpl, 
rhs.m_colourImpl );
 
 3229        swap( m_code, 
rhs.m_code );
 
 3230        swap( m_engaged, 
rhs.m_engaged );
 
 3234    ColourImpl::ColourGuard::~ColourGuard() {
 
 3236            m_colourImpl->use( Colour::None );
 
 3240    ColourImpl::ColourGuard&
 
 3241    ColourImpl::ColourGuard::engage( std::ostream& 
stream ) & {
 
 3246    ColourImpl::ColourGuard&&
 
 3247    ColourImpl::ColourGuard::engage( std::ostream& 
stream ) && {
 
 3249        return CATCH_MOVE(*
this);
 
 3255        class NoColourImpl final : 
public ColourImpl {
 
 3257            NoColourImpl( IStream* 
stream ): ColourImpl( 
stream ) {}
 
 3260            void use( Colour::Code )
 const override {}
 
 3268#if defined ( CATCH_CONFIG_COLOUR_WIN32 )  
 3273    class Win32ColourImpl final : 
public ColourImpl {
 
 3275        Win32ColourImpl(IStream* 
stream):
 
 3277            CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
 
 3278            GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ),
 
 3280            originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
 
 3281            originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
 
 3284        static bool useImplementationForStream(IStream 
const& 
stream) {
 
 3288            return stream.isConsole();
 
 3292        void use( Colour::Code _colourCode )
 const override {
 
 3293            switch( _colourCode ) {
 
 3294                case Colour::None:      
return setTextAttribute( originalForegroundAttributes );
 
 3295                case Colour::White:     
return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
 
 3296                case Colour::Red:       
return setTextAttribute( FOREGROUND_RED );
 
 3297                case Colour::Green:     
return setTextAttribute( FOREGROUND_GREEN );
 
 3298                case Colour::Blue:      
return setTextAttribute( FOREGROUND_BLUE );
 
 3299                case Colour::Cyan:      
return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
 
 3300                case Colour::Yellow:    
return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
 
 3301                case Colour::Grey:      
return setTextAttribute( 0 );
 
 3303                case Colour::LightGrey:     
return setTextAttribute( FOREGROUND_INTENSITY );
 
 3304                case Colour::BrightRed:     
return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
 
 3305                case Colour::BrightGreen:   
return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
 
 3306                case Colour::BrightWhite:   
return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
 
 3307                case Colour::BrightYellow:  
return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );
 
 3309                case Colour::Bright: CATCH_INTERNAL_ERROR( 
"not a colour" );
 
 3312                    CATCH_ERROR( 
"Unknown colour requested" );
 
 3316        void setTextAttribute( WORD _textAttribute )
 const {
 
 3317            SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ),
 
 3319                                         originalBackgroundAttributes );
 
 3321        WORD originalForegroundAttributes;
 
 3322        WORD originalBackgroundAttributes;
 
 3331#if defined( CATCH_PLATFORM_LINUX ) || defined( CATCH_PLATFORM_MAC ) 
 3332#    define CATCH_INTERNAL_HAS_ISATTY 
 3339    class ANSIColourImpl final : 
public ColourImpl {
 
 3341        ANSIColourImpl( IStream* 
stream ): ColourImpl( 
stream ) {}
 
 3343        static bool useImplementationForStream(IStream 
const& 
stream) {
 
 3351            bool useColour = 
stream.isConsole();
 
 3352#if defined( CATCH_INTERNAL_HAS_ISATTY ) && \ 
 3353    !( defined( __DJGPP__ ) && defined( __STRICT_ANSI__ ) ) 
 3355            useColour = useColour && isatty( STDOUT_FILENO );
 
 3357#    if defined( CATCH_PLATFORM_MAC ) || defined( CATCH_PLATFORM_IPHONE ) 
 3358            useColour = useColour && !isDebuggerActive();
 
 3365        void use( Colour::Code _colourCode )
 const override {
 
 3366            auto setColour = [&out =
 
 3367                                  m_stream->stream()]( 
char const* escapeCode ) {
 
 3371                out << 
'\033' << escapeCode << std::flush;
 
 3373            switch( _colourCode ) {
 
 3375                case Colour::White:     
return setColour( 
"[0m" );
 
 3376                case Colour::Red:       
return setColour( 
"[0;31m" );
 
 3377                case Colour::Green:     
return setColour( 
"[0;32m" );
 
 3378                case Colour::Blue:      
return setColour( 
"[0;34m" );
 
 3379                case Colour::Cyan:      
return setColour( 
"[0;36m" );
 
 3380                case Colour::Yellow:    
return setColour( 
"[0;33m" );
 
 3381                case Colour::Grey:      
return setColour( 
"[1;30m" );
 
 3383                case Colour::LightGrey:     
return setColour( 
"[0;37m" );
 
 3384                case Colour::BrightRed:     
return setColour( 
"[1;31m" );
 
 3385                case Colour::BrightGreen:   
return setColour( 
"[1;32m" );
 
 3386                case Colour::BrightWhite:   
return setColour( 
"[1;37m" );
 
 3387                case Colour::BrightYellow:  
return setColour( 
"[1;33m" );
 
 3389                case Colour::Bright: CATCH_INTERNAL_ERROR( 
"not a colour" );
 
 3390                default: CATCH_INTERNAL_ERROR( 
"Unknown colour requested" );
 
 3400    Detail::unique_ptr<ColourImpl> makeColourImpl( ColourMode implSelection,
 
 3402#if defined( CATCH_CONFIG_COLOUR_WIN32 ) 
 3403        if ( implSelection == ColourMode::Win32 ) {
 
 3404            return Detail::make_unique<Win32ColourImpl>( 
stream );
 
 3407        if ( implSelection == ColourMode::ANSI ) {
 
 3408            return Detail::make_unique<ANSIColourImpl>( 
stream );
 
 3410        if ( implSelection == ColourMode::None ) {
 
 3411            return Detail::make_unique<NoColourImpl>( 
stream );
 
 3414        if ( implSelection == ColourMode::PlatformDefault) {
 
 3415#if defined( CATCH_CONFIG_COLOUR_WIN32 ) 
 3416            if ( Win32ColourImpl::useImplementationForStream( *
stream ) ) {
 
 3417                return Detail::make_unique<Win32ColourImpl>( 
stream );
 
 3420            if ( ANSIColourImpl::useImplementationForStream( *
stream ) ) {
 
 3421                return Detail::make_unique<ANSIColourImpl>( 
stream );
 
 3423            return Detail::make_unique<NoColourImpl>( 
stream );
 
 3426        CATCH_ERROR( 
"Could not create colour impl for selection " << 
static_cast<int>(implSelection) );
 
 3429    bool isColourImplAvailable( ColourMode colourSelection ) {
 
 3430        switch ( colourSelection ) {
 
 3431#if defined( CATCH_CONFIG_COLOUR_WIN32 ) 
 3432        case ColourMode::Win32:
 
 3434        case ColourMode::ANSI:
 
 3435        case ColourMode::None:
 
 3436        case ColourMode::PlatformDefault:
 
 3446#if defined(__clang__) 
 3447#    pragma clang diagnostic pop 
 3455    Context* Context::currentContext = 
nullptr;
 
 3457    void cleanUpContext() {
 
 3458        delete Context::currentContext;
 
 3459        Context::currentContext = 
nullptr;
 
 3461    void Context::createContext() {
 
 3462        currentContext = 
new Context();
 
 3465    Context& getCurrentMutableContext() {
 
 3466        if ( !Context::currentContext ) { Context::createContext(); }
 
 3468        return *Context::currentContext;
 
 3471    void Context::setResultCapture( IResultCapture* resultCapture ) {
 
 3472        m_resultCapture = resultCapture;
 
 3475    void Context::setConfig( IConfig 
const* config ) { m_config = config; }
 
 3477    SimplePcg32& sharedRng() {
 
 3478        static SimplePcg32 s_rng;
 
 3490#if defined(CATCH_CONFIG_ANDROID_LOGWRITE) 
 3491#include <android/log.h> 
 3494        void writeToDebugConsole( std::string 
const& text ) {
 
 3495            __android_log_write( ANDROID_LOG_DEBUG, 
"Catch", text.c_str() );
 
 3499#elif defined(CATCH_PLATFORM_WINDOWS) 
 3502        void writeToDebugConsole( std::string 
const& text ) {
 
 3503            ::OutputDebugStringA( text.c_str() );
 
 3510        void writeToDebugConsole( std::string 
const& text ) {
 
 3520#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) 
 3523#  include <sys/types.h> 
 3528#ifdef __apple_build_version__ 
 3531#  include <sys/sysctl.h> 
 3535        #ifdef __apple_build_version__ 
 3541        bool isDebuggerActive(){
 
 3543            struct kinfo_proc   info;
 
 3549            info.kp_proc.p_flag = 0;
 
 3556            mib[2] = KERN_PROC_PID;
 
 3561            size = 
sizeof(info);
 
 3562            if( sysctl(mib, 
sizeof(mib) / 
sizeof(*mib), &info, &
size, 
nullptr, 0) != 0 ) {
 
 3563                Catch::cerr() << 
"\n** Call to sysctl failed - unable to determine if debugger is active **\n\n" << std::flush;
 
 3569            return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
 
 3572        bool isDebuggerActive() {
 
 3579#elif defined(CATCH_PLATFORM_LINUX) 
 3591        bool isDebuggerActive(){
 
 3595            std::ifstream in(
"/proc/self/status");
 
 3596            for( std::string line; std::getline(in, line); ) {
 
 3597                static const int PREFIX_LEN = 11;
 
 3598                if( 
line.compare(0, PREFIX_LEN, 
"TracerPid:\t") == 0 ) {
 
 3602                    return line.length() > PREFIX_LEN && 
line[PREFIX_LEN] != 
'0';
 
 3609#elif defined(_MSC_VER) 
 3610    extern "C" __declspec(dllimport) 
int __stdcall IsDebuggerPresent();
 
 3612        bool isDebuggerActive() {
 
 3613            return IsDebuggerPresent() != 0;
 
 3616#elif defined(__MINGW32__) 
 3617    extern "C" __declspec(dllimport) 
int __stdcall IsDebuggerPresent();
 
 3619        bool isDebuggerActive() {
 
 3620            return IsDebuggerPresent() != 0;
 
 3625       bool isDebuggerActive() { 
return false; }
 
 3634    ITransientExpression::~ITransientExpression() = 
default;
 
 3636    void formatReconstructedExpression( std::ostream &os, std::string 
const& lhs, StringRef 
op, std::string 
const& rhs ) {
 
 3637        if( 
lhs.size() + 
rhs.size() < 40 &&
 
 3638                lhs.find(
'\n') == std::string::npos &&
 
 3639                rhs.find(
'\n') == std::string::npos )
 
 3640            os << 
lhs << 
' ' << 
op << 
' ' << 
rhs;
 
 3642            os << 
lhs << 
'\n' << 
op << 
'\n' << 
rhs;
 
 3652#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) 
 3654    void throw_exception(std::exception 
const& e) {
 
 3655        Catch::cerr() << 
"Catch will terminate because it needed to throw an exception.\n" 
 3656                      << 
"The message was: " << e.what() << 
'\n';
 
 3662    void throw_logic_error(std::string 
const& 
msg) {
 
 3663        throw_exception(std::logic_error(
msg));
 
 3667    void throw_domain_error(std::string 
const& 
msg) {
 
 3668        throw_exception(std::domain_error(
msg));
 
 3672    void throw_runtime_error(std::string 
const& 
msg) {
 
 3673        throw_exception(std::runtime_error(
msg));
 
 3686    IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() = 
default;
 
 3693            StringRef extractInstanceName(StringRef enumInstance) {
 
 3695                size_t name_start = enumInstance.size();
 
 3696                while (name_start > 0 && enumInstance[name_start - 1] != 
':') {
 
 3699                return enumInstance.substr(name_start, enumInstance.size() - name_start);
 
 3703        std::vector<StringRef> parseEnums( StringRef enums ) {
 
 3705            std::vector<StringRef> parsed;
 
 3706            parsed.reserve( enumValues.size() );
 
 3707            for( 
auto const& enumValue : enumValues ) {
 
 3708                parsed.push_back(
trim(extractInstanceName(enumValue)));
 
 3713        EnumInfo::~EnumInfo() {}
 
 3715        StringRef EnumInfo::lookup( 
int value )
 const {
 
 3716            for( 
auto const& valueToName : m_values ) {
 
 3717                if( valueToName.first == 
value )
 
 3718                    return valueToName.second;
 
 3720            return "{** unexpected enum value **}"_sr;
 
 3723        Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> 
const& 
values ) {
 
 3724            auto enumInfo = Catch::Detail::make_unique<EnumInfo>();
 
 3725            enumInfo->m_name = enumName;
 
 3726            enumInfo->m_values.reserve( 
values.size() );
 
 3728            const auto valueNames = Catch::Detail::parseEnums( allValueNames );
 
 3729            assert( valueNames.size() == 
values.size() );
 
 3732                enumInfo->m_values.emplace_back(
value, valueNames[
i++]);
 
 3737        EnumInfo 
const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> 
const& 
values ) {
 
 3738            m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, 
values));
 
 3739            return *m_enumInfos.back();
 
 3752        ErrnoGuard::ErrnoGuard():m_oldErrno(errno){}
 
 3753        ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; }
 
 3763        static std::string tryTranslators(
 
 3765                Detail::unique_ptr<IExceptionTranslator const>> 
const& translators ) {
 
 3766            if ( translators.empty() ) {
 
 3767                std::rethrow_exception( std::current_exception() );
 
 3769                return translators[0]->translate( translators.begin() + 1,
 
 3770                                                  translators.end() );
 
 3776    ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() {
 
 3779    void ExceptionTranslatorRegistry::registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) {
 
 3780        m_translators.push_back( CATCH_MOVE( translator ) );
 
 3783#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) 
 3784    std::string ExceptionTranslatorRegistry::translateActiveException()
 const {
 
 3793        if ( std::current_exception() == 
nullptr ) {
 
 3794            return "Non C++ exception. Possibly a CLR exception.";
 
 3800            return tryTranslators(m_translators);
 
 3804        catch( TestFailureException& ) {
 
 3805            std::rethrow_exception(std::current_exception());
 
 3807        catch( TestSkipException& ) {
 
 3808            std::rethrow_exception(std::current_exception());
 
 3810        catch( std::exception 
const& ex ) {
 
 3813        catch( std::string 
const& 
msg ) {
 
 3816        catch( 
const char* 
msg ) {
 
 3820            return "Unknown exception";
 
 3825    std::string ExceptionTranslatorRegistry::translateActiveException()
 const {
 
 3826        CATCH_INTERNAL_ERROR(
"Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
 
 3856#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS ) 
 3862    void FatalConditionHandler::engage_platform() {}
 
 3863    void FatalConditionHandler::disengage_platform() noexcept {}
 
 3864    FatalConditionHandler::FatalConditionHandler() = 
default;
 
 3865    FatalConditionHandler::~FatalConditionHandler() = 
default;
 
 3871#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS ) 
 3872#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time" 
 3875#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) 
 3879    void reportFatal( 
char const * 
const message ) {
 
 3880        Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( 
message );
 
 3886    constexpr std::size_t minStackSizeForErrors = 32 * 1024;
 
 3891#if defined( CATCH_CONFIG_WINDOWS_SEH ) 
 3895    struct SignalDefs { DWORD 
id; 
const char* 
name; };
 
 3900    static SignalDefs signalDefs[] = {
 
 3901        { EXCEPTION_ILLEGAL_INSTRUCTION,  
"SIGILL - Illegal instruction signal" },
 
 3902        { EXCEPTION_STACK_OVERFLOW, 
"SIGSEGV - Stack overflow" },
 
 3903        { EXCEPTION_ACCESS_VIOLATION, 
"SIGSEGV - Segmentation violation signal" },
 
 3904        { EXCEPTION_INT_DIVIDE_BY_ZERO, 
"Divide by zero error" },
 
 3907    static LONG CALLBACK topLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {
 
 3908        for (
auto const& def : signalDefs) {
 
 3909            if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
 
 3910                reportFatal(def.name);
 
 3915        return EXCEPTION_CONTINUE_SEARCH;
 
 3921    static LPTOP_LEVEL_EXCEPTION_FILTER previousTopLevelExceptionFilter = 
nullptr;
 
 3926    FatalConditionHandler::FatalConditionHandler() {
 
 3927        ULONG guaranteeSize = 
static_cast<ULONG
>(minStackSizeForErrors);
 
 3928        if (!SetThreadStackGuarantee(&guaranteeSize)) {
 
 3932                << 
"Failed to reserve piece of stack." 
 3933                << 
" Stack overflows will not be reported successfully.";
 
 3939    FatalConditionHandler::~FatalConditionHandler() = 
default;
 
 3942    void FatalConditionHandler::engage_platform() {
 
 3944        previousTopLevelExceptionFilter = SetUnhandledExceptionFilter(topLevelExceptionFilter);
 
 3947    void FatalConditionHandler::disengage_platform() noexcept {
 
 3948        if (SetUnhandledExceptionFilter(previousTopLevelExceptionFilter) != topLevelExceptionFilter) {
 
 3950                << 
"Unexpected SEH unhandled exception filter on disengage." 
 3951                << 
" The filter was restored, but might be rolled back unexpectedly.";
 
 3953        previousTopLevelExceptionFilter = 
nullptr;
 
 3960#if defined( CATCH_CONFIG_POSIX_SIGNALS ) 
 3972        { SIGINT,  
"SIGINT - Terminal interrupt signal" },
 
 3973        { SIGILL,  
"SIGILL - Illegal instruction signal" },
 
 3974        { SIGFPE,  
"SIGFPE - Floating point error signal" },
 
 3975        { SIGSEGV, 
"SIGSEGV - Segmentation violation signal" },
 
 3976        { SIGTERM, 
"SIGTERM - Termination request signal" },
 
 3977        { SIGABRT, 
"SIGABRT - Abort (abnormal termination) signal" }
 
 3983#if defined(__GNUC__) 
 3984#    pragma GCC diagnostic push 
 3985#    pragma GCC diagnostic ignored "-Wmissing-field-initializers" 
 3988    static char* altStackMem = 
nullptr;
 
 3989    static std::size_t altStackSize = 0;
 
 3990    static stack_t oldSigStack{};
 
 3991    static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
 
 3993    static void restorePreviousSignalHandlers() noexcept {
 
 3998        for (std::size_t 
i = 0; 
i < 
sizeof(signalDefs) / 
sizeof(SignalDefs); ++
i) {
 
 3999            sigaction(signalDefs[
i].
id, &oldSigActions[
i], 
nullptr);
 
 4002        sigaltstack(&oldSigStack, 
nullptr);
 
 4005    static void handleSignal( 
int sig ) {
 
 4006        char const * 
name = 
"<unknown signal>";
 
 4007        for (
auto const& def : signalDefs) {
 
 4008            if (sig == def.id) {
 
 4016        restorePreviousSignalHandlers();
 
 4017        reportFatal( 
name );
 
 4021    FatalConditionHandler::FatalConditionHandler() {
 
 4022        assert(!altStackMem && 
"Cannot initialize POSIX signal handler when one already exists");
 
 4023        if (altStackSize == 0) {
 
 4024            altStackSize = std::max(
static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);
 
 4026        altStackMem = 
new char[altStackSize]();
 
 4029    FatalConditionHandler::~FatalConditionHandler() {
 
 4030        delete[] altStackMem;
 
 4033        altStackMem = 
nullptr;
 
 4036    void FatalConditionHandler::engage_platform() {
 
 4038        sigStack.ss_sp = altStackMem;
 
 4039        sigStack.ss_size = altStackSize;
 
 4040        sigStack.ss_flags = 0;
 
 4041        sigaltstack(&sigStack, &oldSigStack);
 
 4042        struct sigaction sa = { };
 
 4044        sa.sa_handler = handleSignal;
 
 4045        sa.sa_flags = SA_ONSTACK;
 
 4046        for (std::size_t 
i = 0; 
i < 
sizeof(signalDefs)/
sizeof(SignalDefs); ++
i) {
 
 4047            sigaction(signalDefs[
i].
id, &sa, &oldSigActions[
i]);
 
 4051#if defined(__GNUC__) 
 4052#    pragma GCC diagnostic pop 
 4056    void FatalConditionHandler::disengage_platform() noexcept {
 
 4057        restorePreviousSignalHandlers();
 
 4073            static_assert(
sizeof(float) == 
sizeof(uint32_t), 
"Important ULP matcher assumption violated");
 
 4075            std::memcpy(&
i, &
f, 
sizeof(
f));
 
 
 4080            static_assert(
sizeof(double) == 
sizeof(uint64_t), 
"Important ULP matcher assumption violated");
 
 4082            std::memcpy(&
i, &d, 
sizeof(d));
 
 
 4099#if !defined (CATCH_CONFIG_GETENV) 
 4100        char const* 
getEnv( 
char const* ) { 
return nullptr; }
 
 4104#    if defined( _MSC_VER ) 
 4105#        pragma warning( push ) 
 4106#        pragma warning( disable : 4996 )  
 4109            return std::getenv( varName );
 
 4111#    if defined( _MSC_VER ) 
 4112#        pragma warning( pop ) 
 
 4129    Catch::IStream::~IStream() = 
default;
 
 4133        template<
typename WriterF, std::
size_t bufferSize=256>
 
 4134        class StreamBufImpl final : 
public std::streambuf {
 
 4135            char data[bufferSize];
 
 4143            ~StreamBufImpl() noexcept
 override {
 
 4144                StreamBufImpl::sync();
 
 4148            int overflow( 
int c )
 override {
 
 4152                    if( pbase() == epptr() )
 
 4153                        m_writer( std::string( 1, 
static_cast<char>( 
c ) ) );
 
 4155                        sputc( 
static_cast<char>( 
c ) );
 
 4160            int sync()
 override {
 
 4161                if( pbase() != pptr() ) {
 
 4162                    m_writer( std::string( pbase(), 
static_cast<std::string::size_type
>( pptr() - pbase() ) ) );
 
 4163                    setp( pbase(), epptr() );
 
 4171        struct OutputDebugWriter {
 
 4173            void operator()( std::string 
const& 
str ) {
 
 4174                if ( !
str.empty() ) {
 
 4175                    writeToDebugConsole( 
str );
 
 4182        class FileStream final : 
public IStream {
 
 4183            std::ofstream m_ofs;
 
 4185            FileStream( std::string 
const& 
filename ) {
 
 4187                CATCH_ENFORCE( !m_ofs.fail(), 
"Unable to open file: '" << 
filename << 
'\'' );
 
 4188                m_ofs << std::unitbuf;
 
 4190            ~FileStream() 
override = 
default;
 
 4192            std::ostream& 
stream()
 override {
 
 4199        class CoutStream final : 
public IStream {
 
 4204            CoutStream() : m_os( 
Catch::
cout().rdbuf() ) {}
 
 4205            ~CoutStream() 
override = 
default;
 
 4208            std::ostream& 
stream()
 override { 
return m_os; }
 
 4209            bool isConsole()
 const override { 
return true; }
 
 4212        class CerrStream : 
public IStream {
 
 4218            CerrStream(): m_os( 
Catch::
cerr().rdbuf() ) {}
 
 4219            ~CerrStream() 
override = 
default;
 
 4222            std::ostream& 
stream()
 override { 
return m_os; }
 
 4223            bool isConsole()
 const override { 
return true; }
 
 4228        class DebugOutStream final : 
public IStream {
 
 4229            Detail::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf;
 
 4233            :   m_streamBuf( Detail::make_unique<StreamBufImpl<OutputDebugWriter>>() ),
 
 4234                m_os( m_streamBuf.
get() )
 
 4237            ~DebugOutStream() 
override = 
default;
 
 4240            std::ostream& 
stream()
 override { 
return m_os; }
 
 4250            return Detail::make_unique<Detail::CoutStream>();
 
 4254                return Detail::make_unique<Detail::DebugOutStream>();
 
 4255            } 
else if ( 
filename == 
"%stderr" ) {
 
 4256                return Detail::make_unique<Detail::CerrStream>();
 
 4257            } 
else if ( 
filename == 
"%stdout" ) {
 
 4258                return Detail::make_unique<Detail::CoutStream>();
 
 4260                CATCH_ERROR( 
"Unrecognised stream: '" << 
filename << 
'\'' );
 
 4263        return Detail::make_unique<Detail::FileStream>( 
filename );
 
 
 4273    auto operator << (std::ostream& os, LazyExpression 
const& lazyExpr) -> std::ostream& {
 
 4274        if (lazyExpr.m_isNegated)
 
 4278            if (lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression())
 
 4279                os << 
'(' << *lazyExpr.m_transientExpression << 
')';
 
 4281                os << *lazyExpr.m_transientExpression;
 
 4283            os << 
"{** error - unchecked empty expression requested **}";
 
 
 4293#ifdef CATCH_CONFIG_WINDOWS_CRTDBG 
 4298    LeakDetector::LeakDetector() {
 
 4299        int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
 
 4300        flag |= _CRTDBG_LEAK_CHECK_DF;
 
 4301        flag |= _CRTDBG_ALLOC_MEM_DF;
 
 4302        _CrtSetDbgFlag(flag);
 
 4303        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
 
 4304        _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
 
 4306        _CrtSetBreakAlloc(-1);
 
 4312    Catch::LeakDetector::LeakDetector() {}
 
 4316Catch::LeakDetector::~LeakDetector() {
 
 4327        void listTests(IEventListener& reporter, IConfig 
const& config) {
 
 4328            auto const& testSpec = config.testSpec();
 
 4330            reporter.listTests(matchedTestCases);
 
 4333        void listTags(IEventListener& reporter, IConfig 
const& config) {
 
 4334            auto const& testSpec = config.testSpec();
 
 4337            std::map<StringRef, TagInfo, Detail::CaseInsensitiveLess> tagCounts;
 
 4338            for (
auto const& testCase : matchedTestCases) {
 
 4339                for (
auto const& tagName : testCase.getTestCaseInfo().tags) {
 
 4340                    auto it = tagCounts.find(tagName.original);
 
 4341                    if (it == tagCounts.end())
 
 4342                        it = tagCounts.insert(std::make_pair(tagName.original, TagInfo())).first;
 
 4343                    it->second.add(tagName.original);
 
 4347            std::vector<TagInfo> infos; infos.reserve(tagCounts.size());
 
 4348            for (
auto& tagc : tagCounts) {
 
 4349                infos.push_back(CATCH_MOVE(tagc.second));
 
 4352            reporter.listTags(infos);
 
 4355        void listReporters(IEventListener& reporter) {
 
 4356            std::vector<ReporterDescription> descriptions;
 
 4358            auto const& factories = 
getRegistryHub().getReporterRegistry().getFactories();
 
 4359            descriptions.reserve(factories.size());
 
 4360            for (
auto const& fac : factories) {
 
 4361                descriptions.push_back({ fac.first, fac.second->getDescription() });
 
 4364            reporter.listReporters(descriptions);
 
 4367        void listListeners(IEventListener& reporter) {
 
 4368            std::vector<ListenerDescription> descriptions;
 
 4370            auto const& factories =
 
 4372            descriptions.reserve( factories.size() );
 
 4373            for ( 
auto const& fac : factories ) {
 
 4374                descriptions.push_back( { fac->getName(), fac->getDescription() } );
 
 4377            reporter.listListeners( descriptions );
 
 4382    void TagInfo::add( StringRef spelling ) {
 
 4384        spellings.insert( spelling );
 
 4387    std::string TagInfo::all()
 const {
 
 4389        size_t size =  spellings.size() * 2;
 
 4390        for (
auto const& spelling : spellings) {
 
 4391            size += spelling.size();
 
 4394        std::string out; out.reserve(
size);
 
 4395        for (
auto const& spelling : spellings) {
 
 4403    bool list( IEventListener& reporter, Config 
const& config ) {
 
 4404        bool listed = 
false;
 
 4405        if (config.listTests()) {
 
 4407            listTests(reporter, config);
 
 4409        if (config.listTags()) {
 
 4411            listTags(reporter, config);
 
 4413        if (config.listReporters()) {
 
 4415            listReporters(reporter);
 
 4417        if ( config.listListeners() ) {
 
 4419            listListeners( reporter );
 
 
 4429    CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
 
 4430    CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
 
 4431    static LeakDetector leakDetector;
 
 4432    CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
 
 4436#if !defined(CATCH_AMALGAMATED_CUSTOM_MAIN) 
 4438#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) 
 4440extern "C" int __cdecl wmain (
int argc, 
wchar_t * argv[], 
wchar_t * []) {
 
 4443int main (
int argc, 
char * argv[]) {
 
 4448    (
void)&Catch::leakDetector;
 
 4450    return Catch::Session().run( argc, argv );
 
 
 4460    MessageInfo::MessageInfo(   StringRef _macroName,
 
 4461                                SourceLineInfo 
const& _lineInfo,
 
 4462                                ResultWas::OfType _type )
 
 4463    :   macroName( _macroName ),
 
 4464        lineInfo( _lineInfo ),
 
 4466        sequence( ++globalCount )
 
 4470    unsigned int MessageInfo::globalCount = 0;
 
 4480#if defined(CATCH_CONFIG_NEW_CAPTURE) 
 4481    #if defined(_MSC_VER) 
 4485    #define fileno _fileno 
 4494    RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
 
 4495    :   m_originalStream( originalStream ),
 
 4496        m_redirectionStream( redirectionStream ),
 
 4497        m_prevBuf( m_originalStream.rdbuf() )
 
 4499        m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
 
 4502    RedirectedStream::~RedirectedStream() {
 
 4503        m_originalStream.rdbuf( m_prevBuf );
 
 4506    RedirectedStdOut::RedirectedStdOut() : m_cout( 
Catch::
cout(), m_rss.
get() ) {}
 
 4507    auto RedirectedStdOut::str() const -> 
std::
string { 
return m_rss.str(); }
 
 4509    RedirectedStdErr::RedirectedStdErr()
 
 4513    auto RedirectedStdErr::str() const -> 
std::
string { 
return m_rss.str(); }
 
 4515    RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)
 
 4516    :   m_redirectedCout(redirectedCout),
 
 4517        m_redirectedCerr(redirectedCerr)
 
 4520    RedirectedStreams::~RedirectedStreams() {
 
 4521        m_redirectedCout += m_redirectedStdOut.str();
 
 4522        m_redirectedCerr += m_redirectedStdErr.str();
 
 4525#if defined(CATCH_CONFIG_NEW_CAPTURE) 
 4527#if defined(_MSC_VER) 
 4528    TempFile::TempFile() {
 
 4529        if (tmpnam_s(m_buffer)) {
 
 4530            CATCH_RUNTIME_ERROR(
"Could not get a temp filename");
 
 4532        if (fopen_s(&m_file, m_buffer, 
"w+")) {
 
 4534            if (strerror_s(
buffer, errno)) {
 
 4535                CATCH_RUNTIME_ERROR(
"Could not translate errno to a string");
 
 4537            CATCH_RUNTIME_ERROR(
"Could not open the temp file: '" << m_buffer << 
"' because: " << 
buffer);
 
 4541    TempFile::TempFile() {
 
 4542        m_file = std::tmpfile();
 
 4544            CATCH_RUNTIME_ERROR(
"Could not create a temp file.");
 
 4550    TempFile::~TempFile() {
 
 4552         std::fclose(m_file);
 
 4555#if defined(_MSC_VER) 
 4556         std::remove(m_buffer);
 
 4561    FILE* TempFile::getFile() {
 
 4565    std::string TempFile::getContents() {
 
 4566        std::stringstream sstr;
 
 4568        std::rewind(m_file);
 
 4575    OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) :
 
 4576        m_originalStdout(dup(1)),
 
 4577        m_originalStderr(dup(2)),
 
 4578        m_stdoutDest(stdout_dest),
 
 4579        m_stderrDest(stderr_dest) {
 
 4580        dup2(fileno(m_stdoutFile.getFile()), 1);
 
 4581        dup2(fileno(m_stderrFile.getFile()), 2);
 
 4584    OutputRedirect::~OutputRedirect() {
 
 4593        dup2(m_originalStdout, 1);
 
 4594        dup2(m_originalStderr, 2);
 
 4596        m_stdoutDest += m_stdoutFile.getContents();
 
 4597        m_stderrDest += m_stderrFile.getContents();
 
 4604#if defined(CATCH_CONFIG_NEW_CAPTURE) 
 4605    #if defined(_MSC_VER) 
 4620    Optional<unsigned int> 
parseUInt(std::string 
const& input, 
int base) {
 
 4621        auto trimmed = 
trim( input );
 
 4624        if ( trimmed.empty() || trimmed[0] == 
'-' ) {
 
 4630            const auto ret = std::stoull( trimmed, &
pos, base );
 
 4636            if ( 
pos != trimmed.size() ) {
 
 4640            if ( ret > std::numeric_limits<unsigned int>::max() ) {
 
 4643            return static_cast<unsigned int>(ret);
 
 4645        CATCH_CATCH_ANON( std::invalid_argument 
const& ) {
 
 4648        CATCH_CATCH_ANON( std::out_of_range 
const& ) {
 
 
 4663#if !defined(CATCH_CONFIG_POLYFILL_ISNAN) 
 4665        return std::isnan(
f);
 
 
 4668        return std::isnan(d);
 
 
 4673        return std::_isnan(
f);
 
 4675    bool isnan(
double d) {
 
 4676        return std::_isnan(d);
 
 4688#if defined(_MSC_VER) 
 4689#pragma warning(push) 
 4690#pragma warning(disable:4146)  
 4693        uint32_t rotate_right(uint32_t 
val, uint32_t 
count) {
 
 4694            const uint32_t 
mask = 31;
 
 4699#if defined(_MSC_VER) 
 4706    SimplePcg32::SimplePcg32(result_type seed_) {
 
 4711    void SimplePcg32::seed(result_type seed_) {
 
 4718    void SimplePcg32::discard(uint64_t skip) {
 
 4721        for (uint64_t s = 0; 
s < skip; ++
s) {
 
 4722            static_cast<void>((*this)());
 
 4726    SimplePcg32::result_type SimplePcg32::operator()() {
 
 4728        const uint32_t xorshifted = 
static_cast<uint32_t
>(((m_state >> 18u) ^ m_state) >> 27u);
 
 4729        const auto output = rotate_right(xorshifted, m_state >> 59u);
 
 4732        m_state = m_state * 6364136223846793005ULL + s_inc;
 
 4737    bool operator==(SimplePcg32 
const& lhs, SimplePcg32 
const& rhs) {
 
 4738        return lhs.m_state == rhs.m_state;
 
 
 4741    bool operator!=(SimplePcg32 
const& lhs, SimplePcg32 
const& rhs) {
 
 4742        return lhs.m_state != rhs.m_state;
 
 
 4757        case GenerateFrom::Time:
 
 4758            return static_cast<std::uint32_t
>( std::time( 
nullptr ) );
 
 4760        case GenerateFrom::Default:
 
 4761        case GenerateFrom::RandomDevice:
 
 4764            return static_cast<std::uint32_t
>( std::random_device{}() );
 
 4767            CATCH_ERROR(
"Unknown generation method");
 
 
 4778        std::vector<Detail::unique_ptr<EventListenerFactory>> 
listeners;
 
 4779        std::map<std::string, IReporterFactoryPtr, Detail::CaseInsensitiveLess>
 
 
 4783    ReporterRegistry::ReporterRegistry():
 
 4787        m_impl->factories[
"Automake"] =
 
 4788            Detail::make_unique<ReporterFactory<AutomakeReporter>>();
 
 4789        m_impl->factories[
"compact"] =
 
 4790            Detail::make_unique<ReporterFactory<CompactReporter>>();
 
 4791        m_impl->factories[
"console"] =
 
 4792            Detail::make_unique<ReporterFactory<ConsoleReporter>>();
 
 4793        m_impl->factories[
"JUnit"] =
 
 4794            Detail::make_unique<ReporterFactory<JunitReporter>>();
 
 4795        m_impl->factories[
"SonarQube"] =
 
 4796            Detail::make_unique<ReporterFactory<SonarQubeReporter>>();
 
 4797        m_impl->factories[
"TAP"] =
 
 4798            Detail::make_unique<ReporterFactory<TAPReporter>>();
 
 4799        m_impl->factories[
"TeamCity"] =
 
 4800            Detail::make_unique<ReporterFactory<TeamCityReporter>>();
 
 4801        m_impl->factories[
"XML"] =
 
 4802            Detail::make_unique<ReporterFactory<XmlReporter>>();
 
 4805    ReporterRegistry::~ReporterRegistry() = 
default;
 
 4808    ReporterRegistry::create( std::string 
const& 
name,
 
 4809                              ReporterConfig&& config )
 const {
 
 4810        auto it = m_impl->factories.find( 
name );
 
 4811        if ( it == m_impl->factories.end() ) 
return nullptr;
 
 4812        return it->second->create( CATCH_MOVE( config ) );
 
 4815    void ReporterRegistry::registerReporter( std::string 
const& 
name,
 
 4816                                             IReporterFactoryPtr factory ) {
 
 4817        CATCH_ENFORCE( 
name.find( 
"::" ) == 
name.npos,
 
 4818                       "'::' is not allowed in reporter name: '" + 
name +
 
 4820        auto ret = m_impl->factories.emplace( 
name, CATCH_MOVE( factory ) );
 
 4821        CATCH_ENFORCE( ret.second,
 
 4822                       "reporter using '" + 
name +
 
 4823                           "' as name was already registered" );
 
 4825    void ReporterRegistry::registerListener(
 
 4826        Detail::unique_ptr<EventListenerFactory> factory ) {
 
 4827        m_impl->listeners.push_back( CATCH_MOVE( factory ) );
 
 4830    std::map<std::string,
 
 4831             IReporterFactoryPtr,
 
 4832             Detail::CaseInsensitiveLess> 
const&
 
 4833    ReporterRegistry::getFactories()
 const {
 
 4834        return m_impl->factories;
 
 4837    std::vector<Detail::unique_ptr<EventListenerFactory>> 
const&
 
 4838    ReporterRegistry::getListeners()
 const {
 
 4839        return m_impl->listeners;
 
 4856        kvPair splitKVPair(StringRef kvString) {
 
 4857            auto splitPos = 
static_cast<size_t>(
 
 4858                std::find( kvString.begin(), kvString.end(), 
'=' ) -
 
 4861            return { kvString.substr( 0, splitPos ),
 
 4862                     kvString.substr( splitPos + 1, kvString.size() ) };
 
 4868            static constexpr auto separator = 
"::";
 
 4869            static constexpr size_t separatorSize = 2;
 
 4871            size_t separatorPos = 0;
 
 4872            auto findNextSeparator = [&reporterSpec]( 
size_t startPos ) {
 
 4875                    "The code below currently assumes 2 char separator" );
 
 4877                auto currentPos = startPos;
 
 4879                    while ( currentPos < reporterSpec.size() &&
 
 4880                            reporterSpec[currentPos] != separator[0] ) {
 
 4883                    if ( currentPos + 1 < reporterSpec.size() &&
 
 4884                         reporterSpec[currentPos + 1] == separator[1] ) {
 
 4888                } 
while ( currentPos < reporterSpec.size() );
 
 4890                return static_cast<size_t>( -1 );
 
 4893            std::vector<std::string> parts;
 
 4895            while ( separatorPos < reporterSpec.size() ) {
 
 4896                const auto nextSeparator = findNextSeparator( separatorPos );
 
 4897                parts.push_back( 
static_cast<std::string
>( reporterSpec.substr(
 
 4898                    separatorPos, nextSeparator - separatorPos ) ) );
 
 4900                if ( nextSeparator == 
static_cast<size_t>( -1 ) ) {
 
 4903                separatorPos = nextSeparator + separatorSize;
 
 4909            if ( separatorPos == reporterSpec.size() ) {
 
 4910                parts.emplace_back();
 
 
 4917            if ( colourMode == 
"default" ) {
 
 4918                return ColourMode::PlatformDefault;
 
 4919            } 
else if ( colourMode == 
"ansi" ) {
 
 4920                return ColourMode::ANSI;
 
 4921            } 
else if ( colourMode == 
"win32" ) {
 
 4922                return ColourMode::Win32;
 
 4923            } 
else if ( colourMode == 
"none" ) {
 
 4924                return ColourMode::None;
 
 
 4932    bool operator==( ReporterSpec 
const& lhs, ReporterSpec 
const& rhs ) {
 
 4933        return lhs.m_name == rhs.m_name &&
 
 4934               lhs.m_outputFileName == rhs.m_outputFileName &&
 
 4935               lhs.m_colourMode == rhs.m_colourMode &&
 
 4936               lhs.m_customOptions == rhs.m_customOptions;
 
 
 4942        assert( parts.size() > 0 && 
"Split should never return empty vector" );
 
 4944        std::map<std::string, std::string> kvPairs;
 
 4945        Optional<std::string> outputFileName;
 
 4946        Optional<ColourMode> colourMode;
 
 4949        for ( 
size_t i = 1; 
i < parts.size(); ++
i ) {
 
 4950            auto kv = splitKVPair( parts[
i] );
 
 4951            auto key = kv.key, 
value = kv.value;
 
 4953            if ( 
key.empty() || 
value.empty() ) {
 
 4955            } 
else if ( 
key[0] == 
'X' ) {
 
 4958                if ( 
key.size() == 1 ) {
 
 4962                auto ret = kvPairs.emplace( std::string(kv.key), std::string(kv.value) );
 
 4963                if ( !ret.second ) {
 
 4968            } 
else if ( 
key == 
"out" ) {
 
 4970                if ( outputFileName ) {
 
 4973                outputFileName = 
static_cast<std::string
>( 
value );
 
 4974            } 
else if ( 
key == 
"colour-mode" ) {
 
 4981                if ( !colourMode ) {
 
 4990        return ReporterSpec{ CATCH_MOVE( parts[0] ),
 
 4991                             CATCH_MOVE( outputFileName ),
 
 4992                             CATCH_MOVE( colourMode ),
 
 4993                             CATCH_MOVE( kvPairs ) };
 
 
 4996ReporterSpec::ReporterSpec(
 
 4998        Optional<std::string> outputFileName,
 
 4999        Optional<ColourMode> colourMode,
 
 5000        std::map<std::string, std::string> customOptions ):
 
 5001        m_name( CATCH_MOVE( 
name ) ),
 
 5002        m_outputFileName( CATCH_MOVE( outputFileName ) ),
 
 5003        m_colourMode( CATCH_MOVE( colourMode ) ),
 
 5004        m_customOptions( CATCH_MOVE( customOptions ) ) {}
 
 5012    bool isOk( ResultWas::OfType resultType ) {
 
 5013        return ( resultType & ResultWas::FailureBit ) == 0;
 
 
 5016        return flags == ResultWas::Info;
 
 
 5019    ResultDisposition::Flags 
operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
 
 5020        return static_cast<ResultDisposition::Flags
>( 
static_cast<int>( lhs ) | 
static_cast<int>( rhs ) );
 
 
 5038        std::vector<Detail::unique_ptr<std::ostringstream>> 
m_streams;
 
 5044                m_streams.push_back( Detail::make_unique<std::ostringstream>() );
 
 
 
 5060    ReusableStringStream::ReusableStringStream()
 
 5061    :   m_index( Singleton<StringStreams>::getMutable().add() ),
 
 5062        m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )
 
 5065    ReusableStringStream::~ReusableStringStream() {
 
 5066        static_cast<std::ostringstream*
>( m_oss )->
str(
"");
 
 5068        Singleton<StringStreams>::getMutable().release( m_index );
 
 5071    std::string ReusableStringStream::str()
 const {
 
 5072        return static_cast<std::ostringstream*
>( m_oss )->
str();
 
 5075    void ReusableStringStream::str( std::string 
const& 
str ) {
 
 5076        static_cast<std::ostringstream*
>( m_oss )->
str( 
str );
 
 5090    namespace Generators {
 
 5092            struct GeneratorTracker final : TestCaseTracking::TrackerBase,
 
 5097                    TestCaseTracking::NameAndLocation&& nameAndLocation,
 
 5098                    TrackerContext& ctx,
 
 5100                    TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ) {}
 
 5101                ~GeneratorTracker() 
override = 
default;
 
 5103                static GeneratorTracker*
 
 5104                acquire( TrackerContext& ctx,
 
 5105                         TestCaseTracking::NameAndLocationRef 
const&
 
 5107                    GeneratorTracker* tracker;
 
 5109                    ITracker& currentTracker = ctx.currentTracker();
 
 5121                    if ( currentTracker.nameAndLocation() == nameAndLocation ) {
 
 5122                        auto thisTracker = currentTracker.parent()->findChild(
 
 5124                        assert( thisTracker );
 
 5125                        assert( thisTracker->isGeneratorTracker() );
 
 5126                        tracker = 
static_cast<GeneratorTracker*
>( thisTracker );
 
 5127                    } 
else if ( ITracker* childTracker =
 
 5128                                    currentTracker.findChild(
 
 5129                                        nameAndLocation ) ) {
 
 5130                        assert( childTracker );
 
 5131                        assert( childTracker->isGeneratorTracker() );
 
 5133                            static_cast<GeneratorTracker*
>( childTracker );
 
 5138                    if ( !tracker->isComplete() ) { tracker->open(); }
 
 5144                bool isGeneratorTracker()
 const override { 
return true; }
 
 5145                auto hasGenerator() const -> 
bool override {
 
 5148                void close()
 override {
 
 5149                    TrackerBase::close();
 
 5158                    const bool should_wait_for_child = [&]() {
 
 5160                        if ( m_children.empty() ) { 
return false; }
 
 5165                                 []( TestCaseTracking::ITrackerPtr 
const&
 
 5167                                     return tracker->hasStarted();
 
 5168                                 } ) != m_children.end() ) {
 
 5176                        ITracker* parent = m_parent;
 
 5179                        while ( !parent->isSectionTracker() ) {
 
 5180                            parent = parent->parent();
 
 5183                                "Missing root (test case) level section" );
 
 5185                        auto const& parentSection =
 
 5186                            static_cast<SectionTracker const&
>( *parent );
 
 5187                        auto const& filters = parentSection.getFilters();
 
 5189                        if ( filters.empty() ) { 
return true; }
 
 5191                        for ( 
auto const& child : m_children ) {
 
 5192                            if ( child->isSectionTracker() &&
 
 5193                                 std::find( filters.begin(),
 
 5195                                            static_cast<SectionTracker const&
>(
 
 5209                    assert( m_generator && 
"Tracker without generator" );
 
 5210                    if ( should_wait_for_child ||
 
 5211                         ( m_runState == CompletedSuccessfully &&
 
 5214                        m_runState = Executing;
 
 5219                auto getGenerator() const -> GeneratorBasePtr const&
 override {
 
 5222                void setGenerator( GeneratorBasePtr&& generator )
 override {
 
 5229    RunContext::RunContext(IConfig 
const* _config, IEventListenerPtr&& reporter)
 
 5230    :   m_runInfo(_config->
name()),
 
 5232        m_reporter(CATCH_MOVE(reporter)),
 
 5233        m_lastAssertionInfo{ StringRef(), SourceLineInfo(
"",0), StringRef(), ResultDisposition::Normal },
 
 5234        m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
 
 5236        getCurrentMutableContext().setResultCapture( 
this );
 
 5237        m_reporter->testRunStarting(m_runInfo);
 
 5240    RunContext::~RunContext() {
 
 5241        m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
 
 5244    Totals RunContext::runTest(TestCaseHandle 
const& testCase) {
 
 5245        const Totals prevTotals = m_totals;
 
 5247        auto const& testInfo = testCase.getTestCaseInfo();
 
 5248        m_reporter->testCaseStarting(testInfo);
 
 5249        m_activeTestCase = &testCase;
 
 5252        ITracker& rootTracker = m_trackerContext.startRun();
 
 5253        assert(rootTracker.isSectionTracker());
 
 5254        static_cast<SectionTracker&
>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
 
 5289        uint64_t testRuns = 0;
 
 5290        std::string redirectedCout;
 
 5291        std::string redirectedCerr;
 
 5293            m_trackerContext.startCycle();
 
 5294            m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo));
 
 5296            m_reporter->testCasePartialStarting(testInfo, testRuns);
 
 5298            const auto beforeRunTotals = m_totals;
 
 5299            std::string oneRunCout, oneRunCerr;
 
 5300            runCurrentTest(oneRunCout, oneRunCerr);
 
 5301            redirectedCout += oneRunCout;
 
 5302            redirectedCerr += oneRunCerr;
 
 5304            const auto singleRunTotals = m_totals.delta(beforeRunTotals);
 
 5305            auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting());
 
 5307            m_reporter->testCasePartialEnded(statsForOneRun, testRuns);
 
 5309        } 
while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
 
 5311        Totals deltaTotals = m_totals.delta(prevTotals);
 
 5312        if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) {
 
 5313            deltaTotals.assertions.failed++;
 
 5314            deltaTotals.testCases.passed--;
 
 5315            deltaTotals.testCases.failed++;
 
 5317        m_totals.testCases += deltaTotals.testCases;
 
 5318        m_reporter->testCaseEnded(TestCaseStats(testInfo,
 
 5320                                  CATCH_MOVE(redirectedCout),
 
 5321                                  CATCH_MOVE(redirectedCerr),
 
 5324        m_activeTestCase = 
nullptr;
 
 5325        m_testCaseTracker = 
nullptr;
 
 5331    void RunContext::assertionEnded(AssertionResult&& 
result) {
 
 5332        if (
result.getResultType() == ResultWas::Ok) {
 
 5333            m_totals.assertions.passed++;
 
 5334            m_lastAssertionPassed = 
true;
 
 5335        } 
else if (
result.getResultType() == ResultWas::ExplicitSkip) {
 
 5336            m_totals.assertions.skipped++;
 
 5337            m_lastAssertionPassed = 
true;
 
 5338        } 
else if (!
result.succeeded()) {
 
 5339            m_lastAssertionPassed = 
false;
 
 5342            else if( m_activeTestCase->getTestCaseInfo().okToFail() )
 
 5343                m_totals.assertions.failedButOk++;
 
 5345                m_totals.assertions.failed++;
 
 5348            m_lastAssertionPassed = 
true;
 
 5351        m_reporter->assertionEnded(AssertionStats(
result, m_messages, m_totals));
 
 5353        if ( 
result.getResultType() != ResultWas::Warning ) {
 
 5354            m_messageScopes.clear();
 
 5358        resetAssertionInfo();
 
 5359        m_lastResult = CATCH_MOVE( 
result );
 
 5361    void RunContext::resetAssertionInfo() {
 
 5362        m_lastAssertionInfo.macroName = StringRef();
 
 5363        m_lastAssertionInfo.capturedExpression = 
"{Unknown expression after the reported line}"_sr;
 
 5366    void RunContext::notifyAssertionStarted( AssertionInfo 
const& info ) {
 
 5367        m_reporter->assertionStarting( info );
 
 5370    bool RunContext::sectionStarted( StringRef sectionName,
 
 5371                                     SourceLineInfo 
const& sectionLineInfo,
 
 5372                                     Counts& assertions ) {
 
 5373        ITracker& sectionTracker =
 
 5374            SectionTracker::acquire( m_trackerContext,
 
 5375                                     TestCaseTracking::NameAndLocationRef(
 
 5376                                         sectionName, sectionLineInfo ) );
 
 5378        if (!sectionTracker.isOpen())
 
 5380        m_activeSections.push_back(§ionTracker);
 
 5382        SectionInfo sectionInfo( sectionLineInfo, 
static_cast<std::string
>(sectionName) );
 
 5383        m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
 
 5385        m_reporter->sectionStarting(sectionInfo);
 
 5387        assertions = m_totals.assertions;
 
 5392    RunContext::acquireGeneratorTracker( StringRef generatorName,
 
 5393                                         SourceLineInfo 
const& lineInfo ) {
 
 5394        using namespace Generators;
 
 5395        GeneratorTracker* tracker = GeneratorTracker::acquire(
 
 5397            TestCaseTracking::NameAndLocationRef(
 
 5398                 generatorName, lineInfo ) );
 
 5399        m_lastAssertionInfo.lineInfo = lineInfo;
 
 5403    IGeneratorTracker* RunContext::createGeneratorTracker(
 
 5404        StringRef generatorName,
 
 5405        SourceLineInfo lineInfo,
 
 5406        Generators::GeneratorBasePtr&& generator ) {
 
 5408        auto nameAndLoc = TestCaseTracking::NameAndLocation( 
static_cast<std::string
>( generatorName ), lineInfo );
 
 5409        auto& currentTracker = m_trackerContext.currentTracker();
 
 5411            currentTracker.nameAndLocation() != nameAndLoc &&
 
 5412            "Trying to create tracker for a genreator that already has one" );
 
 5414        auto newTracker = Catch::Detail::make_unique<Generators::GeneratorTracker>(
 
 5415            CATCH_MOVE(nameAndLoc), m_trackerContext, ¤tTracker );
 
 5416        auto ret = newTracker.get();
 
 5417        currentTracker.addChild( CATCH_MOVE( newTracker ) );
 
 5419        ret->setGenerator( CATCH_MOVE( generator ) );
 
 5424    bool RunContext::testForMissingAssertions(Counts& assertions) {
 
 5425        if (assertions.total() != 0)
 
 5427        if (!m_config->warnAboutMissingAssertions())
 
 5429        if (m_trackerContext.currentTracker().hasChildren())
 
 5431        m_totals.assertions.failed++;
 
 5432        assertions.failed++;
 
 5436    void RunContext::sectionEnded(SectionEndInfo&& endInfo) {
 
 5437        Counts assertions = m_totals.assertions - endInfo.prevAssertions;
 
 5438        bool missingAssertions = testForMissingAssertions(assertions);
 
 5440        if (!m_activeSections.empty()) {
 
 5441            m_activeSections.back()->close();
 
 5442            m_activeSections.pop_back();
 
 5445        m_reporter->sectionEnded(SectionStats(CATCH_MOVE(endInfo.sectionInfo), assertions, endInfo.durationInSeconds, missingAssertions));
 
 5447        m_messageScopes.clear();
 
 5450    void RunContext::sectionEndedEarly(SectionEndInfo&& endInfo) {
 
 5451        if ( m_unfinishedSections.empty() ) {
 
 5452            m_activeSections.back()->fail();
 
 5454            m_activeSections.back()->close();
 
 5456        m_activeSections.pop_back();
 
 5458        m_unfinishedSections.push_back(CATCH_MOVE(endInfo));
 
 5461    void RunContext::benchmarkPreparing( StringRef 
name ) {
 
 5462        m_reporter->benchmarkPreparing(
name);
 
 5464    void RunContext::benchmarkStarting( BenchmarkInfo 
const& info ) {
 
 5465        m_reporter->benchmarkStarting( info );
 
 5467    void RunContext::benchmarkEnded( BenchmarkStats<> 
const& stats ) {
 
 5468        m_reporter->benchmarkEnded( stats );
 
 5470    void RunContext::benchmarkFailed( StringRef error ) {
 
 5471        m_reporter->benchmarkFailed( error );
 
 5474    void RunContext::pushScopedMessage(MessageInfo 
const & 
message) {
 
 5475        m_messages.push_back(
message);
 
 5478    void RunContext::popScopedMessage(MessageInfo 
const & 
message) {
 
 5479        m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), 
message), m_messages.end());
 
 5482    void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) {
 
 5483        m_messageScopes.emplace_back( CATCH_MOVE(builder) );
 
 5486    std::string RunContext::getCurrentTestName()
 const {
 
 5487        return m_activeTestCase
 
 5488            ? m_activeTestCase->getTestCaseInfo().name
 
 5492    const AssertionResult * RunContext::getLastResult()
 const {
 
 5493        return &(*m_lastResult);
 
 5496    void RunContext::exceptionEarlyReported() {
 
 5497        m_shouldReportUnexpected = 
false;
 
 5500    void RunContext::handleFatalErrorCondition( StringRef 
message ) {
 
 5502        m_reporter->fatalErrorEncountered(
message);
 
 5506        AssertionResultData tempResult( ResultWas::FatalErrorCondition, { 
false } );
 
 5507        tempResult.message = 
static_cast<std::string
>(
message);
 
 5508        AssertionResult 
result(m_lastAssertionInfo, CATCH_MOVE(tempResult));
 
 5510        assertionEnded(CATCH_MOVE(
result) );
 
 5512        handleUnfinishedSections();
 
 5515        auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
 
 5516        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
 
 5519        assertions.failed = 1;
 
 5520        SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, 0, 
false);
 
 5521        m_reporter->sectionEnded(testCaseSectionStats);
 
 5523        auto const& testInfo = m_activeTestCase->getTestCaseInfo();
 
 5526        deltaTotals.testCases.failed = 1;
 
 5527        deltaTotals.assertions.failed = 1;
 
 5528        m_reporter->testCaseEnded(TestCaseStats(testInfo,
 
 5533        m_totals.testCases.failed++;
 
 5534        m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, 
false));
 
 5537    bool RunContext::lastAssertionPassed() {
 
 5538         return m_lastAssertionPassed;
 
 5541    void RunContext::assertionPassed() {
 
 5542        m_lastAssertionPassed = 
true;
 
 5543        ++m_totals.assertions.passed;
 
 5544        resetAssertionInfo();
 
 5545        m_messageScopes.clear();
 
 5548    bool RunContext::aborting()
 const {
 
 5549        return m_totals.assertions.failed >= 
static_cast<std::size_t
>(m_config->abortAfter());
 
 5552    void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
 
 5553        auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
 
 5554        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
 
 5555        m_reporter->sectionStarting(testCaseSection);
 
 5556        Counts prevAssertions = m_totals.assertions;
 
 5557        double duration = 0;
 
 5558        m_shouldReportUnexpected = 
true;
 
 5559        m_lastAssertionInfo = { 
"TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };
 
 5563            if (m_reporter->getPreferences().shouldRedirectStdOut) {
 
 5564#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) 
 5565                RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);
 
 5568                invokeActiveTestCase();
 
 5570                OutputRedirect 
r(redirectedCout, redirectedCerr);
 
 5572                invokeActiveTestCase();
 
 5576                invokeActiveTestCase();
 
 5578            duration = timer.getElapsedSeconds();
 
 5579        } CATCH_CATCH_ANON (TestFailureException&) {
 
 5581        } CATCH_CATCH_ANON (TestSkipException&) {
 
 5586            if( m_shouldReportUnexpected ) {
 
 5587                AssertionReaction dummyReaction;
 
 5591        Counts assertions = m_totals.assertions - prevAssertions;
 
 5592        bool missingAssertions = testForMissingAssertions(assertions);
 
 5594        m_testCaseTracker->close();
 
 5595        handleUnfinishedSections();
 
 5597        m_messageScopes.clear();
 
 5599        SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions);
 
 5600        m_reporter->sectionEnded(testCaseSectionStats);
 
 5603    void RunContext::invokeActiveTestCase() {
 
 5607        FatalConditionHandlerGuard _(&m_fatalConditionhandler);
 
 5613        m_activeTestCase->invoke();
 
 5616    void RunContext::handleUnfinishedSections() {
 
 5619        for (
auto it = m_unfinishedSections.rbegin(),
 
 5620             itEnd = m_unfinishedSections.rend();
 
 5623            sectionEnded(CATCH_MOVE(*it));
 
 5624        m_unfinishedSections.clear();
 
 5627    void RunContext::handleExpr(
 
 5628        AssertionInfo 
const& info,
 
 5629        ITransientExpression 
const& expr,
 
 5630        AssertionReaction& reaction
 
 5632        bool negated = isFalseTest( info.resultDisposition );
 
 5633        bool result = expr.getResult() != negated;
 
 5636            if (!m_includeSuccessfulResults) {
 
 5640                reportExpr(info, ResultWas::Ok, &expr, negated);
 
 5644            reportExpr(info, ResultWas::ExpressionFailed, &expr, negated );
 
 5645            populateReaction( reaction );
 
 5648    void RunContext::reportExpr(
 
 5649            AssertionInfo 
const &info,
 
 5650            ResultWas::OfType resultType,
 
 5651            ITransientExpression 
const *expr,
 
 5654        m_lastAssertionInfo = info;
 
 5655        AssertionResultData 
data( resultType, LazyExpression( negated ) );
 
 5657        AssertionResult assertionResult{ info, CATCH_MOVE( 
data ) };
 
 5658        assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
 
 5660        assertionEnded( CATCH_MOVE(assertionResult) );
 
 5663    void RunContext::handleMessage(
 
 5664            AssertionInfo 
const& info,
 
 5665            ResultWas::OfType resultType,
 
 5667            AssertionReaction& reaction
 
 5669        m_lastAssertionInfo = info;
 
 5671        AssertionResultData 
data( resultType, LazyExpression( 
false ) );
 
 5673        AssertionResult assertionResult{ m_lastAssertionInfo,
 
 5674                                         CATCH_MOVE( 
data ) };
 
 5676        const auto isOk = assertionResult.isOk();
 
 5677        assertionEnded( CATCH_MOVE(assertionResult) );
 
 5679            populateReaction( reaction );
 
 5680        } 
else if ( resultType == ResultWas::ExplicitSkip ) {
 
 5683            reaction.shouldSkip = 
true;
 
 5686    void RunContext::handleUnexpectedExceptionNotThrown(
 
 5687            AssertionInfo 
const& info,
 
 5688            AssertionReaction& reaction
 
 5690        handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction);
 
 5693    void RunContext::handleUnexpectedInflightException(
 
 5694            AssertionInfo 
const& info,
 
 5696            AssertionReaction& reaction
 
 5698        m_lastAssertionInfo = info;
 
 5700        AssertionResultData 
data( ResultWas::ThrewException, LazyExpression( 
false ) );
 
 5702        AssertionResult assertionResult{ info, CATCH_MOVE(
data) };
 
 5703        assertionEnded( CATCH_MOVE(assertionResult) );
 
 5704        populateReaction( reaction );
 
 5707    void RunContext::populateReaction( AssertionReaction& reaction ) {
 
 5708        reaction.shouldDebugBreak = m_config->shouldDebugBreak();
 
 5709        reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal);
 
 5712    void RunContext::handleIncomplete(
 
 5713            AssertionInfo 
const& info
 
 5715        using namespace std::string_literals;
 
 5716        m_lastAssertionInfo = info;
 
 5718        AssertionResultData 
data( ResultWas::ThrewException, LazyExpression( 
false ) );
 
 5719        data.message = 
"Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s;
 
 5720        AssertionResult assertionResult{ info, CATCH_MOVE( 
data ) };
 
 5721        assertionEnded( CATCH_MOVE(assertionResult) );
 
 5723    void RunContext::handleNonExpr(
 
 5724            AssertionInfo 
const &info,
 
 5725            ResultWas::OfType resultType,
 
 5726            AssertionReaction &reaction
 
 5728        m_lastAssertionInfo = info;
 
 5730        AssertionResultData 
data( resultType, LazyExpression( 
false ) );
 
 5731        AssertionResult assertionResult{ info, CATCH_MOVE( 
data ) };
 
 5733        const auto isOk = assertionResult.isOk();
 
 5734        assertionEnded( CATCH_MOVE(assertionResult) );
 
 5735        if ( !isOk ) { populateReaction( reaction ); }
 
 5743            CATCH_INTERNAL_ERROR(
"No result capture instance");
 
 
 5747        sharedRng().seed(config.rngSeed());
 
 
 5751        return getCurrentContext().getConfig()->rngSeed();
 
 
 5760    Section::Section( SectionInfo&& info ):
 
 5761        m_info( CATCH_MOVE( info ) ),
 
 5766        if (m_sectionIncluded) {
 
 5771    Section::Section( SourceLineInfo 
const& _lineInfo,
 
 5773                      const char* 
const ):
 
 5774        m_info( { 
"invalid", 
static_cast<std::size_t
>( -1 ) }, std::string{} ),
 
 5781        if ( m_sectionIncluded ) {
 
 5782            m_info.name = 
static_cast<std::string
>( _name );
 
 5783            m_info.lineInfo = _lineInfo;
 
 5788    Section::~Section() {
 
 5789        if( m_sectionIncluded ) {
 
 5790            SectionEndInfo endInfo{ CATCH_MOVE(m_info), m_assertions, m_timer.getElapsedSeconds() };
 
 5800    Section::operator 
bool()
 const {
 
 5801        return m_sectionIncluded;
 
 5814        static auto getSingletons() -> std::vector<ISingleton*>*& {
 
 5815            static std::vector<ISingleton*>* g_singletons = 
nullptr;
 
 5817                g_singletons = 
new std::vector<ISingleton*>();
 
 5818            return g_singletons;
 
 5822    ISingleton::~ISingleton() = 
default;
 
 5825        getSingletons()->push_back( singleton );
 
 
 5828        auto& singletons = getSingletons();
 
 5829        for( 
auto singleton : *singletons )
 
 5832        singletons = 
nullptr;
 
 
 5844    bool SourceLineInfo::operator == ( SourceLineInfo 
const& 
other ) 
const noexcept {
 
 5847    bool SourceLineInfo::operator < ( SourceLineInfo 
const& 
other ) 
const noexcept {
 
 5853    std::ostream& 
operator << ( std::ostream& os, SourceLineInfo 
const& info ) {
 
 5855        os << info.file << 
'(' << info.line << 
')';
 
 5857        os << info.file << 
':' << info.line;
 
 
 5868#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) 
 5869    void StartupExceptionRegistry::add( std::exception_ptr 
const& exception ) 
noexcept {
 
 5871            m_exceptions.push_back(exception);
 
 5878    std::vector<std::exception_ptr> 
const& StartupExceptionRegistry::getExceptions() const noexcept {
 
 5879        return m_exceptions;
 
 5894#if !defined( CATCH_CONFIG_NOSTDOUT ) 
 5895    std::ostream& 
cout() { 
return std::cout; }
 
 5896    std::ostream& 
cerr() { 
return std::cerr; }
 
 5897    std::ostream& 
clog() { 
return std::clog; }
 
 5911    bool startsWith( std::string 
const& s, std::string 
const& prefix ) {
 
 5912        return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
 
 
 5915        return !s.empty() && s[0] == prefix;
 
 
 5917    bool endsWith( std::string 
const& s, std::string 
const& suffix ) {
 
 5918        return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
 
 
 5921        return !s.empty() && s[s.size()-1] == suffix;
 
 
 5923    bool contains( std::string 
const& s, std::string 
const& infix ) {
 
 5924        return s.find( infix ) != std::string::npos;
 
 
 5927        for ( 
char& 
c : s ) {
 
 
 5937        return static_cast<char>(std::tolower(
static_cast<unsigned char>(
c)));
 
 
 5941        static char const* whitespaceChars = 
"\n\r\t ";
 
 5942        std::string::size_type 
start = 
str.find_first_not_of( whitespaceChars );
 
 5943        std::string::size_type 
end = 
str.find_last_not_of( whitespaceChars );
 
 
 5949        const auto is_ws = [](
char c) {
 
 5950            return c == 
' ' || 
c == 
'\t' || 
c == 
'\n' || 
c == 
'\r';
 
 5952        size_t real_begin = 0;
 
 5953        while (real_begin < 
ref.size() && is_ws(
ref[real_begin])) { ++real_begin; }
 
 5954        size_t real_end = 
ref.size();
 
 5955        while (real_end > real_begin && is_ws(
ref[real_end - 1])) { --real_end; }
 
 5957        return ref.substr(real_begin, real_end - real_begin);
 
 
 5960    bool replaceInPlace( std::string& 
str, std::string 
const& replaceThis, std::string 
const& withThis ) {
 
 5961        bool replaced = 
false;
 
 5962        std::size_t 
i = 
str.find( replaceThis );
 
 5963        while( 
i != std::string::npos ) {
 
 5965            str = 
str.substr( 0, 
i ) + withThis + 
str.substr( 
i+replaceThis.size() );
 
 5966            if( 
i < 
str.size()-withThis.size() )
 
 5967                i = 
str.find( replaceThis, 
i+withThis.size() );
 
 5969                i = std::string::npos;
 
 
 5975        std::vector<StringRef> subStrings;
 
 5976        std::size_t 
start = 0;
 
 5978            if( 
str[
pos] == delimiter ) {
 
 
 5989    std::ostream& 
operator << ( std::ostream& os, pluralise 
const& pluraliser ) {
 
 5990        os << pluraliser.m_count << 
' ' << pluraliser.m_label;
 
 5991        if( pluraliser.m_count != 1 )
 
 
 6006    StringRef::StringRef( 
char const* rawChars ) noexcept
 
 6007    : StringRef( rawChars, std::strlen(rawChars) )
 
 6011    bool StringRef::operator<(StringRef rhs) 
const noexcept {
 
 6012        if (m_size < 
rhs.m_size) {
 
 6013            return strncmp(m_start, 
rhs.m_start, m_size) <= 0;
 
 6015        return strncmp(m_start, 
rhs.m_start, 
rhs.m_size) < 0;
 
 6018    int StringRef::compare( StringRef rhs )
 const {
 
 6020            strncmp( m_start, 
rhs.m_start, std::min( m_size, 
rhs.m_size ) );
 
 6024        if ( cmpResult != 0 ) {
 
 6030        if ( m_size < 
rhs.m_size ) {
 
 6032        } 
else if ( m_size > 
rhs.m_size ) {
 
 6040        return os.write(
str.data(), 
static_cast<std::streamsize
>(
str.size()));
 
 
 6045        ret.reserve(lhs.size() + rhs.size());
 
 
 6051    auto operator+=( std::string& lhs, StringRef rhs ) -> std::string& {
 
 6052        lhs.append(rhs.data(), rhs.size());
 
 
 6062    TagAliasRegistry::~TagAliasRegistry() {}
 
 6064    TagAlias 
const* TagAliasRegistry::find( std::string 
const& alias )
 const {
 
 6065        auto it = m_registry.find( alias );
 
 6066        if( it != m_registry.end() )
 
 6067            return &(it->second);
 
 6072    std::string TagAliasRegistry::expandAliases( std::string 
const& unexpandedTestSpec )
 const {
 
 6073        std::string expandedTestSpec = unexpandedTestSpec;
 
 6074        for( 
auto const& registryKvp : m_registry ) {
 
 6075            std::size_t 
pos = expandedTestSpec.find( registryKvp.first );
 
 6076            if( 
pos != std::string::npos ) {
 
 6077                expandedTestSpec =  expandedTestSpec.substr( 0, 
pos ) +
 
 6078                                    registryKvp.second.tag +
 
 6079                                    expandedTestSpec.substr( 
pos + registryKvp.first.size() );
 
 6082        return expandedTestSpec;
 
 6085    void TagAliasRegistry::add( std::string 
const& alias, std::string 
const& tag, SourceLineInfo 
const& lineInfo ) {
 
 6087                      "error: tag alias, '" << alias << 
"' is not of the form [@alias name].\n" << lineInfo );
 
 6089        CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second,
 
 6090                      "error: tag alias, '" << alias << 
"' already registered.\n" 
 6091                      << 
"\tFirst seen at: " << find(alias)->lineInfo << 
"\n" 
 6092                      << 
"\tRedefined at: " << lineInfo );
 
 6095    ITagAliasRegistry::~ITagAliasRegistry() = 
default;
 
 6097    ITagAliasRegistry 
const& ITagAliasRegistry::get() {
 
 6107    TestCaseInfoHasher::TestCaseInfoHasher( hash_t seed ): m_seed( seed ) {}
 
 6109    uint32_t TestCaseInfoHasher::operator()( TestCaseInfo 
const& t )
 const {
 
 6111        const hash_t prime = 1099511628211u;
 
 6112        hash_t hash = 14695981039346656037u;
 
 6113        for ( 
const char c : t.
name ) {
 
 6117        for ( 
const char c : t.className ) {
 
 6121        for ( 
const Tag& tag : t.tags ) {
 
 6122            for ( 
const char c : tag.original ) {
 
 6129        const uint32_t low{ 
static_cast<uint32_t
>( hash ) };
 
 6130        const uint32_t high{ 
static_cast<uint32_t
>( hash >> 32 ) };
 
 6144        static void enforceNoDuplicateTestCases(
 
 6145            std::vector<TestCaseHandle> 
const& tests ) {
 
 6146            auto testInfoCmp = []( TestCaseInfo 
const* 
lhs,
 
 6147                                   TestCaseInfo 
const* 
rhs ) {
 
 6150            std::set<TestCaseInfo 
const*, 
decltype( testInfoCmp )&> seenTests(
 
 6152            for ( 
auto const& 
test : tests ) {
 
 6153                const auto infoPtr = &
test.getTestCaseInfo();
 
 6154                const auto prev = seenTests.insert( infoPtr );
 
 6155                CATCH_ENFORCE( prev.second,
 
 6156                               "error: test case \"" 
 6157                                   << infoPtr->name << 
"\", with tags \"" 
 6158                                   << infoPtr->tagsAsString()
 
 6159                                   << 
"\" already defined.\n" 
 6160                                   << 
"\tFirst seen at " 
 6161                                   << ( *prev.first )->lineInfo << 
"\n" 
 6162                                   << 
"\tRedefined at " << infoPtr->lineInfo );
 
 6166        static bool matchTest( TestCaseHandle 
const& testCase,
 
 6167                               TestSpec 
const& testSpec,
 
 6168                               IConfig 
const& config ) {
 
 6169            return testSpec.matches( testCase.getTestCaseInfo() ) &&
 
 6175    std::vector<TestCaseHandle> 
sortTests( IConfig 
const& config, std::vector<TestCaseHandle> 
const& unsortedTestCases ) {
 
 6176        switch (config.runOrder()) {
 
 6177        case TestRunOrder::Declared:
 
 6178            return unsortedTestCases;
 
 6180        case TestRunOrder::LexicographicallySorted: {
 
 6181            std::vector<TestCaseHandle> sorted = unsortedTestCases;
 
 6185                []( TestCaseHandle 
const& lhs, TestCaseHandle 
const& rhs ) {
 
 6186                    return lhs.getTestCaseInfo() < rhs.getTestCaseInfo();
 
 6191        case TestRunOrder::Randomized: {
 
 6193            using TestWithHash = std::pair<TestCaseInfoHasher::hash_t, TestCaseHandle>;
 
 6195            TestCaseInfoHasher 
h{ config.rngSeed() };
 
 6196            std::vector<TestWithHash> indexed_tests;
 
 6197            indexed_tests.reserve(unsortedTestCases.size());
 
 6199            for (
auto const& handle : unsortedTestCases) {
 
 6200                indexed_tests.emplace_back(
h(handle.getTestCaseInfo()), handle);
 
 6203            std::sort( indexed_tests.begin(),
 
 6204                       indexed_tests.end(),
 
 6205                       []( TestWithHash 
const& lhs, TestWithHash 
const& rhs ) {
 
 6206                           if ( lhs.first == rhs.first ) {
 
 6207                               return lhs.second.getTestCaseInfo() <
 
 6208                                      rhs.second.getTestCaseInfo();
 
 6210                           return lhs.first < rhs.first;
 
 6213            std::vector<TestCaseHandle> randomized;
 
 6214            randomized.reserve(indexed_tests.size());
 
 6216            for (
auto const& indexed : indexed_tests) {
 
 6217                randomized.push_back(indexed.second);
 
 6224        CATCH_INTERNAL_ERROR(
"Unknown test order value!");
 
 
 6227    bool isThrowSafe( TestCaseHandle 
const& testCase, IConfig 
const& config ) {
 
 6228        return !testCase.getTestCaseInfo().throws() || config.allowThrows();
 
 
 6231    std::vector<TestCaseHandle> 
filterTests( std::vector<TestCaseHandle> 
const& testCases, TestSpec 
const& testSpec, IConfig 
const& config ) {
 
 6232        std::vector<TestCaseHandle> filtered;
 
 6233        filtered.reserve( testCases.size() );
 
 6234        for (
auto const& testCase : testCases) {
 
 6235            if ((!testSpec.hasFilters() && !testCase.getTestCaseInfo().isHidden()) ||
 
 6236                (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) {
 
 6237                filtered.push_back(testCase);
 
 6240        return createShard(filtered, config.shardCount(), config.shardIndex());
 
 
 6243        return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
 
 
 6246    void TestRegistry::registerTest(Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker) {
 
 6247        m_handles.emplace_back(testInfo.get(), testInvoker.get());
 
 6248        m_viewed_test_infos.push_back(testInfo.get());
 
 6249        m_owned_test_infos.push_back(CATCH_MOVE(testInfo));
 
 6250        m_invokers.push_back(CATCH_MOVE(testInvoker));
 
 6253    std::vector<TestCaseInfo*> 
const& TestRegistry::getAllInfos()
 const {
 
 6254        return m_viewed_test_infos;
 
 6257    std::vector<TestCaseHandle> 
const& TestRegistry::getAllTests()
 const {
 
 6260    std::vector<TestCaseHandle> 
const& TestRegistry::getAllTestsSorted( IConfig 
const& config )
 const {
 
 6261        if( m_sortedFunctions.empty() )
 
 6262            enforceNoDuplicateTestCases( m_handles );
 
 6264        if(  m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
 
 6265            m_sortedFunctions = 
sortTests( config, m_handles );
 
 6266            m_currentSortOrder = config.runOrder();
 
 6268        return m_sortedFunctions;
 
 6279#if defined(__clang__) 
 6280#    pragma clang diagnostic push 
 6281#    pragma clang diagnostic ignored "-Wexit-time-destructors" 
 6285namespace TestCaseTracking {
 
 6287    NameAndLocation::NameAndLocation( std::string&& _name, SourceLineInfo 
const& _location )
 
 6288    :   
name( CATCH_MOVE(_name) ),
 
 6293    ITracker::~ITracker() = 
default;
 
 6295    void ITracker::markAsNeedingAnotherRun() {
 
 6296        m_runState = NeedsAnotherRun;
 
 6299    void ITracker::addChild( ITrackerPtr&& child ) {
 
 6300        m_children.push_back( CATCH_MOVE(child) );
 
 6303    ITracker* ITracker::findChild( NameAndLocationRef 
const& nameAndLocation ) {
 
 6304        auto it = std::find_if(
 
 6307            [&nameAndLocation]( ITrackerPtr 
const& tracker ) {
 
 6308                auto const& tnameAndLoc = tracker->nameAndLocation();
 
 6309                if ( tnameAndLoc.location.line !=
 
 6310                     nameAndLocation.location.line ) {
 
 6313                return tnameAndLoc == nameAndLocation;
 
 6315        return ( it != m_children.end() ) ? it->get() : 
nullptr;
 
 6318    bool ITracker::isSectionTracker()
 const { 
return false; }
 
 6319    bool ITracker::isGeneratorTracker()
 const { 
return false; }
 
 6321    bool ITracker::isOpen()
 const {
 
 6322        return m_runState != NotStarted && !isComplete();
 
 6325    bool ITracker::hasStarted()
 const { 
return m_runState != NotStarted; }
 
 6327    void ITracker::openChild() {
 
 6328        if (m_runState != ExecutingChildren) {
 
 6329            m_runState = ExecutingChildren;
 
 6331                m_parent->openChild();
 
 6336    ITracker& TrackerContext::startRun() {
 
 6337        using namespace std::string_literals;
 
 6338        m_rootTracker = Catch::Detail::make_unique<SectionTracker>(
 
 6339            NameAndLocation( 
"{root}"s, CATCH_INTERNAL_LINEINFO ),
 
 6342        m_currentTracker = 
nullptr;
 
 6343        m_runState = Executing;
 
 6344        return *m_rootTracker;
 
 6347    void TrackerContext::completeCycle() {
 
 6348        m_runState = CompletedCycle;
 
 6351    bool TrackerContext::completedCycle()
 const {
 
 6352        return m_runState == CompletedCycle;
 
 6354    void TrackerContext::setCurrentTracker( ITracker* tracker ) {
 
 6355        m_currentTracker = tracker;
 
 6359    TrackerBase::TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
 
 6360        ITracker(CATCH_MOVE(nameAndLocation), parent),
 
 6364    bool TrackerBase::isComplete()
 const {
 
 6365        return m_runState == CompletedSuccessfully || m_runState == Failed;
 
 6368    void TrackerBase::open() {
 
 6369        m_runState = Executing;
 
 6372            m_parent->openChild();
 
 6375    void TrackerBase::close() {
 
 6378        while( &m_ctx.currentTracker() != 
this )
 
 6379            m_ctx.currentTracker().close();
 
 6381        switch( m_runState ) {
 
 6382            case NeedsAnotherRun:
 
 6386                m_runState = CompletedSuccessfully;
 
 6388            case ExecutingChildren:
 
 6389                if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr 
const& t){ return t->isComplete(); }) )
 
 6390                    m_runState = CompletedSuccessfully;
 
 6394            case CompletedSuccessfully:
 
 6396                CATCH_INTERNAL_ERROR( 
"Illogical state: " << m_runState );
 
 6399                CATCH_INTERNAL_ERROR( 
"Unknown state: " << m_runState );
 
 6402        m_ctx.completeCycle();
 
 6404    void TrackerBase::fail() {
 
 6405        m_runState = Failed;
 
 6407            m_parent->markAsNeedingAnotherRun();
 
 6409        m_ctx.completeCycle();
 
 6412    void TrackerBase::moveToParent() {
 
 6414        m_ctx.setCurrentTracker( m_parent );
 
 6416    void TrackerBase::moveToThis() {
 
 6417        m_ctx.setCurrentTracker( 
this );
 
 6420    SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
 
 6421    :   TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
 
 6422        m_trimmed_name(
trim(StringRef(ITracker::nameAndLocation().
name)))
 
 6425            while ( !parent->isSectionTracker() ) {
 
 6426                parent = parent->parent();
 
 6429            SectionTracker& parentSection = 
static_cast<SectionTracker&
>( *parent );
 
 6430            addNextFilters( parentSection.m_filters );
 
 6434    bool SectionTracker::isComplete()
 const {
 
 6435        bool complete = 
true;
 
 6437        if (m_filters.empty()
 
 6438            || m_filters[0].empty()
 
 6439            || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
 
 6440            complete = TrackerBase::isComplete();
 
 6445    bool SectionTracker::isSectionTracker()
 const { 
return true; }
 
 6447    SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef 
const& nameAndLocation ) {
 
 6448        SectionTracker* tracker;
 
 6450        ITracker& currentTracker = ctx.currentTracker();
 
 6451        if ( ITracker* childTracker =
 
 6452                 currentTracker.findChild( nameAndLocation ) ) {
 
 6453            assert( childTracker );
 
 6454            assert( childTracker->isSectionTracker() );
 
 6455            tracker = 
static_cast<SectionTracker*
>( childTracker );
 
 6457            auto newTracker = Catch::Detail::make_unique<SectionTracker>(
 
 6458                NameAndLocation{ 
static_cast<std::string
>(nameAndLocation.name),
 
 6459                                 nameAndLocation.location },
 
 6462            tracker = newTracker.get();
 
 6463            currentTracker.addChild( CATCH_MOVE( newTracker ) );
 
 6466        if ( !ctx.completedCycle() ) {
 
 6473    void SectionTracker::tryOpen() {
 
 6478    void SectionTracker::addInitialFilters( std::vector<std::string> 
const& filters ) {
 
 6479        if( !filters.empty() ) {
 
 6480            m_filters.reserve( m_filters.size() + filters.size() + 2 );
 
 6481            m_filters.emplace_back(StringRef{}); 
 
 6482            m_filters.emplace_back(StringRef{}); 
 
 6483            m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
 
 6486    void SectionTracker::addNextFilters( std::vector<StringRef> 
const& filters ) {
 
 6487        if( filters.size() > 1 )
 
 6488            m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
 
 6491    StringRef SectionTracker::trimmedName()
 const {
 
 6492        return m_trimmed_name;
 
 
 6499#if defined(__clang__) 
 6500#    pragma clang diagnostic pop 
 6509#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) 
 6510        throw TestFailureException{};
 
 6512        CATCH_ERROR( 
"Test failure requires aborting test!" );
 
 
 6517#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) 
 6518        throw Catch::TestSkipException();
 
 6520        CATCH_ERROR( 
"Explicitly skipping tests during runtime requires exceptions" );
 
 
 6532    ITestInvoker::~ITestInvoker() = 
default;
 
 6535        static StringRef extractClassName( StringRef classOrMethodName ) {
 
 6536            if ( !
startsWith( classOrMethodName, 
'&' ) ) {
 
 6537                return classOrMethodName;
 
 6541            const auto methodName =
 
 6542                classOrMethodName.substr( 1, classOrMethodName.size() );
 
 6544            auto reverseStart = std::make_reverse_iterator( methodName.end() );
 
 6545            auto reverseEnd = std::make_reverse_iterator( methodName.begin() );
 
 6551            auto lastColons = std::find( reverseStart, reverseEnd, 
':' ) + 1;
 
 6552            auto secondLastColons =
 
 6553                std::find( lastColons + 1, reverseEnd, 
':' );
 
 6555            auto const startIdx = reverseEnd - secondLastColons;
 
 6556            auto const classNameSize = secondLastColons - lastColons - 1;
 
 6558            return methodName.substr(
 
 6559                static_cast<std::size_t
>( startIdx ),
 
 6560                static_cast<std::size_t
>( classNameSize ) );
 
 6563        class TestInvokerAsFunction final : 
public ITestInvoker {
 
 6564            using TestType = 
void ( * )();
 
 6565            TestType m_testAsFunction;
 
 6568            TestInvokerAsFunction( TestType testAsFunction ) 
noexcept:
 
 6569                m_testAsFunction( testAsFunction ) {}
 
 6571            void invoke()
 const override { m_testAsFunction(); }
 
 6577        return Detail::make_unique<TestInvokerAsFunction>( testAsFunction );
 
 
 6580    AutoReg::AutoReg( Detail::unique_ptr<ITestInvoker> invoker, SourceLineInfo 
const& lineInfo, StringRef classOrMethod, NameAndTags 
const& nameAndTags ) 
noexcept {
 
 6585                            extractClassName( classOrMethod ),
 
 6603    TestSpecParser::TestSpecParser( ITagAliasRegistry 
const& tagAliases ) : m_tagAliases( &tagAliases ) {}
 
 6605    TestSpecParser& TestSpecParser::parse( std::string 
const& arg ) {
 
 6607        m_exclusion = 
false;
 
 6608        m_arg = m_tagAliases->expandAliases( arg );
 
 6609        m_escapeChars.clear();
 
 6610        m_substring.reserve(m_arg.size());
 
 6611        m_patternName.reserve(m_arg.size());
 
 6612        m_realPatternPos = 0;
 
 6614        for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
 
 6616           if( !visitChar( m_arg[m_pos] ) ){
 
 6617               m_testSpec.m_invalidSpecs.push_back(arg);
 
 6623    TestSpec TestSpecParser::testSpec() {
 
 6625        return CATCH_MOVE(m_testSpec);
 
 6627    bool TestSpecParser::visitChar( 
char c ) {
 
 6628        if( (m_mode != EscapedName) && (
c == 
'\\') ) {
 
 6630            addCharToPattern(
c);
 
 6632        }
else if((m_mode != EscapedName) && (
c == 
',') )  {
 
 6638            if( processNoneChar( 
c ) )
 
 6642            processNameChar( 
c );
 
 6646            addCharToPattern(
c);
 
 6651            if( processOtherChar( 
c ) )
 
 6657        if( !isControlChar( 
c ) ) {
 
 6665    bool TestSpecParser::processNoneChar( 
char c ) {
 
 6673            startNewMode( Tag );
 
 6676            startNewMode( QuotedName );
 
 6679            startNewMode( Name );
 
 6683    void TestSpecParser::processNameChar( 
char c ) {
 
 6685            if( m_substring == 
"exclude:" )
 
 6689            startNewMode( Tag );
 
 6692    bool TestSpecParser::processOtherChar( 
char c ) {
 
 6693        if( !isControlChar( 
c ) )
 
 6699    void TestSpecParser::startNewMode( 
Mode mode ) {
 
 6702    void TestSpecParser::endMode() {
 
 6706            return addNamePattern();
 
 6708            return addTagPattern();
 
 6710            revertBackToLastMode();
 
 6714            return startNewMode( 
None );
 
 6717    void TestSpecParser::escape() {
 
 6719        m_mode = EscapedName;
 
 6720        m_escapeChars.push_back(m_realPatternPos);
 
 6722    bool TestSpecParser::isControlChar( 
char c )
 const {
 
 6735                return c == 
'[' || 
c == 
']';
 
 6739    void TestSpecParser::addFilter() {
 
 6740        if( !m_currentFilter.m_required.empty() || !m_currentFilter.m_forbidden.empty() ) {
 
 6741            m_testSpec.m_filters.push_back( CATCH_MOVE(m_currentFilter) );
 
 6742            m_currentFilter = TestSpec::Filter();
 
 6746    void TestSpecParser::saveLastMode() {
 
 6750    void TestSpecParser::revertBackToLastMode() {
 
 6754    bool TestSpecParser::separate() {
 
 6755      if( (m_mode==QuotedName) || (m_mode==Tag) ){
 
 6758         m_pos = m_arg.size();
 
 6759         m_substring.clear();
 
 6760         m_patternName.clear();
 
 6761         m_realPatternPos = 0;
 
 6769    std::string TestSpecParser::preprocessPattern() {
 
 6770        std::string token = m_patternName;
 
 6771        for (std::size_t 
i = 0; 
i < m_escapeChars.size(); ++
i)
 
 6772            token = token.substr(0, m_escapeChars[
i] - 
i) + token.substr(m_escapeChars[
i] - 
i + 1);
 
 6773        m_escapeChars.clear();
 
 6776            token = token.substr(8);
 
 6779        m_patternName.clear();
 
 6780        m_realPatternPos = 0;
 
 6785    void TestSpecParser::addNamePattern() {
 
 6786        auto token = preprocessPattern();
 
 6788        if (!token.empty()) {
 
 6790                m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::NamePattern>(token, m_substring));
 
 6792                m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::NamePattern>(token, m_substring));
 
 6795        m_substring.clear();
 
 6796        m_exclusion = 
false;
 
 6800    void TestSpecParser::addTagPattern() {
 
 6801        auto token = preprocessPattern();
 
 6803        if (!token.empty()) {
 
 6806            if (token.size() > 1 && token[0] == 
'.') {
 
 6807                token.erase(token.begin());
 
 6809                    m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(
".", m_substring));
 
 6811                    m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(
".", m_substring));
 
 6815                m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
 
 6817                m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
 
 6820        m_substring.clear();
 
 6821        m_exclusion = 
false;
 
 6834    bool isWhitespace( 
char c ) {
 
 6835        return c == 
' ' || 
c == 
'\t' || 
c == 
'\n' || 
c == 
'\r';
 
 6838    bool isBreakableBefore( 
char c ) {
 
 6839        static const char chars[] = 
"[({<|";
 
 6840        return std::memchr( chars, 
c, 
sizeof( chars ) - 1 ) != 
nullptr;
 
 6843    bool isBreakableAfter( 
char c ) {
 
 6844        static const char chars[] = 
"])}>.,:;*+-=&/\\";
 
 6845        return std::memchr( chars, 
c, 
sizeof( chars ) - 1 ) != 
nullptr;
 
 6848    bool isBoundary( std::string 
const& line, 
size_t at ) {
 
 6850        assert( at <= 
line.size() );
 
 6852        return at == 
line.size() ||
 
 6853               ( isWhitespace( line[at] ) && !isWhitespace( line[at - 1] ) ) ||
 
 6854               isBreakableBefore( line[at] ) ||
 
 6855               isBreakableAfter( line[at - 1] );
 
 6861    namespace TextFlow {
 
 6863        void Column::const_iterator::calcLength() {
 
 6864            m_addHyphen = 
false;
 
 6865            m_parsedTo = m_lineStart;
 
 6867            std::string 
const& current_line = m_column.m_string;
 
 6868            if ( current_line[m_lineStart] == 
'\n' ) {
 
 6872            const auto maxLineLength = m_column.m_width - indentSize();
 
 6873            const auto maxParseTo = std::min(current_line.size(), m_lineStart + maxLineLength);
 
 6874            while ( m_parsedTo < maxParseTo &&
 
 6875                    current_line[m_parsedTo] != 
'\n' ) {
 
 6882            if ( m_parsedTo < m_lineStart + maxLineLength ) {
 
 6883                m_lineLength = m_parsedTo - m_lineStart;
 
 6888                size_t newLineLength = maxLineLength;
 
 6889                while ( newLineLength > 0 && !isBoundary( current_line, m_lineStart + newLineLength ) ) {
 
 6892                while ( newLineLength > 0 &&
 
 6893                        isWhitespace( current_line[m_lineStart + newLineLength - 1] ) ) {
 
 6898                if ( newLineLength > 0 ) {
 
 6899                    m_lineLength = newLineLength;
 
 6903                    m_lineLength = maxLineLength - 1;
 
 6908        size_t Column::const_iterator::indentSize()
 const {
 
 6910                m_lineStart == 0 ? m_column.m_initialIndent : std::string::npos;
 
 6911            return initial == std::string::npos ? m_column.m_indent : initial;
 
 6915        Column::const_iterator::addIndentAndSuffix( 
size_t position,
 
 6918            const auto desired_indent = indentSize();
 
 6919            ret.reserve( desired_indent + 
length + m_addHyphen );
 
 6920            ret.append( desired_indent, 
' ' );
 
 6921            ret.append( m_column.m_string, position, 
length );
 
 6922            if ( m_addHyphen ) {
 
 6923                ret.push_back( 
'-' );
 
 6929        Column::const_iterator::const_iterator( Column 
const& column ): m_column( column ) {
 
 6930            assert( m_column.m_width > m_column.m_indent );
 
 6931            assert( m_column.m_initialIndent == std::string::npos ||
 
 6932                    m_column.m_width > m_column.m_initialIndent );
 
 6934            if ( m_lineLength == 0 ) {
 
 6935                m_lineStart = m_column.m_string.size();
 
 6939        std::string Column::const_iterator::operator*()
 const {
 
 6940            assert( m_lineStart <= m_parsedTo );
 
 6941            return addIndentAndSuffix( m_lineStart, m_lineLength );
 
 6944        Column::const_iterator& Column::const_iterator::operator++() {
 
 6945            m_lineStart += m_lineLength;
 
 6946            std::string 
const& current_line = m_column.m_string;
 
 6947            if ( m_lineStart < current_line.size() && current_line[m_lineStart] == 
'\n' ) {
 
 6950                while ( m_lineStart < current_line.size() &&
 
 6951                        isWhitespace( current_line[m_lineStart] ) ) {
 
 6956            if ( m_lineStart != current_line.size() ) {
 
 6962        Column::const_iterator Column::const_iterator::operator++( 
int ) {
 
 6963            const_iterator prev( *
this );
 
 6970            for ( 
auto line : 
col ) {
 
 
 6983            ret.width( spaceWidth );
 
 
 6987        Columns::iterator::iterator( Columns 
const& columns, EndTag ):
 
 6988            m_columns( columns.m_columns ), m_activeIterators( 0 ) {
 
 6990            m_iterators.reserve( m_columns.size() );
 
 6991            for ( 
auto const& 
col : m_columns ) {
 
 6992                m_iterators.push_back( 
col.end() );
 
 6996        Columns::iterator::iterator( Columns 
const& columns ):
 
 6997            m_columns( columns.m_columns ),
 
 6998            m_activeIterators( m_columns.
size() ) {
 
 7000            m_iterators.reserve( m_columns.size() );
 
 7001            for ( 
auto const& 
col : m_columns ) {
 
 7002                m_iterators.push_back( 
col.begin() );
 
 7006        std::string Columns::iterator::operator*()
 const {
 
 7009            for ( 
size_t i = 0; 
i < m_columns.size(); ++
i ) {
 
 7010                const auto width = m_columns[
i].width();
 
 7011                if ( m_iterators[
i] != m_columns[
i].
end() ) {
 
 7012                    std::string 
col = *m_iterators[
i];
 
 7027        Columns::iterator& Columns::iterator::operator++() {
 
 7028            for ( 
size_t i = 0; 
i < m_columns.size(); ++
i ) {
 
 7029                if ( m_iterators[
i] != m_columns[
i].
end() ) {
 
 7036        Columns::iterator Columns::iterator::operator++( 
int ) {
 
 7037            iterator prev( *
this );
 
 7044            for ( 
auto line : 
cols ) {
 
 
 7055        Columns Column::operator+( Column 
const& 
other ) {
 
 7062        Columns& Columns::operator+=( Column 
const& 
col ) {
 
 7063            m_columns.push_back( 
col );
 
 7067        Columns Columns::operator+( Column 
const& 
col ) {
 
 7068            Columns combined = *
this;
 
 
 7083#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) 
 7085#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) 
 7086        return std::uncaught_exceptions() > 0;
 
 7088        return std::uncaught_exception();
 
 
 7097    WildcardPattern::WildcardPattern( std::string 
const& 
pattern,
 
 7098                                      CaseSensitive caseSensitivity )
 
 7099    :   m_caseSensitivity( caseSensitivity ),
 
 7100        m_pattern( normaliseString( 
pattern ) )
 
 7103            m_pattern = m_pattern.substr( 1 );
 
 7104            m_wildcard = WildcardAtStart;
 
 7107            m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
 
 7108            m_wildcard = 
static_cast<WildcardPosition
>( m_wildcard | WildcardAtEnd );
 
 7112    bool WildcardPattern::matches( std::string 
const& 
str )
 const {
 
 7113        switch( m_wildcard ) {
 
 7115                return m_pattern == normaliseString( 
str );
 
 7116            case WildcardAtStart:
 
 7117                return endsWith( normaliseString( 
str ), m_pattern );
 
 7120            case WildcardAtBothEnds:
 
 7121                return contains( normaliseString( 
str ), m_pattern );
 
 7123                CATCH_INTERNAL_ERROR( 
"Unknown enum" );
 
 7127    std::string WildcardPattern::normaliseString( std::string 
const& 
str )
 const {
 
 7139#include <type_traits> 
 7145    size_t trailingBytes(
unsigned char c) {
 
 7146        if ((
c & 0xE0) == 0xC0) {
 
 7149        if ((
c & 0xF0) == 0xE0) {
 
 7152        if ((
c & 0xF8) == 0xF0) {
 
 7155        CATCH_INTERNAL_ERROR(
"Invalid multibyte utf-8 start byte encountered");
 
 7158    uint32_t headerValue(
unsigned char c) {
 
 7159        if ((
c & 0xE0) == 0xC0) {
 
 7162        if ((
c & 0xF0) == 0xE0) {
 
 7165        if ((
c & 0xF8) == 0xF0) {
 
 7168        CATCH_INTERNAL_ERROR(
"Invalid multibyte utf-8 start byte encountered");
 
 7171    void hexEscapeChar(std::ostream& os, 
unsigned char c) {
 
 7172        std::ios_base::fmtflags 
f(os.flags());
 
 7174            << std::uppercase << std::hex << std::setfill(
'0') << std::setw(2)
 
 7175            << 
static_cast<int>(
c);
 
 7179    bool shouldNewline(XmlFormatting 
fmt) {
 
 7180        return !!(
static_cast<std::underlying_type_t<XmlFormatting>
>(
fmt & XmlFormatting::Newline));
 
 7183    bool shouldIndent(XmlFormatting 
fmt) {
 
 7184        return !!(
static_cast<std::underlying_type_t<XmlFormatting>
>(
fmt & XmlFormatting::Indent));
 
 7189    XmlFormatting 
operator | (XmlFormatting lhs, XmlFormatting rhs) {
 
 7190        return static_cast<XmlFormatting
>(
 
 7191            static_cast<std::underlying_type_t<XmlFormatting>
>(lhs) |
 
 7192            static_cast<std::underlying_type_t<XmlFormatting>
>(rhs)
 
 
 7196    XmlFormatting 
operator & (XmlFormatting lhs, XmlFormatting rhs) {
 
 7197        return static_cast<XmlFormatting
>(
 
 7198            static_cast<std::underlying_type_t<XmlFormatting>
>(lhs) &
 
 7199            static_cast<std::underlying_type_t<XmlFormatting>
>(rhs)
 
 
 7204    XmlEncode::XmlEncode( StringRef 
str, ForWhat forWhat )
 
 7206        m_forWhat( forWhat )
 
 7209    void XmlEncode::encodeTo( std::ostream& os )
 const {
 
 7213        for( std::size_t idx = 0; 
idx < m_str.size(); ++ 
idx ) {
 
 7214            unsigned char c = 
static_cast<unsigned char>(m_str[
idx]);
 
 7216            case '<':   os << 
"<"; 
break;
 
 7217            case '&':   os << 
"&"; 
break;
 
 7221                if (idx > 2 && m_str[idx - 1] == 
']' && m_str[idx - 2] == 
']')
 
 7228                if (m_forWhat == ForAttributes)
 
 7239                if (
c < 0x09 || (
c > 0x0D && 
c < 0x20) || 
c == 0x7F) {
 
 7240                    hexEscapeChar(os, 
c);
 
 7258                    hexEscapeChar(os, 
c);
 
 7262                auto encBytes = trailingBytes(
c);
 
 7264                if (idx + encBytes - 1 >= m_str.size()) {
 
 7265                    hexEscapeChar(os, 
c);
 
 7272                uint32_t 
value = headerValue(
c);
 
 7273                for (std::size_t 
n = 1; 
n < encBytes; ++
n) {
 
 7274                    unsigned char nc = 
static_cast<unsigned char>(m_str[
idx + 
n]);
 
 7275                    valid &= ((nc & 0xC0) == 0x80);
 
 7284                    (0x80 <= 
value && value < 0x800   && encBytes > 2) ||
 
 7285                    (0x800 < 
value && value < 0x10000 && encBytes > 3) ||
 
 7289                    hexEscapeChar(os, 
c);
 
 7294                for (std::size_t 
n = 0; 
n < encBytes; ++
n) {
 
 7295                    os << m_str[
idx + 
n];
 
 7297                idx += encBytes - 1;
 
 7303    std::ostream& 
operator << ( std::ostream& os, XmlEncode 
const& xmlEncode ) {
 
 7304        xmlEncode.encodeTo( os );
 
 
 7308    XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting 
fmt )
 
 7309    :   m_writer( writer ),
 
 7313    XmlWriter::ScopedElement::ScopedElement( ScopedElement&& 
other ) noexcept
 
 7314    :   m_writer( 
other.m_writer ),
 
 7317        other.m_writer = 
nullptr;
 
 7318        other.m_fmt = XmlFormatting::None;
 
 7320    XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& 
other ) 
noexcept {
 
 7322            m_writer->endElement();
 
 7324        m_writer = 
other.m_writer;
 
 7325        other.m_writer = 
nullptr;
 
 7326        m_fmt = 
other.m_fmt;
 
 7327        other.m_fmt = XmlFormatting::None;
 
 7332    XmlWriter::ScopedElement::~ScopedElement() {
 
 7334            m_writer->endElement(m_fmt);
 
 7338    XmlWriter::ScopedElement&
 
 7339    XmlWriter::ScopedElement::writeText( StringRef text, XmlFormatting 
fmt ) {
 
 7340        m_writer->writeText( text, 
fmt );
 
 7344    XmlWriter::ScopedElement&
 
 7345    XmlWriter::ScopedElement::writeAttribute( StringRef 
name,
 
 7346                                              StringRef attribute ) {
 
 7347        m_writer->writeAttribute( 
name, attribute );
 
 7352    XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
 
 7357    XmlWriter::~XmlWriter() {
 
 7358        while (!m_tags.empty()) {
 
 7361        newlineIfNecessary();
 
 7364    XmlWriter& XmlWriter::startElement( std::string 
const& 
name, XmlFormatting 
fmt ) {
 
 7366        newlineIfNecessary();
 
 7367        if (shouldIndent(
fmt)) {
 
 7371        m_os << 
'<' << 
name;
 
 7372        m_tags.push_back( 
name );
 
 7374        applyFormatting(
fmt);
 
 7378    XmlWriter::ScopedElement XmlWriter::scopedElement( std::string 
const& 
name, XmlFormatting 
fmt ) {
 
 7379        ScopedElement scoped( 
this, 
fmt );
 
 7384    XmlWriter& XmlWriter::endElement(XmlFormatting 
fmt) {
 
 7385        m_indent = m_indent.substr(0, m_indent.size() - 2);
 
 7389            m_tagIsOpen = 
false;
 
 7391            newlineIfNecessary();
 
 7392            if (shouldIndent(
fmt)) {
 
 7395            m_os << 
"</" << m_tags.back() << 
'>';
 
 7398        applyFormatting(
fmt);
 
 7403    XmlWriter& XmlWriter::writeAttribute( StringRef 
name,
 
 7404                                          StringRef attribute ) {
 
 7405        if( !
name.empty() && !attribute.empty() )
 
 7406            m_os << 
' ' << 
name << 
"=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << 
'"';
 
 7410    XmlWriter& XmlWriter::writeAttribute( StringRef 
name, 
bool attribute ) {
 
 7411        writeAttribute(
name, (attribute ? 
"true"_sr : 
"false"_sr));
 
 7415    XmlWriter& XmlWriter::writeAttribute( StringRef 
name,
 
 7416                                          char const* attribute ) {
 
 7417        writeAttribute( 
name, StringRef( attribute ) );
 
 7421    XmlWriter& XmlWriter::writeText( StringRef text, XmlFormatting 
fmt ) {
 
 7422        CATCH_ENFORCE(!m_tags.empty(), 
"Cannot write text as top level element");
 
 7423        if( !text.empty() ){
 
 7424            bool tagWasOpen = m_tagIsOpen;
 
 7426            if (tagWasOpen && shouldIndent(
fmt)) {
 
 7429            m_os << XmlEncode( text, XmlEncode::ForTextNodes );
 
 7430            applyFormatting(
fmt);
 
 7435    XmlWriter& XmlWriter::writeComment( StringRef text, XmlFormatting 
fmt ) {
 
 7437        if (shouldIndent(
fmt)) {
 
 7440        m_os << 
"<!-- " << text << 
" -->";
 
 7441        applyFormatting(
fmt);
 
 7445    void XmlWriter::writeStylesheetRef( StringRef 
url ) {
 
 7446        m_os << R
"(<?xml-stylesheet type="text/xsl" href=")" << url << R"("?>)" << '\n';
 
 7449    void XmlWriter::ensureTagClosed() {
 
 7451            m_os << 
'>' << std::flush;
 
 7452            newlineIfNecessary();
 
 7453            m_tagIsOpen = 
false;
 
 7457    void XmlWriter::applyFormatting(XmlFormatting 
fmt) {
 
 7458        m_needsNewline = shouldNewline(
fmt);
 
 7461    void XmlWriter::writeDeclaration() {
 
 7462        m_os << R
"(<?xml version="1.0" encoding="UTF-8"?>)" << '\n';
 
 7465    void XmlWriter::newlineIfNecessary() {
 
 7466        if( m_needsNewline ) {
 
 7467            m_os << 
'\n' << std::flush;
 
 7468            m_needsNewline = 
false;
 
 7480    std::string MatcherUntypedBase::toString()
 const {
 
 7481        if (m_cachedToString.empty()) {
 
 7482            m_cachedToString = describe();
 
 7484        return m_cachedToString;
 
 7487    MatcherUntypedBase::~MatcherUntypedBase() = 
default;
 
 
 7498    std::string IsEmptyMatcher::describe()
 const {
 
 7502    std::string HasSizeMatcher::describe()
 const {
 
 7503        ReusableStringStream sstr;
 
 7504        sstr << 
"has size == " << m_target_size;
 
 7513        return HasSizeMatcher{ sz };
 
 
 7524bool ExceptionMessageMatcher::match(std::exception 
const& ex)
 const {
 
 7525    return ex.what() == m_message;
 
 7528std::string ExceptionMessageMatcher::describe()
 const {
 
 7529    return "exception message matches \"" + m_message + 
'"';
 
 7533    return ExceptionMessageMatcher(
message);
 
 
 7553    template <
typename FP>
 
 7554    bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {
 
 7562        const auto ulpDist = ulpDistance(lhs, rhs);
 
 7564        return ulpDist <= maxUlpDiff;
 
 7567#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) 
 7569    float nextafter(
float x, 
float y) {
 
 7570        return ::nextafterf(
x, 
y);
 
 7573    double nextafter(
double x, 
double y) {
 
 7574        return ::nextafter(
x, 
y);
 
 7579template <
typename FP>
 
 7580FP 
step(FP 
start, FP direction, uint64_t steps) {
 
 7581    for (uint64_t 
i = 0; 
i < steps; ++
i) {
 
 7582#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) 
 7593bool marginComparison(
double lhs, 
double rhs, 
double margin) {
 
 7594    return (lhs + margin >= rhs) && (
rhs + margin >= 
lhs);
 
 7597template <
typename FloatingPo
int>
 
 7598void write(std::ostream& out, FloatingPoint 
num) {
 
 7599    out << std::scientific
 
 7600        << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1)
 
 7617    WithinAbsMatcher::WithinAbsMatcher(
double target, 
double margin)
 
 7618        :m_target{ 
target }, m_margin{ margin } {
 
 7619        CATCH_ENFORCE(margin >= 0, 
"Invalid margin: " << margin << 
'.' 
 7620            << 
" Margin has to be non-negative.");
 
 7625    bool WithinAbsMatcher::match(
double const& matchee)
 const {
 
 7626        return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);
 
 7629    std::string WithinAbsMatcher::describe()
 const {
 
 7630        return "is within " + ::Catch::Detail::stringify(m_margin) + 
" of " + ::Catch::Detail::stringify(m_target);
 
 7635        :m_target{ 
target }, m_ulps{ ulps }, m_type{ baseType } {
 
 7637                   || m_ulps < (std::numeric_limits<uint32_t>::max)(),
 
 7638            "Provided ULP is impossibly large for a float comparison.");
 
 7639        CATCH_ENFORCE( std::numeric_limits<double>::is_iec559,
 
 7640                       "WithinUlp matcher only supports platforms with " 
 7641                       "IEEE-754 compatible floating point representation" );
 
 7644#if defined(__clang__) 
 7645#pragma clang diagnostic push 
 7647#pragma clang diagnostic ignored "-Wunreachable-code" 
 7650    bool WithinUlpsMatcher::match(
double const& matchee)
 const {
 
 7653            return almostEqualUlps<float>(
static_cast<float>(matchee), 
static_cast<float>(m_target), m_ulps);
 
 7655            return almostEqualUlps<double>(matchee, m_target, m_ulps);
 
 7657            CATCH_INTERNAL_ERROR( 
"Unknown Detail::FloatingPointKind value" );
 
 7661#if defined(__clang__) 
 7662#pragma clang diagnostic pop 
 7665    std::string WithinUlpsMatcher::describe()
 const {
 
 7666        std::stringstream ret;
 
 7668        ret << 
"is within " << m_ulps << 
" ULPs of ";
 
 7671            write(ret, 
static_cast<float>(m_target));
 
 7674            write(ret, m_target);
 
 7681                         -std::numeric_limits<double>::infinity(),
 
 7686                         std::numeric_limits<double>::infinity(),
 
 7691                   step( 
static_cast<float>( m_target ),
 
 7692                         -std::numeric_limits<float>::infinity(),
 
 7696                   step( 
static_cast<float>( m_target ),
 
 7697                         std::numeric_limits<float>::infinity(),
 
 7705    WithinRelMatcher::WithinRelMatcher(
double target, 
double epsilon):
 
 7708        CATCH_ENFORCE(m_epsilon >= 0., 
"Relative comparison with epsilon <  0 does not make sense.");
 
 7709        CATCH_ENFORCE(m_epsilon  < 1., "Relative comparison with epsilon >= 1 does not make sense.
"); 
 7712    bool WithinRelMatcher::match(double const& matchee) const { 
 7713        const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target)); 
 7714        return marginComparison(matchee, m_target, 
 7715                                std::isinf(relMargin)? 0 : relMargin); 
 7718    std::string WithinRelMatcher::describe() const { 
 7719        Catch::ReusableStringStream sstr; 
 7720        sstr << "and 
" << m_target << " are within 
" << m_epsilon * 100. << "% 
of each 
other"; 
 7725WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) { 
 7726    return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Double); 
 
 7729WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) { 
 7730    return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Float); 
 
 7733WithinAbsMatcher WithinAbs(double target, double margin) { 
 7734    return WithinAbsMatcher(target, margin); 
 
 7737WithinRelMatcher WithinRel(double target, double eps) { 
 7738    return WithinRelMatcher(target, eps); 
 
 7741WithinRelMatcher WithinRel(double target) { 
 7742    return WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100); 
 
 7745WithinRelMatcher WithinRel(float target, float eps) { 
 7746    return WithinRelMatcher(target, eps); 
 
 7749WithinRelMatcher WithinRel(float target) { 
 7750    return WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100); 
 
 7755bool IsNaNMatcher::match( double const& matchee ) const { 
 7756    return std::isnan( matchee ); 
 7759std::string IsNaNMatcher::describe() const { 
 7760    using namespace std::string_literals; 
 7764IsNaNMatcher IsNaN() { return IsNaNMatcher(); } 
 7766    } // namespace Matchers 
 7772std::string Catch::Matchers::Detail::finalizeDescription(const std::string& desc) { 
 7774        return "matches undescribed predicate
"; 
 7776        return "matches predicate: \
"" + desc + 
'"';
 
 7783    namespace Matchers {
 
 7784        std::string AllTrueMatcher::describe()
 const { 
return "contains only true"; }
 
 7786        AllTrueMatcher 
AllTrue() { 
return AllTrueMatcher{}; }
 
 7788        std::string NoneTrueMatcher::describe()
 const { 
return "contains no true"; }
 
 7790        NoneTrueMatcher 
NoneTrue() { 
return NoneTrueMatcher{}; }
 
 7792        std::string AnyTrueMatcher::describe()
 const { 
return "contains at least one true"; }
 
 7794        AnyTrueMatcher 
AnyTrue() { 
return AnyTrueMatcher{}; }
 
 7805    CasedString::CasedString( std::string 
const& 
str, CaseSensitive caseSensitivity )
 
 7806    :   m_caseSensitivity( caseSensitivity ),
 
 7807        m_str( adjustString( 
str ) )
 
 7809    std::string CasedString::adjustString( std::string 
const& 
str )
 const {
 
 7810        return m_caseSensitivity == CaseSensitive::No
 
 7814    StringRef CasedString::caseSensitivitySuffix()
 const {
 
 7815        return m_caseSensitivity == CaseSensitive::Yes
 
 7817                   : 
" (case insensitive)"_sr;
 
 7821    StringMatcherBase::StringMatcherBase( StringRef operation, CasedString 
const& comparator )
 
 7822    : m_comparator( comparator ),
 
 7823      m_operation( operation ) {
 
 7826    std::string StringMatcherBase::describe()
 const {
 
 7827        std::string description;
 
 7828        description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
 
 7829                                    m_comparator.caseSensitivitySuffix().size());
 
 7830        description += m_operation;
 
 7831        description += 
": \"";
 
 7832        description += m_comparator.m_str;
 
 7834        description += m_comparator.caseSensitivitySuffix();
 
 7838    StringEqualsMatcher::StringEqualsMatcher( CasedString 
const& comparator ) : StringMatcherBase( 
"equals"_sr, comparator ) {}
 
 7840    bool StringEqualsMatcher::match( std::string 
const& 
source )
 const {
 
 7841        return m_comparator.adjustString( 
source ) == m_comparator.m_str;
 
 7845    StringContainsMatcher::StringContainsMatcher( CasedString 
const& comparator ) : StringMatcherBase( 
"contains"_sr, comparator ) {}
 
 7847    bool StringContainsMatcher::match( std::string 
const& 
source )
 const {
 
 7848        return contains( m_comparator.adjustString( 
source ), m_comparator.m_str );
 
 7852    StartsWithMatcher::StartsWithMatcher( CasedString 
const& comparator ) : StringMatcherBase( 
"starts with"_sr, comparator ) {}
 
 7854    bool StartsWithMatcher::match( std::string 
const& 
source )
 const {
 
 7855        return startsWith( m_comparator.adjustString( 
source ), m_comparator.m_str );
 
 7859    EndsWithMatcher::EndsWithMatcher( CasedString 
const& comparator ) : StringMatcherBase( 
"ends with"_sr, comparator ) {}
 
 7861    bool EndsWithMatcher::match( std::string 
const& 
source )
 const {
 
 7862        return endsWith( m_comparator.adjustString( 
source ), m_comparator.m_str );
 
 7867    RegexMatcher::RegexMatcher(std::string regex, CaseSensitive caseSensitivity): m_regex(CATCH_MOVE(regex)), m_caseSensitivity(caseSensitivity) {}
 
 7869    bool RegexMatcher::match(std::string 
const& matchee)
 const {
 
 7870        auto flags = std::regex::ECMAScript; 
 
 7871        if (m_caseSensitivity == CaseSensitive::No) {
 
 7872            flags |= std::regex::icase;
 
 7874        auto reg = std::regex(m_regex, 
flags);
 
 7875        return std::regex_match(matchee, reg);
 
 7878    std::string RegexMatcher::describe()
 const {
 
 7879        return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Yes)? 
" case sensitively" : 
" case insensitively");
 
 7883    StringEqualsMatcher 
Equals( std::string 
const& 
str, CaseSensitive caseSensitivity ) {
 
 7884        return StringEqualsMatcher( CasedString( 
str, caseSensitivity) );
 
 
 7887        return StringContainsMatcher( CasedString( 
str, caseSensitivity) );
 
 
 7889    EndsWithMatcher 
EndsWith( std::string 
const& 
str, CaseSensitive caseSensitivity ) {
 
 7890        return EndsWithMatcher( CasedString( 
str, caseSensitivity) );
 
 
 7892    StartsWithMatcher 
StartsWith( std::string 
const& 
str, CaseSensitive caseSensitivity ) {
 
 7893        return StartsWithMatcher( CasedString( 
str, caseSensitivity) );
 
 
 7896    RegexMatcher 
Matches(std::string 
const& regex, CaseSensitive caseSensitivity) {
 
 7897        return RegexMatcher(regex, caseSensitivity);
 
 
 7907    MatcherGenericBase::~MatcherGenericBase() = 
default;
 
 7911        std::string 
describe_multi_matcher(StringRef combine, std::string 
const* descriptions_begin, std::string 
const* descriptions_end) {
 
 7912            std::string description;
 
 7913            std::size_t combined_size = 4;
 
 7914            for ( 
auto desc = descriptions_begin; desc != descriptions_end; ++desc ) {
 
 7915                combined_size += desc->size();
 
 7917            combined_size += 
static_cast<size_t>(descriptions_end - descriptions_begin - 1) * combine.size();
 
 7919            description.reserve(combined_size);
 
 7921            description += 
"( ";
 
 7923            for( 
auto desc = descriptions_begin; desc != descriptions_end; ++desc ) {
 
 7927                    description += combine;
 
 7928                description += *desc;
 
 7930            description += 
" )";
 
 
 7948        MatchExpr<std::string, StringMatcher const&> expr( CATCH_MOVE(exceptionMessage), matcher );
 
 7949        handler.handleExpr( expr );
 
 
 7960    AutomakeReporter::~AutomakeReporter() {}
 
 7962    void AutomakeReporter::testCaseEnded(TestCaseStats 
const& _testCaseStats) {
 
 7964        m_stream << 
":test-result: ";
 
 7965        if ( _testCaseStats.totals.testCases.skipped > 0 ) {
 
 7967        } 
else if (_testCaseStats.totals.assertions.allPassed()) {
 
 7969        } 
else if (_testCaseStats.totals.assertions.allOk()) {
 
 7970            m_stream << 
"XFAIL";
 
 7974        m_stream << 
' ' << _testCaseStats.testInfo->name << 
'\n';
 
 7975        StreamingReporterBase::testCaseEnded(_testCaseStats);
 
 7978    void AutomakeReporter::skipTest(TestCaseInfo 
const& testInfo) {
 
 7979        m_stream << 
":test-result: SKIP " << testInfo.name << 
'\n';
 
 7990    ReporterBase::ReporterBase( ReporterConfig&& config ):
 
 7991        IEventListener( config.fullConfig() ),
 
 7992        m_wrapped_stream( CATCH_MOVE(config).takeStream() ),
 
 7993        m_stream( m_wrapped_stream->
stream() ),
 
 7994        m_colour( makeColourImpl( config.colourMode(), m_wrapped_stream.
get() ) ),
 
 7995        m_customOptions( config.customOptions() )
 
 7998    ReporterBase::~ReporterBase() = 
default;
 
 8000    void ReporterBase::listReporters(
 
 8001        std::vector<ReporterDescription> 
const& descriptions ) {
 
 8002        defaultListReporters(m_stream, descriptions, m_config->verbosity());
 
 8005    void ReporterBase::listListeners(
 
 8006        std::vector<ListenerDescription> 
const& descriptions ) {
 
 8007        defaultListListeners( m_stream, descriptions );
 
 8010    void ReporterBase::listTests(std::vector<TestCaseHandle> 
const& tests) {
 
 8011        defaultListTests(m_stream,
 
 8014                         m_config->hasTestFilters(),
 
 8015                         m_config->verbosity());
 
 8018    void ReporterBase::listTags(std::vector<TagInfo> 
const& tags) {
 
 8019        defaultListTags( m_stream, tags, m_config->hasTestFilters() );
 
 8033    static constexpr Colour::Code compactDimColour = Colour::FileName;
 
 8035#ifdef CATCH_PLATFORM_MAC 
 8036    static constexpr Catch::StringRef compactFailedString = 
"FAILED"_sr;
 
 8037    static constexpr Catch::StringRef compactPassedString = 
"PASSED"_sr;
 
 8039    static constexpr Catch::StringRef compactFailedString = 
"failed"_sr;
 
 8040    static constexpr Catch::StringRef compactPassedString = 
"passed"_sr;
 
 8044class AssertionPrinter {
 
 8046    AssertionPrinter& operator= (AssertionPrinter 
const&) = 
delete;
 
 8047    AssertionPrinter(AssertionPrinter 
const&) = 
delete;
 
 8048    AssertionPrinter(std::ostream& _stream, AssertionStats 
const& _stats, 
bool _printInfoMessages, ColourImpl* colourImpl_)
 
 8050        , 
result(_stats.assertionResult)
 
 8051        , messages(_stats.infoMessages)
 
 8052        , itMessage(_stats.infoMessages.
begin())
 
 8053        , printInfoMessages(_printInfoMessages)
 
 8054        , colourImpl(colourImpl_)
 
 8060        itMessage = messages.begin();
 
 8062        switch (
result.getResultType()) {
 
 8064            printResultType(Colour::ResultSuccess, compactPassedString);
 
 8065            printOriginalExpression();
 
 8066            printReconstructedExpression();
 
 8067            if (!
result.hasExpression())
 
 8068                printRemainingMessages(Colour::None);
 
 8070                printRemainingMessages();
 
 8072        case ResultWas::ExpressionFailed:
 
 8074                printResultType(Colour::ResultSuccess, compactFailedString + 
" - but was ok"_sr);
 
 8076                printResultType(Colour::Error, compactFailedString);
 
 8077            printOriginalExpression();
 
 8078            printReconstructedExpression();
 
 8079            printRemainingMessages();
 
 8081        case ResultWas::ThrewException:
 
 8082            printResultType(Colour::Error, compactFailedString);
 
 8083            printIssue(
"unexpected exception with message:");
 
 8085            printExpressionWas();
 
 8086            printRemainingMessages();
 
 8088        case ResultWas::FatalErrorCondition:
 
 8089            printResultType(Colour::Error, compactFailedString);
 
 8090            printIssue(
"fatal error condition with message:");
 
 8092            printExpressionWas();
 
 8093            printRemainingMessages();
 
 8095        case ResultWas::DidntThrowException:
 
 8096            printResultType(Colour::Error, compactFailedString);
 
 8097            printIssue(
"expected exception, got none");
 
 8098            printExpressionWas();
 
 8099            printRemainingMessages();
 
 8101        case ResultWas::Info:
 
 8102            printResultType(Colour::None, 
"info"_sr);
 
 8104            printRemainingMessages();
 
 8106        case ResultWas::Warning:
 
 8107            printResultType(Colour::None, 
"warning"_sr);
 
 8109            printRemainingMessages();
 
 8111        case ResultWas::ExplicitFailure:
 
 8112            printResultType(Colour::Error, compactFailedString);
 
 8113            printIssue(
"explicitly");
 
 8114            printRemainingMessages(Colour::None);
 
 8116        case ResultWas::ExplicitSkip:
 
 8117            printResultType(Colour::Skip, 
"skipped"_sr);
 
 8119            printRemainingMessages();
 
 8122        case ResultWas::Unknown:
 
 8123        case ResultWas::FailureBit:
 
 8124        case ResultWas::Exception:
 
 8125            printResultType(Colour::Error, 
"** internal error **");
 
 8131    void printSourceInfo()
 const {
 
 8132        stream << colourImpl->guardColour( Colour::FileName )
 
 8133               << 
result.getSourceInfo() << 
':';
 
 8136    void printResultType(Colour::Code colour, StringRef passOrFail)
 const {
 
 8137        if (!passOrFail.empty()) {
 
 8138            stream << colourImpl->guardColour(colour) << 
' ' << passOrFail;
 
 8143    void printIssue(
char const* issue)
 const {
 
 8147    void printExpressionWas() {
 
 8148        if (
result.hasExpression()) {
 
 8151                stream << colourImpl->guardColour(compactDimColour) << 
" expression was:";
 
 8153            printOriginalExpression();
 
 8157    void printOriginalExpression()
 const {
 
 8158        if (
result.hasExpression()) {
 
 8163    void printReconstructedExpression()
 const {
 
 8164        if (
result.hasExpandedExpression()) {
 
 8165            stream << colourImpl->guardColour(compactDimColour) << 
" for: ";
 
 8170    void printMessage() {
 
 8171        if (itMessage != messages.end()) {
 
 8172            stream << 
" '" << itMessage->message << 
'\'';
 
 8177    void printRemainingMessages(Colour::Code colour = compactDimColour) {
 
 8178        if (itMessage == messages.end())
 
 8181        const auto itEnd = messages.cend();
 
 8182        const auto N = 
static_cast<std::size_t
>(itEnd - itMessage);
 
 8184        stream << colourImpl->guardColour( colour ) << 
" with " 
 8185               << pluralise( N, 
"message"_sr ) << 
':';
 
 8187        while (itMessage != itEnd) {
 
 8189            if (printInfoMessages || itMessage->type != ResultWas::Info) {
 
 8191                if (itMessage != itEnd) {
 
 8192                    stream << colourImpl->guardColour(compactDimColour) << 
" and";
 
 8202    AssertionResult 
const& 
result;
 
 8203    std::vector<MessageInfo> 
const& messages;
 
 8204    std::vector<MessageInfo>::const_iterator itMessage;
 
 8205    bool printInfoMessages;
 
 8206    ColourImpl* colourImpl;
 
 8211        std::string CompactReporter::getDescription() {
 
 8212            return "Reports test results on a single line, suitable for IDEs";
 
 8215        void CompactReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
 
 8216            m_stream << 
"No test cases matched '" << unmatchedSpec << 
"'\n";
 
 8219        void CompactReporter::testRunStarting( TestRunInfo 
const& ) {
 
 8220            if ( m_config->testSpec().hasFilters() ) {
 
 8221                m_stream << m_colour->guardColour( Colour::BrightYellow )
 
 8223                         << m_config->testSpec()
 
 8226            m_stream << 
"RNG seed: " << 
getSeed() << 
'\n';
 
 8229        void CompactReporter::assertionEnded( AssertionStats 
const& _assertionStats ) {
 
 8230            AssertionResult 
const& 
result = _assertionStats.assertionResult;
 
 8232            bool printInfoMessages = 
true;
 
 8235            if( !m_config->includeSuccessfulResults() && 
result.isOk() ) {
 
 8236                if( 
result.getResultType() != ResultWas::Warning && 
result.getResultType() != ResultWas::ExplicitSkip )
 
 8238                printInfoMessages = 
false;
 
 8241            AssertionPrinter printer( m_stream, _assertionStats, printInfoMessages, m_colour.get() );
 
 8244            m_stream << 
'\n' << std::flush;
 
 8247        void CompactReporter::sectionEnded(SectionStats 
const& _sectionStats) {
 
 8248            double dur = _sectionStats.durationInSeconds;
 
 8249            if ( shouldShowDuration( *m_config, dur ) ) {
 
 8250                m_stream << getFormattedDuration( dur ) << 
" s: " << _sectionStats.sectionInfo.name << 
'\n' << std::flush;
 
 8254        void CompactReporter::testRunEnded( TestRunStats 
const& _testRunStats ) {
 
 8255            printTestRunTotals( m_stream, *m_colour, _testRunStats.totals );
 
 8256            m_stream << 
"\n\n" << std::flush;
 
 8257            StreamingReporterBase::testRunEnded( _testRunStats );
 
 8260        CompactReporter::~CompactReporter() {}
 
 8269#if defined(_MSC_VER) 
 8270#pragma warning(push) 
 8271#pragma warning(disable:4061)  
 8275#if defined(__clang__) 
 8276#  pragma clang diagnostic push 
 8278#  pragma clang diagnostic ignored "-Wunused-function" 
 8288class ConsoleAssertionPrinter {
 
 8290    ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter 
const&) = 
delete;
 
 8291    ConsoleAssertionPrinter(ConsoleAssertionPrinter 
const&) = 
delete;
 
 8292    ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats 
const& _stats, ColourImpl* colourImpl_, 
bool _printInfoMessages)
 
 8295        result(_stats.assertionResult),
 
 8296        colour(Colour::
None),
 
 8297        messages(_stats.infoMessages),
 
 8298        colourImpl(colourImpl_),
 
 8299        printInfoMessages(_printInfoMessages) {
 
 8300        switch (
result.getResultType()) {
 
 8302            colour = Colour::Success;
 
 8303            passOrFail = 
"PASSED"_sr;
 
 8305            if (messages.size() == 1)
 
 8306                messageLabel = 
"with message"_sr;
 
 8307            if (messages.size() > 1)
 
 8308                messageLabel = 
"with messages"_sr;
 
 8310        case ResultWas::ExpressionFailed:
 
 8312                colour = Colour::Success;
 
 8313                passOrFail = 
"FAILED - but was ok"_sr;
 
 8315                colour = Colour::Error;
 
 8316                passOrFail = 
"FAILED"_sr;
 
 8318            if (messages.size() == 1)
 
 8319                messageLabel = 
"with message"_sr;
 
 8320            if (messages.size() > 1)
 
 8321                messageLabel = 
"with messages"_sr;
 
 8323        case ResultWas::ThrewException:
 
 8324            colour = Colour::Error;
 
 8325            passOrFail = 
"FAILED"_sr;
 
 8327            switch (messages.size()) { 
case 0:
 
 8328                messageLabel = 
"due to unexpected exception with "_sr;
 
 8331                messageLabel = 
"due to unexpected exception with message"_sr;
 
 8334                messageLabel = 
"due to unexpected exception with messages"_sr;
 
 8338        case ResultWas::FatalErrorCondition:
 
 8339            colour = Colour::Error;
 
 8340            passOrFail = 
"FAILED"_sr;
 
 8341            messageLabel = 
"due to a fatal error condition"_sr;
 
 8343        case ResultWas::DidntThrowException:
 
 8344            colour = Colour::Error;
 
 8345            passOrFail = 
"FAILED"_sr;
 
 8346            messageLabel = 
"because no exception was thrown where one was expected"_sr;
 
 8348        case ResultWas::Info:
 
 8349            messageLabel = 
"info"_sr;
 
 8351        case ResultWas::Warning:
 
 8352            messageLabel = 
"warning"_sr;
 
 8354        case ResultWas::ExplicitFailure:
 
 8355            passOrFail = 
"FAILED"_sr;
 
 8356            colour = Colour::Error;
 
 8357            if (messages.size() == 1)
 
 8358                messageLabel = 
"explicitly with message"_sr;
 
 8359            if (messages.size() > 1)
 
 8360                messageLabel = 
"explicitly with messages"_sr;
 
 8362        case ResultWas::ExplicitSkip:
 
 8363            colour = Colour::Skip;
 
 8364            passOrFail = 
"SKIPPED"_sr;
 
 8365            if (messages.size() == 1)
 
 8366                messageLabel = 
"explicitly with message"_sr;
 
 8367            if (messages.size() > 1)
 
 8368                messageLabel = 
"explicitly with messages"_sr;
 
 8371        case ResultWas::Unknown:
 
 8372        case ResultWas::FailureBit:
 
 8373        case ResultWas::Exception:
 
 8374            passOrFail = 
"** internal error **"_sr;
 
 8375            colour = Colour::Error;
 
 8380    void print()
 const {
 
 8382        if (stats.totals.assertions.total() > 0) {
 
 8384            printOriginalExpression();
 
 8385            printReconstructedExpression();
 
 8393    void printResultType()
 const {
 
 8394        if (!passOrFail.empty()) {
 
 8395            stream << colourImpl->guardColour(colour) << passOrFail << 
":\n";
 
 8398    void printOriginalExpression()
 const {
 
 8399        if (
result.hasExpression()) {
 
 8400            stream << colourImpl->guardColour( Colour::OriginalExpression )
 
 8401                   << 
"  " << 
result.getExpressionInMacro() << 
'\n';
 
 8404    void printReconstructedExpression()
 const {
 
 8405        if (
result.hasExpandedExpression()) {
 
 8406            stream << 
"with expansion:\n";
 
 8407            stream << colourImpl->guardColour( Colour::ReconstructedExpression )
 
 8408                   << TextFlow::Column( 
result.getExpandedExpression() )
 
 8413    void printMessage()
 const {
 
 8414        if (!messageLabel.empty())
 
 8415            stream << messageLabel << 
':' << 
'\n';
 
 8416        for (
auto const& 
msg : messages) {
 
 8418            if (printInfoMessages || 
msg.type != ResultWas::Info)
 
 8419                stream << TextFlow::Column(
msg.message).indent(2) << 
'\n';
 
 8422    void printSourceInfo()
 const {
 
 8423        stream << colourImpl->guardColour( Colour::FileName )
 
 8424               << 
result.getSourceInfo() << 
": ";
 
 8428    AssertionStats 
const& stats;
 
 8429    AssertionResult 
const& 
result;
 
 8430    Colour::Code colour;
 
 8431    StringRef passOrFail;
 
 8432    StringRef messageLabel;
 
 8433    std::vector<MessageInfo> 
const& messages;
 
 8434    ColourImpl* colourImpl;
 
 8435    bool printInfoMessages;
 
 8438std::size_t makeRatio( std::uint64_t number, std::uint64_t total ) {
 
 8439    const auto ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
 
 8440    return (ratio == 0 && number > 0) ? 1 : 
static_cast<std::size_t
>(ratio);
 
 8444findMax( std::size_t& 
i, std::size_t& 
j, std::size_t& k, std::size_t& l ) {
 
 8445    if (
i > 
j && 
i > k && 
i > l)
 
 8447    else if (
j > k && 
j > l)
 
 8455enum class Justification { 
Left, 
Right };
 
 8462struct ColumnBreak {};
 
 8474    static const uint64_t s_nanosecondsInAMicrosecond = 1000;
 
 8475    static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond;
 
 8476    static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
 
 8477    static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
 
 8479    double m_inNanoseconds;
 
 8483    explicit Duration(
double inNanoseconds, Unit 
units = Unit::Auto)
 
 8484        : m_inNanoseconds(inNanoseconds),
 
 8486        if (m_units == Unit::Auto) {
 
 8487            if (m_inNanoseconds < s_nanosecondsInAMicrosecond)
 
 8488                m_units = Unit::Nanoseconds;
 
 8489            else if (m_inNanoseconds < s_nanosecondsInAMillisecond)
 
 8490                m_units = Unit::Microseconds;
 
 8491            else if (m_inNanoseconds < s_nanosecondsInASecond)
 
 8492                m_units = Unit::Milliseconds;
 
 8493            else if (m_inNanoseconds < s_nanosecondsInAMinute)
 
 8494                m_units = Unit::Seconds;
 
 8496                m_units = Unit::Minutes;
 
 8501    auto value() const -> 
double {
 
 8503        case Unit::Microseconds:
 
 8504            return m_inNanoseconds / 
static_cast<double>(s_nanosecondsInAMicrosecond);
 
 8505        case Unit::Milliseconds:
 
 8506            return m_inNanoseconds / 
static_cast<double>(s_nanosecondsInAMillisecond);
 
 8508            return m_inNanoseconds / 
static_cast<double>(s_nanosecondsInASecond);
 
 8510            return m_inNanoseconds / 
static_cast<double>(s_nanosecondsInAMinute);
 
 8512            return m_inNanoseconds;
 
 8515    StringRef unitsAsString()
 const {
 
 8517        case Unit::Nanoseconds:
 
 8519        case Unit::Microseconds:
 
 8521        case Unit::Milliseconds:
 
 8528            return "** internal error **"_sr;
 
 8533        return os << duration.value() << 
' ' << duration.unitsAsString();
 
 8540    std::vector<ColumnInfo> m_columnInfos;
 
 8541    ReusableStringStream m_oss;
 
 8542    int m_currentColumn = -1;
 
 8543    bool m_isOpen = 
false;
 
 8546    TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos )
 
 8548        m_columnInfos( CATCH_MOVE( columnInfos ) ) {}
 
 8550    auto columnInfos() const -> 
std::vector<ColumnInfo> const& {
 
 8551        return m_columnInfos;
 
 8557            *
this << RowBreak();
 
 8559      TextFlow::Columns headerCols;
 
 8561      for (
auto const& info : m_columnInfos) {
 
 8562                assert(info.width > 2);
 
 8563        headerCols += TextFlow::Column(info.name).width(info.width - 2);
 
 8564        headerCols += spacer;
 
 8566      m_os << headerCols << 
'\n';
 
 8568            m_os << lineOfChars(
'-') << 
'\n';
 
 8573            *
this << RowBreak();
 
 8574            m_os << 
'\n' << std::flush;
 
 8579    template<
typename T>
 
 8580    friend TablePrinter& operator << (TablePrinter& tp, T 
const& 
value) {
 
 8585    friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {
 
 8586        auto colStr = tp.m_oss.str();
 
 8587        const auto strSize = colStr.size();
 
 8590        if (tp.m_currentColumn == 
static_cast<int>(tp.m_columnInfos.size() - 1)) {
 
 8591            tp.m_currentColumn = -1;
 
 8594        tp.m_currentColumn++;
 
 8596        auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
 
 8597        auto padding = (strSize + 1 < colInfo.width)
 
 8598            ? std::string(colInfo.width - (strSize + 1), 
' ')
 
 8600        if (colInfo.justification == Justification::Left)
 
 8601            tp.m_os << colStr << 
padding << 
' ';
 
 8603            tp.m_os << 
padding << colStr << 
' ';
 
 8607    friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {
 
 8608        if (tp.m_currentColumn > 0) {
 
 8610            tp.m_currentColumn = -1;
 
 8616ConsoleReporter::ConsoleReporter(ReporterConfig&& config):
 
 8617    StreamingReporterBase( CATCH_MOVE( config ) ),
 
 8618    m_tablePrinter(Detail::make_unique<TablePrinter>(m_stream,
 
 8619        [&config]() -> 
std::
vector<ColumnInfo> {
 
 8620        if (config.fullConfig()->benchmarkNoAnalysis())
 
 8623                { 
"benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left },
 
 8624                { 
"     samples", 14, Justification::Right },
 
 8625                { 
"  iterations", 14, Justification::Right },
 
 8626                { 
"        mean", 14, Justification::Right }
 
 8632                { 
"benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left },
 
 8633                { 
"samples      mean       std dev", 14, Justification::Right },
 
 8634                { 
"iterations   low mean   low std dev", 14, Justification::Right },
 
 8635                { 
"estimated    high mean  high std dev", 14, Justification::Right }
 
 8639ConsoleReporter::~ConsoleReporter() = 
default;
 
 8641std::string ConsoleReporter::getDescription() {
 
 8642    return "Reports test results as plain lines of text";
 
 8645void ConsoleReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
 
 8646    m_stream << 
"No test cases matched '" << unmatchedSpec << 
"'\n";
 
 8649void ConsoleReporter::reportInvalidTestSpec( StringRef arg ) {
 
 8650    m_stream << 
"Invalid Filter: " << arg << 
'\n';
 
 8653void ConsoleReporter::assertionStarting(AssertionInfo 
const&) {}
 
 8655void ConsoleReporter::assertionEnded(AssertionStats 
const& _assertionStats) {
 
 8656    AssertionResult 
const& 
result = _assertionStats.assertionResult;
 
 8658    bool includeResults = m_config->includeSuccessfulResults() || !
result.isOk();
 
 8662    if (!includeResults && 
result.getResultType() != ResultWas::Warning && 
result.getResultType() != ResultWas::ExplicitSkip)
 
 8667    ConsoleAssertionPrinter printer(m_stream, _assertionStats, m_colour.get(), includeResults);
 
 8669    m_stream << 
'\n' << std::flush;
 
 8672void ConsoleReporter::sectionStarting(SectionInfo 
const& _sectionInfo) {
 
 8673    m_tablePrinter->close();
 
 8674    m_headerPrinted = 
false;
 
 8675    StreamingReporterBase::sectionStarting(_sectionInfo);
 
 8677void ConsoleReporter::sectionEnded(SectionStats 
const& _sectionStats) {
 
 8678    m_tablePrinter->close();
 
 8679    if (_sectionStats.missingAssertions) {
 
 8682            m_colour->guardColour( Colour::ResultError ).engage( m_stream );
 
 8683        if (m_sectionStack.size() > 1)
 
 8684            m_stream << 
"\nNo assertions in section";
 
 8686            m_stream << 
"\nNo assertions in test case";
 
 8687        m_stream << 
" '" << _sectionStats.sectionInfo.name << 
"'\n\n" << std::flush;
 
 8689    double dur = _sectionStats.durationInSeconds;
 
 8690    if (shouldShowDuration(*m_config, dur)) {
 
 8691        m_stream << getFormattedDuration(dur) << 
" s: " << _sectionStats.sectionInfo.name << 
'\n' << std::flush;
 
 8693    if (m_headerPrinted) {
 
 8694        m_headerPrinted = 
false;
 
 8696    StreamingReporterBase::sectionEnded(_sectionStats);
 
 8699void ConsoleReporter::benchmarkPreparing( StringRef 
name ) {
 
 8700  lazyPrintWithoutClosingBenchmarkTable();
 
 8702  auto nameCol = TextFlow::Column( 
static_cast<std::string
>( 
name ) )
 
 8703                       .width( m_tablePrinter->columnInfos()[0].width - 2 );
 
 8705  bool firstLine = 
true;
 
 8706  for (
auto line : nameCol) {
 
 8708      (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
 
 8712    (*m_tablePrinter) << 
line << ColumnBreak();
 
 8716void ConsoleReporter::benchmarkStarting(BenchmarkInfo 
const& info) {
 
 8717    (*m_tablePrinter) << info.samples << ColumnBreak()
 
 8718        << info.iterations << ColumnBreak();
 
 8719    if (!m_config->benchmarkNoAnalysis())
 
 8720        (*m_tablePrinter) << 
Duration(info.estimatedDuration) << ColumnBreak();
 
 8722void ConsoleReporter::benchmarkEnded(BenchmarkStats<> 
const& stats) {
 
 8723    if (m_config->benchmarkNoAnalysis())
 
 8725        (*m_tablePrinter) << 
Duration(stats.mean.point.count()) << ColumnBreak();
 
 8729        (*m_tablePrinter) << ColumnBreak()
 
 8730            << 
Duration(stats.mean.point.count()) << ColumnBreak()
 
 8731            << 
Duration(stats.mean.lower_bound.count()) << ColumnBreak()
 
 8732            << 
Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()
 
 8733            << 
Duration(stats.standardDeviation.point.count()) << ColumnBreak()
 
 8734            << 
Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()
 
 8735            << 
Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();
 
 8739void ConsoleReporter::benchmarkFailed( StringRef error ) {
 
 8740    auto guard = m_colour->guardColour( Colour::Red ).engage( m_stream );
 
 8742        << 
"Benchmark failed (" << error << 
')' 
 8743        << ColumnBreak() << RowBreak();
 
 8746void ConsoleReporter::testCaseEnded(TestCaseStats 
const& _testCaseStats) {
 
 8747    m_tablePrinter->close();
 
 8748    StreamingReporterBase::testCaseEnded(_testCaseStats);
 
 8749    m_headerPrinted = 
false;
 
 8751void ConsoleReporter::testRunEnded(TestRunStats 
const& _testRunStats) {
 
 8752    printTotalsDivider(_testRunStats.totals);
 
 8753    printTestRunTotals( m_stream, *m_colour, _testRunStats.totals );
 
 8754    m_stream << 
'\n' << std::flush;
 
 8755    StreamingReporterBase::testRunEnded(_testRunStats);
 
 8757void ConsoleReporter::testRunStarting(TestRunInfo 
const& _testInfo) {
 
 8758    StreamingReporterBase::testRunStarting(_testInfo);
 
 8759    if ( m_config->testSpec().hasFilters() ) {
 
 8760        m_stream << m_colour->guardColour( Colour::BrightYellow ) << 
"Filters: " 
 8761                 << m_config->testSpec() << 
'\n';
 
 8763    m_stream << 
"Randomness seeded to: " << 
getSeed() << 
'\n';
 
 8766void ConsoleReporter::lazyPrint() {
 
 8768    m_tablePrinter->close();
 
 8769    lazyPrintWithoutClosingBenchmarkTable();
 
 8772void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {
 
 8774    if ( !m_testRunInfoPrinted ) {
 
 8777    if (!m_headerPrinted) {
 
 8778        printTestCaseAndSectionHeader();
 
 8779        m_headerPrinted = 
true;
 
 8782void ConsoleReporter::lazyPrintRunInfo() {
 
 8784             << lineOfChars( 
'~' ) << 
'\n' 
 8785             << m_colour->guardColour( Colour::SecondaryText )
 
 8786             << currentTestRunInfo.name << 
" is a Catch2 v" << 
libraryVersion()
 
 8787             << 
" host application.\n" 
 8788             << 
"Run with -? for options\n\n";
 
 8790    m_testRunInfoPrinted = 
true;
 
 8792void ConsoleReporter::printTestCaseAndSectionHeader() {
 
 8793    assert(!m_sectionStack.empty());
 
 8794    printOpenHeader(currentTestCaseInfo->name);
 
 8796    if (m_sectionStack.size() > 1) {
 
 8797        auto guard = m_colour->guardColour( Colour::Headers ).engage( m_stream );
 
 8800            it = m_sectionStack.begin() + 1, 
 
 8801            itEnd = m_sectionStack.end();
 
 8802        for (; it != itEnd; ++it)
 
 8803            printHeaderString(it->name, 2);
 
 8806    SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
 
 8809    m_stream << lineOfChars( 
'-' ) << 
'\n' 
 8810             << m_colour->guardColour( Colour::FileName ) << lineInfo << 
'\n' 
 8811             << lineOfChars( 
'.' ) << 
"\n\n" 
 8815void ConsoleReporter::printClosedHeader(std::string 
const& _name) {
 
 8816    printOpenHeader(_name);
 
 8817    m_stream << lineOfChars(
'.') << 
'\n';
 
 8819void ConsoleReporter::printOpenHeader(std::string 
const& _name) {
 
 8820    m_stream << lineOfChars(
'-') << 
'\n';
 
 8822        auto guard = m_colour->guardColour( Colour::Headers ).engage( m_stream );
 
 8823        printHeaderString(_name);
 
 8827void ConsoleReporter::printHeaderString(std::string 
const& _string, std::size_t indent) {
 
 8848    std::size_t 
idx = _string.find( 
": " );
 
 8849    if ( idx != std::string::npos && idx < CATCH_CONFIG_CONSOLE_WIDTH / 4 ) {
 
 8854    m_stream << TextFlow::Column( _string )
 
 8855                  .indent( indent + idx )
 
 8856                  .initialIndent( indent )
 
 8860void ConsoleReporter::printTotalsDivider(Totals 
const& totals) {
 
 8861    if (totals.testCases.total() > 0) {
 
 8862        std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
 
 8863        std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
 
 8864        std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
 
 8865        std::size_t skippedRatio = makeRatio(totals.testCases.skipped, totals.testCases.total());
 
 8866        while (failedRatio + failedButOkRatio + passedRatio + skippedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
 
 8867            findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)++;
 
 8868        while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
 
 8869            findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)--;
 
 8871        m_stream << m_colour->guardColour( Colour::Error )
 
 8872                 << std::string( failedRatio, 
'=' )
 
 8873                 << m_colour->guardColour( Colour::ResultExpectedFailure )
 
 8874                 << std::string( failedButOkRatio, 
'=' );
 
 8875        if ( totals.testCases.allPassed() ) {
 
 8876            m_stream << m_colour->guardColour( Colour::ResultSuccess )
 
 8877                     << std::string( passedRatio, 
'=' );
 
 8879            m_stream << m_colour->guardColour( Colour::Success )
 
 8880                     << std::string( passedRatio, 
'=' );
 
 8882        m_stream << m_colour->guardColour( Colour::Skip )
 
 8883                 << std::string( skippedRatio, 
'=' );
 
 8885        m_stream << m_colour->guardColour( Colour::Warning )
 
 8886                 << std::string( CATCH_CONFIG_CONSOLE_WIDTH - 1, 
'=' );
 
 8893#if defined(_MSC_VER) 
 8897#if defined(__clang__) 
 8898#  pragma clang diagnostic pop 
 8909        struct BySectionInfo {
 
 8910            BySectionInfo( SectionInfo 
const& 
other ): m_other( 
other ) {}
 
 8911            BySectionInfo( BySectionInfo 
const& 
other ):
 
 8912                m_other( 
other.m_other ) {}
 
 8914                Detail::unique_ptr<CumulativeReporterBase::SectionNode> 
const&
 
 8917                    ( node->stats.sectionInfo.name == m_other.name ) &&
 
 8918                    ( node->stats.sectionInfo.lineInfo == m_other.lineInfo ) );
 
 8920            void operator=( BySectionInfo 
const& ) = 
delete;
 
 8923            SectionInfo 
const& m_other;
 
 8929        AssertionOrBenchmarkResult::AssertionOrBenchmarkResult(
 
 8930            AssertionStats 
const& assertion ):
 
 8931            m_assertion( assertion ) {}
 
 8933        AssertionOrBenchmarkResult::AssertionOrBenchmarkResult(
 
 8934            BenchmarkStats<> 
const& benchmark ):
 
 8935            m_benchmark( benchmark ) {}
 
 8937        bool AssertionOrBenchmarkResult::isAssertion()
 const {
 
 8938            return m_assertion.some();
 
 8940        bool AssertionOrBenchmarkResult::isBenchmark()
 const {
 
 8941            return m_benchmark.some();
 
 8944        AssertionStats 
const& AssertionOrBenchmarkResult::asAssertion()
 const {
 
 8945            assert(m_assertion.some());
 
 8947            return *m_assertion;
 
 8949        BenchmarkStats<> 
const& AssertionOrBenchmarkResult::asBenchmark()
 const {
 
 8950            assert(m_benchmark.some());
 
 8952            return *m_benchmark;
 
 8957    CumulativeReporterBase::~CumulativeReporterBase() = 
default;
 
 8959    void CumulativeReporterBase::benchmarkEnded(BenchmarkStats<> 
const& benchmarkStats) {
 
 8960        m_sectionStack.back()->assertionsAndBenchmarks.emplace_back(benchmarkStats);
 
 8964    CumulativeReporterBase::sectionStarting( SectionInfo 
const& sectionInfo ) {
 
 8966        SectionStats incompleteStats( SectionInfo(sectionInfo), Counts(), 0, 
false );
 
 8968        if ( m_sectionStack.empty() ) {
 
 8969            if ( !m_rootSection ) {
 
 8971                    Detail::make_unique<SectionNode>( incompleteStats );
 
 8973            node = m_rootSection.get();
 
 8975            SectionNode& parentNode = *m_sectionStack.back();
 
 8976            auto it = std::find_if( parentNode.childSections.begin(),
 
 8977                                    parentNode.childSections.end(),
 
 8978                                    BySectionInfo( sectionInfo ) );
 
 8979            if ( it == parentNode.childSections.end() ) {
 
 8981                    Detail::make_unique<SectionNode>( incompleteStats );
 
 8982                node = newNode.get();
 
 8983                parentNode.childSections.push_back( CATCH_MOVE( newNode ) );
 
 8989        m_deepestSection = node;
 
 8990        m_sectionStack.push_back( node );
 
 8993    void CumulativeReporterBase::assertionEnded(
 
 8994        AssertionStats 
const& assertionStats ) {
 
 8995        assert( !m_sectionStack.empty() );
 
 9001        if ( m_shouldStoreFailedAssertions &&
 
 9002             !assertionStats.assertionResult.isOk() ) {
 
 9004                assertionStats.assertionResult.getExpandedExpression() );
 
 9006        if ( m_shouldStoreSuccesfulAssertions &&
 
 9007             assertionStats.assertionResult.isOk() ) {
 
 9009                assertionStats.assertionResult.getExpandedExpression() );
 
 9011        SectionNode& sectionNode = *m_sectionStack.back();
 
 9012        sectionNode.assertionsAndBenchmarks.emplace_back( assertionStats );
 
 9015    void CumulativeReporterBase::sectionEnded( SectionStats 
const& sectionStats ) {
 
 9016        assert( !m_sectionStack.empty() );
 
 9017        SectionNode& node = *m_sectionStack.back();
 
 9018        node.stats = sectionStats;
 
 9019        m_sectionStack.pop_back();
 
 9022    void CumulativeReporterBase::testCaseEnded(
 
 9023        TestCaseStats 
const& testCaseStats ) {
 
 9024        auto node = Detail::make_unique<TestCaseNode>( testCaseStats );
 
 9025        assert( m_sectionStack.size() == 0 );
 
 9026        node->children.push_back( CATCH_MOVE(m_rootSection) );
 
 9027        m_testCases.push_back( CATCH_MOVE(node) );
 
 9029        assert( m_deepestSection );
 
 9030        m_deepestSection->stdOut = testCaseStats.stdOut;
 
 9031        m_deepestSection->stdErr = testCaseStats.stdErr;
 
 9035    void CumulativeReporterBase::testRunEnded( TestRunStats 
const& testRunStats ) {
 
 9036        assert(!m_testRun && 
"CumulativeReporterBase assumes there can only be one test run");
 
 9037        m_testRun = Detail::make_unique<TestRunNode>( testRunStats );
 
 9038        m_testRun->children.swap( m_testCases );
 
 9039        testRunEndedCumulative();
 
 9042    bool CumulativeReporterBase::SectionNode::hasAnyAssertions()
 const {
 
 9044            assertionsAndBenchmarks.begin(),
 
 9045            assertionsAndBenchmarks.end(),
 
 9046            []( Detail::AssertionOrBenchmarkResult 
const& 
res ) {
 
 9047                return res.isAssertion();
 
 9058    void EventListenerBase::fatalErrorEncountered( StringRef ) {}
 
 9060    void EventListenerBase::benchmarkPreparing( StringRef ) {}
 
 9061    void EventListenerBase::benchmarkStarting( BenchmarkInfo 
const& ) {}
 
 9062    void EventListenerBase::benchmarkEnded( BenchmarkStats<> 
const& ) {}
 
 9063    void EventListenerBase::benchmarkFailed( StringRef ) {}
 
 9065    void EventListenerBase::assertionStarting( AssertionInfo 
const& ) {}
 
 9067    void EventListenerBase::assertionEnded( AssertionStats 
const& ) {}
 
 9068    void EventListenerBase::listReporters(
 
 9069        std::vector<ReporterDescription> 
const& ) {}
 
 9070    void EventListenerBase::listListeners(
 
 9071        std::vector<ListenerDescription> 
const& ) {}
 
 9072    void EventListenerBase::listTests( std::vector<TestCaseHandle> 
const& ) {}
 
 9073    void EventListenerBase::listTags( std::vector<TagInfo> 
const& ) {}
 
 9074    void EventListenerBase::noMatchingTestCases( StringRef ) {}
 
 9075    void EventListenerBase::reportInvalidTestSpec( StringRef ) {}
 
 9076    void EventListenerBase::testRunStarting( TestRunInfo 
const& ) {}
 
 9077    void EventListenerBase::testCaseStarting( TestCaseInfo 
const& ) {}
 
 9078    void EventListenerBase::testCasePartialStarting(TestCaseInfo 
const&, uint64_t) {}
 
 9079    void EventListenerBase::sectionStarting( SectionInfo 
const& ) {}
 
 9080    void EventListenerBase::sectionEnded( SectionStats 
const& ) {}
 
 9081    void EventListenerBase::testCasePartialEnded(TestCaseStats 
const&, uint64_t) {}
 
 9082    void EventListenerBase::testCaseEnded( TestCaseStats 
const& ) {}
 
 9083    void EventListenerBase::testRunEnded( TestRunStats 
const& ) {}
 
 9084    void EventListenerBase::skipTest( TestCaseInfo 
const& ) {}
 
 9099        void listTestNamesOnly(std::ostream& out,
 
 9100                               std::vector<TestCaseHandle> 
const& tests) {
 
 9101            for (
auto const& 
test : tests) {
 
 9102                auto const& testCaseInfo = 
test.getTestCaseInfo();
 
 9105                    out << 
'"' << testCaseInfo.name << 
'"';
 
 9107                    out << testCaseInfo.name;
 
 9120    std::string getFormattedDuration( 
double duration ) {
 
 9125        const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
 
 9126        char buffer[maxDoubleSize];
 
 9131        size_t printedLength = 
static_cast<size_t>(
 
 9132            sprintf_s( 
buffer, 
"%.3f", duration ) );
 
 9134        size_t printedLength = 
static_cast<size_t>(
 
 9135            std::snprintf( 
buffer, maxDoubleSize, 
"%.3f", duration ) );
 
 9137        return std::string( 
buffer, printedLength );
 
 9140    bool shouldShowDuration( IConfig 
const& config, 
double duration ) {
 
 9141        if ( config.showDurations() == ShowDurations::Always ) {
 
 9144        if ( config.showDurations() == ShowDurations::Never ) {
 
 9147        const double min = config.minDuration();
 
 9148        return min >= 0 && duration >= 
min;
 
 9151    std::string serializeFilters( std::vector<std::string> 
const& filters ) {
 
 9153        size_t serialized_size = filters.size() - 1;
 
 9154        for (
auto const& 
filter : filters) {
 
 9155            serialized_size += 
filter.size();
 
 9158        std::string serialized;
 
 9159        serialized.reserve(serialized_size);
 
 9162        for (
auto const& 
filter : filters) {
 
 9164                serialized.push_back(
' ');
 
 9167            serialized.append(
filter);
 
 9174        for ( 
size_t idx = 0; 
idx < CATCH_CONFIG_CONSOLE_WIDTH - 1; ++
idx ) {
 
 9181    defaultListReporters( std::ostream& out,
 
 9182                          std::vector<ReporterDescription> 
const& descriptions,
 
 9184        out << 
"Available reporters:\n";
 
 9185        const auto maxNameLen =
 
 9186            std::max_element( descriptions.begin(),
 
 9188                              []( ReporterDescription 
const& lhs,
 
 9189                                  ReporterDescription 
const& rhs ) {
 
 9190                                  return lhs.name.size() < rhs.name.size();
 
 9194        for ( 
auto const& desc : descriptions ) {
 
 9196                out << TextFlow::Column( desc.name )
 
 9198                           .width( 5 + maxNameLen )
 
 9201                out << TextFlow::Column( desc.name + 
':' )
 
 9203                               .width( 5 + maxNameLen ) +
 
 9204                           TextFlow::Column( desc.description )
 
 9207                               .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 )
 
 9211        out << 
'\n' << std::flush;
 
 9214    void defaultListListeners( std::ostream& out,
 
 9215                               std::vector<ListenerDescription> 
const& descriptions ) {
 
 9216        out << 
"Registered listeners:\n";
 
 9218        if(descriptions.empty()) {
 
 9222        const auto maxNameLen =
 
 9223            std::max_element( descriptions.begin(),
 
 9225                              []( ListenerDescription 
const& lhs,
 
 9226                                  ListenerDescription 
const& rhs ) {
 
 9227                                  return lhs.name.size() < rhs.name.size();
 
 9231        for ( 
auto const& desc : descriptions ) {
 
 9232            out << TextFlow::Column( static_cast<std::string>( desc.name ) +
 
 9235                           .width( maxNameLen + 5 ) +
 
 9236                       TextFlow::Column( desc.description )
 
 9239                           .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 )
 
 9243        out << 
'\n' << std::flush;
 
 9246    void defaultListTags( std::ostream& out,
 
 9247                          std::vector<TagInfo> 
const& tags,
 
 9250            out << 
"Tags for matching test cases:\n";
 
 9252            out << 
"All available tags:\n";
 
 9255        for ( 
auto const& tagCount : tags ) {
 
 9256            ReusableStringStream rss;
 
 9257            rss << 
"  " << std::setw( 2 ) << tagCount.count << 
"  ";
 
 9258            auto str = rss.str();
 
 9259            auto wrapper = TextFlow::Column( tagCount.all() )
 
 9261                               .indent( 
str.size() )
 
 9262                               .width( CATCH_CONFIG_CONSOLE_WIDTH - 10 );
 
 9263            out << 
str << wrapper << 
'\n';
 
 9265        out << pluralise(tags.size(), 
"tag"_sr) << 
"\n\n" << std::flush;
 
 9268    void defaultListTests(std::ostream& out, ColourImpl* streamColour, std::vector<TestCaseHandle> 
const& tests, 
bool isFiltered, 
Verbosity verbosity) {
 
 9273            listTestNamesOnly(out, tests);
 
 9278            out << 
"Matching test cases:\n";
 
 9280            out << 
"All available test cases:\n";
 
 9283        for (
auto const& 
test : tests) {
 
 9284            auto const& testCaseInfo = 
test.getTestCaseInfo();
 
 9285            Colour::Code colour = testCaseInfo.isHidden()
 
 9286                ? Colour::SecondaryText
 
 9288            auto colourGuard = streamColour->guardColour( colour ).engage( out );
 
 9290            out << TextFlow::Column(testCaseInfo.name).indent(2) << 
'\n';
 
 9292                out << TextFlow::Column(Catch::Detail::stringify(testCaseInfo.lineInfo)).indent(4) << 
'\n';
 
 9294            if (!testCaseInfo.tags.empty() &&
 
 9296                out << TextFlow::Column(testCaseInfo.tagsAsString()).indent(6) << 
'\n';
 
 9301            out << pluralise(tests.size(), 
"matching test case"_sr);
 
 9303            out << pluralise(tests.size(), 
"test case"_sr);
 
 9305        out << 
"\n\n" << std::flush;
 
 9309        class SummaryColumn {
 
 9311            SummaryColumn( std::string suffix, Colour::Code colour ):
 
 9312                m_suffix( CATCH_MOVE( suffix ) ), m_colour( colour ) {}
 
 9314            SummaryColumn&& addRow( std::uint64_t 
count ) && {
 
 9316                auto const new_width = std::max( m_width, 
row.size() );
 
 9317                if ( new_width > m_width ) {
 
 9318                    for ( 
auto& oldRow : m_rows ) {
 
 9319                        oldRow.insert( 0, new_width - m_width, 
' ' );
 
 9322                    row.insert( 0, m_width - 
row.size(), 
' ' );
 
 9324                m_width = new_width;
 
 9325                m_rows.push_back( 
row );
 
 9326                return std::move( *
this );
 
 9329            std::string 
const& getSuffix()
 const { 
return m_suffix; }
 
 9330            Colour::Code getColour()
 const { 
return m_colour; }
 
 9331            std::string 
const& getRow( std::size_t 
index )
 const {
 
 9332                return m_rows[
index];
 
 9336            std::string m_suffix;
 
 9337            Colour::Code m_colour;
 
 9338            std::size_t m_width = 0;
 
 9339            std::vector<std::string> m_rows;
 
 9342        void printSummaryRow( std::ostream& 
stream,
 
 9345                              std::vector<SummaryColumn> 
const& 
cols,
 
 9347            for ( 
auto const& 
col : 
cols ) {
 
 9349                auto const& suffix = 
col.getSuffix();
 
 9350                if ( suffix.empty() ) {
 
 9352                    if ( 
value != 
"0" ) {
 
 9355                        stream << colour.guardColour( Colour::Warning )
 
 9358                } 
else if ( 
value != 
"0" ) {
 
 9359                    stream << colour.guardColour( Colour::LightGrey ) << 
" | " 
 9360                           << colour.guardColour( 
col.getColour() ) << 
value 
 9368    void printTestRunTotals( std::ostream& 
stream,
 
 9369                             ColourImpl& streamColour,
 
 9370                             Totals 
const& totals ) {
 
 9371        if ( totals.testCases.total() == 0 ) {
 
 9372            stream << streamColour.guardColour( Colour::Warning )
 
 9373                   << 
"No tests ran\n";
 
 9377        if ( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
 
 9378            stream << streamColour.guardColour( Colour::ResultSuccess )
 
 9379                   << 
"All tests passed";
 
 9381                   << pluralise( totals.assertions.passed, 
"assertion"_sr )
 
 9383                   << pluralise( totals.testCases.passed, 
"test case"_sr )
 
 9388        std::vector<SummaryColumn> columns;
 
 9390        const auto totalAssertionCount =
 
 9391            totals.assertions.total() - totals.assertions.skipped;
 
 9392        columns.push_back( SummaryColumn( 
"", Colour::None )
 
 9393                               .addRow( totals.testCases.total() )
 
 9394                               .addRow( totalAssertionCount ) );
 
 9395        columns.push_back( SummaryColumn( 
"passed", Colour::Success )
 
 9396                               .addRow( totals.testCases.passed )
 
 9397                               .addRow( totals.assertions.passed ) );
 
 9398        columns.push_back( SummaryColumn( 
"failed", Colour::ResultError )
 
 9399                               .addRow( totals.testCases.failed )
 
 9400                               .addRow( totals.assertions.failed ) );
 
 9401        columns.push_back( SummaryColumn( 
"skipped", Colour::Skip )
 
 9402                               .addRow( totals.testCases.skipped )
 
 9406            SummaryColumn( 
"failed as expected", Colour::ResultExpectedFailure )
 
 9407                .addRow( totals.testCases.failedButOk )
 
 9408                .addRow( totals.assertions.failedButOk ) );
 
 9409        printSummaryRow( 
stream, streamColour, 
"test cases"_sr, columns, 0 );
 
 9410        printSummaryRow( 
stream, streamColour, 
"assertions"_sr, columns, 1 );
 
 9428            std::time(&rawtime);
 
 9430            std::tm timeInfo = {};
 
 9431#if defined (_MSC_VER) || defined (__MINGW32__) 
 9432            gmtime_s(&timeInfo, &rawtime);
 
 9433#elif defined (CATCH_PLATFORM_PLAYSTATION) 
 9434            gmtime_s(&rawtime, &timeInfo);
 
 9435#elif defined (__IAR_SYSTEMS_ICC__) 
 9436            timeInfo = *std::gmtime(&rawtime);
 
 9438            gmtime_r(&rawtime, &timeInfo);
 
 9441            auto const timeStampSize = 
sizeof(
"2017-01-16T17:06:45Z");
 
 9442            char timeStamp[timeStampSize];
 
 9443            const char * 
const fmt = 
"%Y-%m-%dT%H:%M:%SZ";
 
 9445            std::strftime(timeStamp, timeStampSize, 
fmt, &timeInfo);
 
 9447            return std::string(timeStamp, timeStampSize - 1);
 
 9450        std::string fileNameTag(std::vector<Tag> 
const& tags) {
 
 9451            auto it = std::find_if(
begin(tags),
 
 9453                                   [] (Tag 
const& tag) {
 
 9454                                       return tag.original.size() > 0
 
 9455                                           && tag.original[0] == 
'#'; });
 
 9456            if (it != tags.end()) {
 
 9457                return static_cast<std::string
>(
 
 9458                    it->original.substr(1, it->original.size() - 1)
 
 9461            return std::string();
 
 9468        std::string formatDuration( 
double seconds ) {
 
 9469            ReusableStringStream rss;
 
 9470            rss << std::fixed << std::setprecision( 3 ) << seconds;
 
 9474        static void normalizeNamespaceMarkers(std::string& 
str) {
 
 9475            std::size_t 
pos = 
str.find( 
"::" );
 
 9476            while ( 
pos != 
str.npos ) {
 
 9477                str.replace( 
pos, 2, 
"." );
 
 9485    JunitReporter::JunitReporter( ReporterConfig&& _config )
 
 9486        :   CumulativeReporterBase( CATCH_MOVE(_config) ),
 
 9489            m_preferences.shouldRedirectStdOut = 
true;
 
 9490            m_preferences.shouldReportAllAssertions = 
true;
 
 9491            m_shouldStoreSuccesfulAssertions = 
false;
 
 9494    std::string JunitReporter::getDescription() {
 
 9495        return "Reports test results in an XML format that looks like Ant's junitreport target";
 
 9498    void JunitReporter::testRunStarting( TestRunInfo 
const& runInfo )  {
 
 9499        CumulativeReporterBase::testRunStarting( runInfo );
 
 9500        xml.startElement( 
"testsuites" );
 
 9502        stdOutForSuite.clear();
 
 9503        stdErrForSuite.clear();
 
 9504        unexpectedExceptions = 0;
 
 9507    void JunitReporter::testCaseStarting( TestCaseInfo 
const& testCaseInfo ) {
 
 9508        m_okToFail = testCaseInfo.okToFail();
 
 9511    void JunitReporter::assertionEnded( AssertionStats 
const& assertionStats ) {
 
 9512        if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )
 
 9513            unexpectedExceptions++;
 
 9514        CumulativeReporterBase::assertionEnded( assertionStats );
 
 9517    void JunitReporter::testCaseEnded( TestCaseStats 
const& testCaseStats ) {
 
 9518        stdOutForSuite += testCaseStats.stdOut;
 
 9519        stdErrForSuite += testCaseStats.stdErr;
 
 9520        CumulativeReporterBase::testCaseEnded( testCaseStats );
 
 9523    void JunitReporter::testRunEndedCumulative() {
 
 9524        const auto suiteTime = suiteTimer.getElapsedSeconds();
 
 9525        writeRun( *m_testRun, suiteTime );
 
 9529    void JunitReporter::writeRun( TestRunNode 
const& testRunNode, 
double suiteTime ) {
 
 9530        XmlWriter::ScopedElement e = xml.scopedElement( 
"testsuite" );
 
 9532        TestRunStats 
const& stats = testRunNode.value;
 
 9533        xml.writeAttribute( 
"name"_sr, stats.runInfo.name );
 
 9534        xml.writeAttribute( 
"errors"_sr, unexpectedExceptions );
 
 9535        xml.writeAttribute( 
"failures"_sr, stats.totals.assertions.failed-unexpectedExceptions );
 
 9536        xml.writeAttribute( 
"skipped"_sr, stats.totals.assertions.skipped );
 
 9537        xml.writeAttribute( 
"tests"_sr, stats.totals.assertions.total() );
 
 9538        xml.writeAttribute( 
"hostname"_sr, 
"tbd"_sr ); 
 
 9539        if( m_config->showDurations() == ShowDurations::Never )
 
 9540            xml.writeAttribute( 
"time"_sr, 
""_sr );
 
 9542            xml.writeAttribute( 
"time"_sr, formatDuration( suiteTime ) );
 
 9547            auto properties = xml.scopedElement(
"properties");
 
 9548            xml.scopedElement(
"property")
 
 9549                .writeAttribute(
"name"_sr, 
"random-seed"_sr)
 
 9550                .writeAttribute(
"value"_sr, m_config->rngSeed());
 
 9551            if (m_config->testSpec().hasFilters()) {
 
 9552                xml.scopedElement(
"property")
 
 9553                    .writeAttribute(
"name"_sr, 
"filters"_sr)
 
 9554                    .writeAttribute(
"value"_sr, m_config->testSpec());
 
 9559        for( 
auto const& child : testRunNode.children )
 
 9560            writeTestCase( *child );
 
 9562        xml.scopedElement( 
"system-out" ).writeText( 
trim( stdOutForSuite ), XmlFormatting::Newline );
 
 9563        xml.scopedElement( 
"system-err" ).writeText( 
trim( stdErrForSuite ), XmlFormatting::Newline );
 
 9566    void JunitReporter::writeTestCase( TestCaseNode 
const& testCaseNode ) {
 
 9567        TestCaseStats 
const& stats = testCaseNode.value;
 
 9571        assert( testCaseNode.children.size() == 1 );
 
 9572        SectionNode 
const& rootSection = *testCaseNode.children.front();
 
 9574        std::string className =
 
 9575            static_cast<std::string
>( stats.testInfo->className );
 
 9577        if( className.empty() ) {
 
 9578            className = fileNameTag(stats.testInfo->tags);
 
 9579            if ( className.empty() ) {
 
 9580                className = 
"global";
 
 9584        if ( !m_config->name().empty() )
 
 9585            className = 
static_cast<std::string
>(m_config->name()) + 
'.' + className;
 
 9587        normalizeNamespaceMarkers(className);
 
 9589        writeSection( className, 
"", rootSection, stats.testInfo->okToFail() );
 
 9592    void JunitReporter::writeSection( std::string 
const& className,
 
 9593                                      std::string 
const& rootName,
 
 9594                                      SectionNode 
const& sectionNode,
 
 9595                                      bool testOkToFail) {
 
 9596        std::string 
name = 
trim( sectionNode.stats.sectionInfo.name );
 
 9597        if( !rootName.empty() )
 
 9600        if( sectionNode.hasAnyAssertions()
 
 9601           || !sectionNode.stdOut.empty()
 
 9602           || !sectionNode.stdErr.empty() ) {
 
 9603            XmlWriter::ScopedElement e = xml.scopedElement( 
"testcase" );
 
 9604            if( className.empty() ) {
 
 9605                xml.writeAttribute( 
"classname"_sr, 
name );
 
 9606                xml.writeAttribute( 
"name"_sr, 
"root"_sr );
 
 9609                xml.writeAttribute( 
"classname"_sr, className );
 
 9610                xml.writeAttribute( 
"name"_sr, 
name );
 
 9612            xml.writeAttribute( 
"time"_sr, formatDuration( sectionNode.stats.durationInSeconds ) );
 
 9617            xml.writeAttribute( 
"status"_sr, 
"run"_sr );
 
 9619            if (sectionNode.stats.assertions.failedButOk) {
 
 9620                xml.scopedElement(
"skipped")
 
 9621                    .writeAttribute(
"message", 
"TEST_CASE tagged with !mayfail");
 
 9624            writeAssertions( sectionNode );
 
 9627            if( !sectionNode.stdOut.empty() )
 
 9628                xml.scopedElement( 
"system-out" ).writeText( 
trim( sectionNode.stdOut ), XmlFormatting::Newline );
 
 9629            if( !sectionNode.stdErr.empty() )
 
 9630                xml.scopedElement( 
"system-err" ).writeText( 
trim( sectionNode.stdErr ), XmlFormatting::Newline );
 
 9632        for( 
auto const& childNode : sectionNode.childSections )
 
 9634                writeSection( 
name, 
"", *childNode, testOkToFail );
 
 9636                writeSection( className, 
name, *childNode, testOkToFail );
 
 9639    void JunitReporter::writeAssertions( SectionNode 
const& sectionNode ) {
 
 9640        for (
auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) {
 
 9641            if (assertionOrBenchmark.isAssertion()) {
 
 9642                writeAssertion(assertionOrBenchmark.asAssertion());
 
 9647    void JunitReporter::writeAssertion( AssertionStats 
const& stats ) {
 
 9648        AssertionResult 
const& 
result = stats.assertionResult;
 
 9650             result.getResultType() == ResultWas::ExplicitSkip ) {
 
 9651            std::string elementName;
 
 9652            switch( 
result.getResultType() ) {
 
 9653                case ResultWas::ThrewException:
 
 9654                case ResultWas::FatalErrorCondition:
 
 9655                    elementName = 
"error";
 
 9657                case ResultWas::ExplicitFailure:
 
 9658                case ResultWas::ExpressionFailed:
 
 9659                case ResultWas::DidntThrowException:
 
 9660                    elementName = 
"failure";
 
 9662                case ResultWas::ExplicitSkip:
 
 9663                    elementName = 
"skipped";
 
 9666                case ResultWas::Info:
 
 9667                case ResultWas::Warning:
 
 9669                case ResultWas::Unknown:
 
 9670                case ResultWas::FailureBit:
 
 9671                case ResultWas::Exception:
 
 9672                    elementName = 
"internalError";
 
 9676            XmlWriter::ScopedElement e = xml.scopedElement( elementName );
 
 9678            xml.writeAttribute( 
"message"_sr, 
result.getExpression() );
 
 9679            xml.writeAttribute( 
"type"_sr, 
result.getTestMacroName() );
 
 9681            ReusableStringStream rss;
 
 9682            if ( 
result.getResultType() == ResultWas::ExplicitSkip ) {
 
 9685                rss << 
"FAILED" << 
":\n";
 
 9686                if (
result.hasExpression()) {
 
 9688                    rss << 
result.getExpressionInMacro();
 
 9691                if (
result.hasExpandedExpression()) {
 
 9692                    rss << 
"with expansion:\n";
 
 9693                    rss << TextFlow::Column(
result.getExpandedExpression()).indent(2) << 
'\n';
 
 9697            if( 
result.hasMessage() )
 
 9698                rss << 
result.getMessage() << 
'\n';
 
 9699            for( 
auto const& 
msg : stats.infoMessages )
 
 9703            rss << 
"at " << 
result.getSourceInfo();
 
 9704            xml.writeText( rss.str(), XmlFormatting::Newline );
 
 9716    void MultiReporter::updatePreferences(IEventListener 
const& reporterish) {
 
 9717        m_preferences.shouldRedirectStdOut |=
 
 9718            reporterish.getPreferences().shouldRedirectStdOut;
 
 9719        m_preferences.shouldReportAllAssertions |=
 
 9720            reporterish.getPreferences().shouldReportAllAssertions;
 
 9723    void MultiReporter::addListener( IEventListenerPtr&& listener ) {
 
 9724        updatePreferences(*listener);
 
 9725        m_reporterLikes.insert(m_reporterLikes.begin() + m_insertedListeners, CATCH_MOVE(listener) );
 
 9726        ++m_insertedListeners;
 
 9729    void MultiReporter::addReporter( IEventListenerPtr&& reporter ) {
 
 9730        updatePreferences(*reporter);
 
 9737        m_haveNoncapturingReporters |= !reporter->getPreferences().shouldRedirectStdOut;
 
 9741        m_reporterLikes.push_back( CATCH_MOVE( reporter ) );
 
 9744    void MultiReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
 
 9745        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9746            reporterish->noMatchingTestCases( unmatchedSpec );
 
 9750    void MultiReporter::fatalErrorEncountered( StringRef error ) {
 
 9751        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9752            reporterish->fatalErrorEncountered( error );
 
 9756    void MultiReporter::reportInvalidTestSpec( StringRef arg ) {
 
 9757        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9758            reporterish->reportInvalidTestSpec( arg );
 
 9762    void MultiReporter::benchmarkPreparing( StringRef 
name ) {
 
 9763        for (
auto& reporterish : m_reporterLikes) {
 
 9764            reporterish->benchmarkPreparing(
name);
 
 9767    void MultiReporter::benchmarkStarting( BenchmarkInfo 
const& benchmarkInfo ) {
 
 9768        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9769            reporterish->benchmarkStarting( benchmarkInfo );
 
 9772    void MultiReporter::benchmarkEnded( BenchmarkStats<> 
const& benchmarkStats ) {
 
 9773        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9774            reporterish->benchmarkEnded( benchmarkStats );
 
 9778    void MultiReporter::benchmarkFailed( StringRef error ) {
 
 9779        for (
auto& reporterish : m_reporterLikes) {
 
 9780            reporterish->benchmarkFailed(error);
 
 9784    void MultiReporter::testRunStarting( TestRunInfo 
const& testRunInfo ) {
 
 9785        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9786            reporterish->testRunStarting( testRunInfo );
 
 9790    void MultiReporter::testCaseStarting( TestCaseInfo 
const& testInfo ) {
 
 9791        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9792            reporterish->testCaseStarting( testInfo );
 
 9797    MultiReporter::testCasePartialStarting( TestCaseInfo 
const& testInfo,
 
 9798                                                uint64_t partNumber ) {
 
 9799        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9800            reporterish->testCasePartialStarting( testInfo, partNumber );
 
 9804    void MultiReporter::sectionStarting( SectionInfo 
const& sectionInfo ) {
 
 9805        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9806            reporterish->sectionStarting( sectionInfo );
 
 9810    void MultiReporter::assertionStarting( AssertionInfo 
const& assertionInfo ) {
 
 9811        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9812            reporterish->assertionStarting( assertionInfo );
 
 9816    void MultiReporter::assertionEnded( AssertionStats 
const& assertionStats ) {
 
 9817        const bool reportByDefault =
 
 9818            assertionStats.assertionResult.getResultType() != ResultWas::Ok ||
 
 9819            m_config->includeSuccessfulResults();
 
 9821        for ( 
auto & reporterish : m_reporterLikes ) {
 
 9822            if ( reportByDefault ||
 
 9823                 reporterish->getPreferences().shouldReportAllAssertions ) {
 
 9824                    reporterish->assertionEnded( assertionStats );
 
 9829    void MultiReporter::sectionEnded( SectionStats 
const& sectionStats ) {
 
 9830        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9831            reporterish->sectionEnded( sectionStats );
 
 9835    void MultiReporter::testCasePartialEnded( TestCaseStats 
const& testStats,
 
 9836                                                  uint64_t partNumber ) {
 
 9837        if ( m_preferences.shouldRedirectStdOut &&
 
 9838             m_haveNoncapturingReporters ) {
 
 9839            if ( !testStats.stdOut.empty() ) {
 
 9842            if ( !testStats.stdErr.empty() ) {
 
 9847        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9848            reporterish->testCasePartialEnded( testStats, partNumber );
 
 9852    void MultiReporter::testCaseEnded( TestCaseStats 
const& testCaseStats ) {
 
 9853        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9854            reporterish->testCaseEnded( testCaseStats );
 
 9858    void MultiReporter::testRunEnded( TestRunStats 
const& testRunStats ) {
 
 9859        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9860            reporterish->testRunEnded( testRunStats );
 
 9865    void MultiReporter::skipTest( TestCaseInfo 
const& testInfo ) {
 
 9866        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9867            reporterish->skipTest( testInfo );
 
 9871    void MultiReporter::listReporters(std::vector<ReporterDescription> 
const& descriptions) {
 
 9872        for (
auto& reporterish : m_reporterLikes) {
 
 9873            reporterish->listReporters(descriptions);
 
 9877    void MultiReporter::listListeners(
 
 9878        std::vector<ListenerDescription> 
const& descriptions ) {
 
 9879        for ( 
auto& reporterish : m_reporterLikes ) {
 
 9880            reporterish->listListeners( descriptions );
 
 9884    void MultiReporter::listTests(std::vector<TestCaseHandle> 
const& tests) {
 
 9885        for (
auto& reporterish : m_reporterLikes) {
 
 9886            reporterish->listTests(tests);
 
 9890    void MultiReporter::listTags(std::vector<TagInfo> 
const& tags) {
 
 9891        for (
auto& reporterish : m_reporterLikes) {
 
 9892            reporterish->listTags(tags);
 
 9905        void registerReporterImpl( std::string 
const& 
name,
 
 9906                                   IReporterFactoryPtr reporterPtr ) {
 
 9909                    name, CATCH_MOVE( reporterPtr ) );
 
 9918        void registerListenerImpl( Detail::unique_ptr<EventListenerFactory> listenerFactory ) {
 
 9934        std::string createMetadataString(IConfig 
const& config) {
 
 9935            ReusableStringStream sstr;
 
 9936            if ( config.testSpec().hasFilters() ) {
 
 9938                         << config.testSpec()
 
 9941            sstr << 
"rng-seed=" << config.rngSeed();
 
 9946    void SonarQubeReporter::testRunStarting(TestRunInfo 
const& testRunInfo) {
 
 9947        CumulativeReporterBase::testRunStarting(testRunInfo);
 
 9949        xml.writeComment( createMetadataString( *m_config ) );
 
 9950        xml.startElement(
"testExecutions");
 
 9951        xml.writeAttribute(
"version"_sr, 
'1');
 
 9954    void SonarQubeReporter::writeRun( TestRunNode 
const& runNode ) {
 
 9955        std::map<StringRef, std::vector<TestCaseNode const*>> testsPerFile;
 
 9957        for ( 
auto const& child : runNode.children ) {
 
 9958            testsPerFile[child->value.testInfo->lineInfo.file].push_back(
 
 9962        for ( 
auto const& kv : testsPerFile ) {
 
 9963            writeTestFile( kv.first, kv.second );
 
 9967    void SonarQubeReporter::writeTestFile(StringRef 
filename, std::vector<TestCaseNode const*> 
const& testCaseNodes) {
 
 9968        XmlWriter::ScopedElement e = xml.scopedElement(
"file");
 
 9969        xml.writeAttribute(
"path"_sr, 
filename);
 
 9971        for (
auto const& child : testCaseNodes)
 
 9972            writeTestCase(*child);
 
 9975    void SonarQubeReporter::writeTestCase(TestCaseNode 
const& testCaseNode) {
 
 9978        assert(testCaseNode.children.size() == 1);
 
 9979        SectionNode 
const& rootSection = *testCaseNode.children.front();
 
 9980        writeSection(
"", rootSection, testCaseNode.value.testInfo->okToFail());
 
 9983    void SonarQubeReporter::writeSection(std::string 
const& rootName, SectionNode 
const& sectionNode, 
bool okToFail) {
 
 9984        std::string 
name = 
trim(sectionNode.stats.sectionInfo.name);
 
 9985        if (!rootName.empty())
 
 9988        if ( sectionNode.hasAnyAssertions()
 
 9989            || !sectionNode.stdOut.empty()
 
 9990            ||  !sectionNode.stdErr.empty() ) {
 
 9991            XmlWriter::ScopedElement e = xml.scopedElement(
"testCase");
 
 9992            xml.writeAttribute(
"name"_sr, 
name);
 
 9993            xml.writeAttribute(
"duration"_sr, 
static_cast<long>(sectionNode.stats.durationInSeconds * 1000));
 
 9995            writeAssertions(sectionNode, okToFail);
 
 9998        for (
auto const& childNode : sectionNode.childSections)
 
 9999            writeSection(
name, *childNode, okToFail);
 
10002    void SonarQubeReporter::writeAssertions(SectionNode 
const& sectionNode, 
bool okToFail) {
 
10003        for (
auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) {
 
10004            if (assertionOrBenchmark.isAssertion()) {
 
10005                writeAssertion(assertionOrBenchmark.asAssertion(), okToFail);
 
10010    void SonarQubeReporter::writeAssertion(AssertionStats 
const& stats, 
bool okToFail) {
 
10011        AssertionResult 
const& 
result = stats.assertionResult;
 
10013             result.getResultType() == ResultWas::ExplicitSkip ) {
 
10014            std::string elementName;
 
10016                elementName = 
"skipped";
 
10018                switch (
result.getResultType()) {
 
10019                case ResultWas::ThrewException:
 
10020                case ResultWas::FatalErrorCondition:
 
10021                    elementName = 
"error";
 
10023                case ResultWas::ExplicitFailure:
 
10024                case ResultWas::ExpressionFailed:
 
10025                case ResultWas::DidntThrowException:
 
10026                    elementName = 
"failure";
 
10028                case ResultWas::ExplicitSkip:
 
10029                    elementName = 
"skipped";
 
10032                case ResultWas::Info:
 
10033                case ResultWas::Warning:
 
10034                case ResultWas::Ok:
 
10035                case ResultWas::Unknown:
 
10036                case ResultWas::FailureBit:
 
10037                case ResultWas::Exception:
 
10038                    elementName = 
"internalError";
 
10043            XmlWriter::ScopedElement e = xml.scopedElement(elementName);
 
10045            ReusableStringStream messageRss;
 
10046            messageRss << 
result.getTestMacroName() << 
'(' << 
result.getExpression() << 
')';
 
10047            xml.writeAttribute(
"message"_sr, messageRss.str());
 
10049            ReusableStringStream textRss;
 
10050            if ( 
result.getResultType() == ResultWas::ExplicitSkip ) {
 
10051                textRss << 
"SKIPPED\n";
 
10053                textRss << 
"FAILED:\n";
 
10054                if (
result.hasExpression()) {
 
10055                    textRss << 
'\t' << 
result.getExpressionInMacro() << 
'\n';
 
10057                if (
result.hasExpandedExpression()) {
 
10058                    textRss << 
"with expansion:\n\t" << 
result.getExpandedExpression() << 
'\n';
 
10062            if (
result.hasMessage())
 
10063                textRss << 
result.getMessage() << 
'\n';
 
10065            for (
auto const& 
msg : stats.infoMessages)
 
10069            textRss << 
"at " << 
result.getSourceInfo();
 
10070            xml.writeText(textRss.str(), XmlFormatting::Newline);
 
10080    StreamingReporterBase::~StreamingReporterBase() = 
default;
 
10083    StreamingReporterBase::testRunStarting( TestRunInfo 
const& _testRunInfo ) {
 
10084        currentTestRunInfo = _testRunInfo;
 
10087    void StreamingReporterBase::testRunEnded( TestRunStats 
const& ) {
 
10088        currentTestCaseInfo = 
nullptr;
 
10095#include <algorithm> 
10103        static constexpr StringRef tapFailedString = 
"not ok"_sr;
 
10104        static constexpr StringRef tapPassedString = 
"ok"_sr;
 
10105        static constexpr Colour::Code tapDimColour = Colour::FileName;
 
10107        class TapAssertionPrinter {
 
10109            TapAssertionPrinter& operator= (TapAssertionPrinter 
const&) = 
delete;
 
10110            TapAssertionPrinter(TapAssertionPrinter 
const&) = 
delete;
 
10111            TapAssertionPrinter(std::ostream& _stream, AssertionStats 
const& _stats, std::size_t _counter, ColourImpl* colour_)
 
10113                , 
result(_stats.assertionResult)
 
10114                , messages(_stats.infoMessages)
 
10115                , itMessage(_stats.infoMessages.
begin())
 
10116                , printInfoMessages(true)
 
10118                , colourImpl( colour_ ) {}
 
10121                itMessage = messages.begin();
 
10123                switch (
result.getResultType()) {
 
10124                case ResultWas::Ok:
 
10125                    printResultType(tapPassedString);
 
10126                    printOriginalExpression();
 
10127                    printReconstructedExpression();
 
10128                    if (!
result.hasExpression())
 
10129                        printRemainingMessages(Colour::None);
 
10131                        printRemainingMessages();
 
10133                case ResultWas::ExpressionFailed:
 
10135                        printResultType(tapPassedString);
 
10137                        printResultType(tapFailedString);
 
10139                    printOriginalExpression();
 
10140                    printReconstructedExpression();
 
10142                        printIssue(
" # TODO");
 
10144                    printRemainingMessages();
 
10146                case ResultWas::ThrewException:
 
10147                    printResultType(tapFailedString);
 
10148                    printIssue(
"unexpected exception with message:"_sr);
 
10150                    printExpressionWas();
 
10151                    printRemainingMessages();
 
10153                case ResultWas::FatalErrorCondition:
 
10154                    printResultType(tapFailedString);
 
10155                    printIssue(
"fatal error condition with message:"_sr);
 
10157                    printExpressionWas();
 
10158                    printRemainingMessages();
 
10160                case ResultWas::DidntThrowException:
 
10161                    printResultType(tapFailedString);
 
10162                    printIssue(
"expected exception, got none"_sr);
 
10163                    printExpressionWas();
 
10164                    printRemainingMessages();
 
10166                case ResultWas::Info:
 
10167                    printResultType(
"info"_sr);
 
10169                    printRemainingMessages();
 
10171                case ResultWas::Warning:
 
10172                    printResultType(
"warning"_sr);
 
10174                    printRemainingMessages();
 
10176                case ResultWas::ExplicitFailure:
 
10177                    printResultType(tapFailedString);
 
10178                    printIssue(
"explicitly"_sr);
 
10179                    printRemainingMessages(Colour::None);
 
10181                case ResultWas::ExplicitSkip:
 
10182                    printResultType(tapPassedString);
 
10183                    printIssue(
" # SKIP"_sr);
 
10185                    printRemainingMessages();
 
10188                case ResultWas::Unknown:
 
10189                case ResultWas::FailureBit:
 
10190                case ResultWas::Exception:
 
10191                    printResultType(
"** internal error **"_sr);
 
10197            void printResultType(StringRef passOrFail)
 const {
 
10198                if (!passOrFail.empty()) {
 
10203            void printIssue(StringRef issue)
 const {
 
10207            void printExpressionWas() {
 
10208                if (
result.hasExpression()) {
 
10210                    stream << colourImpl->guardColour( tapDimColour )
 
10211                           << 
" expression was:";
 
10212                    printOriginalExpression();
 
10216            void printOriginalExpression()
 const {
 
10217                if (
result.hasExpression()) {
 
10222            void printReconstructedExpression()
 const {
 
10223                if (
result.hasExpandedExpression()) {
 
10224                    stream << colourImpl->guardColour( tapDimColour ) << 
" for: ";
 
10226                    std::string expr = 
result.getExpandedExpression();
 
10227                    std::replace(expr.begin(), expr.end(), 
'\n', 
' ');
 
10232            void printMessage() {
 
10233                if (itMessage != messages.end()) {
 
10234                    stream << 
" '" << itMessage->message << 
'\'';
 
10239            void printRemainingMessages(Colour::Code colour = tapDimColour) {
 
10240                if (itMessage == messages.end()) {
 
10245                std::vector<MessageInfo>::const_iterator itEnd = messages.end();
 
10246                const std::size_t N = 
static_cast<std::size_t
>(itEnd - itMessage);
 
10248                stream << colourImpl->guardColour( colour ) << 
" with " 
10249                       << pluralise( N, 
"message"_sr ) << 
':';
 
10251                for (; itMessage != itEnd; ) {
 
10253                    if (printInfoMessages || itMessage->type != ResultWas::Info) {
 
10254                        stream << 
" '" << itMessage->message << 
'\'';
 
10255                        if (++itMessage != itEnd) {
 
10256                            stream << colourImpl->guardColour(tapDimColour) << 
" and";
 
10264            AssertionResult 
const& 
result;
 
10265            std::vector<MessageInfo> 
const& messages;
 
10266            std::vector<MessageInfo>::const_iterator itMessage;
 
10267            bool printInfoMessages;
 
10269            ColourImpl* colourImpl;
 
10274    void TAPReporter::testRunStarting( TestRunInfo 
const& ) {
 
10275        if ( m_config->testSpec().hasFilters() ) {
 
10276            m_stream << 
"# filters: " << m_config->testSpec() << 
'\n';
 
10278        m_stream << 
"# rng-seed: " << m_config->rngSeed() << 
'\n';
 
10281    void TAPReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
 
10282        m_stream << 
"# No test cases matched '" << unmatchedSpec << 
"'\n";
 
10285    void TAPReporter::assertionEnded(AssertionStats 
const& _assertionStats) {
 
10288        m_stream << 
"# " << currentTestCaseInfo->name << 
'\n';
 
10289        TapAssertionPrinter printer(m_stream, _assertionStats, 
counter, m_colour.get());
 
10292        m_stream << 
'\n' << std::flush;
 
10295    void TAPReporter::testRunEnded(TestRunStats 
const& _testRunStats) {
 
10296        m_stream << 
"1.." << _testRunStats.totals.assertions.total();
 
10297        if (_testRunStats.totals.testCases.total() == 0) {
 
10298            m_stream << 
" # Skipped: No tests ran.";
 
10300        m_stream << 
"\n\n" << std::flush;
 
10301        StreamingReporterBase::testRunEnded(_testRunStats);
 
10320        void printHeaderString(std::ostream& os, std::string 
const& _string, std::size_t indent = 0) {
 
10321            std::size_t 
i = _string.find(
": ");
 
10322            if (
i != std::string::npos)
 
10326            os << TextFlow::Column(_string)
 
10327                  .indent(indent + 
i)
 
10328                  .initialIndent(indent) << 
'\n';
 
10331        std::string escape(StringRef 
str) {
 
10332            std::string escaped = 
static_cast<std::string
>(
str);
 
10344    TeamCityReporter::~TeamCityReporter() {}
 
10346    void TeamCityReporter::testRunStarting( TestRunInfo 
const& runInfo ) {
 
10347        m_stream << 
"##teamcity[testSuiteStarted name='" << escape( runInfo.name )
 
10351    void TeamCityReporter::testRunEnded( TestRunStats 
const& runStats ) {
 
10352        m_stream << 
"##teamcity[testSuiteFinished name='" 
10353               << escape( runStats.runInfo.name ) << 
"']\n";
 
10356    void TeamCityReporter::assertionEnded(AssertionStats 
const& assertionStats) {
 
10357        AssertionResult 
const& 
result = assertionStats.assertionResult;
 
10359             result.getResultType() == ResultWas::ExplicitSkip ) {
 
10361            ReusableStringStream 
msg;
 
10362            if (!m_headerPrintedForThisSection)
 
10363                printSectionHeader(
msg.get());
 
10364            m_headerPrintedForThisSection = 
true;
 
10368            switch (
result.getResultType()) {
 
10369            case ResultWas::ExpressionFailed:
 
10370                msg << 
"expression failed";
 
10372            case ResultWas::ThrewException:
 
10373                msg << 
"unexpected exception";
 
10375            case ResultWas::FatalErrorCondition:
 
10376                msg << 
"fatal error condition";
 
10378            case ResultWas::DidntThrowException:
 
10379                msg << 
"no exception was thrown where one was expected";
 
10381            case ResultWas::ExplicitFailure:
 
10382                msg << 
"explicit failure";
 
10384            case ResultWas::ExplicitSkip:
 
10385                msg << 
"explicit skip";
 
10389            case ResultWas::Ok:
 
10390            case ResultWas::Info:
 
10391            case ResultWas::Warning:
 
10392                CATCH_ERROR(
"Internal error in TeamCity reporter");
 
10394            case ResultWas::Unknown:
 
10395            case ResultWas::FailureBit:
 
10396            case ResultWas::Exception:
 
10397                CATCH_ERROR(
"Not implemented");
 
10399            if (assertionStats.infoMessages.size() == 1)
 
10400                msg << 
" with message:";
 
10401            if (assertionStats.infoMessages.size() > 1)
 
10402                msg << 
" with messages:";
 
10403            for (
auto const& messageInfo : assertionStats.infoMessages)
 
10404                msg << 
"\n  \"" << messageInfo.
message << 
'"';
 
10407            if (
result.hasExpression()) {
 
10409                    "\n  " << 
result.getExpressionInMacro() << 
"\n" 
10410                    "with expansion:\n" 
10411                    "  " << 
result.getExpandedExpression() << 
'\n';
 
10414            if ( 
result.getResultType() == ResultWas::ExplicitSkip ) {
 
10415                m_stream << 
"##teamcity[testIgnored";
 
10416            } 
else if ( currentTestCaseInfo->okToFail() ) {
 
10417                msg << 
"- failure ignore as test marked as 'ok to fail'\n";
 
10418                m_stream << 
"##teamcity[testIgnored";
 
10420                m_stream << 
"##teamcity[testFailed";
 
10422            m_stream << 
" name='" << escape( currentTestCaseInfo->name ) << 
'\'' 
10423                     << 
" message='" << escape( 
msg.str() ) << 
'\'' << 
"]\n";
 
10428    void TeamCityReporter::testCaseStarting(TestCaseInfo 
const& testInfo) {
 
10429        m_testTimer.start();
 
10430        StreamingReporterBase::testCaseStarting(testInfo);
 
10431        m_stream << 
"##teamcity[testStarted name='" 
10432            << escape(testInfo.name) << 
"']\n";
 
10436    void TeamCityReporter::testCaseEnded(TestCaseStats 
const& testCaseStats) {
 
10437        StreamingReporterBase::testCaseEnded(testCaseStats);
 
10438        auto const& testCaseInfo = *testCaseStats.testInfo;
 
10439        if (!testCaseStats.stdOut.empty())
 
10440            m_stream << 
"##teamcity[testStdOut name='" 
10441            << escape(testCaseInfo.name)
 
10442            << 
"' out='" << escape(testCaseStats.stdOut) << 
"']\n";
 
10443        if (!testCaseStats.stdErr.empty())
 
10444            m_stream << 
"##teamcity[testStdErr name='" 
10445            << escape(testCaseInfo.name)
 
10446            << 
"' out='" << escape(testCaseStats.stdErr) << 
"']\n";
 
10447        m_stream << 
"##teamcity[testFinished name='" 
10448            << escape(testCaseInfo.name) << 
"' duration='" 
10449            << m_testTimer.getElapsedMilliseconds() << 
"']\n";
 
10453    void TeamCityReporter::printSectionHeader(std::ostream& os) {
 
10454        assert(!m_sectionStack.empty());
 
10456        if (m_sectionStack.size() > 1) {
 
10457            os << lineOfChars(
'-') << 
'\n';
 
10459            std::vector<SectionInfo>::const_iterator
 
10460                it = m_sectionStack.begin() + 1, 
 
10461                itEnd = m_sectionStack.end();
 
10462            for (; it != itEnd; ++it)
 
10463                printHeaderString(os, it->name);
 
10464            os << lineOfChars(
'-') << 
'\n';
 
10467        SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
 
10469        os << lineInfo << 
'\n';
 
10470        os << lineOfChars(
'.') << 
"\n\n";
 
10478#if defined(_MSC_VER) 
10479#pragma warning(push) 
10480#pragma warning(disable:4061)  
10486    XmlReporter::XmlReporter( ReporterConfig&& _config )
 
10487    :   StreamingReporterBase( CATCH_MOVE(_config) ),
 
10490        m_preferences.shouldRedirectStdOut = 
true;
 
10491        m_preferences.shouldReportAllAssertions = 
true;
 
10494    XmlReporter::~XmlReporter() = 
default;
 
10496    std::string XmlReporter::getDescription() {
 
10497        return "Reports test results as an XML document";
 
10500    std::string XmlReporter::getStylesheetRef()
 const {
 
10501        return std::string();
 
10504    void XmlReporter::writeSourceInfo( SourceLineInfo 
const& sourceInfo ) {
 
10506            .writeAttribute( 
"filename"_sr, sourceInfo.file )
 
10507            .writeAttribute( 
"line"_sr, sourceInfo.line );
 
10510    void XmlReporter::testRunStarting( TestRunInfo 
const& testInfo ) {
 
10511        StreamingReporterBase::testRunStarting( testInfo );
 
10512        std::string stylesheetRef = getStylesheetRef();
 
10513        if( !stylesheetRef.empty() )
 
10514            m_xml.writeStylesheetRef( stylesheetRef );
 
10515        m_xml.startElement(
"Catch2TestRun")
 
10516             .writeAttribute(
"name"_sr, m_config->name())
 
10517             .writeAttribute(
"rng-seed"_sr, m_config->rngSeed())
 
10518             .writeAttribute(
"xml-format-version"_sr, 3)
 
10520        if ( m_config->testSpec().hasFilters() ) {
 
10521            m_xml.writeAttribute( 
"filters"_sr, m_config->testSpec() );
 
10525    void XmlReporter::testCaseStarting( TestCaseInfo 
const& testInfo ) {
 
10526        StreamingReporterBase::testCaseStarting(testInfo);
 
10527        m_xml.startElement( 
"TestCase" )
 
10528            .writeAttribute( 
"name"_sr, 
trim( StringRef(testInfo.name) ) )
 
10529            .writeAttribute( 
"tags"_sr, testInfo.tagsAsString() );
 
10531        writeSourceInfo( testInfo.lineInfo );
 
10533        if ( m_config->showDurations() == ShowDurations::Always )
 
10534            m_testCaseTimer.start();
 
10535        m_xml.ensureTagClosed();
 
10538    void XmlReporter::sectionStarting( SectionInfo 
const& sectionInfo ) {
 
10539        StreamingReporterBase::sectionStarting( sectionInfo );
 
10540        if( m_sectionDepth++ > 0 ) {
 
10541            m_xml.startElement( 
"Section" )
 
10542                .writeAttribute( 
"name"_sr, 
trim( StringRef(sectionInfo.name) ) );
 
10543            writeSourceInfo( sectionInfo.lineInfo );
 
10544            m_xml.ensureTagClosed();
 
10548    void XmlReporter::assertionStarting( AssertionInfo 
const& ) { }
 
10550    void XmlReporter::assertionEnded( AssertionStats 
const& assertionStats ) {
 
10552        AssertionResult 
const& 
result = assertionStats.assertionResult;
 
10554        bool includeResults = m_config->includeSuccessfulResults() || !
result.isOk();
 
10556        if( includeResults || 
result.getResultType() == ResultWas::Warning ) {
 
10558            for( 
auto const& 
msg : assertionStats.infoMessages ) {
 
10559                if( 
msg.type == ResultWas::Info && includeResults ) {
 
10560                    auto t = m_xml.scopedElement( 
"Info" );
 
10561                    writeSourceInfo( 
msg.lineInfo );
 
10562                    t.writeText( 
msg.message );
 
10563                } 
else if ( 
msg.type == ResultWas::Warning ) {
 
10564                    auto t = m_xml.scopedElement( 
"Warning" );
 
10565                    writeSourceInfo( 
msg.lineInfo );
 
10566                    t.writeText( 
msg.message );
 
10572        if ( !includeResults && 
result.getResultType() != ResultWas::Warning &&
 
10573             result.getResultType() != ResultWas::ExplicitSkip ) {
 
10578        if( 
result.hasExpression() ) {
 
10579            m_xml.startElement( 
"Expression" )
 
10580                .writeAttribute( 
"success"_sr, 
result.succeeded() )
 
10581                .writeAttribute( 
"type"_sr, 
result.getTestMacroName() );
 
10583            writeSourceInfo( 
result.getSourceInfo() );
 
10585            m_xml.scopedElement( 
"Original" )
 
10586                .writeText( 
result.getExpression() );
 
10587            m_xml.scopedElement( 
"Expanded" )
 
10588                .writeText( 
result.getExpandedExpression() );
 
10592        switch( 
result.getResultType() ) {
 
10593            case ResultWas::ThrewException:
 
10594                m_xml.startElement( 
"Exception" );
 
10595                writeSourceInfo( 
result.getSourceInfo() );
 
10596                m_xml.writeText( 
result.getMessage() );
 
10597                m_xml.endElement();
 
10599            case ResultWas::FatalErrorCondition:
 
10600                m_xml.startElement( 
"FatalErrorCondition" );
 
10601                writeSourceInfo( 
result.getSourceInfo() );
 
10602                m_xml.writeText( 
result.getMessage() );
 
10603                m_xml.endElement();
 
10605            case ResultWas::Info:
 
10606                m_xml.scopedElement( 
"Info" )
 
10607                     .writeText( 
result.getMessage() );
 
10609            case ResultWas::Warning:
 
10612            case ResultWas::ExplicitFailure:
 
10613                m_xml.startElement( 
"Failure" );
 
10614                writeSourceInfo( 
result.getSourceInfo() );
 
10615                m_xml.writeText( 
result.getMessage() );
 
10616                m_xml.endElement();
 
10618            case ResultWas::ExplicitSkip:
 
10619                m_xml.startElement( 
"Skip" );
 
10620                writeSourceInfo( 
result.getSourceInfo() );
 
10621                m_xml.writeText( 
result.getMessage() );
 
10622                m_xml.endElement();
 
10628        if( 
result.hasExpression() )
 
10629            m_xml.endElement();
 
10632    void XmlReporter::sectionEnded( SectionStats 
const& sectionStats ) {
 
10633        StreamingReporterBase::sectionEnded( sectionStats );
 
10634        if ( --m_sectionDepth > 0 ) {
 
10636                XmlWriter::ScopedElement e = m_xml.scopedElement( 
"OverallResults" );
 
10637                e.writeAttribute( 
"successes"_sr, sectionStats.assertions.passed );
 
10638                e.writeAttribute( 
"failures"_sr, sectionStats.assertions.failed );
 
10639                e.writeAttribute( 
"expectedFailures"_sr, sectionStats.assertions.failedButOk );
 
10640                e.writeAttribute( 
"skipped"_sr, sectionStats.assertions.skipped > 0 );
 
10642                if ( m_config->showDurations() == ShowDurations::Always )
 
10643                    e.writeAttribute( 
"durationInSeconds"_sr, sectionStats.durationInSeconds );
 
10646            m_xml.endElement();
 
10650    void XmlReporter::testCaseEnded( TestCaseStats 
const& testCaseStats ) {
 
10651        StreamingReporterBase::testCaseEnded( testCaseStats );
 
10652        XmlWriter::ScopedElement e = m_xml.scopedElement( 
"OverallResult" );
 
10653        e.writeAttribute( 
"success"_sr, testCaseStats.totals.assertions.allOk() );
 
10654        e.writeAttribute( 
"skips"_sr, testCaseStats.totals.assertions.skipped );
 
10656        if ( m_config->showDurations() == ShowDurations::Always )
 
10657            e.writeAttribute( 
"durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() );
 
10658        if( !testCaseStats.stdOut.empty() )
 
10659            m_xml.scopedElement( 
"StdOut" ).writeText( 
trim( StringRef(testCaseStats.stdOut) ), XmlFormatting::Newline );
 
10660        if( !testCaseStats.stdErr.empty() )
 
10661            m_xml.scopedElement( 
"StdErr" ).writeText( 
trim( StringRef(testCaseStats.stdErr) ), XmlFormatting::Newline );
 
10663        m_xml.endElement();
 
10666    void XmlReporter::testRunEnded( TestRunStats 
const& testRunStats ) {
 
10667        StreamingReporterBase::testRunEnded( testRunStats );
 
10668        m_xml.scopedElement( 
"OverallResults" )
 
10669            .writeAttribute( 
"successes"_sr, testRunStats.totals.assertions.passed )
 
10670            .writeAttribute( 
"failures"_sr, testRunStats.totals.assertions.failed )
 
10671            .writeAttribute( 
"expectedFailures"_sr, testRunStats.totals.assertions.failedButOk )
 
10672            .writeAttribute( 
"skips"_sr, testRunStats.totals.assertions.skipped );
 
10673        m_xml.scopedElement( 
"OverallResultsCases")
 
10674            .writeAttribute( 
"successes"_sr, testRunStats.totals.testCases.passed )
 
10675            .writeAttribute( 
"failures"_sr, testRunStats.totals.testCases.failed )
 
10676            .writeAttribute( 
"expectedFailures"_sr, testRunStats.totals.testCases.failedButOk )
 
10677            .writeAttribute( 
"skips"_sr, testRunStats.totals.testCases.skipped );
 
10678        m_xml.endElement();
 
10681    void XmlReporter::benchmarkPreparing( StringRef 
name ) {
 
10682        m_xml.startElement(
"BenchmarkResults")
 
10683             .writeAttribute(
"name"_sr, 
name);
 
10686    void XmlReporter::benchmarkStarting(BenchmarkInfo 
const &info) {
 
10687        m_xml.writeAttribute(
"samples"_sr, info.samples)
 
10688            .writeAttribute(
"resamples"_sr, info.resamples)
 
10689            .writeAttribute(
"iterations"_sr, info.iterations)
 
10690            .writeAttribute(
"clockResolution"_sr, info.clockResolution)
 
10691            .writeAttribute(
"estimatedDuration"_sr, info.estimatedDuration)
 
10692            .writeComment(
"All values in nano seconds"_sr);
 
10695    void XmlReporter::benchmarkEnded(BenchmarkStats<> 
const& benchmarkStats) {
 
10696        m_xml.startElement(
"mean")
 
10697            .writeAttribute(
"value"_sr, benchmarkStats.mean.point.count())
 
10698            .writeAttribute(
"lowerBound"_sr, benchmarkStats.mean.lower_bound.count())
 
10699            .writeAttribute(
"upperBound"_sr, benchmarkStats.mean.upper_bound.count())
 
10700            .writeAttribute(
"ci"_sr, benchmarkStats.mean.confidence_interval);
 
10701        m_xml.endElement();
 
10702        m_xml.startElement(
"standardDeviation")
 
10703            .writeAttribute(
"value"_sr, benchmarkStats.standardDeviation.point.count())
 
10704            .writeAttribute(
"lowerBound"_sr, benchmarkStats.standardDeviation.lower_bound.count())
 
10705            .writeAttribute(
"upperBound"_sr, benchmarkStats.standardDeviation.upper_bound.count())
 
10706            .writeAttribute(
"ci"_sr, benchmarkStats.standardDeviation.confidence_interval);
 
10707        m_xml.endElement();
 
10708        m_xml.startElement(
"outliers")
 
10709            .writeAttribute(
"variance"_sr, benchmarkStats.outlierVariance)
 
10710            .writeAttribute(
"lowMild"_sr, benchmarkStats.outliers.low_mild)
 
10711            .writeAttribute(
"lowSevere"_sr, benchmarkStats.outliers.low_severe)
 
10712            .writeAttribute(
"highMild"_sr, benchmarkStats.outliers.high_mild)
 
10713            .writeAttribute(
"highSevere"_sr, benchmarkStats.outliers.high_severe);
 
10714        m_xml.endElement();
 
10715        m_xml.endElement();
 
10718    void XmlReporter::benchmarkFailed(StringRef error) {
 
10719        m_xml.scopedElement(
"failed").
 
10720            writeAttribute(
"message"_sr, error);
 
10721        m_xml.endElement();
 
10724    void XmlReporter::listReporters(std::vector<ReporterDescription> 
const& descriptions) {
 
10725        auto outerTag = m_xml.scopedElement(
"AvailableReporters");
 
10726        for (
auto const& reporter : descriptions) {
 
10727            auto inner = m_xml.scopedElement(
"Reporter");
 
10728            m_xml.startElement(
"Name", XmlFormatting::Indent)
 
10729                 .writeText(reporter.name, XmlFormatting::None)
 
10730                 .endElement(XmlFormatting::Newline);
 
10731            m_xml.startElement(
"Description", XmlFormatting::Indent)
 
10732                 .writeText(reporter.description, XmlFormatting::None)
 
10733                 .endElement(XmlFormatting::Newline);
 
10737    void XmlReporter::listListeners(std::vector<ListenerDescription> 
const& descriptions) {
 
10738        auto outerTag = m_xml.scopedElement( 
"RegisteredListeners" );
 
10739        for ( 
auto const& listener : descriptions ) {
 
10740            auto inner = m_xml.scopedElement( 
"Listener" );
 
10741            m_xml.startElement( 
"Name", XmlFormatting::Indent )
 
10742                .writeText( listener.name, XmlFormatting::None )
 
10743                .endElement( XmlFormatting::Newline );
 
10744            m_xml.startElement( 
"Description", XmlFormatting::Indent )
 
10745                .writeText( listener.description, XmlFormatting::None )
 
10746                .endElement( XmlFormatting::Newline );
 
10750    void XmlReporter::listTests(std::vector<TestCaseHandle> 
const& tests) {
 
10751        auto outerTag = m_xml.scopedElement(
"MatchingTests");
 
10752        for (
auto const& 
test : tests) {
 
10753            auto innerTag = m_xml.scopedElement(
"TestCase");
 
10754            auto const& testInfo = 
test.getTestCaseInfo();
 
10755            m_xml.startElement(
"Name", XmlFormatting::Indent)
 
10756                 .writeText(testInfo.name, XmlFormatting::None)
 
10757                 .endElement(XmlFormatting::Newline);
 
10758            m_xml.startElement(
"ClassName", XmlFormatting::Indent)
 
10759                 .writeText(testInfo.className, XmlFormatting::None)
 
10760                 .endElement(XmlFormatting::Newline);
 
10761            m_xml.startElement(
"Tags", XmlFormatting::Indent)
 
10762                 .writeText(testInfo.tagsAsString(), XmlFormatting::None)
 
10763                 .endElement(XmlFormatting::Newline);
 
10765            auto sourceTag = m_xml.scopedElement(
"SourceInfo");
 
10766            m_xml.startElement(
"File", XmlFormatting::Indent)
 
10767                 .writeText(testInfo.lineInfo.file, XmlFormatting::None)
 
10768                 .endElement(XmlFormatting::Newline);
 
10769            m_xml.startElement(
"Line", XmlFormatting::Indent)
 
10770                 .writeText(
std::to_string(testInfo.lineInfo.line), XmlFormatting::None)
 
10771                 .endElement(XmlFormatting::Newline);
 
10775    void XmlReporter::listTags(std::vector<TagInfo> 
const& tags) {
 
10776        auto outerTag = m_xml.scopedElement(
"TagsFromMatchingTests");
 
10777        for (
auto const& tag : tags) {
 
10778            auto innerTag = m_xml.scopedElement(
"Tag");
 
10779            m_xml.startElement(
"Count", XmlFormatting::Indent)
 
10781                 .endElement(XmlFormatting::Newline);
 
10782            auto aliasTag = m_xml.scopedElement(
"Aliases");
 
10783            for (
auto const& alias : tag.spellings) {
 
10784                m_xml.startElement(
"Alias", XmlFormatting::Indent)
 
10785                     .writeText(alias, XmlFormatting::None)
 
10786                     .endElement(XmlFormatting::Newline);
 
10793#if defined(_MSC_VER) 
10794#pragma warning(pop) 
std::ostream & operator<<(std::ostream &os, const o2::math_utils::Rotation2Df_t &t)
o2::monitoring::Verbosity Verbosity
std::chrono::duration< double, std::ratio< 1, 1 > > Duration
GeneratorBasePtr m_generator
Justification justification
std::string shardFilePath
Class for time synchronization of RawReader instances.
float sum(float s, o2::dcs::DataPointValue v)
bool match(const std::vector< std::string > &queries, const char *pattern)
GLsizei const GLchar *const  * string
GLuint const GLchar * name
GLboolean GLboolean GLboolean b
GLsizei GLsizei GLchar * source
GLsizei const GLfloat * value
GLint GLint GLsizei GLint GLenum GLenum type
GLenum GLsizei GLsizei GLint * values
GLuint GLsizei GLsizei * length
GLuint GLsizei const GLchar * label
typedef void(APIENTRYP PFNGLCULLFACEPROC)(GLenum mode)
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLuint GLsizei const GLchar * message
GLboolean GLboolean GLboolean GLboolean a
GLubyte GLubyte GLubyte GLubyte w
GLenum GLint GLint * precision
OutlierClassification classify_outliers(std::vector< double >::const_iterator first, std::vector< double >::const_iterator last)
bootstrap_analysis analyse_samples(double confidence_level, unsigned int n_resamples, std::vector< double >::iterator first, std::vector< double >::iterator last)
double erfc_inv(double x)
bool directCompare(double lhs, double rhs)
void throw_optimized_away_error()
double normal_quantile(double p)
double mean(std::vector< double >::const_iterator first, std::vector< double >::const_iterator last)
double weighted_average_quantile(int k, int q, std::vector< double >::iterator first, std::vector< double >::iterator last)
ParserResult convertInto(std::string const &source, std::string &target)
void registerTranslatorImpl(Detail::unique_ptr< IExceptionTranslator > &&translator)
Optional< ColourMode > stringToColourMode(StringRef colourMode)
std::vector< std::string > splitReporterSpec(StringRef reporterSpec)
char const * getEnv(char const *varName)
uint32_t convertToBits(float f)
void throw_generator_exception(char const *msg)
IGeneratorTracker * createGeneratorTracker(StringRef generatorName, SourceLineInfo lineInfo, GeneratorBasePtr &&generator)
IGeneratorTracker * acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const &lineInfo)
std::string describe_multi_matcher(StringRef combine, std::string const *descriptions_begin, std::string const *descriptions_end)
NoneTrueMatcher NoneTrue()
EndsWithMatcher EndsWith(std::string const &str, CaseSensitive caseSensitivity)
StringContainsMatcher ContainsSubstring(std::string const &str, CaseSensitive caseSensitivity)
ExceptionMessageMatcher Message(std::string const &message)
HasSizeMatcher SizeIs(std::size_t sz)
StringEqualsMatcher Equals(std::string const &str, CaseSensitive caseSensitivity)
StartsWithMatcher StartsWith(std::string const &str, CaseSensitive caseSensitivity)
RegexMatcher Matches(std::string const ®ex, CaseSensitive caseSensitivity)
Column Spacer(size_t spaceWidth)
std::ostream & operator<<(std::ostream &os, Column const &col)
void toLowerInPlace(std::string &s)
std::string trim(std::string const &str)
bool isThrowSafe(TestCaseHandle const &testCase, IConfig const &config)
void seedRng(IConfig const &config)
std::uint32_t generateRandomSeed(GenerateFrom from)
auto operator+=(std::string &lhs, StringRef rhs) -> std::string &
void throw_test_failure_exception()
void handleExceptionMatchExpr(AssertionHandler &handler, std::string const &str)
bool operator==(ProcessedReporterSpec const &lhs, ProcessedReporterSpec const &rhs)
Version const & libraryVersion()
Optional< unsigned int > parseUInt(std::string const &input, int base)
auto makeStream(std::string const &filename) -> Detail::unique_ptr< IStream >
Detail::unique_ptr< ITestInvoker > makeTestInvoker(void(*testAsFunction)())
bool uncaught_exceptions()
bool isOk(ResultWas::OfType resultType)
bool isJustInfo(int flags)
IMutableRegistryHub & getMutableRegistryHub()
IRegistryHub const & getRegistryHub()
XmlFormatting operator&(XmlFormatting lhs, XmlFormatting rhs)
std::vector< StringRef > splitStringRef(StringRef str, char delimiter)
bool startsWith(std::string const &s, std::string const &prefix)
void addSingleton(ISingleton *singleton)
void throw_test_skip_exception()
bool shouldContinueOnFailure(int flags)
Clara::Parser makeCommandLineParser(ConfigData &config)
bool contains(std::string const &s, std::string const &infix)
std::ostream & operator<<(std::ostream &os, Version const &version)
std::vector< TestCaseHandle > const & getAllTestCasesSorted(IConfig const &config)
ResultDisposition::Flags operator|(ResultDisposition::Flags lhs, ResultDisposition::Flags rhs)
bool operator!=(SimplePcg32 const &lhs, SimplePcg32 const &rhs)
bool shouldSuppressFailure(int flags)
std::string translateActiveException()
std::string toLower(std::string const &s)
std::vector< TestCaseHandle > sortTests(IConfig const &config, std::vector< TestCaseHandle > const &unsortedTestCases)
bool endsWith(std::string const &s, std::string const &suffix)
std::string operator+(StringRef lhs, StringRef rhs)
Optional< ReporterSpec > parseReporterSpec(StringRef reporterSpec)
std::vector< TestCaseHandle > filterTests(std::vector< TestCaseHandle > const &testCases, TestSpec const &testSpec, IConfig const &config)
IResultCapture & getResultCapture()
Singleton< RegistryHub, IRegistryHub, IMutableRegistryHub > RegistryHubSingleton
bool replaceInPlace(std::string &str, std::string const &replaceThis, std::string const &withThis)
uint8_t itsSharedClusterMap uint8_t
long getCurrentTimestamp()
returns the timestamp in long corresponding to "now"
bool operator<(EntryPM const &entryPM1, EntryPM const &entryPM2)
Defining PrimaryVertex explicitly as messageable.
@ Timer
A message which is created whenever a Timer expires.
int32_t const char int32_t line
D const SVectorGPU< T, D > & rhs
if(!okForPhiMin(phi0, phi1))
Polygon< T > close(Polygon< T > polygon)
ColumnData & operator|=(ColumnData &col1, const ColumnData &col2)
std::vector< T, fair::mq::pmr::polymorphic_allocator< T > > vector
@ Auto
Automatically decide based on DCS settings in CCDB.
Enum< T >::Iterator begin(Enum< T >)
bool endsWith(const std::string &str, const std::string &suffix)
Defining DataPointCompositeObject explicitly as copiable.
std::string to_string(gsl::span< T, Size > span)
FIXME: do not use data model tables.
const char * what() const noexcept override
std::vector< Detail::unique_ptr< EventListenerFactory > > listeners
std::map< std::string, IReporterFactoryPtr, Detail::CaseInsensitiveLess > factories
std::vector< Detail::unique_ptr< std::ostringstream > > m_streams
auto add() -> std::size_t
std::ostringstream m_referenceStream
std::vector< std::size_t > m_unused
void release(std::size_t index)
VectorOfTObjectPtrs other
std::array< uint16_t, 5 > pattern
std::vector< ReadoutWindowData > rows
char const  *restrict const cmp
uint64_t const void const  *restrict const msg