mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-26 15:26:11 +01:00
e1e6872c4c
This is both a really big and a really small commit. It is small in that it only contains renaming, moving and modification of include directives caused by this. It is really big in the obvious way of touching something like 200 files. The new rules for naming files is simple: headers use the `.hpp` extension. The rules for physical file layout is still kinda in progress, but the basics are also simple: * Significant parts of functionality get their own subfolder * Benchmarking is in `catch2/benchmark` * Matchers are in `catch2/matchers` * Generators are in `catch2/generators` * Reporters are in `catch2/reporters` * Baseline testing facilities are in `catch2/` * Various top level folders also contain `internal` subfolder, with files that users probably do not want to include directly, at least not until they have to write something like their own reporter. * The exact files in these subfolders is likely to change later on Note that while some includes were cleaned up in this commit, it is only the low hanging fruit and further cleanup using automatic tooling will happen later. Also note that various include guards, copyright notices and file headers will also be standardized later, rather than in this commit.
359 lines
12 KiB
C++
359 lines
12 KiB
C++
#include <catch2/catch_approx.hpp>
|
|
#include <catch2/catch_test_macros.hpp>
|
|
#include <catch2/generators/catch_generator_exception.hpp>
|
|
#include <catch2/generators/catch_generators_adapters.hpp>
|
|
#include <catch2/generators/catch_generators_random.hpp>
|
|
#include <catch2/generators/catch_generators_range.hpp>
|
|
|
|
// Tests of generator implementation details
|
|
TEST_CASE("Generators internals", "[generators][internals]") {
|
|
using namespace Catch::Generators;
|
|
|
|
SECTION("Single value") {
|
|
auto gen = value(123);
|
|
REQUIRE(gen.get() == 123);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Preset values") {
|
|
auto gen = values({ 1, 3, 5 });
|
|
REQUIRE(gen.get() == 1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 3);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 5);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Generator combinator") {
|
|
auto gen = makeGenerators(1, 5, values({ 2, 4 }), 0);
|
|
REQUIRE(gen.get() == 1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 5);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 2);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 4);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 0);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Explicitly typed generator sequence") {
|
|
auto gen = makeGenerators(as<std::string>{}, "aa", "bb", "cc");
|
|
// This just checks that the type is std::string:
|
|
REQUIRE(gen.get().size() == 2);
|
|
// Iterate over the generator
|
|
REQUIRE(gen.get() == "aa");
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == "bb");
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == "cc");
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Filter generator") {
|
|
// Normal usage
|
|
auto gen = filter([] (int i) { return i != 2; }, values({ 2, 1, 2, 3, 2, 2 }));
|
|
REQUIRE(gen.get() == 1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 3);
|
|
REQUIRE_FALSE(gen.next());
|
|
|
|
// Completely filtered-out generator should throw on construction
|
|
REQUIRE_THROWS_AS(filter([] (int) { return false; }, value(1)), Catch::GeneratorException);
|
|
}
|
|
SECTION("Take generator") {
|
|
SECTION("Take less") {
|
|
auto gen = take(2, values({ 1, 2, 3 }));
|
|
REQUIRE(gen.get() == 1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 2);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Take more") {
|
|
auto gen = take(2, value(1));
|
|
REQUIRE(gen.get() == 1);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
}
|
|
SECTION("Map with explicit return type") {
|
|
auto gen = map<double>([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
|
|
REQUIRE(gen.get() == 2.0);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 4.0);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 6.0);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Map with deduced return type") {
|
|
auto gen = map([] (int i) {return 2.0 * i; }, values({ 1, 2, 3 }));
|
|
REQUIRE(gen.get() == 2.0);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 4.0);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 6.0);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Repeat") {
|
|
SECTION("Singular repeat") {
|
|
auto gen = repeat(1, value(3));
|
|
REQUIRE(gen.get() == 3);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Actual repeat") {
|
|
auto gen = repeat(2, values({ 1, 2, 3 }));
|
|
REQUIRE(gen.get() == 1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 2);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 3);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 2);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 3);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
}
|
|
SECTION("Range") {
|
|
SECTION("Positive auto step") {
|
|
SECTION("Integer") {
|
|
auto gen = range(-2, 2);
|
|
REQUIRE(gen.get() == -2);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 0);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 1);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
}
|
|
SECTION("Negative auto step") {
|
|
SECTION("Integer") {
|
|
auto gen = range(2, -2);
|
|
REQUIRE(gen.get() == 2);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 0);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -1);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
}
|
|
SECTION("Positive manual step") {
|
|
SECTION("Integer") {
|
|
SECTION("Exact") {
|
|
auto gen = range(-7, 5, 3);
|
|
REQUIRE(gen.get() == -7);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -4);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 2);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Slightly over end") {
|
|
auto gen = range(-7, 4, 3);
|
|
REQUIRE(gen.get() == -7);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -4);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 2);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Slightly under end") {
|
|
auto gen = range(-7, 6, 3);
|
|
REQUIRE(gen.get() == -7);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -4);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 2);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 5);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
}
|
|
|
|
SECTION("Floating Point") {
|
|
using Catch::Approx;
|
|
SECTION("Exact") {
|
|
const auto rangeStart = -1.;
|
|
const auto rangeEnd = 1.;
|
|
const auto step = .1;
|
|
|
|
auto gen = range(rangeStart, rangeEnd, step);
|
|
auto expected = rangeStart;
|
|
while( (rangeEnd - expected) > step ) {
|
|
INFO( "Current expected value is " << expected );
|
|
REQUIRE(gen.get() == Approx(expected));
|
|
REQUIRE(gen.next());
|
|
|
|
expected += step;
|
|
}
|
|
REQUIRE(gen.get() == Approx( rangeEnd ) );
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Slightly over end") {
|
|
const auto rangeStart = -1.;
|
|
const auto rangeEnd = 1.;
|
|
const auto step = .3;
|
|
|
|
auto gen = range(rangeStart, rangeEnd, step);
|
|
auto expected = rangeStart;
|
|
while( (rangeEnd - expected) > step ) {
|
|
INFO( "Current expected value is " << expected );
|
|
REQUIRE(gen.get() == Approx(expected));
|
|
REQUIRE(gen.next());
|
|
|
|
expected += step;
|
|
}
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Slightly under end") {
|
|
const auto rangeStart = -1.;
|
|
const auto rangeEnd = .9;
|
|
const auto step = .3;
|
|
|
|
auto gen = range(rangeStart, rangeEnd, step);
|
|
auto expected = rangeStart;
|
|
while( (rangeEnd - expected) > step ) {
|
|
INFO( "Current expected value is " << expected );
|
|
REQUIRE(gen.get() == Approx(expected));
|
|
REQUIRE(gen.next());
|
|
|
|
expected += step;
|
|
}
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
}
|
|
}
|
|
SECTION("Negative manual step") {
|
|
SECTION("Integer") {
|
|
SECTION("Exact") {
|
|
auto gen = range(5, -7, -3);
|
|
REQUIRE(gen.get() == 5);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 2);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -4);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Slightly over end") {
|
|
auto gen = range(5, -6, -3);
|
|
REQUIRE(gen.get() == 5);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 2);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -4);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
SECTION("Slightly under end") {
|
|
auto gen = range(5, -8, -3);
|
|
REQUIRE(gen.get() == 5);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == 2);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -1);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -4);
|
|
REQUIRE(gen.next());
|
|
REQUIRE(gen.get() == -7);
|
|
REQUIRE_FALSE(gen.next());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// todo: uncopyable type used in a generator
|
|
// idea: uncopyable tag type for a stupid generator
|
|
|
|
namespace {
|
|
struct non_copyable {
|
|
non_copyable() = default;
|
|
non_copyable(non_copyable const&) = delete;
|
|
non_copyable& operator=(non_copyable const&) = delete;
|
|
int value = -1;
|
|
};
|
|
|
|
// This class shows how to implement a simple generator for Catch tests
|
|
class TestGen : public Catch::Generators::IGenerator<int> {
|
|
int current_number;
|
|
public:
|
|
|
|
TestGen(non_copyable const& nc):
|
|
current_number(nc.value) {}
|
|
|
|
int const& get() const override;
|
|
bool next() override {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// Avoids -Wweak-vtables
|
|
int const& TestGen::get() const {
|
|
return current_number;
|
|
}
|
|
|
|
}
|
|
|
|
TEST_CASE("GENERATE capture macros", "[generators][internals][approvals]") {
|
|
auto value = GENERATE(take(10, random(0, 10)));
|
|
|
|
non_copyable nc; nc.value = value;
|
|
// neither `GENERATE_COPY` nor plain `GENERATE` would compile here
|
|
auto value2 = GENERATE_REF(Catch::Generators::GeneratorWrapper<int>(std::unique_ptr<Catch::Generators::IGenerator<int>>(new TestGen(nc))));
|
|
REQUIRE(value == value2);
|
|
}
|
|
|
|
TEST_CASE("#1809 - GENERATE_COPY and SingleValueGenerator does not compile", "[generators][compilation][approvals]") {
|
|
// Verify Issue #1809 fix, only needs to compile.
|
|
auto a = GENERATE_COPY(1, 2);
|
|
(void)a;
|
|
auto b = GENERATE_COPY(as<long>{}, 1, 2);
|
|
(void)b;
|
|
int i = 1;
|
|
int j = 2;
|
|
auto c = GENERATE_COPY(i, j);
|
|
(void)c;
|
|
auto d = GENERATE_COPY(as<long>{}, i, j);
|
|
(void)d;
|
|
SUCCEED();
|
|
}
|
|
|
|
TEST_CASE("Multiple random generators in one test case output different values", "[generators][internals][approvals]") {
|
|
SECTION("Integer") {
|
|
auto random1 = Catch::Generators::random(0, 1000);
|
|
auto random2 = Catch::Generators::random(0, 1000);
|
|
size_t same = 0;
|
|
for (size_t i = 0; i < 1000; ++i) {
|
|
same += random1.get() == random2.get();
|
|
random1.next(); random2.next();
|
|
}
|
|
// 0.5% seems like a sane bound for random identical elements within 1000 runs
|
|
REQUIRE(same < 5);
|
|
}
|
|
SECTION("Float") {
|
|
auto random1 = Catch::Generators::random(0., 1000.);
|
|
auto random2 = Catch::Generators::random(0., 1000.);
|
|
size_t same = 0;
|
|
for (size_t i = 0; i < 1000; ++i) {
|
|
same += random1.get() == random2.get();
|
|
random1.next(); random2.next();
|
|
}
|
|
// 0.5% seems like a sane bound for random identical elements within 1000 runs
|
|
REQUIRE(same < 5);
|
|
}
|
|
}
|