Skip to content

Commit

Permalink
Prefer T(...) over T{...} when they behave differently
Browse files Browse the repository at this point in the history
...in gen::construct and gen::makeUnique. Also, add support
for aggregate initialization in gen::makeShared and tests for
all of them.
  • Loading branch information
stolyaroleh committed Dec 14, 2018
1 parent 3eb9b4f commit 468a418
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 11 deletions.
54 changes: 43 additions & 11 deletions include/rapidcheck/gen/Build.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,50 @@ class BuildMapper<T, rc::detail::IndexSequence<Indexes...>, Lenses...> {
std::tuple<Lenses...> m_lenses;
};

template<typename T, typename... Args>
typename std::enable_if<std::is_constructible<T, Args...>::value, T>::type
construct(Args &&... args) {
return T(std::move(args)...);
}

template<typename T, typename... Args>
typename std::enable_if<!std::is_constructible<T, Args...>::value, T>::type
construct(Args &&... args) {
return T{std::move(args)...};
}

template<typename T, typename... Args>
typename std::enable_if<std::is_constructible<T, Args...>::value, std::unique_ptr<T>>::type
makeUnique(Args &&... args) {
return std::unique_ptr<T>(new T(std::move(args)...));
}

template<typename T, typename... Args>
typename std::enable_if<!std::is_constructible<T, Args...>::value, std::unique_ptr<T>>::type
makeUnique(Args &&... args) {
return std::unique_ptr<T>(new T{std::move(args)...});
}

template<typename T, typename... Args>
typename std::enable_if<std::is_constructible<T, Args...>::value, std::shared_ptr<T>>::type
makeShared(Args &&... args) {
return std::shared_ptr<T>(new T(std::move(args)...));
}

template<typename T, typename... Args>
typename std::enable_if<!std::is_constructible<T, Args...>::value, std::shared_ptr<T>>::type
makeShared(Args &&... args) {
return std::shared_ptr<T>(new T{std::move(args)...});
}
} // namespace detail

template <typename T, typename... Args>
Gen<T> construct(Gen<Args>... gens) {
return gen::map(gen::tuple(std::move(gens)...),
[](std::tuple<Args...> &&argsTuple) {
return rc::detail::applyTuple(
std::move(argsTuple),
[](Args &&... args) { return T{std::move(args)...}; });
std::move(argsTuple),
detail::construct<T, Args...>);
});
}

Expand All @@ -141,22 +176,19 @@ Gen<std::unique_ptr<T>> makeUnique(Gen<Args>... gens) {
return gen::map(gen::tuple(std::move(gens)...),
[](std::tuple<Args...> &&argsTuple) {
return rc::detail::applyTuple(
std::move(argsTuple),
[](Args &&... args) {
return std::unique_ptr<T>(new T{std::move(args)...});
});
std::move(argsTuple),
detail::makeUnique<T, Args...>);
});
}

template <typename T, typename... Args>
Gen<std::shared_ptr<T>> makeShared(Gen<Args>... gens) {
return gen::map(gen::tuple(std::move(gens)...),
[](std::tuple<Args...> &&argsTuple) {
return rc::detail::applyTuple(std::move(argsTuple),
[](Args &&... args) {
return std::make_shared<T>(
std::move(args)...);
});
return rc::detail::applyTuple(
std::move(argsTuple),
detail::makeShared<T, Args...>
);
});
}

Expand Down
31 changes: 31 additions & 0 deletions test/gen/BuildTests.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <catch2/catch.hpp>
#include <rapidcheck/catch.h>

#include "util/Aggregate.h"
#include "util/GenUtils.h"
#include "util/Predictable.h"
#include "util/Logger.h"
Expand Down Expand Up @@ -90,6 +91,16 @@ TEST_CASE("gen::construct") {
RC_ASSERT(isArbitraryPredictable(std::get<0>(value)));
RC_ASSERT(isArbitraryPredictable(std::get<1>(value)));
}

SECTION("works with aggregate initializers") {
gen::construct<Aggregate>(gen::arbitrary<int>(), gen::arbitrary<int>());
}

SECTION("prefers T(x, y) over T{x, y} when they behave differently") {
auto a = gen::construct<std::vector<int>>(gen::just(3), gen::just(3))(Random(), 0).value();
std::vector<int> b(3, 3);
RC_ASSERT(a == b);
}
}

TEST_CASE("gen::makeUnique") {
Expand Down Expand Up @@ -122,6 +133,16 @@ TEST_CASE("gen::makeUnique") {
RC_ASSERT(isArbitraryPredictable(std::get<0>(value)));
RC_ASSERT(isArbitraryPredictable(std::get<1>(value)));
}

SECTION("works with aggregate initializers") {
gen::makeUnique<Aggregate>(gen::arbitrary<int>(), gen::arbitrary<int>());
}

SECTION("prefers T(x, y) over T{x, y} when they behave differently") {
auto a = gen::makeUnique<std::vector<int>>(gen::just(3), gen::just(3))(Random(), 0).value();
auto b = std::unique_ptr<std::vector<int>>(new std::vector<int>(3, 3));
RC_ASSERT(*a == *b);
}
}

TEST_CASE("gen::makeShared") {
Expand Down Expand Up @@ -154,6 +175,16 @@ TEST_CASE("gen::makeShared") {
RC_ASSERT(isArbitraryPredictable(std::get<0>(value)));
RC_ASSERT(isArbitraryPredictable(std::get<1>(value)));
}

SECTION("works with aggregate initializers") {
gen::makeShared<Aggregate>(gen::arbitrary<int>(), gen::arbitrary<int>());
}

SECTION("prefers T(x, y) over T{x, y} when they behave differently") {
auto a = gen::makeShared<std::vector<int>>(gen::just(3), gen::just(3))(Random(), 0).value();
auto b = std::shared_ptr<std::vector<int>>(new std::vector<int>(3, 3));
RC_ASSERT(*a == *b);
}
}

namespace {
Expand Down
8 changes: 8 additions & 0 deletions test/util/Aggregate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

namespace rc {
struct Aggregate {
int x;
int y;
};
} // namespace rc

0 comments on commit 468a418

Please sign in to comment.