Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/extras/catch_amalgamated.cpp
diff options
context:
space:
mode:
authorMartin Hořeňovský2023-12-11 00:55:40 +0100
committerMartin Hořeňovský2023-12-11 00:55:40 +0100
commit53d0d913a422d356b23dd927547febdf69ee9081 (patch)
treeb2b624bde9ead96c0e448c8d6ba7dcba6e5ebb40 /extras/catch_amalgamated.cpp
parent1648c30ec3ac1aedd1417d31de18801767ab0d72 (diff)
downloadcatch3-3.5.0.tar.gz
v3.5.0v3.5.0
Diffstat (limited to 'extras/catch_amalgamated.cpp')
-rw-r--r--extras/catch_amalgamated.cpp861
1 files changed, 775 insertions, 86 deletions
diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp
index eba3f00a..cfc38a46 100644
--- a/extras/catch_amalgamated.cpp
+++ b/extras/catch_amalgamated.cpp
@@ -1,3 +1,4 @@
+
// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at
@@ -5,8 +6,8 @@
// SPDX-License-Identifier: BSL-1.0
-// Catch v3.4.0
-// Generated: 2023-07-13 13:23:09.554273
+// Catch v3.5.0
+// Generated: 2023-12-11 00:51:07.662625
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -48,6 +49,80 @@ namespace Catch {
} // namespace Catch
+// Adapted from donated nonius code.
+
+
+#include <vector>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last) {
+ if (!cfg.benchmarkNoAnalysis()) {
+ std::vector<double> samples;
+ samples.reserve(static_cast<size_t>(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<double> e) {
+ return Estimate<FDuration> {
+ FDuration(e.point),
+ FDuration(e.lower_bound),
+ FDuration(e.upper_bound),
+ e.confidence_interval,
+ };
+ };
+ std::vector<FDuration> 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<FDuration> samples;
+ samples.reserve(static_cast<size_t>(last - first));
+
+ FDuration mean = FDuration(0);
+ int i = 0;
+ for (auto it = first; it < last; ++it, ++i) {
+ samples.push_back(FDuration(*it));
+ mean += FDuration(*it);
+ }
+ mean /= i;
+
+ return SampleAnalysis{
+ CATCH_MOVE(samples),
+ Estimate<FDuration>{ mean, mean, mean, 0.0 },
+ Estimate<FDuration>{ FDuration( 0 ),
+ FDuration( 0 ),
+ FDuration( 0 ),
+ 0.0 },
+ OutlierClassification{},
+ 0.0
+ };
+ }
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
+
+
namespace Catch {
@@ -87,7 +162,9 @@ namespace Catch {
+#include <algorithm>
#include <cassert>
+#include <cmath>
#include <cstddef>
#include <numeric>
#include <random>
@@ -106,8 +183,8 @@ namespace Catch {
static sample
resample( URng& rng,
unsigned int resamples,
- std::vector<double>::const_iterator first,
- std::vector<double>::const_iterator last,
+ double const* first,
+ double const* last,
Estimator& estimator ) {
auto n = static_cast<size_t>( last - first );
std::uniform_int_distribution<decltype( n )> dist( 0,
@@ -127,7 +204,7 @@ namespace Catch {
dist( rng ) )] );
}
const auto estimate =
- estimator( resampled.begin(), resampled.end() );
+ estimator( resampled.data(), resampled.data() + resampled.size() );
out.push_back( estimate );
}
std::sort( out.begin(), out.end() );
@@ -244,8 +321,7 @@ namespace Catch {
}
static double
- standard_deviation( std::vector<double>::const_iterator first,
- std::vector<double>::const_iterator last ) {
+ standard_deviation( double const* first, double const* last ) {
auto m = Catch::Benchmark::Detail::mean( first, last );
double variance =
std::accumulate( first,
@@ -259,6 +335,23 @@ namespace Catch {
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<size_t>( 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
@@ -268,23 +361,17 @@ namespace Catch {
namespace Benchmark {
namespace Detail {
-#if defined( __GNUC__ ) || defined( __clang__ )
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wfloat-equal"
-#endif
- bool directCompare( double lhs, double rhs ) { return lhs == rhs; }
-#if defined( __GNUC__ ) || defined( __clang__ )
-# pragma GCC diagnostic pop
-#endif
-
- double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ double weighted_average_quantile( int k,
+ int q,
+ double* first,
+ double* last ) {
auto count = last - first;
double idx = (count - 1) * k / static_cast<double>(q);
int j = static_cast<int>(idx);
double g = idx - j;
std::nth_element(first, first + j, last);
auto xj = first[j];
- if ( directCompare( g, 0 ) ) {
+ if ( Catch::Detail::directCompare( g, 0 ) ) {
return xj;
}
@@ -293,12 +380,11 @@ namespace Catch {
}
OutlierClassification
- classify_outliers( std::vector<double>::const_iterator first,
- std::vector<double>::const_iterator last ) {
+ classify_outliers( double const* first, double const* last ) {
std::vector<double> copy( first, last );
- auto q1 = weighted_average_quantile( 1, 4, copy.begin(), copy.end() );
- auto q3 = weighted_average_quantile( 3, 4, copy.begin(), copy.end() );
+ auto 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 );
@@ -322,8 +408,7 @@ namespace Catch {
return o;
}
- double mean( std::vector<double>::const_iterator first,
- std::vector<double>::const_iterator last ) {
+ double mean( double const* first, double const* last ) {
auto count = last - first;
double sum = 0.;
while (first != last) {
@@ -333,6 +418,9 @@ namespace Catch {
return sum / static_cast<double>(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);
@@ -354,26 +442,77 @@ namespace Catch {
return result;
}
- bootstrap_analysis analyse_samples(double confidence_level,
- unsigned int n_resamples,
- std::vector<double>::iterator first,
- std::vector<double>::iterator last) {
- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
- static std::random_device entropy;
- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
+ Estimate<double>
+ 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;
+ }
- auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
+ double accel = sum_cubes / ( 6 * std::pow( sum_squares, 1.5 ) );
+ long n = static_cast<long>( resample.size() );
+ double prob_n =
+ std::count_if( resample.begin(),
+ resample.end(),
+ [point]( double x ) { return x < point; } ) /
+ static_cast<double>( 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<double>( 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<size_t>( (std::max)( cumn( a1 ), 0l ) );
+ auto hi =
+ static_cast<size_t>( (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)(std::vector<double>::const_iterator,
- std::vector<double>::const_iterator)) {
- auto seed = entropy();
+ auto Estimate = [=](double(*f)(double const*, double const*)) {
+ std::random_device rd;
+ auto seed = rd();
return std::async(std::launch::async, [=] {
- std::mt19937 rng(seed);
+ SimplePcg32 rng( seed );
auto resampled = resample(rng, n_resamples, first, last, f);
return bootstrap(confidence_level, first, last, resampled, f);
});
@@ -385,10 +524,10 @@ namespace Catch {
auto mean_estimate = mean_future.get();
auto stddev_estimate = stddev_future.get();
#else
- auto Estimate = [=](double(*f)(std::vector<double>::const_iterator,
- std::vector<double>::const_iterator)) {
- auto seed = entropy();
- std::mt19937 rng(seed);
+ 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);
};
@@ -397,6 +536,7 @@ namespace Catch {
auto stddev_estimate = Estimate(stddev);
#endif // CATCH_USE_ASYNC
+ auto n = static_cast<int>(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 };
@@ -468,10 +608,10 @@ namespace Catch {
}
namespace literals {
- Approx operator "" _a(long double val) {
+ Approx operator ""_a(long double val) {
return Approx(val);
}
- Approx operator "" _a(unsigned long long val) {
+ Approx operator ""_a(unsigned long long val) {
return Approx(val);
}
} // end namespace literals
@@ -2133,7 +2273,7 @@ namespace Catch {
}
Version const& libraryVersion() {
- static Version version( 3, 4, 0, "", 0 );
+ static Version version( 3, 5, 0, "", 0 );
return version;
}
@@ -2186,8 +2326,36 @@ namespace Detail {
+#include <random>
+
+namespace Catch {
+ namespace Generators {
+ namespace Detail {
+ std::uint32_t getSeed() { return sharedRng()(); }
+ } // namespace Detail
+
+ struct RandomFloatingGenerator<long double>::PImpl {
+ PImpl( long double a, long double b, uint32_t seed ):
+ rng( seed ), dist( a, b ) {}
+
+ Catch::SimplePcg32 rng;
+ std::uniform_real_distribution<long double> dist;
+ };
+
+ RandomFloatingGenerator<long double>::RandomFloatingGenerator(
+ long double a, long double b, std::uint32_t seed) :
+ m_pimpl(Catch::Detail::make_unique<PImpl>(a, b, seed)) {
+ static_cast<void>( next() );
+ }
-std::uint32_t Catch::Generators::Detail::getSeed() { return sharedRng()(); }
+ RandomFloatingGenerator<long double>::~RandomFloatingGenerator() =
+ default;
+ bool RandomFloatingGenerator<long double>::next() {
+ m_current_number = m_pimpl->dist( m_pimpl->rng );
+ return true;
+ }
+ } // namespace Generators
+} // namespace Catch
@@ -3710,7 +3878,7 @@ namespace Catch {
return parsed;
}
- EnumInfo::~EnumInfo() {}
+ EnumInfo::~EnumInfo() = default;
StringRef EnumInfo::lookup( int value ) const {
for( auto const& valueToName : m_values ) {
@@ -3759,6 +3927,7 @@ namespace Catch {
namespace Catch {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
namespace {
static std::string tryTranslators(
std::vector<
@@ -3772,9 +3941,9 @@ namespace Catch {
}
}
+#endif //!defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
- ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() {
- }
+ ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() = default;
void ExceptionTranslatorRegistry::registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) {
m_translators.push_back( CATCH_MOVE( translator ) );
@@ -4083,6 +4252,17 @@ namespace Catch {
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
@@ -4267,6 +4447,147 @@ namespace Detail {
+namespace Catch {
+ void JsonUtils::indent( std::ostream& os, std::uint64_t level ) {
+ for ( std::uint64_t i = 0; i < level; ++i ) {
+ os << " ";
+ }
+ }
+ void JsonUtils::appendCommaNewline( std::ostream& os,
+ bool& should_comma,
+ std::uint64_t level ) {
+ if ( should_comma ) { os << ','; }
+ should_comma = true;
+ os << '\n';
+ indent( os, level );
+ }
+
+ JsonObjectWriter::JsonObjectWriter( std::ostream& os ):
+ JsonObjectWriter{ os, 0 } {}
+
+ JsonObjectWriter::JsonObjectWriter( std::ostream& os,
+ std::uint64_t indent_level ):
+ m_os{ os }, m_indent_level{ indent_level } {
+ m_os << '{';
+ }
+ JsonObjectWriter::JsonObjectWriter( JsonObjectWriter&& source ):
+ 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 ):
+ m_os{ source.m_os },
+ m_indent_level{ source.m_indent_level },
+ m_should_comma{ source.m_should_comma },
+ m_active{ source.m_active } {
+ source.m_active = false;
+ }
+ JsonArrayWriter::~JsonArrayWriter() {
+ if ( !m_active ) { return; }
+
+ m_os << '\n';
+ JsonUtils::indent( m_os, m_indent_level );
+ m_os << ']';
+ }
+
+ JsonObjectWriter JsonArrayWriter::writeObject() {
+ JsonUtils::appendCommaNewline(
+ m_os, m_should_comma, m_indent_level + 1 );
+ return JsonObjectWriter{ m_os, m_indent_level + 1 };
+ }
+
+ JsonArrayWriter JsonArrayWriter::writeArray() {
+ JsonUtils::appendCommaNewline(
+ m_os, m_should_comma, m_indent_level + 1 );
+ return JsonArrayWriter{ m_os, m_indent_level + 1 };
+ }
+
+ JsonArrayWriter& JsonArrayWriter::write( bool value ) {
+ return writeImpl( value );
+ }
+
+ JsonValueWriter::JsonValueWriter( std::ostream& os ):
+ JsonValueWriter{ os, 0 } {}
+
+ JsonValueWriter::JsonValueWriter( std::ostream& os,
+ std::uint64_t indent_level ):
+ m_os{ os }, m_indent_level{ indent_level } {}
+
+ JsonObjectWriter JsonValueWriter::writeObject() && {
+ return JsonObjectWriter{ m_os, m_indent_level };
+ }
+
+ JsonArrayWriter JsonValueWriter::writeArray() && {
+ return JsonArrayWriter{ m_os, m_indent_level };
+ }
+
+ void JsonValueWriter::write( Catch::StringRef value ) && {
+ writeImpl( value, true );
+ }
+
+ void JsonValueWriter::write( bool value ) && {
+ writeImpl( value ? "true"_sr : "false"_sr, false );
+ }
+
+ void JsonValueWriter::writeImpl( Catch::StringRef value, bool quote ) {
+ if ( quote ) { m_os << '"'; }
+ for (char c : value) {
+ // Escape list taken from https://www.json.org/json-en.html,
+ // string definition.
+ // Note that while forward slash _can_ be escaped, it does
+ // not have to be, if JSON is not further embedded somewhere
+ // where forward slash is meaningful.
+ if ( c == '"' ) {
+ m_os << "\\\"";
+ } else if ( c == '\\' ) {
+ m_os << "\\\\";
+ } else if ( c == '\b' ) {
+ m_os << "\\b";
+ } else if ( c == '\f' ) {
+ m_os << "\\f";
+ } else if ( c == '\n' ) {
+ m_os << "\\n";
+ } else if ( c == '\r' ) {
+ m_os << "\\r";
+ } else if ( c == '\t' ) {
+ m_os << "\\t";
+ } else {
+ m_os << c;
+ }
+ }
+ if ( quote ) { m_os << '"'; }
+ }
+
+} // namespace Catch
+
+
+
namespace Catch {
@@ -4309,7 +4630,7 @@ namespace Catch {
#else // ^^ Windows crt debug heap enabled // Windows crt debug heap disabled vv
- Catch::LeakDetector::LeakDetector() {}
+ Catch::LeakDetector::LeakDetector() = default;
#endif // CATCH_CONFIG_WINDOWS_CRTDBG
@@ -4677,6 +4998,14 @@ namespace Catch {
}
#endif
+#if !defined( CATCH_CONFIG_GLOBAL_NEXTAFTER )
+ float nextafter( float x, float y ) { return std::nextafter( x, y ); }
+ double nextafter( double x, double y ) { return std::nextafter( x, y ); }
+#else
+ float nextafter( float x, float y ) { return ::nextafterf( x, y ); }
+ double nextafter( double x, double y ) { return ::nextafter( x, y ); }
+#endif
+
} // end namespace Catch
@@ -4758,10 +5087,10 @@ namespace Catch {
return static_cast<std::uint32_t>( std::time( nullptr ) );
case GenerateFrom::Default:
- case GenerateFrom::RandomDevice:
- // In theory, a platform could have random_device that returns just
- // 16 bits. That is still some randomness, so we don't care too much
- return static_cast<std::uint32_t>( std::random_device{}() );
+ case GenerateFrom::RandomDevice: {
+ std::random_device rd;
+ return Detail::fillBitsFrom<std::uint32_t>( rd );
+ }
default:
CATCH_ERROR("Unknown generation method");
@@ -4800,6 +5129,8 @@ namespace Catch {
Detail::make_unique<ReporterFactory<TeamCityReporter>>();
m_impl->factories["XML"] =
Detail::make_unique<ReporterFactory<XmlReporter>>();
+ m_impl->factories["JSON"] =
+ Detail::make_unique<ReporterFactory<JsonReporter>>();
}
ReporterRegistry::~ReporterRegistry() = default;
@@ -5354,13 +5685,14 @@ namespace Catch {
m_messageScopes.clear();
}
- // Reset working state
- resetAssertionInfo();
+ // Reset working state. assertion info will be reset after
+ // populateReaction is run if it is needed
m_lastResult = CATCH_MOVE( result );
}
void RunContext::resetAssertionInfo() {
m_lastAssertionInfo.macroName = StringRef();
m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;
+ m_lastAssertionInfo.resultDisposition = ResultDisposition::Normal;
}
void RunContext::notifyAssertionStarted( AssertionInfo const& info ) {
@@ -5508,6 +5840,7 @@ namespace Catch {
AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult));
assertionEnded(CATCH_MOVE(result) );
+ resetAssertionInfo();
handleUnfinishedSections();
@@ -5644,6 +5977,7 @@ namespace Catch {
reportExpr(info, ResultWas::ExpressionFailed, &expr, negated );
populateReaction( reaction );
}
+ resetAssertionInfo();
}
void RunContext::reportExpr(
AssertionInfo const &info,
@@ -5682,6 +6016,7 @@ namespace Catch {
// considered "OK"
reaction.shouldSkip = true;
}
+ resetAssertionInfo();
}
void RunContext::handleUnexpectedExceptionNotThrown(
AssertionInfo const& info,
@@ -5702,6 +6037,7 @@ namespace Catch {
AssertionResult assertionResult{ info, CATCH_MOVE(data) };
assertionEnded( CATCH_MOVE(assertionResult) );
populateReaction( reaction );
+ resetAssertionInfo();
}
void RunContext::populateReaction( AssertionReaction& reaction ) {
@@ -5719,6 +6055,7 @@ namespace Catch {
data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s;
AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
assertionEnded( CATCH_MOVE(assertionResult) );
+ resetAssertionInfo();
}
void RunContext::handleNonExpr(
AssertionInfo const &info,
@@ -5733,6 +6070,7 @@ namespace Catch {
const auto isOk = assertionResult.isOk();
assertionEnded( CATCH_MOVE(assertionResult) );
if ( !isOk ) { populateReaction( reaction ); }
+ resetAssertionInfo();
}
@@ -6059,7 +6397,7 @@ namespace Catch {
namespace Catch {
- TagAliasRegistry::~TagAliasRegistry() {}
+ TagAliasRegistry::~TagAliasRegistry() = default;
TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {
auto it = m_registry.find( alias );
@@ -7564,26 +7902,11 @@ namespace {
return ulpDist <= maxUlpDiff;
}
-#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
-
- float nextafter(float x, float y) {
- return ::nextafterf(x, y);
- }
-
- double nextafter(double x, double y) {
- return ::nextafter(x, y);
- }
-
-#endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^
template <typename FP>
FP step(FP start, FP direction, uint64_t steps) {
for (uint64_t i = 0; i < steps; ++i) {
-#if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
start = Catch::nextafter(start, direction);
-#else
- start = std::nextafter(start, direction);
-#endif
}
return start;
}
@@ -7957,7 +8280,7 @@ namespace Catch {
namespace Catch {
- AutomakeReporter::~AutomakeReporter() {}
+ AutomakeReporter::~AutomakeReporter() = default;
void AutomakeReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
// Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR.
@@ -8257,7 +8580,7 @@ private:
StreamingReporterBase::testRunEnded( _testRunStats );
}
- CompactReporter::~CompactReporter() {}
+ CompactReporter::~CompactReporter() = default;
} // end namespace Catch
@@ -8461,6 +8784,7 @@ struct ColumnInfo {
};
struct ColumnBreak {};
struct RowBreak {};
+struct OutputFlush {};
class Duration {
enum class Unit {
@@ -8577,12 +8901,12 @@ public:
}
template<typename T>
- friend TablePrinter& operator << (TablePrinter& tp, T const& value) {
+ friend TablePrinter& operator<< (TablePrinter& tp, T const& value) {
tp.m_oss << value;
return tp;
}
- friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {
+ friend TablePrinter& operator<< (TablePrinter& tp, ColumnBreak) {
auto colStr = tp.m_oss.str();
const auto strSize = colStr.size();
tp.m_oss.str("");
@@ -8604,13 +8928,18 @@ public:
return tp;
}
- friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {
+ friend TablePrinter& operator<< (TablePrinter& tp, RowBreak) {
if (tp.m_currentColumn > 0) {
tp.m_os << '\n';
tp.m_currentColumn = -1;
}
return tp;
}
+
+ friend TablePrinter& operator<<(TablePrinter& tp, OutputFlush) {
+ tp.m_os << std::flush;
+ return tp;
+ }
};
ConsoleReporter::ConsoleReporter(ReporterConfig&& config):
@@ -8632,7 +8961,7 @@ ConsoleReporter::ConsoleReporter(ReporterConfig&& config):
{ "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left },
{ "samples mean std dev", 14, Justification::Right },
{ "iterations low mean low std dev", 14, Justification::Right },
- { "estimated high mean high std dev", 14, Justification::Right }
+ { "est run time high mean high std dev", 14, Justification::Right }
};
}
}())) {}
@@ -8716,8 +9045,11 @@ void ConsoleReporter::benchmarkPreparing( StringRef name ) {
void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
(*m_tablePrinter) << info.samples << ColumnBreak()
<< info.iterations << ColumnBreak();
- if (!m_config->benchmarkNoAnalysis())
- (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak();
+ if ( !m_config->benchmarkNoAnalysis() ) {
+ ( *m_tablePrinter )
+ << Duration( info.estimatedDuration ) << ColumnBreak();
+ }
+ ( *m_tablePrinter ) << OutputFlush{};
}
void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) {
if (m_config->benchmarkNoAnalysis())
@@ -9413,6 +9745,366 @@ namespace Catch {
} // namespace Catch
+//
+
+namespace Catch {
+ namespace {
+ void writeSourceInfo( JsonObjectWriter& writer,
+ SourceLineInfo const& sourceInfo ) {
+ auto source_location_writer =
+ writer.write( "source-location"_sr ).writeObject();
+ source_location_writer.write( "filename"_sr )
+ .write( sourceInfo.file );
+ source_location_writer.write( "line"_sr ).write( sourceInfo.line );
+ }
+
+ void writeTags( JsonArrayWriter writer, std::vector<Tag> const& tags ) {
+ for ( auto const& tag : tags ) {
+ writer.write( tag.original );
+ }
+ }
+
+ void writeProperties( JsonArrayWriter writer,
+ TestCaseInfo const& info ) {
+ if ( info.isHidden() ) { writer.write( "is-hidden"_sr ); }
+ if ( info.okToFail() ) { writer.write( "ok-to-fail"_sr ); }
+ if ( info.expectedToFail() ) {
+ writer.write( "expected-to-fail"_sr );
+ }
+ if ( info.throws() ) { writer.write( "throws"_sr ); }
+ }
+
+ } // namespace
+
+ JsonReporter::JsonReporter( ReporterConfig&& config ):
+ StreamingReporterBase{ CATCH_MOVE( config ) } {
+
+ m_preferences.shouldRedirectStdOut = true;
+ // TBD: Do we want to report all assertions? XML reporter does
+ // not, but for machine-parseable reporters I think the answer
+ // should be yes.
+ m_preferences.shouldReportAllAssertions = true;
+
+ m_objectWriters.emplace( m_stream );
+ m_writers.emplace( Writer::Object );
+ auto& writer = m_objectWriters.top();
+
+ writer.write( "version"_sr ).write( 1 );
+
+ {
+ auto metadata_writer = writer.write( "metadata"_sr ).writeObject();
+ metadata_writer.write( "name"_sr ).write( m_config->name() );
+ metadata_writer.write( "rng-seed"_sr ).write( m_config->rngSeed() );
+ metadata_writer.write( "catch2-version"_sr )
+ .write( libraryVersion() );
+ if ( m_config->testSpec().hasFilters() ) {
+ metadata_writer.write( "filters"_sr )
+ .write( m_config->testSpec() );
+ }
+ }
+ }
+
+ JsonReporter::~JsonReporter() {
+ endListing();
+ // TODO: Ensure this closes the top level object, add asserts
+ assert( m_writers.size() == 1 && "Only the top level object should be open" );
+ assert( m_writers.top() == Writer::Object );
+ endObject();
+ m_stream << '\n' << std::flush;
+ assert( m_writers.empty() );
+ }
+
+ JsonArrayWriter& JsonReporter::startArray() {
+ m_arrayWriters.emplace( m_arrayWriters.top().writeArray() );
+ m_writers.emplace( Writer::Array );
+ return m_arrayWriters.top();
+ }
+ JsonArrayWriter& JsonReporter::startArray( StringRef key ) {
+ m_arrayWriters.emplace(
+ m_objectWriters.top().write( key ).writeArray() );
+ m_writers.emplace( Writer::Array );
+ return m_arrayWriters.top();
+ }
+
+ JsonObjectWriter& JsonReporter::startObject() {
+ m_objectWriters.emplace( m_arrayWriters.top().writeObject() );
+ m_writers.emplace( Writer::Object );
+ return m_objectWriters.top();
+