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

summaryrefslogtreecommitdiffhomepage
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
parent1648c30ec3ac1aedd1417d31de18801767ab0d72 (diff)
downloadcatch3-3.5.0.tar.gz
v3.5.0v3.5.0
-rw-r--r--CMakeLists.txt2
-rw-r--r--docs/faq.md2
-rw-r--r--docs/generators.md2
-rw-r--r--docs/release-notes.md36
-rw-r--r--extras/catch_amalgamated.cpp861
-rw-r--r--extras/catch_amalgamated.hpp1231
-rw-r--r--meson.build2
-rw-r--r--src/catch2/catch_version.cpp2
-rw-r--r--src/catch2/catch_version_macros.hpp2
9 files changed, 1735 insertions, 405 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 42f65237..2cfb6cd1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,7 +32,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
endif()
project(Catch2
- VERSION 3.4.0 # CML version placeholder, don't delete
+ VERSION 3.5.0 # CML version placeholder, don't delete
LANGUAGES CXX
# HOMEPAGE_URL is not supported until CMake version 3.12, which
# we do not target yet.
diff --git a/docs/faq.md b/docs/faq.md
index 608277e2..80923d26 100644
--- a/docs/faq.md
+++ b/docs/faq.md
@@ -84,7 +84,7 @@ and it is also generally repeatable across versions, but we might break
it from time to time. E.g. we broke repeatability with previous versions
in v2.13.4 so that test cases with similar names are shuffled better.
-Since Catch2 vX.Y.Z the random generators use custom distributions,
+Since Catch2 3.5.0 the random generators use custom distributions,
that should be repeatable across different platforms, with few caveats.
For details see the section on random generators in the [Generator
documentation](generators.md#random-number-generators-details).
diff --git a/docs/generators.md b/docs/generators.md
index 7929122b..8bca54c7 100644
--- a/docs/generators.md
+++ b/docs/generators.md
@@ -192,7 +192,7 @@ TEST_CASE("type conversion", "[generators]") {
### Random number generators: details
-> This section applies from Catch2 vX.Y.Z. Before that, random generators
+> This section applies from Catch2 3.5.0. Before that, random generators
> were a thin wrapper around distributions from `<random>`.
All of the `random(a, b)` generators in Catch2 currently generate uniformly
diff --git a/docs/release-notes.md b/docs/release-notes.md
index 8faf4d7c..d263487f 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -2,6 +2,7 @@
# Release notes
**Contents**<br>
+[3.5.0](#350)<br>
[3.4.0](#340)<br>
[3.3.2](#332)<br>
[3.3.1](#331)<br>
@@ -58,6 +59,41 @@
+## 3.5.0
+
+### Improvements
+* Introduced `CATCH_CONFIG_PREFIX_MESSAGES` to prefix only logging macros (#2544)
+ * This means `INFO`, `UNSCOPED_INFO`, `WARN` and `CAPTURE`.
+* Section hints in static analysis mode are now `const`
+ * This prevents Clang-Tidy from complaining about `misc-const-correctness`.
+* `from_range` generator supports C arrays and ranges that require ADL (#2737)
+* Stringification support for `std::optional` now also includes `std::nullopt` (#2740)
+* The Console reporter flushes output after writing benchmark runtime estimate.
+ * This means that you can immediately see for how long the benchmark is expected to run.
+* Added workaround to enable compilation with ICC 19.1 (#2551, #2766)
+* Compiling Catch2 for XBox should work out of the box (#2772)
+ * Catch2 should automatically disable getenv when compiled for XBox.
+* Compiling Catch2 with exceptions disabled no longer triggers `Wunused-function` (#2726)
+* **`random` Generators for integral types are now reproducible across different platforms**
+ * Unlike `<rando>`, Catch2's generators also support 1 byte integral types (`char`, `bool`, ...)
+* **`random` Generators for `float` and `double` are now reproducible across different platforms**
+ * `long double` varies across different platforms too much to be reproducible
+ * This guarantee applies only to platforms with IEEE 754 floats.
+
+### Fixes
+* UDL declaration inside Catch2 are now strictly conforming to the standard
+ * `operator "" _a` is UB, `operator ""_a` is fine. Seriously.
+* Fixed `CAPTURE` tests failing to compile in C++23 mode (#2744)
+* Fixed missing include in `catch_message.hpp` (#2758)
+* Fixed `CHECK_ELSE` suppressing failure from uncaught exceptions(#2723)
+
+### Miscellaneous
+* The documentation for specifying which tests to run through commandline has been completely rewritten (#2738)
+* Fixed installation when building Catch2 with meson (#2722, #2742)
+* Fixed `catch_discover_tests` when using custom reporter and `PRE_TEST` discovery mode (#2747)
+* `catch_discover_tests` supports multi-config CMake generator in `PRE_TEST` discovery mode (#2739, #2746)
+
+
## 3.4.0
### Improvements
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 Tabl