Skip to content

Commit 92cd8d3

Browse files
committed
Prefer T(...) over T{...} when they behave differently
...in gen::construct and gen::makeUnique. Also, add support for aggregate initialization in gen::makeShared and tests for all of them.
1 parent 3eb9b4f commit 92cd8d3

3 files changed

Lines changed: 84 additions & 11 deletions

File tree

include/rapidcheck/gen/Build.hpp

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,51 @@ class BuildMapper<T, rc::detail::IndexSequence<Indexes...>, Lenses...> {
119119
std::tuple<Lenses...> m_lenses;
120120
};
121121

122+
template<typename T, typename... Args>
123+
typename std::enable_if<std::is_constructible<T, Args...>::value, T>::type
124+
construct(Args &&... args) {
125+
return T(std::move(args)...);
126+
}
127+
128+
template<typename T, typename... Args>
129+
typename std::enable_if<!std::is_constructible<T, Args...>::value, T>::type
130+
construct(Args &&... args) {
131+
return T{std::move(args)...};
132+
}
133+
134+
template<typename T, typename... Args>
135+
typename std::enable_if<std::is_constructible<T, Args...>::value, std::unique_ptr<T>>::type
136+
makeUnique(Args &&... args) {
137+
return std::unique_ptr<T>(new T(std::move(args)...));
138+
}
139+
140+
template<typename T, typename... Args>
141+
typename std::enable_if<!std::is_constructible<T, Args...>::value, std::unique_ptr<T>>::type
142+
makeUnique(Args &&... args) {
143+
return std::unique_ptr<T>(new T{std::move(args)...});
144+
}
145+
146+
template<typename T, typename... Args>
147+
typename std::enable_if<std::is_constructible<T, Args...>::value, std::shared_ptr<T>>::type
148+
makeShared(Args &&... args) {
149+
return std::shared_ptr<T>(new T(std::move(args)...));
150+
}
151+
152+
template<typename T, typename... Args>
153+
typename std::enable_if<!std::is_constructible<T, Args...>::value, std::shared_ptr<T>>::type
154+
makeShared(Args &&... args) {
155+
return std::shared_ptr<T>(new T{std::move(args)...});
156+
}
122157
} // namespace detail
123158

124159
template <typename T, typename... Args>
125160
Gen<T> construct(Gen<Args>... gens) {
126161
return gen::map(gen::tuple(std::move(gens)...),
127162
[](std::tuple<Args...> &&argsTuple) {
128163
return rc::detail::applyTuple(
129-
std::move(argsTuple),
130-
[](Args &&... args) { return T{std::move(args)...}; });
164+
std::move(argsTuple),
165+
detail::construct<T, Args...>
166+
);
131167
});
132168
}
133169

@@ -141,22 +177,20 @@ Gen<std::unique_ptr<T>> makeUnique(Gen<Args>... gens) {
141177
return gen::map(gen::tuple(std::move(gens)...),
142178
[](std::tuple<Args...> &&argsTuple) {
143179
return rc::detail::applyTuple(
144-
std::move(argsTuple),
145-
[](Args &&... args) {
146-
return std::unique_ptr<T>(new T{std::move(args)...});
147-
});
180+
std::move(argsTuple),
181+
detail::makeUnique<T, Args...>
182+
);
148183
});
149184
}
150185

151186
template <typename T, typename... Args>
152187
Gen<std::shared_ptr<T>> makeShared(Gen<Args>... gens) {
153188
return gen::map(gen::tuple(std::move(gens)...),
154189
[](std::tuple<Args...> &&argsTuple) {
155-
return rc::detail::applyTuple(std::move(argsTuple),
156-
[](Args &&... args) {
157-
return std::make_shared<T>(
158-
std::move(args)...);
159-
});
190+
return rc::detail::applyTuple(
191+
std::move(argsTuple),
192+
detail::makeShared<T, Args...>
193+
);
160194
});
161195
}
162196

test/gen/BuildTests.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <catch2/catch.hpp>
22
#include <rapidcheck/catch.h>
33

4+
#include "util/Aggregate.h"
45
#include "util/GenUtils.h"
56
#include "util/Predictable.h"
67
#include "util/Logger.h"
@@ -90,6 +91,16 @@ TEST_CASE("gen::construct") {
9091
RC_ASSERT(isArbitraryPredictable(std::get<0>(value)));
9192
RC_ASSERT(isArbitraryPredictable(std::get<1>(value)));
9293
}
94+
95+
SECTION("works with aggregate initializers") {
96+
gen::construct<Aggregate>(gen::arbitrary<int>(), gen::arbitrary<int>());
97+
}
98+
99+
SECTION("prefers T(x, y) over T{x, y} when they behave differently") {
100+
auto a = gen::construct<std::vector<int>>(gen::just(3), gen::just(3))(Random(), 0).value();
101+
std::vector<int> b(3, 3);
102+
RC_ASSERT(a == b);
103+
}
93104
}
94105

95106
TEST_CASE("gen::makeUnique") {
@@ -122,6 +133,16 @@ TEST_CASE("gen::makeUnique") {
122133
RC_ASSERT(isArbitraryPredictable(std::get<0>(value)));
123134
RC_ASSERT(isArbitraryPredictable(std::get<1>(value)));
124135
}
136+
137+
SECTION("works with aggregate initializers") {
138+
gen::makeUnique<Aggregate>(gen::arbitrary<int>(), gen::arbitrary<int>());
139+
}
140+
141+
SECTION("prefers T(x, y) over T{x, y} when they behave differently") {
142+
auto a = gen::makeUnique<std::vector<int>>(gen::just(3), gen::just(3))(Random(), 0).value();
143+
auto b = std::unique_ptr<std::vector<int>>(new std::vector<int>(3, 3));
144+
RC_ASSERT(*a == *b);
145+
}
125146
}
126147

127148
TEST_CASE("gen::makeShared") {
@@ -154,6 +175,16 @@ TEST_CASE("gen::makeShared") {
154175
RC_ASSERT(isArbitraryPredictable(std::get<0>(value)));
155176
RC_ASSERT(isArbitraryPredictable(std::get<1>(value)));
156177
}
178+
179+
SECTION("works with aggregate initializers") {
180+
gen::makeShared<Aggregate>(gen::arbitrary<int>(), gen::arbitrary<int>());
181+
}
182+
183+
SECTION("prefers T(x, y) over T{x, y} when they behave differently") {
184+
auto a = gen::makeShared<std::vector<int>>(gen::just(3), gen::just(3))(Random(), 0).value();
185+
auto b = std::shared_ptr<std::vector<int>>(new std::vector<int>(3, 3));
186+
RC_ASSERT(*a == *b);
187+
}
157188
}
158189

159190
namespace {

test/util/Aggregate.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#pragma once
2+
3+
namespace rc {
4+
struct Aggregate {
5+
int x;
6+
int y;
7+
};
8+
} // namespace rc

0 commit comments

Comments
 (0)