diff --git a/docs/command-line.md b/docs/command-line.md
index 690dcaaa..640fb1d9 100644
--- a/docs/command-line.md
+++ b/docs/command-line.md
@@ -358,10 +358,13 @@ There are currently two warnings implemented:
// (e.g. `REQUIRE`) is encountered.
UnmatchedTestSpec // Fail test run if any of the CLI test specs did
// not match any tests.
+ InfiniteGenerators // Fail if GENERATE would run infinitely
```
> `UnmatchedTestSpec` was introduced in Catch2 3.0.1.
+> `InfiniteGenerators` was introduced in Catch2 vX.Y.Z
+
## Reporting timings
diff --git a/src/catch2/catch_config.cpp b/src/catch2/catch_config.cpp
index fef03d7d..f83821a7 100644
--- a/src/catch2/catch_config.cpp
+++ b/src/catch2/catch_config.cpp
@@ -197,6 +197,9 @@ namespace Catch {
bool Config::warnAboutUnmatchedTestSpecs() const {
return !!( m_data.warnings & WarnAbout::UnmatchedTestSpec );
}
+ bool Config::warnAboutInfiniteGenerators() const {
+ return !!( m_data.warnings & WarnAbout::InfiniteGenerator );
+ }
bool Config::zeroTestsCountAsSuccess() const { return m_data.allowZeroTests; }
ShowDurations Config::showDurations() const { return m_data.showDurations; }
double Config::minDuration() const { return m_data.minDuration; }
diff --git a/src/catch2/catch_config.hpp b/src/catch2/catch_config.hpp
index cdf286ad..8014eb9e 100644
--- a/src/catch2/catch_config.hpp
+++ b/src/catch2/catch_config.hpp
@@ -124,6 +124,7 @@ namespace Catch {
bool includeSuccessfulResults() const override;
bool warnAboutMissingAssertions() const override;
bool warnAboutUnmatchedTestSpecs() const override;
+ bool warnAboutInfiniteGenerators() const override;
bool zeroTestsCountAsSuccess() const override;
ShowDurations showDurations() const override;
double minDuration() const override;
diff --git a/src/catch2/interfaces/catch_interfaces_config.hpp b/src/catch2/interfaces/catch_interfaces_config.hpp
index 82a298db..db4745c3 100644
--- a/src/catch2/interfaces/catch_interfaces_config.hpp
+++ b/src/catch2/interfaces/catch_interfaces_config.hpp
@@ -29,6 +29,8 @@ namespace Catch {
NoAssertions = 0x01,
//! A command line test spec matched no test cases
UnmatchedTestSpec = 0x02,
+ //! The resulting generator in GENERATE is infinite
+ InfiniteGenerator = 0x04,
}; };
enum class ShowDurations {
@@ -71,6 +73,7 @@ namespace Catch {
virtual bool shouldDebugBreak() const = 0;
virtual bool warnAboutMissingAssertions() const = 0;
virtual bool warnAboutUnmatchedTestSpecs() const = 0;
+ virtual bool warnAboutInfiniteGenerators() const = 0;
virtual bool zeroTestsCountAsSuccess() const = 0;
virtual int abortAfter() const = 0;
virtual bool showInvisibles() const = 0;
diff --git a/src/catch2/internal/catch_commandline.cpp b/src/catch2/internal/catch_commandline.cpp
index cf9cbf6d..61825df9 100644
--- a/src/catch2/internal/catch_commandline.cpp
+++ b/src/catch2/internal/catch_commandline.cpp
@@ -32,6 +32,9 @@ namespace Catch {
} else if ( warning == "UnmatchedTestSpec" ) {
config.warnings = static_cast(config.warnings | WarnAbout::UnmatchedTestSpec);
return ParserResult::ok( ParseResultType::Matched );
+ } else if ( warning == "InfiniteGenerators" ) {
+ config.warnings = static_cast(config.warnings | WarnAbout::InfiniteGenerator);
+ return ParserResult::ok( ParseResultType::Matched );
}
return ParserResult ::runtimeError(
diff --git a/src/catch2/internal/catch_run_context.cpp b/src/catch2/internal/catch_run_context.cpp
index 5e5f95a4..8e04748e 100644
--- a/src/catch2/internal/catch_run_context.cpp
+++ b/src/catch2/internal/catch_run_context.cpp
@@ -21,7 +21,9 @@
#include
#include
#include
+#include
#include
+#include
#include
#include
@@ -495,6 +497,11 @@ namespace Catch {
currentTracker.addChild( CATCH_MOVE( newTracker ) );
ret->setGenerator( CATCH_MOVE( generator ) );
+ if ( m_config->warnAboutInfiniteGenerators() &&
+ !ret->getGenerator()->isFinite() ) {
+ // TBD: Would it be better to expand this macro inline?
+ FAIL( "GENERATE() would run infinitely" );
+ }
ret->open();
return ret;
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index c4168e3a..887c07f6 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -169,7 +169,7 @@ if(CATCH_ENABLE_COVERAGE)
endif()
# configure unit tests via CTest
-add_test(NAME RunTests COMMAND $ --order rand --rng-seed time)
+add_test(NAME RunTests COMMAND $ --order rand --rng-seed time --warn InfiniteGenerators)
set_tests_properties(RunTests PROPERTIES
FAIL_REGULAR_EXPRESSION "Filters:"
COST 15
diff --git a/tests/ExtraTests/CMakeLists.txt b/tests/ExtraTests/CMakeLists.txt
index 7e761931..d663efc8 100644
--- a/tests/ExtraTests/CMakeLists.txt
+++ b/tests/ExtraTests/CMakeLists.txt
@@ -589,3 +589,16 @@ set_tests_properties(ThreadSafetyTests::UnscopedMessagesAndAssertions
PASS_REGULAR_EXPRESSION "assertions: 401 \\| 401 failed as expected"
RUN_SERIAL ON
)
+
+add_executable(InfiniteGenerators ${TESTS_DIR}/X95-InfiniteGenerators.cpp)
+target_link_libraries(InfiniteGenerators PRIVATE Catch2::Catch2WithMain)
+
+add_test(
+ NAME Warnings::InfiniteGenerators
+ COMMAND $ --warn InfiniteGenerators
+)
+set_tests_properties(Warnings::InfiniteGenerators
+ PROPERTIES
+ PASS_REGULAR_EXPRESSION "test cases: 1 \\| 1 failed"
+ TIMEOUT 5
+)
diff --git a/tests/ExtraTests/X95-InfiniteGenerators.cpp b/tests/ExtraTests/X95-InfiniteGenerators.cpp
new file mode 100644
index 00000000..31389107
--- /dev/null
+++ b/tests/ExtraTests/X95-InfiniteGenerators.cpp
@@ -0,0 +1,36 @@
+
+// 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
+
+/**\file
+ * Checks that GENERATE over infinite generator errors out when the tests are
+ * run with `-warn InfiniteGenerators`
+ */
+
+#include
+#include
+
+namespace {
+ static int ONE = 1;
+ class infinite_generator : public Catch::Generators::IGenerator {
+ public:
+
+ int const& get() const override { return ONE; }
+ bool next() override { return true; }
+ auto isFinite() const -> bool override { return false; }
+ };
+
+ static auto make_infinite_generator()
+ -> Catch::Generators::GeneratorWrapper {
+ return { new infinite_generator() };
+ }
+
+} // namespace
+
+TEST_CASE() {
+ auto _ = GENERATE( make_infinite_generator() );
+}
diff --git a/tests/SelfTest/Baselines/compact.sw.approved.txt b/tests/SelfTest/Baselines/compact.sw.approved.txt
index f4da808e..e0a691f0 100644
--- a/tests/SelfTest/Baselines/compact.sw.approved.txt
+++ b/tests/SelfTest/Baselines/compact.sw.approved.txt
@@ -1446,8 +1446,8 @@ TestSpecParser.tests.cpp:: passed: spec.matches( testCase ) for: tr
CmdLine.tests.cpp:: passed: cli.parse( { "test", "-w", "NoAssertions" } ) for: {?}
CmdLine.tests.cpp:: passed: config.warnings == WarnAbout::NoAssertions for: 1 == 1
CmdLine.tests.cpp:: passed: !(cli.parse( { "test", "-w", "NoTests" } )) for: !{?}
-CmdLine.tests.cpp:: passed: cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } ) for: {?}
-CmdLine.tests.cpp:: passed: config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) for: 3 == 3
+CmdLine.tests.cpp:: passed: cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } ) for: {?}
+CmdLine.tests.cpp:: passed: config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec | WarnAbout::InfiniteGenerator ) for: 7 == 7
Condition.tests.cpp:: passed: p == 0 for: 0 == 0
Condition.tests.cpp:: passed: p == pNULL for: 0 == 0
Condition.tests.cpp:: passed: p != 0 for: 0x != 0
diff --git a/tests/SelfTest/Baselines/compact.sw.multi.approved.txt b/tests/SelfTest/Baselines/compact.sw.multi.approved.txt
index d6348ab0..b72f4a5e 100644
--- a/tests/SelfTest/Baselines/compact.sw.multi.approved.txt
+++ b/tests/SelfTest/Baselines/compact.sw.multi.approved.txt
@@ -1444,8 +1444,8 @@ TestSpecParser.tests.cpp:: passed: spec.matches( testCase ) for: tr
CmdLine.tests.cpp:: passed: cli.parse( { "test", "-w", "NoAssertions" } ) for: {?}
CmdLine.tests.cpp:: passed: config.warnings == WarnAbout::NoAssertions for: 1 == 1
CmdLine.tests.cpp:: passed: !(cli.parse( { "test", "-w", "NoTests" } )) for: !{?}
-CmdLine.tests.cpp:: passed: cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } ) for: {?}
-CmdLine.tests.cpp:: passed: config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) for: 3 == 3
+CmdLine.tests.cpp:: passed: cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } ) for: {?}
+CmdLine.tests.cpp:: passed: config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec | WarnAbout::InfiniteGenerator ) for: 7 == 7
Condition.tests.cpp:: passed: p == 0 for: 0 == 0
Condition.tests.cpp:: passed: p == pNULL for: 0 == 0
Condition.tests.cpp:: passed: p != 0 for: 0x != 0
diff --git a/tests/SelfTest/Baselines/console.sw.approved.txt b/tests/SelfTest/Baselines/console.sw.approved.txt
index f5166de0..4af80f47 100644
--- a/tests/SelfTest/Baselines/console.sw.approved.txt
+++ b/tests/SelfTest/Baselines/console.sw.approved.txt
@@ -9425,14 +9425,14 @@ CmdLine.tests.cpp:
...............................................................................
CmdLine.tests.cpp:: PASSED:
- REQUIRE( cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } ) )
+ REQUIRE( cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } ) )
with expansion:
{?}
CmdLine.tests.cpp:: PASSED:
- REQUIRE( config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) )
+ REQUIRE( config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec | WarnAbout::InfiniteGenerator ) )
with expansion:
- 3 == 3
+ 7 == 7
-------------------------------------------------------------------------------
Pointers can be compared to null
diff --git a/tests/SelfTest/Baselines/console.sw.multi.approved.txt b/tests/SelfTest/Baselines/console.sw.multi.approved.txt
index bfb0f4bb..2eadff97 100644
--- a/tests/SelfTest/Baselines/console.sw.multi.approved.txt
+++ b/tests/SelfTest/Baselines/console.sw.multi.approved.txt
@@ -9423,14 +9423,14 @@ CmdLine.tests.cpp:
...............................................................................
CmdLine.tests.cpp:: PASSED:
- REQUIRE( cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } ) )
+ REQUIRE( cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } ) )
with expansion:
{?}
CmdLine.tests.cpp:: PASSED:
- REQUIRE( config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) )
+ REQUIRE( config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec | WarnAbout::InfiniteGenerator ) )
with expansion:
- 3 == 3
+ 7 == 7
-------------------------------------------------------------------------------
Pointers can be compared to null
diff --git a/tests/SelfTest/Baselines/tap.sw.approved.txt b/tests/SelfTest/Baselines/tap.sw.approved.txt
index 0c303618..c4e9dccb 100644
--- a/tests/SelfTest/Baselines/tap.sw.approved.txt
+++ b/tests/SelfTest/Baselines/tap.sw.approved.txt
@@ -2371,9 +2371,9 @@ ok {test-number} - config.warnings == WarnAbout::NoAssertions for: 1 == 1
# Parsing warnings
ok {test-number} - !(cli.parse( { "test", "-w", "NoTests" } )) for: !{?}
# Parsing warnings
-ok {test-number} - cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } ) for: {?}
+ok {test-number} - cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } ) for: {?}
# Parsing warnings
-ok {test-number} - config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) for: 3 == 3
+ok {test-number} - config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec | WarnAbout::InfiniteGenerator ) for: 7 == 7
# Pointers can be compared to null
ok {test-number} - p == 0 for: 0 == 0
# Pointers can be compared to null
diff --git a/tests/SelfTest/Baselines/tap.sw.multi.approved.txt b/tests/SelfTest/Baselines/tap.sw.multi.approved.txt
index 611983af..54f36be0 100644
--- a/tests/SelfTest/Baselines/tap.sw.multi.approved.txt
+++ b/tests/SelfTest/Baselines/tap.sw.multi.approved.txt
@@ -2369,9 +2369,9 @@ ok {test-number} - config.warnings == WarnAbout::NoAssertions for: 1 == 1
# Parsing warnings
ok {test-number} - !(cli.parse( { "test", "-w", "NoTests" } )) for: !{?}
# Parsing warnings
-ok {test-number} - cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } ) for: {?}
+ok {test-number} - cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } ) for: {?}
# Parsing warnings
-ok {test-number} - config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) for: 3 == 3
+ok {test-number} - config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec | WarnAbout::InfiniteGenerator ) for: 7 == 7
# Pointers can be compared to null
ok {test-number} - p == 0 for: 0 == 0
# Pointers can be compared to null
diff --git a/tests/SelfTest/Baselines/xml.sw.approved.txt b/tests/SelfTest/Baselines/xml.sw.approved.txt
index bd5a725c..f8f1ff29 100644
--- a/tests/SelfTest/Baselines/xml.sw.approved.txt
+++ b/tests/SelfTest/Baselines/xml.sw.approved.txt
@@ -11291,7 +11291,7 @@ Approx( 1.21999999999999997 )
- cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } )
+ cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } )
{?}
@@ -11299,10 +11299,10 @@ Approx( 1.21999999999999997 )
- config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec )
+ config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec | WarnAbout::InfiniteGenerator )
- 3 == 3
+ 7 == 7
diff --git a/tests/SelfTest/Baselines/xml.sw.multi.approved.txt b/tests/SelfTest/Baselines/xml.sw.multi.approved.txt
index 3bdd4518..f37883d1 100644
--- a/tests/SelfTest/Baselines/xml.sw.multi.approved.txt
+++ b/tests/SelfTest/Baselines/xml.sw.multi.approved.txt
@@ -11291,7 +11291,7 @@ Approx( 1.21999999999999997 )
- cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } )
+ cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } )
{?}
@@ -11299,10 +11299,10 @@ Approx( 1.21999999999999997 )
- config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec )
+ config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec | WarnAbout::InfiniteGenerator )
- 3 == 3
+ 7 == 7
diff --git a/tests/SelfTest/IntrospectiveTests/CmdLine.tests.cpp b/tests/SelfTest/IntrospectiveTests/CmdLine.tests.cpp
index 2cb7cae2..c797ce5c 100644
--- a/tests/SelfTest/IntrospectiveTests/CmdLine.tests.cpp
+++ b/tests/SelfTest/IntrospectiveTests/CmdLine.tests.cpp
@@ -413,9 +413,10 @@ TEST_CASE( "Parsing warnings", "[cli][warnings]" ) {
SECTION( "Combining multiple warnings" ) {
REQUIRE( cli.parse( { "test",
"--warn", "NoAssertions",
- "--warn", "UnmatchedTestSpec" } ) );
+ "--warn", "UnmatchedTestSpec",
+ "--warn", "InfiniteGenerators" } ) );
- REQUIRE( config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) );
+ REQUIRE( config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec | WarnAbout::InfiniteGenerator ) );
}
}