Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMartin Hořeňovský2026-02-09 19:05:39 +0100
committerMartin Hořeňovský2026-02-10 09:37:15 +0100
commitd079ee13ab137547ab26bd1ed5ca2858d7fbd847 (patch)
tree1e73da54d02eecbf095dd07bd4c0183d7a7f107b
parent0056cd4efb01ab65f02af188e137fc65d79e18f8 (diff)
downloadcatch3-d079ee13ab137547ab26bd1ed5ca2858d7fbd847.tar.gz
Allow generators to declare themselves (infinite)
This will be useful later to implement warning on infinitely running `GENERATE` expressions.
-rw-r--r--docs/deprecations.md15
-rw-r--r--docs/generators.md11
-rw-r--r--examples/300-Gen-OwnGenerator.cpp2
-rw-r--r--examples/301-Gen-MapTypeConversion.cpp2
-rw-r--r--src/catch2/generators/catch_generators.hpp14
-rw-r--r--src/catch2/generators/catch_generators_adapters.hpp20
-rw-r--r--src/catch2/generators/catch_generators_random.cpp5
-rw-r--r--src/catch2/generators/catch_generators_random.hpp3
-rw-r--r--src/catch2/generators/catch_generators_range.hpp4
-rw-r--r--src/catch2/interfaces/catch_interfaces_generatortracker.cpp2
-rw-r--r--src/catch2/interfaces/catch_interfaces_generatortracker.hpp9
-rw-r--r--tests/SelfTest/Baselines/automake.sw.approved.txt5
-rw-r--r--tests/SelfTest/Baselines/automake.sw.multi.approved.txt5
-rw-r--r--tests/SelfTest/Baselines/compact.sw.approved.txt18
-rw-r--r--tests/SelfTest/Baselines/compact.sw.multi.approved.txt18
-rw-r--r--tests/SelfTest/Baselines/console.std.approved.txt4
-rw-r--r--tests/SelfTest/Baselines/console.sw.approved.txt131
-rw-r--r--tests/SelfTest/Baselines/console.sw.multi.approved.txt131
-rw-r--r--tests/SelfTest/Baselines/junit.sw.approved.txt12
-rw-r--r--tests/SelfTest/Baselines/junit.sw.multi.approved.txt12
-rw-r--r--tests/SelfTest/Baselines/sonarqube.sw.approved.txt10
-rw-r--r--tests/SelfTest/Baselines/sonarqube.sw.multi.approved.txt10
-rw-r--r--tests/SelfTest/Baselines/tap.sw.approved.txt30
-rw-r--r--tests/SelfTest/Baselines/tap.sw.multi.approved.txt30
-rw-r--r--tests/SelfTest/Baselines/teamcity.sw.approved.txt10
-rw-r--r--tests/SelfTest/Baselines/teamcity.sw.multi.approved.txt10
-rw-r--r--tests/SelfTest/Baselines/xml.sw.approved.txt146
-rw-r--r--tests/SelfTest/Baselines/xml.sw.multi.approved.txt146
-rw-r--r--tests/SelfTest/IntrospectiveTests/GeneratorsImpl.tests.cpp69
-rw-r--r--tests/SelfTest/UsageTests/Generators.tests.cpp1
-rw-r--r--tests/SelfTest/UsageTests/Skip.tests.cpp2
31 files changed, 869 insertions, 18 deletions
diff --git a/docs/deprecations.md b/docs/deprecations.md
index 20312cd5..b7efa862 100644
--- a/docs/deprecations.md
+++ b/docs/deprecations.md
@@ -48,6 +48,21 @@ If you are mutating the fixture instance from within the test case, and
want to keep doing so in the future, mark the mutated members as `mutable`.
+### Generator interfaces
+
+#### Defaulted `UntypedGeneratorBase::isFinite()`
+
+> Deprecated in Catch2 vX.Y.Z
+
+The `UntypedGeneratorBase` currently provides a default implementation
+for `isFinite` that always returns `true`. This was done to keep backwards
+compatibility with pre-existing generators, as infinite generators can
+be diagnosed as errors in some cases.
+
+In the future, all generators will be expected to override `isFinite`.
+
+
+
---
[Home](Readme.md#top)
diff --git a/docs/generators.md b/docs/generators.md
index f45eac06..5db2941b 100644
--- a/docs/generators.md
+++ b/docs/generators.md
@@ -276,11 +276,22 @@ struct IGenerator : GeneratorUntypedBase {
* Going backwards is not supported.
*/
virtual void skipToNthElementImpl( std::size_t n );
+
+ /**
+ * 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 = 0;
};
```
> `skipToNthElementImpl` was added in Catch2 vX.Y.Z
+> `isFinite` was added in Catch2 vX.Y.Z
+
However, to be able to use your custom generator inside `GENERATE`, it
will need to be wrapped inside a `GeneratorWrapper<T>`.
`GeneratorWrapper<T>` is a value wrapper around a
diff --git a/examples/300-Gen-OwnGenerator.cpp b/examples/300-Gen-OwnGenerator.cpp
index b7f9d5da..ff28ad73 100644
--- a/examples/300-Gen-OwnGenerator.cpp
+++ b/examples/300-Gen-OwnGenerator.cpp
@@ -40,6 +40,8 @@ public:
return true;
}
+ bool isFinite() const override { return false; }
+
// Note: this improves the performance only a bit, but it is here
// to show how you can override the skip functionality.
void skipToNthElementImpl( std::size_t n ) override {
diff --git a/examples/301-Gen-MapTypeConversion.cpp b/examples/301-Gen-MapTypeConversion.cpp
index 0a284483..26f7538c 100644
--- a/examples/301-Gen-MapTypeConversion.cpp
+++ b/examples/301-Gen-MapTypeConversion.cpp
@@ -40,6 +40,8 @@ public:
bool next() override {
return !!std::getline(m_stream, m_line);
}
+
+ bool isFinite() const override { return true; }
};
std::string const& LineGenerator::get() const {
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>;
diff --git a/tests/SelfTest/Baselines/automake.sw.approved.txt b/tests/SelfTest/Baselines/automake.sw.approved.txt
index 314feb2f..bc019b38 100644
--- a/tests/SelfTest/Baselines/automake.sw.approved.txt
+++ b/tests/SelfTest/Baselines/automake.sw.approved.txt
@@ -169,6 +169,7 @@ Nor would this
:test-result: PASS Floating point matchers: double
:test-result: PASS Floating point matchers: float
:test-result: PASS GENERATE can combine literals and generators
+:test-result: PASS Generator adapters properly handle isFinite
:test-result: PASS Generators -- adapters
:test-result: PASS Generators -- simple
:test-result: PASS Generators can be skipped forward
@@ -226,11 +227,15 @@ Nor would this
:test-result: PASS Product with differing arities - std::tuple<int>
:test-result: PASS Random seed generation accepts known methods
:test-result: PASS Random seed generation reports unknown methods
+:test-result: PASS RandomGenerator reports itself as infinite - float
+:test-result: PASS RandomGenerator reports itself as infinite - int
+:test-result: PASS RandomGenerator reports itself as infinite - long double
:test-result: PASS Range type with sentinel
:test-result: FAIL Reconstruction should be based on stringification: #914
:test-result: FAIL Regex string matcher
:test-result: PASS Registering reporter with '::' in name fails
:test-result: PASS Regression test #1
+:test-result: PASS RepeatGenerator refuses infinite generators
:test-result: PASS Reporter's write listings to provided stream
:test-result: PASS Reproducer for #2309 - a very long description past 80 chars (default console width) with a late colon : blablabla
:test-result: PASS SUCCEED counts as a test pass
diff --git a/tests/SelfTest/Baselines/automake.sw.multi.approved.txt b/tests/SelfTest/Baselines/automake.sw.multi.approved.txt
index e646593d..3079c349 100644
--- a/tests/SelfTest/Baselines/automake.sw.multi.approved.txt
+++ b/tests/SelfTest/Baselines/automake.sw.multi.approved.txt
@@ -167,6 +167,7 @@
:test-result: PASS Floating point matchers: double
:test-result: PASS Floating point matchers: float
:test-result: PASS GENERATE can combine literals and generators
+:test-result: PASS Generator adapters properly handle isFinite
:test-result: PASS Generators -- adapters
:test-result: PASS Generators -- simple
:test-result: PASS Generators can be skipped forward
@@ -224,11 +225,15 @@
:test-result: PASS Product with differing arities - std::tuple<int>
:test-result: PASS Random seed generation accepts known methods
:test-result: PASS Random seed generation reports unknown methods
+:test-result: PASS RandomGenerator reports itself as infinite - float
+:test-result: PASS RandomGenerator reports itself as infinite - int
+:test-result: PASS RandomGenerator reports itself as infinite - long double
:test-result: PASS Range type with sentinel
:test-result: FAIL Reconstruction should be based on stringification: #914
:test-result: FAIL Regex string matcher
:test-result: PASS Registering reporter with '::' in name fails
:test-result: PASS Regression test #1
+:test-result: PASS RepeatGenerator refuses infinite generators
:test-result: PASS Reporter's write listings to provided stream
:test-result: PASS Reproducer for #2309 - a very long description past 80 chars (default console width) with a late colon : blablabla
:test-result: PASS SUCCEED counts as a test pass
diff --git a/tests/SelfTest/Baselines/compact.sw.approved.txt b/tests/SelfTest/Baselines/compact.sw.approved.txt
index 94123b41..f4da808e 100644
--- a/tests/SelfTest/Baselines/compact.sw.approved.txt
+++ b/tests/SelfTest/Baselines/compact.sw.approved.txt
@@ -751,6 +751,16 @@ Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
+GeneratorsImpl.tests.cpp:<line number>: passed: finite_cat.isFinite() for: true
+GeneratorsImpl.tests.cpp:<line number>: passed: !(infinite_cat.isFinite()) for: !false
+GeneratorsImpl.tests.cpp:<line number>: passed: take_1.isFinite() for: true
+GeneratorsImpl.tests.cpp:<line number>: passed: take_2.isFinite() for: true
+GeneratorsImpl.tests.cpp:<line number>: passed: finite_chunk.isFinite() for: true
+GeneratorsImpl.tests.cpp:<line number>: passed: !(infinite_chunk.isFinite()) for: !false
+GeneratorsImpl.tests.cpp:<line number>: passed: finite_map.isFinite() for: true
+GeneratorsImpl.tests.cpp:<line number>: passed: !(infinite_map.isFinite()) for: !false
+GeneratorsImpl.tests.cpp:<line number>: passed: finite_filter.isFinite() for: true
+GeneratorsImpl.tests.cpp:<line number>: passed: !(infinite_filter.isFinite()) for: !false
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
@@ -1559,6 +1569,9 @@ RandomNumberGeneration.tests.cpp:<line number>: passed: Catch::generateRandomSee
RandomNumberGeneration.tests.cpp:<line number>: passed: Catch::generateRandomSeed(method)
RandomNumberGeneration.tests.cpp:<line number>: passed: Catch::generateRandomSeed(method)
RandomNumberGeneration.tests.cpp:<line number>: passed: Catch::generateRandomSeed(static_cast<Catch::GenerateFrom>(77))
+GeneratorsImpl.tests.cpp:<line number>: passed: !(Catch::Generators::random( TestType{ 0 }, TestType{ 100 } ).isFinite()) for: !false
+GeneratorsImpl.tests.cpp:<line number>: passed: !(Catch::Generators::random( TestType{ 0 }, TestType{ 100 } ).isFinite()) for: !false
+GeneratorsImpl.tests.cpp:<line number>: passed: !(Catch::Generators::random( TestType{ 0 }, TestType{ 100 } ).isFinite()) for: !false
ToString.tests.cpp:<line number>: passed: Catch::Detail::stringify(UsesSentinel{}) == "{ }" for: "{ }" == "{ }"
Decomposition.tests.cpp:<line number>: failed: truthy(false) for: Hey, its truthy!
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches( "this STRING contains 'abc' as a substring" ) for: "this string contains 'abc' as a substring" matches "this STRING contains 'abc' as a substring" case sensitively
@@ -1566,6 +1579,7 @@ Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches( "con
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches( "this string contains 'abc' as a" ) for: "this string contains 'abc' as a substring" matches "this string contains 'abc' as a" case sensitively
Reporters.tests.cpp:<line number>: passed: registry.registerReporter( "with::doublecolons", Catch::Detail::make_unique<TestReporterFactory>() ), "'::' is not allowed in reporter name: 'with::doublecolons'" for: "'::' is not allowed in reporter name: 'with::doublecolons'" equals: "'::' is not allowed in reporter name: 'with::doublecolons'"
Matchers.tests.cpp:<line number>: passed: actual, !UnorderedEquals( expected ) for: { 'a', 'b' } not UnorderedEquals: { 'c', 'b' }
+GeneratorsImpl.tests.cpp:<line number>: passed: RepeatGenerator<int>( 2, random( 1, 100 ) )
Reporters.tests.cpp:<line number>: passed: !(factories.empty()) for: !false
Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring("fakeTag"s) for: "All available tags:
1 [fakeTag]
@@ -2946,7 +2960,7 @@ InternalBenchmark.tests.cpp:<line number>: passed: med == 18. for: 18.0 == 18.0
InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
Misc.tests.cpp:<line number>: passed:
Misc.tests.cpp:<line number>: passed:
-test cases: 443 | 323 passed | 96 failed | 6 skipped | 18 failed as expected
-assertions: 2362 | 2161 passed | 158 failed | 43 failed as expected
+test cases: 448 | 328 passed | 96 failed | 6 skipped | 18 failed as expected
+assertions: 2376 | 2175 passed | 158 failed | 43 failed as expected
diff --git a/tests/SelfTest/Baselines/compact.sw.multi.approved.txt b/tests/SelfTest/Baselines/compact.sw.multi.approved.txt
index e44e771d..d6348ab0 100644
--- a/tests/SelfTest/Baselines/compact.sw.multi.approved.txt
+++ b/tests/SelfTest/Baselines/compact.sw.multi.approved.txt
@@ -749,6 +749,16 @@ Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
+GeneratorsImpl.tests.cpp:<line number>: passed: finite_cat.isFinite() for: true
+GeneratorsImpl.tests.cpp:<line number>: passed: !(infinite_cat.isFinite()) for: !false
+GeneratorsImpl.tests.cpp:<line number>: passed: take_1.isFinite() for: true
+GeneratorsImpl.tests.cpp:<line number>: passed: take_2.isFinite() for: true
+GeneratorsImpl.tests.cpp:<line number>: passed: finite_chunk.isFinite() for: true
+GeneratorsImpl.tests.cpp:<line number>: passed: !(infinite_chunk.isFinite()) for: !false
+GeneratorsImpl.tests.cpp:<line number>: passed: finite_map.isFinite() for: true
+GeneratorsImpl.tests.cpp:<line number>: passed: !(infinite_map.isFinite()) for: !false
+GeneratorsImpl.tests.cpp:<line number>: passed: finite_filter.isFinite() for: true
+GeneratorsImpl.tests.cpp:<line number>: passed: !(infinite_filter.isFinite()) for: !false
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
Generators.tests.cpp:<line number>: passed: i % 2 == 0 for: 0 == 0
@@ -1557,6 +1567,9 @@ RandomNumberGeneration.tests.cpp:<line number>: passed: Catch::generateRandomSee
RandomNumberGeneration.tests.cpp:<line number>: passed: Catch::generateRandomSeed(method)
RandomNumberGeneration.tests.cpp:<line number>: passed: Catch::generateRandomSeed(method)
RandomNumberGeneration.tests.cpp:<line number>: passed: Catch::generateRandomSeed(static_cast<Catch::GenerateFrom>(77))
+GeneratorsImpl.tests.cpp:<line number>: passed: !(Catch::Generators::random( TestType{ 0 }, TestType{ 100 } ).isFinite()) for: !false
+GeneratorsImpl.tests.cpp:<line number>: passed: !(Catch::Generators::random( TestType{ 0 }, TestType{ 100 } ).isFinite()) for: !false
+GeneratorsImpl.tests.cpp:<line number>: passed: !(Catch::Generators::random( TestType{ 0 }, TestType{ 100 } ).isFinite()) for: !false
ToString.tests.cpp:<line number>: passed: Catch::Detail::stringify(UsesSentinel{}) == "{ }" for: "{ }" == "{ }"
Decomposition.tests.cpp:<line number>: failed: truthy(false) for: Hey, its truthy!
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches( "this STRING contains 'abc' as a substring" ) for: "this string contains 'abc' as a substring" matches "this STRING contains 'abc' as a substring" case sensitively
@@ -1564,6 +1577,7 @@ Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches( "con
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Matches( "this string contains 'abc' as a" ) for: "this string contains 'abc' as a substring" matches "this string contains 'abc' as a" case sensitively
Reporters.tests.cpp:<line number>: passed: registry.registerReporter( "with::doublecolons", Catch::Detail::make_unique<TestReporterFactory>() ), "'::' is not allowed in reporter name: 'with::doublecolons'" for: "'::' is not allowed in reporter name: 'with::doublecolons'" equals: "'::' is not allowed in reporter name: 'with::doublecolons'"
Matchers.tests.cpp:<line number>: passed: actual, !UnorderedEquals( expected ) for: { 'a', 'b' } not UnorderedEquals: { 'c', 'b' }
+GeneratorsImpl.tests.cpp:<line number>: passed: RepeatGenerator<int>( 2, random( 1, 100 ) )
Reporters.tests.cpp:<line number>: passed: !(factories.empty()) for: !false
Reporters.tests.cpp:<line number>: passed: listingString, ContainsSubstring("fakeTag"s) for: "All available tags:
1 [fakeTag]
@@ -2935,7 +2949,7 @@ InternalBenchmark.tests.cpp:<line number>: passed: med == 18. for: 18.0 == 18.0
InternalBenchmark.tests.cpp:<line number>: passed: q3 == 23. for: 23.0 == 23.0
Misc.tests.cpp:<line number>: passed:
Misc.tests.cpp:<line number>: passed:
-test cases: 443 | 323 passed | 96 failed | 6 skipped | 18 failed as expected
-assertions: 2362 | 2161 passed | 158 failed | 43 failed as expected
+test cases: 448 | 328 passed | 96 failed | 6 skipped | 18 failed as expected
+assertions: 2376 | 2175 passed | 158 failed | 43 failed as expected
diff --git a/tests/SelfTest/Baselines/console.std.approved.txt b/tests/SelfTest/Baselines/console.std.approved.txt
index 4529fef8..cd178a0c 100644
--- a/tests/SelfTest/Baselines/console.std.approved.txt
+++ b/tests/SelfTest/Baselines/console.std.approved.txt
@@ -1743,6 +1743,6 @@ due to unexpected exception with message:
Why would you throw a std::string?
===============================================================================
-test cases: 443 | 341 passed | 76 failed | 7 skipped | 19 failed as expected
-assertions: 2340 | 2161 passed | 136 failed | 43 failed as expected
+test cases: 448 | 346 passed | 76 failed | 7 skipped | 19 failed as expected
+assertions: 2354 | 2175 passed | 136 failed | 43 failed as expected
diff --git a/tests/SelfTest/Baselines/console.sw.approved.txt b/tests/SelfTest/Baselines/console.sw.approved.txt
index 48a4c85f..f5166de0 100644
--- a/tests/SelfTest/Baselines/console.sw.approved.txt
+++ b/tests/SelfTest/Baselines/console.sw.approved.txt
@@ -5315,6 +5315,91 @@ with expansion:
0 == 0
-------------------------------------------------------------------------------
+Generator adapters properly handle isFinite
+ concat generator
+-------------------------------------------------------------------------------
+GeneratorsImpl.tests.cpp:<line number>
+...............................................................................
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( finite_cat.isFinite() )
+with expansion:
+ true
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE_FALSE( infinite_cat.isFinite() )
+with expansion:
+ !false
+
+-------------------------------------------------------------------------------
+Generator adapters properly handle isFinite
+ take generator
+-------------------------------------------------------------------------------
+GeneratorsImpl.tests.cpp:<line number>
+...............................................................................
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( take_1.isFinite() )
+with expansion:
+ true
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( take_2.isFinite() )
+with expansion:
+ true
+
+-------------------------------------------------------------------------------
+Generator adapters properly handle isFinite
+ chunk generator
+-------------------------------------------------------------------------------
+GeneratorsImpl.tests.cpp:<line number>
+...............................................................................
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE( finite_chunk.isFinite() )
+with expansion:
+ true
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED:
+ REQUIRE_FALSE( infinite_chunk.isFinite() )
+with expansion:
+ !false
+
+-------------------------------------------------------------------------------
+Generator adapters properly handle isFinite
+ map
+-------------------------------------------------------------------------------
+GeneratorsImpl.tests.cpp:<line number>
+...............................................................................
+
+GeneratorsImpl.tests.cpp:<line number>: PASSED: