diff options
| author | Martin Hořeňovský | 2026-02-10 09:16:03 +0100 |
|---|---|---|
| committer | Martin Hořeňovský | 2026-02-10 09:37:19 +0100 |
| commit | daadf42a0e21ac09abc1f286f875078b24e2dd4d (patch) | |
| tree | 1a680c2c82f71ad1701ce0b8e3c28ce9e50470b9 | |
| parent | d079ee13ab137547ab26bd1ed5ca2858d7fbd847 (diff) | |
| download | catch3-daadf42a0e21ac09abc1f286f875078b24e2dd4d.tar.gz | |
Add --warn InfiniteGenerators
| -rw-r--r-- | docs/command-line.md | 3 | ||||
| -rw-r--r-- | src/catch2/catch_config.cpp | 3 | ||||
| -rw-r--r-- | src/catch2/catch_config.hpp | 1 | ||||
| -rw-r--r-- | src/catch2/interfaces/catch_interfaces_config.hpp | 3 | ||||
| -rw-r--r-- | src/catch2/internal/catch_commandline.cpp | 3 | ||||
| -rw-r--r-- | src/catch2/internal/catch_run_context.cpp | 7 | ||||
| -rw-r--r-- | tests/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | tests/ExtraTests/CMakeLists.txt | 13 | ||||
| -rw-r--r-- | tests/ExtraTests/X95-InfiniteGenerators.cpp | 36 | ||||
| -rw-r--r-- | tests/SelfTest/Baselines/compact.sw.approved.txt | 4 | ||||
| -rw-r--r-- | tests/SelfTest/Baselines/compact.sw.multi.approved.txt | 4 | ||||
| -rw-r--r-- | tests/SelfTest/Baselines/console.sw.approved.txt | 6 | ||||
| -rw-r--r-- | tests/SelfTest/Baselines/console.sw.multi.approved.txt | 6 | ||||
| -rw-r--r-- | tests/SelfTest/Baselines/tap.sw.approved.txt | 4 | ||||
| -rw-r--r-- | tests/SelfTest/Baselines/tap.sw.multi.approved.txt | 4 | ||||
| -rw-r--r-- | tests/SelfTest/Baselines/xml.sw.approved.txt | 6 | ||||
| -rw-r--r-- | tests/SelfTest/Baselines/xml.sw.multi.approved.txt | 6 | ||||
| -rw-r--r-- | tests/SelfTest/IntrospectiveTests/CmdLine.tests.cpp | 5 |
18 files changed, 93 insertions, 23 deletions
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 + <a id="reporting-timings"></a> ## 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<WarnAbout::What>(config.warnings | WarnAbout::UnmatchedTestSpec); return ParserResult::ok( ParseResultType::Matched ); + } else if ( warning == "InfiniteGenerators" ) { + config.warnings = static_cast<WarnAbout::What>(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 <catch2/internal/catch_assertion_handler.hpp> #include <catch2/internal/catch_test_failure_exception.hpp> #include <catch2/internal/catch_thread_local.hpp> +#include <catch2/internal/catch_unreachable.hpp> #include <catch2/internal/catch_result_type.hpp> +#include <catch2/catch_test_macros.hpp> #include <cassert> #include <algorithm> @@ -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 $<TARGET_FILE:SelfTest> --order rand --rng-seed time) +add_test(NAME RunTests COMMAND $<TARGET_FILE:SelfTest> --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 $<TARGET_FILE:InfiniteGenerators> --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 <catch2/catch_test_macros.hpp> +#include <catch2/generators/catch_generators.hpp> + +namespace { + static int ONE = 1; + class infinite_generator : public Catch::Generators::IGenerator<int> { + 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<int> { + 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:<line number>: passed: spec.matches( testCase ) for: tr CmdLine.tests.cpp:<line number>: passed: cli.parse( { "test", "-w", "NoAssertions" } ) for: {?} CmdLine.tests.cpp:<line number>: passed: config.warnings == WarnAbout::NoAssertions for: 1 == 1 CmdLine.tests.cpp:<line number>: passed: !(cli.parse( { "test", "-w", "NoTests" } )) for: !{?} -CmdLine.tests.cpp:<line number>: passed: cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } ) for: {?} -CmdLine.tests.cpp:<line number>: passed: config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) for: 3 == 3 +CmdLine.tests.cpp:<line number>: passed: cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } ) for: {?} +CmdLine.tests.cpp:<line number>: passed: config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec | WarnAbout::InfiniteGenerator ) for: 7 == 7 Condition.tests.cpp:<line number>: passed: p == 0 for: 0 == 0 Condition.tests.cpp:<line number>: passed: p == pNULL for: 0 == 0 Condition.tests.cpp:<line number>: passed: p != 0 for: 0x<hex digits> != 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:<line number>: passed: spec.matches( testCase ) for: tr CmdLine.tests.cpp:<line number>: passed: cli.parse( { "test", "-w", "NoAssertions" } ) for: {?} CmdLine.tests.cpp:<line number>: passed: config.warnings == WarnAbout::NoAssertions for: 1 == 1 CmdLine.tests.cpp:<line number>: passed: !(cli.parse( { "test", "-w", "NoTests" } )) for: !{?} -CmdLine.tests.cpp:<line number>: passed: cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } ) for: {?} -CmdLine.tests.cpp:<line number>: passed: config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) for: 3 == 3 +CmdLine.tests.cpp:<line number>: passed: cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } ) for: {?} +CmdLine.tests.cpp:<line number>: passed: config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec | WarnAbout::InfiniteGenerator ) for: 7 == 7 Condition.tests.cpp:<line number>: passed: p == 0 for: 0 == 0 Condition.tests.cpp:<line number>: passed: p == pNULL for: 0 == 0 Condition.tests.cpp:<line number>: passed: p != 0 for: 0x<hex digits> != 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:<line number> ............................................................................... CmdLine.tests.cpp:<line number>: PASSED: - REQUIRE( cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } ) ) + REQUIRE( cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } ) ) with expansion: {?} CmdLine.tests.cpp:<line number>: 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:<line number> ............................................................................... CmdLine.tests.cpp:<line number>: PASSED: - REQUIRE( cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } ) ) + REQUIRE( cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } ) ) with expansion: {?} CmdLine.tests.cpp:<line number>: 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 ) <Section name="Combining multiple warnings" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > <Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > <Original> - cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } ) + cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } ) </Original> <Expanded> {?} @@ -11299,10 +11299,10 @@ Approx( 1.21999999999999997 ) </Expression> <Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > <Original> - config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) + config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec | WarnAbout::InfiniteGenerator ) </Original> <Expanded> - 3 == 3 + 7 == 7 </Expanded> </Expression> <OverallResults successes="2" failures="0" expectedFailures="0" skipped="false"/> 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 ) <Section name="Combining multiple warnings" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > <Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > <Original> - cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec" } ) + cli.parse( { "test", "--warn", "NoAssertions", "--warn", "UnmatchedTestSpec", "--warn", "InfiniteGenerators" } ) </Original> <Expanded> {?} @@ -11299,10 +11299,10 @@ Approx( 1.21999999999999997 ) </Expression> <Expression success="true" type="REQUIRE" filename="tests/<exe-name>/IntrospectiveTests/CmdLine.tests.cpp" > <Original> - config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec ) + config.warnings == ( WarnAbout::NoAssertions | WarnAbout::UnmatchedTestSpec | WarnAbout::InfiniteGenerator ) </Original> <Expanded> - 3 == 3 + 7 == 7 </Expanded> </Expression> <OverallResults successes="2" failures="0" expectedFailures="0" skipped="false"/> 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 ) ); } } |