diff --git a/CMakeLists.txt b/CMakeLists.txt index 28f22f3c..983c5867 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) endif() -project(Catch2 LANGUAGES CXX VERSION 2.12.4) +project(Catch2 LANGUAGES CXX VERSION 2.13.0) # Provide path for scripts list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake") diff --git a/README.md b/README.md index acfa8c88..82541b54 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/wRuqI3INY7fTagL7) +[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/aavJBzemrxUgGV9S) [![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/command-line.md b/docs/command-line.md index dd5150eb..a99a1072 100644 --- a/docs/command-line.md +++ b/docs/command-line.md @@ -224,7 +224,7 @@ When set to ```yes``` Catch will report the duration of each test case, in milli
-D, --min-duration <value>
-> `--min-duration` was [introduced](https://github.com/catchorg/Catch2/pull/1910) in Catch X.Y.Z +> `--min-duration` was [introduced](https://github.com/catchorg/Catch2/pull/1910) in Catch 2.13.0 When set, Catch will report the duration of each test case that took more than <value> seconds, in milliseconds. This option is overriden by both diff --git a/docs/generators.md b/docs/generators.md index 2b5a2183..0f6c7309 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -92,7 +92,7 @@ TEST_CASE("Complex mix of sections and generates") { } ``` -> The ability to place `GENERATE` between two `SECTION`s was [introduced](https://github.com/catchorg/Catch2/issues/1938) in Catch X.Y.Z. +> The ability to place `GENERATE` between two `SECTION`s was [introduced](https://github.com/catchorg/Catch2/issues/1938) in Catch 2.13.0. ## Provided generators diff --git a/docs/release-notes.md b/docs/release-notes.md index af9a4ce2..33e3d255 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -2,6 +2,7 @@ # Release notes **Contents**
+[2.13.0](#2130)
[2.12.4](#2124)
[2.12.3](#2123)
[2.12.2](#2122)
@@ -39,6 +40,18 @@ [Older versions](#older-versions)
[Even Older versions](#even-older-versions)
+## 2.13.0 + +### Improvements +* `GENERATE` can now follow a `SECTION` at the same level of nesting (#1938) + * The `SECTION`(s) before the `GENERATE` will not be run multiple times, the following ones will. +* Added `-D`/`--min-duration` command line flag (#1910) + * If a test takes longer to finish than the provided value, its name and duration will be printed. + * This flag is overriden by setting `-d`/`--duration`. + +### Fixes +* `TAPReporter` no longer skips successful assertions (#1983) + ## 2.12.4 diff --git a/include/catch.hpp b/include/catch.hpp index 1502663b..18509248 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 12 -#define CATCH_VERSION_PATCH 4 +#define CATCH_VERSION_MINOR 13 +#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 57589d9b..ad3e800e 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, 12, 4, "", 0 ); + static Version version( 2, 13, 0, "", 0 ); return version; } diff --git a/single_include/catch2/catch.hpp b/single_include/catch2/catch.hpp index b066b71d..cf1fae15 100644 --- a/single_include/catch2/catch.hpp +++ b/single_include/catch2/catch.hpp @@ -1,6 +1,6 @@ /* - * Catch v2.12.4 - * Generated: 2020-07-05 11:47:18.451282 + * Catch v2.13.0 + * Generated: 2020-07-12 20:07:49.015950 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. @@ -14,8 +14,8 @@ #define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 12 -#define CATCH_VERSION_PATCH 4 +#define CATCH_VERSION_MINOR 13 +#define CATCH_VERSION_PATCH 0 #ifdef __clang__ # pragma clang system_header @@ -4522,6 +4522,7 @@ namespace Catch { virtual int abortAfter() const = 0; virtual bool showInvisibles() const = 0; virtual ShowDurations::OrNot showDurations() const = 0; + virtual double minDuration() const = 0; virtual TestSpec const& testSpec() const = 0; virtual bool hasTestFilters() const = 0; virtual std::vector const& getTestsOrTags() const = 0; @@ -5294,6 +5295,7 @@ namespace Catch { Verbosity verbosity = Verbosity::Normal; WarnAbout::What warnings = WarnAbout::Nothing; ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; + double minDuration = -1; RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; UseColour::YesOrNo useColour = UseColour::Auto; WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; @@ -5344,6 +5346,7 @@ namespace Catch { bool warnAboutMissingAssertions() const override; bool warnAboutNoTests() const override; ShowDurations::OrNot showDurations() const override; + double minDuration() const override; RunTests::InWhatOrder runOrder() const override; unsigned int rngSeed() const override; UseColour::YesOrNo useColour() const override; @@ -5721,6 +5724,9 @@ namespace Catch { // Returns double formatted as %.3f (format expected on output) std::string getFormattedDuration( double duration ); + //! Should the reporter show + bool shouldShowDuration( IConfig const& config, double duration ); + std::string serializeFilters( std::vector const& container ); template @@ -6114,8 +6120,6 @@ namespace Catch { static std::string getDescription(); - ReporterPreferences getPreferences() const override; - void noMatchingTestCases(std::string const& spec) override; void assertionStarting(AssertionInfo const&) override; @@ -7499,6 +7503,7 @@ namespace TestCaseTracking { virtual bool isSuccessfullyCompleted() const = 0; virtual bool isOpen() const = 0; // Started but not complete virtual bool hasChildren() const = 0; + virtual bool hasStarted() const = 0; virtual ITracker& parent() = 0; @@ -7565,6 +7570,9 @@ namespace TestCaseTracking { bool isSuccessfullyCompleted() const override; bool isOpen() const override; bool hasChildren() const override; + bool hasStarted() const override { + return m_runState != NotStarted; + } void addChild( ITrackerPtr const& child ) override; @@ -9861,6 +9869,9 @@ namespace Catch { | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) ["-d"]["--durations"] ( "show test durations" ) + | Opt( config.minDuration, "seconds" ) + ["-D"]["--min-duration"] + ( "show test durations for tests taking at least the given number of seconds" ) | Opt( loadTestNamesFromFile, "filename" ) ["-f"]["--input-file"] ( "load test names to run from a file" ) @@ -10008,6 +10019,7 @@ namespace Catch { bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } + double Config::minDuration() const { return m_data.minDuration; } RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } unsigned int Config::rngSeed() const { return m_data.rngSeed; } UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } @@ -12547,7 +12559,7 @@ namespace Catch { currentTracker.addChild( tracker ); } - if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( !tracker->isComplete() ) { tracker->open(); } @@ -12561,8 +12573,28 @@ namespace Catch { } void close() override { TrackerBase::close(); - // Generator interface only finds out if it has another item on atual move - if (m_runState == CompletedSuccessfully && m_generator->next()) { + // If a generator has a child (it is followed by a section) + // and none of its children have started, then we must wait + // until later to start consuming its values. + // This catches cases where `GENERATE` is placed between two + // `SECTION`s. + // **The check for m_children.empty cannot be removed**. + // doing so would break `GENERATE` _not_ followed by `SECTION`s. + const bool should_wait_for_child = + !m_children.empty() && + std::find_if( m_children.begin(), + m_children.end(), + []( TestCaseTracking::ITrackerPtr tracker ) { + return tracker->hasStarted(); + } ) == m_children.end(); + + // This check is a bit tricky, because m_generator->next() + // has a side-effect, where it consumes generator's current + // value, but we do not want to invoke the side-effect if + // this generator is still waiting for any child to start. + if ( should_wait_for_child || + ( m_runState == CompletedSuccessfully && + m_generator->next() ) ) { m_children.clear(); m_runState = Executing; } @@ -12702,7 +12734,6 @@ namespace Catch { using namespace Generators; GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation( static_cast(generatorName), lineInfo ) ); - assert( tracker.isOpen() ); m_lastAssertionInfo.lineInfo = lineInfo; return tracker; } @@ -14381,7 +14412,8 @@ namespace TestCaseTracking { bool SectionTracker::isComplete() const { bool complete = true; - if ((m_filters.empty() || m_filters[0] == "") + if (m_filters.empty() + || m_filters[0] == "" || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { complete = TrackerBase::isComplete(); } @@ -15206,7 +15238,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 12, 4, "", 0 ); + static Version version( 2, 13, 0, "", 0 ); return version; } @@ -15608,6 +15640,17 @@ namespace Catch { return std::string(buffer); } + bool shouldShowDuration( IConfig const& config, double duration ) { + if ( config.showDurations() == ShowDurations::Always ) { + return true; + } + if ( config.showDurations() == ShowDurations::Never ) { + return false; + } + const double min = config.minDuration(); + return min >= 0 && duration >= min; + } + std::string serializeFilters( std::vector const& container ) { ReusableStringStream oss; bool first = true; @@ -15874,10 +15917,6 @@ private: return "Reports test results on a single line, suitable for IDEs"; } - ReporterPreferences CompactReporter::getPreferences() const { - return m_reporterPrefs; - } - void CompactReporter::noMatchingTestCases( std::string const& spec ) { stream << "No test cases matched '" << spec << '\'' << std::endl; } @@ -15904,8 +15943,9 @@ private: } void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + double dur = _sectionStats.durationInSeconds; + if ( shouldShowDuration( *m_config, dur ) ) { + stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl; } } @@ -16325,8 +16365,9 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { stream << "\nNo assertions in test case"; stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; } - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + double dur = _sectionStats.durationInSeconds; + if (shouldShowDuration(*m_config, dur)) { + stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl; } if (m_headerPrinted) { m_headerPrinted = false; diff --git a/single_include/catch2/catch_reporter_tap.hpp b/single_include/catch2/catch_reporter_tap.hpp index 1bfe4f5e..5ac8524c 100644 --- a/single_include/catch2/catch_reporter_tap.hpp +++ b/single_include/catch2/catch_reporter_tap.hpp @@ -23,16 +23,17 @@ namespace Catch { using StreamingReporterBase::StreamingReporterBase; + TAPReporter( ReporterConfig const& config ): + StreamingReporterBase( config ) { + m_reporterPrefs.shouldReportAllAssertions = true; + } + ~TAPReporter() override; static std::string getDescription() { return "Reports test results in TAP format, suitable for test harnesses"; } - ReporterPreferences getPreferences() const override { - return m_reporterPrefs; - } - void noMatchingTestCases( std::string const& spec ) override { stream << "# No test cases matched '" << spec << "'" << std::endl; } @@ -203,16 +204,15 @@ namespace Catch { return; } - // using messages.end() directly (or auto) yields compilation error: - std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); + const auto itEnd = messages.cend(); + const auto N = static_cast( std::distance( itMessage, itEnd ) ); { Colour colourGuard( colour ); stream << " with " << pluralise( N, "message" ) << ":"; } - for(; itMessage != itEnd; ) { + while( itMessage != itEnd ) { // If this assertion is a warning ignore any INFO messages if( printInfoMessages || itMessage->type != ResultWas::Info ) { stream << " '" << itMessage->message << "'"; @@ -220,7 +220,9 @@ namespace Catch { Colour colourGuard( dimColour() ); stream << " and"; } + continue; } + ++itMessage; } } @@ -234,10 +236,9 @@ namespace Catch { }; void printTotals( const Totals& totals ) const { + stream << "1.." << totals.assertions.total(); if( totals.testCases.total() == 0 ) { - stream << "1..0 # Skipped: No tests ran."; - } else { - stream << "1.." << counter; + stream << " # Skipped: No tests ran."; } } };