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

summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMartin Hořeňovský2022-01-03 23:16:39 +0100
committerMartin Hořeňovský2022-01-03 23:16:39 +0100
commitf4af9f69265d009a457aa99d1075cfba78652a66 (patch)
treeb80c683490404be8e30ef59ecacae971917dc722
parent57c9c935ee32538b706c79793116922c4481f0c5 (diff)
downloadcatch3-3.0.0-preview4.tar.gz
Bump version to v3.0.0 preview 4v3.0.0-preview4
-rw-r--r--extras/catch_amalgamated.cpp3021
-rw-r--r--extras/catch_amalgamated.hpp3337
-rw-r--r--src/catch2/catch_version.cpp2
3 files changed, 3762 insertions, 2598 deletions
diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp
index b67149f0..e42faf64 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.3
-// Generated: 2020-10-08 13:59:26.616931
+// Catch v3.0.0-preview.4
+// Generated: 2022-01-03 23:14:23.198909
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -33,8 +33,8 @@ namespace {
using Catch::Benchmark::Detail::sample;
template <typename URng, typename Estimator>
- sample resample(URng& rng, int resamples, std::vector<double>::iterator first, std::vector<double>::iterator last, Estimator& estimator) {
- auto n = last - first;
+ sample resample(URng& rng, unsigned int resamples, std::vector<double>::iterator first, std::vector<double>::iterator last, Estimator& estimator) {
+ auto n = static_cast<size_t>(last - first);
std::uniform_int_distribution<decltype(n)> dist(0, n - 1);
sample out;
@@ -42,7 +42,7 @@ using Catch::Benchmark::Detail::sample;
std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] {
std::vector<double> resampled;
resampled.reserve(n);
- std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; });
+ std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[static_cast<std::ptrdiff_t>(dist(rng))]; });
return estimator(resampled.begin(), resampled.end());
});
std::sort(out.begin(), out.end());
@@ -179,7 +179,7 @@ namespace Catch {
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 sg = (std::min)(mg_min / 4., sb / std::sqrt(n));
double sg2 = sg * sg;
double sb2 = sb * sb;
@@ -190,7 +190,7 @@ namespace Catch {
double k0 = -n * nd;
double k1 = sb2 - n * sg2 + nd;
double det = k1 * k1 - 4 * sg2 * k0;
- return (int)(-2. * k0 / (k1 + std::sqrt(det)));
+ return static_cast<int>(-2. * k0 / (k1 + std::sqrt(det)));
};
auto var_out = [n, sb2, sg2](double c) {
@@ -198,11 +198,11 @@ namespace Catch {
return (nc / n) * (sb2 - nc * sg2);
};
- return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2;
+ return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2;
}
- bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) {
+ 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;
@@ -289,25 +289,6 @@ namespace Catch {
} // namespace Catch
-////////////////////////////////////////////////
-// vvv formerly catch_complete_invoke.cpp vvv //
-////////////////////////////////////////////////
-
-
-namespace Catch {
- namespace Benchmark {
- namespace Detail {
- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
- const std::string benchmarkErrorMsg = "a benchmark failed to run successfully";
- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
- } // namespace Detail
- } // namespace Benchmark
-} // namespace Catch
-
-
-
-
/////////////////////////////////////////////////
// vvv formerly catch_run_for_at_least.cpp vvv //
/////////////////////////////////////////////////
@@ -351,7 +332,7 @@ bool marginComparison(double lhs, double rhs, double margin) {
namespace Catch {
Approx::Approx ( double value )
- : m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
+ : m_epsilon( std::numeric_limits<float>::epsilon()*100. ),
m_margin( 0.0 ),
m_scale( 0.0 ),
m_value( value )
@@ -495,7 +476,7 @@ namespace Catch {
: expr;
}
- std::string AssertionResult::getMessage() const {
+ StringRef AssertionResult::getMessage() const {
return m_resultData.message;
}
SourceLineInfo AssertionResult::getSourceInfo() const {
@@ -510,13 +491,39 @@ namespace Catch {
+#include <ostream>
namespace Catch {
+ namespace Detail {
+ namespace {
+ class RDBufStream : public IStream {
+ mutable std::ostream m_os;
- Config::Config( ConfigData const& data )
- : m_data( data ),
- m_stream( openStream() )
- {
+ public:
+ //! The streambuf `sb` must outlive the constructed object.
+ RDBufStream( std::streambuf* sb ): m_os( sb ) {}
+ ~RDBufStream() override = default;
+
+ public: // IStream
+ std::ostream& stream() const override { return m_os; }
+ };
+ } // unnamed namespace
+ } // namespace Detail
+
+ std::ostream& operator<<( std::ostream& os,
+ ConfigData::ReporterAndFile const& reporter ) {
+ os << "{ " << reporter.reporterName << ", ";
+ if ( reporter.outputFileName ) {
+ os << *reporter.outputFileName;
+ } else {
+ os << "<default-output>";
+ }
+ return os << " }";
+ }
+
+ Config::Config( ConfigData const& data ):
+ m_data( data ),
+ m_defaultStream( openStream( data.defaultOutputFilename ) ) {
// We need to trim filter specs to avoid trouble with superfluous
// whitespace (esp. important for bdd macros, as those are manually
// aligned with whitespace).
@@ -536,25 +543,37 @@ namespace Catch {
}
}
m_testSpec = parser.testSpec();
+
+ m_reporterStreams.reserve( m_data.reporterSpecifications.size() );
+ for ( auto const& reporterAndFile : m_data.reporterSpecifications ) {
+ if ( reporterAndFile.outputFileName.none() ) {
+ m_reporterStreams.emplace_back( new Detail::RDBufStream(
+ m_defaultStream->stream().rdbuf() ) );
+ } else {
+ m_reporterStreams.emplace_back(
+ openStream( *reporterAndFile.outputFileName ) );
+ }
+ }
}
Config::~Config() = default;
- std::string const& Config::getFilename() const {
- return m_data.outputFilename ;
- }
-
bool Config::listTests() const { return m_data.listTests; }
bool Config::listTags() const { return m_data.listTags; }
bool Config::listReporters() const { return m_data.listReporters; }
- std::string Config::getProcessName() const { return m_data.processName; }
- std::string const& Config::getReporterName() const { return m_data.reporterName; }
-
std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
+ std::vector<ConfigData::ReporterAndFile> const& Config::getReportersAndOutputFiles() const {
+ return m_data.reporterSpecifications;
+ }
+
+ std::ostream& Config::getReporterOutputStream(std::size_t reporterIdx) const {
+ return m_reporterStreams.at(reporterIdx)->stream();
+ }
+
TestSpec const& Config::testSpec() const { return m_testSpec; }
bool Config::hasTestFilters() const { return m_hasTestFilters; }
@@ -562,15 +581,22 @@ namespace Catch {
// IConfig interface
bool Config::allowThrows() const { return !m_data.noThrow; }
- std::ostream& Config::stream() const { return m_stream->stream(); }
- std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
+ std::ostream& Config::defaultStream() const { return m_defaultStream->stream(); }
+ 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::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); }
+ 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; }
- unsigned int Config::rngSeed() const { return m_data.rngSeed; }
+ 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; }
UseColour Config::useColour() const { return m_data.useColour; }
bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
int Config::abortAfter() const { return m_data.abortAfter; }
@@ -578,13 +604,13 @@ namespace Catch {
Verbosity Config::verbosity() const { return m_data.verbosity; }
bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
- int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
+ 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); }
- IStream const* Config::openStream() {
- return Catch::makeStream(m_data.outputFilename);
+ Detail::unique_ptr<IStream const> Config::openStream(std::string const& outputFileName) {
+ return Catch::makeStream(outputFileName);
}
} // end namespace Catch
@@ -598,13 +624,6 @@ namespace Catch {
////////////////////////////////////////////////////////////////////////////
- Catch::MessageBuilder::MessageBuilder( StringRef const& macroName,
- SourceLineInfo const& lineInfo,
- ResultWas::OfType type )
- :m_info(macroName, lineInfo, type) {}
-
- ////////////////////////////////////////////////////////////////////////////
-
ScopedMessage::ScopedMessage( MessageBuilder const& builder ):
m_info( builder.m_info ) {
@@ -613,7 +632,7 @@ namespace Catch {
}
ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
- m_info( std::move( old.m_info ) ) {
+ m_info( CATCH_MOVE( old.m_info ) ) {
old.m_moved = true;
}
@@ -729,16 +748,16 @@ namespace Catch {
public: // IMutableRegistryHub
void registerReporter( std::string const& name, IReporterFactoryPtr factory ) override {
- m_reporterRegistry.registerReporter( name, std::move(factory) );
+ m_reporterRegistry.registerReporter( name, CATCH_MOVE(factory) );
}
void registerListener( IReporterFactoryPtr factory ) override {
- m_reporterRegistry.registerListener( std::move(factory) );
+ m_reporterRegistry.registerListener( CATCH_MOVE(factory) );
}
void registerTest( Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker ) override {
- m_testCaseRegistry.registerTest( std::move(testInfo), std::move(invoker) );
+ m_testCaseRegistry.registerTest( CATCH_MOVE(testInfo), CATCH_MOVE(invoker) );
}
- void registerTranslator( const IExceptionTranslator* translator ) override {
- m_exceptionTranslatorRegistry.registerTranslator( translator );
+ void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& 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 );
@@ -786,6 +805,7 @@ namespace Catch {
#include <algorithm>
+#include <cassert>
#include <iomanip>
#include <set>
@@ -794,31 +814,35 @@ namespace Catch {
namespace {
const int MaxExitCode = 255;
- IStreamingReporterPtr createReporter(std::string const& reporterName, IConfig const* config) {
+ IStreamingReporterPtr createReporter(std::string const& reporterName, ReporterConfig const& config) {
auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config);
- CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'");
+ CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << '\'');
return reporter;
}
IStreamingReporterPtr makeReporter(Config const* config) {
- if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {
- return createReporter(config->getReporterName(), config);
+ if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()
+ && config->getReportersAndOutputFiles().size() == 1) {
+ auto& stream = config->getReporterOutputStream(0);
+ return createReporter(config->getReportersAndOutputFiles()[0].reporterName, ReporterConfig(config, stream));
}
- // On older platforms, returning unique_ptr<ListeningReporter>
- // when the return type is unique_ptr<IStreamingReporter>
- // doesn't compile without a std::move call. However, this causes
- // a warning on newer platforms. Thus, we have to work around
- // it a bit and downcast the pointer manually.
- auto ret = Detail::unique_ptr<IStreamingReporter>(new ListeningReporter);
- auto& multi = static_cast<ListeningReporter&>(*ret);
+ auto multi = Detail::make_unique<ListeningReporter>(config);
+
auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
for (auto const& listener : listeners) {
- multi.addListener(listener->create(Catch::ReporterConfig(config)));
+ multi->addListener(listener->create(Catch::ReporterConfig(config, config->defaultStream())));
}
- multi.addReporter(createReporter(config->getReporterName(), config));
- return ret;
+
+ std::size_t reporterIdx = 0;
+ for (auto const& reporterAndFile : config->getReportersAndOutputFiles()) {
+ auto& stream = config->getReporterOutputStream(reporterIdx);
+ multi->addReporter(createReporter(reporterAndFile.reporterName, ReporterConfig(config, stream)));
+ reporterIdx++;
+ }
+
+ return multi;
}
class TestGroup {
@@ -826,26 +850,33 @@ namespace Catch {
explicit TestGroup(IStreamingReporterPtr&& reporter, Config const* config):
m_reporter(reporter.get()),
m_config{config},
- m_context{config, std::move(reporter)} {
+ m_context{config, CATCH_MOVE(reporter)} {
- auto const& allTestCases = getAllTestCasesSorted(*m_config);
- m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);
- auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
+ assert( m_config->testSpec().getInvalidSpecs().empty() &&
+ "Invalid test specs should be handled before running tests" );
- if (m_matches.empty() && invalidArgs.empty()) {
- for (auto const& test : allTestCases)
- if (!test.getTestCaseInfo().isHidden())
- m_tests.emplace(&test);
+ 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 {
- for (auto const& match : m_matches)
- m_tests.insert(match.tests.begin(), match.tests.end());
+ 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() {
- auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
Totals totals;
- m_context.testGroupStarting(m_config->name(), 1, 1);
for (auto const& testCase : m_tests) {
if (!m_context.aborting())
totals += m_context.runTest(*testCase);
@@ -855,28 +886,26 @@ namespace Catch {
for (auto const& match : m_matches) {
if (match.tests.empty()) {
- m_reporter->noMatchingTestCases(match.name);
- totals.error = -1;
+ m_unmatchedTestSpecs = true;
+ m_reporter->noMatchingTestCases( match.name );
}
}
- if (!invalidArgs.empty()) {
- for (auto const& invalidArg: invalidArgs)
- m_reporter->reportInvalidArguments(invalidArg);
- }
-
- m_context.testGroupEnded(m_config->name(), totals, 1, 1);
return totals;
}
- private:
- using Tests = std::set<TestCaseHandle const*>;
+ bool hadUnmatchedTestSpecs() const {
+ return m_unmatchedTestSpecs;
+ }
+
+ private:
IStreamingReporter* m_reporter;
Config const* m_config;
RunContext m_context;
- Tests m_tests;
+ std::set<TestCaseHandle const*> m_tests;
TestSpec::Matches m_matches;
+ bool m_unmatchedTestSpecs = false;
};
void applyFilenamesAsTags() {
@@ -924,16 +953,16 @@ namespace Catch {
void Session::showHelp() const {
Catch::cout()
- << "\nCatch v" << libraryVersion() << "\n"
- << m_cli << std::endl
- << "For more detailed usage please see the project docs\n" << std::endl;
+ << "\nCatch 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: " << "Catch Test\n"
- << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
+ << std::left << std::setw(16) << "version: " << libraryVersion() << '\n' << std::flush;
}
int Session::applyCommandLine( int argc, char const * const * argv ) {
@@ -941,6 +970,7 @@ namespace Catch {
return 1;
auto result = m_cli.parse( Clara::Args( argc, argv ) );
+
if( !result ) {
config();
getCurrentMutableContext().setConfig(m_config.get());
@@ -949,7 +979,7 @@ namespace Catch {
<< "\nError(s) in input:\n"
<< TextFlow::Column( result.errorMessage() ).indent( 2 )
<< "\n\n";
- Catch::cerr() << "Run with -? for usage\n" << std::endl;
+ Catch::cerr() << "Run with -? for usage\n\n" << std::flush;
return MaxExitCode;
}
@@ -957,6 +987,7 @@ namespace Catch {
showHelp();
if( m_configData.libIdentify )
libIdentify();
+
m_config.reset();
return 0;
}
@@ -992,12 +1023,12 @@ namespace Catch {
int Session::run() {
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
- Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
+ Catch::cout() << "...waiting for enter/ return before starting\n" << std::flush;
static_cast<void>(std::getchar());
}
int exitCode = runInternal();
if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
- Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
+ Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << '\n' << std::flush;
static_cast<void>(std::getchar());
}
return exitCode;
@@ -1026,6 +1057,14 @@ namespace Catch {
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 1;
+ }
+
CATCH_TRY {
config(); // Force config to be constructed
@@ -1041,16 +1080,32 @@ namespace Catch {
// Create reporter(s) so we can route listings through them
auto reporter = makeReporter(m_config.get());
+ auto const& invalidSpecs = m_config->testSpec().getInvalidSpecs();
+ if ( !invalidSpecs.empty() ) {
+ for ( auto const& spec : invalidSpecs ) {
+ reporter->reportInvalidTestSpec( spec );
+ }
+ return 1;
+ }
+
+
// Handle list request
if (list(*reporter, *m_config)) {
return 0;
}
- TestGroup tests { std::move(reporter), m_config.get() };
+ TestGroup tests { CATCH_MOVE(reporter), m_config.get() };
auto const totals = tests.execute();
- if( m_config->warnAboutNoTests() && totals.error == -1 )
+ if ( tests.hadUnmatchedTestSpecs()
+ && m_config->warnAboutUnmatchedTestSpecs() ) {
+ return 3;
+ }
+
+ if ( totals.testCases.total() == 0
+ && !m_config->zeroTestsCountAsSuccess() ) {
return 2;
+ }
// Note that on unices only the lower 8 bits are usually used, clamping
// the return value to 255 prevents false negative when some multiple
@@ -1059,7 +1114,7 @@ namespace Catch {
}
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
catch( std::exception& ex ) {
- Catch::cerr() << ex.what() << std::endl;
+ Catch::cerr() << ex.what() << '\n' << std::flush;
return MaxExitCode;
}
#endif
@@ -1159,16 +1214,25 @@ namespace Catch {
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<TestCaseInfo>
- makeTestCaseInfo(std::string const& _className,
+ makeTestCaseInfo(StringRef _className,
NameAndTags const& nameAndTags,
SourceLineInfo const& _lineInfo ) {
return Detail::make_unique<TestCaseInfo>(_className, nameAndTags, _lineInfo);
}
- TestCaseInfo::TestCaseInfo(std::string const& _className,
+ TestCaseInfo::TestCaseInfo(StringRef _className,
NameAndTags const& _nameAndTags,
SourceLineInfo const& _lineInfo):
name( _nameAndTags.name.empty() ? makeDefaultName() : _nameAndTags.name ),
@@ -1180,7 +1244,6 @@ namespace Catch {
// (including optional hidden tag and filename tag)
auto requiredSize = originalTags.size() + sizeOfExtraTags(_lineInfo.file);
backingTags.reserve(requiredSize);
- backingLCaseTags.reserve(requiredSize);
// We cannot copy the tags directly, as we need to normalize
// some tags, so that [.foo] is copied as [.][foo].
@@ -1204,6 +1267,7 @@ namespace Catch {
// 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(), "Empty tags are not allowed");
enforceNotReservedTag(tagStr, lineInfo);
properties |= parseSpecialTag(tagStr);
// When copying a tag to the backing storage, we need to
@@ -1225,9 +1289,8 @@ namespace Catch {
}
// Sort and prepare tags
- toLowerInPlace(backingLCaseTags);
- std::sort(begin(tags), end(tags), [](Tag lhs, Tag rhs) { return lhs.lowerCased < rhs.lowerCased; });
- tags.erase(std::unique(begin(tags), end(tags), [](Tag lhs, Tag rhs) {return lhs.lowerCased == rhs.lowerCased; }),
+ std::sort(begin(tags), end(tags));
+ tags.erase(std::unique(begin(tags), end(tags)),
end(tags));
}
@@ -1273,24 +1336,22 @@ namespace Catch {
backingTags += tagStr;
const auto backingEnd = backingTags.size();
backingTags += ']';
- backingLCaseTags += '[';
- // We append the tag to the lower-case backing storage as-is,
- // because we will perform the lower casing later, in bulk
- backingLCaseTags += tagStr;
- backingLCaseTags += ']';
- tags.emplace_back(StringRef(backingTags.c_str() + backingStart, backingEnd - backingStart),
- StringRef(backingLCaseTags.c_str() + backingStart, backingEnd - backingStart));
- }
-
-
- bool TestCaseHandle::operator == ( TestCaseHandle const& rhs ) const {
- return m_invoker == rhs.m_invoker
- && m_info->name == rhs.m_info->name
- && m_info->className == rhs.m_info->className;
+ tags.emplace_back(StringRef(backingTags.c_str() + backingStart, backingEnd - backingStart));
}
- bool TestCaseHandle::operator < ( TestCaseHandle const& rhs ) const {
- return m_info->name < rhs.m_info->name;
+ 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;
}
TestCaseInfo const& TestCaseHandle::getTestCaseInfo() const {
@@ -1330,15 +1391,13 @@ namespace Catch {
TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
: Pattern( filterString )
- , m_tag( toLower( tag ) )
+ , m_tag( tag )
{}
bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
- return std::find_if(begin(testCase.tags),
- end(testCase.tags),
- [&](Tag const& tag) {
- return tag.lowerCased == m_tag;
- }) != end(testCase.tags);
+ return std::find( begin( testCase.tags ),
+ end( testCase.tags ),
+ Tag( m_tag ) ) != end( testCase.tags );
}
bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
@@ -1390,8 +1449,8 @@ namespace Catch {
return matches;
}
- const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{
- return (m_invalidArgs);
+ const TestSpec::vectorStrings& TestSpec::getInvalidSpecs() const {
+ return m_invalidSpecs;
}
}
@@ -1400,49 +1459,13 @@ namespace Catch {
#include <chrono>
-static const uint64_t nanosecondsInSecond = 1000000000;
-
namespace Catch {
- auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
- return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
- }
-
namespace {
- auto estimateClockResolution() -> uint64_t {
- uint64_t sum = 0;
- static const uint64_t iterations = 1000000;
-
- auto startTime = getCurrentNanosecondsSinceEpoch();
-
- for( std::size_t i = 0; i < iterations; ++i ) {
-
- uint64_t ticks;
- uint64_t baseTicks = getCurrentNanosecondsSinceEpoch();
- do {
- ticks = getCurrentNanosecondsSinceEpoch();
- } while( ticks == baseTicks );
-
- auto delta = ticks - baseTicks;
- sum += delta;
-
- // If we have been calibrating for over 3 seconds -- the clock
- // is terrible and we should move on.
- // TBD: How to signal that the measured resolution is probably wrong?
- if (ticks > startTime + 3 * nanosecondsInSecond) {
- return sum / ( i + 1u );
- }
- }
-
- // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers
- // - and potentially do more iterations if there's a high variance.
- return sum/iterations;
+ static auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
}
- }
- auto getEstimatedClockResolution() -> uint64_t {
- static auto s_resolution = estimateClockResolution();
- return s_resolution;
- }
+ } // end unnamed namespace
void Timer::start() {
m_nanoseconds = getCurrentNanosecondsSinceEpoch();
@@ -1464,12 +1487,6 @@ namespace Catch {
} // namespace Catch
-#if defined(__clang__)
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wexit-time-destructors"
-# pragma clang diagnostic ignored "-Wglobal-constructors"
-#endif
-
#include <cmath>
@@ -1479,8 +1496,6 @@ namespace Catch {
namespace Detail {
- const std::string unprintableString = "{?}";
-
namespace {
const int hexThreshold = 255;
@@ -1517,6 +1532,48 @@ namespace Detail {
}
} // end unnamed namespace
+ std::string convertIntoString(StringRef string, bool escape_invisibles) {
+ 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 (!escape_invisibles) {
+ 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<int>( size ), inc = 1;
@@ -1543,44 +1600,25 @@ namespace Detail {
//// ======================================================= ////
std::string StringMaker<std::string>::convert(const std::string& str) {
- if (!getCurrentContext().getConfig()->showInvisibles()) {
- return '"' + str + '"';
- }
-
- std::string s("\"");
- for (char c : str) {
- switch (c) {
- case '\n':
- s.append("\\n");
- break;
- case '\t':
- s.append("\\t");
- break;
- default:
- s.push_back(c);
- break;
- }
- }
- s.append("\"");
- return s;
+ return Detail::convertIntoString( str );
}
#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
std::string StringMaker<std::string_view>::convert(std::string_view str) {
- return ::Catch::Detail::stringify(std::string{ str });
+ return Detail::convertIntoString( StringRef( str.data(), str.size() ) );
}
#endif
std::string StringMaker<char const*>::convert(char const* str) {
if (str) {
- return ::Catch::Detail::stringify(std::string{ str });
+ return Detail::convertIntoString( str );
} else {
return{ "{null string}" }