diff options
| author | Martin Hořeňovský | 2022-01-03 23:16:39 +0100 |
|---|---|---|
| committer | Martin Hořeňovský | 2022-01-03 23:16:39 +0100 |
| commit | f4af9f69265d009a457aa99d1075cfba78652a66 (patch) | |
| tree | b80c683490404be8e30ef59ecacae971917dc722 | |
| parent | 57c9c935ee32538b706c79793116922c4481f0c5 (diff) | |
| download | catch3-3.0.0-preview4.tar.gz | |
Bump version to v3.0.0 preview 4v3.0.0-preview4
| -rw-r--r-- | extras/catch_amalgamated.cpp | 3021 | ||||
| -rw-r--r-- | extras/catch_amalgamated.hpp | 3337 | ||||
| -rw-r--r-- | src/catch2/catch_version.cpp | 2 |
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}" } |