diff --git a/docs/Readme.md b/docs/Readme.md
index 52eb64a5..126ee1be 100644
--- a/docs/Readme.md
+++ b/docs/Readme.md
@@ -11,6 +11,7 @@ Once you're up and running consider the following reference material.
* [Logging macros](logging.md#top)
* [Test cases and sections](test-cases-and-sections.md#top)
* [Test fixtures](test-fixtures.md#top)
+* [Skipping tests at runtime](skipping.md#top)
* [Reporters (output customization)](reporters.md#top)
* [Event Listeners](event-listeners.md#top)
* [Data Generators (value parameterized tests)](generators.md#top)
diff --git a/docs/command-line.md b/docs/command-line.md
index 6fc99f59..e7a448b1 100644
--- a/docs/command-line.md
+++ b/docs/command-line.md
@@ -561,10 +561,10 @@ processes, as is done with the [Bazel test sharding](https://docs.bazel.build/ve
> Introduced in Catch2 3.0.1.
-By default, Catch2 test binaries return non-0 exit code if no tests were
-run, e.g. if the binary was compiled with no tests, or the provided test
-spec matched no tests. This flag overrides that, so a test run with no
-tests still returns 0.
+By default, Catch2 test binaries return non-0 exit code if no tests were run,
+e.g. if the binary was compiled with no tests, the provided test spec matched no
+tests, or all tests [were skipped at runtime](skipping.md#top). This flag
+overrides that, so a test run with no tests still returns 0.
## Output verbosity
```
diff --git a/docs/deprecations.md b/docs/deprecations.md
index 2c9bf551..5926f2c5 100644
--- a/docs/deprecations.md
+++ b/docs/deprecations.md
@@ -26,6 +26,15 @@ to accurately probe the environment for this information so the flag
where it will export `BAZEL_TEST=1` for purposes like the above. Catch2
will now instead inspect the environment instead of relying on build configuration.
+### `IEventLister::skipTest( TestCaseInfo const& testInfo )`
+
+This event (including implementations in derived classes such as `ReporterBase`)
+is deprecated and will be removed in the next major release. It is currently
+invoked for all test cases that are not going to be executed due to the test run
+being aborted (when using `--abort` or `--abortx`). It is however
+**NOT** invoked for test cases that are [explicitly skipped using the `SKIP`
+macro](skipping.md#top).
+
---
[Home](Readme.md#top)
diff --git a/docs/skipping.md b/docs/skipping.md
new file mode 100644
index 00000000..edd2a1a1
--- /dev/null
+++ b/docs/skipping.md
@@ -0,0 +1,72 @@
+
+# Skipping Test Cases at Runtime
+
+> [Introduced](https://github.com/catchorg/Catch2/pull/2360) in Catch2 X.Y.Z.
+
+In some situations it may not be possible to meaningfully execute a test case, for example when the system under test is missing certain hardware capabilities.
+If the required conditions can only be determined at runtime, it often doesn't make sense to consider such a test case as either passed or failed, because it simply can not run at all.
+To properly express such scenarios, Catch2 allows to explicitly _skip_ test cases, using the `SKIP` macro:
+
+**SKIP(** _message expression_ **)**
+
+Example usage:
+
+```c++
+TEST_CASE("copy files between drives") {
+ if(getNumberOfHardDrives() < 2) {
+ SKIP("at least two hard drives required");
+ }
+ // ...
+}
+```
+
+This test case is then reported as _skipped_ instead of _passed_ or _failed_.
+
+The `SKIP` macro behaves similarly to an explicit [`FAIL`](logging.md#top), in that it is the last expression that will be executed:
+
+```c++
+TEST_CASE("my test") {
+ printf("foo");
+ SKIP();
+ printf("bar"); // not printed
+}
+```
+
+However a failed assertion _before_ a `SKIP` still causes the entire test case to fail:
+
+```c++
+TEST_CASE("failing test") {
+ CHECK(1 == 2);
+ SKIP();
+}
+```
+
+## Interaction with Sections and Generators
+
+Sections, nested sections as well as test cases with [generators](generators.md#top) can all be individually skipped, with the rest executing as usual:
+
+```c++
+TEST_CASE("complex test case") {
+ int value = GENERATE(2, 4, 6);
+ SECTION("a") {
+ SECTION("a1") { CHECK(value < 8); }
+ SECTION("a2") {
+ if (value == 4) {
+ SKIP();
+ }
+ CHECK(value % 2 == 0);
+ }
+ }
+}
+```
+
+This test case will report 5 passing assertions; one for each of the three values in section `a1`, as well as one for each in `a2`, except for when `value == 4`.
+
+Note that as soon as one section is skipped, the entire test case will be reported as _skipped_ (unless there is a failing assertion, in which case it will be reported as _failed_ instead).
+
+If all test cases in a run are skipped, Catch2 returns a non-zero exit code by default.
+This can be overridden using the [--allow-running-no-tests](command-line.md#no-tests-override) flag.
+
+---
+
+[Home](Readme.md#top)
diff --git a/src/catch2/catch_session.cpp b/src/catch2/catch_session.cpp
index 128f21d9..43465f0c 100644
--- a/src/catch2/catch_session.cpp
+++ b/src/catch2/catch_session.cpp
@@ -341,6 +341,12 @@ namespace Catch {
return 2;
}
+ if ( totals.testCases.total() > 0 &&
+ totals.testCases.total() == totals.testCases.skipped
+ && !m_config->zeroTestsCountAsSuccess() ) {
+ return 4;
+ }
+
// Note that on unices only the lower 8 bits are usually used, clamping
// the return value to 255 prevents false negative when some multiple
// of 256 tests has failed
diff --git a/src/catch2/catch_test_macros.hpp b/src/catch2/catch_test_macros.hpp
index cce2852f..1088afbe 100644
--- a/src/catch2/catch_test_macros.hpp
+++ b/src/catch2/catch_test_macros.hpp
@@ -49,6 +49,7 @@
#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__ )
+ #define CATCH_SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ )
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
@@ -102,6 +103,7 @@
#define CATCH_FAIL( ... ) (void)(0)
#define CATCH_FAIL_CHECK( ... ) (void)(0)
#define CATCH_SUCCEED( ... ) (void)(0)
+ #define CATCH_SKIP( ... ) (void)(0)
#define CATCH_STATIC_REQUIRE( ... ) (void)(0)
#define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)
@@ -146,6 +148,7 @@
#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__ )
+ #define SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ )
#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
@@ -198,6 +201,7 @@
#define FAIL( ... ) (void)(0)
#define FAIL_CHECK( ... ) (void)(0)
#define SUCCEED( ... ) (void)(0)
+ #define SKIP( ... ) (void)(0)
#define STATIC_REQUIRE( ... ) (void)(0)
#define STATIC_REQUIRE_FALSE( ... ) (void)(0)
diff --git a/src/catch2/catch_totals.cpp b/src/catch2/catch_totals.cpp
index a3e2b384..bd1954fb 100644
--- a/src/catch2/catch_totals.cpp
+++ b/src/catch2/catch_totals.cpp
@@ -14,6 +14,7 @@ namespace Catch {
diff.passed = passed - other.passed;
diff.failed = failed - other.failed;
diff.failedButOk = failedButOk - other.failedButOk;
+ diff.skipped = skipped - other.skipped;
return diff;
}
@@ -21,14 +22,15 @@ namespace Catch {
passed += other.passed;
failed += other.failed;
failedButOk += other.failedButOk;
+ skipped += other.skipped;
return *this;
}
std::uint64_t Counts::total() const {
- return passed + failed + failedButOk;
+ return passed + failed + failedButOk + skipped;
}
bool Counts::allPassed() const {
- return failed == 0 && failedButOk == 0;
+ return failed == 0 && failedButOk == 0 && skipped == 0;
}
bool Counts::allOk() const {
return failed == 0;
@@ -53,6 +55,8 @@ namespace Catch {
++diff.testCases.failed;
else if( diff.assertions.failedButOk > 0 )
++diff.testCases.failedButOk;
+ else if ( diff.assertions.skipped > 0 )
+ ++ diff.testCases.skipped;
else
++diff.testCases.passed;
return diff;
diff --git a/src/catch2/catch_totals.hpp b/src/catch2/catch_totals.hpp
index 8dd360c6..386392c9 100644
--- a/src/catch2/catch_totals.hpp
+++ b/src/catch2/catch_totals.hpp
@@ -23,6 +23,7 @@ namespace Catch {
std::uint64_t passed = 0;
std::uint64_t failed = 0;
std::uint64_t failedButOk = 0;
+ std::uint64_t skipped = 0;
};
struct Totals {
diff --git a/src/catch2/interfaces/catch_interfaces_reporter.hpp b/src/catch2/interfaces/catch_interfaces_reporter.hpp
index 5f286363..da0112e3 100644
--- a/src/catch2/interfaces/catch_interfaces_reporter.hpp
+++ b/src/catch2/interfaces/catch_interfaces_reporter.hpp
@@ -242,7 +242,12 @@ namespace Catch {
*/
virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
- //! Called with test cases that are skipped due to the test run aborting
+ /**
+ * Called with test cases that are skipped due to the test run aborting.
+ * NOT called for test cases that are explicitly skipped using the `SKIP` macro.
+ *
+ * Deprecated - will be removed in the next major release.
+ */
virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
//! Called if a fatal error (signal/structured exception) occured
diff --git a/src/catch2/internal/catch_assertion_handler.cpp b/src/catch2/internal/catch_assertion_handler.cpp
index f051314c..0b14e0bb 100644
--- a/src/catch2/internal/catch_assertion_handler.cpp
+++ b/src/catch2/internal/catch_assertion_handler.cpp
@@ -50,6 +50,13 @@ namespace Catch {
if (m_reaction.shouldThrow) {
throw_test_failure_exception();
}
+ if ( m_reaction.shouldSkip ) {
+#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
+ throw Catch::TestSkipException();
+#else
+ CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" );
+#endif
+ }
}
void AssertionHandler::setCompleted() {
m_completed = true;
diff --git a/src/catch2/internal/catch_assertion_handler.hpp b/src/catch2/internal/catch_assertion_handler.hpp
index 36b55243..ae7776d8 100644
--- a/src/catch2/internal/catch_assertion_handler.hpp
+++ b/src/catch2/internal/catch_assertion_handler.hpp
@@ -22,6 +22,7 @@ namespace Catch {
struct AssertionReaction {
bool shouldDebugBreak = false;
bool shouldThrow = false;
+ bool shouldSkip = false;
};
class AssertionHandler {
diff --git a/src/catch2/internal/catch_console_colour.hpp b/src/catch2/internal/catch_console_colour.hpp
index 9aa6a163..d9144315 100644
--- a/src/catch2/internal/catch_console_colour.hpp
+++ b/src/catch2/internal/catch_console_colour.hpp
@@ -47,6 +47,7 @@ namespace Catch {
Error = BrightRed,
Success = Green,
+ Skip = LightGrey,
OriginalExpression = Cyan,
ReconstructedExpression = BrightYellow,
diff --git a/src/catch2/internal/catch_exception_translator_registry.cpp b/src/catch2/internal/catch_exception_translator_registry.cpp
index 2a240a9b..0645c6ce 100644
--- a/src/catch2/internal/catch_exception_translator_registry.cpp
+++ b/src/catch2/internal/catch_exception_translator_registry.cpp
@@ -44,6 +44,9 @@ namespace Catch {
catch( TestFailureException& ) {
std::rethrow_exception(std::current_exception());
}
+ catch( TestSkipException& ) {
+ std::rethrow_exception(std::current_exception());
+ }
catch( std::exception const& ex ) {
return ex.what();
}
diff --git a/src/catch2/internal/catch_result_type.hpp b/src/catch2/internal/catch_result_type.hpp
index faf0683d..e66afaff 100644
--- a/src/catch2/internal/catch_result_type.hpp
+++ b/src/catch2/internal/catch_result_type.hpp
@@ -16,6 +16,8 @@ namespace Catch {
Ok = 0,
Info = 1,
Warning = 2,
+ // TODO: Should explicit skip be considered "not OK" (cf. isOk)? I.e., should it have the failure bit?
+ ExplicitSkip = 4,
FailureBit = 0x10,
diff --git a/src/catch2/internal/catch_run_context.cpp b/src/catch2/internal/catch_run_context.cpp
index d2e8fb8c..e1b81d0b 100644
--- a/src/catch2/internal/catch_run_context.cpp
+++ b/src/catch2/internal/catch_run_context.cpp
@@ -270,6 +270,9 @@ namespace Catch {
if (result.getResultType() == ResultWas::Ok) {
m_totals.assertions.passed++;
m_lastAssertionPassed = true;
+ } else if (result.getResultType() == ResultWas::ExplicitSkip) {
+ m_totals.assertions.skipped++;
+ m_lastAssertionPassed = true;
} else if (!result.succeeded()) {
m_lastAssertionPassed = false;
if (result.isOk()) {
@@ -475,6 +478,8 @@ namespace Catch {
duration = timer.getElapsedSeconds();
} CATCH_CATCH_ANON (TestFailureException&) {
// This just means the test was aborted due to failure
+ } CATCH_CATCH_ANON (TestSkipException&) {
+ // This just means the test was explicitly skipped
} CATCH_CATCH_ALL {
// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
// are reported without translation at the point of origin.
@@ -571,8 +576,13 @@ namespace Catch {
data.message = static_cast(message);
AssertionResult assertionResult{ m_lastAssertionInfo, data };
assertionEnded( assertionResult );
- if( !assertionResult.isOk() )
+ if ( !assertionResult.isOk() ) {
populateReaction( reaction );
+ } else if ( resultType == ResultWas::ExplicitSkip ) {
+ // TODO: Need to handle this explicitly, as ExplicitSkip is
+ // considered "OK"
+ reaction.shouldSkip = true;
+ }
}
void RunContext::handleUnexpectedExceptionNotThrown(
AssertionInfo const& info,
diff --git a/src/catch2/internal/catch_test_failure_exception.hpp b/src/catch2/internal/catch_test_failure_exception.hpp
index 810a81c9..13c5fc08 100644
--- a/src/catch2/internal/catch_test_failure_exception.hpp
+++ b/src/catch2/internal/catch_test_failure_exception.hpp
@@ -20,6 +20,9 @@ namespace Catch {
*/
[[noreturn]] void throw_test_failure_exception();
+ //! Used to signal that the remainder of a test should be skipped
+ struct TestSkipException{};
+
} // namespace Catch
#endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED
diff --git a/src/catch2/reporters/catch_reporter_automake.cpp b/src/catch2/reporters/catch_reporter_automake.cpp
index 0660d092..993b594b 100644
--- a/src/catch2/reporters/catch_reporter_automake.cpp
+++ b/src/catch2/reporters/catch_reporter_automake.cpp
@@ -17,7 +17,9 @@ namespace Catch {
void AutomakeReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
// Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR.
m_stream << ":test-result: ";
- if (_testCaseStats.totals.assertions.allPassed()) {
+ if ( _testCaseStats.totals.testCases.skipped > 0 ) {
+ m_stream << "SKIP";
+ } else if (_testCaseStats.totals.assertions.allPassed()) {
m_stream << "PASS";
} else if (_testCaseStats.totals.assertions.allOk()) {
m_stream << "XFAIL";
diff --git a/src/catch2/reporters/catch_reporter_compact.cpp b/src/catch2/reporters/catch_reporter_compact.cpp
index d8088457..643626ea 100644
--- a/src/catch2/reporters/catch_reporter_compact.cpp
+++ b/src/catch2/reporters/catch_reporter_compact.cpp
@@ -105,6 +105,11 @@ public:
printIssue("explicitly");
printRemainingMessages(Colour::None);
break;
+ case ResultWas::ExplicitSkip:
+ printResultType(Colour::Skip, "skipped"_sr);
+ printMessage();
+ printRemainingMessages();
+ break;
// These cases are here to prevent compiler warnings
case ResultWas::Unknown:
case ResultWas::FailureBit:
@@ -220,7 +225,7 @@ private:
// Drop out if result was successful and we're not printing those
if( !m_config->includeSuccessfulResults() && result.isOk() ) {
- if( result.getResultType() != ResultWas::Warning )
+ if( result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip )
return;
printInfoMessages = false;
}
diff --git a/src/catch2/reporters/catch_reporter_console.cpp b/src/catch2/reporters/catch_reporter_console.cpp
index 0edb121e..b394d2be 100644
--- a/src/catch2/reporters/catch_reporter_console.cpp
+++ b/src/catch2/reporters/catch_reporter_console.cpp
@@ -111,6 +111,14 @@ public:
if (_stats.infoMessages.size() > 1)
messageLabel = "explicitly with messages";
break;
+ case ResultWas::ExplicitSkip:
+ colour = Colour::Skip;
+ passOrFail = "SKIPPED"_sr;
+ if (_stats.infoMessages.size() == 1)
+ messageLabel = "explicitly with message";
+ if (_stats.infoMessages.size() > 1)
+ messageLabel = "explicitly with messages";
+ break;
// These cases are here to prevent compiler warnings
case ResultWas::Unknown:
case ResultWas::FailureBit:
@@ -185,13 +193,16 @@ std::size_t makeRatio( std::uint64_t number, std::uint64_t total ) {
return (ratio == 0 && number > 0) ? 1 : static_cast(ratio);
}
-std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) {
- if (i > j && i > k)
+std::size_t&
+findMax( std::size_t& i, std::size_t& j, std::size_t& k, std::size_t& l ) {
+ if (i > j && i > k && i > l)
return i;
- else if (j > k)
+ else if (j > k && j > l)
return j;
- else
+ else if (k > l)
return k;
+ else
+ return l;
}
enum class Justification { Left, Right };
@@ -400,7 +411,8 @@ void ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
// Drop out if result was successful but we're not printing them.
- if (!includeResults && result.getResultType() != ResultWas::Warning)
+ // TODO: Make configurable whether skips should be printed
+ if (!includeResults && result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip)
return;
lazyPrint();
@@ -603,10 +615,11 @@ void ConsoleReporter::printTotalsDivider(Totals const& totals) {
std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
- while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
- findMax(failedRatio, failedButOkRatio, passedRatio)++;
+ std::size_t skippedRatio = makeRatio(totals.testCases.skipped, totals.testCases.total());
+ while (failedRatio + failedButOkRatio + passedRatio + skippedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
+ findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)++;
while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
- findMax(failedRatio, failedButOkRatio, passedRatio)--;
+ findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)--;
m_stream << m_colour->guardColour( Colour::Error )
<< std::string( failedRatio, '=' )
@@ -619,6 +632,8 @@ void ConsoleReporter::printTotalsDivider(Totals const& totals) {
m_stream << m_colour->guardColour( Colour::Success )
<< std::string( passedRatio, '=' );
}
+ m_stream << m_colour->guardColour( Colour::Skip )
+ << std::string( skippedRatio, '=' );
} else {
m_stream << m_colour->guardColour( Colour::Warning )
<< std::string( CATCH_CONFIG_CONSOLE_WIDTH - 1, '=' );
diff --git a/src/catch2/reporters/catch_reporter_helpers.cpp b/src/catch2/reporters/catch_reporter_helpers.cpp
index f6aa6fc5..ffb32ffb 100644
--- a/src/catch2/reporters/catch_reporter_helpers.cpp
+++ b/src/catch2/reporters/catch_reporter_helpers.cpp
@@ -316,15 +316,22 @@ namespace Catch {
}
std::vector columns;
+ // Don't include "skipped assertions" in total count
+ const auto totalAssertionCount =
+ totals.assertions.total() - totals.assertions.skipped;
columns.push_back( SummaryColumn( "", Colour::None )
.addRow( totals.testCases.total() )
- .addRow( totals.assertions.total() ) );
+ .addRow( totalAssertionCount ) );
columns.push_back( SummaryColumn( "passed", Colour::Success )
.addRow( totals.testCases.passed )
.addRow( totals.assertions.passed ) );
columns.push_back( SummaryColumn( "failed", Colour::ResultError )
.addRow( totals.testCases.failed )
.addRow( totals.assertions.failed ) );
+ columns.push_back( SummaryColumn( "skipped", Colour::Skip )
+ .addRow( totals.testCases.skipped )
+ // Don't print "skipped assertions"
+ .addRow( 0 ) );
columns.push_back(
SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
.addRow( totals.testCases.failedButOk )
diff --git a/src/catch2/reporters/catch_reporter_junit.cpp b/src/catch2/reporters/catch_reporter_junit.cpp
index 837d0489..22d6526f 100644
--- a/src/catch2/reporters/catch_reporter_junit.cpp
+++ b/src/catch2/reporters/catch_reporter_junit.cpp
@@ -132,6 +132,7 @@ namespace Catch {
xml.writeAttribute( "name"_sr, stats.runInfo.name );
xml.writeAttribute( "errors"_sr, unexpectedExceptions );
xml.writeAttribute( "failures"_sr, stats.totals.assertions.failed-unexpectedExceptions );
+ xml.writeAttribute( "skipped"_sr, stats.totals.assertions.skipped );
xml.writeAttribute( "tests"_sr, stats.totals.assertions.total() );
xml.writeAttribute( "hostname"_sr, "tbd"_sr ); // !TBD
if( m_config->showDurations() == ShowDurations::Never )
@@ -244,7 +245,8 @@ namespace Catch {
void JunitReporter::writeAssertion( AssertionStats const& stats ) {
AssertionResult const& result = stats.assertionResult;
- if( !result.isOk() ) {
+ if ( !result.isOk() ||
+ result.getResultType() == ResultWas::ExplicitSkip ) {
std::string elementName;
switch( result.getResultType() ) {
case ResultWas::ThrewException:
@@ -256,7 +258,9 @@ namespace Catch {
case ResultWas::DidntThrowException:
elementName = "failure";
break;
-
+ case ResultWas::ExplicitSkip:
+ elementName = "skipped";
+ break;
// We should never see these here:
case ResultWas::Info:
case ResultWas::Warning:
@@ -274,7 +278,9 @@ namespace Catch {
xml.writeAttribute( "type"_sr, result.getTestMacroName() );
ReusableStringStream rss;
- if (stats.totals.assertions.total() > 0) {
+ if ( result.getResultType() == ResultWas::ExplicitSkip ) {
+ rss << "SKIPPED\n";
+ } else {
rss << "FAILED" << ":\n";
if (result.hasExpression()) {
rss << " ";
@@ -285,8 +291,6 @@ namespace Catch {
rss << "with expansion:\n";
rss << TextFlow::Column(result.getExpandedExpression()).indent(2) << '\n';
}
- } else {
- rss << '\n';
}
if( !result.getMessage().empty() )
diff --git a/src/catch2/reporters/catch_reporter_sonarqube.cpp b/src/catch2/reporters/catch_reporter_sonarqube.cpp
index 365979f4..ac59c87f 100644
--- a/src/catch2/reporters/catch_reporter_sonarqube.cpp
+++ b/src/catch2/reporters/catch_reporter_sonarqube.cpp
@@ -97,7 +97,8 @@ namespace Catch {
void SonarQubeReporter::writeAssertion(AssertionStats const& stats, bool okToFail) {
AssertionResult const& result = stats.assertionResult;
- if (!result.isOk()) {
+ if ( !result.isOk() ||
+ result.getResultType() == ResultWas::ExplicitSkip ) {
std::string elementName;
if (okToFail) {
elementName = "skipped";
@@ -108,15 +109,13 @@ namespace Catch {
elementName = "error";
break;
case ResultWas::ExplicitFailure:
- elementName = "failure";
- break;
case ResultWas::ExpressionFailed:
- elementName = "failure";
- break;
case ResultWas::DidntThrowException:
elementName = "failure";
break;
-
+ case ResultWas::ExplicitSkip:
+ elementName = "skipped";
+ break;
// We should never see these here:
case ResultWas::Info:
case ResultWas::Warning:
@@ -136,7 +135,9 @@ namespace Catch {
xml.writeAttribute("message"_sr, messageRss.str());
ReusableStringStream textRss;
- if (stats.totals.assertions.total() > 0) {
+ if ( result.getResultType() == ResultWas::ExplicitSkip ) {
+ textRss << "SKIPPED\n";
+ } else {
textRss << "FAILED:\n";
if (result.hasExpression()) {
textRss << '\t' << result.getExpressionInMacro() << '\n';
diff --git a/src/catch2/reporters/catch_reporter_tap.cpp b/src/catch2/reporters/catch_reporter_tap.cpp
index 59f8fb8b..d1257111 100644
--- a/src/catch2/reporters/catch_reporter_tap.cpp
+++ b/src/catch2/reporters/catch_reporter_tap.cpp
@@ -100,6 +100,12 @@ namespace Catch {
printIssue("explicitly"_sr);
printRemainingMessages(Colour::None);
break;
+ case ResultWas::ExplicitSkip:
+ printResultType(tapPassedString);
+ printIssue(" # SKIP"_sr);
+ printMessage();
+ printRemainingMessages();
+ break;
// These cases are here to prevent compiler warnings
case ResultWas::Unknown:
case ResultWas::FailureBit:
diff --git a/src/catch2/reporters/catch_reporter_teamcity.cpp b/src/catch2/reporters/catch_reporter_teamcity.cpp
index 1d002c27..32072800 100644
--- a/src/catch2/reporters/catch_reporter_teamcity.cpp
+++ b/src/catch2/reporters/catch_reporter_teamcity.cpp
@@ -59,7 +59,8 @@ namespace Catch {
void TeamCityReporter::assertionEnded(AssertionStats const& assertionStats) {
AssertionResult const& result = assertionStats.assertionResult;
- if (!result.isOk()) {
+ if ( !result.isOk() ||
+ result.getResultType() == ResultWas::ExplicitSkip ) {
ReusableStringStream msg;
if (!m_headerPrintedForThisSection)
@@ -84,6 +85,9 @@ namespace Catch {
case ResultWas::ExplicitFailure:
msg << "explicit failure";
break;
+ case ResultWas::ExplicitSkip:
+ msg << "explicit skip";
+ break;
// We shouldn't get here because of the isOk() test
case ResultWas::Ok:
@@ -111,18 +115,16 @@ namespace Catch {
" " << result.getExpandedExpression() << '\n';
}
- if (currentTestCaseInfo->okToFail()) {
+ if ( result.getResultType() == ResultWas::ExplicitSkip ) {
+ m_stream << "##teamcity[testIgnored";
+ } else if ( currentTestCaseInfo->okToFail() ) {
msg << "- failure ignore as test marked as 'ok to fail'\n";
- m_stream << "##teamcity[testIgnored"
- << " name='" << escape(currentTestCaseInfo->name) << '\''
- << " message='" << escape(msg.str()) << '\''
- << "]\n";
+ m_stream << "##teamcity[testIgnored";
} else {
- m_stream << "##teamcity[testFailed"
- << " name='" << escape(currentTestCaseInfo->name) << '\''
- << " message='" << escape(msg.str()) << '\''
- << "]\n";
+ m_stream << "##teamcity[testFailed";
}
+ m_stream << " name='" << escape( currentTestCaseInfo->name ) << '\''
+ << " message='" << escape( msg.str() ) << '\'' << "]\n";
}
m_stream.flush();
}
diff --git a/src/catch2/reporters/catch_reporter_xml.cpp b/src/catch2/reporters/catch_reporter_xml.cpp
index 57fa1cab..011f9006 100644
--- a/src/catch2/reporters/catch_reporter_xml.cpp
+++ b/src/catch2/reporters/catch_reporter_xml.cpp
@@ -108,9 +108,10 @@ namespace Catch {
}
// Drop out if result was successful but we're not printing them.
- if( !includeResults && result.getResultType() != ResultWas::Warning )
+ if ( !includeResults && result.getResultType() != ResultWas::Warning &&
+ result.getResultType() != ResultWas::ExplicitSkip ) {
return;
-
+ }
// Print the expression if there is one.
if( result.hasExpression() ) {
@@ -153,6 +154,12 @@ namespace Catch {
m_xml.writeText( result.getMessage() );
m_xml.endElement();
break;
+ case ResultWas::ExplicitSkip:
+ m_xml.startElement( "Skip" );
+ writeSourceInfo( result.getSourceInfo() );
+ m_xml.writeText( result.getMessage() );
+ m_xml.endElement();
+ break;
default:
break;
}
@@ -163,15 +170,18 @@ namespace Catch {
void XmlReporter::sectionEnded( SectionStats const& sectionStats ) {
StreamingReporterBase::sectionEnded( sectionStats );
- if( --m_sectionDepth > 0 ) {
- XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
- e.writeAttribute( "successes"_sr, sectionStats.assertions.passed );
- e.writeAttribute( "failures"_sr, sectionStats.assertions.failed );
- e.writeAttribute( "expectedFailures"_sr, sectionStats.assertions.failedButOk );
-
- if ( m_config->showDurations() == ShowDurations::Always )
- e.writeAttribute( "durationInSeconds"_sr, sectionStats.durationInSeconds );
+ if ( --m_sectionDepth > 0 ) {
+ {
+ XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
+ e.writeAttribute( "successes"_sr, sectionStats.assertions.passed );
+ e.writeAttribute( "failures"_sr, sectionStats.assertions.failed );
+ e.writeAttribute( "expectedFailures"_sr, sectionStats.assertions.failedButOk );
+ e.writeAttribute( "skipped"_sr, sectionStats.assertions.skipped > 0 );
+ if ( m_config->showDurations() == ShowDurations::Always )
+ e.writeAttribute( "durationInSeconds"_sr, sectionStats.durationInSeconds );
+ }
+ // Ends assertion tag
m_xml.endElement();
}
}
@@ -180,6 +190,7 @@ namespace Catch {
StreamingReporterBase::testCaseEnded( testCaseStats );
XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
e.writeAttribute( "success"_sr, testCaseStats.totals.assertions.allOk() );
+ e.writeAttribute( "skips"_sr, testCaseStats.totals.assertions.skipped );
if ( m_config->showDurations() == ShowDurations::Always )
e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() );
@@ -197,11 +208,13 @@ namespace Catch {
m_xml.scopedElement( "OverallResults" )
.writeAttribute( "successes"_sr, testRunStats.totals.assertions.passed )
.writeAttribute( "failures"_sr, testRunStats.totals.assertions.failed )
- .writeAttribute( "expectedFailures"_sr, testRunStats.totals.assertions.failedButOk );
+ .writeAttribute( "expectedFailures"_sr, testRunStats.totals.assertions.failedButOk )
+ .writeAttribute( "skips"_sr, testRunStats.totals.assertions.skipped );
m_xml.scopedElement( "OverallResultsCases")
.writeAttribute( "successes"_sr, testRunStats.totals.testCases.passed )
.writeAttribute( "failures"_sr, testRunStats.totals.testCases.failed )
- .writeAttribute( "expectedFailures"_sr, testRunStats.totals.testCases.failedButOk );
+ .writeAttribute( "expectedFailures"_sr, testRunStats.totals.testCases.failedButOk )
+ .writeAttribute( "skips"_sr, testRunStats.totals.testCases.skipped );
m_xml.endElement();
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index b40fbceb..023f478b 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -116,6 +116,7 @@ set(TEST_SOURCES
${SELF_TEST_DIR}/UsageTests/Generators.tests.cpp
${SELF_TEST_DIR}/UsageTests/Message.tests.cpp
${SELF_TEST_DIR}/UsageTests/Misc.tests.cpp
+ ${SELF_TEST_DIR}/UsageTests/Skip.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringByte.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringChrono.tests.cpp
${SELF_TEST_DIR}/UsageTests/ToStringGeneral.tests.cpp
@@ -272,6 +273,10 @@ add_test(NAME TestSpecs::OverrideFailureWithNoMatchedTests
COMMAND $ "___nonexistent_test___" --allow-running-no-tests
)
+add_test(NAME TestSpecs::OverrideAllSkipFailure
+ COMMAND $ "tests can be skipped dynamically at runtime" --allow-running-no-tests
+)
+
add_test(NAME TestSpecs::NonMatchingTestSpecIsRoundTrippable
COMMAND $ Tracker, "this test does not exist" "[nor does this tag]"
)
diff --git a/tests/ExtraTests/CMakeLists.txt b/tests/ExtraTests/CMakeLists.txt
index d5b27fba..4172d7a0 100644
--- a/tests/ExtraTests/CMakeLists.txt
+++ b/tests/ExtraTests/CMakeLists.txt
@@ -488,15 +488,32 @@ set_tests_properties(TestSpecs::EmptySpecWithNoTestsFails
PROPERTIES
WILL_FAIL ON
)
+
add_test(
NAME TestSpecs::OverrideFailureWithEmptySpec
COMMAND $ --allow-running-no-tests
)
+
add_test(
NAME List::Listeners::WorksWithoutRegisteredListeners
COMMAND $ --list-listeners
)
+
+
+add_executable(AllSkipped ${TESTS_DIR}/X93-AllSkipped.cpp)
+target_link_libraries(AllSkipped PRIVATE Catch2::Catch2WithMain)
+
+add_test(
+ NAME TestSpecs::SkippingAllTestsFails
+ COMMAND $
+)
+set_tests_properties(TestSpecs::SkippingAllTestsFails
+ PROPERTIES
+ WILL_FAIL ON
+)
+
set( EXTRA_TEST_BINARIES
+ AllSkipped
PrefixedMacros
DisabledMacros
DisabledExceptions-DefaultHandler
diff --git a/tests/ExtraTests/X93-AllSkipped.cpp b/tests/ExtraTests/X93-AllSkipped.cpp
new file mode 100644
index 00000000..8e7d0afe
--- /dev/null
+++ b/tests/ExtraTests/X93-AllSkipped.cpp
@@ -0,0 +1,16 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+
+#include
+
+TEST_CASE( "this test case is being skipped" ) { SKIP(); }
+
+TEST_CASE( "all sections in this test case are being skipped" ) {
+ SECTION( "A" ) { SKIP(); }
+ SECTION( "B" ) { SKIP(); }
+}
diff --git a/tests/SelfTest/Baselines/automake.sw.approved.txt b/tests/SelfTest/Baselines/automake.sw.approved.txt
index 332439a7..64e92396 100644
--- a/tests/SelfTest/Baselines/automake.sw.approved.txt
+++ b/tests/SelfTest/Baselines/automake.sw.approved.txt
@@ -297,6 +297,7 @@ Message from section two
:test-result: PASS X/level/1/b
:test-result: PASS XmlEncode
:test-result: PASS XmlWriter writes boolean attributes as true/false
+:test-result: SKIP a succeeding test can still be skipped
:test-result: PASS analyse no analysis
:test-result: PASS array -> toString
:test-result: PASS benchmark function call
@@ -309,10 +310,14 @@ Message from section two
:test-result: PASS comparisons between const int variables
:test-result: PASS comparisons between int variables
:test-result: PASS convertToBits
+:test-result: SKIP dynamic skipping works with generators
:test-result: PASS empty tags are not allowed
:test-result: PASS erfc_inv
:test-result: PASS estimate_clock_resolution
:test-result: PASS even more nested SECTION tests
+:test-result: XFAIL failed assertions before SKIP cause test case to fail
+:test-result: XFAIL failing for some generator values causes entire test case to fail
+:test-result: XFAIL failing in some unskipped sections causes entire test case to fail
:test-result: FAIL first tag
loose text artifact
:test-result: FAIL has printf
@@ -331,6 +336,10 @@ loose text artifact
:test-result: FAIL mix info, unscoped info and warning
:test-result: FAIL more nested SECTION tests
:test-result: PASS nested SECTION tests
+a!
+b1!
+!
+:test-result: FAIL nested sections can be skipped dynamically at runtime
:test-result: PASS non streamable - with conv. op
:test-result: PASS non-copyable objects
:test-result: PASS normal_cdf
@@ -352,9 +361,11 @@ loose text artifact
:test-result: PASS run_for_at_least, chronometer
:test-result: PASS run_for_at_least, int
:test-result: FAIL second tag
+:test-result: SKIP sections can be skipped dynamically at runtime
:test-result: FAIL send a single char to INFO
:test-result: FAIL sends information to INFO
:test-result: PASS shortened hide tags are split apart
+:test-result: SKIP skipped tests can optionally provide a reason
:test-result: PASS splitString
:test-result: FAIL stacks unscoped info in loops
:test-result: PASS startsWith
@@ -376,6 +387,7 @@ loose text artifact
:test-result: PASS strlen3
:test-result: PASS tables
:test-result: PASS tags with dots in later positions are not parsed as hidden
+:test-result: SKIP tests can be skipped dynamically at runtime
:test-result: FAIL thrown std::strings are translated
:test-result: PASS toString on const wchar_t const pointer returns the string contents
:test-result: PASS toString on const wchar_t pointer returns the string contents
diff --git a/tests/SelfTest/Baselines/automake.sw.multi.approved.txt b/tests/SelfTest/Baselines/automake.sw.multi.approved.txt
index a7461ae5..d6f5ebe9 100644
--- a/tests/SelfTest/Baselines/automake.sw.multi.approved.txt
+++ b/tests/SelfTest/Baselines/automake.sw.multi.approved.txt
@@ -290,6 +290,7 @@
:test-result: PASS X/level/1/b
:test-result: PASS XmlEncode
:test-result: PASS XmlWriter writes boolean attributes as true/false
+:test-result: SKIP a succeeding test can still be skipped
:test-result: PASS analyse no analysis
:test-result: PASS array -> toString
:test-result: PASS benchmark function call
@@ -302,10 +303,14 @@
:test-result: PASS comparisons between const int variables
:test-result: PASS comparisons between int variables
:test-result: PASS convertToBits
+:test-result: SKIP dynamic skipping works with generators
:test-result: PASS empty tags are not allowed
:test-result: PASS erfc_inv
:test-result: PASS estimate_clock_resolution
:test-result: PASS even more nested SECTION tests
+:test-result: XFAIL failed assertions before SKIP cause test case to fail
+:test-result: XFAIL failing for some generator values causes entire test case to fail
+:test-result: XFAIL failing in some unskipped sections causes entire test case to fail
:test-result: FAIL first tag
:test-result: FAIL has printf
:test-result: PASS is_unary_function
@@ -323,6 +328,7 @@
:test-result: FAIL mix info, unscoped info and warning
:test-result: FAIL more nested SECTION tests
:test-result: PASS nested SECTION tests
+:test-result: FAIL nested sections can be skipped dynamically at runtime
:test-result: PASS non streamable - with conv. op
:test-result: PASS non-copyable objects
:test-result: PASS normal_cdf
@@ -344,9 +350,11 @@
:test-result: PASS run_for_at_least, chronometer
:test-result: PASS run_for_at_least, int
:test-result: FAIL second tag
+:test-result: SKIP sections can be skipped dynamically at runtime
:test-result: FAIL send a single char to INFO
:test-result: FAIL sends information to INFO
:test-result: PASS shortened hide tags are split apart
+:test-result: SKIP skipped tests can optionally provide a reason
:test-result: PASS splitString
:test-result: FAIL stacks unscoped info in loops
:test-result: PASS startsWith
@@ -368,6 +376,7 @@
:test-result: PASS strlen3
:test-result: PASS tables
:test-result: PASS tags with dots in later positions are not parsed as hidden
+:test-result: SKIP tests can be skipped dynamically at runtime
:test-result: FAIL thrown std::strings are translated
:test-result: PASS toString on const wchar_t const pointer returns the string contents
:test-result: PASS toString on const wchar_t pointer returns the string contents
diff --git a/tests/SelfTest/Baselines/compact.sw.approved.txt b/tests/SelfTest/Baselines/compact.sw.approved.txt
index ff6b2875..1d8ea9a8 100644
--- a/tests/SelfTest/Baselines/compact.sw.approved.txt
+++ b/tests/SelfTest/Baselines/compact.sw.approved.txt
@@ -2060,6 +2060,8 @@ Xml.tests.cpp:: passed: encode( "[\x7F]" ) == "[\\x7F]" for: "[\x7F
Xml.tests.cpp:: passed: stream.str(), ContainsSubstring(R"(attr1="true")") && ContainsSubstring(R"(attr2="false")") for: "
" ( contains: "attr1="true"" and contains: "attr2="false"" )
+Skip.tests.cpp:: passed:
+Skip.tests.cpp:: skipped:
InternalBenchmark.tests.cpp:: passed: analysis.mean.point.count() == 23 for: 23.0 == 23
InternalBenchmark.tests.cpp:: passed: analysis.mean.lower_bound.count() == 23 for: 23.0 == 23
InternalBenchmark.tests.cpp:: passed: analysis.mean.upper_bound.count() == 23 for: 23.0 == 23
@@ -2149,6 +2151,9 @@ FloatingPoint.tests.cpp:: passed: convertToBits( -0. ) == ( 1ULL <<
9223372036854775808 (0x)
FloatingPoint.tests.cpp:: passed: convertToBits( std::numeric_limits::denorm_min() ) == 1 for: 1 == 1
FloatingPoint.tests.cpp:: passed: convertToBits( std::numeric_limits::denorm_min() ) == 1 for: 1 == 1
+Skip.tests.cpp:: skipped: 'skipping because answer = 41'
+Skip.tests.cpp:: passed:
+Skip.tests.cpp:: skipped: 'skipping because answer = 43'
Tag.tests.cpp:: passed: Catch::TestCaseInfo("", { "test with an empty tag", "[]" }, dummySourceLineInfo)
InternalBenchmark.tests.cpp:: passed: erfc_inv(1.103560) == Approx(-0.09203687623843015) for: -0.0920368762 == Approx( -0.0920368762 )
InternalBenchmark.tests.cpp:: passed: erfc_inv(1.067400) == Approx(-0.05980291115763361) for: -0.0598029112 == Approx( -0.0598029112 )
@@ -2158,6 +2163,14 @@ InternalBenchmark.tests.cpp:: passed: res.outliers.total() == 0 for
Misc.tests.cpp:: passed:
Misc.tests.cpp:: passed:
Misc.tests.cpp:: passed:
+Skip.tests.cpp:: failed: 3 == 4
+Skip.tests.cpp:: skipped:
+Skip.tests.cpp:: failed: explicitly
+Skip.tests.cpp:: skipped:
+Skip.tests.cpp:: failed: explicitly
+Skip.tests.cpp:: skipped:
+Skip.tests.cpp:: skipped:
+Skip.tests.cpp:: failed: explicitly
loose text artifact
Clara.tests.cpp:: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function::value'
Clara.tests.cpp:: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function::value'
@@ -2215,6 +2228,10 @@ Misc.tests.cpp:: passed: a < b for: 1 < 2
Misc.tests.cpp:: passed: a != b for: 1 != 2
Misc.tests.cpp:: passed: b != a for: 2 != 1
Misc.tests.cpp:: passed: a != b for: 1 != 2
+a!
+b1!
+Skip.tests.cpp:: skipped:
+!
Tricky.tests.cpp:: passed: s == "7" for: "7" == "7"
Tricky.tests.cpp:: passed: ti == typeid(int) for: {?} == {?}
InternalBenchmark.tests.cpp:: passed: normal_cdf(0.000000) == Approx(0.50000000000000000) for: 0.5 == Approx( 0.5 )
@@ -2299,9 +2316,13 @@ InternalBenchmark.tests.cpp:: passed: x >= old_x for: 128 >= 64
InternalBenchmark.tests.cpp:: passed: Timing.elapsed >= time for: 128 ns >= 100 ns
InternalBenchmark.tests.cpp:: passed: Timing.result == Timing.iterations + 17 for: 145 == 145
InternalBenchmark.tests.cpp:: passed: Timing.iterations >= time.count() for: 128 >= 100
+Skip.tests.cpp:: passed:
+Skip.tests.cpp:: skipped:
+Skip.tests.cpp:: passed:
Misc.tests.cpp:: failed: false with 1 message: '3'
Message.tests.cpp:: failed: false with 2 messages: 'hi' and 'i := 7'
Tag.tests.cpp:: passed: testcase.tags, VectorContains( Tag( "magic-tag" ) ) && VectorContains( Tag( "."_catch_sr ) ) for: { {?}, {?} } ( Contains: {?} and Contains: {?} )
+Skip.tests.cpp:: skipped: 'skipping because answer = 43'
StringManip.tests.cpp:: passed: splitStringRef("", ','), Equals(std::vector()) for: { } Equals: { }
StringManip.tests.cpp:: passed: splitStringRef("abc", ','), Equals(std::vector{"abc"}) for: { abc } Equals: { abc }
StringManip.tests.cpp:: passed: splitStringRef("abc,def", ','), Equals(std::vector{"abc", "def"}) for: { abc, def } Equals: { abc, def }
@@ -2367,6 +2388,7 @@ Generators.tests.cpp:: passed: strlen(std::get<0>(data)) == static_
Generators.tests.cpp:: passed: strlen(std::get<0>(data)) == static_cast(std::get<1>(data)) for: 6 == 6
Tag.tests.cpp:: passed: testcase.tags.size() == 1 for: 1 == 1
Tag.tests.cpp:: passed: testcase.tags[0].original == "magic.tag"_catch_sr for: magic.tag == magic.tag
+Skip.tests.cpp:: skipped:
Exception.tests.cpp:: failed: unexpected exception with message: 'Why would you throw a std::string?'
Misc.tests.cpp:: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load""
@@ -2463,7 +2485,7 @@ InternalBenchmark.tests.cpp:: passed: med == 18. for: 18.0 == 18.0
InternalBenchmark.tests.cpp:: passed: q3 == 23. for: 23.0 == 23.0
Misc.tests.cpp:: passed:
Misc.tests.cpp:: passed:
-test cases: 395 | 305 passed | 83 failed | 7 failed as expected
-assertions: 2163 | 1993 passed | 143 failed | 27 failed as expected
+test cases: 404 | 305 passed | 84 failed | 5 skipped | 10 failed as expected
+assertions: 2173 | 1997 passed | 145 failed | 31 failed as expected
diff --git a/tests/SelfTest/Baselines/compact.sw.multi.approved.txt b/tests/SelfTest/Baselines/compact.sw.multi.approved.txt
index d11bdbae..1b450553 100644
--- a/tests/SelfTest/Baselines/compact.sw.multi.approved.txt
+++ b/tests/SelfTest/Baselines/compact.sw.multi.approved.txt
@@ -2053,6 +2053,8 @@ Xml.tests.cpp:: passed: encode( "[\x7F]" ) == "[\\x7F]" for: "[\x7F
Xml.tests.cpp:: passed: stream.str(), ContainsSubstring(R"(attr1="true")") && ContainsSubstring(R"(attr2="false")") for: "
" ( contains: "attr1="true"" and contains: "attr2="false"" )
+Skip.tests.cpp:: passed:
+Skip.tests.cpp:: skipped:
InternalBenchmark.tests.cpp:: passed: analysis.mean.point.count() == 23 for: 23.0 == 23
InternalBenchmark.tests.cpp:: passed: analysis.mean.lower_bound.count() == 23 for: 23.0 == 23
InternalBenchmark.tests.cpp:: passed: analysis.mean.upper_bound.count() == 23 for: 23.0 == 23
@@ -2142,6 +2144,9 @@ FloatingPoint.tests.cpp:: passed: convertToBits( -0. ) == ( 1ULL <<
9223372036854775808 (0x)
FloatingPoint.tests.cpp:: passed: convertToBits( std::numeric_limits::denorm_min() ) == 1 for: 1 == 1
FloatingPoint.tests.cpp:: passed: convertToBits( std::numeric_limits::denorm_min() ) == 1 for: 1 == 1
+Skip.tests.cpp:: skipped: 'skipping because answer = 41'
+Skip.tests.cpp:: passed:
+Skip.tests.cpp:: skipped: 'skipping because answer = 43'
Tag.tests.cpp:: passed: Catch::TestCaseInfo("", { "test with an empty tag", "[]" }, dummySourceLineInfo)
InternalBenchmark.tests.cpp:: passed: erfc_inv(1.103560) == Approx(-0.09203687623843015) for: -0.0920368762 == Approx( -0.0920368762 )
InternalBenchmark.tests.cpp:: passed: erfc_inv(1.067400) == Approx(-0.05980291115763361) for: -0.0598029112 == Approx( -0.0598029112 )
@@ -2151,6 +2156,14 @@ InternalBenchmark.tests.cpp:: passed: res.outliers.total() == 0 for
Misc.tests.cpp:: passed:
Misc.tests.cpp:: passed:
Misc.tests.cpp:: passed:
+Skip.tests.cpp:: failed: 3 == 4
+Skip.tests.cpp:: skipped:
+Skip.tests.cpp:: failed: explicitly
+Skip.tests.cpp:: skipped:
+Skip.tests.cpp:: failed: explicitly
+Skip.tests.cpp:: skipped:
+Skip.tests.cpp:: skipped:
+Skip.tests.cpp:: failed: explicitly
Clara.tests.cpp:: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function::value'
Clara.tests.cpp:: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function::value'
Clara.tests.cpp:: passed: with 1 message: 'Catch::Clara::Detail::is_unary_function::value'
@@ -2207,6 +2220,7 @@ Misc.tests.cpp:: passed: a < b for: 1 < 2
Misc.tests.cpp:: passed: a != b for: 1 != 2
Misc.tests.cpp:: passed: b != a for: 2 != 1
Misc.tests.cpp:: passed: a != b for: 1 != 2
+Skip.tests.cpp:: skipped:
Tricky.tests.cpp:: passed: s == "7" for: "7" == "7"
Tricky.tests.cpp:: passed: ti == typeid(int) for: {?} == {?}
InternalBenchmark.tests.cpp:: passed: normal_cdf(0.000000) == Approx(0.50000000000000000) for: 0.5 == Approx( 0.5 )
@@ -2291,9 +2305,13 @@ InternalBenchmark.tests.cpp:: passed: x >= old_x for: 128 >= 64
InternalBenchmark.tests.cpp:: passed: Timing.elapsed >= time for: 128 ns >= 100 ns
InternalBenchmark.tests.cpp:: passed: Timing.result == Timing.iterations + 17 for: 145 == 145
InternalBenchmark.tests.cpp:: passed: Timing.iterations >= time.count() for: 128 >= 100
+Skip.tests.cpp:: passed:
+Skip.tests.cpp:: skipped:
+Skip.tests.cpp:: passed:
Misc.tests.cpp:: failed: false with 1 message: '3'
Message.tests.cpp:: failed: false with 2 messages: 'hi' and 'i := 7'
Tag.tests.cpp:: passed: testcase.tags, VectorContains( Tag( "magic-tag" ) ) && VectorContains( Tag( "."_catch_sr ) ) for: { {?}, {?} } ( Contains: {?} and Contains: {?} )
+Skip.tests.cpp:: skipped: 'skipping because answer = 43'
StringManip.tests.cpp:: passed: splitStringRef("", ','), Equals(std::vector()) for: { } Equals: { }
StringManip.tests.cpp:: passed: splitStringRef("abc", ','), Equals(std::vector{"abc"}) for: { abc } Equals: { abc }
StringManip.tests.cpp:: passed: splitStringRef("abc,def", ','), Equals(std::vector{"abc", "def"}) for: { abc, def } Equals: { abc, def }
@@ -2359,6 +2377,7 @@ Generators.tests.cpp:: passed: strlen(std::get<0>(data)) == static_
Generators.tests.cpp:: passed: strlen(std::get<0>(data)) == static_cast(std::get<1>(data)) for: 6 == 6
Tag.tests.cpp:: passed: testcase.tags.size() == 1 for: 1 == 1
Tag.tests.cpp:: passed: testcase.tags[0].original == "magic.tag"_catch_sr for: magic.tag == magic.tag
+Skip.tests.cpp:: skipped:
Exception.tests.cpp:: failed: unexpected exception with message: 'Why would you throw a std::string?'
Misc.tests.cpp:: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load""
Misc.tests.cpp:: passed: result == "\"wide load\"" for: ""wide load"" == ""wide load""
@@ -2455,7 +2474,7 @@ InternalBenchmark.tests.cpp:: passed: med == 18. for: 18.0 == 18.0
InternalBenchmark.tests.cpp:: passed: q3 == 23. for: 23.0 == 23.0
Misc.tests.cpp:: passed:
Misc.tests.cpp:: passed:
-test cases: 395 | 305 passed | 83 failed | 7 failed as expected
-assertions: 2163 | 1993 passed | 143 failed | 27 failed as expected
+test cases: 404 | 305 passed | 84 failed | 5 skipped | 10 failed as expected
+assertions: 2173 | 1997 passed | 145 failed | 31 failed as expected
diff --git a/tests/SelfTest/Baselines/console.std.approved.txt b/tests/SelfTest/Baselines/console.std.approved.txt
index 39fd845b..dd3199f0 100644
--- a/tests/SelfTest/Baselines/console.std.approved.txt
+++ b/tests/SelfTest/Baselines/console.std.approved.txt
@@ -1164,6 +1164,14 @@ Exception.tests.cpp:: FAILED:
due to unexpected exception with message:
unexpected exception
+-------------------------------------------------------------------------------
+a succeeding test can still be skipped
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+
-------------------------------------------------------------------------------
checkedElse, failing
-------------------------------------------------------------------------------
@@ -1186,6 +1194,87 @@ Misc.tests.cpp:: FAILED:
with expansion:
false
+-------------------------------------------------------------------------------
+dynamic skipping works with generators
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+explicitly with message:
+ skipping because answer = 41
+
+-------------------------------------------------------------------------------
+dynamic skipping works with generators
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+explicitly with message:
+ skipping because answer = 43
+
+-------------------------------------------------------------------------------
+failed assertions before SKIP cause test case to fail
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: FAILED:
+ CHECK( 3 == 4 )
+
+Skip.tests.cpp:: SKIPPED:
+
+-------------------------------------------------------------------------------
+failing for some generator values causes entire test case to fail
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: FAILED:
+
+-------------------------------------------------------------------------------
+failing for some generator values causes entire test case to fail
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+
+-------------------------------------------------------------------------------
+failing for some generator values causes entire test case to fail
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: FAILED:
+
+-------------------------------------------------------------------------------
+failing for some generator values causes entire test case to fail
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+
+-------------------------------------------------------------------------------
+failing in some unskipped sections causes entire test case to fail
+ skipped
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+
+-------------------------------------------------------------------------------
+failing in some unskipped sections causes entire test case to fail
+ not skipped
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: FAILED:
+
loose text artifact
-------------------------------------------------------------------------------
just failure
@@ -1304,6 +1393,19 @@ Misc.tests.cpp:: FAILED:
with expansion:
1 == 2
+a!
+b1!
+-------------------------------------------------------------------------------
+nested sections can be skipped dynamically at runtime
+ B
+ B2
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+
+!
-------------------------------------------------------------------------------
not prints unscoped info from previous failures
-------------------------------------------------------------------------------
@@ -1338,6 +1440,15 @@ Message.tests.cpp:: FAILED:
with message:
this SHOULD be seen only ONCE
+-------------------------------------------------------------------------------
+sections can be skipped dynamically at runtime
+ skipped
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+
-------------------------------------------------------------------------------
send a single char to INFO
-------------------------------------------------------------------------------
@@ -1361,6 +1472,16 @@ with messages:
hi
i := 7
+-------------------------------------------------------------------------------
+skipped tests can optionally provide a reason
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+explicitly with message:
+ skipping because answer = 43
+
-------------------------------------------------------------------------------
stacks unscoped info in loops
-------------------------------------------------------------------------------
@@ -1383,6 +1504,14 @@ with messages:
5
6
+-------------------------------------------------------------------------------
+tests can be skipped dynamically at runtime
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+
-------------------------------------------------------------------------------
thrown std::strings are translated
-------------------------------------------------------------------------------
@@ -1394,6 +1523,6 @@ due to unexpected exception with message:
Why would you throw a std::string?
===============================================================================
-test cases: 395 | 319 passed | 69 failed | 7 failed as expected
-assertions: 2148 | 1993 passed | 128 failed | 27 failed as expected
+test cases: 404 | 319 passed | 69 failed | 6 skipped | 10 failed as expected
+assertions: 2156 | 1997 passed | 128 failed | 31 failed as expected
diff --git a/tests/SelfTest/Baselines/console.sw.approved.txt b/tests/SelfTest/Baselines/console.sw.approved.txt
index 57fa6239..48609d97 100644
--- a/tests/SelfTest/Baselines/console.sw.approved.txt
+++ b/tests/SelfTest/Baselines/console.sw.approved.txt
@@ -14659,6 +14659,16 @@ with expansion:
" ( contains: "attr1="true"" and contains: "attr2="false"" )
+-------------------------------------------------------------------------------
+a succeeding test can still be skipped
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: PASSED:
+
+Skip.tests.cpp:: SKIPPED:
+
-------------------------------------------------------------------------------
analyse no analysis
-------------------------------------------------------------------------------
@@ -15204,6 +15214,34 @@ FloatingPoint.tests.cpp:: PASSED:
with expansion:
1 == 1
+-------------------------------------------------------------------------------
+dynamic skipping works with generators
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+explicitly with message:
+ skipping because answer = 41
+
+-------------------------------------------------------------------------------
+dynamic skipping works with generators
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: PASSED:
+
+-------------------------------------------------------------------------------
+dynamic skipping works with generators
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+explicitly with message:
+ skipping because answer = 43
+
-------------------------------------------------------------------------------
empty tags are not allowed
-------------------------------------------------------------------------------
@@ -15279,6 +15317,67 @@ Misc.tests.cpp:
Misc.tests.cpp:: PASSED:
+-------------------------------------------------------------------------------
+failed assertions before SKIP cause test case to fail
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: FAILED:
+ CHECK( 3 == 4 )
+
+Skip.tests.cpp:: SKIPPED:
+
+-------------------------------------------------------------------------------
+failing for some generator values causes entire test case to fail
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: FAILED:
+
+-------------------------------------------------------------------------------
+failing for some generator values causes entire test case to fail
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+
+-------------------------------------------------------------------------------
+failing for some generator values causes entire test case to fail
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: FAILED:
+
+-------------------------------------------------------------------------------
+failing for some generator values causes entire test case to fail
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+
+-------------------------------------------------------------------------------
+failing in some unskipped sections causes entire test case to fail
+ skipped
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+
+-------------------------------------------------------------------------------
+failing in some unskipped sections causes entire test case to fail
+ not skipped
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: FAILED:
+
-------------------------------------------------------------------------------
first tag
-------------------------------------------------------------------------------
@@ -15775,6 +15874,40 @@ Misc.tests.cpp:: PASSED:
with expansion:
1 != 2
+a-------------------------------------------------------------------------------
+nested sections can be skipped dynamically at runtime
+ A
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+
+No assertions in section 'A'
+
+!
+b1-------------------------------------------------------------------------------
+nested sections can be skipped dynamically at runtime
+ B
+ B1
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+
+No assertions in section 'B1'
+
+!
+-------------------------------------------------------------------------------
+nested sections can be skipped dynamically at runtime
+ B
+ B2
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+
+!
-------------------------------------------------------------------------------
non streamable - with conv. op
-------------------------------------------------------------------------------
@@ -16376,6 +16509,33 @@ Misc.tests.cpp:
No assertions in test case 'second tag'
+-------------------------------------------------------------------------------
+sections can be skipped dynamically at runtime
+ not skipped
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: PASSED:
+
+-------------------------------------------------------------------------------
+sections can be skipped dynamically at runtime
+ skipped
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+
+-------------------------------------------------------------------------------
+sections can be skipped dynamically at runtime
+ also not skipped
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: PASSED:
+
-------------------------------------------------------------------------------
send a single char to INFO
-------------------------------------------------------------------------------
@@ -16410,6 +16570,16 @@ Tag.tests.cpp:: PASSED:
with expansion:
{ {?}, {?} } ( Contains: {?} and Contains: {?} )
+-------------------------------------------------------------------------------
+skipped tests can optionally provide a reason
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+explicitly with message:
+ skipping because answer = 43
+
-------------------------------------------------------------------------------
splitString
-------------------------------------------------------------------------------
@@ -16837,6 +17007,14 @@ Tag.tests.cpp:: PASSED:
with expansion:
magic.tag == magic.tag
+-------------------------------------------------------------------------------
+tests can be skipped dynamically at runtime
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+
-------------------------------------------------------------------------------
thrown std::strings are translated
-------------------------------------------------------------------------------
@@ -17544,6 +17722,6 @@ Misc.tests.cpp:
Misc.tests.cpp:: PASSED:
===============================================================================
-test cases: 395 | 305 passed | 83 failed | 7 failed as expected
-assertions: 2163 | 1993 passed | 143 failed | 27 failed as expected
+test cases: 404 | 305 passed | 84 failed | 5 skipped | 10 failed as expected
+assertions: 2173 | 1997 passed | 145 failed | 31 failed as expected
diff --git a/tests/SelfTest/Baselines/console.sw.multi.approved.txt b/tests/SelfTest/Baselines/console.sw.multi.approved.txt
index 6e5faa96..aa319412 100644
--- a/tests/SelfTest/Baselines/console.sw.multi.approved.txt
+++ b/tests/SelfTest/Baselines/console.sw.multi.approved.txt
@@ -14652,6 +14652,16 @@ with expansion:
" ( contains: "attr1="true"" and contains: "attr2="false"" )
+-------------------------------------------------------------------------------
+a succeeding test can still be skipped
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: PASSED:
+
+Skip.tests.cpp:: SKIPPED:
+
-------------------------------------------------------------------------------
analyse no analysis
-------------------------------------------------------------------------------
@@ -15197,6 +15207,34 @@ FloatingPoint.tests.cpp:: PASSED:
with expansion:
1 == 1
+-------------------------------------------------------------------------------
+dynamic skipping works with generators
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+explicitly with message:
+ skipping because answer = 41
+
+-------------------------------------------------------------------------------
+dynamic skipping works with generators
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: PASSED:
+
+-------------------------------------------------------------------------------
+dynamic skipping works with generators
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: SKIPPED:
+explicitly with message:
+ skipping because answer = 43
+
-------------------------------------------------------------------------------
empty tags are not allowed
-------------------------------------------------------------------------------
@@ -15272,6 +15310,67 @@ Misc.tests.cpp:
Misc.tests.cpp:: PASSED:
+-------------------------------------------------------------------------------
+failed assertions before SKIP cause test case to fail
+-------------------------------------------------------------------------------
+Skip.tests.cpp:
+...............................................................................
+
+Skip.tests.cpp:: FAILED:
+ CHECK( 3 == 4 )
+
+Skip.tests.cpp: