diff --git a/CMakeLists.txt b/CMakeLists.txt index 42c8a0319e..94f90d9f12 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.2.3) +project(Catch2 LANGUAGES CXX VERSION 2.3.0) # Provide path for scripts list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake") diff --git a/README.md b/README.md index 15ed90450b..386f8534cd 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/u7qF77qgv9YqOr55) +[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/Gcuv2Xx3wmWIPNzy) [![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/conanfile.py b/conanfile.py index 9fea152550..7605395914 100644 --- a/conanfile.py +++ b/conanfile.py @@ -4,7 +4,7 @@ class CatchConan(ConanFile): name = "Catch" - version = "2.2.3" + version = "2.3.0" description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD" author = "philsquared" generators = "cmake" diff --git a/docs/release-notes.md b/docs/release-notes.md index 6ebe4d03d0..e40be99c09 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,5 +1,36 @@ +# 2.3.0 + +**This release changes the include paths provided by our CMake and +pkg-config integration. The proper include path for the single-header +when using one of the above is now ``. This change +also necessitated changes to paths inside the repository, so that the +single-header version is now at `single_include/catch2/catch.hpp`, rather +than `single_include/catch.hpp`.** + + + +## Fixes +* Fixed Objective-C++ build +* `-Wunused-variable` suppression no longer leaks from Catch's header under Clang +* Implementation of the experimental new output capture can now be disabled (#1335) + * This allows building Catch2 on platforms that do not provide things like `dup` or `tmpfile`. +* The JUnit and XML reporters will no longer skip over successful tests when running without `-s` (#1264, #1267, #1310) + * See improvements for more details + +## Improvements +* pkg-config and CMake integration has been rewritten + * If you use them, the new include path is `#include ` + * CMake installation now also installs scripts from `contrib/` + * For details see the [new documentation](cmake-integration.md#top) +* Reporters now have a new customization point, `ReporterPreferences::shouldReportAllAssertions` + * When this is set to `false` and the tests are run without `-s`, passing assertions are not sent to the reporter. + * Defaults to `false`. +* Added `DYNAMIC_SECTION`, a section variant that constructs its name using stream + * This means that you can do `DYNAMIC_SECTION("For X := " << x)`. + + # 2.2.3 **To fix some of the bugs, some behavior had to change in potentially breaking manner.** diff --git a/include/catch.hpp b/include/catch.hpp index b4a058458c..0a49cb3162 100644 --- a/include/catch.hpp +++ b/include/catch.hpp @@ -10,8 +10,8 @@ #define TWOBLUECUBES_CATCH_HPP_INCLUDED #define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 2 -#define CATCH_VERSION_PATCH 3 +#define CATCH_VERSION_MINOR 3 +#define CATCH_VERSION_PATCH 0 #ifdef __clang__ # pragma clang system_header diff --git a/include/internal/catch_version.cpp b/include/internal/catch_version.cpp index 94e11e0851..1585ff7a7c 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, 2, 3, "", 0 ); + static Version version( 2, 3, 0, "", 0 ); return version; } diff --git a/single_include/catch2/catch.hpp b/single_include/catch2/catch.hpp index 6fac1e7cb0..bdc2f74a9a 100644 --- a/single_include/catch2/catch.hpp +++ b/single_include/catch2/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v2.2.3 - * Generated: 2018-06-11 22:16:30.128800 + * Catch v2.3.0 + * Generated: 2018-07-23 10:09:14.936841 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved. @@ -14,8 +14,8 @@ #define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 2 -#define CATCH_VERSION_PATCH 3 +#define CATCH_VERSION_MINOR 3 +#define CATCH_VERSION_PATCH 0 #ifdef __clang__ # pragma clang system_header @@ -30,13 +30,15 @@ # pragma warning(push) # pragma warning(disable: 161 1682) # else // __ICC -# pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ + // GCC likes to warn on REQUIREs, and we cannot suppress them + // locally because g++'s support for _Pragma is lacking in older, + // still supported, versions # pragma GCC diagnostic ignored "-Wparentheses" # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-variable" @@ -55,7 +57,9 @@ # if defined(CATCH_CONFIG_DISABLE_MATCHERS) # undef CATCH_CONFIG_DISABLE_MATCHERS # endif -# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif #endif #if !defined(CATCH_CONFIG_IMPL_ONLY) @@ -145,6 +149,12 @@ namespace Catch { # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic pop" ) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// @@ -176,6 +186,12 @@ namespace Catch { # define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH #endif +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + //////////////////////////////////////////////////////////////////////////////// // Cygwin #ifdef __CYGWIN__ @@ -245,6 +261,14 @@ namespace Catch { # define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS #endif +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS @@ -253,6 +277,10 @@ namespace Catch { # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS #endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS +#endif // end catch_compiler_capabilities.h #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line @@ -551,7 +579,7 @@ struct AutoReg : NonCopyable { #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ @@ -580,7 +608,7 @@ struct AutoReg : NonCopyable { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS // end catch_test_registry.h @@ -1776,7 +1804,7 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \ catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ } while( false ) @@ -1848,19 +1876,22 @@ namespace Catch { namespace Catch { struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name ); + + // Deprecated SectionInfo ( SourceLineInfo const& _lineInfo, std::string const& _name, - std::string const& _description = std::string() ); + std::string const& ) : SectionInfo( _lineInfo, _name ) {} std::string name; - std::string description; + std::string description; // !Deprecated: this will always be empty SourceLineInfo lineInfo; }; struct SectionEndInfo { - SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ); - SectionInfo sectionInfo; Counts prevAssertions; double durationInSeconds; @@ -1914,8 +1945,15 @@ namespace Catch { } // end namespace Catch - #define INTERNAL_CATCH_SECTION( ... ) \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#define INTERNAL_CATCH_SECTION( ... ) \ + CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ + CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS + +#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ + CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ + CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS // end catch_section.h // start catch_benchmark.h @@ -2102,6 +2140,8 @@ namespace Detail { static Approx custom(); + Approx operator-() const; + template ::value>::type> Approx operator()( T const& value ) { Approx approx( static_cast(value) ); @@ -2197,7 +2237,12 @@ namespace Detail { double m_scale; double m_value; }; -} +} // end namespace Detail + +namespace literals { + Detail::Approx operator "" _a(long double val); + Detail::Approx operator "" _a(unsigned long long val); +} // end namespace literals template<> struct StringMaker { @@ -2962,7 +3007,7 @@ namespace Catch { std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); const char* className = class_getName( cls ); - getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo("",0) ) ); + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) ); noTestMethods++; } } @@ -3586,6 +3631,7 @@ namespace Catch { struct ReporterPreferences { bool shouldRedirectStdOut = false; + bool shouldReportAllAssertions = false; }; template @@ -4676,6 +4722,12 @@ namespace Detail { return Approx( 0 ); } + Approx Approx::operator-() const { + auto temp(*this); + temp.m_value = -temp.m_value; + return temp; + } + std::string Approx::toString() const { ReusableStringStream rss; rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; @@ -4690,6 +4742,15 @@ namespace Detail { } // end namespace Detail +namespace literals { + Detail::Approx operator "" _a(long double val) { + return Detail::Approx(val); + } + Detail::Approx operator "" _a(unsigned long long val) { + return Detail::Approx(val); + } +} // end namespace literals + std::string StringMaker::convert(Catch::Detail::Approx const& value) { return value.toString(); } @@ -4998,9 +5059,11 @@ namespace Catch { // end catch_run_context.h namespace Catch { - auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { - expr.streamReconstructedExpression( os ); - return os; + namespace { + auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { + expr.streamReconstructedExpression( os ); + return os; + } } LazyExpression::LazyExpression( bool isNegated ) @@ -7530,8 +7593,11 @@ namespace Catch { using Reporters = std::vector; Reporters m_listeners; IStreamingReporterPtr m_reporter = nullptr; + ReporterPreferences m_preferences; public: + ListeningReporter(); + void addListener( IStreamingReporterPtr&& listener ); void addReporter( IStreamingReporterPtr&& reporter ); @@ -8260,6 +8326,8 @@ namespace Catch { auto str() const -> std::string; }; +#if defined(CATCH_CONFIG_NEW_CAPTURE) + // Windows's implementation of std::tmpfile is terrible (it tries // to create a file inside system folder, thus requiring elevated // privileges for the binary), so we have to use tmpnam(_s) and @@ -8303,6 +8371,8 @@ namespace Catch { std::string& m_stderrDest; }; +#endif + } // end namespace Catch #endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H @@ -8313,13 +8383,15 @@ namespace Catch { #include #include -#if defined(_MSC_VER) -#include //_dup and _dup2 -#define dup _dup -#define dup2 _dup2 -#define fileno _fileno -#else -#include // dup and dup2 +#if defined(CATCH_CONFIG_NEW_CAPTURE) + #if defined(_MSC_VER) + #include //_dup and _dup2 + #define dup _dup + #define dup2 _dup2 + #define fileno _fileno + #else + #include // dup and dup2 + #endif #endif namespace Catch { @@ -8345,6 +8417,8 @@ namespace Catch { {} auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } +#if defined(CATCH_CONFIG_NEW_CAPTURE) + #if defined(_MSC_VER) TempFile::TempFile() { if (tmpnam_s(m_buffer)) { @@ -8417,12 +8491,16 @@ namespace Catch { m_stderrDest += m_stderrFile.getContents(); } +#endif // CATCH_CONFIG_NEW_CAPTURE + } // namespace Catch -#if defined(_MSC_VER) -#undef dup -#undef dup2 -#undef fileno +#if defined(CATCH_CONFIG_NEW_CAPTURE) + #if defined(_MSC_VER) + #undef dup + #undef dup2 + #undef fileno + #endif #endif // end catch_output_redirect.cpp // start catch_random_number_generator.cpp @@ -8430,53 +8508,36 @@ namespace Catch { // start catch_random_number_generator.h #include +#include namespace Catch { struct IConfig; + std::mt19937& rng(); void seedRng( IConfig const& config ); - unsigned int rngSeed(); - struct RandomNumberGenerator { - using result_type = unsigned int; - - static constexpr result_type (min)() { return 0; } - static constexpr result_type (max)() { return 1000000; } - - result_type operator()( result_type n ) const; - result_type operator()() const; - - template - static void shuffle( V& vector ) { - RandomNumberGenerator rng; - std::shuffle( vector.begin(), vector.end(), rng ); - } - }; - } // end catch_random_number_generator.h -#include - namespace Catch { + std::mt19937& rng() { + static std::mt19937 s_rng; + return s_rng; + } + void seedRng( IConfig const& config ) { - if( config.rngSeed() != 0 ) + if( config.rngSeed() != 0 ) { std::srand( config.rngSeed() ); + rng().seed( config.rngSeed() ); + } } + unsigned int rngSeed() { return getCurrentContext().getConfig()->rngSeed(); } - - RandomNumberGenerator::result_type RandomNumberGenerator::operator()( result_type n ) const { - return std::rand() % n; - } - RandomNumberGenerator::result_type RandomNumberGenerator::operator()() const { - return std::rand() % (max)(); - } - } // end catch_random_number_generator.cpp // start catch_registry_hub.cpp @@ -8759,7 +8820,7 @@ namespace Catch { m_config(_config), m_reporter(std::move(reporter)), m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, - m_includeSuccessfulResults( m_config->includeSuccessfulResults() ) + m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) { m_context.setRunner(this); m_context.setConfig(m_config); @@ -8949,7 +9010,7 @@ namespace Catch { // Recreate section for test case (as we will lose the one that was in scope) auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); Counts assertions; assertions.failed = 1; @@ -8987,7 +9048,7 @@ namespace Catch { void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); m_reporter->sectionStarting(testCaseSection); Counts prevAssertions = m_totals.assertions; double duration = 0; @@ -9182,7 +9243,7 @@ namespace Catch { Section::~Section() { if( m_sectionIncluded ) { - SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; if( uncaught_exceptions() ) getResultCapture().sectionEndedEarly( endInfo ); else @@ -9203,17 +9264,11 @@ namespace Catch { SectionInfo::SectionInfo ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description ) + std::string const& _name ) : name( _name ), - description( _description ), lineInfo( _lineInfo ) {} - SectionEndInfo::SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) - : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) - {} - } // end namespace Catch // end catch_section_info.cpp // start catch_session.cpp @@ -9774,6 +9829,12 @@ namespace Catch { namespace Catch { + namespace { + char toLowerCh(char c) { + return static_cast( std::tolower( c ) ); + } + } + bool startsWith( std::string const& s, std::string const& prefix ) { return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); } @@ -9789,9 +9850,6 @@ namespace Catch { bool contains( std::string const& s, std::string const& infix ) { return s.find( infix ) != std::string::npos; } - char toLowerCh(char c) { - return static_cast( std::tolower( c ) ); - } void toLowerInPlace( std::string& s ) { std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); } @@ -10033,31 +10091,33 @@ namespace Catch { namespace Catch { - TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { - if( startsWith( tag, '.' ) || - tag == "!hide" ) - return TestCaseInfo::IsHidden; - else if( tag == "!throws" ) - return TestCaseInfo::Throws; - else if( tag == "!shouldfail" ) - return TestCaseInfo::ShouldFail; - else if( tag == "!mayfail" ) - return TestCaseInfo::MayFail; - else if( tag == "!nonportable" ) - return TestCaseInfo::NonPortable; - else if( tag == "!benchmark" ) - return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); - else - return TestCaseInfo::None; - } - bool isReservedTag( std::string const& tag ) { - return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast(tag[0]) ); - } - 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" - << _lineInfo ); + namespace { + TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, '.' ) || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else if( tag == "!nonportable" ) + return TestCaseInfo::NonPortable; + else if( tag == "!benchmark" ) + return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); + else + return TestCaseInfo::None; + } + bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast(tag[0]) ); + } + 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" + << _lineInfo ); + } } TestCase makeTestCase( ITestInvoker* _testCase, @@ -10205,7 +10265,7 @@ namespace Catch { break; case RunTests::InRandomOrder: seedRng( config ); - RandomNumberGenerator::shuffle( sorted ); + std::shuffle( sorted.begin(), sorted.end(), rng() ); break; case RunTests::InDeclarationOrder: // already in declaration order @@ -10348,8 +10408,8 @@ namespace TestCaseTracking { TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) const { return - tracker->nameAndLocation().name == m_nameAndLocation.name && - tracker->nameAndLocation().location == m_nameAndLocation.location; + tracker->nameAndLocation().location == m_nameAndLocation.location && + tracker->nameAndLocation().name == m_nameAndLocation.name; } TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) @@ -10733,34 +10793,36 @@ namespace Catch { return std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); } - auto estimateClockResolution() -> uint64_t { - uint64_t sum = 0; - static const uint64_t iterations = 1000000; + namespace { + auto estimateClockResolution() -> uint64_t { + uint64_t sum = 0; + static const uint64_t iterations = 1000000; - auto startTime = getCurrentNanosecondsSinceEpoch(); + auto startTime = getCurrentNanosecondsSinceEpoch(); - for( std::size_t i = 0; i < iterations; ++i ) { + for( std::size_t i = 0; i < iterations; ++i ) { - uint64_t ticks; - uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); - do { - ticks = getCurrentNanosecondsSinceEpoch(); - } while( ticks == baseTicks ); + uint64_t ticks; + uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); + do { + ticks = getCurrentNanosecondsSinceEpoch(); + } while( ticks == baseTicks ); - auto delta = ticks - baseTicks; - sum += delta; + 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; + // 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; + } } - } - // 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; + // 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; + } } auto getEstimatedClockResolution() -> uint64_t { static auto s_resolution = estimateClockResolution(); @@ -11004,8 +11066,8 @@ std::string StringMaker::convert(double value) { std::string ratio_string::symbol() { return "a"; } std::string ratio_string::symbol() { return "f"; } -std::string ratio_string::symbol() { return "p"; } -std::string ratio_string::symbol() { return "n"; } +std::string ratio_string::symbol() { return "p"; } +std::string ratio_string::symbol() { return "n"; } std::string ratio_string::symbol() { return "u"; } std::string ratio_string::symbol() { return "m"; } @@ -11117,7 +11179,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 2, 3, "", 0 ); + static Version version( 2, 3, 0, "", 0 ); return version; } @@ -11719,9 +11781,7 @@ class AssertionPrinter { } ReporterPreferences CompactReporter::getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; + return m_reporterPrefs; } void CompactReporter::noMatchingTestCases( std::string const& spec ) { @@ -12436,6 +12496,7 @@ namespace Catch { xml( _config.stream() ) { m_reporterPrefs.shouldRedirectStdOut = true; + m_reporterPrefs.shouldReportAllAssertions = true; } JunitReporter::~JunitReporter() {} @@ -12626,6 +12687,11 @@ namespace Catch { namespace Catch { + ListeningReporter::ListeningReporter() { + // We will assume that listeners will always want all assertions + m_preferences.shouldReportAllAssertions = true; + } + void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { m_listeners.push_back( std::move( listener ) ); } @@ -12633,10 +12699,11 @@ namespace Catch { void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { assert(!m_reporter && "Listening reporter can wrap only 1 real reporter"); m_reporter = std::move( reporter ); + m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut; } ReporterPreferences ListeningReporter::getPreferences() const { - return m_reporter->getPreferences(); + return m_preferences; } std::set ListeningReporter::getSupportedVerbosities() { @@ -12762,6 +12829,7 @@ namespace Catch { m_xml(_config.stream()) { m_reporterPrefs.shouldRedirectStdOut = true; + m_reporterPrefs.shouldReportAllAssertions = true; } XmlReporter::~XmlReporter() = default; @@ -12818,8 +12886,7 @@ namespace Catch { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) - .writeAttribute( "name", trim( sectionInfo.name ) ) - .writeAttribute( "description", sectionInfo.description ); + .writeAttribute( "name", trim( sectionInfo.name ) ); writeSourceInfo( sectionInfo.lineInfo ); m_xml.ensureTagClosed(); } @@ -13061,6 +13128,7 @@ int main (int argc, char * const argv[]) { #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) @@ -13070,11 +13138,11 @@ int main (int argc, char * const argv[]) { // "BDD-style" convenience wrappers #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc ) -#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc ) -#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) -#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc ) -#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) +#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) +#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) +#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And when: " << desc ) +#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) +#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -13119,6 +13187,7 @@ int main (int argc, char * const argv[]) { #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) @@ -13132,15 +13201,16 @@ int main (int argc, char * const argv[]) { #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc ) -#define WHEN( desc ) SECTION( std::string(" When: ") + desc ) -#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc ) -#define THEN( desc ) SECTION( std::string(" Then: ") + desc ) -#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc ) +#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) +#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) +#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And when: " << desc ) +#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) +#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) using Catch::Detail::Approx; -#else +#else // CATCH_CONFIG_DISABLE + ////// // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ #ifdef CATCH_CONFIG_PREFIX_ALL @@ -13185,6 +13255,7 @@ using Catch::Detail::Approx; #define CATCH_METHOD_AS_TEST_CASE( method, ... ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) #define CATCH_SECTION( ... ) +#define CATCH_DYNAMIC_SECTION( ... ) #define CATCH_FAIL( ... ) (void)(0) #define CATCH_FAIL_CHECK( ... ) (void)(0) #define CATCH_SUCCEED( ... ) (void)(0) @@ -13243,6 +13314,7 @@ using Catch::Detail::Approx; #define METHOD_AS_TEST_CASE( method, ... ) #define REGISTER_TEST_CASE( Function, ... ) (void)(0) #define SECTION( ... ) +#define DYNAMIC_SECTION( ... ) #define FAIL( ... ) (void)(0) #define FAIL_CHECK( ... ) (void)(0) #define SUCCEED( ... ) (void)(0) diff --git a/single_include/catch2/catch_reporter_tap.hpp b/single_include/catch2/catch_reporter_tap.hpp index 19e54ed197..ccc4051be0 100644 --- a/single_include/catch2/catch_reporter_tap.hpp +++ b/single_include/catch2/catch_reporter_tap.hpp @@ -30,9 +30,7 @@ namespace Catch { } ReporterPreferences getPreferences() const override { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; + return m_reporterPrefs; } void noMatchingTestCases( std::string const& spec ) override { diff --git a/test_package/conanfile.py b/test_package/conanfile.py index 7ed77b5caf..b9fc6f91e3 100644 --- a/test_package/conanfile.py +++ b/test_package/conanfile.py @@ -10,7 +10,7 @@ class CatchConanTest(ConanFile): settings = "os", "compiler", "arch", "build_type" username = getenv("CONAN_USERNAME", "philsquared") channel = getenv("CONAN_CHANNEL", "testing") - requires = "Catch/2.2.3@%s/%s" % (username, channel) + requires = "Catch/2.3.0@%s/%s" % (username, channel) def build(self): cmake = CMake(self)