Add a generator that takes an iterator pair

This commit is contained in:
Martin Hořeňovský 2019-10-06 13:49:50 +02:00
parent b8b765d55e
commit 319cb9e1da
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
8 changed files with 196 additions and 8 deletions

View File

@ -46,13 +46,16 @@ a test case,
* `MapGenerator<T, U, Func>` -- returns the result of applying `Func` * `MapGenerator<T, U, Func>` -- returns the result of applying `Func`
on elements from a different generator on elements from a different generator
* `ChunkGenerator<T>` -- returns chunks (inside `std::vector`) of n elements from a generator * `ChunkGenerator<T>` -- returns chunks (inside `std::vector`) of n elements from a generator
* 3 specific purpose generators * 4 specific purpose generators
* `RandomIntegerGenerator<Integral>` -- generates random Integrals from range * `RandomIntegerGenerator<Integral>` -- generates random Integrals from range
* `RandomFloatGenerator<Float>` -- generates random Floats from range * `RandomFloatGenerator<Float>` -- generates random Floats from range
* `RangeGenerator<T>` -- generates all values inside a specific range * `RangeGenerator<T>` -- generates all values inside a specific range
* `IteratorGenerator<T>` -- copies and returns values from an iterator range
> `ChunkGenerator<T>`, `RandomIntegerGenerator<Integral>`, `RandomFloatGenerator<Float>` and `RangeGenerator<T>` were introduced in Catch 2.7.0. > `ChunkGenerator<T>`, `RandomIntegerGenerator<Integral>`, `RandomFloatGenerator<Float>` and `RangeGenerator<T>` were introduced in Catch 2.7.0.
> `IteratorGenerator<T>` was introduced in Catch X.Y.Z.
The generators also have associated helper functions that infer their The generators also have associated helper functions that infer their
type, making their usage much nicer. These are type, making their usage much nicer. These are
@ -68,9 +71,12 @@ type, making their usage much nicer. These are
* `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator` * `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator`
* `range(start, end)` for `RangeGenerator<T>` with a step size of `1` * `range(start, end)` for `RangeGenerator<T>` with a step size of `1`
* `range(start, end, step)` for `RangeGenerator<T>` with a custom step size * `range(start, end, step)` for `RangeGenerator<T>` with a custom step size
* `from_range(InputIterator from, InputIterator to)` for `IteratorGenerator<T>`
> `chunk()`, `random()` and both `range()` functions were introduced in Catch 2.7.0. > `chunk()`, `random()` and both `range()` functions were introduced in Catch 2.7.0.
> `from_range` has been introduced in Catch X.Y.Z
And can be used as shown in the example below to create a generator And can be used as shown in the example below to create a generator
that returns 100 odd random number: that returns 100 odd random number:

View File

@ -128,6 +128,39 @@ GeneratorWrapper<T> range(T const& start, T const& end) {
} }
template <typename T>
class IteratorGenerator final : public IGenerator<T> {
static_assert(!std::is_same<T, bool>::value,
"IteratorGenerator currently does not support bools"
"because of std::vector<bool> specialization");
std::vector<T> m_elems;
size_t m_current = 0;
public:
template <typename InputIterator, typename InputSentinel>
IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {
if (m_elems.empty()) {
Catch::throw_exception(GeneratorException("IteratorGenerator received no valid values"));
}
}
T const& get() const override {
return m_elems[m_current];
}
bool next() override {
++m_current;
return m_current != m_elems.size();
}
};
template <typename InputIterator,
typename InputSentinel,
typename ResultType = typename std::iterator_traits<InputIterator>::value_type>
GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {
return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to));
}
} // namespace Generators } // namespace Generators
} // namespace Catch } // namespace Catch

View File

@ -310,6 +310,12 @@ Condition.tests.cpp:<line number>: passed: 6 == uc for: 6 == 6
Condition.tests.cpp:<line number>: passed: (std::numeric_limits<uint32_t>::max)() > ul for: 4294967295 (0x<hex digits>) > 4 Condition.tests.cpp:<line number>: passed: (std::numeric_limits<uint32_t>::max)() > ul for: 4294967295 (0x<hex digits>) > 4
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Contains("not there", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" contains: "not there" (case insensitive) Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Contains("not there", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" contains: "not there" (case insensitive)
Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Contains("STRING") for: "this string contains 'abc' as a substring" contains: "STRING" Matchers.tests.cpp:<line number>: failed: testStringForMatching(), Contains("STRING") for: "this string contains 'abc' as a substring" contains: "STRING"
Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
Generators.tests.cpp:<line number>: passed: elem % 2 == 1 for: 1 == 1
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'custom exception - not std'; expression was: throwCustom() Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'custom exception - not std'; expression was: throwCustom()
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'custom exception - not std'; expression was: throwCustom(), std::exception Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'custom exception - not std'; expression was: throwCustom(), std::exception
Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'custom std exception' Exception.tests.cpp:<line number>: failed: unexpected exception with message: 'custom std exception'

View File

@ -1380,6 +1380,6 @@ due to unexpected exception with message:
Why would you throw a std::string? Why would you throw a std::string?
=============================================================================== ===============================================================================
test cases: 300 | 226 passed | 70 failed | 4 failed as expected test cases: 301 | 227 passed | 70 failed | 4 failed as expected
assertions: 1564 | 1412 passed | 131 failed | 21 failed as expected assertions: 1570 | 1418 passed | 131 failed | 21 failed as expected

View File

@ -2381,6 +2381,72 @@ Matchers.tests.cpp:<line number>: FAILED:
with expansion: with expansion:
"this string contains 'abc' as a substring" contains: "STRING" "this string contains 'abc' as a substring" contains: "STRING"
-------------------------------------------------------------------------------
Copy and then generate a range
-------------------------------------------------------------------------------
Generators.tests.cpp:<line number>
...............................................................................
Generators.tests.cpp:<line number>: PASSED:
REQUIRE( elem % 2 == 1 )
with expansion:
1 == 1
-------------------------------------------------------------------------------
Copy and then generate a range
-------------------------------------------------------------------------------
Generators.tests.cpp:<line number>
...............................................................................
Generators.tests.cpp:<line number>: PASSED:
REQUIRE( elem % 2 == 1 )
with expansion:
1 == 1
-------------------------------------------------------------------------------
Copy and then generate a range
-------------------------------------------------------------------------------
Generators.tests.cpp:<line number>
...............................................................................
Generators.tests.cpp:<line number>: PASSED:
REQUIRE( elem % 2 == 1 )
with expansion:
1 == 1
-------------------------------------------------------------------------------
Copy and then generate a range
-------------------------------------------------------------------------------
Generators.tests.cpp:<line number>
...............................................................................
Generators.tests.cpp:<line number>: PASSED:
REQUIRE( elem % 2 == 1 )
with expansion:
1 == 1
-------------------------------------------------------------------------------
Copy and then generate a range
-------------------------------------------------------------------------------
Generators.tests.cpp:<line number>
...............................................................................
Generators.tests.cpp:<line number>: PASSED:
REQUIRE( elem % 2 == 1 )
with expansion:
1 == 1
-------------------------------------------------------------------------------
Copy and then generate a range
-------------------------------------------------------------------------------
Generators.tests.cpp:<line number>
...............................................................................
Generators.tests.cpp:<line number>: PASSED:
REQUIRE( elem % 2 == 1 )
with expansion:
1 == 1
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Custom exceptions can be translated when testing for nothrow Custom exceptions can be translated when testing for nothrow
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -12499,6 +12565,6 @@ Misc.tests.cpp:<line number>
Misc.tests.cpp:<line number>: PASSED: Misc.tests.cpp:<line number>: PASSED:
=============================================================================== ===============================================================================
test cases: 300 | 210 passed | 86 failed | 4 failed as expected test cases: 301 | 211 passed | 86 failed | 4 failed as expected
assertions: 1581 | 1412 passed | 148 failed | 21 failed as expected assertions: 1587 | 1418 passed | 148 failed | 21 failed as expected

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<testsuitesloose text artifact <testsuitesloose text artifact
> >
<testsuite name="<exe-name>" errors="17" failures="132" tests="1582" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}"> <testsuite name="<exe-name>" errors="17" failures="132" tests="1588" hostname="tbd" time="{duration}" timestamp="{iso8601-timestamp}">
<properties> <properties>
<property name="filters" value="~[!nonportable]~[!benchmark]~[approvals]"/> <property name="filters" value="~[!nonportable]~[!benchmark]~[approvals]"/>
<property name="random-seed" value="1"/> <property name="random-seed" value="1"/>
@ -254,6 +254,7 @@ Matchers.tests.cpp:<line number>
Matchers.tests.cpp:<line number> Matchers.tests.cpp:<line number>
</failure> </failure>
</testcase> </testcase>
<testcase classname="<exe-name>.global" name="Copy and then generate a range" time="{duration}"/>
<testcase classname="<exe-name>.global" name="Custom exceptions can be translated when testing for nothrow" time="{duration}"> <testcase classname="<exe-name>.global" name="Custom exceptions can be translated when testing for nothrow" time="{duration}">
<error message="throwCustom()" type="REQUIRE_NOTHROW"> <error message="throwCustom()" type="REQUIRE_NOTHROW">
custom exception - not std custom exception - not std

View File

@ -2816,6 +2816,57 @@ Nor would this
</Expression> </Expression>
<OverallResult success="false"/> <OverallResult success="false"/>
</TestCase> </TestCase>
<TestCase name="Copy and then generate a range" tags="[generators]" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Original>
elem % 2 == 1
</Original>
<Expanded>
1 == 1
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Original>
elem % 2 == 1
</Original>
<Expanded>
1 == 1
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Original>
elem % 2 == 1
</Original>
<Expanded>
1 == 1
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Original>
elem % 2 == 1
</Original>
<Expanded>
1 == 1
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Original>
elem % 2 == 1
</Original>
<Expanded>
1 == 1
</Expanded>
</Expression>
<Expression success="true" type="REQUIRE" filename="projects/<exe-name>/UsageTests/Generators.tests.cpp" >
<Original>
elem % 2 == 1
</Original>
<Expanded>
1 == 1
</Expanded>
</Expression>
<OverallResult success="true"/>
</TestCase>
<TestCase name="Custom exceptions can be translated when testing for nothrow" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" > <TestCase name="Custom exceptions can be translated when testing for nothrow" tags="[!throws][.][failing]" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Expression success="false" type="REQUIRE_NOTHROW" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" > <Expression success="false" type="REQUIRE_NOTHROW" filename="projects/<exe-name>/UsageTests/Exception.tests.cpp" >
<Original> <Original>
@ -14872,7 +14923,7 @@ loose text artifact
</Section> </Section>
<OverallResult success="true"/> <OverallResult success="true"/>
</TestCase> </TestCase>
<OverallResults successes="1412" failures="149" expectedFailures="21"/> <OverallResults successes="1418" failures="149" expectedFailures="21"/>
</Group> </Group>
<OverallResults successes="1412" failures="148" expectedFailures="21"/> <OverallResults successes="1418" failures="148" expectedFailures="21"/>
</Catch> </Catch>

View File

@ -212,3 +212,28 @@ TEST_CASE("Nested generators and captured variables", "[generators]") {
auto values = GENERATE_COPY(range(from, to)); auto values = GENERATE_COPY(range(from, to));
REQUIRE(values > -6); REQUIRE(values > -6);
} }
namespace {
std::vector<int> make_data() {
return { 1, 3, 5, 7, 9, 11 };
}
}
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wexit-time-destructors"
#endif
TEST_CASE("Copy and then generate a range", "[generators]") {
static auto data = make_data();
// It is important to notice that a generator is only initialized
// **once** per run. What this means is that modifying data will not
// modify the underlying generator.
auto elem = GENERATE_REF(from_range(data.begin(), data.end()));
REQUIRE(elem % 2 == 1);
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif