mirror of
https://github.com/Naios/continuable.git
synced 2025-12-10 02:36:43 +08:00
Convert more tests into proper gtest cases
This commit is contained in:
parent
a5640a5d35
commit
5904ea06b4
@ -72,7 +72,7 @@ struct all_map {
|
||||
}
|
||||
};
|
||||
|
||||
TEST(traverse_single_test, test_container_categories) {
|
||||
TEST(traverse_container, categories) {
|
||||
using cti::detail::traversal::container_category_of_t;
|
||||
using cti::detail::traversal::container_category_tag;
|
||||
|
||||
@ -94,7 +94,7 @@ TEST(traverse_single_test, test_container_categories) {
|
||||
"Wrong category!");
|
||||
}
|
||||
|
||||
TEST(traverse_single_test, test_mixed_traversal) {
|
||||
TEST(traverse_mixed, traversal) {
|
||||
auto res =
|
||||
map_pack(all_map_float{}, 0, 1.f, make_tuple(1.f, 3),
|
||||
std::vector<std::vector<int>>{{1, 2}, {4, 5}},
|
||||
@ -110,19 +110,19 @@ TEST(traverse_single_test, test_mixed_traversal) {
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
|
||||
TEST(traverse_single_test, test_mixed_traversal_build_regression) {
|
||||
TEST(traverse_mixed, build_regression) {
|
||||
// Broken build regression tests:
|
||||
traverse_pack(my_mapper{}, int(0), 1.f);
|
||||
map_pack(all_map{}, 0, std::vector<int>{1, 2});
|
||||
}
|
||||
|
||||
TEST(traverse_single_test, test_mixed_traversal_container_container_map) {
|
||||
TEST(traverse_mixed, container_container_map) {
|
||||
// Also a regression test
|
||||
auto res = map_pack(all_map{}, std::vector<std::vector<int>>{{1, 2}});
|
||||
EXPECT_EQ((res[0][0]), (0));
|
||||
}
|
||||
|
||||
TEST(traverse_single_test, test_mixed_traversal_result_tuple_mapped) {
|
||||
TEST(traverse_mixed, result_tuple_mapped) {
|
||||
auto res = map_pack(
|
||||
my_mapper{}, 0, 1.f,
|
||||
make_tuple(1.f, 3, std::vector<std::vector<int>>{{1, 2}, {4, 5}},
|
||||
@ -141,7 +141,7 @@ TEST(traverse_single_test, test_mixed_traversal_result_tuple_mapped) {
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
|
||||
TEST(traverse_single_test, test_mixed_traversal_all_elements_traversed) {
|
||||
TEST(traverse_mixed, all_elements_traversed) {
|
||||
int count = 0;
|
||||
traverse_pack(
|
||||
[&](int el) {
|
||||
@ -153,30 +153,6 @@ TEST(traverse_single_test, test_mixed_traversal_all_elements_traversed) {
|
||||
EXPECT_EQ((count), (7));
|
||||
}
|
||||
|
||||
/*
|
||||
struct my_unwrapper {
|
||||
template <typename T,
|
||||
typename std::enable_if<is_future<T>::value>::type* = nullptr>
|
||||
auto operator()(T future) const -> typename future_traits<T>::result_type {
|
||||
return future.get();
|
||||
}
|
||||
};
|
||||
|
||||
static void test_mixed_early_unwrapping() {
|
||||
{
|
||||
auto res = map_pack(my_unwrapper{}, // ...
|
||||
0, 1, make_ready_future(3),
|
||||
make_tuple(make_ready_future(4), make_ready_future(5)));
|
||||
|
||||
auto expected = make_tuple(0, 1, 3, make_tuple(4, 5));
|
||||
|
||||
static_assert(std::is_same<decltype(res), decltype(expected)>::value,
|
||||
"Type mismatch!");
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
struct my_allocator {
|
||||
using value_type = T;
|
||||
@ -218,54 +194,48 @@ struct my_allocator {
|
||||
}
|
||||
};
|
||||
|
||||
void test_mixed_container_remap() {
|
||||
// Traits
|
||||
// Traits
|
||||
TEST(traverse_mixed_container_remap, all_elements_traversed) {
|
||||
// TODO Enable this
|
||||
// using detail::container_remapping::has_push_back;
|
||||
// EXPECT_EQ((has_push_back<std::vector<int>, int>::value), true);
|
||||
// EXPECT_EQ((has_push_back<int, int>::value), false);
|
||||
}
|
||||
|
||||
static unsigned long int_remapper(unsigned short i) {
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
// Rebinds the values
|
||||
TEST(traverse_rebind_allocator, maps_values) {
|
||||
std::vector<unsigned short> source = {1, 2, 3};
|
||||
std::vector<unsigned long> dest = map_pack(int_remapper, source);
|
||||
|
||||
EXPECT_TRUE((dest == decltype(dest){0, 1, 2}));
|
||||
}
|
||||
|
||||
// Rebinds the allocator
|
||||
TEST(traverse_rebind_allocator, converts_allocator) {
|
||||
static unsigned const canary = 78787;
|
||||
|
||||
my_allocator<unsigned short> allocator(canary);
|
||||
std::vector<unsigned short, my_allocator<unsigned short>> source(allocator);
|
||||
|
||||
// Empty
|
||||
{
|
||||
// TODO Enable this
|
||||
// using detail::container_remapping::has_push_back;
|
||||
// EXPECT_EQ((has_push_back<std::vector<int>, int>::value), true);
|
||||
// EXPECT_EQ((has_push_back<int, int>::value), false);
|
||||
std::vector<unsigned long, my_allocator<unsigned long>> remapped =
|
||||
map_pack(int_remapper, source);
|
||||
|
||||
EXPECT_EQ((remapped.get_allocator().state_), (canary));
|
||||
}
|
||||
|
||||
// Rebind
|
||||
// Non empty
|
||||
source.push_back(1);
|
||||
{
|
||||
auto const remapper = [](unsigned short i) -> unsigned long {
|
||||
return i - 1;
|
||||
};
|
||||
std::vector<unsigned long, my_allocator<unsigned long>> remapped =
|
||||
map_pack(int_remapper, source);
|
||||
|
||||
// Rebinds the values
|
||||
{
|
||||
std::vector<unsigned short> source = {1, 2, 3};
|
||||
std::vector<unsigned long> dest = map_pack(remapper, source);
|
||||
|
||||
EXPECT_TRUE((dest == decltype(dest){0, 1, 2}));
|
||||
}
|
||||
|
||||
// Rebinds the allocator
|
||||
{
|
||||
static unsigned const canary = 78787;
|
||||
|
||||
my_allocator<unsigned short> allocator(canary);
|
||||
std::vector<unsigned short, my_allocator<unsigned short>> source(
|
||||
allocator);
|
||||
|
||||
// Empty
|
||||
{
|
||||
std::vector<unsigned long, my_allocator<unsigned long>> remapped =
|
||||
map_pack(remapper, source);
|
||||
|
||||
EXPECT_EQ((remapped.get_allocator().state_), (canary));
|
||||
}
|
||||
|
||||
// Non empty
|
||||
source.push_back(1);
|
||||
{
|
||||
std::vector<unsigned long, my_allocator<unsigned long>> remapped =
|
||||
map_pack(remapper, source);
|
||||
|
||||
EXPECT_EQ((remapped.get_allocator().state_), (canary));
|
||||
}
|
||||
}
|
||||
EXPECT_EQ((remapped.get_allocator().state_), (canary));
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,7 +255,8 @@ struct my_int_mapper {
|
||||
}
|
||||
};
|
||||
|
||||
void test_mixed_fall_through() {
|
||||
// TODO Take a look at this... what it was supposed to test
|
||||
TEST(traverse_mixed_fall_through, misc) {
|
||||
traverse_pack(my_int_mapper{}, int(0),
|
||||
std::vector<tuple<float, float>>{make_tuple(1.f, 2.f)},
|
||||
make_tuple(std::vector<float>{1.f, 2.f}));
|
||||
@ -298,12 +269,15 @@ void test_mixed_fall_through() {
|
||||
std::vector<std::vector<float>>{{1.f, 2.f}},
|
||||
make_tuple(77.f, 2));
|
||||
|
||||
(void)res1;
|
||||
|
||||
auto res2 = map_pack(
|
||||
[](int) {
|
||||
// ...
|
||||
return 0;
|
||||
},
|
||||
1, std::vector<int>{2, 3});
|
||||
(void)res2;
|
||||
}
|
||||
|
||||
class counter_mapper {
|
||||
@ -370,276 +344,270 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void test_strategic_traverse() {
|
||||
// Every element in the pack is visited
|
||||
{
|
||||
int counter = 0;
|
||||
counter_mapper mapper(counter);
|
||||
traverse_pack(mapper, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
||||
EXPECT_EQ(counter, 3);
|
||||
}
|
||||
|
||||
// Every element in the pack is visited from left to right
|
||||
{
|
||||
int counter = 0;
|
||||
traverse_pack(
|
||||
[&](int el) {
|
||||
EXPECT_EQ(counter, el);
|
||||
++counter;
|
||||
},
|
||||
0, 1, 2, 3);
|
||||
EXPECT_EQ(counter, 4);
|
||||
}
|
||||
|
||||
// Elements accepted by the mapper aren't traversed:
|
||||
// - Signature
|
||||
{
|
||||
int counter = 0;
|
||||
counter_mapper_rejecting_non_tag_1 mapper(counter);
|
||||
traverse_pack(mapper, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
||||
EXPECT_EQ(counter, 1);
|
||||
}
|
||||
|
||||
// - SFINAE
|
||||
{
|
||||
int counter = 0;
|
||||
counter_mapper_rejecting_non_tag_1_sfinae mapper(counter);
|
||||
traverse_pack(mapper, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
||||
EXPECT_EQ(counter, 1);
|
||||
}
|
||||
|
||||
// Remapping works across values
|
||||
{
|
||||
tuple<int, int, int> res = map_pack([](int i) { return i + 1; }, 0, 1, 2);
|
||||
|
||||
auto expected = make_tuple(1, 2, 3);
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
|
||||
// Remapping works across types
|
||||
{
|
||||
tag_shift_mapper mapper;
|
||||
tuple<float, test_tag_2, test_tag_3, test_tag_1> res =
|
||||
map_pack(mapper, 1, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
||||
|
||||
EXPECT_EQ(get<0>(res), 0.f);
|
||||
}
|
||||
|
||||
// Remapping works with move-only objects
|
||||
{
|
||||
std::unique_ptr<int> p1(new int(1));
|
||||
std::unique_ptr<int> p2(new int(2));
|
||||
std::unique_ptr<int> p3(new int(3));
|
||||
|
||||
tuple<std::unique_ptr<unsigned>, std::unique_ptr<unsigned>,
|
||||
std::unique_ptr<unsigned>>
|
||||
res = map_pack(
|
||||
// Since we pass the unique_ptr's as r-value,
|
||||
// those should be passed as r-values to the mapper.
|
||||
[](std::unique_ptr<int>&& ptr) {
|
||||
// We explicitly move the ownership here
|
||||
std::unique_ptr<int> owned = std::move(ptr);
|
||||
return std::unique_ptr<unsigned>(new unsigned(*owned + 1));
|
||||
},
|
||||
std::move(p1), std::move(p2), std::move(p3));
|
||||
|
||||
// We expect the ownership of p1 - p3 to be invalid
|
||||
EXPECT_TRUE((!bool(p1)));
|
||||
EXPECT_TRUE((!bool(p2)));
|
||||
EXPECT_TRUE((!bool(p3)));
|
||||
|
||||
EXPECT_EQ((*get<0>(res)), 2U);
|
||||
EXPECT_EQ((*get<1>(res)), 3U);
|
||||
EXPECT_EQ((*get<2>(res)), 4U);
|
||||
}
|
||||
|
||||
// Move only types contained in a pack which was passed as l-value
|
||||
// reference is forwarded to the mapper as reference too.
|
||||
{
|
||||
std::vector<std::unique_ptr<int>> container;
|
||||
container.push_back(std::unique_ptr<int>(new int(3)));
|
||||
|
||||
std::vector<int> res =
|
||||
map_pack([](std::unique_ptr<int>& p) { return *p; }, container);
|
||||
|
||||
EXPECT_EQ(res.size(), 1U);
|
||||
EXPECT_EQ(res[0], 3);
|
||||
}
|
||||
|
||||
// Single object remapping returns the value itself without any boxing
|
||||
{
|
||||
int res = map_pack([](int i) { return i; }, 1);
|
||||
EXPECT_EQ(res, 1);
|
||||
}
|
||||
|
||||
// Make it possible to pass move only objects in as reference,
|
||||
// while returning those as reference.
|
||||
{
|
||||
std::unique_ptr<int> ptr(new int(7));
|
||||
|
||||
std::unique_ptr<int> const& ref = map_pack(
|
||||
[](std::unique_ptr<int> const& ref) -> std::unique_ptr<int> const& {
|
||||
// ...
|
||||
return ref;
|
||||
},
|
||||
ptr);
|
||||
|
||||
EXPECT_EQ(*ref, 7);
|
||||
*ptr = 0;
|
||||
EXPECT_EQ(*ref, 0);
|
||||
}
|
||||
|
||||
// Multiple args: Make it possible to pass move only objects in
|
||||
// as reference, while returning those as reference.
|
||||
{
|
||||
std::unique_ptr<int> ptr1(new int(6));
|
||||
std::unique_ptr<int> ptr2(new int(7));
|
||||
|
||||
tuple<std::unique_ptr<int> const&, std::unique_ptr<int> const&> ref =
|
||||
map_pack(
|
||||
[](std::unique_ptr<int> const& ref) -> std::unique_ptr<int> const& {
|
||||
// ...
|
||||
return ref;
|
||||
},
|
||||
ptr1, ptr2);
|
||||
|
||||
EXPECT_EQ((*get<0>(ref)), 6);
|
||||
EXPECT_EQ((*get<1>(ref)), 7);
|
||||
*ptr1 = 1;
|
||||
*ptr2 = 2;
|
||||
EXPECT_EQ((*get<0>(ref)), 1);
|
||||
EXPECT_EQ((*get<1>(ref)), 2);
|
||||
}
|
||||
// Every element in the pack is visited
|
||||
TEST(traverse_strategic_traverse, visit_all_elements) {
|
||||
int counter = 0;
|
||||
counter_mapper mapper(counter);
|
||||
traverse_pack(mapper, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
||||
EXPECT_EQ(counter, 3);
|
||||
}
|
||||
|
||||
void test_strategic_container_traverse() {
|
||||
// Every element in the container is visited
|
||||
// - Plain container
|
||||
{
|
||||
int counter = 0;
|
||||
counter_mapper mapper(counter);
|
||||
std::vector<int> container;
|
||||
container.resize(100);
|
||||
traverse_pack(mapper, std::move(container));
|
||||
EXPECT_EQ(counter, 100);
|
||||
}
|
||||
// Every element in the pack is visited from left to right
|
||||
TEST(traverse_strategic_traverse, visit_left_to_right) {
|
||||
int counter = 0;
|
||||
traverse_pack(
|
||||
[&](int el) {
|
||||
EXPECT_EQ(counter, el);
|
||||
++counter;
|
||||
},
|
||||
0, 1, 2, 3);
|
||||
EXPECT_EQ(counter, 4);
|
||||
}
|
||||
|
||||
// - Nested container
|
||||
{
|
||||
int counter = 0;
|
||||
counter_mapper mapper(counter);
|
||||
std::vector<std::vector<int>> container;
|
||||
for (unsigned i = 0; i < 10; ++i) {
|
||||
std::vector<int> nested;
|
||||
nested.resize(10);
|
||||
container.push_back(nested);
|
||||
}
|
||||
// Elements accepted by the mapper aren't traversed:
|
||||
// - Signature
|
||||
TEST(traverse_strategic_traverse, visit_non_accepted) {
|
||||
int counter = 0;
|
||||
counter_mapper_rejecting_non_tag_1 mapper(counter);
|
||||
traverse_pack(mapper, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
||||
EXPECT_EQ(counter, 1);
|
||||
}
|
||||
|
||||
traverse_pack(mapper, std::move(container));
|
||||
EXPECT_EQ(counter, 100);
|
||||
}
|
||||
// - SFINAE
|
||||
TEST(traverse_strategic_traverse, visit_not_finaed) {
|
||||
int counter = 0;
|
||||
counter_mapper_rejecting_non_tag_1_sfinae mapper(counter);
|
||||
traverse_pack(mapper, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
||||
EXPECT_EQ(counter, 1);
|
||||
}
|
||||
|
||||
// Every element in the container is visited from left to right
|
||||
{
|
||||
int counter = 0;
|
||||
traverse_pack(
|
||||
[&](int el) {
|
||||
EXPECT_EQ(counter, el);
|
||||
++counter;
|
||||
},
|
||||
std::vector<int>{0, 1}, std::vector<std::vector<int>>{{2, 3}, {4, 5}});
|
||||
EXPECT_EQ(counter, 6);
|
||||
}
|
||||
// Remapping works across values
|
||||
TEST(traverse_strategic_traverse, remap_across_values) {
|
||||
tuple<int, int, int> res = map_pack([](int i) { return i + 1; }, 0, 1, 2);
|
||||
|
||||
// The container type itself is changed
|
||||
// - Plain container
|
||||
{
|
||||
std::vector<int> container{1, 2, 3};
|
||||
std::vector<float> res =
|
||||
map_pack([](int) { return 0.f; }, std::move(container));
|
||||
EXPECT_EQ(res.size(), 3U);
|
||||
}
|
||||
auto expected = make_tuple(1, 2, 3);
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
|
||||
// - Nested container
|
||||
{
|
||||
std::vector<std::vector<int>> container;
|
||||
std::vector<std::vector<float>> res =
|
||||
map_pack([](int) { return 0.f; }, std::move(container));
|
||||
}
|
||||
// Remapping works across types
|
||||
TEST(traverse_strategic_traverse, remap_across_types) {
|
||||
tag_shift_mapper mapper;
|
||||
tuple<float, test_tag_2, test_tag_3, test_tag_1> res =
|
||||
map_pack(mapper, 1, test_tag_1{}, test_tag_2{}, test_tag_3{});
|
||||
|
||||
// - Move only container
|
||||
{
|
||||
std::vector<std::unique_ptr<int>> container;
|
||||
container.push_back(std::unique_ptr<int>(new int(5)));
|
||||
std::vector<int> res = map_pack(
|
||||
[](std::unique_ptr<int>&& ptr) { return *ptr; }, std::move(container));
|
||||
EXPECT_EQ(get<0>(res), 0.f);
|
||||
}
|
||||
|
||||
EXPECT_EQ(res.size(), 1U);
|
||||
EXPECT_EQ(res[0], 5);
|
||||
}
|
||||
// Remapping works with move-only objects
|
||||
TEST(traverse_strategic_traverse, remap_move_only) {
|
||||
std::unique_ptr<int> p1(new int(1));
|
||||
std::unique_ptr<int> p2(new int(2));
|
||||
std::unique_ptr<int> p3(new int(3));
|
||||
|
||||
// Every element in the container is remapped
|
||||
// - Plain container
|
||||
{
|
||||
std::vector<int> container(100, 1);
|
||||
auto res = map_pack([](int) { return 2; }, std::move(container));
|
||||
|
||||
EXPECT_TRUE(
|
||||
(std::all_of(res.begin(), res.end(), [](int i) { return i == 2; })));
|
||||
}
|
||||
|
||||
// - Nested container
|
||||
{
|
||||
std::vector<std::list<int>> container;
|
||||
for (unsigned i = 0; i < 10; ++i) {
|
||||
std::list<int> nested(10, 1);
|
||||
container.push_back(nested);
|
||||
}
|
||||
|
||||
auto res = map_pack([](int) { return 2; }, std::move(container));
|
||||
EXPECT_TRUE(
|
||||
(std::all_of(res.begin(), res.end(), [](std::list<int> const& nested) {
|
||||
return std::all_of(nested.begin(), nested.end(),
|
||||
[](int i) { return i == 2; });
|
||||
})));
|
||||
}
|
||||
|
||||
/// - Ensure correct container remapping when returning references
|
||||
{
|
||||
// l-value references
|
||||
{
|
||||
std::vector<std::unique_ptr<int>> container;
|
||||
container.push_back(std::unique_ptr<int>(new int(7)));
|
||||
|
||||
std::vector<int> res = map_pack(
|
||||
[](std::unique_ptr<int> const& ref) -> int const& {
|
||||
// ...
|
||||
return *ref;
|
||||
tuple<std::unique_ptr<unsigned>, std::unique_ptr<unsigned>,
|
||||
std::unique_ptr<unsigned>>
|
||||
res = map_pack(
|
||||
// Since we pass the unique_ptr's as r-value,
|
||||
// those should be passed as r-values to the mapper.
|
||||
[](std::unique_ptr<int>&& ptr) {
|
||||
// We explicitly move the ownership here
|
||||
std::unique_ptr<int> owned = std::move(ptr);
|
||||
return std::unique_ptr<unsigned>(new unsigned(*owned + 1));
|
||||
},
|
||||
container);
|
||||
std::move(p1), std::move(p2), std::move(p3));
|
||||
|
||||
EXPECT_EQ(res.size(), 1U);
|
||||
EXPECT_EQ(res[0], 7);
|
||||
}
|
||||
// We expect the ownership of p1 - p3 to be invalid
|
||||
EXPECT_TRUE((!bool(p1)));
|
||||
EXPECT_TRUE((!bool(p2)));
|
||||
EXPECT_TRUE((!bool(p3)));
|
||||
|
||||
// r-value references
|
||||
{
|
||||
std::vector<std::unique_ptr<std::unique_ptr<int>>> container;
|
||||
container.push_back(std::unique_ptr<std::unique_ptr<int>>(
|
||||
new std::unique_ptr<int>(new int(7))));
|
||||
EXPECT_EQ((*get<0>(res)), 2U);
|
||||
EXPECT_EQ((*get<1>(res)), 3U);
|
||||
EXPECT_EQ((*get<2>(res)), 4U);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<int>> res = map_pack(
|
||||
[](std::unique_ptr<std::unique_ptr<int>> &
|
||||
ref) -> std::unique_ptr<int>&& {
|
||||
// Move only types contained in a pack which was passed as l-value
|
||||
// reference is forwarded to the mapper as reference too.
|
||||
TEST(traverse_strategic_traverse, remap_references) {
|
||||
std::vector<std::unique_ptr<int>> container;
|
||||
container.push_back(std::unique_ptr<int>(new int(3)));
|
||||
|
||||
std::vector<int> res =
|
||||
map_pack([](std::unique_ptr<int>& p) { return *p; }, container);
|
||||
|
||||
EXPECT_EQ(res.size(), 1U);
|
||||
EXPECT_EQ(res[0], 3);
|
||||
}
|
||||
|
||||
// Single object remapping returns the value itself without any boxing
|
||||
TEST(traverse_strategic_traverse, remap_single_values) {
|
||||
int res = map_pack([](int i) { return i; }, 1);
|
||||
EXPECT_EQ(res, 1);
|
||||
}
|
||||
|
||||
// Make it possible to pass move only objects in as reference,
|
||||
// while returning those as reference.
|
||||
TEST(traverse_strategic_traverse, remap_move_only_as_ref) {
|
||||
std::unique_ptr<int> ptr(new int(7));
|
||||
|
||||
std::unique_ptr<int> const& ref = map_pack(
|
||||
[](std::unique_ptr<int> const& ref) -> std::unique_ptr<int> const& {
|
||||
// ...
|
||||
return ref;
|
||||
},
|
||||
ptr);
|
||||
|
||||
EXPECT_EQ(*ref, 7);
|
||||
*ptr = 0;
|
||||
EXPECT_EQ(*ref, 0);
|
||||
}
|
||||
|
||||
// Multiple args: Make it possible to pass move only objects in
|
||||
// as reference, while returning those as reference.
|
||||
TEST(traverse_strategic_traverse, remap_multiple_move_only_as_ref) {
|
||||
std::unique_ptr<int> ptr1(new int(6));
|
||||
std::unique_ptr<int> ptr2(new int(7));
|
||||
|
||||
tuple<std::unique_ptr<int> const&, std::unique_ptr<int> const&> ref =
|
||||
map_pack(
|
||||
[](std::unique_ptr<int> const& ref) -> std::unique_ptr<int> const& {
|
||||
// ...
|
||||
return std::move(*ref);
|
||||
return ref;
|
||||
},
|
||||
container);
|
||||
ptr1, ptr2);
|
||||
|
||||
EXPECT_EQ(res.size(), 1U);
|
||||
EXPECT_EQ((*res[0]), 7);
|
||||
}
|
||||
EXPECT_EQ((*get<0>(ref)), 6);
|
||||
EXPECT_EQ((*get<1>(ref)), 7);
|
||||
*ptr1 = 1;
|
||||
*ptr2 = 2;
|
||||
EXPECT_EQ((*get<0>(ref)), 1);
|
||||
EXPECT_EQ((*get<1>(ref)), 2);
|
||||
}
|
||||
|
||||
// Every element in the container is visited
|
||||
// - Plain container
|
||||
TEST(test_strategic_container_traverse, plain_container) {
|
||||
int counter = 0;
|
||||
counter_mapper mapper(counter);
|
||||
std::vector<int> container;
|
||||
container.resize(100);
|
||||
traverse_pack(mapper, std::move(container));
|
||||
EXPECT_EQ(counter, 100);
|
||||
}
|
||||
|
||||
// - Nested container
|
||||
TEST(test_strategic_container_traverse, nested_container) {
|
||||
int counter = 0;
|
||||
counter_mapper mapper(counter);
|
||||
std::vector<std::vector<int>> container;
|
||||
for (unsigned i = 0; i < 10; ++i) {
|
||||
std::vector<int> nested;
|
||||
nested.resize(10);
|
||||
container.push_back(nested);
|
||||
}
|
||||
|
||||
traverse_pack(mapper, std::move(container));
|
||||
EXPECT_EQ(counter, 100);
|
||||
}
|
||||
|
||||
// Every element in the container is visited from left to right
|
||||
TEST(test_strategic_container_traverse, left_to_right) {
|
||||
int counter = 0;
|
||||
traverse_pack(
|
||||
[&](int el) {
|
||||
EXPECT_EQ(counter, el);
|
||||
++counter;
|
||||
},
|
||||
std::vector<int>{0, 1}, std::vector<std::vector<int>>{{2, 3}, {4, 5}});
|
||||
EXPECT_EQ(counter, 6);
|
||||
}
|
||||
|
||||
// The container type itself is changed
|
||||
// - Plain container
|
||||
TEST(test_strategic_container_traverse, type_changed_plain) {
|
||||
std::vector<int> container{1, 2, 3};
|
||||
std::vector<float> res =
|
||||
map_pack([](int) { return 0.f; }, std::move(container));
|
||||
EXPECT_EQ(res.size(), 3U);
|
||||
}
|
||||
|
||||
// - Nested container
|
||||
TEST(test_strategic_container_traverse, type_changed_nested) {
|
||||
std::vector<std::vector<int>> container;
|
||||
std::vector<std::vector<float>> res =
|
||||
map_pack([](int) { return 0.f; }, std::move(container));
|
||||
}
|
||||
|
||||
// - Move only container
|
||||
TEST(test_strategic_container_traverse, type_changed_move_only) {
|
||||
std::vector<std::unique_ptr<int>> container;
|
||||
container.push_back(std::unique_ptr<int>(new int(5)));
|
||||
std::vector<int> res = map_pack(
|
||||
[](std::unique_ptr<int>&& ptr) { return *ptr; }, std::move(container));
|
||||
|
||||
EXPECT_EQ(res.size(), 1U);
|
||||
EXPECT_EQ(res[0], 5);
|
||||
}
|
||||
|
||||
// Every element in the container is remapped
|
||||
// - Plain container
|
||||
TEST(test_strategic_container_traverse, every_element_remapped_plain) {
|
||||
std::vector<int> container(100, 1);
|
||||
auto res = map_pack([](int) { return 2; }, std::move(container));
|
||||
|
||||
EXPECT_TRUE(
|
||||
(std::all_of(res.begin(), res.end(), [](int i) { return i == 2; })));
|
||||
}
|
||||
|
||||
// - Nested container
|
||||
TEST(test_strategic_container_traverse, every_element_remapped_nested) {
|
||||
std::vector<std::list<int>> container;
|
||||
for (unsigned i = 0; i < 10; ++i) {
|
||||
std::list<int> nested(10, 1);
|
||||
container.push_back(nested);
|
||||
}
|
||||
|
||||
auto res = map_pack([](int) { return 2; }, std::move(container));
|
||||
EXPECT_TRUE(
|
||||
(std::all_of(res.begin(), res.end(), [](std::list<int> const& nested) {
|
||||
return std::all_of(nested.begin(), nested.end(),
|
||||
[](int i) { return i == 2; });
|
||||
})));
|
||||
}
|
||||
|
||||
/// - Ensure correct container remapping when returning references
|
||||
// l-value references
|
||||
TEST(test_strategic_container_traverse, every_element_remapped_lvalue) {
|
||||
std::vector<std::unique_ptr<int>> container;
|
||||
container.push_back(std::unique_ptr<int>(new int(7)));
|
||||
|
||||
std::vector<int> res = map_pack(
|
||||
[](std::unique_ptr<int> const& ref) -> int const& {
|
||||
// ...
|
||||
return *ref;
|
||||
},
|
||||
container);
|
||||
|
||||
EXPECT_EQ(res.size(), 1U);
|
||||
EXPECT_EQ(res[0], 7);
|
||||
}
|
||||
|
||||
// r-value references
|
||||
TEST(test_strategic_container_traverse, every_element_remapped_rvalue) {
|
||||
std::vector<std::unique_ptr<std::unique_ptr<int>>> container;
|
||||
container.push_back(std::unique_ptr<std::unique_ptr<int>>(
|
||||
new std::unique_ptr<int>(new int(7))));
|
||||
|
||||
std::vector<std::unique_ptr<int>> res = map_pack(
|
||||
[](std::unique_ptr<std::unique_ptr<int>> &
|
||||
ref) -> std::unique_ptr<int>&& {
|
||||
// ...
|
||||
return std::move(*ref);
|
||||
},
|
||||
container);
|
||||
|
||||
EXPECT_EQ(res.size(), 1U);
|
||||
EXPECT_EQ((*res[0]), 7);
|
||||
}
|
||||
|
||||
TEST(traverse_single_test, test_strategic_tuple_like_traverse_homogeneous) {
|
||||
@ -650,70 +618,68 @@ TEST(traverse_single_test, test_strategic_tuple_like_traverse_homogeneous) {
|
||||
EXPECT_TRUE((res == std::array<float, 3>{{1.f, 1.f, 1.f}}));
|
||||
}
|
||||
|
||||
void test_strategic_tuple_like_traverse() {
|
||||
// Every element in the tuple like type is visited
|
||||
{
|
||||
int counter = 0;
|
||||
counter_mapper mapper(counter);
|
||||
traverse_pack(mapper, make_tuple(test_tag_1{}, test_tag_2{}, test_tag_3{}));
|
||||
EXPECT_EQ(counter, 3);
|
||||
}
|
||||
// Every element in the tuple like type is visited
|
||||
TEST(traverse_strategic_tuple_like_traverse, all_elements_visited) {
|
||||
int counter = 0;
|
||||
counter_mapper mapper(counter);
|
||||
traverse_pack(mapper, make_tuple(test_tag_1{}, test_tag_2{}, test_tag_3{}));
|
||||
EXPECT_EQ(counter, 3);
|
||||
}
|
||||
|
||||
// Every element in the tuple like type is visited from left to right
|
||||
{
|
||||
int counter = 0;
|
||||
traverse_pack(
|
||||
[&](int el) {
|
||||
EXPECT_EQ(counter, el);
|
||||
++counter;
|
||||
},
|
||||
make_tuple(0, 1), make_tuple(make_tuple(2, 3), make_tuple(4, 5)),
|
||||
make_tuple(make_tuple(make_tuple(6, 7))));
|
||||
EXPECT_EQ(counter, 8);
|
||||
}
|
||||
// Every element in the tuple like type is visited from left to right
|
||||
TEST(traverse_strategic_tuple_like_traverse, visited_left_to_right) {
|
||||
int counter = 0;
|
||||
traverse_pack(
|
||||
[&](int el) {
|
||||
EXPECT_EQ(counter, el);
|
||||
++counter;
|
||||
},
|
||||
make_tuple(0, 1), make_tuple(make_tuple(2, 3), make_tuple(4, 5)),
|
||||
make_tuple(make_tuple(make_tuple(6, 7))));
|
||||
EXPECT_EQ(counter, 8);
|
||||
}
|
||||
|
||||
// The container tuple like type itself is changed
|
||||
{
|
||||
tag_shift_mapper mapper;
|
||||
tuple<float, test_tag_2, test_tag_3, test_tag_1> res = map_pack(
|
||||
mapper, make_tuple(1, test_tag_1{}, test_tag_2{}, test_tag_3{}));
|
||||
// The container tuple like type itself is changed
|
||||
TEST(traverse_strategic_tuple_like_traverse, type_is_remapped) {
|
||||
tag_shift_mapper mapper;
|
||||
tuple<float, test_tag_2, test_tag_3, test_tag_1> res =
|
||||
map_pack(mapper, make_tuple(1, test_tag_1{}, test_tag_2{}, test_tag_3{}));
|
||||
|
||||
EXPECT_EQ(get<0>(res), 0.f);
|
||||
}
|
||||
EXPECT_EQ(get<0>(res), 0.f);
|
||||
}
|
||||
|
||||
// Every element in the tuple like type is remapped
|
||||
{
|
||||
tuple<float, float, float> res =
|
||||
map_pack([](int) { return 1.f; }, make_tuple(0, 0, 0));
|
||||
// Every element in the tuple like type is remapped
|
||||
TEST(traverse_strategic_tuple_like_traverse, all_elements_remapped) {
|
||||
tuple<float, float, float> res =
|
||||
map_pack([](int) { return 1.f; }, make_tuple(0, 0, 0));
|
||||
|
||||
auto expected = make_tuple(1.f, 1.f, 1.f);
|
||||
auto expected = make_tuple(1.f, 1.f, 1.f);
|
||||
|
||||
static_assert(std::is_same<decltype(res), decltype(expected)>::value,
|
||||
"Type mismatch!");
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
static_assert(std::is_same<decltype(res), decltype(expected)>::value,
|
||||
"Type mismatch!");
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
|
||||
// Make it possible to pass tuples containing move only objects
|
||||
// in as reference, while returning those as reference.
|
||||
{
|
||||
auto value = make_tuple(std::unique_ptr<int>(new int(6)),
|
||||
std::unique_ptr<int>(new int(7)));
|
||||
// Make it possible to pass tuples containing move only objects
|
||||
// in as reference, while returning those as reference.
|
||||
TEST(traverse_strategic_tuple_like_traverse, remap_references) {
|
||||
auto value = make_tuple(std::unique_ptr<int>(new int(6)),
|
||||
std::unique_ptr<int>(new int(7)));
|
||||
|
||||
tuple<std::unique_ptr<int> const&, std::unique_ptr<int> const&> ref =
|
||||
map_pack(
|
||||
[](std::unique_ptr<int> const& ref) -> std::unique_ptr<int> const& {
|
||||
// ...
|
||||
return ref;
|
||||
},
|
||||
value);
|
||||
tuple<std::unique_ptr<int> const&, std::unique_ptr<int> const&> ref =
|
||||
map_pack(
|
||||
[](std::unique_ptr<int> const& ref) -> std::unique_ptr<int> const& {
|
||||
// ...
|
||||
return ref;
|
||||
},
|
||||
value);
|
||||
|
||||
EXPECT_EQ((*get<0>(ref)), 6);
|
||||
EXPECT_EQ((*get<1>(ref)), 7);
|
||||
(*get<0>(ref)) = 1;
|
||||
(*get<1>(ref)) = 2;
|
||||
EXPECT_EQ((*get<0>(ref)), 1);
|
||||
EXPECT_EQ((*get<1>(ref)), 2);
|
||||
}
|
||||
EXPECT_EQ((*get<0>(ref)), 6);
|
||||
EXPECT_EQ((*get<1>(ref)), 7);
|
||||
(*get<0>(ref)) = 1;
|
||||
(*get<1>(ref)) = 2;
|
||||
EXPECT_EQ((*get<0>(ref)), 1);
|
||||
EXPECT_EQ((*get<1>(ref)), 2);
|
||||
}
|
||||
|
||||
/// A mapper which duplicates the given element
|
||||
@ -732,44 +698,40 @@ struct zero_mapper {
|
||||
}
|
||||
};
|
||||
|
||||
void test_spread_traverse() {
|
||||
// 1:2 mappings (multiple arguments)
|
||||
{
|
||||
tuple<int, int, int, int> res = map_pack(duplicate_mapper{}, 1, 2);
|
||||
// 1:2 mappings (multiple arguments)
|
||||
TEST(traverse_spread_traverse, one_to_two_mapping) {
|
||||
tuple<int, int, int, int> res = map_pack(duplicate_mapper{}, 1, 2);
|
||||
|
||||
auto expected = make_tuple(1, 1, 2, 2);
|
||||
auto expected = make_tuple(1, 1, 2, 2);
|
||||
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
|
||||
// 1:0 mappings
|
||||
{
|
||||
using Result = decltype(map_pack(zero_mapper{}, 0, 1, 2));
|
||||
static_assert(std::is_void<Result>::value, "Failed...");
|
||||
}
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
|
||||
void test_spread_container_traverse() {
|
||||
// 1:2 mappings (multiple arguments)
|
||||
{
|
||||
std::vector<tuple<int, int>> res =
|
||||
map_pack(duplicate_mapper{}, std::vector<int>{1});
|
||||
|
||||
std::vector<tuple<int, int>> expected;
|
||||
expected.push_back(make_tuple(1, 1));
|
||||
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
|
||||
// 1:0 mappings
|
||||
{
|
||||
using Result = decltype(map_pack(zero_mapper{}, std::vector<int>{1}));
|
||||
static_assert(std::is_void<Result>::value, "Failed...");
|
||||
}
|
||||
// 1:0 mappings
|
||||
TEST(traverse_spread_traverse, one_to_zero_mapping) {
|
||||
using Result = decltype(map_pack(zero_mapper{}, 0, 1, 2));
|
||||
static_assert(std::is_void<Result>::value, "Failed...");
|
||||
}
|
||||
|
||||
// 1:2 mappings (multiple arguments)
|
||||
TEST(traverse_single_test, test_spread_container_traverse_multiple_args) {
|
||||
TEST(traverse_spread_container_traverse, one_to_two_mapping) {
|
||||
std::vector<tuple<int, int>> res =
|
||||
map_pack(duplicate_mapper{}, std::vector<int>{1});
|
||||
|
||||
std::vector<tuple<int, int>> expected;
|
||||
expected.push_back(make_tuple(1, 1));
|
||||
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
|
||||
// 1:0 mappings
|
||||
TEST(traverse_spread_container_traverse, one_to_zero_mapping) {
|
||||
using Result = decltype(map_pack(zero_mapper{}, std::vector<int>{1}));
|
||||
static_assert(std::is_void<Result>::value, "Failed...");
|
||||
}
|
||||
|
||||
// 1:2 mappings (multiple arguments)
|
||||
TEST(traverse_spread_container_traverse, multiple_args) {
|
||||
auto res = map_pack(duplicate_mapper{}, std::array<int, 2>{{1, 2}});
|
||||
|
||||
std::array<int, 4> expected{{1, 1, 2, 2}};
|
||||
@ -777,29 +739,26 @@ TEST(traverse_single_test, test_spread_container_traverse_multiple_args) {
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
|
||||
void test_spread_tuple_like_traverse() {
|
||||
// 1:2 mappings (multiple arguments)
|
||||
{
|
||||
tuple<tuple<int, int, int, int>> res =
|
||||
map_pack(duplicate_mapper{}, make_tuple(make_tuple(1, 2)));
|
||||
// 1:2 mappings (multiple arguments)
|
||||
TEST(traverse_spread_tuple_like_traverse, multiple_args) {
|
||||
tuple<tuple<int, int, int, int>> res =
|
||||
map_pack(duplicate_mapper{}, make_tuple(make_tuple(1, 2)));
|
||||
|
||||
tuple<tuple<int, int, int, int>> expected =
|
||||
make_tuple(make_tuple(1, 1, 2, 2));
|
||||
tuple<tuple<int, int, int, int>> expected =
|
||||
make_tuple(make_tuple(1, 1, 2, 2));
|
||||
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
|
||||
// 1:0 mappings
|
||||
{
|
||||
using Result =
|
||||
decltype(map_pack(zero_mapper{}, make_tuple(make_tuple(1, 2), 1), 1));
|
||||
static_assert(std::is_void<Result>::value, "Failed...");
|
||||
}
|
||||
|
||||
// 1:0 mappings
|
||||
{
|
||||
using Result =
|
||||
decltype(map_pack(zero_mapper{}, std::array<int, 2>{{1, 2}}));
|
||||
static_assert(std::is_void<Result>::value, "Failed...");
|
||||
}
|
||||
EXPECT_TRUE((res == expected));
|
||||
}
|
||||
|
||||
// 1:0 mappings
|
||||
TEST(traverse_spread_tuple_like_traverse, one_to_zero_mapping_tuple) {
|
||||
using Result =
|
||||
decltype(map_pack(zero_mapper{}, make_tuple(make_tuple(1, 2), 1), 1));
|
||||
static_assert(std::is_void<Result>::value, "Failed...");
|
||||
}
|
||||
|
||||
// 1:0 mappings
|
||||
TEST(traverse_spread_tuple_like_traverse, one_to_zero_mapping_array) {
|
||||
using Result = decltype(map_pack(zero_mapper{}, std::array<int, 2>{{1, 2}}));
|
||||
static_assert(std::is_void<Result>::value, "Failed...");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user