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

summaryrefslogtreecommitdiffhomepage
path: root/extras
diff options
context:
space:
mode:
authorMartin Hořeňovský2022-05-17 22:13:36 +0200
committerMartin Hořeňovský2022-05-17 22:13:36 +0200
commit605a34765aa5d5ecbf476b4598a862ada971b0cc (patch)
tree12f9c74f3d86a2996b1bc2355b635926a0b24ebf /extras
parentabb669d4fdaeb08ec7e087541d32e7130bc775ef (diff)
downloadcatch3-3.0.1.tar.gz
v3.0.1v3.0.1
Diffstat (limited to 'extras')
-rw-r--r--extras/catch_amalgamated.cpp251
-rw-r--r--extras/catch_amalgamated.hpp271
2 files changed, 428 insertions, 94 deletions
diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp
index 58a1c7d5..bd8c8119 100644
--- a/extras/catch_amalgamated.cpp
+++ b/extras/catch_amalgamated.cpp
@@ -5,8 +5,8 @@
// SPDX-License-Identifier: BSL-1.0
-// Catch v3.0.0-preview.5
-// Generated: 2022-04-20 23:45:15.004945
+// Catch v3.0.1
+// Generated: 2022-05-17 22:08:47.054486
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -145,6 +145,15 @@ 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) {
auto count = last - first;
double idx = (count - 1) * k / static_cast<double>(q);
@@ -152,7 +161,9 @@ namespace Catch {
double g = idx - j;
std::nth_element(first, first + j, last);
auto xj = first[j];
- if (g == 0) return xj;
+ if ( directCompare( g, 0 ) ) {
+ return xj;
+ }
auto xj1 = *std::min_element(first + (j + 1), last);
return xj + g * (xj1 - xj);
@@ -594,6 +605,7 @@ namespace Catch {
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<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
@@ -635,6 +647,7 @@ namespace Catch {
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; }
@@ -1215,7 +1228,7 @@ namespace Catch {
else if( tag == "!nonportable"_sr )
return TestCaseProperties::NonPortable;
else if( tag == "!benchmark"_sr )
- return static_cast<TestCaseProperties>(TestCaseProperties::Benchmark | TestCaseProperties::IsHidden );
+ return TestCaseProperties::Benchmark | TestCaseProperties::IsHidden;
else
return TestCaseProperties::None;
}
@@ -1860,13 +1873,19 @@ namespace Catch {
}
Version const& libraryVersion() {
- static Version version( 3, 0, 0, "preview", 5 );
+ static Version version( 3, 0, 1, "", 0 );
return version;
}
}
+
+
+
+std::uint32_t Catch::Generators::Detail::getSeed() { return sharedRng()(); }
+
+
/** \file
* This is a special TU that combines what would otherwise be a very
* small generator-related TUs into one bigger TU.
@@ -2001,6 +2020,32 @@ namespace Catch {
+#include <string>
+
+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
+
+
+
#include <algorithm>
#include <cassert>
#include <iomanip>
@@ -2412,7 +2457,7 @@ namespace Catch {
return Detail::InternalParseResult::runtimeError(
"Expected argument following " +
token.token);
- auto result = valueRef->setValue(argToken.token);
+ const auto result = valueRef->setValue(argToken.token);
if (!result)
return Detail::InternalParseResult(result);
if (result.value() ==
@@ -3109,7 +3154,10 @@ namespace Catch {
( "list all/matching tags" )
| Opt( config.listReporters )
["--list-reporters"]
- ( "list all 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)" )
@@ -3125,6 +3173,9 @@ namespace Catch {
| 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)" )
@@ -3230,7 +3281,6 @@ namespace Catch {
class NoColourImpl : public ColourImpl {
public:
NoColourImpl( IStream* stream ): ColourImpl( stream ) {}
- static bool useColourOnPlatform() { return true; }
private:
void use( Colour::Code ) const override {}
@@ -3257,7 +3307,7 @@ namespace {
originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
}
- static bool useColourOnPlatform(IStream const& stream) {
+ 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.
@@ -3316,7 +3366,7 @@ namespace {
public:
ANSIColourImpl( IStream* stream ): ColourImpl( stream ) {}
- static bool useColourOnPlatform(IStream const& 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
@@ -3390,13 +3440,13 @@ namespace Catch {
// todo: check win32 eligibility under ifdef, otherwise ansi
if ( implSelection == ColourMode::PlatformDefault) {
#if defined (CATCH_CONFIG_COLOUR_WIN32)
- if ( Win32ColourImpl::useColourOnPlatform( *stream ) ) {
+ if ( Win32ColourImpl::useImplementationForStream( *stream ) ) {
return Detail::make_unique<Win32ColourImpl>( stream );
} else {
return Detail::make_unique<NoColourImpl>( stream );
}
#endif
- if ( ANSIColourImpl::useColourOnPlatform( *stream ) ) {
+ if ( ANSIColourImpl::useImplementationForStream( *stream ) ) {
return Detail::make_unique<ANSIColourImpl>( stream );
}
return Detail::make_unique<NoColourImpl>( stream );
@@ -3475,7 +3525,7 @@ namespace Catch {
Context::~Context() = default;
- SimplePcg32& rng() {
+ SimplePcg32& sharedRng() {
static SimplePcg32 s_rng;
return s_rng;
}
@@ -4079,7 +4129,7 @@ namespace Detail {
setp( data, data + sizeof(data) );
}
- ~StreamBufImpl() noexcept {
+ ~StreamBufImpl() noexcept override {
StreamBufImpl::sync();
}
@@ -4250,6 +4300,19 @@ namespace Catch {
reporter.listReporters(descriptions);
}
+ void listListeners(IEventListener& reporter) {
+ std::vector<ListenerDescription> 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 ) {
@@ -4287,6 +4350,10 @@ namespace Catch {
listed = true;
listReporters(reporter);
}
+ if ( config.listListeners() ) {
+ listed = true;
+ listListeners( reporter );
+ }
return listed;
}
@@ -4297,7 +4364,7 @@ namespace Catch {
namespace Catch {
CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
- LeakDetector leakDetector;
+ static LeakDetector leakDetector;
CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
}
@@ -4581,7 +4648,8 @@ namespace Catch {
void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr factory ) {
CATCH_ENFORCE( name.find( "::" ) == name.npos,
"'::' is not allowed in reporter name: '" + name + '\'' );
- m_factories.emplace(name, CATCH_MOVE(factory));
+ auto ret = m_factories.emplace(name, CATCH_MOVE(factory));
+ CATCH_ENFORCE( ret.second, "reporter using '" + name + "' as name was already registered" );
}
void ReporterRegistry::registerListener(
Detail::unique_ptr<EventListenerFactory> factory ) {
@@ -4851,7 +4919,7 @@ namespace Catch {
GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
: TrackerBase( nameAndLocation, ctx, parent )
{}
- ~GeneratorTracker();
+ ~GeneratorTracker() override;
static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) {
GeneratorTracker* tracker;
@@ -4962,7 +5030,7 @@ namespace Catch {
// this generator is still waiting for any child to start.
if ( should_wait_for_child ||
( m_runState == CompletedSuccessfully &&
- m_generator->next() ) ) {
+ m_generator->countedNext() ) ) {
m_children.clear();
m_runState = Executing;
}
@@ -5012,6 +5080,39 @@ namespace Catch {
assert(rootTracker.isSectionTracker());
static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
+ // We intentionally only seed the internal RNG once per test case,
+ // before it is first invoked. The reason for that is a complex
+ // interplay of generator/section implementation details and the
+ // Random*Generator types.
+ //
+ // The issue boils down to us needing to seed the Random*Generators
+ // with different seed each, so that they return different sequences
+ // of random numbers. We do this by giving them a number from the
+ // shared RNG instance as their seed.
+ //
+ // However, this runs into an issue if the reseeding happens each
+ // time the test case is entered (as opposed to first time only),
+ // because multiple generators could get the same seed, e.g. in
+ // ```cpp
+ // TEST_CASE() {
+ // auto i = GENERATE(take(10, random(0, 100));
+ // SECTION("A") {
+ // auto j = GENERATE(take(10, random(0, 100));
+ // }
+ // SECTION("B") {
+ // auto k = GENERATE(take(10, random(0, 100));
+ // }
+ // }
+ // ```
+ // `i` and `j` would properly return values from different sequences,
+ // but `i` and `k` would return the same sequence, because their seed
+ // would be the same.
+ // (The reason their seeds would be the same is that the generator
+ // for k would be initialized when the test case is entered the second
+ // time, after the shared RNG instance was reset to the same value
+ // it had when the generator for i was initialized.)
+ seedRng( *m_config );
+
uint64_t testRuns = 0;
do {
m_trackerContext.startCycle();
@@ -5241,8 +5342,6 @@ namespace Catch {
m_shouldReportUnexpected = true;
m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };
- seedRng(*m_config);
-
Timer timer;
CATCH_TRY {
if (m_reporter->getPreferences().shouldRedirectStdOut) {
@@ -5417,10 +5516,7 @@ namespace Catch {
}
void seedRng(IConfig const& config) {
- if (config.rngSeed() != 0) {
- std::srand(config.rngSeed());
- rng().seed(config.rngSeed());
- }
+ sharedRng().seed(config.rngSeed());
}
unsigned int rngSeed() {
@@ -5642,7 +5738,7 @@ namespace Catch {
namespace Catch {
StringRef::StringRef( char const* rawChars ) noexcept
- : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) )
+ : StringRef( rawChars, std::strlen(rawChars) )
{}
auto StringRef::operator == ( StringRef other ) const noexcept -> bool {
@@ -7213,14 +7309,26 @@ namespace Detail {
ret << " ([";
if (m_type == Detail::FloatingPointKind::Double) {
- write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps));
+ write( ret,
+ step( m_target,
+ -std::numeric_limits<double>::infinity(),
+ m_ulps ) );
ret << ", ";
- write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps));
+ write( ret,
+ step( m_target,
+ std::numeric_limits<double>::infinity(),
+ m_ulps ) );
} else {
// We have to cast INFINITY to float because of MinGW, see #1782
- write(ret, step(static_cast<float>(m_target), static_cast<float>(-INFINITY), m_ulps));
+ write( ret,
+ step( static_cast<float>( m_target ),
+ -std::numeric_limits<float>::infinity(),
+ m_ulps ) );
ret << ", ";
- write(ret, step(static_cast<float>(m_target), static_cast<float>( INFINITY), m_ulps));
+ write( ret,
+ step( static_cast<float>( m_target ),
+ std::numeric_limits<float>::infinity(),
+ m_ulps ) );
}
ret << "])";
@@ -7706,6 +7814,33 @@ namespace Catch {
out << '\n' << std::flush;
}
+ void defaultListListeners( std::ostream& out,
+ std::vector<ListenerDescription> const& descriptions ) {
+ const auto maxNameLen =
+ std::max_element( descriptions.begin(),
+ descriptions.end(),
+ []( ListenerDescription const& lhs,
+ ListenerDescription const& rhs ) {
+ return lhs.name.size() < rhs.name.size();
+ } )
+ ->name.size();
+
+ out << "Registered listeners:\n";
+ for ( auto const& desc : descriptions ) {
+ out << TextFlow::Column( static_cast<std::string>( desc.name ) +
+ ':' )
+ .indent( 2 )
+ .width( maxNameLen + 5 ) +
+ TextFlow::Column( desc.description )
+ .initialIndent( 0 )
+ .indent( 2 )
+ .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 )
+ << '\n';
+ }
+
+ out << '\n' << std::flush;
+ }
+
void defaultListTags( std::ostream& out,
std::vector<TagInfo> const& tags,
bool isFiltered ) {
@@ -7786,6 +7921,8 @@ namespace Catch {
void EventListenerBase::assertionEnded( AssertionStats const& ) {}
void EventListenerBase::listReporters(
std::vector<ReporterDescription> const& ) {}
+ void EventListenerBase::listListeners(
+ std::vector<ListenerDescription> const& ) {}
void EventListenerBase::listTests( std::vector<TestCaseHandle> const& ) {}
void EventListenerBase::listTags( std::vector<TagInfo> const& ) {}
void EventListenerBase::noMatchingTestCases( StringRef ) {}
@@ -7822,6 +7959,11 @@ namespace Catch {
defaultListReporters(m_stream, descriptions, m_config->verbosity());
}
+ void ReporterBase::listListeners(
+ std::vector<ListenerDescription> const& descriptions ) {
+ defaultListListeners( m_stream, descriptions );
+ }
+
void ReporterBase::listTests(std::vector<TestCaseHandle> const& tests) {
defaultListTests(m_stream,
m_colour.get(),
@@ -9415,6 +9557,13 @@ namespace Catch {
}
}
+ void MultiReporter::listListeners(
+ std::vector<ListenerDescription> const& descriptions ) {
+ for ( auto& reporterish : m_reporterLikes ) {
+ reporterish->listListeners( descriptions );
+ }
+ }
+
void MultiReporter::listTests(std::vector<TestCaseHandle> const& tests) {
for (auto& reporterish : m_reporterLikes) {
reporterish->listTests(tests);
@@ -9432,6 +9581,29 @@ namespace Catch {
+
+namespace Catch {
+ namespace Detail {
+
+ void registerReporterImpl( std::string const& name,
+ IReporterFactoryPtr reporterPtr ) {
+ CATCH_TRY {
+ getMutableRegistryHub().registerReporter(
+ name, CATCH_MOVE( reporterPtr ) );
+ }
+ CATCH_CATCH_ALL {
+ // Do not throw when constructing global objects, instead
+ // register the exception to be processed later
+ getMutableRegistryHub().registerStartupException();
+ }
+ }
+
+ } // namespace Detail
+} // namespace Catch
+
+
+
+
#include <map>
namespace Catch {
@@ -9689,11 +9861,6 @@ namespace Catch {
}
private:
- void printSourceInfo() const {
- stream << colourImpl->guardColour( tapDimColour )
- << result.getSourceInfo() << ':';
- }
-
void printResultType(StringRef passOrFail) const {
if (!passOrFail.empty()) {
stream << passOrFail << ' ' << counter << " -";
@@ -10009,7 +10176,8 @@ namespace Catch {
m_xml.writeStylesheetRef( stylesheetRef );
m_xml.startElement("Catch2TestRun")
.writeAttribute("name"_sr, m_config->name())
- .writeAttribute("rng-seed"_sr, m_config->rngSeed());
+ .writeAttribute("rng-seed"_sr, m_config->rngSeed())
+ .writeAttribute("catch2-version"_sr, libraryVersion());
if (m_config->testSpec().hasFilters())
m_xml.writeAttribute( "filters"_sr, serializeFilters( m_config->getTestsOrTags() ) );
}
@@ -10212,6 +10380,19 @@ namespace Catch {
}
}
+ void XmlReporter::listListeners(std::vector<ListenerDescription> const& descriptions) {
+ auto outerTag = m_xml.scopedElement( "RegisteredListeners" );
+ for ( auto const& listener : descriptions ) {
+ auto inner = m_xml.scopedElement( "Listener" );
+ m_xml.startElement( "Name", XmlFormatting::Indent )
+ .writeText( listener.name, XmlFormatting::None )
+ .endElement( XmlFormatting::Newline );
+ m_xml.startElement( "Description", XmlFormatting::Indent )
+ .writeText( listener.description, XmlFormatting::None )
+ .endElement( XmlFormatting::Newline );
+ }
+ }
+
void XmlReporter::listTests(std::vector<TestCaseHandle> const& tests) {
auto outerTag = m_xml.scopedElement("MatchingTests");
for (auto const& test : tests) {
diff --git a/extras/catch_amalgamated.hpp b/extras/catch_amalgamated.hpp
index a5f8df0a..5c1caa36 100644
--- a/extras/catch_amalgamated.hpp
+++ b/extras/catch_amalgamated.hpp
@@ -5,8 +5,8 @@
// SPDX-License-Identifier: BSL-1.0
-// Catch v3.0.0-preview.5
-// Generated: 2022-04-20 23:45:13.582550
+// Catch v3.0.1
+// Generated: 2022-05-17 22:08:46.674860
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -274,6 +274,7 @@ namespace Catch {
virtual std::vector<std::string> const& getSectionsToRun() const = 0;
virtual Verbosity verbosity() const = 0;
+ virtual bool skipBenchmarks() const = 0;
virtual bool benchmarkNoAnalysis() const = 0;
virtual unsigned int benchmarkSamples() const = 0;
virtual double benchmarkConfidenceInterval() const = 0;
@@ -688,7 +689,7 @@ namespace Catch {
class IMutableContext : public IContext {
public:
- virtual ~IMutableContext(); // = default
+ ~IMutableContext() override; // = default
virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
virtual void setConfig( IConfig const* config ) = 0;
@@ -715,7 +716,7 @@ namespace Catch {
void cleanUpContext();
class SimplePcg32;
- SimplePcg32& rng();
+ SimplePcg32& sharedRng();
}
#endif // CATCH_CONTEXT_HPP_INCLUDED
@@ -1287,6 +1288,7 @@ namespace Catch {
namespace Catch {
struct ReporterDescription;
+ struct ListenerDescription;
struct TagInfo;
struct TestCaseInfo;
class TestCaseHandle;
@@ -1509,11 +1511,12 @@ namespace Catch {
//! Writes out information about provided reporters using reporter-specific format
virtual void listReporters(std::vector<ReporterDescription> const& descriptions) = 0;
+ //! Writes out the provided listeners descriptions using reporter-specific format
+ virtual void listListeners(std::vector<ListenerDescription> const& descriptions) = 0;
//! Writes out information about provided tests using reporter-specific format
virtual void listTests(std::vector<TestCaseHandle> const& tests) = 0;
//! Writes out information about the provided tags using reporter-specific format
virtual void listTags(std::vector<TagInfo> const& tags) = 0;
-
};
using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
@@ -2226,6 +2229,10 @@ namespace Catch {
namespace Detail {
using sample = std::vector<double>;
+ // Used when we know we want == comparison of two doubles
+ // to centralize warning suppression
+ bool directCompare( double lhs, double rhs );
+
double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last);
template <typename Iterator>
@@ -2256,7 +2263,7 @@ namespace Catch {
double mean(Iterator first, Iterator last) {
auto count = last - first;
double sum = std::accumulate(first, last, 0.);
- return sum / count;
+ return sum / static_cast<double>(count);
}
template <typename Estimator, typename Iterator>
@@ -2302,15 +2309,17 @@ namespace Catch {
});
double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));
- int n = static_cast<int>(resample.size());
+ 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 (prob_n == 0) return { point, point, point, confidence_level };
+ if ( 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 ) -> int {
+ auto cumn = [n]( double x ) -> long {
return std::lround( normal_cdf( x ) * n );
};
auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); };
@@ -2318,7 +2327,7 @@ namespace Catch {
double b2 = bias - z1;
double a1 = a(b1);
double a2 = a(b2);
- auto lo = static_cast<size_t>((std::max)(cumn(a1), 0));
+ 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 };
@@ -2619,8 +2628,11 @@ namespace Catch {
// sets lambda to be used in fun *and* executes benchmark!
template <typename Fun, std::enable_if_t<!Detail::is_related<Fun, Benchmark>::value, int> = 0>
Benchmark & operator=(Fun func) {
- fun = Detail::BenchmarkFunction(func);
- run();
+ auto const* cfg = getCurrentContext().getConfig();
+ if (!cfg->skipBenchmarks()) {
+ fun = Detail::BenchmarkFunction(func);
+ run();
+ }
return *this;
}
@@ -2679,9 +2691,7 @@ namespace Catch {
template <typename T, bool Destruct>
struct ObjectStorage
{
- using TStorage = std::aligned_storage_t<sizeof(T), std::alignment_of<T>::value>;
-
- ObjectStorage() : data() {}
+ ObjectStorage() = default;
ObjectStorage(const ObjectStorage& other)
{
@@ -2690,7 +2700,7 @@ namespace Catch {
ObjectStorage(ObjectStorage&& other)
{
- new(&data) T(CATCH_MOVE(other.stored_object()));
+ new(data) T(CATCH_MOVE(other.stored_object()));
}
~ObjectStorage() { destruct_on_exit<T>(); }
@@ -2698,7 +2708,7 @@ namespace Catch {
template <typename... Args>
void construct(Args&&... args)
{
- new (&data) T(CATCH_FORWARD(args)...);
+ new (data) T(CATCH_FORWARD(args)...);
}
template <bool AllowManualDestruction = !Destruct>
@@ -2710,21 +2720,21 @@ namespace Catch {
private:
// If this is a constructor benchmark, destruct the underlying object
template <typename U>
- void destruct_on_exit(std::enable_if_t<Destruct, U>* = 0) { destruct<true>(); }
+ void destruct_on_exit(std::enable_if_t<Destruct, U>* = nullptr) { destruct<true>(); }
// Otherwise, don't
template <typename U>
- void destruct_on_exit(std::enable_if_t<!Destruct, U>* = 0) { }
+ void destruct_on_exit(std::enable_if_t<!Destruct, U>* = nullptr) { }
T& stored_object() {
- return *static_cast<T*>(static_cast<void*>(&data));
+ return *static_cast<T*>(static_cast<void*>(data));
}
T const& stored_object() const {
- return *static_cast<T*>(static_cast<void*>(&data));
+ return *static_cast<T*>(static_cast<void*>(data));
}
- TStorage data;
+ alignas( T ) unsigned char data[sizeof( T )]{};
};
} // namespace Detail
@@ -4147,6 +4157,7 @@ namespace Catch {
bool listTests = false;
bool listTags = false;
bool listReporters = false;
+ bool listListeners = false;
bool showSuccessfulTests = false;
bool shouldDebugBreak = false;
@@ -4163,6 +4174,7 @@ namespace Catch {
unsigned int shardCount = 1;
unsigned int shardIndex = 0;
+ bool skipBenchmarks = false;
bool benchmarkNoAnalysis = false;
unsigned int benchmarkSamples = 100;
double benchmarkConfidenceInterval = 0.95;
@@ -4197,6 +4209,7 @@ namespace Catch {
bool listTests() const;
bool listTags() const;
bool listReporters() const;
+ bool listListeners() const;
std::vector<ReporterSpec> const& getReporterSpecs() const;
std::vector<ProcessedReporterSpec> const&
@@ -4228,6 +4241,7 @@ namespace Catch {
int abortAfter() const override;
bool showInvisibles() const override;
Verbosity verbosity() const override;
+ bool skipBenchmarks() const override;
bool benchmarkNoAnalysis() const override;
unsigned int benchmarkSamples() const override;
double benchmarkConfidenceInterval() const override;
@@ -6993,6 +7007,7 @@ namespace Catch {
#endif // CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
+
#ifndef CATCH_VERSION_HPP_INCLUDED
#define CATCH_VERSION_HPP_INCLUDED
@@ -7032,7 +7047,7 @@ namespace Catch {
#define CATCH_VERSION_MAJOR 3
#define CATCH_VERSION_MINOR 0
-#define CATCH_VERSION_PATCH 0
+#define CATCH_VERSION_PATCH 1
#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
@@ -7090,10 +7105,30 @@ namespace Catch {
#define CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
+#include <string>
+
namespace Catch {
namespace Generators {
class GeneratorUntypedBase {
+ // Caches result from `toStringImpl`, assume that when it is an
+ // empty string, the cache is invalidated.
+ mutable std::string m_stringReprCache;
+
+ // Counts based on `next` returning true
+ std::size_t m_currentElementIndex = 0;
+
+ /**
+ * Attempts to move the generator to the next element
+ *
+ * Returns true iff the move succeeded (and a valid element
+ * can be retrieved).
+ */
+ virtual bool next() = 0;
+
+ //! Customization point for `currentElementAsString`
+ virtual std::string stringifyImpl() const = 0;
+
public:
GeneratorUntypedBase() = default;
// Generation of copy ops is deprecated (and Clang will complain)
@@ -7103,11 +7138,34 @@ namespace Catch {
virtual ~GeneratorUntypedBase(); // = default;
- // Attempts to move the generator to the next element
- //
- // Returns true iff the move succeeded (and a valid element
- // can be retrieved).
- virtual bool next() = 0;
+ /**
+ * Attempts to move the generator to the next element
+ *
+ * Serves as a non-virtual interface to `next`, so that the
+ * top level interface can provide sanity checking and shared
+ * features.
+ *
+ * As with `next`, returns true iff the move succeeded and
+ * the generator has new valid element to provide.
+ */
+ bool countedNext();
+
+ std::size_t currentElementIndex() const { return m_currentElementIndex; }
+
+ /**
+ * Returns generator's current element as user-friendly string.
+ *
+ * By default returns string equivalent to calling
+ * `Catch::Detail::stringify` on the current element, but generators
+ * can customize their implementation as needed.
+ *
+ * Not thread-safe due to internal caching.
+ *
+ * The returned ref is valid only until the generator instance
+ * is destructed, or it moves onto the next element, whichever
+ * comes first.
+ */
+ StringRef currentElementAsString() const;
};
using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
@@ -7142,6 +7200,10 @@ namespace Detail {
template<typename T>
class IGenerator : public GeneratorUntypedBase {
+ std::string stringifyImpl() const override {
+ return ::Catch::Detail::stringify( get() );
+ }
+
public:
~IGenerator() override = default;
IGenerator() = default;
@@ -7174,7 +7236,7 @@ namespace Detail {
return m_generator->get();
}
bool next() {
- return m_generator->next();
+ return m_generator->countedNext();
}
};
@@ -7641,16 +7703,21 @@ namespace Catch {
namespace Catch {
namespace Generators {
+namespace Detail {
+ // Returns a suitable seed for a random floating generator based off
+ // the primary internal rng. It does so by taking current value from
+ // the rng and returning it as the seed.
+ std::uint32_t getSeed();
+}
template <typename Float>
class RandomFloatingGenerator final : public IGenerator<Float> {
- Catch::SimplePcg32& m_rng;
+ Catch::SimplePcg32 m_rng;
std::uniform_real_distribution<Float> m_dist;
Float m_current_number;
public:
-
- RandomFloatingGenerator(Float a, Float b):
- m_rng(rng()),
+ RandomFloatingGenerator( Float a, Float b, std::uint32_t seed ):
+ m_rng(seed),
m_dist(a, b) {
static_cast<void>(next());
}
@@ -7666,13 +7733,12 @@ public:
template <typename Integer>
class RandomIntegerGenerator final : public IGenerator<Integer> {
- Catch::SimplePcg32& m_rng;
+ Catch::SimplePcg32 m_rng;
std::uniform_int_distribution<Integer> m_dist;
Integer m_current_number;
public:
-
- RandomIntegerGenerator(Integer a, Integer b):
- m_rng(rng()),
+ RandomIntegerGenerator( Integer a, Integer b, std::uint32_t seed ):
+ m_rng(seed),
m_dist(a, b) {