diff options
| author | Martin Hořeňovský | 2026-02-09 19:05:39 +0100 |
|---|---|---|
| committer | Martin Hořeňovský | 2026-02-10 09:37:15 +0100 |
| commit | d079ee13ab137547ab26bd1ed5ca2858d7fbd847 (patch) | |
| tree | 1e73da54d02eecbf095dd07bd4c0183d7a7f107b /src/catch2 | |
| parent | 0056cd4efb01ab65f02af188e137fc65d79e18f8 (diff) | |
| download | catch3-d079ee13ab137547ab26bd1ed5ca2858d7fbd847.tar.gz | |
Allow generators to declare themselves (infinite)
This will be useful later to implement warning on infinitely
running `GENERATE` expressions.
Diffstat (limited to 'src/catch2')
7 files changed, 57 insertions, 0 deletions
diff --git a/src/catch2/generators/catch_generators.hpp b/src/catch2/generators/catch_generators.hpp index e64f9b5f..719775fb 100644 --- a/src/catch2/generators/catch_generators.hpp +++ b/src/catch2/generators/catch_generators.hpp @@ -64,6 +64,8 @@ namespace Detail { bool next() { return m_generator->countedNext(); } + + bool isFinite() const { return m_generator->isFinite(); } }; @@ -84,6 +86,8 @@ namespace Detail { bool next() override { return false; } + + bool isFinite() const override { return true; } }; template<typename T> @@ -112,6 +116,8 @@ namespace Detail { ++m_idx; return m_idx < m_values.size(); } + + bool isFinite() const override { return true; } }; template <typename T, typename DecayedT = std::decay_t<T>> @@ -176,6 +182,14 @@ namespace Detail { } return m_current < m_generators.size(); } + + bool isFinite() const override { + for (auto const& gen : m_generators) { + if (!gen.isFinite()) { return false; + } + } + return true; + } }; diff --git a/src/catch2/generators/catch_generators_adapters.hpp b/src/catch2/generators/catch_generators_adapters.hpp index 35c103ce..2f6d8ed3 100644 --- a/src/catch2/generators/catch_generators_adapters.hpp +++ b/src/catch2/generators/catch_generators_adapters.hpp @@ -62,6 +62,8 @@ namespace Generators { } return success; } + + bool isFinite() const override { return true; } }; template <typename T> @@ -103,6 +105,8 @@ namespace Generators { while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true); return success; } + + bool isFinite() const override { return m_generator.isFinite(); } }; @@ -127,6 +131,9 @@ namespace Generators { m_target_repeats(repeats) { assert(m_target_repeats > 0 && "Repeat generator must repeat at least once"); + if (!m_generator.isFinite()) { + Detail::throw_generator_exception( "Cannot repeat infinite generator" ); + } } T const& get() const override { @@ -160,6 +167,8 @@ namespace Generators { } return m_current_repeat < m_target_repeats; } + + bool isFinite() const override { return m_generator.isFinite(); } }; template <typename T> @@ -207,6 +216,8 @@ namespace Generators { } return success; } + + bool isFinite() const override { return m_generator.isFinite(); } }; template <typename Func, typename U, typename T = FunctionReturnType<Func, U>> @@ -256,6 +267,8 @@ namespace Generators { } return true; } + + bool isFinite() const override { return m_generator.isFinite(); } }; template <typename T> @@ -297,6 +310,13 @@ namespace Generators { ++m_current_generator; return m_current_generator < m_generators.size(); } + + bool isFinite() const override { + for ( auto const& gen : m_generators ) { + if ( !gen.isFinite() ) { return false; } + } + return true; + } }; template <typename T, typename... Generators> diff --git a/src/catch2/generators/catch_generators_random.cpp b/src/catch2/generators/catch_generators_random.cpp index 00a8e634..d5163c16 100644 --- a/src/catch2/generators/catch_generators_random.cpp +++ b/src/catch2/generators/catch_generators_random.cpp @@ -37,5 +37,10 @@ namespace Catch { m_current_number = m_pimpl->dist( m_pimpl->rng ); return true; } + + bool RandomFloatingGenerator<long double>::isFinite() const { + return false; + } + } // namespace Generators } // namespace Catch diff --git a/src/catch2/generators/catch_generators_random.hpp b/src/catch2/generators/catch_generators_random.hpp index 71283561..e0287360 100644 --- a/src/catch2/generators/catch_generators_random.hpp +++ b/src/catch2/generators/catch_generators_random.hpp @@ -42,6 +42,7 @@ public: m_current_number = m_dist(m_rng); return true; } + bool isFinite() const override { return false; } }; template <> @@ -59,6 +60,7 @@ public: bool next() override; ~RandomFloatingGenerator() override; // = default + bool isFinite() const override; }; template <typename Integer> @@ -80,6 +82,7 @@ public: m_current_number = m_dist(m_rng); return true; } + bool isFinite() const override { return false; } }; template <typename T> diff --git a/src/catch2/generators/catch_generators_range.hpp b/src/catch2/generators/catch_generators_range.hpp index 55d673c2..62739b23 100644 --- a/src/catch2/generators/catch_generators_range.hpp +++ b/src/catch2/generators/catch_generators_range.hpp @@ -48,6 +48,8 @@ public: m_current += m_step; return (m_positive) ? (m_current < m_end) : (m_current > m_end); } + + bool isFinite() const override { return true; } }; template <typename T> @@ -87,6 +89,8 @@ public: ++m_current; return m_current != m_elems.size(); } + + bool isFinite() const override { return true; } }; template <typename InputIterator, diff --git a/src/catch2/interfaces/catch_interfaces_generatortracker.cpp b/src/catch2/interfaces/catch_interfaces_generatortracker.cpp index 4ac23ddb..8442be4e 100644 --- a/src/catch2/interfaces/catch_interfaces_generatortracker.cpp +++ b/src/catch2/interfaces/catch_interfaces_generatortracker.cpp @@ -55,5 +55,7 @@ namespace Catch { return m_stringReprCache; } + bool GeneratorUntypedBase::isFinite() const { return true; } + } // namespace Generators } // namespace Catch diff --git a/src/catch2/interfaces/catch_interfaces_generatortracker.hpp b/src/catch2/interfaces/catch_interfaces_generatortracker.hpp index eb3871bc..12cb9d79 100644 --- a/src/catch2/interfaces/catch_interfaces_generatortracker.hpp +++ b/src/catch2/interfaces/catch_interfaces_generatortracker.hpp @@ -88,6 +88,15 @@ namespace Catch { * comes first. */ StringRef currentElementAsString() const; + + /** + * Returns true if calls to `next` will eventually return false + * + * Note that for backwards compatibility this is currently defaulted + * to return `true`, but in the future all generators will have to + * provide their own implementation. + */ + virtual bool isFinite() const; }; using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>; |