| | #include "catch.hpp" |
| |
|
| | #include <cstring> |
| |
|
| |
|
| | |
| | TEST_CASE("Generators -- simple", "[generators]") { |
| | auto i = GENERATE(1, 2, 3); |
| | SECTION("one") { |
| | auto j = GENERATE(values({ -3, -2, -1 })); |
| | REQUIRE(j < i); |
| | } |
| |
|
| | SECTION("two") { |
| | |
| | auto str = GENERATE(as<std::string>{}, "a", "bb", "ccc"); |
| | REQUIRE(4u * i > str.size()); |
| | } |
| | } |
| |
|
| | |
| | TEST_CASE("3x3x3 ints", "[generators]") { |
| | auto x = GENERATE(1, 2, 3); |
| | auto y = GENERATE(4, 5, 6); |
| | auto z = GENERATE(7, 8, 9); |
| | |
| | CHECK(x < y); |
| | CHECK(y < z); |
| | REQUIRE(x < z); |
| | } |
| |
|
| | |
| | TEST_CASE("tables", "[generators]") { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | using tuple_type = std::tuple<char const*, int>; |
| | auto data = GENERATE(table<char const*, int>({ |
| | tuple_type{"first", 5}, |
| | tuple_type{"second", 6}, |
| | tuple_type{"third", 5}, |
| | tuple_type{"etc...", 6} |
| | })); |
| |
|
| | REQUIRE(strlen(std::get<0>(data)) == static_cast<size_t>(std::get<1>(data))); |
| | } |
| |
|
| |
|
| | #ifdef __cpp_structured_bindings |
| |
|
| | |
| | TEST_CASE( "strlen2", "[approvals][generators]" ) { |
| | using tuple_type = std::tuple<std::string, int>; |
| | auto [test_input, expected] = |
| | GENERATE( table<std::string, size_t>( { tuple_type{ "one", 3 }, |
| | tuple_type{ "two", 3 }, |
| | tuple_type{ "three", 5 }, |
| | tuple_type{ "four", 4 } } ) ); |
| |
|
| | REQUIRE( test_input.size() == expected ); |
| | } |
| | #endif |
| |
|
| |
|
| | |
| | struct Data { std::string str; size_t len; }; |
| |
|
| | TEST_CASE( "strlen3", "[generators]" ) { |
| | auto data = GENERATE( values<Data>({ |
| | {"one", 3}, |
| | {"two", 3}, |
| | {"three", 5}, |
| | {"four", 4} |
| | })); |
| |
|
| | REQUIRE( data.str.size() == data.len ); |
| | } |
| |
|
| |
|
| |
|
| | #ifdef __cpp_structured_bindings |
| |
|
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | static auto eatCucumbers( int start, int eat ) -> int { return start-eat; } |
| |
|
| | SCENARIO("Eating cucumbers", "[generators][approvals]") { |
| | using tuple_type = std::tuple<int, int, int>; |
| | auto [start, eat, left] = GENERATE( table<int, int, int>( |
| | { tuple_type{ 12, 5, 7 }, tuple_type{ 20, 5, 15 } } ) ); |
| |
|
| | GIVEN( "there are " << start << " cucumbers" ) |
| | WHEN( "I eat " << eat << " cucumbers" ) |
| | THEN( "I should have " << left << " cucumbers" ) { |
| | REQUIRE( eatCucumbers( start, eat ) == left ); |
| | } |
| | } |
| | #endif |
| |
|
| | |
| | TEST_CASE("Generators -- adapters", "[generators][generic]") { |
| | |
| | |
| | SECTION("Filtering by predicate") { |
| | SECTION("Basic usage") { |
| | |
| | auto i = GENERATE(filter([] (int val) { return val % 2 == 0; }, values({ 1, 2, 3, 4, 5, 6 }))); |
| | REQUIRE(i % 2 == 0); |
| | } |
| | SECTION("Throws if there are no matching values") { |
| | using namespace Catch::Generators; |
| | REQUIRE_THROWS_AS(filter([] (int) {return false; }, value(1)), Catch::GeneratorException); |
| | } |
| | } |
| | SECTION("Shortening a range") { |
| | |
| | auto i = GENERATE(take(3, values({ 1, 2, 3, 4, 5, 6 }))); |
| | REQUIRE(i < 4); |
| | } |
| | SECTION("Transforming elements") { |
| | SECTION("Same type") { |
| | |
| | auto i = GENERATE(map([] (int val) { return val * 2; }, values({ 1, 2, 3 }))); |
| | REQUIRE(i % 2 == 0); |
| | } |
| | SECTION("Different type") { |
| | |
| | auto i = GENERATE(map<std::string>([] (int val) { return std::to_string(val); }, values({ 1, 2, 3 }))); |
| | REQUIRE(i.size() == 1); |
| | } |
| | SECTION("Different deduced type") { |
| | |
| | auto i = GENERATE(map([] (int val) { return std::to_string(val); }, values({ 1, 2, 3 }))); |
| | REQUIRE(i.size() == 1); |
| | } |
| | } |
| | SECTION("Repeating a generator") { |
| | |
| | auto j = GENERATE(repeat(2, values({ 1, 2, 3 }))); |
| | REQUIRE(j > 0); |
| | } |
| | SECTION("Chunking a generator into sized pieces") { |
| | SECTION("Number of elements in source is divisible by chunk size") { |
| | auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3, 3 }))); |
| | REQUIRE(chunk2.size() == 2); |
| | REQUIRE(chunk2.front() == chunk2.back()); |
| | } |
| | SECTION("Number of elements in source is not divisible by chunk size") { |
| | auto chunk2 = GENERATE(chunk(2, values({ 1, 1, 2, 2, 3 }))); |
| | REQUIRE(chunk2.size() == 2); |
| | REQUIRE(chunk2.front() == chunk2.back()); |
| | REQUIRE(chunk2.front() < 3); |
| | } |
| | SECTION("Chunk size of zero") { |
| | auto chunk2 = GENERATE(take(3, chunk(0, value(1)))); |
| | REQUIRE(chunk2.size() == 0); |
| | } |
| | SECTION("Throws on too small generators") { |
| | using namespace Catch::Generators; |
| | REQUIRE_THROWS_AS(chunk(2, value(1)), Catch::GeneratorException); |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | TEST_CASE("Random generator", "[generators][approvals]") { |
| | SECTION("Infer int from integral arguments") { |
| | auto val = GENERATE(take(4, random(0, 1))); |
| | STATIC_REQUIRE(std::is_same<decltype(val), int>::value); |
| | REQUIRE(0 <= val); |
| | REQUIRE(val <= 1); |
| | } |
| | SECTION("Infer double from double arguments") { |
| | auto val = GENERATE(take(4, random(0., 1.))); |
| | STATIC_REQUIRE(std::is_same<decltype(val), double>::value); |
| | REQUIRE(0. <= val); |
| | REQUIRE(val < 1); |
| | } |
| | } |
| |
|
| |
|
| | TEST_CASE("Nested generators and captured variables", "[generators]") { |
| | |
| | using record = std::tuple<int, int>; |
| | |
| | auto extent = GENERATE(table<int, int>({ |
| | record{3, 7}, |
| | record{-5, -3}, |
| | record{90, 100} |
| | })); |
| |
|
| | auto from = std::get<0>(extent); |
| | auto to = std::get<1>(extent); |
| |
|
| | auto values = GENERATE_COPY(range(from, to)); |
| | REQUIRE(values > -6); |
| | } |
| |
|
| | namespace { |
| | size_t call_count = 0; |
| | size_t test_count = 0; |
| | std::vector<int> make_data() { |
| | return { 1, 3, 5, 7, 9, 11 }; |
| | } |
| | std::vector<int> make_data_counted() { |
| | ++call_count; |
| | return make_data(); |
| | } |
| | } |
| |
|
| | #if defined(__clang__) |
| | #pragma clang diagnostic push |
| | #pragma clang diagnostic ignored "-Wexit-time-destructors" |
| | #endif |
| |
|
| | TEST_CASE("Copy and then generate a range", "[generators]") { |
| | SECTION("from var and iterators") { |
| | static auto data = make_data(); |
| |
|
| | |
| | |
| | |
| | auto elem = GENERATE_REF(from_range(data.begin(), data.end())); |
| | REQUIRE(elem % 2 == 1); |
| | } |
| | SECTION("From a temporary container") { |
| | auto elem = GENERATE(from_range(make_data_counted())); |
| | ++test_count; |
| | REQUIRE(elem % 2 == 1); |
| | } |
| | SECTION("Final validation") { |
| | REQUIRE(call_count == 1); |
| | REQUIRE(make_data().size() == test_count); |
| | } |
| | } |
| |
|
| | TEST_CASE("#1913 - GENERATE inside a for loop should not keep recreating the generator", "[regression][generators]") { |
| | static int counter = 0; |
| | for (int i = 0; i < 3; ++i) { |
| | int _ = GENERATE(1, 2); |
| | (void)_; |
| | ++counter; |
| | } |
| | |
| | REQUIRE(counter < 7); |
| | } |
| |
|
| | TEST_CASE("#1913 - GENERATEs can share a line", "[regression][generators]") { |
| | int i = GENERATE(1, 2); int j = GENERATE(3, 4); |
| | REQUIRE(i != j); |
| | } |
| |
|
| |
|
| | #if defined(__clang__) |
| | #pragma clang diagnostic pop |
| | #endif |
| |
|