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.";
}
}
};