diff --git a/CMakeLists.txt b/CMakeLists.txt index 549ee178..e2329c69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ if(NOT DEFINED PROJECT_NAME) set(NOT_SUBPROJECT ON) endif() -project(Catch2 LANGUAGES CXX VERSION 2.7.1) +project(Catch2 LANGUAGES CXX VERSION 2.7.2) # Provide path for scripts list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake") diff --git a/README.md b/README.md index a09ad44b..535ac6ec 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ [![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2) [![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2) [![codecov](https://codecov.io/gh/catchorg/Catch2/branch/master/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2) -[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/ZFBZ5XbLA9F1gzKi) +[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/rsEsNO9M0flb5NlQ) [![Join the chat in Discord: https://discord.gg/4CWS9zD](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/4CWS9zD) -The latest version of the single header can be downloaded directly using this link +The latest version of the single header can be downloaded directly using this link ## Catch2 is released! diff --git a/docs/release-notes.md b/docs/release-notes.md index 528f6cf1..c5f92d2b 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ # Release notes **Contents**
+[2.7.2](#272)
[2.7.1](#271)
[2.7.0](#270)
[2.6.1](#261)
@@ -22,6 +23,28 @@ [Older versions](#older-versions)
[Even Older versions](#even-older-versions)
+ +## 2.7.2 + +### Improvements +* Added an approximate vector matcher (#1499) + +### Fixes +* Filters will no longer be shown if there were none +* Fixed compilation error when using Homebrew GCC on OS X (#1588, #1589) +* Fixed the console reporter not showing messages that start with a newline (#1455, #1470) +* Modified JUnit reporter's output so that rng seed and filters are reported according to the JUnit schema (#1598) +* Fixed some obscure warnings and static analysis passes + +### Miscellaneous +* Various improvements to `ParseAndAddCatchTests` (#1559, #1601) + * When a target is parsed, it receives `ParseAndAddCatchTests_TESTS` property which summarizes found tests + * Fixed problem with tests not being found if the `OptionalCatchTestLauncher` variables is used + * Including the script will no longer forcefully modify `CMAKE_MINIMUM_REQUIRED_VERSION` + * CMake object libraries are ignored when parsing to avoid needless warnings +* `CatchAddTests` now adds test's tags to their CTest labels (#1600) +* Added basic CPack support to our build + ## 2.7.1 ### Improvements diff --git a/include/catch.hpp b/include/catch.hpp index 5ee7ffdd..5667def9 100644 --- a/include/catch.hpp +++ b/include/catch.hpp @@ -11,7 +11,7 @@ #define CATCH_VERSION_MAJOR 2 #define CATCH_VERSION_MINOR 7 -#define CATCH_VERSION_PATCH 1 +#define CATCH_VERSION_PATCH 2 #ifdef __clang__ # pragma clang system_header diff --git a/include/internal/catch_version.cpp b/include/internal/catch_version.cpp index 43832053..5f4917c1 100644 --- a/include/internal/catch_version.cpp +++ b/include/internal/catch_version.cpp @@ -37,7 +37,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 7, 1, "", 0 ); + static Version version( 2, 7, 2, "", 0 ); return version; } diff --git a/single_include/catch2/catch.hpp b/single_include/catch2/catch.hpp index 98672c07..df14c357 100644 --- a/single_include/catch2/catch.hpp +++ b/single_include/catch2/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v2.7.1 - * Generated: 2019-04-05 18:22:37.720122 + * Catch v2.7.2 + * Generated: 2019-04-22 23:13:14.687465 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. @@ -15,7 +15,7 @@ #define CATCH_VERSION_MAJOR 2 #define CATCH_VERSION_MINOR 7 -#define CATCH_VERSION_PATCH 1 +#define CATCH_VERSION_PATCH 2 #ifdef __clang__ # pragma clang system_header @@ -3113,7 +3113,7 @@ public: // The following functions create the actual matcher objects. // The user has to explicitly specify type to the function, because - // infering std::function is hard (but possible) and + // inferring std::function is hard (but possible) and // requires a lot of TMP. template Generic::PredicateMatcher Predicate(std::function const& predicate, std::string const& description = "") { @@ -3201,28 +3201,6 @@ namespace Catch { namespace Matchers { namespace Vector { - namespace Detail { - template - size_t count(InputIterator first, InputIterator last, T const& item) { - size_t cnt = 0; - for (; first != last; ++first) { - if (*first == item) { - ++cnt; - } - } - return cnt; - } - template - bool contains(InputIterator first, InputIterator last, T const& item) { - for (; first != last; ++first) { - if (*first == item) { - return true; - } - } - return false; - } - } - template struct ContainsElementMatcher : MatcherBase> { @@ -3297,6 +3275,42 @@ namespace Matchers { std::vector const& m_comparator; }; + template + struct ApproxMatcher : MatcherBase> { + + ApproxMatcher(std::vector const& comparator) : m_comparator( comparator ) {} + + bool match(std::vector const &v) const override { + if (m_comparator.size() != v.size()) + return false; + for (std::size_t i = 0; i < v.size(); ++i) + if (m_comparator[i] != approx(v[i])) + return false; + return true; + } + std::string describe() const override { + return "is approx: " + ::Catch::Detail::stringify( m_comparator ); + } + template ::value>::type> + ApproxMatcher& epsilon( T const& newEpsilon ) { + approx.epsilon(newEpsilon); + return *this; + } + template ::value>::type> + ApproxMatcher& margin( T const& newMargin ) { + approx.margin(newMargin); + return *this; + } + template ::value>::type> + ApproxMatcher& scale( T const& newScale ) { + approx.scale(newScale); + return *this; + } + + std::vector const& m_comparator; + mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom(); + }; + template struct UnorderedEqualsMatcher : MatcherBase> { UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} @@ -3306,28 +3320,7 @@ namespace Matchers { if (m_target.size() != vec.size()) { return false; } - auto lfirst = m_target.begin(), llast = m_target.end(); - auto rfirst = vec.begin(), rlast = vec.end(); - // Cut common prefix to optimize checking of permuted parts - while (lfirst != llast && *lfirst == *rfirst) { - ++lfirst; ++rfirst; - } - if (lfirst == llast) { - return true; - } - - for (auto mid = lfirst; mid != llast; ++mid) { - // Skip already counted items - if (Detail::contains(lfirst, mid, *mid)) { - continue; - } - size_t num_vec = Detail::count(rfirst, rlast, *mid); - if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { - return false; - } - } - - return true; + return std::is_permutation(m_target.begin(), m_target.end(), vec.begin()); } std::string describe() const override { @@ -3357,6 +3350,11 @@ namespace Matchers { return Vector::EqualsMatcher( comparator ); } + template + Vector::ApproxMatcher Approx( std::vector const& comparator ) { + return Vector::ApproxMatcher( comparator ); + } + template Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { return Vector::UnorderedEqualsMatcher(target); @@ -4535,7 +4533,7 @@ namespace Catch { public: NamePattern( std::string const& name ); virtual ~NamePattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; + bool matches( TestCaseInfo const& testCase ) const override; private: WildcardPattern m_wildcardPattern; }; @@ -4544,7 +4542,7 @@ namespace Catch { public: TagPattern( std::string const& tag ); virtual ~TagPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; + bool matches( TestCaseInfo const& testCase ) const override; private: std::string m_tag; }; @@ -4553,7 +4551,7 @@ namespace Catch { public: ExcludedPattern( PatternPtr const& underlyingPattern ); virtual ~ExcludedPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; + bool matches( TestCaseInfo const& testCase ) const override; private: PatternPtr m_underlyingPattern; }; @@ -4728,7 +4726,7 @@ namespace Catch { std::vector const& getTestsOrTags() const override; std::vector const& getSectionsToRun() const override; - virtual TestSpec const& testSpec() const override; + TestSpec const& testSpec() const override; bool hasTestFilters() const override; bool showHelp() const; @@ -5419,11 +5417,11 @@ namespace Catch { class ReporterFactory : public IReporterFactory { - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { + IStreamingReporterPtr create( ReporterConfig const& config ) const override { return std::unique_ptr( new T( config ) ); } - virtual std::string getDescription() const override { + std::string getDescription() const override { return T::getDescription(); } }; @@ -5440,10 +5438,10 @@ namespace Catch { class ListenerFactory : public IReporterFactory { - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { + IStreamingReporterPtr create( ReporterConfig const& config ) const override { return std::unique_ptr( new T( config ) ); } - virtual std::string getDescription() const override { + std::string getDescription() const override { return std::string(); } }; @@ -5844,8 +5842,6 @@ namespace TestCaseTracking { public: - static TrackerContext& instance(); - ITracker& startRun(); void endRun(); @@ -5991,18 +5987,18 @@ namespace Detail { return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); } - void Approx::setMargin(double margin) { - CATCH_ENFORCE(margin >= 0, - "Invalid Approx::margin: " << margin << '.' + void Approx::setMargin(double newMargin) { + CATCH_ENFORCE(newMargin >= 0, + "Invalid Approx::margin: " << newMargin << '.' << " Approx::Margin has to be non-negative."); - m_margin = margin; + m_margin = newMargin; } - void Approx::setEpsilon(double epsilon) { - CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0, - "Invalid Approx::epsilon: " << epsilon << '.' + void Approx::setEpsilon(double newEpsilon) { + CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0, + "Invalid Approx::epsilon: " << newEpsilon << '.' << " Approx::epsilon has to be in [0, 1]"); - m_epsilon = epsilon; + m_epsilon = newEpsilon; } } // end namespace Detail @@ -6638,6 +6634,9 @@ public: m_suffix = false; auto width = m_column.m_width - indent(); m_end = m_pos; + if (line()[m_pos] == '\n') { + ++m_end; + } while (m_end < line().size() && line()[m_end] != '\n') ++m_end; @@ -8042,10 +8041,7 @@ namespace Catch { m_stream( openStream() ) { TestSpecParser parser(ITagAliasRegistry::get()); - if (data.testsOrTags.empty()) { - parser.parse("~[.]"); // All not hidden tests - } - else { + if (!data.testsOrTags.empty()) { m_hasTestFilters = true; for( auto const& testOrTags : data.testsOrTags ) parser.parse( testOrTags ); @@ -8163,7 +8159,7 @@ namespace { originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); } - virtual void use( Colour::Code _colourCode ) override { + void use( Colour::Code _colourCode ) override { switch( _colourCode ) { case Colour::None: return setTextAttribute( originalForegroundAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); @@ -8226,7 +8222,7 @@ namespace { // https://github.com/philsquared/Catch/pull/131 class PosixColourImpl : public IColourImpl { public: - virtual void use( Colour::Code _colourCode ) override { + void use( Colour::Code _colourCode ) override { switch( _colourCode ) { case Colour::None: case Colour::White: return setColour( "[0m" ); @@ -8337,27 +8333,27 @@ namespace Catch { class Context : public IMutableContext, NonCopyable { public: // IContext - virtual IResultCapture* getResultCapture() override { + IResultCapture* getResultCapture() override { return m_resultCapture; } - virtual IRunner* getRunner() override { + IRunner* getRunner() override { return m_runner; } - virtual IConfigPtr const& getConfig() const override { + IConfigPtr const& getConfig() const override { return m_config; } - virtual ~Context() override; + ~Context() override; public: // IMutableContext - virtual void setResultCapture( IResultCapture* resultCapture ) override { + void setResultCapture( IResultCapture* resultCapture ) override { m_resultCapture = resultCapture; } - virtual void setRunner( IRunner* runner ) override { + void setRunner( IRunner* runner ) override { m_runner = runner; } - virtual void setConfig( IConfigPtr const& config ) override { + void setConfig( IConfigPtr const& config ) override { m_config = config; } @@ -8423,19 +8419,23 @@ namespace Catch { # include # include # include -# include # include # include -namespace Catch { +#ifdef __apple_build_version__ + // These headers will only compile with AppleClang (XCode) + // For other compilers (Clang, GCC, ... ) we need to exclude them +# include +#endif + namespace Catch { + #ifdef __apple_build_version__ // The following function is taken directly from the following technical note: - // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + // https://developer.apple.com/library/archive/qa/qa1361/_index.html // Returns true if the current process is being debugged (either // running under the debugger or has a debugger attached post facto). bool isDebuggerActive(){ - int mib[4]; struct kinfo_proc info; std::size_t size; @@ -8465,6 +8465,12 @@ namespace Catch { return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); } + #else + bool isDebuggerActive() { + // We need to find another way to determine this for non-appleclang compilers on macOS + return false; + } + #endif } // namespace Catch #elif defined(CATCH_PLATFORM_LINUX) @@ -8569,7 +8575,7 @@ namespace Catch { public: ~ExceptionTranslatorRegistry(); virtual void registerTranslator( const IExceptionTranslator* translator ); - virtual std::string translateActiveException() const override; + std::string translateActiveException() const override; std::string tryTranslators() const; private: @@ -9842,7 +9848,7 @@ namespace Catch { if (strerror_s(buffer, errno)) { CATCH_RUNTIME_ERROR("Could not translate errno to a string"); } - CATCH_RUNTIME_ERROR("Coul dnot open the temp file: '" << m_buffer << "' because: " << buffer); + CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer); } } #else @@ -10920,7 +10926,10 @@ namespace Catch { auto const& allTestCases = getAllTestCasesSorted(*config); for (auto const& testCase : allTestCases) { - if (!context.aborting() && matchTest(testCase, testSpec, *config)) + bool matching = (!testSpec.hasFilters() && !testCase.isHidden()) || + (testSpec.hasFilters() && matchTest(testCase, testSpec, *config)); + + if (!context.aborting() && matching) totals += context.runTest(testCase); else context.reporter().skipTest(testCase); @@ -11646,7 +11655,7 @@ namespace Catch { void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { CATCH_ENFORCE( !isReservedTag(tag), "Tag name: [" << tag << "] is not allowed.\n" - << "Tag names starting with non alpha-numeric characters are reserved\n" + << "Tag names starting with non alphanumeric characters are reserved\n" << _lineInfo ); } } @@ -11828,9 +11837,12 @@ namespace Catch { std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { std::vector filtered; filtered.reserve( testCases.size() ); - for( auto const& testCase : testCases ) - if( matchTest( testCase, testSpec, config ) ) - filtered.push_back( testCase ); + for (auto const& testCase : testCases) { + if ((!testSpec.hasFilters() && !testCase.isHidden()) || + (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) { + filtered.push_back(testCase); + } + } return filtered; } std::vector const& getAllTestCasesSorted( IConfig const& config ) { @@ -11906,11 +11918,6 @@ namespace TestCaseTracking { ITracker::~ITracker() = default; - TrackerContext& TrackerContext::instance() { - static TrackerContext s_instance; - return s_instance; - } - ITracker& TrackerContext::startRun() { m_rootTracker = std::make_shared( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); m_currentTracker = nullptr; @@ -12692,7 +12699,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 7, 1, "", 0 ); + static Version version( 2, 7, 2, "", 0 ); return version; } @@ -14051,22 +14058,6 @@ namespace Catch { void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { CumulativeReporterBase::testRunStarting( runInfo ); xml.startElement( "testsuites" ); - - if ( m_config->hasTestFilters() || m_config->rngSeed() != 0 ) - xml.startElement("properties"); - - if ( m_config->hasTestFilters() ) { - xml.scopedElement( "property" ) - .writeAttribute( "name" , "filters" ) - .writeAttribute( "value" , serializeFilters( m_config->getTestsOrTags() ) ); - } - - if( m_config->rngSeed() != 0 ) { - xml.scopedElement( "property" ) - .writeAttribute( "name", "random-seed" ) - .writeAttribute( "value", m_config->rngSeed() ); - xml.endElement(); - } } void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { @@ -14105,6 +14096,7 @@ namespace Catch { void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; xml.writeAttribute( "name", stats.groupInfo.name ); xml.writeAttribute( "errors", unexpectedExceptions ); @@ -14117,6 +14109,21 @@ namespace Catch { xml.writeAttribute( "time", suiteTime ); xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + // Write properties if there are any + if (m_config->hasTestFilters() || m_config->rngSeed() != 0) { + auto properties = xml.scopedElement("properties"); + if (m_config->hasTestFilters()) { + xml.scopedElement("property") + .writeAttribute("name", "filters") + .writeAttribute("value", serializeFilters(m_config->getTestsOrTags())); + } + if (m_config->rngSeed() != 0) { + xml.scopedElement("property") + .writeAttribute("name", "random-seed") + .writeAttribute("value", m_config->rngSeed()); + } + } + // Write test cases for( auto const& child : groupNode.children ) writeTestCase( *child );