test: merge poly tests in a single file, use typed tests to reduce the boilerplate

This commit is contained in:
Michele Caini
2022-01-29 10:51:25 +01:00
parent 84445aa28b
commit e4897f709e
3 changed files with 129 additions and 339 deletions

View File

@@ -223,8 +223,7 @@ SETUP_BASIC_TEST(meta_utility entt/meta/meta_utility.cpp)
# Test poly
SETUP_BASIC_TEST(poly_deduced entt/poly/poly_deduced.cpp)
SETUP_BASIC_TEST(poly_defined entt/poly/poly_defined.cpp)
SETUP_BASIC_TEST(poly entt/poly/poly.cpp)
# Test process

View File

@@ -4,6 +4,51 @@
#include <entt/core/type_traits.hpp>
#include <entt/poly/poly.hpp>
struct Deduced
: entt::type_list<> {
template<typename Base>
struct type: Base {
void incr() {
entt::poly_call<0>(*this);
}
void set(int v) {
entt::poly_call<1>(*this, v);
}
int get() const {
return entt::poly_call<2>(*this);
}
void decr() {
entt::poly_call<3>(*this);
}
int mul(int v) const {
return static_cast<int>(entt::poly_call<4>(*this, v));
}
};
template<typename Type>
struct members {
static void decr(Type &self) {
self.set(self.get() - 1);
}
static double mul(const Type &self, double v) {
return v * self.get();
}
};
template<typename Type>
using impl = entt::value_list<
&Type::incr,
&Type::set,
&Type::get,
&members<Type>::decr,
&members<Type>::mul>;
};
struct Defined
: entt::type_list<
void(),
@@ -83,15 +128,35 @@ struct impl {
int value{};
};
struct alignas(64u) over_aligned: impl {};
template<typename Type>
struct Poly: testing::Test {
using basic = entt::poly<Type>;
using zeroed = entt::basic_poly<Type, 0>;
struct alignas(64u) over_aligned: impl {};
static constexpr auto alignment = alignof(over_aligned);
static inline entt::basic_poly<Type, alignment, alignment> sbo[2] = {over_aligned{}, over_aligned{}};
static inline entt::basic_poly<Type, alignment> nosbo[2] = {over_aligned{}, over_aligned{}};
};
template<typename Type>
using PolyDeathTest = Poly<Type>;
using PolyTypes = ::testing::Types<Deduced, Defined>;
TYPED_TEST_SUITE(Poly, PolyTypes);
TYPED_TEST_SUITE(PolyDeathTest, PolyTypes);
TYPED_TEST(Poly, Functionalities) {
using poly_type = typename TestFixture::basic;
TEST(PolyDefined, Functionalities) {
impl instance{};
entt::poly<Defined> empty{};
entt::poly<Defined> in_place{std::in_place_type<impl>, 3};
entt::poly<Defined> alias{std::in_place_type<impl &>, instance};
entt::poly<Defined> value{impl{}};
poly_type empty{};
poly_type in_place{std::in_place_type<impl>, 3};
poly_type alias{std::in_place_type<impl &>, instance};
poly_type value{impl{}};
ASSERT_FALSE(empty);
ASSERT_TRUE(in_place);
@@ -119,7 +184,7 @@ TEST(PolyDefined, Functionalities) {
ASSERT_TRUE(empty);
ASSERT_EQ(empty->get(), 3);
entt::poly<Defined> ref = in_place.as_ref();
poly_type ref = in_place.as_ref();
ASSERT_TRUE(ref);
ASSERT_NE(ref.data(), nullptr);
@@ -128,17 +193,17 @@ TEST(PolyDefined, Functionalities) {
ASSERT_EQ(ref.type(), entt::type_id<impl>());
ASSERT_EQ(ref->get(), 3);
entt::poly<Defined> null{};
poly_type null{};
std::swap(empty, null);
ASSERT_FALSE(empty);
entt::poly<Defined> copy = in_place;
poly_type copy = in_place;
ASSERT_TRUE(copy);
ASSERT_EQ(copy->get(), 3);
entt::poly<Defined> move = std::move(copy);
poly_type move = std::move(copy);
ASSERT_TRUE(move);
ASSERT_TRUE(copy);
@@ -150,8 +215,10 @@ TEST(PolyDefined, Functionalities) {
ASSERT_EQ(move.type(), entt::type_id<void>());
}
TEST(PolyDefined, Owned) {
entt::poly<Defined> poly{impl{}};
TYPED_TEST(Poly, Owned) {
using poly_type = typename TestFixture::basic;
poly_type poly{impl{}};
auto *ptr = static_cast<impl *>(poly.data());
ASSERT_TRUE(poly);
@@ -174,9 +241,11 @@ TEST(PolyDefined, Owned) {
ASSERT_EQ(poly->mul(3), 3);
}
TEST(PolyDefined, Reference) {
TYPED_TEST(Poly, Reference) {
using poly_type = typename TestFixture::basic;
impl instance{};
entt::poly<Defined> poly{std::in_place_type<impl &>, instance};
poly_type poly{std::in_place_type<impl &>, instance};
ASSERT_TRUE(poly);
ASSERT_NE(poly.data(), nullptr);
@@ -198,9 +267,11 @@ TEST(PolyDefined, Reference) {
ASSERT_EQ(poly->mul(3), 3);
}
TEST(PolyDefined, ConstReference) {
TYPED_TEST(Poly, ConstReference) {
using poly_type = typename TestFixture::basic;
impl instance{};
entt::poly<Defined> poly{std::in_place_type<const impl &>, instance};
poly_type poly{std::in_place_type<const impl &>, instance};
ASSERT_TRUE(poly);
ASSERT_EQ(poly.data(), nullptr);
@@ -217,16 +288,20 @@ TEST(PolyDefined, ConstReference) {
ASSERT_EQ(poly->mul(3), 0);
}
TEST(PolyDefinedDeathTest, ConstReference) {
TYPED_TEST(PolyDeathTest, ConstReference) {
using poly_type = typename TestFixture::basic;
impl instance{};
entt::poly<Defined> poly{std::in_place_type<const impl &>, instance};
poly_type poly{std::in_place_type<const impl &>, instance};
ASSERT_TRUE(poly);
ASSERT_DEATH(poly->set(1), "");
}
TEST(PolyDefined, AsRef) {
entt::poly<Defined> poly{impl{}};
TYPED_TEST(Poly, AsRef) {
using poly_type = typename TestFixture::basic;
poly_type poly{impl{}};
auto ref = poly.as_ref();
auto cref = std::as_const(poly).as_ref();
@@ -256,16 +331,19 @@ TEST(PolyDefined, AsRef) {
ASSERT_NE(cref.data(), nullptr);
}
TEST(PolyDefined, SBOVsZeroedSBOSize) {
entt::poly<Defined> sbo{impl{}};
TYPED_TEST(Poly, SBOVsZeroedSBOSize) {
using poly_type = typename TestFixture::basic;
using zeroed_type = typename TestFixture::zeroed;
poly_type sbo{impl{}};
const auto broken = sbo.data();
entt::poly<Defined> other = std::move(sbo);
poly_type other = std::move(sbo);
ASSERT_NE(broken, other.data());
entt::basic_poly<Defined, 0u> dyn{impl{}};
zeroed_type dyn{impl{}};
const auto valid = dyn.data();
entt::basic_poly<Defined, 0u> same = std::move(dyn);
zeroed_type same = std::move(dyn);
ASSERT_EQ(valid, same.data());
@@ -275,26 +353,34 @@ TEST(PolyDefined, SBOVsZeroedSBOSize) {
ASSERT_EQ(same->get(), 1);
}
TEST(PolyDefined, Alignment) {
static constexpr auto alignment = alignof(over_aligned);
TYPED_TEST(Poly, SboAlignment) {
using poly_type = typename TestFixture::basic;
auto test = [](auto *target, auto cb) {
const auto *data = target[0].data();
const auto *data = TestFixture::sbo[0].data();
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(target[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(target[1u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::sbo[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::sbo[1u].data()) % alignment) == 0u);
std::swap(target[0], target[1]);
std::swap(TestFixture::sbo[0], TestFixture::sbo[1]);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(target[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(target[1u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::sbo[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::sbo[1u].data()) % alignment) == 0u);
cb(data, target[1].data());
};
entt::basic_poly<Defined, alignment> nosbo[2] = {over_aligned{}, over_aligned{}};
test(nosbo, [](auto *pre, auto *post) { ASSERT_EQ(pre, post); });
entt::basic_poly<Defined, alignment, alignment> sbo[2] = {over_aligned{}, over_aligned{}};
test(sbo, [](auto *pre, auto *post) { ASSERT_NE(pre, post); });
ASSERT_NE(data, TestFixture::sbo[1].data());
}
TYPED_TEST(Poly, NoSboAlignment) {
using poly_type = typename TestFixture::basic;
const auto *data = TestFixture::nosbo[0].data();
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::nosbo[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::nosbo[1u].data()) % alignment) == 0u);
std::swap(TestFixture::nosbo[0], TestFixture::nosbo[1]);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::nosbo[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(TestFixture::nosbo[1u].data()) % alignment) == 0u);
ASSERT_EQ(data, TestFixture::nosbo[1].data());
}

View File

@@ -1,295 +0,0 @@
#include <functional>
#include <type_traits>
#include <gtest/gtest.h>
#include <entt/core/type_traits.hpp>
#include <entt/poly/poly.hpp>
struct Deduced
: entt::type_list<> {
template<typename Base>
struct type: Base {
void incr() {
entt::poly_call<0>(*this);
}
void set(int v) {
entt::poly_call<1>(*this, v);
}
int get() const {
return entt::poly_call<2>(*this);
}
void decr() {
entt::poly_call<3>(*this);
}
int mul(int v) const {
return static_cast<int>(entt::poly_call<4>(*this, v));
}
};
template<typename Type>
struct members {
static void decr(Type &self) {
self.set(self.get() - 1);
}
static double mul(const Type &self, double v) {
return v * self.get();
}
};
template<typename Type>
using impl = entt::value_list<
&Type::incr,
&Type::set,
&Type::get,
&members<Type>::decr,
&members<Type>::mul>;
};
struct impl {
impl() = default;
impl(int v)
: value{v} {}
void incr() {
++value;
}
void set(int v) {
value = v;
}
int get() const {
return value;
}
void decrement() {
--value;
}
double multiply(double v) const {
return v * value;
}
int value{};
};
struct alignas(64u) over_aligned: impl {};
TEST(PolyDeduced, Functionalities) {
impl instance{};
entt::poly<Deduced> empty{};
entt::poly<Deduced> in_place{std::in_place_type<impl>, 3};
entt::poly<Deduced> alias{std::in_place_type<impl &>, instance};
entt::poly<Deduced> value{impl{}};
ASSERT_FALSE(empty);
ASSERT_TRUE(in_place);
ASSERT_TRUE(alias);
ASSERT_TRUE(value);
ASSERT_EQ(empty.type(), entt::type_id<void>());
ASSERT_EQ(in_place.type(), entt::type_id<impl>());
ASSERT_EQ(alias.type(), entt::type_id<impl>());
ASSERT_EQ(value.type(), entt::type_id<impl>());
ASSERT_EQ(alias.data(), &instance);
ASSERT_EQ(std::as_const(alias).data(), &instance);
empty = impl{};
ASSERT_TRUE(empty);
ASSERT_NE(empty.data(), nullptr);
ASSERT_NE(std::as_const(empty).data(), nullptr);
ASSERT_EQ(empty.type(), entt::type_id<impl>());
ASSERT_EQ(empty->get(), 0);
empty.template emplace<impl>(3);
ASSERT_TRUE(empty);
ASSERT_EQ(empty->get(), 3);
entt::poly<Deduced> ref = in_place.as_ref();
ASSERT_TRUE(ref);
ASSERT_NE(ref.data(), nullptr);
ASSERT_EQ(ref.data(), in_place.data());
ASSERT_EQ(std::as_const(ref).data(), std::as_const(in_place).data());
ASSERT_EQ(ref.type(), entt::type_id<impl>());
ASSERT_EQ(ref->get(), 3);
entt::poly<Deduced> null{};
std::swap(empty, null);
ASSERT_FALSE(empty);
entt::poly<Deduced> copy = in_place;
ASSERT_TRUE(copy);
ASSERT_EQ(copy->get(), 3);
entt::poly<Deduced> move = std::move(copy);
ASSERT_TRUE(move);
ASSERT_TRUE(copy);
ASSERT_EQ(move->get(), 3);
move.reset();
ASSERT_FALSE(move);
ASSERT_EQ(move.type(), entt::type_id<void>());
}
TEST(PolyDeduced, Owned) {
entt::poly<Deduced> poly{impl{}};
auto *ptr = static_cast<impl *>(poly.data());
ASSERT_TRUE(poly);
ASSERT_NE(poly.data(), nullptr);
ASSERT_NE(std::as_const(poly).data(), nullptr);
ASSERT_EQ(ptr->value, 0);
ASSERT_EQ(poly->get(), 0);
poly->set(1);
poly->incr();
ASSERT_EQ(ptr->value, 2);
ASSERT_EQ(poly->get(), 2);
ASSERT_EQ(poly->mul(3), 6);
poly->decr();
ASSERT_EQ(ptr->value, 1);
ASSERT_EQ(poly->get(), 1);
ASSERT_EQ(poly->mul(3), 3);
}
TEST(PolyDeduced, Reference) {
impl instance{};
entt::poly<Deduced> poly{std::in_place_type<impl &>, instance};
ASSERT_TRUE(poly);
ASSERT_NE(poly.data(), nullptr);
ASSERT_NE(std::as_const(poly).data(), nullptr);
ASSERT_EQ(instance.value, 0);
ASSERT_EQ(poly->get(), 0);
poly->set(1);
poly->incr();
ASSERT_EQ(instance.value, 2);
ASSERT_EQ(poly->get(), 2);
ASSERT_EQ(poly->mul(3), 6);
poly->decr();
ASSERT_EQ(instance.value, 1);
ASSERT_EQ(poly->get(), 1);
ASSERT_EQ(poly->mul(3), 3);
}
TEST(PolyDeduced, ConstReference) {
impl instance{};
entt::poly<Deduced> poly{std::in_place_type<const impl &>, instance};
ASSERT_TRUE(poly);
ASSERT_EQ(poly.data(), nullptr);
ASSERT_NE(std::as_const(poly).data(), nullptr);
ASSERT_EQ(instance.value, 0);
ASSERT_EQ(poly->get(), 0);
ASSERT_EQ(instance.value, 0);
ASSERT_EQ(poly->get(), 0);
ASSERT_EQ(poly->mul(3), 0);
ASSERT_EQ(instance.value, 0);
ASSERT_EQ(poly->get(), 0);
ASSERT_EQ(poly->mul(3), 0);
}
TEST(PolyDeducedDeathTest, ConstReference) {
impl instance{};
entt::poly<Deduced> poly{std::in_place_type<const impl &>, instance};
ASSERT_TRUE(poly);
ASSERT_DEATH(poly->set(1), "");
}
TEST(PolyDeduced, AsRef) {
entt::poly<Deduced> poly{impl{}};
auto ref = poly.as_ref();
auto cref = std::as_const(poly).as_ref();
ASSERT_NE(poly.data(), nullptr);
ASSERT_NE(ref.data(), nullptr);
ASSERT_EQ(cref.data(), nullptr);
ASSERT_NE(std::as_const(cref).data(), nullptr);
std::swap(ref, cref);
ASSERT_EQ(ref.data(), nullptr);
ASSERT_NE(std::as_const(ref).data(), nullptr);
ASSERT_NE(cref.data(), nullptr);
ref = ref.as_ref();
cref = std::as_const(cref).as_ref();
ASSERT_EQ(ref.data(), nullptr);
ASSERT_NE(std::as_const(ref).data(), nullptr);
ASSERT_EQ(cref.data(), nullptr);
ASSERT_NE(std::as_const(cref).data(), nullptr);
ref = impl{};
cref = impl{};
ASSERT_NE(ref.data(), nullptr);
ASSERT_NE(cref.data(), nullptr);
}
TEST(PolyDeduced, SBOVsZeroedSBOSize) {
entt::poly<Deduced> sbo{impl{}};
const auto broken = sbo.data();
entt::poly<Deduced> other = std::move(sbo);
ASSERT_NE(broken, other.data());
entt::basic_poly<Deduced, 0u> dyn{impl{}};
const auto valid = dyn.data();
entt::basic_poly<Deduced, 0u> same = std::move(dyn);
ASSERT_EQ(valid, same.data());
// everything works as expected
same->incr();
ASSERT_EQ(same->get(), 1);
}
TEST(PolyDeduced, Alignment) {
static constexpr auto alignment = alignof(over_aligned);
auto test = [](auto *target, auto cb) {
const auto *data = target[0].data();
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(target[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(target[1u].data()) % alignment) == 0u);
std::swap(target[0], target[1]);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(target[0u].data()) % alignment) == 0u);
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(target[1u].data()) % alignment) == 0u);
cb(data, target[1].data());
};
entt::basic_poly<Deduced, alignment> nosbo[2] = {over_aligned{}, over_aligned{}};
test(nosbo, [](auto *pre, auto *post) { ASSERT_EQ(pre, post); });
entt::basic_poly<Deduced, alignment, alignment> sbo[2] = {over_aligned{}, over_aligned{}};
test(sbo, [](auto *pre, auto *post) { ASSERT_NE(pre, post); });
}