From 800d08778c4aca1263eac312e6a3cbea4b394adf Mon Sep 17 00:00:00 2001
From: Nana Sakisaka <1901813+saki7@users.noreply.github.com>
Date: Tue, 3 Feb 2026 22:14:23 +0900
Subject: [PATCH 1/5] Organize obsolete assets
---
index.html | 15 ---------------
{workbench => scripts}/unicode/create_tables.cpp | 0
{workbench => scripts}/unicode/download_data.sh | 0
3 files changed, 15 deletions(-)
delete mode 100644 index.html
rename {workbench => scripts}/unicode/create_tables.cpp (100%)
rename {workbench => scripts}/unicode/download_data.sh (100%)
diff --git a/index.html b/index.html
deleted file mode 100644
index 1eb81150a..000000000
--- a/index.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
- Automatic redirection failed, click this
- link
- © Copyright Beman Dawes, 2001
- Distributed under the Boost Software License, Version 1.0. (See
- accompanying file
- LICENSE_1_0.txt or copy at
- www.boost.org/LICENSE_1_0.txt)
-
-
\ No newline at end of file
diff --git a/workbench/unicode/create_tables.cpp b/scripts/unicode/create_tables.cpp
similarity index 100%
rename from workbench/unicode/create_tables.cpp
rename to scripts/unicode/create_tables.cpp
diff --git a/workbench/unicode/download_data.sh b/scripts/unicode/download_data.sh
similarity index 100%
rename from workbench/unicode/download_data.sh
rename to scripts/unicode/download_data.sh
From bf18e4b7a77ab8832b31d50e4af3c1140f1a923a Mon Sep 17 00:00:00 2001
From: Nana Sakisaka <1901813+saki7@users.noreply.github.com>
Date: Tue, 3 Feb 2026 22:22:27 +0900
Subject: [PATCH 2/5] Trigger `push` event only on the `main` branch
This prevents duplicate workflow runs that was triggered when a PR was
created directly from a branch which exists in the remote repository
---
.github/workflows/ci.yml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3e018a6b1..bc051d24c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -8,6 +8,8 @@ name: CI
on:
pull_request:
push:
+ branches:
+ - 'main'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
From df90bb8b8d23158ba7bc3ac22d6320d24ca15a60 Mon Sep 17 00:00:00 2001
From: Nana Sakisaka <1901813+saki7@users.noreply.github.com>
Date: Tue, 3 Feb 2026 22:24:39 +0900
Subject: [PATCH 3/5] Remove `IRIS_CI_IS_B2` and the amalgamated version of
Catch2
---
test/x4/catch_amalgamated.cpp | 12007 ---------------------------
test/x4/catch_amalgamated.hpp | 14306 --------------------------------
test/x4/test.hpp | 6 +-
3 files changed, 1 insertion(+), 26318 deletions(-)
delete mode 100644 test/x4/catch_amalgamated.cpp
delete mode 100644 test/x4/catch_amalgamated.hpp
diff --git a/test/x4/catch_amalgamated.cpp b/test/x4/catch_amalgamated.cpp
deleted file mode 100644
index c85f39b3b..000000000
--- a/test/x4/catch_amalgamated.cpp
+++ /dev/null
@@ -1,12007 +0,0 @@
-
-// Copyright Catch2 Authors
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE.txt or copy at
-// https://www.boost.org/LICENSE_1_0.txt)
-
-// SPDX-License-Identifier: BSL-1.0
-
-// Catch v3.10.0
-// Generated: 2025-08-24 16:18:04.775778
-// ----------------------------------------------------------
-// This file is an amalgamation of multiple different files.
-// You probably shouldn't edit it directly.
-// ----------------------------------------------------------
-
-#include "catch_amalgamated.hpp"
-
-
-#ifndef CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
-#define CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
-
-
-#if defined(CATCH_PLATFORM_WINDOWS)
-
-// We might end up with the define made globally through the compiler,
-// and we don't want to trigger warnings for this
-#if !defined(NOMINMAX)
-# define NOMINMAX
-#endif
-#if !defined(WIN32_LEAN_AND_MEAN)
-# define WIN32_LEAN_AND_MEAN
-#endif
-
-#include
-
-#endif // defined(CATCH_PLATFORM_WINDOWS)
-
-#endif // CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
-
-
-
-
-namespace Catch {
- namespace Benchmark {
- namespace Detail {
- ChronometerConcept::~ChronometerConcept() = default;
- } // namespace Detail
- } // namespace Benchmark
-} // namespace Catch
-
-
-// Adapted from donated nonius code.
-
-
-#include
-
-namespace Catch {
- namespace Benchmark {
- namespace Detail {
- SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last) {
- if (!cfg.benchmarkNoAnalysis()) {
- std::vector samples;
- samples.reserve(static_cast(last - first));
- for (auto current = first; current != last; ++current) {
- samples.push_back( current->count() );
- }
-
- auto analysis = Catch::Benchmark::Detail::analyse_samples(
- cfg.benchmarkConfidenceInterval(),
- cfg.benchmarkResamples(),
- samples.data(),
- samples.data() + samples.size() );
- auto outliers = Catch::Benchmark::Detail::classify_outliers(
- samples.data(), samples.data() + samples.size() );
-
- auto wrap_estimate = [](Estimate e) {
- return Estimate {
- FDuration(e.point),
- FDuration(e.lower_bound),
- FDuration(e.upper_bound),
- e.confidence_interval,
- };
- };
- std::vector samples2;
- samples2.reserve(samples.size());
- for (auto s : samples) {
- samples2.push_back( FDuration( s ) );
- }
-
- return {
- CATCH_MOVE(samples2),
- wrap_estimate(analysis.mean),
- wrap_estimate(analysis.standard_deviation),
- outliers,
- analysis.outlier_variance,
- };
- } else {
- std::vector samples;
- samples.reserve(static_cast(last - first));
-
- FDuration mean = FDuration(0);
- int i = 0;
- for (auto it = first; it < last; ++it, ++i) {
- samples.push_back(*it);
- mean += *it;
- }
- mean /= i;
-
- return SampleAnalysis{
- CATCH_MOVE(samples),
- Estimate{ mean, mean, mean, 0.0 },
- Estimate{ FDuration( 0 ),
- FDuration( 0 ),
- FDuration( 0 ),
- 0.0 },
- OutlierClassification{},
- 0.0
- };
- }
- }
- } // namespace Detail
- } // namespace Benchmark
-} // namespace Catch
-
-
-
-
-namespace Catch {
- namespace Benchmark {
- namespace Detail {
- struct do_nothing {
- void operator()() const {}
- };
-
- BenchmarkFunction::callable::~callable() = default;
- BenchmarkFunction::BenchmarkFunction():
- f( new model{ {} } ){}
- } // namespace Detail
- } // namespace Benchmark
-} // namespace Catch
-
-
-
-
-#include
-
-namespace Catch {
- namespace Benchmark {
- namespace Detail {
- struct optimized_away_error : std::exception {
- const char* what() const noexcept override;
- };
-
- const char* optimized_away_error::what() const noexcept {
- return "could not measure benchmark, maybe it was optimized away";
- }
-
- void throw_optimized_away_error() {
- Catch::throw_exception(optimized_away_error{});
- }
-
- } // namespace Detail
- } // namespace Benchmark
-} // namespace Catch
-
-
-// Adapted from donated nonius code.
-
-
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-
-#if defined(CATCH_CONFIG_USE_ASYNC)
-#include
-#endif
-
-namespace Catch {
- namespace Benchmark {
- namespace Detail {
- namespace {
-
- template
- static sample
- resample( URng& rng,
- unsigned int resamples,
- double const* first,
- double const* last,
- Estimator& estimator ) {
- auto n = static_cast( last - first );
- Catch::uniform_integer_distribution dist( 0, n - 1 );
-
- sample out;
- out.reserve( resamples );
- std::vector resampled;
- resampled.reserve( n );
- for ( size_t i = 0; i < resamples; ++i ) {
- resampled.clear();
- for ( size_t s = 0; s < n; ++s ) {
- resampled.push_back( first[dist( rng )] );
- }
- const auto estimate =
- estimator( resampled.data(), resampled.data() + resampled.size() );
- out.push_back( estimate );
- }
- std::sort( out.begin(), out.end() );
- return out;
- }
-
- static double outlier_variance( Estimate mean,
- Estimate stddev,
- int n ) {
- double sb = stddev.point;
- double mn = mean.point / n;
- double mg_min = mn / 2.;
- double sg = (std::min)( mg_min / 4., sb / std::sqrt( n ) );
- double sg2 = sg * sg;
- double sb2 = sb * sb;
-
- auto c_max = [n, mn, sb2, sg2]( double x ) -> double {
- double k = mn - x;
- double d = k * k;
- double nd = n * d;
- double k0 = -n * nd;
- double k1 = sb2 - n * sg2 + nd;
- double det = k1 * k1 - 4 * sg2 * k0;
- return static_cast( -2. * k0 /
- ( k1 + std::sqrt( det ) ) );
- };
-
- auto var_out = [n, sb2, sg2]( double c ) {
- double nc = n - c;
- return ( nc / n ) * ( sb2 - nc * sg2 );
- };
-
- return (std::min)( var_out( 1 ),
- var_out(
- (std::min)( c_max( 0. ),
- c_max( mg_min ) ) ) ) /
- sb2;
- }
-
- static double erf_inv( double x ) {
- // Code accompanying the article "Approximating the erfinv
- // function" in GPU Computing Gems, Volume 2
- double w, p;
-
- w = -log( ( 1.0 - x ) * ( 1.0 + x ) );
-
- if ( w < 6.250000 ) {
- w = w - 3.125000;
- p = -3.6444120640178196996e-21;
- p = -1.685059138182016589e-19 + p * w;
- p = 1.2858480715256400167e-18 + p * w;
- p = 1.115787767802518096e-17 + p * w;
- p = -1.333171662854620906e-16 + p * w;
- p = 2.0972767875968561637e-17 + p * w;
- p = 6.6376381343583238325e-15 + p * w;
- p = -4.0545662729752068639e-14 + p * w;
- p = -8.1519341976054721522e-14 + p * w;
- p = 2.6335093153082322977e-12 + p * w;
- p = -1.2975133253453532498e-11 + p * w;
- p = -5.4154120542946279317e-11 + p * w;
- p = 1.051212273321532285e-09 + p * w;
- p = -4.1126339803469836976e-09 + p * w;
- p = -2.9070369957882005086e-08 + p * w;
- p = 4.2347877827932403518e-07 + p * w;
- p = -1.3654692000834678645e-06 + p * w;
- p = -1.3882523362786468719e-05 + p * w;
- p = 0.0001867342080340571352 + p * w;
- p = -0.00074070253416626697512 + p * w;
- p = -0.0060336708714301490533 + p * w;
- p = 0.24015818242558961693 + p * w;
- p = 1.6536545626831027356 + p * w;
- } else if ( w < 16.000000 ) {
- w = sqrt( w ) - 3.250000;
- p = 2.2137376921775787049e-09;
- p = 9.0756561938885390979e-08 + p * w;
- p = -2.7517406297064545428e-07 + p * w;
- p = 1.8239629214389227755e-08 + p * w;
- p = 1.5027403968909827627e-06 + p * w;
- p = -4.013867526981545969e-06 + p * w;
- p = 2.9234449089955446044e-06 + p * w;
- p = 1.2475304481671778723e-05 + p * w;
- p = -4.7318229009055733981e-05 + p * w;
- p = 6.8284851459573175448e-05 + p * w;
- p = 2.4031110387097893999e-05 + p * w;
- p = -0.0003550375203628474796 + p * w;
- p = 0.00095328937973738049703 + p * w;
- p = -0.0016882755560235047313 + p * w;
- p = 0.0024914420961078508066 + p * w;
- p = -0.0037512085075692412107 + p * w;
- p = 0.005370914553590063617 + p * w;
- p = 1.0052589676941592334 + p * w;
- p = 3.0838856104922207635 + p * w;
- } else {
- w = sqrt( w ) - 5.000000;
- p = -2.7109920616438573243e-11;
- p = -2.5556418169965252055e-10 + p * w;
- p = 1.5076572693500548083e-09 + p * w;
- p = -3.7894654401267369937e-09 + p * w;
- p = 7.6157012080783393804e-09 + p * w;
- p = -1.4960026627149240478e-08 + p * w;
- p = 2.9147953450901080826e-08 + p * w;
- p = -6.7711997758452339498e-08 + p * w;
- p = 2.2900482228026654717e-07 + p * w;
- p = -9.9298272942317002539e-07 + p * w;
- p = 4.5260625972231537039e-06 + p * w;
- p = -1.9681778105531670567e-05 + p * w;
- p = 7.5995277030017761139e-05 + p * w;
- p = -0.00021503011930044477347 + p * w;
- p = -0.00013871931833623122026 + p * w;
- p = 1.0103004648645343977 + p * w;
- p = 4.8499064014085844221 + p * w;
- }
- return p * x;
- }
-
- static double
- standard_deviation( double const* first, double const* last ) {
- auto m = Catch::Benchmark::Detail::mean( first, last );
- double variance =
- std::accumulate( first,
- last,
- 0.,
- [m]( double a, double b ) {
- double diff = b - m;
- return a + diff * diff;
- } ) /
- static_cast( last - first );
- return std::sqrt( variance );
- }
-
- static sample jackknife( double ( *estimator )( double const*,
- double const* ),
- double* first,
- double* last ) {
- const auto second = first + 1;
- sample results;
- results.reserve( static_cast( last - first ) );
-
- for ( auto it = first; it != last; ++it ) {
- std::iter_swap( it, first );
- results.push_back( estimator( second, last ) );
- }
-
- return results;
- }
-
-
- } // namespace
- } // namespace Detail
- } // namespace Benchmark
-} // namespace Catch
-
-namespace Catch {
- namespace Benchmark {
- namespace Detail {
-
- double weighted_average_quantile( int k,
- int q,
- double* first,
- double* last ) {
- auto count = last - first;
- double idx = static_cast((count - 1) * k) / static_cast(q);
- int j = static_cast(idx);
- double g = idx - j;
- std::nth_element(first, first + j, last);
- auto xj = first[j];
- if ( Catch::Detail::directCompare( g, 0 ) ) {
- return xj;
- }
-
- auto xj1 = *std::min_element(first + (j + 1), last);
- return xj + g * (xj1 - xj);
- }
-
- OutlierClassification
- classify_outliers( double const* first, double const* last ) {
- std::vector copy( first, last );
-
- auto q1 = weighted_average_quantile( 1, 4, copy.data(), copy.data() + copy.size() );
- auto q3 = weighted_average_quantile( 3, 4, copy.data(), copy.data() + copy.size() );
- auto iqr = q3 - q1;
- auto los = q1 - ( iqr * 3. );
- auto lom = q1 - ( iqr * 1.5 );
- auto him = q3 + ( iqr * 1.5 );
- auto his = q3 + ( iqr * 3. );
-
- OutlierClassification o;
- for ( ; first != last; ++first ) {
- const double t = *first;
- if ( t < los ) {
- ++o.low_severe;
- } else if ( t < lom ) {
- ++o.low_mild;
- } else if ( t > his ) {
- ++o.high_severe;
- } else if ( t > him ) {
- ++o.high_mild;
- }
- ++o.samples_seen;
- }
- return o;
- }
-
- double mean( double const* first, double const* last ) {
- auto count = last - first;
- double sum = 0.;
- while (first != last) {
- sum += *first;
- ++first;
- }
- return sum / static_cast(count);
- }
-
- double normal_cdf( double x ) {
- return std::erfc( -x / std::sqrt( 2.0 ) ) / 2.0;
- }
-
- double erfc_inv(double x) {
- return erf_inv(1.0 - x);
- }
-
- double normal_quantile(double p) {
- static const double ROOT_TWO = std::sqrt(2.0);
-
- double result = 0.0;
- assert(p >= 0 && p <= 1);
- if (p < 0 || p > 1) {
- return result;
- }
-
- result = -erfc_inv(2.0 * p);
- // result *= normal distribution standard deviation (1.0) * sqrt(2)
- result *= /*sd * */ ROOT_TWO;
- // result += normal disttribution mean (0)
- return result;
- }
-
- Estimate
- bootstrap( double confidence_level,
- double* first,
- double* last,
- sample const& resample,
- double ( *estimator )( double const*, double const* ) ) {
- auto n_samples = last - first;
-
- double point = estimator( first, last );
- // Degenerate case with a single sample
- if ( n_samples == 1 )
- return { point, point, point, confidence_level };
-
- sample jack = jackknife( estimator, first, last );
- double jack_mean =
- mean( jack.data(), jack.data() + jack.size() );
- double sum_squares = 0, sum_cubes = 0;
- for ( double x : jack ) {
- auto difference = jack_mean - x;
- auto square = difference * difference;
- auto cube = square * difference;
- sum_squares += square;
- sum_cubes += cube;
- }
-
- double accel = sum_cubes / ( 6 * std::pow( sum_squares, 1.5 ) );
- long n = static_cast( resample.size() );
- double prob_n = static_cast(
- std::count_if( resample.begin(),
- resample.end(),
- [point]( double x ) { return x < point; } )) /
- static_cast( n );
- // degenerate case with uniform samples
- if ( Catch::Detail::directCompare( prob_n, 0. ) ) {
- return { point, point, point, confidence_level };
- }
-
- double bias = normal_quantile( prob_n );
- double z1 = normal_quantile( ( 1. - confidence_level ) / 2. );
-
- auto cumn = [n]( double x ) -> long {
- return std::lround( normal_cdf( x ) *
- static_cast( n ) );
- };
- auto a = [bias, accel]( double b ) {
- return bias + b / ( 1. - accel * b );
- };
- double b1 = bias + z1;
- double b2 = bias - z1;
- double a1 = a( b1 );
- double a2 = a( b2 );
- auto lo = static_cast( (std::max)( cumn( a1 ), 0l ) );
- auto hi =
- static_cast( (std::min)( cumn( a2 ), n - 1 ) );
-
- return { point, resample[lo], resample[hi], confidence_level };
- }
-
- bootstrap_analysis analyse_samples(double confidence_level,
- unsigned int n_resamples,
- double* first,
- double* last) {
- auto mean = &Detail::mean;
- auto stddev = &standard_deviation;
-
-#if defined(CATCH_CONFIG_USE_ASYNC)
- auto Estimate = [=](double(*f)(double const*, double const*)) {
- std::random_device rd;
- auto seed = rd();
- return std::async(std::launch::async, [=] {
- SimplePcg32 rng( seed );
- auto resampled = resample(rng, n_resamples, first, last, f);
- return bootstrap(confidence_level, first, last, resampled, f);
- });
- };
-
- auto mean_future = Estimate(mean);
- auto stddev_future = Estimate(stddev);
-
- auto mean_estimate = mean_future.get();
- auto stddev_estimate = stddev_future.get();
-#else
- auto Estimate = [=](double(*f)(double const* , double const*)) {
- std::random_device rd;
- auto seed = rd();
- SimplePcg32 rng( seed );
- auto resampled = resample(rng, n_resamples, first, last, f);
- return bootstrap(confidence_level, first, last, resampled, f);
- };
-
- auto mean_estimate = Estimate(mean);
- auto stddev_estimate = Estimate(stddev);
-#endif // CATCH_USE_ASYNC
-
- auto n = static_cast(last - first); // seriously, one can't use integral types without hell in C++
- double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);
-
- return { mean_estimate, stddev_estimate, outlier_variance };
- }
- } // namespace Detail
- } // namespace Benchmark
-} // namespace Catch
-
-
-
-#include
-#include
-
-namespace {
-
-// Performs equivalent check of std::fabs(lhs - rhs) <= margin
-// But without the subtraction to allow for INFINITY in comparison
-bool marginComparison(double lhs, double rhs, double margin) {
- return (lhs + margin >= rhs) && (rhs + margin >= lhs);
-}
-
-}
-
-namespace Catch {
-
- Approx::Approx ( double value )
- : m_epsilon( static_cast(std::numeric_limits::epsilon())*100. ),
- m_margin( 0.0 ),
- m_scale( 0.0 ),
- m_value( value )
- {}
-
- Approx Approx::custom() {
- return Approx( 0 );
- }
-
- Approx Approx::operator-() const {
- auto temp(*this);
- temp.m_value = -temp.m_value;
- return temp;
- }
-
-
- std::string Approx::toString() const {
- ReusableStringStream rss;
- rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
- return rss.str();
- }
-
- bool Approx::equalityComparisonImpl(const double other) const {
- // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
- // Thanks to Richard Harris for his help refining the scaled margin value
- return marginComparison(m_value, other, m_margin)
- || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
- }
-
- void Approx::setMargin(double newMargin) {
- CATCH_ENFORCE(newMargin >= 0,
- "Invalid Approx::margin: " << newMargin << '.'
- << " Approx::Margin has to be non-negative.");
- m_margin = newMargin;
- }
-
- void Approx::setEpsilon(double newEpsilon) {
- CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
- "Invalid Approx::epsilon: " << newEpsilon << '.'
- << " Approx::epsilon has to be in [0, 1]");
- m_epsilon = newEpsilon;
- }
-
-namespace literals {
- Approx operator ""_a(long double val) {
- return Approx(val);
- }
- Approx operator ""_a(unsigned long long val) {
- return Approx(val);
- }
-} // end namespace literals
-
-std::string StringMaker::convert(Catch::Approx const& value) {
- return value.toString();
-}
-
-} // end namespace Catch
-
-
-
-namespace Catch {
-
- AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const& _lazyExpression):
- lazyExpression(_lazyExpression),
- resultType(_resultType) {}
-
- std::string AssertionResultData::reconstructExpression() const {
-
- if( reconstructedExpression.empty() ) {
- if( lazyExpression ) {
- ReusableStringStream rss;
- rss << lazyExpression;
- reconstructedExpression = rss.str();
- }
- }
- return reconstructedExpression;
- }
-
- AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData&& data )
- : m_info( info ),
- m_resultData( CATCH_MOVE(data) )
- {}
-
- // Result was a success
- bool AssertionResult::succeeded() const {
- return Catch::isOk( m_resultData.resultType );
- }
-
- // Result was a success, or failure is suppressed
- bool AssertionResult::isOk() const {
- return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
- }
-
- ResultWas::OfType AssertionResult::getResultType() const {
- return m_resultData.resultType;
- }
-
- bool AssertionResult::hasExpression() const {
- return !m_info.capturedExpression.empty();
- }
-
- bool AssertionResult::hasMessage() const {
- return !m_resultData.message.empty();
- }
-
- std::string AssertionResult::getExpression() const {
- // Possibly overallocating by 3 characters should be basically free
- std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
- if (isFalseTest(m_info.resultDisposition)) {
- expr += "!(";
- }
- expr += m_info.capturedExpression;
- if (isFalseTest(m_info.resultDisposition)) {
- expr += ')';
- }
- return expr;
- }
-
- std::string AssertionResult::getExpressionInMacro() const {
- if ( m_info.macroName.empty() ) {
- return static_cast( m_info.capturedExpression );
- }
- std::string expr;
- expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
- expr += m_info.macroName;
- expr += "( ";
- expr += m_info.capturedExpression;
- expr += " )";
- return expr;
- }
-
- bool AssertionResult::hasExpandedExpression() const {
- return hasExpression() && getExpandedExpression() != getExpression();
- }
-
- std::string AssertionResult::getExpandedExpression() const {
- std::string expr = m_resultData.reconstructExpression();
- return expr.empty()
- ? getExpression()
- : expr;
- }
-
- StringRef AssertionResult::getMessage() const {
- return m_resultData.message;
- }
- SourceLineInfo AssertionResult::getSourceInfo() const {
- return m_info.lineInfo;
- }
-
- StringRef AssertionResult::getTestMacroName() const {
- return m_info.macroName;
- }
-
-} // end namespace Catch
-
-
-
-#include
-
-namespace Catch {
-
- namespace {
- static bool enableBazelEnvSupport() {
-#if defined( CATCH_CONFIG_BAZEL_SUPPORT )
- return true;
-#else
- return Detail::getEnv( "BAZEL_TEST" ) != nullptr;
-#endif
- }
-
- struct bazelShardingOptions {
- unsigned int shardIndex, shardCount;
- std::string shardFilePath;
- };
-
- static Optional readBazelShardingOptions() {
- const auto bazelShardIndex = Detail::getEnv( "TEST_SHARD_INDEX" );
- const auto bazelShardTotal = Detail::getEnv( "TEST_TOTAL_SHARDS" );
- const auto bazelShardInfoFile = Detail::getEnv( "TEST_SHARD_STATUS_FILE" );
-
-
- const bool has_all =
- bazelShardIndex && bazelShardTotal && bazelShardInfoFile;
- if ( !has_all ) {
- // We provide nice warning message if the input is
- // misconfigured.
- auto warn = []( const char* env_var ) {
- Catch::cerr()
- << "Warning: Bazel shard configuration is missing '"
- << env_var << "'. Shard configuration is skipped.\n";
- };
- if ( !bazelShardIndex ) {
- warn( "TEST_SHARD_INDEX" );
- }
- if ( !bazelShardTotal ) {
- warn( "TEST_TOTAL_SHARDS" );
- }
- if ( !bazelShardInfoFile ) {
- warn( "TEST_SHARD_STATUS_FILE" );
- }
- return {};
- }
-
- auto shardIndex = parseUInt( bazelShardIndex );
- if ( !shardIndex ) {
- Catch::cerr()
- << "Warning: could not parse 'TEST_SHARD_INDEX' ('" << bazelShardIndex
- << "') as unsigned int.\n";
- return {};
- }
- auto shardTotal = parseUInt( bazelShardTotal );
- if ( !shardTotal ) {
- Catch::cerr()
- << "Warning: could not parse 'TEST_TOTAL_SHARD' ('"
- << bazelShardTotal << "') as unsigned int.\n";
- return {};
- }
-
- return bazelShardingOptions{
- *shardIndex, *shardTotal, bazelShardInfoFile };
-
- }
- } // end namespace
-
-
- bool operator==( ProcessedReporterSpec const& lhs,
- ProcessedReporterSpec const& rhs ) {
- return lhs.name == rhs.name &&
- lhs.outputFilename == rhs.outputFilename &&
- lhs.colourMode == rhs.colourMode &&
- lhs.customOptions == rhs.customOptions;
- }
-
- Config::Config( ConfigData const& data ):
- m_data( data ) {
- // We need to trim filter specs to avoid trouble with superfluous
- // whitespace (esp. important for bdd macros, as those are manually
- // aligned with whitespace).
-
- for (auto& elem : m_data.testsOrTags) {
- elem = trim(elem);
- }
- for (auto& elem : m_data.sectionsToRun) {
- elem = trim(elem);
- }
-
- // Insert the default reporter if user hasn't asked for a specific one
- if ( m_data.reporterSpecifications.empty() ) {
-#if defined( CATCH_CONFIG_DEFAULT_REPORTER )
- const auto default_spec = CATCH_CONFIG_DEFAULT_REPORTER;
-#else
- const auto default_spec = "console";
-#endif
- auto parsed = parseReporterSpec(default_spec);
- CATCH_ENFORCE( parsed,
- "Cannot parse the provided default reporter spec: '"
- << default_spec << '\'' );
- m_data.reporterSpecifications.push_back( std::move( *parsed ) );
- }
-
- if ( enableBazelEnvSupport() ) {
- readBazelEnvVars();
- }
-
- // Bazel support can modify the test specs, so parsing has to happen
- // after reading Bazel env vars.
- TestSpecParser parser( ITagAliasRegistry::get() );
- if ( !m_data.testsOrTags.empty() ) {
- m_hasTestFilters = true;
- for ( auto const& testOrTags : m_data.testsOrTags ) {
- parser.parse( testOrTags );
- }
- }
- m_testSpec = parser.testSpec();
-
-
- // We now fixup the reporter specs to handle default output spec,
- // default colour spec, etc
- bool defaultOutputUsed = false;
- for ( auto const& reporterSpec : m_data.reporterSpecifications ) {
- // We do the default-output check separately, while always
- // using the default output below to make the code simpler
- // and avoid superfluous copies.
- if ( reporterSpec.outputFile().none() ) {
- CATCH_ENFORCE( !defaultOutputUsed,
- "Internal error: cannot use default output for "
- "multiple reporters" );
- defaultOutputUsed = true;
- }
-
- m_processedReporterSpecs.push_back( ProcessedReporterSpec{
- reporterSpec.name(),
- reporterSpec.outputFile() ? *reporterSpec.outputFile()
- : data.defaultOutputFilename,
- reporterSpec.colourMode().valueOr( data.defaultColourMode ),
- reporterSpec.customOptions() } );
- }
- }
-
- Config::~Config() = default;
-
-
- bool Config::listTests() const { return m_data.listTests; }
- bool Config::listTags() const { return m_data.listTags; }
- bool Config::listReporters() const { return m_data.listReporters; }
- bool Config::listListeners() const { return m_data.listListeners; }
-
- std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
- std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
-
- std::vector const& Config::getReporterSpecs() const {
- return m_data.reporterSpecifications;
- }
-
- std::vector const&
- Config::getProcessedReporterSpecs() const {
- return m_processedReporterSpecs;
- }
-
- TestSpec const& Config::testSpec() const { return m_testSpec; }
- bool Config::hasTestFilters() const { return m_hasTestFilters; }
-
- bool Config::showHelp() const { return m_data.showHelp; }
-
- // IConfig interface
- bool Config::allowThrows() const { return !m_data.noThrow; }
- StringRef Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
- bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
- bool Config::warnAboutMissingAssertions() const {
- return !!( m_data.warnings & WarnAbout::NoAssertions );
- }
- bool Config::warnAboutUnmatchedTestSpecs() const {
- return !!( m_data.warnings & WarnAbout::UnmatchedTestSpec );
- }
- bool Config::zeroTestsCountAsSuccess() const { return m_data.allowZeroTests; }
- ShowDurations Config::showDurations() const { return m_data.showDurations; }
- double Config::minDuration() const { return m_data.minDuration; }
- TestRunOrder Config::runOrder() const { return m_data.runOrder; }
- uint32_t Config::rngSeed() const { return m_data.rngSeed; }
- unsigned int Config::shardCount() const { return m_data.shardCount; }
- unsigned int Config::shardIndex() const { return m_data.shardIndex; }
- ColourMode Config::defaultColourMode() const { return m_data.defaultColourMode; }
- bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
- int Config::abortAfter() const { return m_data.abortAfter; }
- bool Config::showInvisibles() const { return m_data.showInvisibles; }
- Verbosity Config::verbosity() const { return m_data.verbosity; }
-
- bool Config::skipBenchmarks() const { return m_data.skipBenchmarks; }
- bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
- unsigned int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
- double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }
- unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
- std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
-
- void Config::readBazelEnvVars() {
- // Register a JUnit reporter for Bazel. Bazel sets an environment
- // variable with the path to XML output. If this file is written to
- // during test, Bazel will not generate a default XML output.
- // This allows the XML output file to contain higher level of detail
- // than what is possible otherwise.
- const auto bazelOutputFile = Detail::getEnv( "XML_OUTPUT_FILE" );
-
- if ( bazelOutputFile ) {
- m_data.reporterSpecifications.push_back(
- { "junit", std::string( bazelOutputFile ), {}, {} } );
- }
-
- const auto bazelTestSpec = Detail::getEnv( "TESTBRIDGE_TEST_ONLY" );
- if ( bazelTestSpec ) {
- // Presumably the test spec from environment should overwrite
- // the one we got from CLI (if we got any)
- m_data.testsOrTags.clear();
- m_data.testsOrTags.push_back( bazelTestSpec );
- }
-
- const auto bazelShardOptions = readBazelShardingOptions();
- if ( bazelShardOptions ) {
- std::ofstream f( bazelShardOptions->shardFilePath,
- std::ios_base::out | std::ios_base::trunc );
- if ( f.is_open() ) {
- f << "";
- m_data.shardIndex = bazelShardOptions->shardIndex;
- m_data.shardCount = bazelShardOptions->shardCount;
- }
- }
- }
-
-} // end namespace Catch
-
-
-
-
-
-namespace Catch {
- std::uint32_t getSeed() {
- return getCurrentContext().getConfig()->rngSeed();
- }
-}
-
-
-
-#include
-#include
-
-namespace Catch {
-
- ////////////////////////////////////////////////////////////////////////////
-
-
- ScopedMessage::ScopedMessage( MessageBuilder&& builder ):
- m_info( CATCH_MOVE(builder.m_info) ) {
- m_info.message = builder.m_stream.str();
- getResultCapture().pushScopedMessage( m_info );
- }
-
- ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
- m_info( CATCH_MOVE( old.m_info ) ) {
- old.m_moved = true;
- }
-
- ScopedMessage::~ScopedMessage() {
- if ( !m_moved ){
- getResultCapture().popScopedMessage(m_info);
- }
- }
-
-
- Capturer::Capturer( StringRef macroName,
- SourceLineInfo const& lineInfo,
- ResultWas::OfType resultType,
- StringRef names ):
- m_resultCapture( getResultCapture() ) {
- auto trimmed = [&] (size_t start, size_t end) {
- while (names[start] == ',' || isspace(static_cast(names[start]))) {
- ++start;
- }
- while (names[end] == ',' || isspace(static_cast(names[end]))) {
- --end;
- }
- return names.substr(start, end - start + 1);
- };
- auto skipq = [&] (size_t start, char quote) {
- for (auto i = start + 1; i < names.size() ; ++i) {
- if (names[i] == quote)
- return i;
- if (names[i] == '\\')
- ++i;
- }
- CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
- };
-
- size_t start = 0;
- std::stack openings;
- for (size_t pos = 0; pos < names.size(); ++pos) {
- char c = names[pos];
- switch (c) {
- case '[':
- case '{':
- case '(':
- // It is basically impossible to disambiguate between
- // comparison and start of template args in this context
-// case '<':
- openings.push(c);
- break;
- case ']':
- case '}':
- case ')':
-// case '>':
- openings.pop();
- break;
- case '"':
- case '\'':
- pos = skipq(pos, c);
- break;
- case ',':
- if (start != pos && openings.empty()) {
- m_messages.emplace_back(macroName, lineInfo, resultType);
- m_messages.back().message = static_cast(trimmed(start, pos));
- m_messages.back().message += " := ";
- start = pos;
- }
- break;
- default:; // noop
- }
- }
- assert(openings.empty() && "Mismatched openings");
- m_messages.emplace_back(macroName, lineInfo, resultType);
- m_messages.back().message = static_cast(trimmed(start, names.size() - 1));
- m_messages.back().message += " := ";
- }
- Capturer::~Capturer() {
- assert( m_captured == m_messages.size() );
- for ( size_t i = 0; i < m_captured; ++i ) {
- m_resultCapture.popScopedMessage( m_messages[i] );
- }
- }
-
- void Capturer::captureValue( size_t index, std::string const& value ) {
- assert( index < m_messages.size() );
- m_messages[index].message += value;
- m_resultCapture.pushScopedMessage( m_messages[index] );
- m_captured++;
- }
-
-} // end namespace Catch
-
-
-
-
-#include
-
-namespace Catch {
-
- namespace {
-
- class RegistryHub : public IRegistryHub,
- public IMutableRegistryHub,
- private Detail::NonCopyable {
-
- public: // IRegistryHub
- RegistryHub() = default;
- ReporterRegistry const& getReporterRegistry() const override {
- return m_reporterRegistry;
- }
- ITestCaseRegistry const& getTestCaseRegistry() const override {
- return m_testCaseRegistry;
- }
- IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
- return m_exceptionTranslatorRegistry;
- }
- ITagAliasRegistry const& getTagAliasRegistry() const override {
- return m_tagAliasRegistry;
- }
- StartupExceptionRegistry const& getStartupExceptionRegistry() const override {
- return m_exceptionRegistry;
- }
-
- public: // IMutableRegistryHub
- void registerReporter( std::string const& name, IReporterFactoryPtr factory ) override {
- m_reporterRegistry.registerReporter( name, CATCH_MOVE(factory) );
- }
- void registerListener( Detail::unique_ptr factory ) override {
- m_reporterRegistry.registerListener( CATCH_MOVE(factory) );
- }
- void registerTest( Detail::unique_ptr&& testInfo, Detail::unique_ptr&& invoker ) override {
- m_testCaseRegistry.registerTest( CATCH_MOVE(testInfo), CATCH_MOVE(invoker) );
- }
- void registerTranslator( Detail::unique_ptr&& translator ) override {
- m_exceptionTranslatorRegistry.registerTranslator( CATCH_MOVE(translator) );
- }
- void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {
- m_tagAliasRegistry.add( alias, tag, lineInfo );
- }
- void registerStartupException() noexcept override {
-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
- m_exceptionRegistry.add(std::current_exception());
-#else
- CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
-#endif
- }
- IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
- return m_enumValuesRegistry;
- }
-
- private:
- TestRegistry m_testCaseRegistry;
- ReporterRegistry m_reporterRegistry;
- ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
- TagAliasRegistry m_tagAliasRegistry;
- StartupExceptionRegistry m_exceptionRegistry;
- Detail::EnumValuesRegistry m_enumValuesRegistry;
- };
- }
-
- using RegistryHubSingleton = Singleton;
-
- IRegistryHub const& getRegistryHub() {
- return RegistryHubSingleton::get();
- }
- IMutableRegistryHub& getMutableRegistryHub() {
- return RegistryHubSingleton::getMutable();
- }
- void cleanUp() {
- cleanupSingletons();
- cleanUpContext();
- }
- std::string translateActiveException() {
- return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
- }
-
-
-} // end namespace Catch
-
-
-
-#include
-#include
-#include
-#include
-
-namespace Catch {
-
- namespace {
- IEventListenerPtr createReporter(std::string const& reporterName, ReporterConfig&& config) {
- auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, CATCH_MOVE(config));
- CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << '\'');
-
- return reporter;
- }
-
- IEventListenerPtr prepareReporters(Config const* config) {
- if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()
- && config->getProcessedReporterSpecs().size() == 1) {
- auto const& spec = config->getProcessedReporterSpecs()[0];
- return createReporter(
- spec.name,
- ReporterConfig( config,
- makeStream( spec.outputFilename ),
- spec.colourMode,
- spec.customOptions ) );
- }
-
- auto multi = Detail::make_unique(config);
-
- auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
- for (auto const& listener : listeners) {
- multi->addListener(listener->create(config));
- }
-
- for ( auto const& reporterSpec : config->getProcessedReporterSpecs() ) {
- multi->addReporter( createReporter(
- reporterSpec.name,
- ReporterConfig( config,
- makeStream( reporterSpec.outputFilename ),
- reporterSpec.colourMode,
- reporterSpec.customOptions ) ) );
- }
-
- return multi;
- }
-
- class TestGroup {
- public:
- explicit TestGroup(IEventListenerPtr&& reporter, Config const* config):
- m_reporter(reporter.get()),
- m_config{config},
- m_context{config, CATCH_MOVE(reporter)} {
-
- assert( m_config->testSpec().getInvalidSpecs().empty() &&
- "Invalid test specs should be handled before running tests" );
-
- auto const& allTestCases = getAllTestCasesSorted(*m_config);
- auto const& testSpec = m_config->testSpec();
- if ( !testSpec.hasFilters() ) {
- for ( auto const& test : allTestCases ) {
- if ( !test.getTestCaseInfo().isHidden() ) {
- m_tests.emplace( &test );
- }
- }
- } else {
- m_matches =
- testSpec.matchesByFilter( allTestCases, *m_config );
- for ( auto const& match : m_matches ) {
- m_tests.insert( match.tests.begin(),
- match.tests.end() );
- }
- }
-
- m_tests = createShard(m_tests, m_config->shardCount(), m_config->shardIndex());
- }
-
- Totals execute() {
- Totals totals;
- for (auto const& testCase : m_tests) {
- if (!m_context.aborting())
- totals += m_context.runTest(*testCase);
- else
- m_reporter->skipTest(testCase->getTestCaseInfo());
- }
-
- for (auto const& match : m_matches) {
- if (match.tests.empty()) {
- m_unmatchedTestSpecs = true;
- m_reporter->noMatchingTestCases( match.name );
- }
- }
-
- return totals;
- }
-
- bool hadUnmatchedTestSpecs() const {
- return m_unmatchedTestSpecs;
- }
-
-
- private:
- IEventListener* m_reporter;
- Config const* m_config;
- RunContext m_context;
- std::set m_tests;
- TestSpec::Matches m_matches;
- bool m_unmatchedTestSpecs = false;
- };
-
- void applyFilenamesAsTags() {
- for (auto const& testInfo : getRegistryHub().getTestCaseRegistry().getAllInfos()) {
- testInfo->addFilenameTag();
- }
- }
-
- } // anon namespace
-
- Session::Session() {
- static bool alreadyInstantiated = false;
- if( alreadyInstantiated ) {
- CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
- CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
- }
-
- // There cannot be exceptions at startup in no-exception mode.
-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
- const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
- if ( !exceptions.empty() ) {
- config();
- getCurrentMutableContext().setConfig(m_config.get());
-
- m_startupExceptions = true;
- auto errStream = makeStream( "%stderr" );
- auto colourImpl = makeColourImpl(
- ColourMode::PlatformDefault, errStream.get() );
- auto guard = colourImpl->guardColour( Colour::Red );
- errStream->stream() << "Errors occurred during startup!" << '\n';
- // iterate over all exceptions and notify user
- for ( const auto& ex_ptr : exceptions ) {
- try {
- std::rethrow_exception(ex_ptr);
- } catch ( std::exception const& ex ) {
- errStream->stream() << TextFlow::Column( ex.what() ).indent(2) << '\n';
- }
- }
- }
-#endif
-
- alreadyInstantiated = true;
- m_cli = makeCommandLineParser( m_configData );
- }
- Session::~Session() {
- Catch::cleanUp();
- }
-
- void Session::showHelp() const {
- Catch::cout()
- << "\nCatch2 v" << libraryVersion() << '\n'
- << m_cli << '\n'
- << "For more detailed usage please see the project docs\n\n" << std::flush;
- }
- void Session::libIdentify() {
- Catch::cout()
- << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
- << std::left << std::setw(16) << "category: " << "testframework\n"
- << std::left << std::setw(16) << "framework: " << "Catch2\n"
- << std::left << std::setw(16) << "version: " << libraryVersion() << '\n' << std::flush;
- }
-
- int Session::applyCommandLine( int argc, char const * const * argv ) {
- if ( m_startupExceptions ) { return UnspecifiedErrorExitCode; }
-
- auto result = m_cli.parse( Clara::Args( argc, argv ) );
-
- if( !result ) {
- config();
- getCurrentMutableContext().setConfig(m_config.get());
- auto errStream = makeStream( "%stderr" );
- auto colour = makeColourImpl( ColourMode::PlatformDefault, errStream.get() );
-
- errStream->stream()
- << colour->guardColour( Colour::Red )
- << "\nError(s) in input:\n"
- << TextFlow::Column( result.errorMessage() ).indent( 2 )
- << "\n\n";
- errStream->stream() << "Run with -? for usage\n\n" << std::flush;
- return UnspecifiedErrorExitCode;
- }
-
- if( m_configData.showHelp )
- showHelp();
- if( m_configData.libIdentify )
- libIdentify();
-
- m_config.reset();
- return 0;
- }
-
-#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
- int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
-
- char **utf8Argv = new char *[ argc ];
-
- for ( int i = 0; i < argc; ++i ) {
- int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
-
- utf8Argv[ i ] = new char[ bufSize ];
-
- WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
- }
-
- int returnCode = applyCommandLine( argc, utf8Argv );
-
- for ( int i = 0; i < argc; ++i )
- delete [] utf8Argv[ i ];
-
- delete [] utf8Argv;
-
- return returnCode;
- }
-#endif
-
- void Session::useConfigData( ConfigData const& configData ) {
- m_configData = configData;
- m_config.reset();
- }
-
- int Session::run() {
- if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
- Catch::cout() << "...waiting for enter/ return before starting\n" << std::flush;
- static_cast(std::getchar());
- }
- int exitCode = runInternal();
- if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
- Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << '\n' << std::flush;
- static_cast(std::getchar());
- }
- return exitCode;
- }
-
- Clara::Parser const& Session::cli() const {
- return m_cli;
- }
- void Session::cli( Clara::Parser const& newParser ) {
- m_cli = newParser;
- }
- ConfigData& Session::configData() {
- return m_configData;
- }
- Config& Session::config() {
- if( !m_config )
- m_config = Detail::make_unique( m_configData );
- return *m_config;
- }
-
- int Session::runInternal() {
- if ( m_startupExceptions ) { return UnspecifiedErrorExitCode; }
-
- if (m_configData.showHelp || m_configData.libIdentify) {
- return 0;
- }
-
- if ( m_configData.shardIndex >= m_configData.shardCount ) {
- Catch::cerr() << "The shard count (" << m_configData.shardCount
- << ") must be greater than the shard index ("
- << m_configData.shardIndex << ")\n"
- << std::flush;
- return UnspecifiedErrorExitCode;
- }
-
- CATCH_TRY {
- config(); // Force config to be constructed
-
- seedRng( *m_config );
-
- if (m_configData.filenamesAsTags) {
- applyFilenamesAsTags();
- }
-
- // Set up global config instance before we start calling into other functions
- getCurrentMutableContext().setConfig(m_config.get());
-
- // Create reporter(s) so we can route listings through them
- auto reporter = prepareReporters(m_config.get());
-
- auto const& invalidSpecs = m_config->testSpec().getInvalidSpecs();
- if ( !invalidSpecs.empty() ) {
- for ( auto const& spec : invalidSpecs ) {
- reporter->reportInvalidTestSpec( spec );
- }
- return InvalidTestSpecExitCode;
- }
-
-
- // Handle list request
- if (list(*reporter, *m_config)) {
- return 0;
- }
-
- TestGroup tests { CATCH_MOVE(reporter), m_config.get() };
- auto const totals = tests.execute();
-
- if ( tests.hadUnmatchedTestSpecs()
- && m_config->warnAboutUnmatchedTestSpecs() ) {
- // UnmatchedTestSpecExitCode
- return UnmatchedTestSpecExitCode;
- }
-
- if ( totals.testCases.total() == 0
- && !m_config->zeroTestsCountAsSuccess() ) {
- return NoTestsRunExitCode;
- }
-
- if ( totals.testCases.total() > 0 &&
- totals.testCases.total() == totals.testCases.skipped
- && !m_config->zeroTestsCountAsSuccess() ) {
- return AllTestsSkippedExitCode;
- }
-
- if ( totals.assertions.failed ) { return TestFailureExitCode; }
- return 0;
-
- }
-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
- catch( std::exception& ex ) {
- Catch::cerr() << ex.what() << '\n' << std::flush;
- return UnspecifiedErrorExitCode;
- }
-#endif
- }
-
-} // end namespace Catch
-
-
-
-
-namespace Catch {
-
- RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {
- CATCH_TRY {
- getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);
- } CATCH_CATCH_ALL {
- // Do not throw when constructing global objects, instead register the exception to be processed later
- getMutableRegistryHub().registerStartupException();
- }
- }
-
-}
-
-
-
-#include
-#include
-#include
-
-namespace Catch {
-
- namespace {
- using TCP_underlying_type = uint8_t;
- static_assert(sizeof(TestCaseProperties) == sizeof(TCP_underlying_type),
- "The size of the TestCaseProperties is different from the assumed size");
-
- constexpr TestCaseProperties operator|(TestCaseProperties lhs, TestCaseProperties rhs) {
- return static_cast(
- static_cast(lhs) | static_cast(rhs)
- );
- }
-
- constexpr TestCaseProperties& operator|=(TestCaseProperties& lhs, TestCaseProperties rhs) {
- lhs = static_cast(
- static_cast(lhs) | static_cast(rhs)
- );
- return lhs;
- }
-
- constexpr TestCaseProperties operator&(TestCaseProperties lhs, TestCaseProperties rhs) {
- return static_cast(
- static_cast(lhs) & static_cast(rhs)
- );
- }
-
- constexpr bool applies(TestCaseProperties tcp) {
- static_assert(static_cast(TestCaseProperties::None) == 0,
- "TestCaseProperties::None must be equal to 0");
- return tcp != TestCaseProperties::None;
- }
-
- TestCaseProperties parseSpecialTag( StringRef tag ) {
- if( !tag.empty() && tag[0] == '.' )
- return TestCaseProperties::IsHidden;
- else if( tag == "!throws"_sr )
- return TestCaseProperties::Throws;
- else if( tag == "!shouldfail"_sr )
- return TestCaseProperties::ShouldFail;
- else if( tag == "!mayfail"_sr )
- return TestCaseProperties::MayFail;
- else if( tag == "!nonportable"_sr )
- return TestCaseProperties::NonPortable;
- else if( tag == "!benchmark"_sr )
- return TestCaseProperties::Benchmark | TestCaseProperties::IsHidden;
- else
- return TestCaseProperties::None;
- }
- bool isReservedTag( StringRef tag ) {
- return parseSpecialTag( tag ) == TestCaseProperties::None
- && tag.size() > 0
- && !std::isalnum( static_cast(tag[0]) );
- }
- void enforceNotReservedTag( StringRef tag, SourceLineInfo const& _lineInfo ) {
- CATCH_ENFORCE( !isReservedTag(tag),
- "Tag name: [" << tag << "] is not allowed.\n"
- << "Tag names starting with non alphanumeric characters are reserved\n"
- << _lineInfo );
- }
-
- std::string makeDefaultName() {
- static size_t counter = 0;
- return "Anonymous test case " + std::to_string(++counter);
- }
-
- constexpr StringRef extractFilenamePart(StringRef filename) {
- size_t lastDot = filename.size();
- while (lastDot > 0 && filename[lastDot - 1] != '.') {
- --lastDot;
- }
- // In theory we could have filename without any extension in it
- if ( lastDot == 0 ) { return StringRef(); }
-
- --lastDot;
- size_t nameStart = lastDot;
- while (nameStart > 0 && filename[nameStart - 1] != '/' && filename[nameStart - 1] != '\\') {
- --nameStart;
- }
-
- return filename.substr(nameStart, lastDot - nameStart);
- }
-
- // Returns the upper bound on size of extra tags ([#file]+[.])
- constexpr size_t sizeOfExtraTags(StringRef filepath) {
- // [.] is 3, [#] is another 3
- const size_t extras = 3 + 3;
- return extractFilenamePart(filepath).size() + extras;
- }
- } // end unnamed namespace
-
- bool operator<( Tag const& lhs, Tag const& rhs ) {
- Detail::CaseInsensitiveLess cmp;
- return cmp( lhs.original, rhs.original );
- }
- bool operator==( Tag const& lhs, Tag const& rhs ) {
- Detail::CaseInsensitiveEqualTo cmp;
- return cmp( lhs.original, rhs.original );
- }
-
- Detail::unique_ptr
- makeTestCaseInfo(StringRef _className,
- NameAndTags const& nameAndTags,
- SourceLineInfo const& _lineInfo ) {
- return Detail::make_unique(_className, nameAndTags, _lineInfo);
- }
-
- TestCaseInfo::TestCaseInfo(StringRef _className,
- NameAndTags const& _nameAndTags,
- SourceLineInfo const& _lineInfo):
- name( _nameAndTags.name.empty() ? makeDefaultName() : _nameAndTags.name ),
- className( _className ),
- lineInfo( _lineInfo )
- {
- StringRef originalTags = _nameAndTags.tags;
- // We need to reserve enough space to store all of the tags
- // (including optional hidden tag and filename tag)
- auto requiredSize = originalTags.size() + sizeOfExtraTags(_lineInfo.file);
- backingTags.reserve(requiredSize);
-
- // We cannot copy the tags directly, as we need to normalize
- // some tags, so that [.foo] is copied as [.][foo].
- size_t tagStart = 0;
- size_t tagEnd = 0;
- bool inTag = false;
- for (size_t idx = 0; idx < originalTags.size(); ++idx) {
- auto c = originalTags[idx];
- if (c == '[') {
- CATCH_ENFORCE(
- !inTag,
- "Found '[' inside a tag while registering test case '"
- << _nameAndTags.name << "' at " << _lineInfo );
-
- inTag = true;
- tagStart = idx;
- }
- if (c == ']') {
- CATCH_ENFORCE(
- inTag,
- "Found unmatched ']' while registering test case '"
- << _nameAndTags.name << "' at " << _lineInfo );
-
- inTag = false;
- tagEnd = idx;
- assert(tagStart < tagEnd);
-
- // We need to check the tag for special meanings, copy
- // it over to backing storage and actually reference the
- // backing storage in the saved tags
- StringRef tagStr = originalTags.substr(tagStart+1, tagEnd - tagStart - 1);
- CATCH_ENFORCE( !tagStr.empty(),
- "Found an empty tag while registering test case '"
- << _nameAndTags.name << "' at "
- << _lineInfo );
-
- enforceNotReservedTag(tagStr, lineInfo);
- properties |= parseSpecialTag(tagStr);
- // When copying a tag to the backing storage, we need to
- // check if it is a merged hide tag, such as [.foo], and
- // if it is, we need to handle it as if it was [foo].
- if (tagStr.size() > 1 && tagStr[0] == '.') {
- tagStr = tagStr.substr(1, tagStr.size() - 1);
- }
- // We skip over dealing with the [.] tag, as we will add
- // it later unconditionally and then sort and unique all
- // the tags.
- internalAppendTag(tagStr);
- }
- }
- CATCH_ENFORCE( !inTag,
- "Found an unclosed tag while registering test case '"
- << _nameAndTags.name << "' at " << _lineInfo );
-
-
- // Add [.] if relevant
- if (isHidden()) {
- internalAppendTag("."_sr);
- }
-
- // Sort and prepare tags
- std::sort(begin(tags), end(tags));
- tags.erase(std::unique(begin(tags), end(tags)),
- end(tags));
- }
-
- bool TestCaseInfo::isHidden() const {
- return applies( properties & TestCaseProperties::IsHidden );
- }
- bool TestCaseInfo::throws() const {
- return applies( properties & TestCaseProperties::Throws );
- }
- bool TestCaseInfo::okToFail() const {
- return applies( properties & (TestCaseProperties::ShouldFail | TestCaseProperties::MayFail ) );
- }
- bool TestCaseInfo::expectedToFail() const {
- return applies( properties & (TestCaseProperties::ShouldFail) );
- }
-
- void TestCaseInfo::addFilenameTag() {
- std::string combined("#");
- combined += extractFilenamePart(lineInfo.file);
- internalAppendTag(combined);
- }
-
- std::string TestCaseInfo::tagsAsString() const {
- std::string ret;
- // '[' and ']' per tag
- std::size_t full_size = 2 * tags.size();
- for (const auto& tag : tags) {
- full_size += tag.original.size();
- }
- ret.reserve(full_size);
- for (const auto& tag : tags) {
- ret.push_back('[');
- ret += tag.original;
- ret.push_back(']');
- }
-
- return ret;
- }
-
- void TestCaseInfo::internalAppendTag(StringRef tagStr) {
- backingTags += '[';
- const auto backingStart = backingTags.size();
- backingTags += tagStr;
- const auto backingEnd = backingTags.size();
- backingTags += ']';
- tags.emplace_back(StringRef(backingTags.c_str() + backingStart, backingEnd - backingStart));
- }
-
- bool operator<( TestCaseInfo const& lhs, TestCaseInfo const& rhs ) {
- // We want to avoid redoing the string comparisons multiple times,
- // so we store the result of a three-way comparison before using
- // it in the actual comparison logic.
- const auto cmpName = lhs.name.compare( rhs.name );
- if ( cmpName != 0 ) {
- return cmpName < 0;
- }
- const auto cmpClassName = lhs.className.compare( rhs.className );
- if ( cmpClassName != 0 ) {
- return cmpClassName < 0;
- }
- return lhs.tags < rhs.tags;
- }
-
-} // end namespace Catch
-
-
-
-#include
-#include
-#include
-#include
-
-namespace Catch {
-
- TestSpec::Pattern::Pattern( std::string const& name )
- : m_name( name )
- {}
-
- TestSpec::Pattern::~Pattern() = default;
-
- std::string const& TestSpec::Pattern::name() const {
- return m_name;
- }
-
-
- TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
- : Pattern( filterString )
- , m_wildcardPattern( toLower( name ), CaseSensitive::No )
- {}
-
- bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
- return m_wildcardPattern.matches( testCase.name );
- }
-
- void TestSpec::NamePattern::serializeTo( std::ostream& out ) const {
- out << '"' << name() << '"';
- }
-
-
- TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
- : Pattern( filterString )
- , m_tag( tag )
- {}
-
- bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
- return std::find( begin( testCase.tags ),
- end( testCase.tags ),
- Tag( m_tag ) ) != end( testCase.tags );
- }
-
- void TestSpec::TagPattern::serializeTo( std::ostream& out ) const {
- out << name();
- }
-
- bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
- bool should_use = !testCase.isHidden();
- for (auto const& pattern : m_required) {
- should_use = true;
- if (!pattern->matches(testCase)) {
- return false;
- }
- }
- for (auto const& pattern : m_forbidden) {
- if (pattern->matches(testCase)) {
- return false;
- }
- }
- return should_use;
- }
-
- void TestSpec::Filter::serializeTo( std::ostream& out ) const {
- bool first = true;
- for ( auto const& pattern : m_required ) {
- if ( !first ) {
- out << ' ';
- }
- out << *pattern;
- first = false;
- }
- for ( auto const& pattern : m_forbidden ) {
- if ( !first ) {
- out << ' ';
- }
- out << *pattern;
- first = false;
- }
- }
-
-
- std::string TestSpec::extractFilterName( Filter const& filter ) {
- Catch::ReusableStringStream sstr;
- sstr << filter;
- return sstr.str();
- }
-
- bool TestSpec::hasFilters() const {
- return !m_filters.empty();
- }
-
- bool TestSpec::matches( TestCaseInfo const& testCase ) const {
- return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
- }
-
- TestSpec::Matches TestSpec::matchesByFilter( std::vector const& testCases, IConfig const& config ) const {
- Matches matches;
- matches.reserve( m_filters.size() );
- for ( auto const& filter : m_filters ) {
- std::vector currentMatches;
- for ( auto const& test : testCases )
- if ( isThrowSafe( test, config ) &&
- filter.matches( test.getTestCaseInfo() ) )
- currentMatches.emplace_back( &test );
- matches.push_back(
- FilterMatch{ extractFilterName( filter ), currentMatches } );
- }
- return matches;
- }
-
- const TestSpec::vectorStrings& TestSpec::getInvalidSpecs() const {
- return m_invalidSpecs;
- }
-
- void TestSpec::serializeTo( std::ostream& out ) const {
- bool first = true;
- for ( auto const& filter : m_filters ) {
- if ( !first ) {
- out << ',';
- }
- out << filter;
- first = false;
- }
- }
-
-}
-
-
-
-#include
-
-namespace Catch {
-
- namespace {
- static auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
- return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count();
- }
- } // end unnamed namespace
-
- void Timer::start() {
- m_nanoseconds = getCurrentNanosecondsSinceEpoch();
- }
- auto Timer::getElapsedNanoseconds() const -> uint64_t {
- return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;
- }
- auto Timer::getElapsedMicroseconds() const -> uint64_t {
- return getElapsedNanoseconds()/1000;
- }
- auto Timer::getElapsedMilliseconds() const -> unsigned int {
- return static_cast(getElapsedMicroseconds()/1000);
- }
- auto Timer::getElapsedSeconds() const -> double {
- return static_cast(getElapsedMicroseconds())/1000000.0;
- }
-
-
-} // namespace Catch
-
-
-
-
-#include
-
-namespace Catch {
-
-namespace Detail {
-
- namespace {
- const int hexThreshold = 255;
-
- struct Endianness {
- enum Arch : uint8_t {
- Big,
- Little
- };
-
- static Arch which() {
- int one = 1;
- // If the lowest byte we read is non-zero, we can assume
- // that little endian format is used.
- auto value = *reinterpret_cast(&one);
- return value ? Little : Big;
- }
- };
-
- template
- std::string fpToString(T value, int precision) {
- if (Catch::isnan(value)) {
- return "nan";
- }
-
- ReusableStringStream rss;
- rss << std::setprecision(precision)
- << std::fixed
- << value;
- std::string d = rss.str();
- std::size_t i = d.find_last_not_of('0');
- if (i != std::string::npos && i != d.size() - 1) {
- if (d[i] == '.')
- i++;
- d = d.substr(0, i + 1);
- }
- return d;
- }
- } // end unnamed namespace
-
- std::string convertIntoString(StringRef string, bool escapeInvisibles) {
- std::string ret;
- // This is enough for the "don't escape invisibles" case, and a good
- // lower bound on the "escape invisibles" case.
- ret.reserve(string.size() + 2);
-
- if (!escapeInvisibles) {
- ret += '"';
- ret += string;
- ret += '"';
- return ret;
- }
-
- ret += '"';
- for (char c : string) {
- switch (c) {
- case '\r':
- ret.append("\\r");
- break;
- case '\n':
- ret.append("\\n");
- break;
- case '\t':
- ret.append("\\t");
- break;
- case '\f':
- ret.append("\\f");
- break;
- default:
- ret.push_back(c);
- break;
- }
- }
- ret += '"';
-
- return ret;
- }
-
- std::string convertIntoString(StringRef string) {
- return convertIntoString(string, getCurrentContext().getConfig()->showInvisibles());
- }
-
- std::string rawMemoryToString( const void *object, std::size_t size ) {
- // Reverse order for little endian architectures
- int i = 0, end = static_cast( size ), inc = 1;
- if( Endianness::which() == Endianness::Little ) {
- i = end-1;
- end = inc = -1;
- }
-
- unsigned char const *bytes = static_cast(object);
- ReusableStringStream rss;
- rss << "0x" << std::setfill('0') << std::hex;
- for( ; i != end; i += inc )
- rss << std::setw(2) << static_cast(bytes[i]);
- return rss.str();
- }
-
- std::string makeExceptionHappenedString() {
- return "{ stringification failed with an exception: \"" +
- translateActiveException() + "\" }";
-
- }
-
-} // end Detail namespace
-
-
-
-//// ======================================================= ////
-//
-// Out-of-line defs for full specialization of StringMaker
-//
-//// ======================================================= ////
-
-std::string StringMaker::convert(const std::string& str) {
- return Detail::convertIntoString( str );
-}
-
-#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
-std::string StringMaker::convert(std::string_view str) {
- return Detail::convertIntoString( StringRef( str.data(), str.size() ) );
-}
-#endif
-
-std::string StringMaker::convert(char const* str) {
- if (str) {
- return Detail::convertIntoString( str );
- } else {
- return{ "{null string}" };
- }
-}
-std::string StringMaker::convert(char* str) { // NOLINT(readability-non-const-parameter)
- if (str) {
- return Detail::convertIntoString( str );
- } else {
- return{ "{null string}" };
- }
-}
-
-#ifdef CATCH_CONFIG_WCHAR
-std::string StringMaker::convert(const std::wstring& wstr) {
- std::string s;
- s.reserve(wstr.size());
- for (auto c : wstr) {
- s += (c <= 0xff) ? static_cast(c) : '?';
- }
- return ::Catch::Detail::stringify(s);
-}
-
-# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
-std::string StringMaker::convert(std::wstring_view str) {
- return StringMaker::convert(std::wstring(str));
-}
-# endif
-
-std::string StringMaker::convert(wchar_t const * str) {
- if (str) {
- return ::Catch::Detail::stringify(std::wstring{ str });
- } else {
- return{ "{null string}" };
- }
-}
-std::string StringMaker::convert(wchar_t * str) {
- if (str) {
- return ::Catch::Detail::stringify(std::wstring{ str });
- } else {
- return{ "{null string}" };
- }
-}
-#endif
-
-#if defined(CATCH_CONFIG_CPP17_BYTE)
-#include
-std::string StringMaker::convert(std::byte value) {
- return ::Catch::Detail::stringify(std::to_integer(value));
-}
-#endif // defined(CATCH_CONFIG_CPP17_BYTE)
-
-std::string StringMaker::convert(int value) {
- return ::Catch::Detail::stringify(static_cast(value));
-}
-std::string StringMaker::convert(long value) {
- return ::Catch::Detail::stringify(static_cast(value));
-}
-std::string StringMaker::convert(long long value) {
- ReusableStringStream rss;
- rss << value;
- if (value > Detail::hexThreshold) {
- rss << " (0x" << std::hex << value << ')';
- }
- return rss.str();
-}
-
-std::string StringMaker::convert(unsigned int value) {
- return ::Catch::Detail::stringify(static_cast(value));
-}
-std::string StringMaker::convert(unsigned long value) {
- return ::Catch::Detail::stringify(static_cast(value));
-}
-std::string StringMaker::convert(unsigned long long value) {
- ReusableStringStream rss;
- rss << value;
- if (value > Detail::hexThreshold) {
- rss << " (0x" << std::hex << value << ')';
- }
- return rss.str();
-}
-
-std::string StringMaker::convert(signed char value) {
- if (value == '\r') {
- return "'\\r'";
- } else if (value == '\f') {
- return "'\\f'";
- } else if (value == '\n') {
- return "'\\n'";
- } else if (value == '\t') {
- return "'\\t'";
- } else if ('\0' <= value && value < ' ') {
- return ::Catch::Detail::stringify(static_cast(value));
- } else {
- char chstr[] = "' '";
- chstr[1] = value;
- return chstr;
- }
-}
-std::string StringMaker::convert(char c) {
- return ::Catch::Detail::stringify(static_cast(c));
-}
-std::string StringMaker::convert(unsigned char value) {
- return ::Catch::Detail::stringify(static_cast(value));
-}
-
-int StringMaker::precision = std::numeric_limits::max_digits10;
-
-std::string StringMaker::convert(float value) {
- return Detail::fpToString(value, precision) + 'f';
-}
-
-int StringMaker::precision = std::numeric_limits::max_digits10;
-
-std::string StringMaker::convert(double value) {
- return Detail::fpToString(value, precision);
-}
-
-} // end namespace Catch
-
-
-
-namespace Catch {
-
- Counts Counts::operator - ( Counts const& other ) const {
- Counts diff;
- diff.passed = passed - other.passed;
- diff.failed = failed - other.failed;
- diff.failedButOk = failedButOk - other.failedButOk;
- diff.skipped = skipped - other.skipped;
- return diff;
- }
-
- Counts& Counts::operator += ( Counts const& other ) {
- passed += other.passed;
- failed += other.failed;
- failedButOk += other.failedButOk;
- skipped += other.skipped;
- return *this;
- }
-
- std::uint64_t Counts::total() const {
- return passed + failed + failedButOk + skipped;
- }
- bool Counts::allPassed() const {
- return failed == 0 && failedButOk == 0 && skipped == 0;
- }
- bool Counts::allOk() const {
- return failed == 0;
- }
-
- Totals Totals::operator - ( Totals const& other ) const {
- Totals diff;
- diff.assertions = assertions - other.assertions;
- diff.testCases = testCases - other.testCases;
- return diff;
- }
-
- Totals& Totals::operator += ( Totals const& other ) {
- assertions += other.assertions;
- testCases += other.testCases;
- return *this;
- }
-
- Totals Totals::delta( Totals const& prevTotals ) const {
- Totals diff = *this - prevTotals;
- if( diff.assertions.failed > 0 )
- ++diff.testCases.failed;
- else if( diff.assertions.failedButOk > 0 )
- ++diff.testCases.failedButOk;
- else if ( diff.assertions.skipped > 0 )
- ++ diff.testCases.skipped;
- else
- ++diff.testCases.passed;
- return diff;
- }
-
-}
-
-
-
-
-namespace Catch {
- namespace Detail {
- void registerTranslatorImpl(
- Detail::unique_ptr&& translator ) {
- getMutableRegistryHub().registerTranslator(
- CATCH_MOVE( translator ) );
- }
- } // namespace Detail
-} // namespace Catch
-
-
-#include
-
-namespace Catch {
-
- Version::Version
- ( unsigned int _majorVersion,
- unsigned int _minorVersion,
- unsigned int _patchNumber,
- char const * const _branchName,
- unsigned int _buildNumber )
- : majorVersion( _majorVersion ),
- minorVersion( _minorVersion ),
- patchNumber( _patchNumber ),
- branchName( _branchName ),
- buildNumber( _buildNumber )
- {}
-
- std::ostream& operator << ( std::ostream& os, Version const& version ) {
- os << version.majorVersion << '.'
- << version.minorVersion << '.'
- << version.patchNumber;
- // branchName is never null -> 0th char is \0 if it is empty
- if (version.branchName[0]) {
- os << '-' << version.branchName
- << '.' << version.buildNumber;
- }
- return os;
- }
-
- Version const& libraryVersion() {
- static Version version( 3, 10, 0, "", 0 );
- return version;
- }
-
-}
-
-
-
-
-namespace Catch {
-
- const char* GeneratorException::what() const noexcept {
- return m_msg;
- }
-
-} // end namespace Catch
-
-
-
-
-namespace Catch {
-
- IGeneratorTracker::~IGeneratorTracker() = default;
-
-namespace Generators {
-
-namespace Detail {
-
- [[noreturn]]
- void throw_generator_exception(char const* msg) {
- Catch::throw_exception(GeneratorException{ msg });
- }
-} // end namespace Detail
-
- GeneratorUntypedBase::~GeneratorUntypedBase() = default;
-
- IGeneratorTracker* acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) {
- return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
- }
-
- IGeneratorTracker* createGeneratorTracker( StringRef generatorName,
- SourceLineInfo lineInfo,
- GeneratorBasePtr&& generator ) {
- return getResultCapture().createGeneratorTracker(
- generatorName, lineInfo, CATCH_MOVE( generator ) );
- }
-
-} // namespace Generators
-} // namespace Catch
-
-
-
-
-#include
-
-namespace Catch {
- namespace Generators {
- namespace Detail {
- std::uint32_t getSeed() { return sharedRng()(); }
- } // namespace Detail
-
- struct RandomFloatingGenerator::PImpl {
- PImpl( long double a, long double b, uint32_t seed ):
- rng( seed ), dist( a, b ) {}
-
- Catch::SimplePcg32 rng;
- std::uniform_real_distribution dist;
- };
-
- RandomFloatingGenerator::RandomFloatingGenerator(
- long double a, long double b, std::uint32_t seed) :
- m_pimpl(Catch::Detail::make_unique(a, b, seed)) {
- static_cast( next() );
- }
-
- RandomFloatingGenerator::~RandomFloatingGenerator() =
- default;
- bool RandomFloatingGenerator::next() {
- m_current_number = m_pimpl->dist( m_pimpl->rng );
- return true;
- }
- } // namespace Generators
-} // namespace Catch
-
-
-
-
-namespace Catch {
- IResultCapture::~IResultCapture() = default;
-}
-
-
-
-
-namespace Catch {
- IConfig::~IConfig() = default;
-}
-
-
-
-
-namespace Catch {
- IExceptionTranslator::~IExceptionTranslator() = default;
- IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;
-}
-
-
-
-#include
-
-namespace Catch {
- namespace Generators {
-
- bool GeneratorUntypedBase::countedNext() {
- auto ret = next();
- if ( ret ) {
- m_stringReprCache.clear();
- ++m_currentElementIndex;
- }
- return ret;
- }
-
- StringRef GeneratorUntypedBase::currentElementAsString() const {
- if ( m_stringReprCache.empty() ) {
- m_stringReprCache = stringifyImpl();
- }
- return m_stringReprCache;
- }
-
- } // namespace Generators
-} // namespace Catch
-
-
-
-
-namespace Catch {
- IRegistryHub::~IRegistryHub() = default;
- IMutableRegistryHub::~IMutableRegistryHub() = default;
-}
-
-
-
-#include
-
-namespace Catch {
-
- ReporterConfig::ReporterConfig(
- IConfig const* _fullConfig,
- Detail::unique_ptr _stream,
- ColourMode colourMode,
- std::map customOptions ):
- m_stream( CATCH_MOVE(_stream) ),
- m_fullConfig( _fullConfig ),
- m_colourMode( colourMode ),
- m_customOptions( CATCH_MOVE( customOptions ) ) {}
-
- Detail::unique_ptr ReporterConfig::takeStream() && {
- assert( m_stream );
- return CATCH_MOVE( m_stream );
- }
- IConfig const * ReporterConfig::fullConfig() const { return m_fullConfig; }
- ColourMode ReporterConfig::colourMode() const { return m_colourMode; }
-
- std::map const&
- ReporterConfig::customOptions() const {
- return m_customOptions;
- }
-
- ReporterConfig::~ReporterConfig() = default;
-
- AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
- std::vector const& _infoMessages,
- Totals const& _totals )
- : assertionResult( _assertionResult ),
- infoMessages( _infoMessages ),
- totals( _totals )
- {
- if( assertionResult.hasMessage() ) {
- // Copy message into messages list.
- // !TBD This should have been done earlier, somewhere
- MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
- builder.m_info.message = static_cast(assertionResult.getMessage());
-
- infoMessages.push_back( CATCH_MOVE(builder.m_info) );
- }
- }
-
- SectionStats::SectionStats( SectionInfo&& _sectionInfo,
- Counts const& _assertions,
- double _durationInSeconds,
- bool _missingAssertions )
- : sectionInfo( CATCH_MOVE(_sectionInfo) ),
- assertions( _assertions ),
- durationInSeconds( _durationInSeconds ),
- missingAssertions( _missingAssertions )
- {}
-
-
- TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
- Totals const& _totals,
- std::string&& _stdOut,
- std::string&& _stdErr,
- bool _aborting )
- : testInfo( &_testInfo ),
- totals( _totals ),
- stdOut( CATCH_MOVE(_stdOut) ),
- stdErr( CATCH_MOVE(_stdErr) ),
- aborting( _aborting )
- {}
-
-
- TestRunStats::TestRunStats( TestRunInfo const& _runInfo,
- Totals const& _totals,
- bool _aborting )
- : runInfo( _runInfo ),
- totals( _totals ),
- aborting( _aborting )
- {}
-
- IEventListener::~IEventListener() = default;
-
-} // end namespace Catch
-
-
-
-
-namespace Catch {
- IReporterFactory::~IReporterFactory() = default;
- EventListenerFactory::~EventListenerFactory() = default;
-}
-
-
-
-
-namespace Catch {
- ITestCaseRegistry::~ITestCaseRegistry() = default;
-}
-
-
-
-namespace Catch {
-
- AssertionHandler::AssertionHandler
- ( StringRef macroName,
- SourceLineInfo const& lineInfo,
- StringRef capturedExpression,
- ResultDisposition::Flags resultDisposition )
- : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
- m_resultCapture( getResultCapture() )
- {
- m_resultCapture.notifyAssertionStarted( m_assertionInfo );
- }
-
- void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
- m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
- }
- void AssertionHandler::handleMessage(ResultWas::OfType resultType, std::string&& message) {
- m_resultCapture.handleMessage( m_assertionInfo, resultType, CATCH_MOVE(message), m_reaction );
- }
-
- auto AssertionHandler::allowThrows() const -> bool {
- return getCurrentContext().getConfig()->allowThrows();
- }
-
- void AssertionHandler::complete() {
- m_completed = true;
- if( m_reaction.shouldDebugBreak ) {
-
- // If you find your debugger stopping you here then go one level up on the
- // call-stack for the code that caused it (typically a failed assertion)
-
- // (To go back to the test and change execution, jump over the throw, next)
- CATCH_BREAK_INTO_DEBUGGER();
- }
- if (m_reaction.shouldThrow) {
- throw_test_failure_exception();
- }
- if ( m_reaction.shouldSkip ) {
- throw_test_skip_exception();
- }
- }
-
- void AssertionHandler::handleUnexpectedInflightException() {
- m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
- }
-
- void AssertionHandler::handleExceptionThrownAsExpected() {
- m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
- }
- void AssertionHandler::handleExceptionNotThrownAsExpected() {
- m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
- }
-
- void AssertionHandler::handleUnexpectedExceptionNotThrown() {
- m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
- }
-
- void AssertionHandler::handleThrowingCallSkipped() {
- m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
- }
-
- // This is the overload that takes a string and infers the Equals matcher from it
- // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
- void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str ) {
- handleExceptionMatchExpr( handler, Matchers::Equals( str ) );
- }
-
-} // namespace Catch
-
-
-
-
-#include
-
-namespace Catch {
- namespace Detail {
-
- bool CaseInsensitiveLess::operator()( StringRef lhs,
- StringRef rhs ) const {
- return std::lexicographical_compare(
- lhs.begin(), lhs.end(),
- rhs.begin(), rhs.end(),
- []( char l, char r ) { return toLower( l ) < toLower( r ); } );
- }
-
- bool
- CaseInsensitiveEqualTo::operator()( StringRef lhs,
- StringRef rhs ) const {
- return std::equal(
- lhs.begin(), lhs.end(),
- rhs.begin(), rhs.end(),
- []( char l, char r ) { return toLower( l ) == toLower( r ); } );
- }
-
- } // namespace Detail
-} // namespace Catch
-
-
-
-
-#include
-#include
-
-namespace {
- bool isOptPrefix( char c ) {
- return c == '-'
-#ifdef CATCH_PLATFORM_WINDOWS
- || c == '/'
-#endif
- ;
- }
-
- Catch::StringRef normaliseOpt( Catch::StringRef optName ) {
- if ( optName[0] == '-'
-#if defined(CATCH_PLATFORM_WINDOWS)
- || optName[0] == '/'
-#endif
- ) {
- return optName.substr( 1, optName.size() );
- }
-
- return optName;
- }
-
- static size_t find_first_separator(Catch::StringRef sr) {
- auto is_separator = []( char c ) {
- return c == ' ' || c == ':' || c == '=';
- };
- size_t pos = 0;
- while (pos < sr.size()) {
- if (is_separator(sr[pos])) { return pos; }
- ++pos;
- }
-
- return Catch::StringRef::npos;
- }
-
-} // namespace
-
-namespace Catch {
- namespace Clara {
- namespace Detail {
-
- void TokenStream::loadBuffer() {
- m_tokenBuffer.clear();
-
- // Skip any empty strings
- while ( it != itEnd && it->empty() ) {
- ++it;
- }
-
- if ( it != itEnd ) {
- StringRef next = *it;
- if ( isOptPrefix( next[0] ) ) {
- auto delimiterPos = find_first_separator(next);
- if ( delimiterPos != StringRef::npos ) {
- m_tokenBuffer.push_back(
- { TokenType::Option,
- next.substr( 0, delimiterPos ) } );
- m_tokenBuffer.push_back(
- { TokenType::Argument,
- next.substr( delimiterPos + 1, next.size() ) } );
- } else {
- if ( next.size() > 1 && next[1] != '-' && next.size() > 2 ) {
- // Combined short args, e.g. "-ab" for "-a -b"
- for ( size_t i = 1; i < next.size(); ++i ) {
- m_tokenBuffer.push_back(
- { TokenType::Option,
- next.substr( i, 1 ) } );
- }
- } else {
- m_tokenBuffer.push_back(
- { TokenType::Option, next } );
- }
- }
- } else {
- m_tokenBuffer.push_back(
- { TokenType::Argument, next } );
- }
- }
- }
-
- TokenStream::TokenStream( Args const& args ):
- TokenStream( args.m_args.begin(), args.m_args.end() ) {}
-
- TokenStream::TokenStream( Iterator it_, Iterator itEnd_ ):
- it( it_ ), itEnd( itEnd_ ) {
- loadBuffer();
- }
-
- TokenStream& TokenStream::operator++() {
- if ( m_tokenBuffer.size() >= 2 ) {
- m_tokenBuffer.erase( m_tokenBuffer.begin() );
- } else {
- if ( it != itEnd )
- ++it;
- loadBuffer();
- }
- return *this;
- }
-
- ParserResult convertInto( std::string const& source,
- std::string& target ) {
- target = source;
- return ParserResult::ok( ParseResultType::Matched );
- }
-
- ParserResult convertInto( std::string const& source,
- bool& target ) {
- std::string srcLC = toLower( source );
-
- if ( srcLC == "y" || srcLC == "1" || srcLC == "true" ||
- srcLC == "yes" || srcLC == "on" ) {
- target = true;
- } else if ( srcLC == "n" || srcLC == "0" || srcLC == "false" ||
- srcLC == "no" || srcLC == "off" ) {
- target = false;
- } else {
- return ParserResult::runtimeError(
- "Expected a boolean value but did not recognise: '" +
- source + '\'' );
- }
- return ParserResult::ok( ParseResultType::Matched );
- }
-
- size_t ParserBase::cardinality() const { return 1; }
-
- InternalParseResult ParserBase::parse( Args const& args ) const {
- return parse( static_cast(args.exeName()), TokenStream( args ) );
- }
-
- ParseState::ParseState( ParseResultType type,
- TokenStream remainingTokens ):
- m_type( type ), m_remainingTokens( CATCH_MOVE(remainingTokens) ) {}
-
- ParserResult BoundFlagRef::setFlag( bool flag ) {
- m_ref = flag;
- return ParserResult::ok( ParseResultType::Matched );
- }
-
- ResultBase::~ResultBase() = default;
-
- bool BoundRef::isContainer() const { return false; }
-
- bool BoundRef::isFlag() const { return false; }
-
- bool BoundFlagRefBase::isFlag() const { return true; }
-
-} // namespace Detail
-
- Detail::InternalParseResult Arg::parse(std::string const&,
- Detail::TokenStream tokens) const {
- auto validationResult = validate();
- if (!validationResult)
- return Detail::InternalParseResult(validationResult);
-
- auto token = *tokens;
- if (token.type != Detail::TokenType::Argument)
- return Detail::InternalParseResult::ok(Detail::ParseState(
- ParseResultType::NoMatch, CATCH_MOVE(tokens)));
-
- assert(!m_ref->isFlag());
- auto valueRef =
- static_cast(m_ref.get());
-
- auto result = valueRef->setValue(static_cast(token.token));
- if ( !result )
- return Detail::InternalParseResult( result );
- else
- return Detail::InternalParseResult::ok(
- Detail::ParseState( ParseResultType::Matched,
- CATCH_MOVE( ++tokens ) ) );
- }
-
- Opt::Opt(bool& ref) :
- ParserRefImpl(std::make_shared(ref)) {}
-
- Detail::HelpColumns Opt::getHelpColumns() const {
- ReusableStringStream oss;
- bool first = true;
- for (auto const& opt : m_optNames) {
- if (first)
- first = false;
- else
- oss << ", ";
- oss << opt;
- }
- if (!m_hint.empty())
- oss << " <" << m_hint << '>';
- return { oss.str(), m_description };
- }
-
- bool Opt::isMatch(StringRef optToken) const {
- auto normalisedToken = normaliseOpt(optToken);
- for (auto const& name : m_optNames) {
- if (normaliseOpt(name) == normalisedToken)
- return true;
- }
- return false;
- }
-
- Detail::InternalParseResult Opt::parse(std::string const&,
- Detail::TokenStream tokens) const {
- auto validationResult = validate();
- if (!validationResult)
- return Detail::InternalParseResult(validationResult);
-
- if (tokens &&
- tokens->type == Detail::TokenType::Option) {
- auto const& token = *tokens;
- if (isMatch(token.token)) {
- if (m_ref->isFlag()) {
- auto flagRef =
- static_cast(
- m_ref.get());
- auto result = flagRef->setFlag(true);
- if (!result)
- return Detail::InternalParseResult(result);
- if (result.value() ==
- ParseResultType::ShortCircuitAll)
- return Detail::InternalParseResult::ok(Detail::ParseState(
- result.value(), CATCH_MOVE(tokens)));
- } else {
- auto valueRef =
- static_cast(
- m_ref.get());
- ++tokens;
- if (!tokens)
- return Detail::InternalParseResult::runtimeError(
- "Expected argument following " +
- token.token);
- auto const& argToken = *tokens;
- if (argToken.type != Detail::TokenType::Argument)
- return Detail::InternalParseResult::runtimeError(
- "Expected argument following " +
- token.token);
- const auto result = valueRef->setValue(static_cast(argToken.token));
- if (!result)
- return Detail::InternalParseResult(result);
- if (result.value() ==
- ParseResultType::ShortCircuitAll)
- return Detail::InternalParseResult::ok(Detail::ParseState(
- result.value(), CATCH_MOVE(tokens)));
- }
- return Detail::InternalParseResult::ok(Detail::ParseState(
- ParseResultType::Matched, CATCH_MOVE(++tokens)));
- }
- }
- return Detail::InternalParseResult::ok(
- Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(tokens)));
- }
-
- Detail::Result Opt::validate() const {
- if (m_optNames.empty())
- return Detail::Result::logicError("No options supplied to Opt");
- for (auto const& name : m_optNames) {
- if (name.empty())
- return Detail::Result::logicError(
- "Option name cannot be empty");
-#ifdef CATCH_PLATFORM_WINDOWS
- if (name[0] != '-' && name[0] != '/')
- return Detail::Result::logicError(
- "Option name must begin with '-' or '/'");
-#else
- if (name[0] != '-')
- return Detail::Result::logicError(
- "Option name must begin with '-'");
-#endif
- }
- return ParserRefImpl::validate();
- }
-
- ExeName::ExeName() :
- m_name(std::make_shared("")) {}
-
- ExeName::ExeName(std::string& ref) : ExeName() {
- m_ref = std::make_shared>(ref);
- }
-
- Detail::InternalParseResult
- ExeName::parse(std::string const&,
- Detail::TokenStream tokens) const {
- return Detail::InternalParseResult::ok(
- Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(tokens)));
- }
-
- ParserResult ExeName::set(std::string const& newName) {
- auto lastSlash = newName.find_last_of("\\/");
- auto filename = (lastSlash == std::string::npos)
- ? newName
- : newName.substr(lastSlash + 1);
-
- *m_name = filename;
- if (m_ref)
- return m_ref->setValue(filename);
- else
- return ParserResult::ok(ParseResultType::Matched);
- }
-
-
-
-
- Parser& Parser::operator|=( Parser const& other ) {
- m_options.insert( m_options.end(),
- other.m_options.begin(),
- other.m_options.end() );
- m_args.insert(
- m_args.end(), other.m_args.begin(), other.m_args.end() );
- return *this;
- }
-
- std::vector Parser::getHelpColumns() const {
- std::vector cols;
- cols.reserve( m_options.size() );
- for ( auto const& o : m_options ) {
- cols.push_back(o.getHelpColumns());
- }
- return cols;
- }
-
- void Parser::writeToStream( std::ostream& os ) const {
- if ( !m_exeName.name().empty() ) {
- os << "usage:\n"
- << " " << m_exeName.name() << ' ';
- bool required = true, first = true;
- for ( auto const& arg : m_args ) {
- if ( first )
- first = false;
- else
- os << ' ';
- if ( arg.isOptional() && required ) {
- os << '[';
- required = false;
- }
- os << '<' << arg.hint() << '>';
- if ( arg.cardinality() == 0 )
- os << " ... ";
- }
- if ( !required )
- os << ']';
- if ( !m_options.empty() )
- os << " options";
- os << "\n\nwhere options are:\n";
- }
-
- auto rows = getHelpColumns();
- size_t consoleWidth = CATCH_CONFIG_CONSOLE_WIDTH;
- size_t optWidth = 0;
- for ( auto const& cols : rows )
- optWidth = ( std::max )( optWidth, cols.left.size() + 2 );
-
- optWidth = ( std::min )( optWidth, consoleWidth / 2 );
-
- for ( auto& cols : rows ) {
- auto row = TextFlow::Column( CATCH_MOVE(cols.left) )
- .width( optWidth )
- .indent( 2 ) +
- TextFlow::Spacer( 4 ) +
- TextFlow::Column( static_cast(cols.descriptions) )
- .width( consoleWidth - 7 - optWidth );
- os << row << '\n';
- }
- }
-
- Detail::Result Parser::validate() const {
- for ( auto const& opt : m_options ) {
- auto result = opt.validate();
- if ( !result )
- return result;
- }
- for ( auto const& arg : m_args ) {
- auto result = arg.validate();
- if ( !result )
- return result;
- }
- return Detail::Result::ok();
- }
-
- Detail::InternalParseResult
- Parser::parse( std::string const& exeName,
- Detail::TokenStream tokens ) const {
-
- struct ParserInfo {
- ParserBase const* parser = nullptr;
- size_t count = 0;
- };
- std::vector parseInfos;
- parseInfos.reserve( m_options.size() + m_args.size() );
- for ( auto const& opt : m_options ) {
- parseInfos.push_back( { &opt, 0 } );
- }
- for ( auto const& arg : m_args ) {
- parseInfos.push_back( { &arg, 0 } );
- }
-
- m_exeName.set( exeName );
-
- auto result = Detail::InternalParseResult::ok(
- Detail::ParseState( ParseResultType::NoMatch, CATCH_MOVE(tokens) ) );
- while ( result.value().remainingTokens() ) {
- bool tokenParsed = false;
-
- for ( auto& parseInfo : parseInfos ) {
- if ( parseInfo.parser->cardinality() == 0 ||
- parseInfo.count < parseInfo.parser->cardinality() ) {
- result = parseInfo.parser->parse(
- exeName, CATCH_MOVE(result).value().remainingTokens() );
- if ( !result )
- return result;
- if ( result.value().type() !=
- ParseResultType::NoMatch ) {
- tokenParsed = true;
- ++parseInfo.count;
- break;
- }
- }
- }
-
- if ( result.value().type() == ParseResultType::ShortCircuitAll )
- return result;
- if ( !tokenParsed )
- return Detail::InternalParseResult::runtimeError(
- "Unrecognised token: " +
- result.value().remainingTokens()->token );
- }
- // !TBD Check missing required options
- return result;
- }
-
- Args::Args(int argc, char const* const* argv) :
- m_exeName(argv[0]), m_args(argv + 1, argv + argc) {}
-
- Args::Args(std::initializer_list args) :
- m_exeName(*args.begin()),
- m_args(args.begin() + 1, args.end()) {}
-
-
- Help::Help( bool& showHelpFlag ):
- Opt( [&]( bool flag ) {
- showHelpFlag = flag;
- return ParserResult::ok( ParseResultType::ShortCircuitAll );
- } ) {
- static_cast ( *this )(
- "display usage information" )["-?"]["-h"]["--help"]
- .optional();
- }
-
- } // namespace Clara
-} // namespace Catch
-
-
-
-
-#include
-#include
-
-namespace Catch {
-
- Clara::Parser makeCommandLineParser( ConfigData& config ) {
-
- using namespace Clara;
-
- auto const setWarning = [&]( std::string const& warning ) {
- if ( warning == "NoAssertions" ) {
- config.warnings = static_cast(config.warnings | WarnAbout::NoAssertions);
- return ParserResult::ok( ParseResultType::Matched );
- } else if ( warning == "UnmatchedTestSpec" ) {
- config.warnings = static_cast(config.warnings | WarnAbout::UnmatchedTestSpec);
- return ParserResult::ok( ParseResultType::Matched );
- }
-
- return ParserResult ::runtimeError(
- "Unrecognised warning option: '" + warning + '\'' );
- };
- auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
- std::ifstream f( filename.c_str() );
- if( !f.is_open() )
- return ParserResult::runtimeError( "Unable to load input file: '" + filename + '\'' );
-
- std::string line;
- while( std::getline( f, line ) ) {
- line = trim(line);
- if( !line.empty() && !startsWith( line, '#' ) ) {
- if( !startsWith( line, '"' ) )
- line = '"' + CATCH_MOVE(line) + '"';
- config.testsOrTags.push_back( line );
- config.testsOrTags.emplace_back( "," );
- }
- }
- //Remove comma in the end
- if(!config.testsOrTags.empty())
- config.testsOrTags.erase( config.testsOrTags.end()-1 );
-
- return ParserResult::ok( ParseResultType::Matched );
- };
- auto const setTestOrder = [&]( std::string const& order ) {
- if( startsWith( "declared", order ) )
- config.runOrder = TestRunOrder::Declared;
- else if( startsWith( "lexical", order ) )
- config.runOrder = TestRunOrder::LexicographicallySorted;
- else if( startsWith( "random", order ) )
- config.runOrder = TestRunOrder::Randomized;
- else
- return ParserResult::runtimeError( "Unrecognised ordering: '" + order + '\'' );
- return ParserResult::ok( ParseResultType::Matched );
- };
- auto const setRngSeed = [&]( std::string const& seed ) {
- if( seed == "time" ) {
- config.rngSeed = generateRandomSeed(GenerateFrom::Time);
- return ParserResult::ok(ParseResultType::Matched);
- } else if (seed == "random-device") {
- config.rngSeed = generateRandomSeed(GenerateFrom::RandomDevice);
- return ParserResult::ok(ParseResultType::Matched);
- }
-
- // TODO: ideally we should be parsing uint32_t directly
- // fix this later when we add new parse overload
- auto parsedSeed = parseUInt( seed, 0 );
- if ( !parsedSeed ) {
- return ParserResult::runtimeError( "Could not parse '" + seed + "' as seed" );
- }
- config.rngSeed = *parsedSeed;
- return ParserResult::ok( ParseResultType::Matched );
- };
- auto const setDefaultColourMode = [&]( std::string const& colourMode ) {
- Optional maybeMode = Catch::Detail::stringToColourMode(toLower( colourMode ));
- if ( !maybeMode ) {
- return ParserResult::runtimeError(
- "colour mode must be one of: default, ansi, win32, "
- "or none. '" +
- colourMode + "' is not recognised" );
- }
- auto mode = *maybeMode;
- if ( !isColourImplAvailable( mode ) ) {
- return ParserResult::runtimeError(
- "colour mode '" + colourMode +
- "' is not supported in this binary" );
- }
- config.defaultColourMode = mode;
- return ParserResult::ok( ParseResultType::Matched );
- };
- auto const setWaitForKeypress = [&]( std::string const& keypress ) {
- auto keypressLc = toLower( keypress );
- if (keypressLc == "never")
- config.waitForKeypress = WaitForKeypress::Never;
- else if( keypressLc == "start" )
- config.waitForKeypress = WaitForKeypress::BeforeStart;
- else if( keypressLc == "exit" )
- config.waitForKeypress = WaitForKeypress::BeforeExit;
- else if( keypressLc == "both" )
- config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
- else
- return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" );
- return ParserResult::ok( ParseResultType::Matched );
- };
- auto const setVerbosity = [&]( std::string const& verbosity ) {
- auto lcVerbosity = toLower( verbosity );
- if( lcVerbosity == "quiet" )
- config.verbosity = Verbosity::Quiet;
- else if( lcVerbosity == "normal" )
- config.verbosity = Verbosity::Normal;
- else if( lcVerbosity == "high" )
- config.verbosity = Verbosity::High;
- else
- return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + '\'' );
- return ParserResult::ok( ParseResultType::Matched );
- };
- auto const setReporter = [&]( std::string const& userReporterSpec ) {
- if ( userReporterSpec.empty() ) {
- return ParserResult::runtimeError( "Received empty reporter spec." );
- }
-
- Optional parsed =
- parseReporterSpec( userReporterSpec );
- if ( !parsed ) {
- return ParserResult::runtimeError(
- "Could not parse reporter spec '" + userReporterSpec +
- "'" );
- }
-
- auto const& reporterSpec = *parsed;
-
- auto const& factories =
- getRegistryHub().getReporterRegistry().getFactories();
- auto result = factories.find( reporterSpec.name() );
-
- if ( result == factories.end() ) {
- return ParserResult::runtimeError(
- "Unrecognized reporter, '" + reporterSpec.name() +
- "'. Check available with --list-reporters" );
- }
-
-
- const bool hadOutputFile = reporterSpec.outputFile().some();
- config.reporterSpecifications.push_back( CATCH_MOVE( *parsed ) );
- // It would be enough to check this only once at the very end, but
- // there is not a place where we could call this check, so do it
- // every time it could fail. For valid inputs, this is still called
- // at most once.
- if (!hadOutputFile) {
- int n_reporters_without_file = 0;
- for (auto const& spec : config.reporterSpecifications) {
- if (spec.outputFile().none()) {
- n_reporters_without_file++;
- }
- }
- if (n_reporters_without_file > 1) {
- return ParserResult::runtimeError( "Only one reporter may have unspecified output file." );
- }
- }
-
- return ParserResult::ok( ParseResultType::Matched );
- };
- auto const setShardCount = [&]( std::string const& shardCount ) {
- auto parsedCount = parseUInt( shardCount );
- if ( !parsedCount ) {
- return ParserResult::runtimeError(
- "Could not parse '" + shardCount + "' as shard count" );
- }
- if ( *parsedCount == 0 ) {
- return ParserResult::runtimeError(
- "Shard count must be positive" );
- }
- config.shardCount = *parsedCount;
- return ParserResult::ok( ParseResultType::Matched );
- };
-
- auto const setShardIndex = [&](std::string const& shardIndex) {
- auto parsedIndex = parseUInt( shardIndex );
- if ( !parsedIndex ) {
- return ParserResult::runtimeError(
- "Could not parse '" + shardIndex + "' as shard index" );
- }
- config.shardIndex = *parsedIndex;
- return ParserResult::ok( ParseResultType::Matched );
- };
-
- auto cli
- = ExeName( config.processName )
- | Help( config.showHelp )
- | Opt( config.showSuccessfulTests )
- ["-s"]["--success"]
- ( "include successful tests in output" )
- | Opt( config.shouldDebugBreak )
- ["-b"]["--break"]
- ( "break into debugger on failure" )
- | Opt( config.noThrow )
- ["-e"]["--nothrow"]
- ( "skip exception tests" )
- | Opt( config.showInvisibles )
- ["-i"]["--invisibles"]
- ( "show invisibles (tabs, newlines)" )
- | Opt( config.defaultOutputFilename, "filename" )
- ["-o"]["--out"]
- ( "default output filename" )
- | Opt( accept_many, setReporter, "name[::key=value]*" )
- ["-r"]["--reporter"]
- ( "reporter to use (defaults to console)" )
- | Opt( config.name, "name" )
- ["-n"]["--name"]
- ( "suite name" )
- | Opt( [&]( bool ){ config.abortAfter = 1; } )
- ["-a"]["--abort"]
- ( "abort at first failure" )
- | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )
- ["-x"]["--abortx"]
- ( "abort after x failures" )
- | Opt( accept_many, setWarning, "warning name" )
- ["-w"]["--warn"]
- ( "enable warnings" )
- | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
- ["-d"]["--durations"]
- ( "show test durations" )
- | Opt( config.minDuration, "seconds" )
- ["-D"]["--min-duration"]
- ( "show test durations for tests taking at least the given number of seconds" )
- | Opt( loadTestNamesFromFile, "filename" )
- ["-f"]["--input-file"]
- ( "load test names to run from a file" )
- | Opt( config.filenamesAsTags )
- ["-#"]["--filenames-as-tags"]
- ( "adds a tag for the filename" )
- | Opt( config.sectionsToRun, "section name" )
- ["-c"]["--section"]
- ( "specify section to run" )
- | Opt( setVerbosity, "quiet|normal|high" )
- ["-v"]["--verbosity"]
- ( "set output verbosity" )
- | Opt( config.listTests )
- ["--list-tests"]
- ( "list all/matching test cases" )
- | Opt( config.listTags )
- ["--list-tags"]
- ( "list all/matching tags" )
- | Opt( config.listReporters )
- ["--list-reporters"]
- ( "list all available reporters" )
- | Opt( config.listListeners )
- ["--list-listeners"]
- ( "list all listeners" )
- | Opt( setTestOrder, "decl|lex|rand" )
- ["--order"]
- ( "test case order (defaults to decl)" )
- | Opt( setRngSeed, "'time'|'random-device'|number" )
- ["--rng-seed"]
- ( "set a specific seed for random numbers" )
- | Opt( setDefaultColourMode, "ansi|win32|none|default" )
- ["--colour-mode"]
- ( "what color mode should be used as default" )
- | Opt( config.libIdentify )
- ["--libidentify"]
- ( "report name and version according to libidentify standard" )
- | Opt( setWaitForKeypress, "never|start|exit|both" )
- ["--wait-for-keypress"]
- ( "waits for a keypress before exiting" )
- | Opt( config.skipBenchmarks)
- ["--skip-benchmarks"]
- ( "disable running benchmarks")
- | Opt( config.benchmarkSamples, "samples" )
- ["--benchmark-samples"]
- ( "number of samples to collect (default: 100)" )
- | Opt( config.benchmarkResamples, "resamples" )
- ["--benchmark-resamples"]
- ( "number of resamples for the bootstrap (default: 100000)" )
- | Opt( config.benchmarkConfidenceInterval, "confidence interval" )
- ["--benchmark-confidence-interval"]
- ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" )
- | Opt( config.benchmarkNoAnalysis )
- ["--benchmark-no-analysis"]
- ( "perform only measurements; do not perform any analysis" )
- | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" )
- ["--benchmark-warmup-time"]
- ( "amount of time in milliseconds spent on warming up each test (default: 100)" )
- | Opt( setShardCount, "shard count" )
- ["--shard-count"]
- ( "split the tests to execute into this many groups" )
- | Opt( setShardIndex, "shard index" )
- ["--shard-index"]
- ( "index of the group of tests to execute (see --shard-count)" )
- | Opt( config.allowZeroTests )
- ["--allow-running-no-tests"]
- ( "Treat 'No tests run' as a success" )
- | Arg( config.testsOrTags, "test name|pattern|tags" )
- ( "which test or tests to use" );
-
- return cli;
- }
-
-} // end namespace Catch
-
-
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wexit-time-destructors"
-#endif
-
-
-
-#include
-#include
-#include
-
-namespace Catch {
-
- ColourImpl::~ColourImpl() = default;
-
- ColourImpl::ColourGuard ColourImpl::guardColour( Colour::Code colourCode ) {
- return ColourGuard(colourCode, this );
- }
-
- void ColourImpl::ColourGuard::engageImpl( std::ostream& stream ) {
- assert( &stream == &m_colourImpl->m_stream->stream() &&
- "Engaging colour guard for different stream than used by the "
- "parent colour implementation" );
- static_cast( stream );
-
- m_engaged = true;
- m_colourImpl->use( m_code );
- }
-
- ColourImpl::ColourGuard::ColourGuard( Colour::Code code,
- ColourImpl const* colour ):
- m_colourImpl( colour ), m_code( code ) {
- }
- ColourImpl::ColourGuard::ColourGuard( ColourGuard&& rhs ) noexcept:
- m_colourImpl( rhs.m_colourImpl ),
- m_code( rhs.m_code ),
- m_engaged( rhs.m_engaged ) {
- rhs.m_engaged = false;
- }
- ColourImpl::ColourGuard&
- ColourImpl::ColourGuard::operator=( ColourGuard&& rhs ) noexcept {
- using std::swap;
- swap( m_colourImpl, rhs.m_colourImpl );
- swap( m_code, rhs.m_code );
- swap( m_engaged, rhs.m_engaged );
-
- return *this;
- }
- ColourImpl::ColourGuard::~ColourGuard() {
- if ( m_engaged ) {
- m_colourImpl->use( Colour::None );
- }
- }
-
- ColourImpl::ColourGuard&
- ColourImpl::ColourGuard::engage( std::ostream& stream ) & {
- engageImpl( stream );
- return *this;
- }
-
- ColourImpl::ColourGuard&&
- ColourImpl::ColourGuard::engage( std::ostream& stream ) && {
- engageImpl( stream );
- return CATCH_MOVE(*this);
- }
-
- namespace {
- //! A do-nothing implementation of colour, used as fallback for unknown
- //! platforms, and when the user asks to deactivate all colours.
- class NoColourImpl final : public ColourImpl {
- public:
- NoColourImpl( IStream* stream ): ColourImpl( stream ) {}
-
- private:
- void use( Colour::Code ) const override {}
- };
- } // namespace
-
-
-} // namespace Catch
-
-
-#if defined ( CATCH_CONFIG_COLOUR_WIN32 ) /////////////////////////////////////////
-
-namespace Catch {
-namespace {
-
- class Win32ColourImpl final : public ColourImpl {
- public:
- Win32ColourImpl(IStream* stream):
- ColourImpl(stream) {
- CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
- GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ),
- &csbiInfo );
- originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
- originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
- }
-
- static bool useImplementationForStream(IStream const& stream) {
- // Win32 text colour APIs can only be used on console streams
- // We cannot check that the output hasn't been redirected,
- // so we just check that the original stream is console stream.
- return stream.isConsole();
- }
-
- private:
- void use( Colour::Code _colourCode ) const override {
- switch( _colourCode ) {
- case Colour::None: return setTextAttribute( originalForegroundAttributes );
- case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
- case Colour::Red: return setTextAttribute( FOREGROUND_RED );
- case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
- case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE );
- case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
- case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
- case Colour::Grey: return setTextAttribute( 0 );
-
- case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY );
- case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
- case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
- case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
- case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );
-
- case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
-
- default:
- CATCH_ERROR( "Unknown colour requested" );
- }
- }
-
- void setTextAttribute( WORD _textAttribute ) const {
- SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ),
- _textAttribute |
- originalBackgroundAttributes );
- }
- WORD originalForegroundAttributes;
- WORD originalBackgroundAttributes;
- };
-
-} // end anon namespace
-} // end namespace Catch
-
-#endif // Windows/ ANSI/ None
-
-
-#if defined( CATCH_PLATFORM_LINUX ) || defined( CATCH_PLATFORM_MAC ) || defined( __GLIBC__ ) || defined(__FreeBSD__)
-# define CATCH_INTERNAL_HAS_ISATTY
-# include
-#endif
-
-namespace Catch {
-namespace {
-
- class ANSIColourImpl final : public ColourImpl {
- public:
- ANSIColourImpl( IStream* stream ): ColourImpl( stream ) {}
-
- static bool useImplementationForStream(IStream const& stream) {
- // This is kinda messy due to trying to support a bunch of
- // different platforms at once.
- // The basic idea is that if we are asked to do autodetection (as
- // opposed to being told to use posixy colours outright), then we
- // only want to use the colours if we are writing to console.
- // However, console might be redirected, so we make an attempt at
- // checking for that on platforms where we know how to do that.
- bool useColour = stream.isConsole();
-#if defined( CATCH_INTERNAL_HAS_ISATTY ) && \
- !( defined( __DJGPP__ ) && defined( __STRICT_ANSI__ ) )
- ErrnoGuard _; // for isatty
- useColour = useColour && isatty( STDOUT_FILENO );
-# endif
-# if defined( CATCH_PLATFORM_MAC ) || defined( CATCH_PLATFORM_IPHONE )
- useColour = useColour && !isDebuggerActive();
-# endif
-
- return useColour;
- }
-
- private:
- void use( Colour::Code _colourCode ) const override {
- auto setColour = [&out =
- m_stream->stream()]( char const* escapeCode ) {
- // The escape sequence must be flushed to console, otherwise
- // if stdin and stderr are intermixed, we'd get accidentally
- // coloured output.
- out << '\033' << escapeCode << std::flush;
- };
- switch( _colourCode ) {
- case Colour::None:
- case Colour::White: return setColour( "[0m" );
- case Colour::Red: return setColour( "[0;31m" );
- case Colour::Green: return setColour( "[0;32m" );
- case Colour::Blue: return setColour( "[0;34m" );
- case Colour::Cyan: return setColour( "[0;36m" );
- case Colour::Yellow: return setColour( "[0;33m" );
- case Colour::Grey: return setColour( "[1;30m" );
-
- case Colour::LightGrey: return setColour( "[0;37m" );
- case Colour::BrightRed: return setColour( "[1;31m" );
- case Colour::BrightGreen: return setColour( "[1;32m" );
- case Colour::BrightWhite: return setColour( "[1;37m" );
- case Colour::BrightYellow: return setColour( "[1;33m" );
-
- case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
- default: CATCH_INTERNAL_ERROR( "Unknown colour requested" );
- }
- }
- };
-
-} // end anon namespace
-} // end namespace Catch
-
-namespace Catch {
-
- Detail::unique_ptr makeColourImpl( ColourMode colourSelection,
- IStream* stream ) {
-#if defined( CATCH_CONFIG_COLOUR_WIN32 )
- if ( colourSelection == ColourMode::Win32 ) {
- return Detail::make_unique( stream );
- }
-#endif
- if ( colourSelection == ColourMode::ANSI ) {
- return Detail::make_unique( stream );
- }
- if ( colourSelection == ColourMode::None ) {
- return Detail::make_unique( stream );
- }
-
- if ( colourSelection == ColourMode::PlatformDefault) {
-#if defined( CATCH_CONFIG_COLOUR_WIN32 )
- if ( Win32ColourImpl::useImplementationForStream( *stream ) ) {
- return Detail::make_unique( stream );
- }
-#endif
- if ( ANSIColourImpl::useImplementationForStream( *stream ) ) {
- return Detail::make_unique( stream );
- }
- return Detail::make_unique( stream );
- }
-
- CATCH_ERROR( "Could not create colour impl for selection " << static_cast(colourSelection) );
- }
-
- bool isColourImplAvailable( ColourMode colourSelection ) {
- switch ( colourSelection ) {
-#if defined( CATCH_CONFIG_COLOUR_WIN32 )
- case ColourMode::Win32:
-#endif
- case ColourMode::ANSI:
- case ColourMode::None:
- case ColourMode::PlatformDefault:
- return true;
- default:
- return false;
- }
- }
-
-
-} // end namespace Catch
-
-#if defined(__clang__)
-# pragma clang diagnostic pop
-#endif
-
-
-
-
-namespace Catch {
-
- Context* Context::currentContext = nullptr;
-
- void cleanUpContext() {
- delete Context::currentContext;
- Context::currentContext = nullptr;
- }
- void Context::createContext() {
- currentContext = new Context();
- }
-
- Context& getCurrentMutableContext() {
- if ( !Context::currentContext ) { Context::createContext(); }
- // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
- return *Context::currentContext;
- }
-
- SimplePcg32& sharedRng() {
- static SimplePcg32 s_rng;
- return s_rng;
- }
-
-}
-
-
-
-
-
-#include
-
-#if defined(CATCH_CONFIG_ANDROID_LOGWRITE)
-#include
-
- namespace Catch {
- void writeToDebugConsole( std::string const& text ) {
- __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() );
- }
- }
-
-#elif defined(CATCH_PLATFORM_WINDOWS)
-
- namespace Catch {
- void writeToDebugConsole( std::string const& text ) {
- ::OutputDebugStringA( text.c_str() );
- }
- }
-
-#else
-
- namespace Catch {
- void writeToDebugConsole( std::string const& text ) {
- // !TBD: Need a version for Mac/ XCode and other IDEs
- Catch::cout() << text;
- }
- }
-
-#endif // Platform
-
-
-
-#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
-
-# include
-# include
-# include
-# include
-# include
-
-#ifdef __apple_build_version__
- // These headers will only compile with AppleClang (XCode)
- // For other compilers (Clang, GCC, ... ) we need to exclude them
-# include
-#endif
-
- namespace Catch {
- #ifdef __apple_build_version__
- // The following function is taken directly from the following technical note:
- // https://developer.apple.com/library/archive/qa/qa1361/_index.html
-
- // Returns true if the current process is being debugged (either
- // running under the debugger or has a debugger attached post facto).
- bool isDebuggerActive(){
- int mib[4];
- struct kinfo_proc info;
- std::size_t size;
-
- // Initialize the flags so that, if sysctl fails for some bizarre
- // reason, we get a predictable result.
-
- info.kp_proc.p_flag = 0;
-
- // Initialize mib, which tells sysctl the info we want, in this case
- // we're looking for information about a specific process ID.
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PID;
- mib[3] = getpid();
-
- // Call sysctl.
-
- size = sizeof(info);
- if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) {
- Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n\n" << std::flush;
- return false;
- }
-
- // We're being debugged if the P_TRACED flag is set.
-
- return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
- }
- #else
- bool isDebuggerActive() {
- // We need to find another way to determine this for non-appleclang compilers on macOS
- return false;
- }
- #endif
- } // namespace Catch
-
-#elif defined(CATCH_PLATFORM_LINUX)
- #include
- #include
-
- namespace Catch{
- // The standard POSIX way of detecting a debugger is to attempt to
- // ptrace() the process, but this needs to be done from a child and not
- // this process itself to still allow attaching to this process later
- // if wanted, so is rather heavy. Under Linux we have the PID of the
- // "debugger" (which doesn't need to be gdb, of course, it could also
- // be strace, for example) in /proc/$PID/status, so just get it from
- // there instead.
- bool isDebuggerActive(){
- // Libstdc++ has a bug, where std::ifstream sets errno to 0
- // This way our users can properly assert over errno values
- ErrnoGuard guard;
- std::ifstream in("/proc/self/status");
- for( std::string line; std::getline(in, line); ) {
- static const int PREFIX_LEN = 11;
- if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
- // We're traced if the PID is not 0 and no other PID starts
- // with 0 digit, so it's enough to check for just a single
- // character.
- return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
- }
- }
-
- return false;
- }
- } // namespace Catch
-#elif defined(_MSC_VER)
- extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
- namespace Catch {
- bool isDebuggerActive() {
- return IsDebuggerPresent() != 0;
- }
- }
-#elif defined(__MINGW32__)
- extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
- namespace Catch {
- bool isDebuggerActive() {
- return IsDebuggerPresent() != 0;
- }
- }
-#else
- namespace Catch {
- bool isDebuggerActive() { return false; }
- }
-#endif // Platform
-
-
-
-
-namespace Catch {
-
- void ITransientExpression::streamReconstructedExpression(
- std::ostream& os ) const {
- // We can't make this function pure virtual to keep ITransientExpression
- // constexpr, so we write error message instead
- os << "Some class derived from ITransientExpression without overriding streamReconstructedExpression";
- }
-
- void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {
- if( lhs.size() + rhs.size() < 40 &&
- lhs.find('\n') == std::string::npos &&
- rhs.find('\n') == std::string::npos )
- os << lhs << ' ' << op << ' ' << rhs;
- else
- os << lhs << '\n' << op << '\n' << rhs;
- }
-}
-
-
-
-#include
-
-
-namespace Catch {
-#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
- [[noreturn]]
- void throw_exception(std::exception const& e) {
- Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n"
- << "The message was: " << e.what() << '\n';
- std::terminate();
- }
-#endif
-
- [[noreturn]]
- void throw_logic_error(std::string const& msg) {
- throw_exception(std::logic_error(msg));
- }
-
- [[noreturn]]
- void throw_domain_error(std::string const& msg) {
- throw_exception(std::domain_error(msg));
- }
-
- [[noreturn]]
- void throw_runtime_error(std::string const& msg) {
- throw_exception(std::runtime_error(msg));
- }
-
-
-
-} // namespace Catch;
-
-
-
-#include
-
-namespace Catch {
-
- IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() = default;
-
- namespace Detail {
-
- namespace {
- // Extracts the actual name part of an enum instance
- // In other words, it returns the Blue part of Bikeshed::Colour::Blue
- StringRef extractInstanceName(StringRef enumInstance) {
- // Find last occurrence of ":"
- size_t name_start = enumInstance.size();
- while (name_start > 0 && enumInstance[name_start - 1] != ':') {
- --name_start;
- }
- return enumInstance.substr(name_start, enumInstance.size() - name_start);
- }
- }
-
- std::vector parseEnums( StringRef enums ) {
- auto enumValues = splitStringRef( enums, ',' );
- std::vector parsed;
- parsed.reserve( enumValues.size() );
- for( auto const& enumValue : enumValues ) {
- parsed.push_back(trim(extractInstanceName(enumValue)));
- }
- return parsed;
- }
-
- EnumInfo::~EnumInfo() = default;
-
- StringRef EnumInfo::lookup( int value ) const {
- for( auto const& valueToName : m_values ) {
- if( valueToName.first == value )
- return valueToName.second;
- }
- return "{** unexpected enum value **}"_sr;
- }
-
- Catch::Detail::unique_ptr makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector const& values ) {
- auto enumInfo = Catch::Detail::make_unique();
- enumInfo->m_name = enumName;
- enumInfo->m_values.reserve( values.size() );
-
- const auto valueNames = Catch::Detail::parseEnums( allValueNames );
- assert( valueNames.size() == values.size() );
- std::size_t i = 0;
- for( auto value : values )
- enumInfo->m_values.emplace_back(value, valueNames[i++]);
-
- return enumInfo;
- }
-
- EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector const& values ) {
- m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
- return *m_enumInfos.back();
- }
-
- } // Detail
-} // Catch
-
-
-
-
-
-#include
-
-namespace Catch {
- ErrnoGuard::ErrnoGuard():m_oldErrno(errno){}
- ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; }
-}
-
-
-
-#include
-
-namespace Catch {
-
-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
- namespace {
- static std::string tryTranslators(
- std::vector<
- Detail::unique_ptr> const& translators ) {
- if ( translators.empty() ) {
- std::rethrow_exception( std::current_exception() );
- } else {
- return translators[0]->translate( translators.begin() + 1,
- translators.end() );
- }
- }
-
- }
-#endif //!defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
-
- ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() = default;
-
- void ExceptionTranslatorRegistry::registerTranslator( Detail::unique_ptr&& translator ) {
- m_translators.push_back( CATCH_MOVE( translator ) );
- }
-
-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
- std::string ExceptionTranslatorRegistry::translateActiveException() const {
- // Compiling a mixed mode project with MSVC means that CLR
- // exceptions will be caught in (...) as well. However, these do
- // do not fill-in std::current_exception and thus lead to crash
- // when attempting rethrow.
- // /EHa switch also causes structured exceptions to be caught
- // here, but they fill-in current_exception properly, so
- // at worst the output should be a little weird, instead of
- // causing a crash.
- if ( std::current_exception() == nullptr ) {
- return "Non C++ exception. Possibly a CLR exception.";
- }
-
- // First we try user-registered translators. If none of them can
- // handle the exception, it will be rethrown handled by our defaults.
- try {
- return tryTranslators(m_translators);
- }
- // To avoid having to handle TFE explicitly everywhere, we just
- // rethrow it so that it goes back up the caller.
- catch( TestFailureException& ) {
- return "{ nested assertion failed }";
- }
- catch( TestSkipException& ) {
- return "{ nested SKIP() called }";
- }
- catch( std::exception const& ex ) {
- return ex.what();
- }
- catch( std::string const& msg ) {
- return msg;
- }
- catch( const char* msg ) {
- return msg;
- }
- catch(...) {
- return "Unknown exception";
- }
- }
-
-#else // ^^ Exceptions are enabled // Exceptions are disabled vv
- std::string ExceptionTranslatorRegistry::translateActiveException() const {
- CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
- }
-#endif
-
-}
-
-
-
-/** \file
- * This file provides platform specific implementations of FatalConditionHandler
- *
- * This means that there is a lot of conditional compilation, and platform
- * specific code. Currently, Catch2 supports a dummy handler (if no
- * handler is desired), and 2 platform specific handlers:
- * * Windows' SEH
- * * POSIX signals
- *
- * Consequently, various pieces of code below are compiled if either of
- * the platform specific handlers is enabled, or if none of them are
- * enabled. It is assumed that both cannot be enabled at the same time,
- * and doing so should cause a compilation error.
- *
- * If another platform specific handler is added, the compile guards
- * below will need to be updated taking these assumptions into account.
- */
-
-
-
-#include
-
-#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )
-
-namespace Catch {
-
- // If neither SEH nor signal handling is required, the handler impls
- // do not have to do anything, and can be empty.
- void FatalConditionHandler::engage_platform() {}
- void FatalConditionHandler::disengage_platform() noexcept {}
- FatalConditionHandler::FatalConditionHandler() = default;
- FatalConditionHandler::~FatalConditionHandler() = default;
-
-} // end namespace Catch
-
-#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS
-
-#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )
-#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time"
-#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS
-
-#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
-
-namespace {
- //! Signals fatal error message to the run context
- void reportFatal( char const * const message ) {
- Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
- }
-
- //! Minimal size Catch2 needs for its own fatal error handling.
- //! Picked empirically, so it might not be sufficient on all
- //! platforms, and for all configurations.
- constexpr std::size_t minStackSizeForErrors = 32 * 1024;
-} // end unnamed namespace
-
-#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
-
-#if defined( CATCH_CONFIG_WINDOWS_SEH )
-
-namespace Catch {
-
- struct SignalDefs { DWORD id; const char* name; };
-
- // There is no 1-1 mapping between signals and windows exceptions.
- // Windows can easily distinguish between SO and SigSegV,
- // but SigInt, SigTerm, etc are handled differently.
- static constexpr SignalDefs signalDefs[] = {
- { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
- { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
- { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
- { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
- };
-
- static LONG CALLBACK topLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {
- for (auto const& def : signalDefs) {
- if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
- reportFatal(def.name);
- }
- }
- // If its not an exception we care about, pass it along.
- // This stops us from eating debugger breaks etc.
- return EXCEPTION_CONTINUE_SEARCH;
- }
-
- // Since we do not support multiple instantiations, we put these
- // into global variables and rely on cleaning them up in outlined
- // constructors/destructors
- static LPTOP_LEVEL_EXCEPTION_FILTER previousTopLevelExceptionFilter = nullptr;
-
-
- // For MSVC, we reserve part of the stack memory for handling
- // memory overflow structured exception.
- FatalConditionHandler::FatalConditionHandler() {
- ULONG guaranteeSize = static_cast(minStackSizeForErrors);
- if (!SetThreadStackGuarantee(&guaranteeSize)) {
- // We do not want to fully error out, because needing
- // the stack reserve should be rare enough anyway.
- Catch::cerr()
- << "Failed to reserve piece of stack."
- << " Stack overflows will not be reported successfully.";
- }
- }
-
- // We do not attempt to unset the stack guarantee, because
- // Windows does not support lowering the stack size guarantee.
- FatalConditionHandler::~FatalConditionHandler() = default;
-
-
- void FatalConditionHandler::engage_platform() {
- // Register as a the top level exception filter.
- previousTopLevelExceptionFilter = SetUnhandledExceptionFilter(topLevelExceptionFilter);
- }
-
- void FatalConditionHandler::disengage_platform() noexcept {
- if (SetUnhandledExceptionFilter(previousTopLevelExceptionFilter) != topLevelExceptionFilter) {
- Catch::cerr()
- << "Unexpected SEH unhandled exception filter on disengage."
- << " The filter was restored, but might be rolled back unexpectedly.";
- }
- previousTopLevelExceptionFilter = nullptr;
- }
-
-} // end namespace Catch
-
-#endif // CATCH_CONFIG_WINDOWS_SEH
-
-#if defined( CATCH_CONFIG_POSIX_SIGNALS )
-
-#include
-
-namespace Catch {
-
- struct SignalDefs {
- int id;
- const char* name;
- };
-
- static constexpr SignalDefs signalDefs[] = {
- { SIGINT, "SIGINT - Terminal interrupt signal" },
- { SIGILL, "SIGILL - Illegal instruction signal" },
- { SIGFPE, "SIGFPE - Floating point error signal" },
- { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
- { SIGTERM, "SIGTERM - Termination request signal" },
- { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
- };
-
-// Older GCCs trigger -Wmissing-field-initializers for T foo = {}
-// which is zero initialization, but not explicit. We want to avoid
-// that.
-#if defined(__GNUC__)
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-#endif
-
- static char* altStackMem = nullptr;
- static std::size_t altStackSize = 0;
- static stack_t oldSigStack{};
- static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
-
- static void restorePreviousSignalHandlers() noexcept {
- // We set signal handlers back to the previous ones. Hopefully
- // nobody overwrote them in the meantime, and doesn't expect
- // their signal handlers to live past ours given that they
- // installed them after ours..
- for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
- sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
- }
- // Return the old stack
- sigaltstack(&oldSigStack, nullptr);
- }
-
- static void handleSignal( int sig ) {
- char const * name = "";
- for (auto const& def : signalDefs) {
- if (sig == def.id) {
- name = def.name;
- break;
- }
- }
- // We need to restore previous signal handlers and let them do
- // their thing, so that the users can have the debugger break
- // when a signal is raised, and so on.
- restorePreviousSignalHandlers();
- reportFatal( name );
- raise( sig );
- }
-
- FatalConditionHandler::FatalConditionHandler() {
- assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");
- if (altStackSize == 0) {
- altStackSize = std::max(static_cast(SIGSTKSZ), minStackSizeForErrors);
- }
- altStackMem = new char[altStackSize]();
- }
-
- FatalConditionHandler::~FatalConditionHandler() {
- delete[] altStackMem;
- // We signal that another instance can be constructed by zeroing
- // out the pointer.
- altStackMem = nullptr;
- }
-
- void FatalConditionHandler::engage_platform() {
- stack_t sigStack;
- sigStack.ss_sp = altStackMem;
- sigStack.ss_size = altStackSize;
- sigStack.ss_flags = 0;
- sigaltstack(&sigStack, &oldSigStack);
- struct sigaction sa = { };
-
- sa.sa_handler = handleSignal;
- sa.sa_flags = SA_ONSTACK;
- for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
- sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
- }
- }
-
-#if defined(__GNUC__)
-# pragma GCC diagnostic pop
-#endif
-
-
- void FatalConditionHandler::disengage_platform() noexcept {
- restorePreviousSignalHandlers();
- }
-
-} // end namespace Catch
-
-#endif // CATCH_CONFIG_POSIX_SIGNALS
-
-
-
-
-#include
-
-namespace Catch {
- namespace Detail {
-
- uint32_t convertToBits(float f) {
- static_assert(sizeof(float) == sizeof(uint32_t), "Important ULP matcher assumption violated");
- uint32_t i;
- std::memcpy(&i, &f, sizeof(f));
- return i;
- }
-
- uint64_t convertToBits(double d) {
- static_assert(sizeof(double) == sizeof(uint64_t), "Important ULP matcher assumption violated");
- uint64_t i;
- std::memcpy(&i, &d, sizeof(d));
- return i;
- }
-
-#if defined( __GNUC__ ) || defined( __clang__ )
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
- bool directCompare( float lhs, float rhs ) { return lhs == rhs; }
- bool directCompare( double lhs, double rhs ) { return lhs == rhs; }
-#if defined( __GNUC__ ) || defined( __clang__ )
-# pragma GCC diagnostic pop
-#endif
-
-
- } // end namespace Detail
-} // end namespace Catch
-
-
-
-
-
-
-#include
-
-namespace Catch {
- namespace Detail {
-
-#if !defined (CATCH_CONFIG_GETENV)
- char const* getEnv( char const* ) { return nullptr; }
-#else
-
- char const* getEnv( char const* varName ) {
-# if defined( _MSC_VER )
-# pragma warning( push )
-# pragma warning( disable : 4996 ) // use getenv_s instead of getenv
-# endif
-
- return std::getenv( varName );
-
-# if defined( _MSC_VER )
-# pragma warning( pop )
-# endif
- }
-#endif
-} // namespace Detail
-} // namespace Catch
-
-
-
-
-#include
-#include
-
-namespace Catch {
-
- Catch::IStream::~IStream() = default;
-
-namespace Detail {
- namespace {
- template
- class StreamBufImpl final : public std::streambuf {
- char data[bufferSize];
- WriterF m_writer;
-
- public:
- StreamBufImpl() {
- setp( data, data + sizeof(data) );
- }
-
- ~StreamBufImpl() noexcept override {
- StreamBufImpl::sync();
- }
-
- private:
- int overflow( int c ) override {
- sync();
-
- if( c != EOF ) {
- if( pbase() == epptr() )
- m_writer( std::string( 1, static_cast( c ) ) );
- else
- sputc( static_cast( c ) );
- }
- return 0;
- }
-
- int sync() override {
- if( pbase() != pptr() ) {
- m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) );
- setp( pbase(), epptr() );
- }
- return 0;
- }
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- struct OutputDebugWriter {
-
- void operator()( std::string const& str ) {
- if ( !str.empty() ) {
- writeToDebugConsole( str );
- }
- }
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- class FileStream final : public IStream {
- std::ofstream m_ofs;
- public:
- FileStream( std::string const& filename ) {
- m_ofs.open( filename.c_str() );
- CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << '\'' );
- m_ofs << std::unitbuf;
- }
- public: // IStream
- std::ostream& stream() override {
- return m_ofs;
- }
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- class CoutStream final : public IStream {
- std::ostream m_os;
- public:
- // Store the streambuf from cout up-front because
- // cout may get redirected when running tests
- CoutStream() : m_os( Catch::cout().rdbuf() ) {}
-
- public: // IStream
- std::ostream& stream() override { return m_os; }
- bool isConsole() const override { return true; }
- };
-
- class CerrStream : public IStream {
- std::ostream m_os;
-
- public:
- // Store the streambuf from cerr up-front because
- // cout may get redirected when running tests
- CerrStream(): m_os( Catch::cerr().rdbuf() ) {}
-
- public: // IStream
- std::ostream& stream() override { return m_os; }
- bool isConsole() const override { return true; }
- };
-
- ///////////////////////////////////////////////////////////////////////////
-
- class DebugOutStream final : public IStream {
- Detail::unique_ptr> m_streamBuf;
- std::ostream m_os;
- public:
- DebugOutStream()
- : m_streamBuf( Detail::make_unique>() ),
- m_os( m_streamBuf.get() )
- {}
-
- public: // IStream
- std::ostream& stream() override { return m_os; }
- };
-
- } // unnamed namespace
-} // namespace Detail
-
- ///////////////////////////////////////////////////////////////////////////
-
- auto makeStream( std::string const& filename ) -> Detail::unique_ptr {
- if ( filename.empty() || filename == "-" ) {
- return Detail::make_unique();
- }
- if( filename[0] == '%' ) {
- if ( filename == "%debug" ) {
- return Detail::make_unique();
- } else if ( filename == "%stderr" ) {
- return Detail::make_unique();
- } else if ( filename == "%stdout" ) {
- return Detail::make_unique();
- } else {
- CATCH_ERROR( "Unrecognised stream: '" << filename << '\'' );
- }
- }
- return Detail::make_unique( filename );
- }
-
-}
-
-
-
-namespace Catch {
-
- namespace {
- static bool needsEscape( char c ) {
- return c == '"' || c == '\\' || c == '\b' || c == '\f' ||
- c == '\n' || c == '\r' || c == '\t';
- }
-
- static Catch::StringRef makeEscapeStringRef( char c ) {
- if ( c == '"' ) {
- return "\\\""_sr;
- } else if ( c == '\\' ) {
- return "\\\\"_sr;
- } else if ( c == '\b' ) {
- return "\\b"_sr;
- } else if ( c == '\f' ) {
- return "\\f"_sr;
- } else if ( c == '\n' ) {
- return "\\n"_sr;
- } else if ( c == '\r' ) {
- return "\\r"_sr;
- } else if ( c == '\t' ) {
- return "\\t"_sr;
- }
- Catch::Detail::Unreachable();
- }
- } // namespace
-
- void JsonUtils::indent( std::ostream& os, std::uint64_t level ) {
- for ( std::uint64_t i = 0; i < level; ++i ) {
- os << " ";
- }
- }
- void JsonUtils::appendCommaNewline( std::ostream& os,
- bool& should_comma,
- std::uint64_t level ) {
- if ( should_comma ) { os << ','; }
- should_comma = true;
- os << '\n';
- indent( os, level );
- }
-
- JsonObjectWriter::JsonObjectWriter( std::ostream& os ):
- JsonObjectWriter{ os, 0 } {}
-
- JsonObjectWriter::JsonObjectWriter( std::ostream& os,
- std::uint64_t indent_level ):
- m_os{ os }, m_indent_level{ indent_level } {
- m_os << '{';
- }
- JsonObjectWriter::JsonObjectWriter( JsonObjectWriter&& source ) noexcept:
- m_os{ source.m_os },
- m_indent_level{ source.m_indent_level },
- m_should_comma{ source.m_should_comma },
- m_active{ source.m_active } {
- source.m_active = false;
- }
-
- JsonObjectWriter::~JsonObjectWriter() {
- if ( !m_active ) { return; }
-
- m_os << '\n';
- JsonUtils::indent( m_os, m_indent_level );
- m_os << '}';
- }
-
- JsonValueWriter JsonObjectWriter::write( StringRef key ) {
- JsonUtils::appendCommaNewline(
- m_os, m_should_comma, m_indent_level + 1 );
-
- m_os << '"' << key << "\": ";
- return JsonValueWriter{ m_os, m_indent_level + 1 };
- }
-
- JsonArrayWriter::JsonArrayWriter( std::ostream& os ):
- JsonArrayWriter{ os, 0 } {}
- JsonArrayWriter::JsonArrayWriter( std::ostream& os,
- std::uint64_t indent_level ):
- m_os{ os }, m_indent_level{ indent_level } {
- m_os << '[';
- }
- JsonArrayWriter::JsonArrayWriter( JsonArrayWriter&& source ) noexcept:
- m_os{ source.m_os },
- m_indent_level{ source.m_indent_level },
- m_should_comma{ source.m_should_comma },
- m_active{ source.m_active } {
- source.m_active = false;
- }
- JsonArrayWriter::~JsonArrayWriter() {
- if ( !m_active ) { return; }
-
- m_os << '\n';
- JsonUtils::indent( m_os, m_indent_level );
- m_os << ']';
- }
-
- JsonObjectWriter JsonArrayWriter::writeObject() {
- JsonUtils::appendCommaNewline(
- m_os, m_should_comma, m_indent_level + 1 );
- return JsonObjectWriter{ m_os, m_indent_level + 1 };
- }
-
- JsonArrayWriter JsonArrayWriter::writeArray() {
- JsonUtils::appendCommaNewline(
- m_os, m_should_comma, m_indent_level + 1 );
- return JsonArrayWriter{ m_os, m_indent_level + 1 };
- }
-
- JsonArrayWriter& JsonArrayWriter::write( bool value ) {
- return writeImpl( value );
- }
-
- JsonValueWriter::JsonValueWriter( std::ostream& os ):
- JsonValueWriter{ os, 0 } {}
-
- JsonValueWriter::JsonValueWriter( std::ostream& os,
- std::uint64_t indent_level ):
- m_os{ os }, m_indent_level{ indent_level } {}
-
- JsonObjectWriter JsonValueWriter::writeObject() && {
- return JsonObjectWriter{ m_os, m_indent_level };
- }
-
- JsonArrayWriter JsonValueWriter::writeArray() && {
- return JsonArrayWriter{ m_os, m_indent_level };
- }
-
- void JsonValueWriter::write( Catch::StringRef value ) && {
- writeImpl( value, true );
- }
-
- void JsonValueWriter::write( bool value ) && {
- writeImpl( value ? "true"_sr : "false"_sr, false );
- }
-
- void JsonValueWriter::writeImpl( Catch::StringRef value, bool quote ) {
- if ( quote ) { m_os << '"'; }
- size_t current_start = 0;
- for ( size_t i = 0; i < value.size(); ++i ) {
- if ( needsEscape( value[i] ) ) {
- if ( current_start < i ) {
- m_os << value.substr( current_start, i - current_start );
- }
- m_os << makeEscapeStringRef( value[i] );
- current_start = i + 1;
- }
- }
- if ( current_start < value.size() ) {
- m_os << value.substr( current_start, value.size() - current_start );
- }
- if ( quote ) { m_os << '"'; }
- }
-
-} // namespace Catch
-
-
-
-
-namespace Catch {
-
- auto operator << (std::ostream& os, LazyExpression const& lazyExpr) -> std::ostream& {
- if (lazyExpr.m_isNegated)
- os << '!';
-
- if (lazyExpr) {
- if (lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression())
- os << '(' << *lazyExpr.m_transientExpression << ')';
- else
- os << *lazyExpr.m_transientExpression;
- } else {
- os << "{** error - unchecked empty expression requested **}";
- }
- return os;
- }
-
-} // namespace Catch
-
-
-
-
-#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
-#include
-
-namespace Catch {
-
- LeakDetector::LeakDetector() {
- int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
- flag |= _CRTDBG_LEAK_CHECK_DF;
- flag |= _CRTDBG_ALLOC_MEM_DF;
- _CrtSetDbgFlag(flag);
- _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
- _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
- // Change this to leaking allocation's number to break there
- _CrtSetBreakAlloc(-1);
- }
-}
-
-#else // ^^ Windows crt debug heap enabled // Windows crt debug heap disabled vv
-
- Catch::LeakDetector::LeakDetector() = default;
-
-#endif // CATCH_CONFIG_WINDOWS_CRTDBG
-
-Catch::LeakDetector::~LeakDetector() {
- Catch::cleanUp();
-}
-
-
-
-
-namespace Catch {
- namespace {
-
- void listTests(IEventListener& reporter, IConfig const& config) {
- auto const& testSpec = config.testSpec();
- auto matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
- reporter.listTests(matchedTestCases);
- }
-
- void listTags(IEventListener& reporter, IConfig const& config) {
- auto const& testSpec = config.testSpec();
- std::vector matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
-
- std::map tagCounts;
- for (auto const& testCase : matchedTestCases) {
- for (auto const& tagName : testCase.getTestCaseInfo().tags) {
- auto it = tagCounts.find(tagName.original);
- if (it == tagCounts.end())
- it = tagCounts.insert(std::make_pair(tagName.original, TagInfo())).first;
- it->second.add(tagName.original);
- }
- }
-
- std::vector infos; infos.reserve(tagCounts.size());
- for (auto& tagc : tagCounts) {
- infos.push_back(CATCH_MOVE(tagc.second));
- }
-
- reporter.listTags(infos);
- }
-
- void listReporters(IEventListener& reporter) {
- std::vector descriptions;
-
- auto const& factories = getRegistryHub().getReporterRegistry().getFactories();
- descriptions.reserve(factories.size());
- for (auto const& fac : factories) {
- descriptions.push_back({ fac.first, fac.second->getDescription() });
- }
-
- reporter.listReporters(descriptions);
- }
-
- void listListeners(IEventListener& reporter) {
- std::vector descriptions;
-
- auto const& factories =
- getRegistryHub().getReporterRegistry().getListeners();
- descriptions.reserve( factories.size() );
- for ( auto const& fac : factories ) {
- descriptions.push_back( { fac->getName(), fac->getDescription() } );
- }
-
- reporter.listListeners( descriptions );
- }
-
- } // end anonymous namespace
-
- void TagInfo::add( StringRef spelling ) {
- ++count;
- spellings.insert( spelling );
- }
-
- std::string TagInfo::all() const {
- // 2 per tag for brackets '[' and ']'
- size_t size = spellings.size() * 2;
- for (auto const& spelling : spellings) {
- size += spelling.size();
- }
-
- std::string out; out.reserve(size);
- for (auto const& spelling : spellings) {
- out += '[';
- out += spelling;
- out += ']';
- }
- return out;
- }
-
- bool list( IEventListener& reporter, Config const& config ) {
- bool listed = false;
- if (config.listTests()) {
- listed = true;
- listTests(reporter, config);
- }
- if (config.listTags()) {
- listed = true;
- listTags(reporter, config);
- }
- if (config.listReporters()) {
- listed = true;
- listReporters(reporter);
- }
- if ( config.listListeners() ) {
- listed = true;
- listListeners( reporter );
- }
- return listed;
- }
-
-} // end namespace Catch
-
-
-
-namespace Catch {
- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
- static const LeakDetector leakDetector;
- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
-}
-
-// Allow users of amalgamated .cpp file to remove our main and provide their own.
-#if !defined(CATCH_AMALGAMATED_CUSTOM_MAIN)
-
-#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
-// Standard C/C++ Win32 Unicode wmain entry point
-extern "C" int __cdecl wmain (int argc, wchar_t * argv[], wchar_t * []) {
-#else
-// Standard C/C++ main entry point
-int main (int argc, char * argv[]) {
-#endif
-
- // We want to force the linker not to discard the global variable
- // and its constructor, as it (optionally) registers leak detector
- (void)&Catch::leakDetector;
-
- return Catch::Session().run( argc, argv );
-}
-
-#endif // !defined(CATCH_AMALGAMATED_CUSTOM_MAIN
-
-
-
-
-namespace Catch {
-
- MessageInfo::MessageInfo( StringRef _macroName,
- SourceLineInfo const& _lineInfo,
- ResultWas::OfType _type )
- : macroName( _macroName ),
- lineInfo( _lineInfo ),
- type( _type ),
- sequence( ++globalCount )
- {}
-
- // Messages are owned by their individual threads, so the counter should be thread-local as well.
- // Alternative consideration: atomic, so threads don't share IDs and things are easier to debug.
- thread_local unsigned int MessageInfo::globalCount = 0;
-
-} // end namespace Catch
-
-
-
-#include
-#include
-#include
-#include
-
-#if defined( CATCH_CONFIG_NEW_CAPTURE )
-# if defined( _MSC_VER )
-# include //_dup and _dup2
-# define dup _dup
-# define dup2 _dup2
-# define fileno _fileno
-# else
-# include