From 319cb9e1daec5076ff1a3acd10b959c2bce05c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Ho=C5=99e=C5=88ovsk=C3=BD?= Date: Sun, 6 Oct 2019 13:49:50 +0200 Subject: [PATCH] Add a generator that takes an iterator pair --- docs/generators.md | 8 ++- .../internal/catch_generators_specific.hpp | 33 +++++++++ .../Baselines/compact.sw.approved.txt | 6 ++ .../Baselines/console.std.approved.txt | 4 +- .../Baselines/console.sw.approved.txt | 70 ++++++++++++++++++- .../SelfTest/Baselines/junit.sw.approved.txt | 3 +- .../SelfTest/Baselines/xml.sw.approved.txt | 55 ++++++++++++++- .../SelfTest/UsageTests/Generators.tests.cpp | 25 +++++++ 8 files changed, 196 insertions(+), 8 deletions(-) diff --git a/docs/generators.md b/docs/generators.md index 490cfcac..934a6731 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -46,13 +46,16 @@ a test case, * `MapGenerator` -- returns the result of applying `Func` on elements from a different generator * `ChunkGenerator` -- returns chunks (inside `std::vector`) of n elements from a generator -* 3 specific purpose generators +* 4 specific purpose generators * `RandomIntegerGenerator` -- generates random Integrals from range * `RandomFloatGenerator` -- generates random Floats from range * `RangeGenerator` -- generates all values inside a specific range + * `IteratorGenerator` -- copies and returns values from an iterator range > `ChunkGenerator`, `RandomIntegerGenerator`, `RandomFloatGenerator` and `RangeGenerator` were introduced in Catch 2.7.0. +> `IteratorGenerator` was introduced in Catch X.Y.Z. + The generators also have associated helper functions that infer their 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` * `range(start, end)` for `RangeGenerator` with a step size of `1` * `range(start, end, step)` for `RangeGenerator` with a custom step size +* `from_range(InputIterator from, InputIterator to)` for `IteratorGenerator` > `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 that returns 100 odd random number: diff --git a/include/internal/catch_generators_specific.hpp b/include/internal/catch_generators_specific.hpp index 7aae06bd..7985ac70 100644 --- a/include/internal/catch_generators_specific.hpp +++ b/include/internal/catch_generators_specific.hpp @@ -128,6 +128,39 @@ GeneratorWrapper range(T const& start, T const& end) { } +template +class IteratorGenerator final : public IGenerator { + static_assert(!std::is_same::value, + "IteratorGenerator currently does not support bools" + "because of std::vector specialization"); + + std::vector m_elems; + size_t m_current = 0; +public: + template + 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 ::value_type> +GeneratorWrapper from_range(InputIterator from, InputSentinel to) { + return GeneratorWrapper(pf::make_unique>(from, to)); +} + } // namespace Generators } // namespace Catch diff --git a/projects/SelfTest/Baselines/compact.sw.approved.txt b/projects/SelfTest/Baselines/compact.sw.approved.txt index e7919287..89276649 100644 --- a/projects/SelfTest/Baselines/compact.sw.approved.txt +++ b/projects/SelfTest/Baselines/compact.sw.approved.txt @@ -310,6 +310,12 @@ Condition.tests.cpp:: passed: 6 == uc for: 6 == 6 Condition.tests.cpp:: passed: (std::numeric_limits::max)() > ul for: 4294967295 (0x) > 4 Matchers.tests.cpp:: failed: testStringForMatching(), Contains("not there", Catch::CaseSensitive::No) for: "this string contains 'abc' as a substring" contains: "not there" (case insensitive) Matchers.tests.cpp:: failed: testStringForMatching(), Contains("STRING") for: "this string contains 'abc' as a substring" contains: "STRING" +Generators.tests.cpp:: passed: elem % 2 == 1 for: 1 == 1 +Generators.tests.cpp:: passed: elem % 2 == 1 for: 1 == 1 +Generators.tests.cpp:: passed: elem % 2 == 1 for: 1 == 1 +Generators.tests.cpp:: passed: elem % 2 == 1 for: 1 == 1 +Generators.tests.cpp:: passed: elem % 2 == 1 for: 1 == 1 +Generators.tests.cpp:: passed: elem % 2 == 1 for: 1 == 1 Exception.tests.cpp:: failed: unexpected exception with message: 'custom exception - not std'; expression was: throwCustom() Exception.tests.cpp:: failed: unexpected exception with message: 'custom exception - not std'; expression was: throwCustom(), std::exception Exception.tests.cpp:: failed: unexpected exception with message: 'custom std exception' diff --git a/projects/SelfTest/Baselines/console.std.approved.txt b/projects/SelfTest/Baselines/console.std.approved.txt index 7eaae82c..49363a68 100644 --- a/projects/SelfTest/Baselines/console.std.approved.txt +++ b/projects/SelfTest/Baselines/console.std.approved.txt @@ -1380,6 +1380,6 @@ due to unexpected exception with message: Why would you throw a std::string? =============================================================================== -test cases: 300 | 226 passed | 70 failed | 4 failed as expected -assertions: 1564 | 1412 passed | 131 failed | 21 failed as expected +test cases: 301 | 227 passed | 70 failed | 4 failed as expected +assertions: 1570 | 1418 passed | 131 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/console.sw.approved.txt b/projects/SelfTest/Baselines/console.sw.approved.txt index 4415fe06..9bb87218 100644 --- a/projects/SelfTest/Baselines/console.sw.approved.txt +++ b/projects/SelfTest/Baselines/console.sw.approved.txt @@ -2381,6 +2381,72 @@ Matchers.tests.cpp:: FAILED: with expansion: "this string contains 'abc' as a substring" contains: "STRING" +------------------------------------------------------------------------------- +Copy and then generate a range +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( elem % 2 == 1 ) +with expansion: + 1 == 1 + +------------------------------------------------------------------------------- +Copy and then generate a range +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( elem % 2 == 1 ) +with expansion: + 1 == 1 + +------------------------------------------------------------------------------- +Copy and then generate a range +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( elem % 2 == 1 ) +with expansion: + 1 == 1 + +------------------------------------------------------------------------------- +Copy and then generate a range +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( elem % 2 == 1 ) +with expansion: + 1 == 1 + +------------------------------------------------------------------------------- +Copy and then generate a range +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( elem % 2 == 1 ) +with expansion: + 1 == 1 + +------------------------------------------------------------------------------- +Copy and then generate a range +------------------------------------------------------------------------------- +Generators.tests.cpp: +............................................................................... + +Generators.tests.cpp:: PASSED: + REQUIRE( elem % 2 == 1 ) +with expansion: + 1 == 1 + ------------------------------------------------------------------------------- Custom exceptions can be translated when testing for nothrow ------------------------------------------------------------------------------- @@ -12499,6 +12565,6 @@ Misc.tests.cpp: Misc.tests.cpp:: PASSED: =============================================================================== -test cases: 300 | 210 passed | 86 failed | 4 failed as expected -assertions: 1581 | 1412 passed | 148 failed | 21 failed as expected +test cases: 301 | 211 passed | 86 failed | 4 failed as expected +assertions: 1587 | 1418 passed | 148 failed | 21 failed as expected diff --git a/projects/SelfTest/Baselines/junit.sw.approved.txt b/projects/SelfTest/Baselines/junit.sw.approved.txt index b16b6638..d1ec9db4 100644 --- a/projects/SelfTest/Baselines/junit.sw.approved.txt +++ b/projects/SelfTest/Baselines/junit.sw.approved.txt @@ -1,7 +1,7 @@ - + @@ -254,6 +254,7 @@ Matchers.tests.cpp: Matchers.tests.cpp: + custom exception - not std diff --git a/projects/SelfTest/Baselines/xml.sw.approved.txt b/projects/SelfTest/Baselines/xml.sw.approved.txt index 65e5f4bd..9df28085 100644 --- a/projects/SelfTest/Baselines/xml.sw.approved.txt +++ b/projects/SelfTest/Baselines/xml.sw.approved.txt @@ -2816,6 +2816,57 @@ Nor would this + + + + elem % 2 == 1 + + + 1 == 1 + + + + + elem % 2 == 1 + + + 1 == 1 + + + + + elem % 2 == 1 + + + 1 == 1 + + + + + elem % 2 == 1 + + + 1 == 1 + + + + + elem % 2 == 1 + + + 1 == 1 + + + + + elem % 2 == 1 + + + 1 == 1 + + + + @@ -14872,7 +14923,7 @@ loose text artifact - + - + diff --git a/projects/SelfTest/UsageTests/Generators.tests.cpp b/projects/SelfTest/UsageTests/Generators.tests.cpp index e9b2f807..0d58186b 100644 --- a/projects/SelfTest/UsageTests/Generators.tests.cpp +++ b/projects/SelfTest/UsageTests/Generators.tests.cpp @@ -212,3 +212,28 @@ TEST_CASE("Nested generators and captured variables", "[generators]") { auto values = GENERATE_COPY(range(from, to)); REQUIRE(values > -6); } + +namespace { + std::vector 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