Squashed 'external/entt/entt/' content from commit fef92113
git-subtree-dir: external/entt/entt git-subtree-split: fef921132cae7588213d0f9bcd2fb9c8ffd8b7fc
This commit is contained in:
32
test/entt/common/basic_test_allocator.hpp
Normal file
32
test/entt/common/basic_test_allocator.hpp
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef ENTT_COMMON_BASIC_TEST_ALLOCATOR_HPP
|
||||
#define ENTT_COMMON_BASIC_TEST_ALLOCATOR_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace test {
|
||||
|
||||
template<typename Type, typename Pocs = std::true_type>
|
||||
struct basic_test_allocator: std::allocator<Type> {
|
||||
// basic pocca/pocma/pocs allocator
|
||||
|
||||
using base = std::allocator<Type>;
|
||||
using propagate_on_container_copy_assignment = std::true_type;
|
||||
using propagate_on_container_swap = Pocs;
|
||||
|
||||
using std::allocator<Type>::allocator;
|
||||
|
||||
basic_test_allocator &operator=(const basic_test_allocator &other) {
|
||||
// necessary to avoid call suppression
|
||||
base::operator=(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const basic_test_allocator &other) {
|
||||
return (this == &other);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
18
test/entt/common/config.h
Normal file
18
test/entt/common/config.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef ENTT_COMMON_CONFIG_H
|
||||
#define ENTT_COMMON_CONFIG_H
|
||||
|
||||
namespace test {
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define ENTT_DEBUG_TEST(Case, Test) TEST(Case, DISABLED_##Test)
|
||||
# define ENTT_DEBUG_TEST_F(Case, Test) TEST_F(Case, DISABLED_##Test)
|
||||
# define ENTT_DEBUG_TYPED_TEST(Case, Test) TYPED_TEST(Case, DISABLED_##Test)
|
||||
#else
|
||||
# define ENTT_DEBUG_TEST(Case, Test) TEST(Case, Test)
|
||||
# define ENTT_DEBUG_TEST_F(Case, Test) TEST_F(Case, Test)
|
||||
# define ENTT_DEBUG_TYPED_TEST(Case, Test) TYPED_TEST(Case, Test)
|
||||
#endif
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
69
test/entt/common/throwing_allocator.hpp
Normal file
69
test/entt/common/throwing_allocator.hpp
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef ENTT_COMMON_THROWING_ALLOCATOR_HPP
|
||||
#define ENTT_COMMON_THROWING_ALLOCATOR_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace test {
|
||||
|
||||
template<typename Type>
|
||||
class throwing_allocator: std::allocator<Type> {
|
||||
template<typename Other>
|
||||
friend class throwing_allocator;
|
||||
|
||||
using base = std::allocator<Type>;
|
||||
struct test_exception {};
|
||||
|
||||
public:
|
||||
using value_type = Type;
|
||||
using pointer = value_type *;
|
||||
using const_pointer = const value_type *;
|
||||
using void_pointer = void *;
|
||||
using const_void_pointer = const void *;
|
||||
using propagate_on_container_move_assignment = std::true_type;
|
||||
using propagate_on_container_swap = std::true_type;
|
||||
using exception_type = test_exception;
|
||||
|
||||
template<class Other>
|
||||
struct rebind {
|
||||
using other = throwing_allocator<Other>;
|
||||
};
|
||||
|
||||
throwing_allocator() = default;
|
||||
|
||||
template<class Other>
|
||||
throwing_allocator(const throwing_allocator<Other> &other)
|
||||
: base{other} {}
|
||||
|
||||
pointer allocate(std::size_t length) {
|
||||
if(trigger_on_allocate) {
|
||||
trigger_on_allocate = false;
|
||||
throw test_exception{};
|
||||
}
|
||||
|
||||
trigger_on_allocate = trigger_after_allocate;
|
||||
trigger_after_allocate = false;
|
||||
|
||||
return base::allocate(length);
|
||||
}
|
||||
|
||||
void deallocate(pointer mem, std::size_t length) {
|
||||
base::deallocate(mem, length);
|
||||
}
|
||||
|
||||
bool operator==(const throwing_allocator<Type> &) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const throwing_allocator<Type> &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
static inline bool trigger_on_allocate{};
|
||||
static inline bool trigger_after_allocate{};
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
46
test/entt/common/throwing_type.hpp
Normal file
46
test/entt/common/throwing_type.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef ENTT_COMMON_THROWING_TYPE_HPP
|
||||
#define ENTT_COMMON_THROWING_TYPE_HPP
|
||||
|
||||
namespace test {
|
||||
|
||||
class throwing_type {
|
||||
struct test_exception {};
|
||||
|
||||
public:
|
||||
using exception_type = test_exception;
|
||||
static constexpr auto moved_from_value = -1;
|
||||
|
||||
throwing_type(int value)
|
||||
: data{value} {}
|
||||
|
||||
throwing_type(const throwing_type &other)
|
||||
: data{other.data} {
|
||||
if(data == trigger_on_value) {
|
||||
data = moved_from_value;
|
||||
throw exception_type{};
|
||||
}
|
||||
}
|
||||
|
||||
throwing_type &operator=(const throwing_type &other) {
|
||||
if(other.data == trigger_on_value) {
|
||||
data = moved_from_value;
|
||||
throw exception_type{};
|
||||
}
|
||||
|
||||
data = other.data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator int() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline int trigger_on_value{};
|
||||
|
||||
private:
|
||||
int data{};
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
64
test/entt/common/tracked_memory_resource.hpp
Normal file
64
test/entt/common/tracked_memory_resource.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef ENTT_COMMON_TRACKED_MEMORY_RESOURCE_HPP
|
||||
#define ENTT_COMMON_TRACKED_MEMORY_RESOURCE_HPP
|
||||
|
||||
#ifdef ENTT_HAS_HEADER_VERSION
|
||||
# include <version>
|
||||
#
|
||||
# if defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L
|
||||
# define ENTT_HAS_TRACKED_MEMORY_RESOURCE
|
||||
#
|
||||
# include <cstddef>
|
||||
# include <memory_resource>
|
||||
# include <string>
|
||||
|
||||
namespace test {
|
||||
|
||||
class tracked_memory_resource: public std::pmr::memory_resource {
|
||||
void *do_allocate(std::size_t bytes, std::size_t alignment) override {
|
||||
++alloc_counter;
|
||||
return std::pmr::get_default_resource()->allocate(bytes, alignment);
|
||||
}
|
||||
|
||||
void do_deallocate(void *value, std::size_t bytes, std::size_t alignment) override {
|
||||
++dealloc_counter;
|
||||
std::pmr::get_default_resource()->deallocate(value, bytes, alignment);
|
||||
}
|
||||
|
||||
bool do_is_equal(const std::pmr::memory_resource &other) const noexcept override {
|
||||
return (this == &other);
|
||||
}
|
||||
|
||||
public:
|
||||
using string_type = std::pmr::string;
|
||||
using size_type = std::size_t;
|
||||
|
||||
static constexpr const char *default_value = "a string long enough to force an allocation (hopefully)";
|
||||
|
||||
tracked_memory_resource()
|
||||
: alloc_counter{},
|
||||
dealloc_counter{} {}
|
||||
|
||||
size_type do_allocate_counter() const noexcept {
|
||||
return alloc_counter;
|
||||
}
|
||||
|
||||
size_type do_deallocate_counter() const noexcept {
|
||||
return dealloc_counter;
|
||||
}
|
||||
|
||||
void reset() noexcept {
|
||||
alloc_counter = 0u;
|
||||
dealloc_counter = 0u;
|
||||
}
|
||||
|
||||
private:
|
||||
size_type alloc_counter;
|
||||
size_type dealloc_counter;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
8
test/entt/config/version.cpp
Normal file
8
test/entt/config/version.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
#include <regex>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/config/version.h>
|
||||
|
||||
TEST(Version, All) {
|
||||
ASSERT_STREQ(ENTT_VERSION, ENTT_XSTR(ENTT_VERSION_MAJOR) "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH));
|
||||
ASSERT_TRUE(std::regex_match(ENTT_VERSION, std::regex{"^[0-9]+\\.[0-9]+\\.[0-9]+$"}));
|
||||
}
|
1257
test/entt/container/dense_map.cpp
Normal file
1257
test/entt/container/dense_map.cpp
Normal file
File diff suppressed because it is too large
Load Diff
946
test/entt/container/dense_set.cpp
Normal file
946
test/entt/container/dense_set.cpp
Normal file
@ -0,0 +1,946 @@
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/container/dense_set.hpp>
|
||||
#include <entt/core/memory.hpp>
|
||||
#include <entt/core/utility.hpp>
|
||||
#include "../common/throwing_allocator.hpp"
|
||||
#include "../common/tracked_memory_resource.hpp"
|
||||
|
||||
struct transparent_equal_to {
|
||||
using is_transparent = void;
|
||||
|
||||
template<typename Type, typename Other>
|
||||
constexpr std::enable_if_t<std::is_convertible_v<Other, Type>, bool>
|
||||
operator()(const Type &lhs, const Other &rhs) const {
|
||||
return lhs == static_cast<Type>(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(DenseSet, Functionalities) {
|
||||
entt::dense_set<int, entt::identity, transparent_equal_to> set;
|
||||
const auto &cset = set;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE([[maybe_unused]] auto alloc = set.get_allocator());
|
||||
|
||||
ASSERT_TRUE(set.empty());
|
||||
ASSERT_EQ(set.size(), 0u);
|
||||
ASSERT_EQ(set.load_factor(), 0.f);
|
||||
ASSERT_EQ(set.max_load_factor(), .875f);
|
||||
ASSERT_EQ(set.max_size(), (std::vector<std::pair<std::size_t, int>>{}.max_size()));
|
||||
|
||||
set.max_load_factor(.9f);
|
||||
|
||||
ASSERT_EQ(set.max_load_factor(), .9f);
|
||||
|
||||
ASSERT_EQ(set.begin(), set.end());
|
||||
ASSERT_EQ(cset.begin(), cset.end());
|
||||
ASSERT_EQ(set.cbegin(), set.cend());
|
||||
|
||||
ASSERT_NE(set.max_bucket_count(), 0u);
|
||||
ASSERT_EQ(set.bucket_count(), 8u);
|
||||
ASSERT_EQ(set.bucket_size(3u), 0u);
|
||||
|
||||
ASSERT_EQ(set.bucket(0), 0u);
|
||||
ASSERT_EQ(set.bucket(3), 3u);
|
||||
ASSERT_EQ(set.bucket(8), 0u);
|
||||
ASSERT_EQ(set.bucket(10), 2u);
|
||||
|
||||
ASSERT_EQ(set.begin(1u), set.end(1u));
|
||||
ASSERT_EQ(cset.begin(1u), cset.end(1u));
|
||||
ASSERT_EQ(set.cbegin(1u), set.cend(1u));
|
||||
|
||||
ASSERT_FALSE(set.contains(42));
|
||||
ASSERT_FALSE(set.contains(4.2));
|
||||
|
||||
ASSERT_EQ(set.find(42), set.end());
|
||||
ASSERT_EQ(set.find(4.2), set.end());
|
||||
ASSERT_EQ(cset.find(42), set.cend());
|
||||
ASSERT_EQ(cset.find(4.2), set.cend());
|
||||
|
||||
ASSERT_EQ(set.hash_function()(42), 42);
|
||||
ASSERT_TRUE(set.key_eq()(42, 42));
|
||||
|
||||
set.emplace(0);
|
||||
|
||||
ASSERT_EQ(set.count(0), 1u);
|
||||
ASSERT_EQ(set.count(4.2), 0u);
|
||||
ASSERT_EQ(cset.count(0.0), 1u);
|
||||
ASSERT_EQ(cset.count(42), 0u);
|
||||
|
||||
ASSERT_FALSE(set.empty());
|
||||
ASSERT_EQ(set.size(), 1u);
|
||||
|
||||
ASSERT_NE(set.begin(), set.end());
|
||||
ASSERT_NE(cset.begin(), cset.end());
|
||||
ASSERT_NE(set.cbegin(), set.cend());
|
||||
|
||||
ASSERT_TRUE(set.contains(0));
|
||||
ASSERT_EQ(set.bucket(0), 0u);
|
||||
|
||||
set.clear();
|
||||
|
||||
ASSERT_TRUE(set.empty());
|
||||
ASSERT_EQ(set.size(), 0u);
|
||||
|
||||
ASSERT_EQ(set.begin(), set.end());
|
||||
ASSERT_EQ(cset.begin(), cset.end());
|
||||
ASSERT_EQ(set.cbegin(), set.cend());
|
||||
|
||||
ASSERT_FALSE(set.contains(0));
|
||||
}
|
||||
|
||||
TEST(DenseSet, Constructors) {
|
||||
static constexpr std::size_t minimum_bucket_count = 8u;
|
||||
entt::dense_set<int> set;
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
|
||||
|
||||
set = entt::dense_set<int>{std::allocator<int>{}};
|
||||
set = entt::dense_set<int>{2u * minimum_bucket_count, std::allocator<float>{}};
|
||||
set = entt::dense_set<int>{4u * minimum_bucket_count, std::hash<int>(), std::allocator<double>{}};
|
||||
|
||||
set.emplace(3);
|
||||
|
||||
entt::dense_set<int> temp{set, set.get_allocator()};
|
||||
entt::dense_set<int> other{std::move(temp), set.get_allocator()};
|
||||
|
||||
ASSERT_EQ(set.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
ASSERT_EQ(set.bucket_count(), 4u * minimum_bucket_count);
|
||||
ASSERT_EQ(other.bucket_count(), 4u * minimum_bucket_count);
|
||||
}
|
||||
|
||||
TEST(DenseSet, Copy) {
|
||||
entt::dense_set<std::size_t, entt::identity> set;
|
||||
set.max_load_factor(set.max_load_factor() - .05f);
|
||||
set.emplace(3u);
|
||||
|
||||
entt::dense_set<std::size_t, entt::identity> other{set};
|
||||
|
||||
ASSERT_TRUE(set.contains(3u));
|
||||
ASSERT_TRUE(other.contains(3u));
|
||||
ASSERT_EQ(set.max_load_factor(), other.max_load_factor());
|
||||
|
||||
set.emplace(1u);
|
||||
set.emplace(11u);
|
||||
other.emplace(0u);
|
||||
other = set;
|
||||
|
||||
ASSERT_TRUE(other.contains(3u));
|
||||
ASSERT_TRUE(other.contains(1u));
|
||||
ASSERT_TRUE(other.contains(11u));
|
||||
ASSERT_FALSE(other.contains(0u));
|
||||
|
||||
ASSERT_EQ(other.bucket(3u), set.bucket(11u));
|
||||
ASSERT_EQ(other.bucket(3u), other.bucket(11u));
|
||||
ASSERT_EQ(*other.begin(3u), *set.begin(3u));
|
||||
ASSERT_EQ(*other.begin(3u), 11u);
|
||||
ASSERT_EQ((*++other.begin(3u)), 3u);
|
||||
}
|
||||
|
||||
TEST(DenseSet, Move) {
|
||||
entt::dense_set<std::size_t, entt::identity> set;
|
||||
set.max_load_factor(set.max_load_factor() - .05f);
|
||||
set.emplace(3u);
|
||||
|
||||
entt::dense_set<std::size_t, entt::identity> other{std::move(set)};
|
||||
|
||||
ASSERT_EQ(set.size(), 0u);
|
||||
ASSERT_TRUE(other.contains(3u));
|
||||
ASSERT_EQ(set.max_load_factor(), other.max_load_factor());
|
||||
|
||||
set = other;
|
||||
set.emplace(1u);
|
||||
set.emplace(11u);
|
||||
other.emplace(0u);
|
||||
other = std::move(set);
|
||||
|
||||
ASSERT_EQ(set.size(), 0u);
|
||||
ASSERT_TRUE(other.contains(3u));
|
||||
ASSERT_TRUE(other.contains(1u));
|
||||
ASSERT_TRUE(other.contains(11u));
|
||||
ASSERT_FALSE(other.contains(0u));
|
||||
|
||||
ASSERT_EQ(other.bucket(3u), other.bucket(11u));
|
||||
ASSERT_EQ(*other.begin(3u), 11u);
|
||||
ASSERT_EQ(*++other.begin(3u), 3u);
|
||||
}
|
||||
|
||||
TEST(DenseSet, Iterator) {
|
||||
using iterator = typename entt::dense_set<int>::iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, int>);
|
||||
static_assert(std::is_same_v<iterator::pointer, const int *>);
|
||||
static_assert(std::is_same_v<iterator::reference, const int &>);
|
||||
|
||||
entt::dense_set<int> set;
|
||||
set.emplace(3);
|
||||
|
||||
iterator end{set.begin()};
|
||||
iterator begin{};
|
||||
begin = set.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, set.begin());
|
||||
ASSERT_EQ(end, set.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(begin++, set.begin());
|
||||
ASSERT_EQ(begin--, set.end());
|
||||
|
||||
ASSERT_EQ(begin + 1, set.end());
|
||||
ASSERT_EQ(end - 1, set.begin());
|
||||
|
||||
ASSERT_EQ(++begin, set.end());
|
||||
ASSERT_EQ(--begin, set.begin());
|
||||
|
||||
ASSERT_EQ(begin += 1, set.end());
|
||||
ASSERT_EQ(begin -= 1, set.begin());
|
||||
|
||||
ASSERT_EQ(begin + (end - begin), set.end());
|
||||
ASSERT_EQ(begin - (begin - end), set.end());
|
||||
|
||||
ASSERT_EQ(end - (end - begin), set.begin());
|
||||
ASSERT_EQ(end + (begin - end), set.begin());
|
||||
|
||||
ASSERT_EQ(begin[0u], *set.begin().operator->());
|
||||
ASSERT_EQ(begin[0u], *set.begin());
|
||||
|
||||
ASSERT_LT(begin, end);
|
||||
ASSERT_LE(begin, set.begin());
|
||||
|
||||
ASSERT_GT(end, begin);
|
||||
ASSERT_GE(end, set.end());
|
||||
|
||||
set.emplace(42);
|
||||
begin = set.begin();
|
||||
|
||||
ASSERT_EQ(begin[0u], 3);
|
||||
ASSERT_EQ(begin[1u], 42);
|
||||
}
|
||||
|
||||
TEST(DenseSet, ConstIterator) {
|
||||
using iterator = typename entt::dense_set<int>::const_iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, int>);
|
||||
static_assert(std::is_same_v<iterator::pointer, const int *>);
|
||||
static_assert(std::is_same_v<iterator::reference, const int &>);
|
||||
|
||||
entt::dense_set<int> set;
|
||||
set.emplace(3);
|
||||
|
||||
iterator cend{set.cbegin()};
|
||||
iterator cbegin{};
|
||||
cbegin = set.cend();
|
||||
std::swap(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin, set.cbegin());
|
||||
ASSERT_EQ(cend, set.cend());
|
||||
ASSERT_NE(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin++, set.cbegin());
|
||||
ASSERT_EQ(cbegin--, set.cend());
|
||||
|
||||
ASSERT_EQ(cbegin + 1, set.cend());
|
||||
ASSERT_EQ(cend - 1, set.cbegin());
|
||||
|
||||
ASSERT_EQ(++cbegin, set.cend());
|
||||
ASSERT_EQ(--cbegin, set.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin += 1, set.cend());
|
||||
ASSERT_EQ(cbegin -= 1, set.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin + (cend - cbegin), set.cend());
|
||||
ASSERT_EQ(cbegin - (cbegin - cend), set.cend());
|
||||
|
||||
ASSERT_EQ(cend - (cend - cbegin), set.cbegin());
|
||||
ASSERT_EQ(cend + (cbegin - cend), set.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin[0u], *set.cbegin().operator->());
|
||||
ASSERT_EQ(cbegin[0u], *set.cbegin());
|
||||
|
||||
ASSERT_LT(cbegin, cend);
|
||||
ASSERT_LE(cbegin, set.cbegin());
|
||||
|
||||
ASSERT_GT(cend, cbegin);
|
||||
ASSERT_GE(cend, set.cend());
|
||||
|
||||
set.emplace(42);
|
||||
cbegin = set.cbegin();
|
||||
|
||||
ASSERT_EQ(cbegin[0u], 3);
|
||||
ASSERT_EQ(cbegin[1u], 42);
|
||||
}
|
||||
|
||||
TEST(DenseSet, IteratorConversion) {
|
||||
entt::dense_set<int> set;
|
||||
set.emplace(3);
|
||||
|
||||
typename entt::dense_set<int, int>::iterator it = set.begin();
|
||||
typename entt::dense_set<int, int>::const_iterator cit = it;
|
||||
|
||||
static_assert(std::is_same_v<decltype(*it), const int &>);
|
||||
static_assert(std::is_same_v<decltype(*cit), const int &>);
|
||||
|
||||
ASSERT_EQ(*it, 3);
|
||||
ASSERT_EQ(*it.operator->(), 3);
|
||||
ASSERT_EQ(it.operator->(), cit.operator->());
|
||||
ASSERT_EQ(*it, *cit);
|
||||
|
||||
ASSERT_EQ(it - cit, 0);
|
||||
ASSERT_EQ(cit - it, 0);
|
||||
ASSERT_LE(it, cit);
|
||||
ASSERT_LE(cit, it);
|
||||
ASSERT_GE(it, cit);
|
||||
ASSERT_GE(cit, it);
|
||||
ASSERT_EQ(it, cit);
|
||||
ASSERT_NE(++cit, it);
|
||||
}
|
||||
|
||||
TEST(DenseSet, Insert) {
|
||||
entt::dense_set<int> set;
|
||||
typename entt::dense_set<int>::iterator it;
|
||||
bool result;
|
||||
|
||||
ASSERT_TRUE(set.empty());
|
||||
ASSERT_EQ(set.size(), 0u);
|
||||
ASSERT_EQ(set.find(0), set.end());
|
||||
ASSERT_FALSE(set.contains(0));
|
||||
|
||||
int value{1};
|
||||
std::tie(it, result) = set.insert(std::as_const(value));
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(set.size(), 1u);
|
||||
ASSERT_EQ(it, --set.end());
|
||||
ASSERT_TRUE(set.contains(1));
|
||||
ASSERT_NE(set.find(1), set.end());
|
||||
ASSERT_EQ(*it, 1);
|
||||
|
||||
std::tie(it, result) = set.insert(value);
|
||||
|
||||
ASSERT_FALSE(result);
|
||||
ASSERT_EQ(set.size(), 1u);
|
||||
ASSERT_EQ(it, --set.end());
|
||||
ASSERT_EQ(*it, 1);
|
||||
|
||||
std::tie(it, result) = set.insert(3);
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(set.size(), 2u);
|
||||
ASSERT_EQ(it, --set.end());
|
||||
ASSERT_TRUE(set.contains(3));
|
||||
ASSERT_NE(set.find(3), set.end());
|
||||
ASSERT_EQ(*it, 3);
|
||||
|
||||
std::tie(it, result) = set.insert(3);
|
||||
|
||||
ASSERT_FALSE(result);
|
||||
ASSERT_EQ(set.size(), 2u);
|
||||
ASSERT_EQ(it, --set.end());
|
||||
ASSERT_EQ(*it, 3);
|
||||
|
||||
int range[2u]{7, 9};
|
||||
set.insert(std::begin(range), std::end(range));
|
||||
|
||||
ASSERT_EQ(set.size(), 4u);
|
||||
ASSERT_TRUE(set.contains(7));
|
||||
ASSERT_NE(set.find(9), set.end());
|
||||
}
|
||||
|
||||
TEST(DenseSet, InsertRehash) {
|
||||
static constexpr std::size_t minimum_bucket_count = 8u;
|
||||
entt::dense_set<std::size_t, entt::identity> set;
|
||||
|
||||
ASSERT_EQ(set.size(), 0u);
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
|
||||
|
||||
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
|
||||
ASSERT_TRUE(set.insert(next).second);
|
||||
}
|
||||
|
||||
ASSERT_EQ(set.size(), minimum_bucket_count);
|
||||
ASSERT_GT(set.bucket_count(), minimum_bucket_count);
|
||||
ASSERT_TRUE(set.contains(minimum_bucket_count / 2u));
|
||||
ASSERT_EQ(set.bucket(minimum_bucket_count / 2u), minimum_bucket_count / 2u);
|
||||
ASSERT_FALSE(set.contains(minimum_bucket_count));
|
||||
|
||||
ASSERT_TRUE(set.insert(minimum_bucket_count).second);
|
||||
|
||||
ASSERT_EQ(set.size(), minimum_bucket_count + 1u);
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count * 2u);
|
||||
ASSERT_TRUE(set.contains(minimum_bucket_count / 2u));
|
||||
ASSERT_EQ(set.bucket(minimum_bucket_count / 2u), minimum_bucket_count / 2u);
|
||||
ASSERT_TRUE(set.contains(minimum_bucket_count));
|
||||
|
||||
for(std::size_t next{}; next <= minimum_bucket_count; ++next) {
|
||||
ASSERT_TRUE(set.contains(next));
|
||||
ASSERT_EQ(set.bucket(next), next);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DenseSet, InsertSameBucket) {
|
||||
static constexpr std::size_t minimum_bucket_count = 8u;
|
||||
entt::dense_set<std::size_t, entt::identity> set;
|
||||
|
||||
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
|
||||
ASSERT_EQ(set.cbegin(next), set.cend(next));
|
||||
}
|
||||
|
||||
ASSERT_TRUE(set.insert(1u).second);
|
||||
ASSERT_TRUE(set.insert(9u).second);
|
||||
|
||||
ASSERT_EQ(set.size(), 2u);
|
||||
ASSERT_TRUE(set.contains(1u));
|
||||
ASSERT_NE(set.find(9u), set.end());
|
||||
ASSERT_EQ(set.bucket(1u), 1u);
|
||||
ASSERT_EQ(set.bucket(9u), 1u);
|
||||
ASSERT_EQ(set.bucket_size(1u), 2u);
|
||||
ASSERT_EQ(set.cbegin(6u), set.cend(6u));
|
||||
}
|
||||
|
||||
TEST(DenseSet, Emplace) {
|
||||
entt::dense_set<int> set;
|
||||
typename entt::dense_set<int>::iterator it;
|
||||
bool result;
|
||||
|
||||
ASSERT_TRUE(set.empty());
|
||||
ASSERT_EQ(set.size(), 0u);
|
||||
ASSERT_EQ(set.find(0), set.end());
|
||||
ASSERT_FALSE(set.contains(0));
|
||||
|
||||
std::tie(it, result) = set.emplace();
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(set.size(), 1u);
|
||||
ASSERT_EQ(it, --set.end());
|
||||
ASSERT_TRUE(set.contains(0));
|
||||
ASSERT_NE(set.find(0), set.end());
|
||||
ASSERT_EQ(*it, 0);
|
||||
|
||||
std::tie(it, result) = set.emplace();
|
||||
|
||||
ASSERT_FALSE(result);
|
||||
ASSERT_EQ(set.size(), 1u);
|
||||
ASSERT_EQ(it, --set.end());
|
||||
ASSERT_EQ(*it, 0);
|
||||
|
||||
std::tie(it, result) = set.emplace(1);
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(set.size(), 2u);
|
||||
ASSERT_EQ(it, --set.end());
|
||||
ASSERT_TRUE(set.contains(1));
|
||||
ASSERT_NE(set.find(1), set.end());
|
||||
ASSERT_EQ(*it, 1);
|
||||
|
||||
std::tie(it, result) = set.emplace(1);
|
||||
|
||||
ASSERT_FALSE(result);
|
||||
ASSERT_EQ(set.size(), 2u);
|
||||
ASSERT_EQ(it, --set.end());
|
||||
ASSERT_EQ(*it, 1);
|
||||
}
|
||||
|
||||
TEST(DenseSet, EmplaceRehash) {
|
||||
static constexpr std::size_t minimum_bucket_count = 8u;
|
||||
entt::dense_set<std::size_t, entt::identity> set;
|
||||
|
||||
ASSERT_EQ(set.size(), 0u);
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
|
||||
|
||||
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
|
||||
ASSERT_TRUE(set.emplace(next).second);
|
||||
ASSERT_LE(set.load_factor(), set.max_load_factor());
|
||||
}
|
||||
|
||||
ASSERT_EQ(set.size(), minimum_bucket_count);
|
||||
ASSERT_GT(set.bucket_count(), minimum_bucket_count);
|
||||
ASSERT_TRUE(set.contains(minimum_bucket_count / 2u));
|
||||
ASSERT_EQ(set.bucket(minimum_bucket_count / 2u), minimum_bucket_count / 2u);
|
||||
ASSERT_FALSE(set.contains(minimum_bucket_count));
|
||||
|
||||
ASSERT_TRUE(set.emplace(minimum_bucket_count).second);
|
||||
|
||||
ASSERT_EQ(set.size(), minimum_bucket_count + 1u);
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count * 2u);
|
||||
ASSERT_TRUE(set.contains(minimum_bucket_count / 2u));
|
||||
ASSERT_EQ(set.bucket(minimum_bucket_count / 2u), minimum_bucket_count / 2u);
|
||||
ASSERT_TRUE(set.contains(minimum_bucket_count));
|
||||
|
||||
for(std::size_t next{}; next <= minimum_bucket_count; ++next) {
|
||||
ASSERT_TRUE(set.contains(next));
|
||||
ASSERT_EQ(set.bucket(next), next);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DenseSet, EmplaceSameBucket) {
|
||||
static constexpr std::size_t minimum_bucket_count = 8u;
|
||||
entt::dense_set<std::size_t, entt::identity> set;
|
||||
|
||||
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
|
||||
ASSERT_EQ(set.cbegin(next), set.cend(next));
|
||||
}
|
||||
|
||||
ASSERT_TRUE(set.emplace(1u).second);
|
||||
ASSERT_TRUE(set.emplace(9u).second);
|
||||
|
||||
ASSERT_EQ(set.size(), 2u);
|
||||
ASSERT_TRUE(set.contains(1u));
|
||||
ASSERT_NE(set.find(9u), set.end());
|
||||
ASSERT_EQ(set.bucket(1u), 1u);
|
||||
ASSERT_EQ(set.bucket(9u), 1u);
|
||||
ASSERT_EQ(set.bucket_size(1u), 2u);
|
||||
ASSERT_EQ(set.cbegin(6u), set.cend(6u));
|
||||
}
|
||||
|
||||
TEST(DenseSet, Erase) {
|
||||
static constexpr std::size_t minimum_bucket_count = 8u;
|
||||
entt::dense_set<std::size_t, entt::identity> set;
|
||||
|
||||
for(std::size_t next{}, last = minimum_bucket_count + 1u; next < last; ++next) {
|
||||
set.emplace(next);
|
||||
}
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 2 * minimum_bucket_count);
|
||||
ASSERT_EQ(set.size(), minimum_bucket_count + 1u);
|
||||
|
||||
for(std::size_t next{}, last = minimum_bucket_count + 1u; next < last; ++next) {
|
||||
ASSERT_TRUE(set.contains(next));
|
||||
}
|
||||
|
||||
auto it = set.erase(++set.begin());
|
||||
it = set.erase(it, it + 1);
|
||||
|
||||
ASSERT_EQ(*--set.end(), 6u);
|
||||
ASSERT_EQ(set.erase(6u), 1u);
|
||||
ASSERT_EQ(set.erase(6u), 0u);
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 2 * minimum_bucket_count);
|
||||
ASSERT_EQ(set.size(), minimum_bucket_count + 1u - 3u);
|
||||
|
||||
ASSERT_EQ(it, ++set.begin());
|
||||
ASSERT_EQ(*it, 7u);
|
||||
ASSERT_EQ(*--set.end(), 5u);
|
||||
|
||||
for(std::size_t next{}, last = minimum_bucket_count + 1u; next < last; ++next) {
|
||||
if(next == 1u || next == 8u || next == 6u) {
|
||||
ASSERT_FALSE(set.contains(next));
|
||||
ASSERT_EQ(set.bucket_size(next), 0u);
|
||||
} else {
|
||||
ASSERT_TRUE(set.contains(next));
|
||||
ASSERT_EQ(set.bucket(next), next);
|
||||
ASSERT_EQ(set.bucket_size(next), 1u);
|
||||
}
|
||||
}
|
||||
|
||||
set.erase(set.begin(), set.end());
|
||||
|
||||
for(std::size_t next{}, last = minimum_bucket_count + 1u; next < last; ++next) {
|
||||
ASSERT_FALSE(set.contains(next));
|
||||
}
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 2 * minimum_bucket_count);
|
||||
ASSERT_EQ(set.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(DenseSet, EraseWithMovableKeyValue) {
|
||||
static constexpr std::size_t minimum_bucket_count = 8u;
|
||||
entt::dense_set<std::string> set;
|
||||
|
||||
set.emplace("0");
|
||||
set.emplace("1");
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
|
||||
ASSERT_EQ(set.size(), 2u);
|
||||
|
||||
auto it = set.erase(set.find("0"));
|
||||
|
||||
ASSERT_EQ(*it, "1");
|
||||
ASSERT_EQ(set.size(), 1u);
|
||||
ASSERT_FALSE(set.contains("0"));
|
||||
}
|
||||
|
||||
TEST(DenseSet, EraseFromBucket) {
|
||||
static constexpr std::size_t minimum_bucket_count = 8u;
|
||||
entt::dense_set<std::size_t, entt::identity> set;
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
|
||||
ASSERT_EQ(set.size(), 0u);
|
||||
|
||||
for(std::size_t next{}; next < 4u; ++next) {
|
||||
ASSERT_TRUE(set.emplace(2u * minimum_bucket_count * next).second);
|
||||
ASSERT_TRUE(set.emplace(2u * minimum_bucket_count * next + 2u).second);
|
||||
ASSERT_TRUE(set.emplace(2u * minimum_bucket_count * (next + 1u) - 1u).second);
|
||||
}
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 2u * minimum_bucket_count);
|
||||
ASSERT_EQ(set.size(), 12u);
|
||||
|
||||
ASSERT_EQ(set.bucket_size(0u), 4u);
|
||||
ASSERT_EQ(set.bucket_size(2u), 4u);
|
||||
ASSERT_EQ(set.bucket_size(15u), 4u);
|
||||
|
||||
set.erase(set.end() - 3, set.end());
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 2u * minimum_bucket_count);
|
||||
ASSERT_EQ(set.size(), 9u);
|
||||
|
||||
ASSERT_EQ(set.bucket_size(0u), 3u);
|
||||
ASSERT_EQ(set.bucket_size(2u), 3u);
|
||||
ASSERT_EQ(set.bucket_size(15u), 3u);
|
||||
|
||||
for(std::size_t next{}; next < 3u; ++next) {
|
||||
ASSERT_TRUE(set.contains(2u * minimum_bucket_count * next));
|
||||
ASSERT_EQ(set.bucket(2u * minimum_bucket_count * next), 0u);
|
||||
|
||||
ASSERT_TRUE(set.contains(2u * minimum_bucket_count * next + 2u));
|
||||
ASSERT_EQ(set.bucket(2u * minimum_bucket_count * next + 2u), 2u);
|
||||
|
||||
ASSERT_TRUE(set.contains(2u * minimum_bucket_count * (next + 1u) - 1u));
|
||||
ASSERT_EQ(set.bucket(2u * minimum_bucket_count * (next + 1u) - 1u), 15u);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(set.contains(2u * minimum_bucket_count * 3u));
|
||||
ASSERT_FALSE(set.contains(2u * minimum_bucket_count * 3u + 2u));
|
||||
ASSERT_FALSE(set.contains(2u * minimum_bucket_count * (3u + 1u) - 1u));
|
||||
|
||||
set.erase(*++set.begin(0u));
|
||||
set.erase(*++set.begin(2u));
|
||||
set.erase(*++set.begin(15u));
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 2u * minimum_bucket_count);
|
||||
ASSERT_EQ(set.size(), 6u);
|
||||
|
||||
ASSERT_EQ(set.bucket_size(0u), 2u);
|
||||
ASSERT_EQ(set.bucket_size(2u), 2u);
|
||||
ASSERT_EQ(set.bucket_size(15u), 2u);
|
||||
|
||||
ASSERT_FALSE(set.contains(2u * minimum_bucket_count * 1u));
|
||||
ASSERT_FALSE(set.contains(2u * minimum_bucket_count * 1u + 2u));
|
||||
ASSERT_FALSE(set.contains(2u * minimum_bucket_count * (1u + 1u) - 1u));
|
||||
|
||||
while(set.begin(15) != set.end(15u)) {
|
||||
set.erase(*set.begin(15));
|
||||
}
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 2u * minimum_bucket_count);
|
||||
ASSERT_EQ(set.size(), 4u);
|
||||
|
||||
ASSERT_EQ(set.bucket_size(0u), 2u);
|
||||
ASSERT_EQ(set.bucket_size(2u), 2u);
|
||||
ASSERT_EQ(set.bucket_size(15u), 0u);
|
||||
|
||||
ASSERT_TRUE(set.contains(0u * minimum_bucket_count));
|
||||
ASSERT_TRUE(set.contains(0u * minimum_bucket_count + 2u));
|
||||
ASSERT_TRUE(set.contains(4u * minimum_bucket_count));
|
||||
ASSERT_TRUE(set.contains(4u * minimum_bucket_count + 2u));
|
||||
|
||||
set.erase(4u * minimum_bucket_count + 2u);
|
||||
set.erase(0u * minimum_bucket_count);
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 2u * minimum_bucket_count);
|
||||
ASSERT_EQ(set.size(), 2u);
|
||||
|
||||
ASSERT_EQ(set.bucket_size(0u), 1u);
|
||||
ASSERT_EQ(set.bucket_size(2u), 1u);
|
||||
ASSERT_EQ(set.bucket_size(15u), 0u);
|
||||
|
||||
ASSERT_FALSE(set.contains(0u * minimum_bucket_count));
|
||||
ASSERT_TRUE(set.contains(0u * minimum_bucket_count + 2u));
|
||||
ASSERT_TRUE(set.contains(4u * minimum_bucket_count));
|
||||
ASSERT_FALSE(set.contains(4u * minimum_bucket_count + 2u));
|
||||
}
|
||||
|
||||
TEST(DenseSet, Swap) {
|
||||
entt::dense_set<int> set;
|
||||
entt::dense_set<int> other;
|
||||
|
||||
set.emplace(0);
|
||||
|
||||
ASSERT_FALSE(set.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_TRUE(set.contains(0));
|
||||
ASSERT_FALSE(other.contains(0));
|
||||
|
||||
set.swap(other);
|
||||
|
||||
ASSERT_TRUE(set.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_FALSE(set.contains(0));
|
||||
ASSERT_TRUE(other.contains(0));
|
||||
}
|
||||
|
||||
TEST(DenseSet, EqualRange) {
|
||||
entt::dense_set<int, entt::identity, transparent_equal_to> set;
|
||||
const auto &cset = set;
|
||||
|
||||
set.emplace(42);
|
||||
|
||||
ASSERT_EQ(set.equal_range(0).first, set.end());
|
||||
ASSERT_EQ(set.equal_range(0).second, set.end());
|
||||
|
||||
ASSERT_EQ(cset.equal_range(0).first, cset.cend());
|
||||
ASSERT_EQ(cset.equal_range(0).second, cset.cend());
|
||||
|
||||
ASSERT_EQ(set.equal_range(0.0).first, set.end());
|
||||
ASSERT_EQ(set.equal_range(0.0).second, set.end());
|
||||
|
||||
ASSERT_EQ(cset.equal_range(0.0).first, cset.cend());
|
||||
ASSERT_EQ(cset.equal_range(0.0).second, cset.cend());
|
||||
|
||||
ASSERT_NE(set.equal_range(42).first, set.end());
|
||||
ASSERT_EQ(*set.equal_range(42).first, 42);
|
||||
ASSERT_EQ(set.equal_range(42).second, set.end());
|
||||
|
||||
ASSERT_NE(cset.equal_range(42).first, cset.cend());
|
||||
ASSERT_EQ(*cset.equal_range(42).first, 42);
|
||||
ASSERT_EQ(cset.equal_range(42).second, cset.cend());
|
||||
|
||||
ASSERT_NE(set.equal_range(42.0).first, set.end());
|
||||
ASSERT_EQ(*set.equal_range(42.0).first, 42);
|
||||
ASSERT_EQ(set.equal_range(42.0).second, set.end());
|
||||
|
||||
ASSERT_NE(cset.equal_range(42.0).first, cset.cend());
|
||||
ASSERT_EQ(*cset.equal_range(42.0).first, 42);
|
||||
ASSERT_EQ(cset.equal_range(42.0).second, cset.cend());
|
||||
}
|
||||
|
||||
TEST(DenseSet, LocalIterator) {
|
||||
using iterator = typename entt::dense_set<std::size_t, entt::identity>::local_iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, std::size_t>);
|
||||
static_assert(std::is_same_v<iterator::pointer, const std::size_t *>);
|
||||
static_assert(std::is_same_v<iterator::reference, const std::size_t &>);
|
||||
|
||||
static constexpr std::size_t minimum_bucket_count = 8u;
|
||||
entt::dense_set<std::size_t, entt::identity> set;
|
||||
set.emplace(3u);
|
||||
set.emplace(3u + minimum_bucket_count);
|
||||
|
||||
iterator end{set.begin(3u)};
|
||||
iterator begin{};
|
||||
begin = set.end(3u);
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, set.begin(3u));
|
||||
ASSERT_EQ(end, set.end(3u));
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(*begin.operator->(), 3u + minimum_bucket_count);
|
||||
ASSERT_EQ(*begin, 3u + minimum_bucket_count);
|
||||
|
||||
ASSERT_EQ(begin++, set.begin(3u));
|
||||
ASSERT_EQ(++begin, set.end(3u));
|
||||
}
|
||||
|
||||
TEST(DenseSet, ConstLocalIterator) {
|
||||
using iterator = typename entt::dense_set<std::size_t, entt::identity>::const_local_iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, std::size_t>);
|
||||
static_assert(std::is_same_v<iterator::pointer, const std::size_t *>);
|
||||
static_assert(std::is_same_v<iterator::reference, const std::size_t &>);
|
||||
|
||||
static constexpr std::size_t minimum_bucket_count = 8u;
|
||||
entt::dense_set<std::size_t, entt::identity> set;
|
||||
set.emplace(3u);
|
||||
set.emplace(3u + minimum_bucket_count);
|
||||
|
||||
iterator cend{set.begin(3u)};
|
||||
iterator cbegin{};
|
||||
cbegin = set.end(3u);
|
||||
std::swap(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin, set.begin(3u));
|
||||
ASSERT_EQ(cend, set.end(3u));
|
||||
ASSERT_NE(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(*cbegin.operator->(), 3u + minimum_bucket_count);
|
||||
ASSERT_EQ(*cbegin, 3u + minimum_bucket_count);
|
||||
|
||||
ASSERT_EQ(cbegin++, set.begin(3u));
|
||||
ASSERT_EQ(++cbegin, set.end(3u));
|
||||
}
|
||||
|
||||
TEST(DenseSet, LocalIteratorConversion) {
|
||||
entt::dense_set<int> set;
|
||||
set.emplace(3);
|
||||
|
||||
typename entt::dense_set<int>::local_iterator it = set.begin(set.bucket(3));
|
||||
typename entt::dense_set<int>::const_local_iterator cit = it;
|
||||
|
||||
static_assert(std::is_same_v<decltype(*it), const int &>);
|
||||
static_assert(std::is_same_v<decltype(*cit), const int &>);
|
||||
|
||||
ASSERT_EQ(*it, 3);
|
||||
ASSERT_EQ(*it.operator->(), 3);
|
||||
ASSERT_EQ(it.operator->(), cit.operator->());
|
||||
ASSERT_EQ(*it, *cit);
|
||||
|
||||
ASSERT_EQ(it, cit);
|
||||
ASSERT_NE(++cit, it);
|
||||
}
|
||||
|
||||
TEST(DenseSet, Rehash) {
|
||||
static constexpr std::size_t minimum_bucket_count = 8u;
|
||||
entt::dense_set<std::size_t, entt::identity> set;
|
||||
set.emplace(32u);
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
|
||||
ASSERT_TRUE(set.contains(32u));
|
||||
ASSERT_EQ(set.bucket(32u), 0u);
|
||||
|
||||
set.rehash(12u);
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 2u * minimum_bucket_count);
|
||||
ASSERT_TRUE(set.contains(32u));
|
||||
ASSERT_EQ(set.bucket(32u), 0u);
|
||||
|
||||
set.rehash(44u);
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 8u * minimum_bucket_count);
|
||||
ASSERT_TRUE(set.contains(32u));
|
||||
ASSERT_EQ(set.bucket(32u), 32u);
|
||||
|
||||
set.rehash(0u);
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
|
||||
ASSERT_TRUE(set.contains(32u));
|
||||
ASSERT_EQ(set.bucket(32u), 0u);
|
||||
|
||||
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
|
||||
set.emplace(next);
|
||||
}
|
||||
|
||||
ASSERT_EQ(set.size(), minimum_bucket_count + 1u);
|
||||
ASSERT_EQ(set.bucket_count(), 2u * minimum_bucket_count);
|
||||
|
||||
set.rehash(0u);
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 2u * minimum_bucket_count);
|
||||
ASSERT_TRUE(set.contains(32u));
|
||||
|
||||
set.rehash(55u);
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 8u * minimum_bucket_count);
|
||||
ASSERT_TRUE(set.contains(32u));
|
||||
|
||||
set.rehash(2u);
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 2u * minimum_bucket_count);
|
||||
ASSERT_TRUE(set.contains(32u));
|
||||
ASSERT_EQ(set.bucket(32u), 0u);
|
||||
|
||||
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
|
||||
ASSERT_TRUE(set.contains(next));
|
||||
ASSERT_EQ(set.bucket(next), next);
|
||||
}
|
||||
|
||||
ASSERT_EQ(set.bucket_size(0u), 2u);
|
||||
ASSERT_EQ(set.bucket_size(3u), 1u);
|
||||
|
||||
ASSERT_EQ(*set.begin(0u), 0u);
|
||||
ASSERT_EQ(*++set.begin(0u), 32u);
|
||||
|
||||
set.clear();
|
||||
set.rehash(2u);
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
|
||||
ASSERT_FALSE(set.contains(32u));
|
||||
|
||||
for(std::size_t next{}; next < minimum_bucket_count; ++next) {
|
||||
ASSERT_FALSE(set.contains(next));
|
||||
}
|
||||
|
||||
ASSERT_EQ(set.bucket_size(0u), 0u);
|
||||
ASSERT_EQ(set.bucket_size(3u), 0u);
|
||||
}
|
||||
|
||||
TEST(DenseSet, Reserve) {
|
||||
static constexpr std::size_t minimum_bucket_count = 8u;
|
||||
entt::dense_set<int> set;
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
|
||||
|
||||
set.reserve(0u);
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
|
||||
|
||||
set.reserve(minimum_bucket_count);
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), 2 * minimum_bucket_count);
|
||||
ASSERT_EQ(set.bucket_count(), entt::next_power_of_two(std::ceil(minimum_bucket_count / set.max_load_factor())));
|
||||
}
|
||||
|
||||
TEST(DenseSet, ThrowingAllocator) {
|
||||
using allocator = test::throwing_allocator<std::size_t>;
|
||||
using packed_allocator = test::throwing_allocator<std::pair<std::size_t, std::size_t>>;
|
||||
using packed_exception = typename packed_allocator::exception_type;
|
||||
|
||||
static constexpr std::size_t minimum_bucket_count = 8u;
|
||||
entt::dense_set<std::size_t, std::hash<std::size_t>, std::equal_to<std::size_t>, allocator> set{};
|
||||
|
||||
packed_allocator::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
|
||||
ASSERT_THROW(set.reserve(2u * set.bucket_count()), packed_exception);
|
||||
ASSERT_EQ(set.bucket_count(), minimum_bucket_count);
|
||||
|
||||
packed_allocator::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW(set.emplace(), packed_exception);
|
||||
ASSERT_FALSE(set.contains(0u));
|
||||
|
||||
packed_allocator::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW(set.emplace(std::size_t{}), packed_exception);
|
||||
ASSERT_FALSE(set.contains(0u));
|
||||
|
||||
packed_allocator::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW(set.insert(0u), packed_exception);
|
||||
ASSERT_FALSE(set.contains(0u));
|
||||
}
|
||||
|
||||
#if defined(ENTT_HAS_TRACKED_MEMORY_RESOURCE)
|
||||
|
||||
TEST(DenseSet, NoUsesAllocatorConstruction) {
|
||||
using allocator = std::pmr::polymorphic_allocator<int>;
|
||||
|
||||
test::tracked_memory_resource memory_resource{};
|
||||
entt::dense_set<int, std::hash<int>, std::equal_to<int>, allocator> set{&memory_resource};
|
||||
|
||||
set.reserve(1u);
|
||||
memory_resource.reset();
|
||||
set.emplace(0);
|
||||
|
||||
ASSERT_TRUE(set.get_allocator().resource()->is_equal(memory_resource));
|
||||
ASSERT_EQ(memory_resource.do_allocate_counter(), 0u);
|
||||
ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
|
||||
}
|
||||
|
||||
TEST(DenseSet, UsesAllocatorConstruction) {
|
||||
using string_type = typename test::tracked_memory_resource::string_type;
|
||||
using allocator = std::pmr::polymorphic_allocator<string_type>;
|
||||
|
||||
test::tracked_memory_resource memory_resource{};
|
||||
entt::dense_set<string_type, std::hash<string_type>, std::equal_to<string_type>, allocator> set{&memory_resource};
|
||||
|
||||
set.reserve(1u);
|
||||
memory_resource.reset();
|
||||
set.emplace(test::tracked_memory_resource::default_value);
|
||||
|
||||
ASSERT_TRUE(set.get_allocator().resource()->is_equal(memory_resource));
|
||||
ASSERT_GT(memory_resource.do_allocate_counter(), 0u);
|
||||
ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
|
||||
}
|
||||
|
||||
#endif
|
98
test/entt/core/algorithm.cpp
Normal file
98
test/entt/core/algorithm.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/algorithm.hpp>
|
||||
|
||||
struct boxed_int {
|
||||
int value;
|
||||
};
|
||||
|
||||
TEST(Algorithm, StdSort) {
|
||||
// well, I'm pretty sure it works, it's std::sort!!
|
||||
std::array<int, 5> arr{{4, 1, 3, 2, 0}};
|
||||
entt::std_sort sort;
|
||||
|
||||
sort(arr.begin(), arr.end());
|
||||
|
||||
for(auto i = 0u; i < (arr.size() - 1u); ++i) {
|
||||
ASSERT_LT(arr[i], arr[i + 1u]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Algorithm, StdSortBoxedInt) {
|
||||
// well, I'm pretty sure it works, it's std::sort!!
|
||||
std::array<boxed_int, 6> arr{{{4}, {1}, {3}, {2}, {0}, {6}}};
|
||||
entt::std_sort sort;
|
||||
|
||||
sort(arr.begin(), arr.end(), [](const auto &lhs, const auto &rhs) {
|
||||
return lhs.value > rhs.value;
|
||||
});
|
||||
|
||||
for(auto i = 0u; i < (arr.size() - 1u); ++i) {
|
||||
ASSERT_GT(arr[i].value, arr[i + 1u].value);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Algorithm, InsertionSort) {
|
||||
std::array<int, 5> arr{{4, 1, 3, 2, 0}};
|
||||
entt::insertion_sort sort;
|
||||
|
||||
sort(arr.begin(), arr.end());
|
||||
|
||||
for(auto i = 0u; i < (arr.size() - 1u); ++i) {
|
||||
ASSERT_LT(arr[i], arr[i + 1u]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Algorithm, InsertionSortBoxedInt) {
|
||||
std::array<boxed_int, 6> arr{{{4}, {1}, {3}, {2}, {0}, {6}}};
|
||||
entt::insertion_sort sort;
|
||||
|
||||
sort(arr.begin(), arr.end(), [](const auto &lhs, const auto &rhs) {
|
||||
return lhs.value > rhs.value;
|
||||
});
|
||||
|
||||
for(auto i = 0u; i < (arr.size() - 1u); ++i) {
|
||||
ASSERT_GT(arr[i].value, arr[i + 1u].value);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Algorithm, InsertionSortEmptyContainer) {
|
||||
std::vector<int> vec{};
|
||||
entt::insertion_sort sort;
|
||||
// this should crash with asan enabled if we break the constraint
|
||||
sort(vec.begin(), vec.end());
|
||||
}
|
||||
|
||||
TEST(Algorithm, RadixSort) {
|
||||
std::array<uint32_t, 5> arr{{4, 1, 3, 2, 0}};
|
||||
entt::radix_sort<8, 32> sort;
|
||||
|
||||
sort(arr.begin(), arr.end(), [](const auto &value) {
|
||||
return value;
|
||||
});
|
||||
|
||||
for(auto i = 0u; i < (arr.size() - 1u); ++i) {
|
||||
ASSERT_LT(arr[i], arr[i + 1u]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Algorithm, RadixSortBoxedInt) {
|
||||
std::array<boxed_int, 6> arr{{{4}, {1}, {3}, {2}, {0}, {6}}};
|
||||
entt::radix_sort<2, 6> sort;
|
||||
|
||||
sort(arr.rbegin(), arr.rend(), [](const auto &instance) {
|
||||
return instance.value;
|
||||
});
|
||||
|
||||
for(auto i = 0u; i < (arr.size() - 1u); ++i) {
|
||||
ASSERT_GT(arr[i].value, arr[i + 1u].value);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Algorithm, RadixSortEmptyContainer) {
|
||||
std::vector<int> vec{};
|
||||
entt::radix_sort<8, 32> sort;
|
||||
// this should crash with asan enabled if we break the constraint
|
||||
sort(vec.begin(), vec.end());
|
||||
}
|
1466
test/entt/core/any.cpp
Normal file
1466
test/entt/core/any.cpp
Normal file
File diff suppressed because it is too large
Load Diff
182
test/entt/core/compressed_pair.cpp
Normal file
182
test/entt/core/compressed_pair.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/compressed_pair.hpp>
|
||||
|
||||
struct empty_type {};
|
||||
|
||||
struct move_only_type {
|
||||
move_only_type()
|
||||
: value{new int{99}} {}
|
||||
|
||||
move_only_type(int v)
|
||||
: value{new int{v}} {}
|
||||
|
||||
~move_only_type() {
|
||||
delete value;
|
||||
}
|
||||
|
||||
move_only_type(const move_only_type &) = delete;
|
||||
move_only_type &operator=(const move_only_type &) = delete;
|
||||
|
||||
move_only_type(move_only_type &&other) noexcept
|
||||
: value{std::exchange(other.value, nullptr)} {}
|
||||
|
||||
move_only_type &operator=(move_only_type &&other) noexcept {
|
||||
delete value;
|
||||
value = std::exchange(other.value, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
int *value;
|
||||
};
|
||||
|
||||
struct non_default_constructible {
|
||||
non_default_constructible(int v)
|
||||
: value{v} {}
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
TEST(CompressedPair, Size) {
|
||||
struct local {
|
||||
int value;
|
||||
empty_type empty;
|
||||
};
|
||||
|
||||
static_assert(sizeof(entt::compressed_pair<int, int>) == sizeof(int[2u]));
|
||||
static_assert(sizeof(entt::compressed_pair<empty_type, int>) == sizeof(int));
|
||||
static_assert(sizeof(entt::compressed_pair<int, empty_type>) == sizeof(int));
|
||||
static_assert(sizeof(entt::compressed_pair<int, empty_type>) < sizeof(local));
|
||||
static_assert(sizeof(entt::compressed_pair<int, empty_type>) < sizeof(std::pair<int, empty_type>));
|
||||
}
|
||||
|
||||
TEST(CompressedPair, ConstructCopyMove) {
|
||||
static_assert(!std::is_default_constructible_v<entt::compressed_pair<non_default_constructible, empty_type>>);
|
||||
static_assert(std::is_default_constructible_v<entt::compressed_pair<move_only_type, empty_type>>);
|
||||
|
||||
static_assert(std::is_copy_constructible_v<entt::compressed_pair<non_default_constructible, empty_type>>);
|
||||
static_assert(!std::is_copy_constructible_v<entt::compressed_pair<move_only_type, empty_type>>);
|
||||
static_assert(std::is_copy_assignable_v<entt::compressed_pair<non_default_constructible, empty_type>>);
|
||||
static_assert(!std::is_copy_assignable_v<entt::compressed_pair<move_only_type, empty_type>>);
|
||||
|
||||
static_assert(std::is_move_constructible_v<entt::compressed_pair<move_only_type, empty_type>>);
|
||||
static_assert(std::is_move_assignable_v<entt::compressed_pair<move_only_type, empty_type>>);
|
||||
|
||||
entt::compressed_pair copyable{non_default_constructible{42}, empty_type{}};
|
||||
auto by_copy{copyable};
|
||||
|
||||
ASSERT_EQ(by_copy.first().value, 42);
|
||||
|
||||
by_copy.first().value = 3;
|
||||
copyable = by_copy;
|
||||
|
||||
ASSERT_EQ(copyable.first().value, 3);
|
||||
|
||||
entt::compressed_pair<empty_type, move_only_type> movable{};
|
||||
auto by_move{std::move(movable)};
|
||||
|
||||
ASSERT_EQ(*by_move.second().value, 99);
|
||||
ASSERT_EQ(movable.second().value, nullptr);
|
||||
|
||||
*by_move.second().value = 3;
|
||||
movable = std::move(by_move);
|
||||
|
||||
ASSERT_EQ(*movable.second().value, 3);
|
||||
ASSERT_EQ(by_move.second().value, nullptr);
|
||||
}
|
||||
|
||||
TEST(CompressedPair, PiecewiseConstruct) {
|
||||
std::vector<int> vec{42};
|
||||
entt::compressed_pair<empty_type, empty_type> empty{std::piecewise_construct, std::make_tuple(), std::make_tuple()};
|
||||
entt::compressed_pair<std::vector<int>, std::size_t> pair{std::piecewise_construct, std::forward_as_tuple(std::move(vec)), std::make_tuple(sizeof(empty))};
|
||||
|
||||
ASSERT_EQ(pair.first().size(), 1u);
|
||||
ASSERT_EQ(pair.second(), sizeof(empty));
|
||||
ASSERT_EQ(vec.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(CompressedPair, DeductionGuide) {
|
||||
int value = 42;
|
||||
empty_type empty{};
|
||||
entt::compressed_pair pair{value, 3};
|
||||
|
||||
static_assert(std::is_same_v<decltype(entt::compressed_pair{empty_type{}, empty}), entt::compressed_pair<empty_type, empty_type>>);
|
||||
|
||||
ASSERT_TRUE((std::is_same_v<decltype(pair), entt::compressed_pair<int, int>>));
|
||||
ASSERT_EQ(pair.first(), 42);
|
||||
ASSERT_EQ(pair.second(), 3);
|
||||
}
|
||||
|
||||
TEST(CompressedPair, Getters) {
|
||||
entt::compressed_pair pair{3, empty_type{}};
|
||||
const auto &cpair = pair;
|
||||
|
||||
static_assert(std::is_same_v<decltype(pair.first()), int &>);
|
||||
static_assert(std::is_same_v<decltype(pair.second()), empty_type &>);
|
||||
|
||||
static_assert(std::is_same_v<decltype(cpair.first()), const int &>);
|
||||
static_assert(std::is_same_v<decltype(cpair.second()), const empty_type &>);
|
||||
|
||||
ASSERT_EQ(pair.first(), cpair.first());
|
||||
ASSERT_EQ(&pair.second(), &cpair.second());
|
||||
}
|
||||
|
||||
TEST(CompressedPair, Swap) {
|
||||
entt::compressed_pair pair{1, 2};
|
||||
entt::compressed_pair other{3, 4};
|
||||
|
||||
swap(pair, other);
|
||||
|
||||
ASSERT_EQ(pair.first(), 3);
|
||||
ASSERT_EQ(pair.second(), 4);
|
||||
ASSERT_EQ(other.first(), 1);
|
||||
ASSERT_EQ(other.second(), 2);
|
||||
|
||||
pair.swap(other);
|
||||
|
||||
ASSERT_EQ(pair.first(), 1);
|
||||
ASSERT_EQ(pair.second(), 2);
|
||||
ASSERT_EQ(other.first(), 3);
|
||||
ASSERT_EQ(other.second(), 4);
|
||||
}
|
||||
|
||||
TEST(CompressedPair, Get) {
|
||||
entt::compressed_pair pair{1, 2};
|
||||
|
||||
ASSERT_EQ(pair.get<0>(), 1);
|
||||
ASSERT_EQ(pair.get<1>(), 2);
|
||||
|
||||
ASSERT_EQ(&pair.get<0>(), &pair.first());
|
||||
ASSERT_EQ(&pair.get<1>(), &pair.second());
|
||||
|
||||
auto &&[first, second] = pair;
|
||||
|
||||
ASSERT_EQ(first, 1);
|
||||
ASSERT_EQ(second, 2);
|
||||
|
||||
first = 3;
|
||||
second = 4;
|
||||
|
||||
ASSERT_EQ(pair.first(), 3);
|
||||
ASSERT_EQ(pair.second(), 4);
|
||||
|
||||
auto &[cfirst, csecond] = std::as_const(pair);
|
||||
|
||||
ASSERT_EQ(cfirst, 3);
|
||||
ASSERT_EQ(csecond, 4);
|
||||
|
||||
static_assert(std::is_same_v<decltype(cfirst), const int>);
|
||||
static_assert(std::is_same_v<decltype(csecond), const int>);
|
||||
|
||||
auto [tfirst, tsecond] = entt::compressed_pair{9, 99};
|
||||
|
||||
ASSERT_EQ(tfirst, 9);
|
||||
ASSERT_EQ(tsecond, 99);
|
||||
|
||||
static_assert(std::is_same_v<decltype(cfirst), const int>);
|
||||
static_assert(std::is_same_v<decltype(csecond), const int>);
|
||||
}
|
72
test/entt/core/enum.cpp
Normal file
72
test/entt/core/enum.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/enum.hpp>
|
||||
|
||||
enum class detected {
|
||||
foo = 0x01,
|
||||
bar = 0x02,
|
||||
quux = 0x04,
|
||||
_entt_enum_as_bitmask
|
||||
};
|
||||
|
||||
// small type on purpose
|
||||
enum class registered : std::uint8_t {
|
||||
foo = 0x01,
|
||||
bar = 0x02,
|
||||
quux = 0x04
|
||||
};
|
||||
|
||||
template<>
|
||||
struct entt::enum_as_bitmask<registered>
|
||||
: std::true_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct Enum: testing::Test {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
using EnumTypes = ::testing::Types<detected, registered>;
|
||||
|
||||
TYPED_TEST_SUITE(Enum, EnumTypes, );
|
||||
|
||||
TYPED_TEST(Enum, Functionalities) {
|
||||
using enum_type = typename TestFixture::type;
|
||||
|
||||
ASSERT_TRUE(!!((enum_type::foo | enum_type::bar) & enum_type::foo));
|
||||
ASSERT_TRUE(!!((enum_type::foo | enum_type::bar) & enum_type::bar));
|
||||
ASSERT_TRUE(!((enum_type::foo | enum_type::bar) & enum_type::quux));
|
||||
|
||||
ASSERT_TRUE(!!((enum_type::foo ^ enum_type::bar) & enum_type::foo));
|
||||
ASSERT_TRUE(!((enum_type::foo ^ enum_type::foo) & enum_type::foo));
|
||||
|
||||
ASSERT_TRUE(!(~enum_type::foo & enum_type::foo));
|
||||
ASSERT_TRUE(!!(~enum_type::foo & enum_type::bar));
|
||||
|
||||
ASSERT_TRUE(enum_type::foo == enum_type::foo);
|
||||
ASSERT_TRUE(enum_type::foo != enum_type::bar);
|
||||
|
||||
enum_type value = enum_type::foo;
|
||||
|
||||
ASSERT_TRUE(!!(value & enum_type::foo));
|
||||
ASSERT_TRUE(!(value & enum_type::bar));
|
||||
ASSERT_TRUE(!(value & enum_type::quux));
|
||||
|
||||
value |= (enum_type::bar | enum_type::quux);
|
||||
|
||||
ASSERT_TRUE(!!(value & enum_type::foo));
|
||||
ASSERT_TRUE(!!(value & enum_type::bar));
|
||||
ASSERT_TRUE(!!(value & enum_type::quux));
|
||||
|
||||
value &= (enum_type::bar | enum_type::quux);
|
||||
|
||||
ASSERT_TRUE(!(value & enum_type::foo));
|
||||
ASSERT_TRUE(!!(value & enum_type::bar));
|
||||
ASSERT_TRUE(!!(value & enum_type::quux));
|
||||
|
||||
value ^= enum_type::bar;
|
||||
|
||||
ASSERT_TRUE(!(value & enum_type::foo));
|
||||
ASSERT_TRUE(!(value & enum_type::bar));
|
||||
ASSERT_TRUE(!!(value & enum_type::quux));
|
||||
}
|
22
test/entt/core/family.cpp
Normal file
22
test/entt/core/family.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/family.hpp>
|
||||
|
||||
using a_family = entt::family<struct a_family_type>;
|
||||
using another_family = entt::family<struct another_family_type>;
|
||||
|
||||
TEST(Family, Functionalities) {
|
||||
auto t1 = a_family::value<int>;
|
||||
auto t2 = a_family::value<int>;
|
||||
auto t3 = a_family::value<char>;
|
||||
auto t4 = another_family::value<double>;
|
||||
|
||||
ASSERT_EQ(t1, t2);
|
||||
ASSERT_NE(t1, t3);
|
||||
ASSERT_EQ(t1, t4);
|
||||
}
|
||||
|
||||
TEST(Family, Uniqueness) {
|
||||
ASSERT_NE(a_family::value<int>, a_family::value<int &>);
|
||||
ASSERT_NE(a_family::value<int>, a_family::value<int &&>);
|
||||
ASSERT_NE(a_family::value<int>, a_family::value<const int &>);
|
||||
}
|
224
test/entt/core/hashed_string.cpp
Normal file
224
test/entt/core/hashed_string.cpp
Normal file
@ -0,0 +1,224 @@
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
|
||||
template<typename>
|
||||
struct foobar_t;
|
||||
|
||||
template<>
|
||||
struct foobar_t<std::uint32_t> {
|
||||
static constexpr auto value = 0xbf9cf968;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct foobar_t<std::uint64_t> {
|
||||
static constexpr auto value = 0x85944171f73967e8;
|
||||
};
|
||||
|
||||
inline constexpr auto foobar_v = foobar_t<entt::id_type>::value;
|
||||
|
||||
TEST(BasicHashedString, DeductionGuide) {
|
||||
static_assert(std::is_same_v<decltype(entt::basic_hashed_string{"foo"}), entt::hashed_string>);
|
||||
static_assert(std::is_same_v<decltype(entt::basic_hashed_string{L"foo"}), entt::hashed_wstring>);
|
||||
}
|
||||
|
||||
TEST(HashedString, Functionalities) {
|
||||
using namespace entt::literals;
|
||||
using hash_type = entt::hashed_string::hash_type;
|
||||
|
||||
const char *bar = "bar";
|
||||
|
||||
auto foo_hs = entt::hashed_string{"foo"};
|
||||
auto bar_hs = entt::hashed_string{bar};
|
||||
|
||||
ASSERT_NE(static_cast<hash_type>(foo_hs), static_cast<hash_type>(bar_hs));
|
||||
ASSERT_STREQ(static_cast<const char *>(foo_hs), "foo");
|
||||
ASSERT_STREQ(static_cast<const char *>(bar_hs), bar);
|
||||
ASSERT_STREQ(foo_hs.data(), "foo");
|
||||
ASSERT_STREQ(bar_hs.data(), bar);
|
||||
ASSERT_EQ(foo_hs.size(), 3u);
|
||||
ASSERT_EQ(bar_hs.size(), 3u);
|
||||
|
||||
ASSERT_EQ(foo_hs, foo_hs);
|
||||
ASSERT_NE(foo_hs, bar_hs);
|
||||
|
||||
entt::hashed_string hs{"foobar"};
|
||||
|
||||
ASSERT_EQ(static_cast<hash_type>(hs), foobar_v);
|
||||
ASSERT_EQ(hs.value(), foobar_v);
|
||||
|
||||
ASSERT_EQ(foo_hs, "foo"_hs);
|
||||
ASSERT_NE(bar_hs, "foo"_hs);
|
||||
|
||||
entt::hashed_string empty_hs{};
|
||||
|
||||
ASSERT_EQ(empty_hs, entt::hashed_string{});
|
||||
ASSERT_NE(empty_hs, foo_hs);
|
||||
|
||||
empty_hs = foo_hs;
|
||||
|
||||
ASSERT_NE(empty_hs, entt::hashed_string{});
|
||||
ASSERT_EQ(empty_hs, foo_hs);
|
||||
}
|
||||
|
||||
TEST(HashedString, Empty) {
|
||||
using hash_type = entt::hashed_string::hash_type;
|
||||
|
||||
entt::hashed_string hs{};
|
||||
|
||||
ASSERT_EQ(hs.size(), 0u);
|
||||
ASSERT_EQ(static_cast<hash_type>(hs), hash_type{});
|
||||
ASSERT_EQ(static_cast<const char *>(hs), nullptr);
|
||||
}
|
||||
|
||||
TEST(HashedString, Correctness) {
|
||||
const char *foobar = "foobar";
|
||||
std::string_view view{"foobar__", 6};
|
||||
|
||||
ASSERT_EQ(entt::hashed_string{foobar}, foobar_v);
|
||||
ASSERT_EQ((entt::hashed_string{view.data(), view.size()}), foobar_v);
|
||||
ASSERT_EQ(entt::hashed_string{"foobar"}, foobar_v);
|
||||
|
||||
ASSERT_EQ(entt::hashed_string::value(foobar), foobar_v);
|
||||
ASSERT_EQ(entt::hashed_string::value(view.data(), view.size()), foobar_v);
|
||||
ASSERT_EQ(entt::hashed_string::value("foobar"), foobar_v);
|
||||
|
||||
ASSERT_EQ(entt::hashed_string{foobar}.size(), 6u);
|
||||
ASSERT_EQ((entt::hashed_string{view.data(), view.size()}).size(), 6u);
|
||||
ASSERT_EQ(entt::hashed_string{"foobar"}.size(), 6u);
|
||||
}
|
||||
|
||||
TEST(HashedString, Order) {
|
||||
using namespace entt::literals;
|
||||
const entt::hashed_string lhs = "foo"_hs;
|
||||
const entt::hashed_string rhs = "bar"_hs;
|
||||
|
||||
ASSERT_FALSE(lhs < lhs);
|
||||
ASSERT_FALSE(rhs < rhs);
|
||||
|
||||
ASSERT_LT(rhs, lhs);
|
||||
ASSERT_LE(rhs, lhs);
|
||||
|
||||
ASSERT_GT(lhs, rhs);
|
||||
ASSERT_GE(lhs, rhs);
|
||||
}
|
||||
|
||||
TEST(HashedString, Constexprness) {
|
||||
using namespace entt::literals;
|
||||
constexpr std::string_view view{"foobar__", 6};
|
||||
|
||||
static_assert(entt::hashed_string{"quux"} == "quux"_hs);
|
||||
static_assert(entt::hashed_string{"foobar"} == foobar_v);
|
||||
|
||||
static_assert(entt::hashed_string::value("quux") == "quux"_hs);
|
||||
static_assert(entt::hashed_string::value("foobar") == foobar_v);
|
||||
|
||||
static_assert(entt::hashed_string{"quux", 4} == "quux"_hs);
|
||||
static_assert(entt::hashed_string{view.data(), view.size()} == foobar_v);
|
||||
|
||||
static_assert(entt::hashed_string::value("quux", 4) == "quux"_hs);
|
||||
static_assert(entt::hashed_string::value(view.data(), view.size()) == foobar_v);
|
||||
|
||||
static_assert(entt::hashed_string{"bar"} < "foo"_hs);
|
||||
static_assert(entt::hashed_string{"bar"} <= "bar"_hs);
|
||||
|
||||
static_assert(entt::hashed_string{"foo"} > "bar"_hs);
|
||||
static_assert(entt::hashed_string{"foo"} >= "foo"_hs);
|
||||
}
|
||||
|
||||
TEST(HashedWString, Functionalities) {
|
||||
using namespace entt::literals;
|
||||
using hash_type = entt::hashed_wstring::hash_type;
|
||||
|
||||
const wchar_t *bar = L"bar";
|
||||
|
||||
auto foo_hws = entt::hashed_wstring{L"foo"};
|
||||
auto bar_hws = entt::hashed_wstring{bar};
|
||||
|
||||
ASSERT_NE(static_cast<hash_type>(foo_hws), static_cast<hash_type>(bar_hws));
|
||||
ASSERT_STREQ(static_cast<const wchar_t *>(foo_hws), L"foo");
|
||||
ASSERT_STREQ(static_cast<const wchar_t *>(bar_hws), bar);
|
||||
ASSERT_STREQ(foo_hws.data(), L"foo");
|
||||
ASSERT_STREQ(bar_hws.data(), bar);
|
||||
ASSERT_EQ(foo_hws.size(), 3u);
|
||||
ASSERT_EQ(bar_hws.size(), 3u);
|
||||
|
||||
ASSERT_EQ(foo_hws, foo_hws);
|
||||
ASSERT_NE(foo_hws, bar_hws);
|
||||
|
||||
entt::hashed_wstring hws{L"foobar"};
|
||||
|
||||
ASSERT_EQ(static_cast<hash_type>(hws), foobar_v);
|
||||
ASSERT_EQ(hws.value(), foobar_v);
|
||||
|
||||
ASSERT_EQ(foo_hws, L"foo"_hws);
|
||||
ASSERT_NE(bar_hws, L"foo"_hws);
|
||||
}
|
||||
|
||||
TEST(HashedWString, Empty) {
|
||||
using hash_type = entt::hashed_wstring::hash_type;
|
||||
|
||||
entt::hashed_wstring hws{};
|
||||
|
||||
ASSERT_EQ(hws.size(), 0u);
|
||||
ASSERT_EQ(static_cast<hash_type>(hws), hash_type{});
|
||||
ASSERT_EQ(static_cast<const wchar_t *>(hws), nullptr);
|
||||
}
|
||||
|
||||
TEST(HashedWString, Correctness) {
|
||||
const wchar_t *foobar = L"foobar";
|
||||
std::wstring_view view{L"foobar__", 6};
|
||||
|
||||
ASSERT_EQ(entt::hashed_wstring{foobar}, foobar_v);
|
||||
ASSERT_EQ((entt::hashed_wstring{view.data(), view.size()}), foobar_v);
|
||||
ASSERT_EQ(entt::hashed_wstring{L"foobar"}, foobar_v);
|
||||
|
||||
ASSERT_EQ(entt::hashed_wstring::value(foobar), foobar_v);
|
||||
ASSERT_EQ(entt::hashed_wstring::value(view.data(), view.size()), foobar_v);
|
||||
ASSERT_EQ(entt::hashed_wstring::value(L"foobar"), foobar_v);
|
||||
|
||||
ASSERT_EQ(entt::hashed_wstring{foobar}.size(), 6u);
|
||||
ASSERT_EQ((entt::hashed_wstring{view.data(), view.size()}).size(), 6u);
|
||||
ASSERT_EQ(entt::hashed_wstring{L"foobar"}.size(), 6u);
|
||||
}
|
||||
|
||||
TEST(HashedWString, Order) {
|
||||
using namespace entt::literals;
|
||||
const entt::hashed_wstring lhs = L"foo"_hws;
|
||||
const entt::hashed_wstring rhs = L"bar"_hws;
|
||||
|
||||
ASSERT_FALSE(lhs < lhs);
|
||||
ASSERT_FALSE(rhs < rhs);
|
||||
|
||||
ASSERT_LT(rhs, lhs);
|
||||
ASSERT_LE(rhs, lhs);
|
||||
|
||||
ASSERT_GT(lhs, rhs);
|
||||
ASSERT_GE(lhs, rhs);
|
||||
}
|
||||
|
||||
TEST(HashedWString, Constexprness) {
|
||||
using namespace entt::literals;
|
||||
constexpr std::wstring_view view{L"foobar__", 6};
|
||||
|
||||
static_assert(entt::hashed_wstring{L"quux"} == L"quux"_hws);
|
||||
static_assert(entt::hashed_wstring{L"foobar"} == foobar_v);
|
||||
|
||||
static_assert(entt::hashed_wstring::value(L"quux") == L"quux"_hws);
|
||||
static_assert(entt::hashed_wstring::value(L"foobar") == foobar_v);
|
||||
|
||||
static_assert(entt::hashed_wstring{L"quux", 4} == L"quux"_hws);
|
||||
static_assert(entt::hashed_wstring{view.data(), view.size()} == foobar_v);
|
||||
|
||||
static_assert(entt::hashed_wstring::value(L"quux", 4) == L"quux"_hws);
|
||||
static_assert(entt::hashed_wstring::value(view.data(), view.size()) == foobar_v);
|
||||
|
||||
static_assert(entt::hashed_wstring{L"bar"} < L"foo"_hws);
|
||||
static_assert(entt::hashed_wstring{L"bar"} <= L"bar"_hws);
|
||||
|
||||
static_assert(entt::hashed_wstring{L"foo"} > L"bar"_hws);
|
||||
static_assert(entt::hashed_wstring{L"foo"} >= L"foo"_hws);
|
||||
}
|
31
test/entt/core/ident.cpp
Normal file
31
test/entt/core/ident.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include <type_traits>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/ident.hpp>
|
||||
|
||||
struct a_type {};
|
||||
struct another_type {};
|
||||
|
||||
TEST(Ident, Uniqueness) {
|
||||
using id = entt::ident<a_type, another_type>;
|
||||
constexpr a_type an_instance;
|
||||
constexpr another_type another_instance;
|
||||
|
||||
ASSERT_NE(id::value<a_type>, id::value<another_type>);
|
||||
ASSERT_EQ(id::value<a_type>, id::value<decltype(an_instance)>);
|
||||
ASSERT_NE(id::value<a_type>, id::value<decltype(another_instance)>);
|
||||
ASSERT_EQ(id::value<a_type>, id::value<a_type>);
|
||||
ASSERT_EQ(id::value<another_type>, id::value<another_type>);
|
||||
|
||||
// test uses in constant expressions
|
||||
switch(id::value<another_type>) {
|
||||
case id::value<a_type>:
|
||||
FAIL();
|
||||
case id::value<another_type>:
|
||||
SUCCEED();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Identifier, SingleType) {
|
||||
using id = entt::ident<a_type>;
|
||||
[[maybe_unused]] std::integral_constant<id::value_type, id::value<a_type>> ic;
|
||||
}
|
55
test/entt/core/iterator.cpp
Normal file
55
test/entt/core/iterator.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/iterator.hpp>
|
||||
|
||||
struct clazz {
|
||||
int value{0};
|
||||
};
|
||||
|
||||
TEST(InputIteratorPointer, Functionalities) {
|
||||
clazz instance{};
|
||||
entt::input_iterator_pointer ptr{std::move(instance)};
|
||||
ptr->value = 42;
|
||||
|
||||
ASSERT_EQ(instance.value, 0);
|
||||
ASSERT_EQ(ptr->value, 42);
|
||||
ASSERT_EQ(ptr->value, (*ptr).value);
|
||||
ASSERT_EQ(ptr.operator->(), &ptr.operator*());
|
||||
}
|
||||
|
||||
TEST(IotaIterator, Functionalities) {
|
||||
entt::iota_iterator<std::size_t> first{};
|
||||
const entt::iota_iterator<std::size_t> last{2u};
|
||||
|
||||
ASSERT_NE(first, last);
|
||||
ASSERT_FALSE(first == last);
|
||||
ASSERT_TRUE(first != last);
|
||||
|
||||
ASSERT_EQ(*first++, 0u);
|
||||
ASSERT_EQ(*first, 1u);
|
||||
ASSERT_EQ(*++first, *last);
|
||||
ASSERT_EQ(*first, 2u);
|
||||
}
|
||||
|
||||
TEST(IterableAdaptor, Functionalities) {
|
||||
std::vector<int> vec{1, 2};
|
||||
entt::iterable_adaptor iterable{vec.begin(), vec.end()};
|
||||
decltype(iterable) other{};
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(other = iterable);
|
||||
ASSERT_NO_FATAL_FAILURE(std::swap(other, iterable));
|
||||
|
||||
ASSERT_EQ(iterable.begin(), vec.begin());
|
||||
ASSERT_EQ(iterable.end(), vec.end());
|
||||
|
||||
ASSERT_EQ(*iterable.cbegin(), 1);
|
||||
ASSERT_EQ(*++iterable.cbegin(), 2);
|
||||
ASSERT_EQ(++iterable.cbegin(), --iterable.end());
|
||||
|
||||
for(auto value: entt::iterable_adaptor<const int *, const void *>{vec.data(), vec.data() + 1u}) {
|
||||
ASSERT_EQ(value, 1);
|
||||
}
|
||||
}
|
241
test/entt/core/memory.cpp
Normal file
241
test/entt/core/memory.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/memory.hpp>
|
||||
#include "../common/basic_test_allocator.hpp"
|
||||
#include "../common/config.h"
|
||||
#include "../common/throwing_allocator.hpp"
|
||||
#include "../common/throwing_type.hpp"
|
||||
#include "../common/tracked_memory_resource.hpp"
|
||||
|
||||
TEST(ToAddress, Functionalities) {
|
||||
std::shared_ptr<int> shared = std::make_shared<int>();
|
||||
auto *plain = std::addressof(*shared);
|
||||
|
||||
ASSERT_EQ(entt::to_address(shared), plain);
|
||||
ASSERT_EQ(entt::to_address(plain), plain);
|
||||
}
|
||||
|
||||
TEST(PoccaPocmaAndPocs, Functionalities) {
|
||||
test::basic_test_allocator<int> lhs, rhs;
|
||||
// honestly, I don't even know how one is supposed to test such a thing :)
|
||||
entt::propagate_on_container_copy_assignment(lhs, rhs);
|
||||
entt::propagate_on_container_move_assignment(lhs, rhs);
|
||||
entt::propagate_on_container_swap(lhs, rhs);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(PoccaPocmaAndPocsDeathTest, Functionalities) {
|
||||
using pocs = std::false_type;
|
||||
test::basic_test_allocator<int, pocs> lhs, rhs;
|
||||
ASSERT_DEATH(entt::propagate_on_container_swap(lhs, rhs), "");
|
||||
}
|
||||
|
||||
TEST(IsPowerOfTwo, Functionalities) {
|
||||
// constexpr-ness guaranteed
|
||||
constexpr auto zero_is_power_of_two = entt::is_power_of_two(0u);
|
||||
|
||||
ASSERT_FALSE(zero_is_power_of_two);
|
||||
ASSERT_TRUE(entt::is_power_of_two(1u));
|
||||
ASSERT_TRUE(entt::is_power_of_two(2u));
|
||||
ASSERT_TRUE(entt::is_power_of_two(4u));
|
||||
ASSERT_FALSE(entt::is_power_of_two(7u));
|
||||
ASSERT_TRUE(entt::is_power_of_two(128u));
|
||||
ASSERT_FALSE(entt::is_power_of_two(200u));
|
||||
}
|
||||
|
||||
TEST(NextPowerOfTwo, Functionalities) {
|
||||
// constexpr-ness guaranteed
|
||||
constexpr auto next_power_of_two_of_zero = entt::next_power_of_two(0u);
|
||||
|
||||
ASSERT_EQ(next_power_of_two_of_zero, 1u);
|
||||
ASSERT_EQ(entt::next_power_of_two(1u), 1u);
|
||||
ASSERT_EQ(entt::next_power_of_two(2u), 2u);
|
||||
ASSERT_EQ(entt::next_power_of_two(3u), 4u);
|
||||
ASSERT_EQ(entt::next_power_of_two(17u), 32u);
|
||||
ASSERT_EQ(entt::next_power_of_two(32u), 32u);
|
||||
ASSERT_EQ(entt::next_power_of_two(33u), 64u);
|
||||
ASSERT_EQ(entt::next_power_of_two(std::pow(2, 16)), std::pow(2, 16));
|
||||
ASSERT_EQ(entt::next_power_of_two(std::pow(2, 16) + 1u), std::pow(2, 17));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(NextPowerOfTwoDeathTest, Functionalities) {
|
||||
ASSERT_DEATH(static_cast<void>(entt::next_power_of_two((std::size_t{1u} << (std::numeric_limits<std::size_t>::digits - 1)) + 1)), "");
|
||||
}
|
||||
|
||||
TEST(FastMod, Functionalities) {
|
||||
// constexpr-ness guaranteed
|
||||
constexpr auto fast_mod_of_zero = entt::fast_mod(0u, 8u);
|
||||
|
||||
ASSERT_EQ(fast_mod_of_zero, 0u);
|
||||
ASSERT_EQ(entt::fast_mod(7u, 8u), 7u);
|
||||
ASSERT_EQ(entt::fast_mod(8u, 8u), 0u);
|
||||
}
|
||||
|
||||
TEST(AllocateUnique, Functionalities) {
|
||||
test::throwing_allocator<test::throwing_type> allocator{};
|
||||
test::throwing_allocator<test::throwing_type>::trigger_on_allocate = true;
|
||||
test::throwing_type::trigger_on_value = 0;
|
||||
|
||||
ASSERT_THROW((entt::allocate_unique<test::throwing_type>(allocator, 0)), test::throwing_allocator<test::throwing_type>::exception_type);
|
||||
ASSERT_THROW((entt::allocate_unique<test::throwing_type>(allocator, test::throwing_type{0})), test::throwing_type::exception_type);
|
||||
|
||||
std::unique_ptr<test::throwing_type, entt::allocation_deleter<test::throwing_allocator<test::throwing_type>>> ptr = entt::allocate_unique<test::throwing_type>(allocator, 42);
|
||||
|
||||
ASSERT_TRUE(ptr);
|
||||
ASSERT_EQ(*ptr, 42);
|
||||
|
||||
ptr.reset();
|
||||
|
||||
ASSERT_FALSE(ptr);
|
||||
}
|
||||
|
||||
#if defined(ENTT_HAS_TRACKED_MEMORY_RESOURCE)
|
||||
|
||||
TEST(AllocateUnique, NoUsesAllocatorConstruction) {
|
||||
test::tracked_memory_resource memory_resource{};
|
||||
std::pmr::polymorphic_allocator<int> allocator{&memory_resource};
|
||||
|
||||
using type = std::unique_ptr<int, entt::allocation_deleter<std::pmr::polymorphic_allocator<int>>>;
|
||||
type ptr = entt::allocate_unique<int>(allocator, 0);
|
||||
|
||||
ASSERT_EQ(memory_resource.do_allocate_counter(), 1u);
|
||||
ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
|
||||
}
|
||||
|
||||
TEST(AllocateUnique, UsesAllocatorConstruction) {
|
||||
using string_type = typename test::tracked_memory_resource::string_type;
|
||||
|
||||
test::tracked_memory_resource memory_resource{};
|
||||
std::pmr::polymorphic_allocator<string_type> allocator{&memory_resource};
|
||||
|
||||
using type = std::unique_ptr<string_type, entt::allocation_deleter<std::pmr::polymorphic_allocator<string_type>>>;
|
||||
type ptr = entt::allocate_unique<string_type>(allocator, test::tracked_memory_resource::default_value);
|
||||
|
||||
ASSERT_GT(memory_resource.do_allocate_counter(), 1u);
|
||||
ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST(UsesAllocatorConstructionArgs, NoUsesAllocatorConstruction) {
|
||||
const auto value = 42;
|
||||
const auto args = entt::uses_allocator_construction_args<int>(std::allocator<int>{}, value);
|
||||
|
||||
static_assert(std::tuple_size_v<decltype(args)> == 1u);
|
||||
static_assert(std::is_same_v<decltype(args), const std::tuple<const int &>>);
|
||||
|
||||
ASSERT_EQ(std::get<0>(args), value);
|
||||
}
|
||||
|
||||
TEST(UsesAllocatorConstructionArgs, LeadingAllocatorConvention) {
|
||||
const auto value = 42;
|
||||
const auto args = entt::uses_allocator_construction_args<std::tuple<int, char>>(std::allocator<int>{}, value, 'c');
|
||||
|
||||
static_assert(std::tuple_size_v<decltype(args)> == 4u);
|
||||
static_assert(std::is_same_v<decltype(args), const std::tuple<std::allocator_arg_t, const std::allocator<int> &, const int &, char &&>>);
|
||||
|
||||
ASSERT_EQ(std::get<2>(args), value);
|
||||
}
|
||||
|
||||
TEST(UsesAllocatorConstructionArgs, TrailingAllocatorConvention) {
|
||||
const auto size = 42u;
|
||||
const auto args = entt::uses_allocator_construction_args<std::vector<int>>(std::allocator<int>{}, size);
|
||||
|
||||
static_assert(std::tuple_size_v<decltype(args)> == 2u);
|
||||
static_assert(std::is_same_v<decltype(args), const std::tuple<const unsigned int &, const std::allocator<int> &>>);
|
||||
|
||||
ASSERT_EQ(std::get<0>(args), size);
|
||||
}
|
||||
|
||||
TEST(UsesAllocatorConstructionArgs, PairPiecewiseConstruct) {
|
||||
const auto size = 42u;
|
||||
const auto tup = std::make_tuple(size);
|
||||
const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, std::piecewise_construct, std::make_tuple(3), tup);
|
||||
|
||||
static_assert(std::tuple_size_v<decltype(args)> == 3u);
|
||||
static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<int &&>, std::tuple<const unsigned int &, const std::allocator<int> &>>>);
|
||||
|
||||
ASSERT_EQ(std::get<0>(std::get<2>(args)), size);
|
||||
}
|
||||
|
||||
TEST(UsesAllocatorConstructionArgs, PairNoArgs) {
|
||||
[[maybe_unused]] const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{});
|
||||
|
||||
static_assert(std::tuple_size_v<decltype(args)> == 3u);
|
||||
static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<>, std::tuple<const std::allocator<int> &>>>);
|
||||
}
|
||||
|
||||
TEST(UsesAllocatorConstructionArgs, PairValues) {
|
||||
const auto size = 42u;
|
||||
const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, 3, size);
|
||||
|
||||
static_assert(std::tuple_size_v<decltype(args)> == 3u);
|
||||
static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<int &&>, std::tuple<const unsigned int &, const std::allocator<int> &>>>);
|
||||
|
||||
ASSERT_EQ(std::get<0>(std::get<2>(args)), size);
|
||||
}
|
||||
|
||||
TEST(UsesAllocatorConstructionArgs, PairConstLValueReference) {
|
||||
const auto value = std::make_pair(3, 42u);
|
||||
const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, value);
|
||||
|
||||
static_assert(std::tuple_size_v<decltype(args)> == 3u);
|
||||
static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<const int &>, std::tuple<const unsigned int &, const std::allocator<int> &>>>);
|
||||
|
||||
ASSERT_EQ(std::get<0>(std::get<1>(args)), 3);
|
||||
ASSERT_EQ(std::get<0>(std::get<2>(args)), 42u);
|
||||
}
|
||||
|
||||
TEST(UsesAllocatorConstructionArgs, PairRValueReference) {
|
||||
[[maybe_unused]] const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, std::make_pair(3, 42u));
|
||||
|
||||
static_assert(std::tuple_size_v<decltype(args)> == 3u);
|
||||
static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<int &&>, std::tuple<unsigned int &&, const std::allocator<int> &>>>);
|
||||
}
|
||||
|
||||
TEST(MakeObjUsingAllocator, Functionalities) {
|
||||
const auto size = 42u;
|
||||
test::throwing_allocator<int>::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW((entt::make_obj_using_allocator<std::vector<int, test::throwing_allocator<int>>>(test::throwing_allocator<int>{}, size)), test::throwing_allocator<int>::exception_type);
|
||||
|
||||
const auto vec = entt::make_obj_using_allocator<std::vector<int>>(std::allocator<int>{}, size);
|
||||
|
||||
ASSERT_FALSE(vec.empty());
|
||||
ASSERT_EQ(vec.size(), size);
|
||||
}
|
||||
|
||||
TEST(UninitializedConstructUsingAllocator, NoUsesAllocatorConstruction) {
|
||||
alignas(int) std::byte storage[sizeof(int)];
|
||||
std::allocator<int> allocator{};
|
||||
|
||||
int *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<int *>(&storage), allocator, 42);
|
||||
|
||||
ASSERT_EQ(*value, 42);
|
||||
}
|
||||
|
||||
#if defined(ENTT_HAS_TRACKED_MEMORY_RESOURCE)
|
||||
|
||||
TEST(UninitializedConstructUsingAllocator, UsesAllocatorConstruction) {
|
||||
using string_type = typename test::tracked_memory_resource::string_type;
|
||||
|
||||
test::tracked_memory_resource memory_resource{};
|
||||
std::pmr::polymorphic_allocator<string_type> allocator{&memory_resource};
|
||||
alignas(string_type) std::byte storage[sizeof(string_type)];
|
||||
|
||||
string_type *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<string_type *>(&storage), allocator, test::tracked_memory_resource::default_value);
|
||||
|
||||
ASSERT_GT(memory_resource.do_allocate_counter(), 0u);
|
||||
ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
|
||||
ASSERT_EQ(*value, test::tracked_memory_resource::default_value);
|
||||
|
||||
value->~string_type();
|
||||
}
|
||||
|
||||
#endif
|
22
test/entt/core/monostate.cpp
Normal file
22
test/entt/core/monostate.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/core/monostate.hpp>
|
||||
|
||||
TEST(Monostate, Functionalities) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const bool b_pre = entt::monostate<entt::hashed_string{"foobar"}>{};
|
||||
const int i_pre = entt::monostate<"foobar"_hs>{};
|
||||
|
||||
ASSERT_FALSE(b_pre);
|
||||
ASSERT_EQ(i_pre, int{});
|
||||
|
||||
entt::monostate<"foobar"_hs>{} = true;
|
||||
entt::monostate_v<"foobar"_hs> = 42;
|
||||
|
||||
const bool &b_post = entt::monostate<"foobar"_hs>{};
|
||||
const int &i_post = entt::monostate_v<entt::hashed_string{"foobar"}>;
|
||||
|
||||
ASSERT_TRUE(b_post);
|
||||
ASSERT_EQ(i_post, 42);
|
||||
}
|
38
test/entt/core/tuple.cpp
Normal file
38
test/entt/core/tuple.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include <tuple>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/tuple.hpp>
|
||||
|
||||
TEST(Tuple, IsTuple) {
|
||||
static_assert(!entt::is_tuple_v<int>);
|
||||
static_assert(entt::is_tuple_v<std::tuple<>>);
|
||||
static_assert(entt::is_tuple_v<std::tuple<int>>);
|
||||
static_assert(entt::is_tuple_v<std::tuple<int, char>>);
|
||||
}
|
||||
|
||||
TEST(Tuple, UnwrapTuple) {
|
||||
auto single = std::make_tuple(42);
|
||||
auto multi = std::make_tuple(42, 'c');
|
||||
auto ref = std::forward_as_tuple(std::get<0>(single));
|
||||
|
||||
ASSERT_TRUE((std::is_same_v<decltype(entt::unwrap_tuple(single)), int &>));
|
||||
ASSERT_TRUE((std::is_same_v<decltype(entt::unwrap_tuple(multi)), std::tuple<int, char> &>));
|
||||
ASSERT_TRUE((std::is_same_v<decltype(entt::unwrap_tuple(ref)), int &>));
|
||||
|
||||
ASSERT_TRUE((std::is_same_v<decltype(entt::unwrap_tuple(std::move(single))), int &&>));
|
||||
ASSERT_TRUE((std::is_same_v<decltype(entt::unwrap_tuple(std::move(multi))), std::tuple<int, char> &&>));
|
||||
ASSERT_TRUE((std::is_same_v<decltype(entt::unwrap_tuple(std::move(ref))), int &>));
|
||||
|
||||
ASSERT_TRUE((std::is_same_v<decltype(entt::unwrap_tuple(std::as_const(single))), const int &>));
|
||||
ASSERT_TRUE((std::is_same_v<decltype(entt::unwrap_tuple(std::as_const(multi))), const std::tuple<int, char> &>));
|
||||
ASSERT_TRUE((std::is_same_v<decltype(entt::unwrap_tuple(std::as_const(ref))), int &>));
|
||||
|
||||
ASSERT_EQ(entt::unwrap_tuple(single), 42);
|
||||
ASSERT_EQ(entt::unwrap_tuple(multi), multi);
|
||||
ASSERT_EQ(entt::unwrap_tuple(std::move(ref)), 42);
|
||||
}
|
||||
|
||||
TEST(Tuple, ForwardApply) {
|
||||
ASSERT_EQ(entt::forward_apply{[](auto &&...args) { return sizeof...(args); }}(std::make_tuple()), 0u);
|
||||
ASSERT_EQ(entt::forward_apply{[](int i) { return i; }}(std::make_tuple(42)), 42);
|
||||
ASSERT_EQ(entt::forward_apply{[](auto... args) { return (args + ...); }}(std::make_tuple('a', 1u)), 'b');
|
||||
}
|
116
test/entt/core/type_info.cpp
Normal file
116
test/entt/core/type_info.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/core/type_traits.hpp>
|
||||
|
||||
template<>
|
||||
struct entt::type_name<float> final {
|
||||
[[nodiscard]] static constexpr std::string_view value() noexcept {
|
||||
return std::string_view{""};
|
||||
}
|
||||
};
|
||||
|
||||
TEST(TypeIndex, Functionalities) {
|
||||
ASSERT_EQ(entt::type_index<int>::value(), entt::type_index<int>::value());
|
||||
ASSERT_NE(entt::type_index<int>::value(), entt::type_index<char>::value());
|
||||
ASSERT_NE(entt::type_index<int>::value(), entt::type_index<int &&>::value());
|
||||
ASSERT_NE(entt::type_index<int &>::value(), entt::type_index<const int &>::value());
|
||||
ASSERT_EQ(static_cast<entt::id_type>(entt::type_index<int>{}), entt::type_index<int>::value());
|
||||
}
|
||||
|
||||
TEST(TypeHash, Functionalities) {
|
||||
ASSERT_NE(entt::type_hash<int>::value(), entt::type_hash<const int>::value());
|
||||
ASSERT_NE(entt::type_hash<int>::value(), entt::type_hash<char>::value());
|
||||
ASSERT_EQ(entt::type_hash<int>::value(), entt::type_hash<int>::value());
|
||||
ASSERT_EQ(static_cast<entt::id_type>(entt::type_hash<int>{}), entt::type_hash<int>::value());
|
||||
}
|
||||
|
||||
TEST(TypeName, Functionalities) {
|
||||
ASSERT_EQ(entt::type_name<int>::value(), std::string_view{"int"});
|
||||
ASSERT_EQ(entt::type_name<float>{}.value(), std::string_view{""});
|
||||
|
||||
ASSERT_TRUE((entt::type_name<entt::integral_constant<3>>::value() == std::string_view{"std::integral_constant<int, 3>"})
|
||||
|| (entt::type_name<entt::integral_constant<3>>::value() == std::string_view{"std::__1::integral_constant<int, 3>"})
|
||||
|| (entt::type_name<entt::integral_constant<3>>::value() == std::string_view{"struct std::integral_constant<int,3>"}));
|
||||
|
||||
ASSERT_TRUE(((entt::type_name<entt::type_list<entt::type_list<int, char>, double>>::value()) == std::string_view{"entt::type_list<entt::type_list<int, char>, double>"})
|
||||
|| ((entt::type_name<entt::type_list<entt::type_list<int, char>, double>>::value()) == std::string_view{"struct entt::type_list<struct entt::type_list<int,char>,double>"}));
|
||||
|
||||
ASSERT_EQ(static_cast<std::string_view>(entt::type_name<int>{}), entt::type_name<int>::value());
|
||||
}
|
||||
|
||||
TEST(TypeInfo, Functionalities) {
|
||||
static_assert(std::is_copy_constructible_v<entt::type_info>);
|
||||
static_assert(std::is_move_constructible_v<entt::type_info>);
|
||||
static_assert(std::is_copy_assignable_v<entt::type_info>);
|
||||
static_assert(std::is_move_assignable_v<entt::type_info>);
|
||||
|
||||
entt::type_info info{std::in_place_type<int>};
|
||||
entt::type_info other{std::in_place_type<void>};
|
||||
|
||||
ASSERT_EQ(info, entt::type_info{std::in_place_type<int &>});
|
||||
ASSERT_EQ(info, entt::type_info{std::in_place_type<int &&>});
|
||||
ASSERT_EQ(info, entt::type_info{std::in_place_type<const int &>});
|
||||
|
||||
ASSERT_NE(info, other);
|
||||
ASSERT_TRUE(info == info);
|
||||
ASSERT_FALSE(info != info);
|
||||
|
||||
ASSERT_EQ(info.index(), entt::type_index<int>::value());
|
||||
ASSERT_EQ(info.hash(), entt::type_hash<int>::value());
|
||||
ASSERT_EQ(info.name(), entt::type_name<int>::value());
|
||||
|
||||
other = info;
|
||||
|
||||
ASSERT_EQ(other.index(), entt::type_index<int>::value());
|
||||
ASSERT_EQ(other.hash(), entt::type_hash<int>::value());
|
||||
ASSERT_EQ(other.name(), entt::type_name<int>::value());
|
||||
|
||||
ASSERT_EQ(other.index(), info.index());
|
||||
ASSERT_EQ(other.hash(), info.hash());
|
||||
ASSERT_EQ(other.name(), info.name());
|
||||
|
||||
other = std::move(info);
|
||||
|
||||
ASSERT_EQ(other.index(), entt::type_index<int>::value());
|
||||
ASSERT_EQ(other.hash(), entt::type_hash<int>::value());
|
||||
ASSERT_EQ(other.name(), entt::type_name<int>::value());
|
||||
|
||||
ASSERT_EQ(other.index(), info.index());
|
||||
ASSERT_EQ(other.hash(), info.hash());
|
||||
ASSERT_EQ(other.name(), info.name());
|
||||
}
|
||||
|
||||
TEST(TypeInfo, Order) {
|
||||
entt::type_info rhs = entt::type_id<int>();
|
||||
entt::type_info lhs = entt::type_id<char>();
|
||||
|
||||
// let's adjust the two objects since values are generated at runtime
|
||||
rhs < lhs ? void() : std::swap(lhs, rhs);
|
||||
|
||||
ASSERT_FALSE(lhs < lhs);
|
||||
ASSERT_FALSE(rhs < rhs);
|
||||
|
||||
ASSERT_LT(rhs, lhs);
|
||||
ASSERT_LE(rhs, lhs);
|
||||
|
||||
ASSERT_GT(lhs, rhs);
|
||||
ASSERT_GE(lhs, rhs);
|
||||
}
|
||||
|
||||
TEST(TypeId, Functionalities) {
|
||||
const int value = 42;
|
||||
|
||||
ASSERT_EQ(entt::type_id(value), entt::type_id<int>());
|
||||
ASSERT_EQ(entt::type_id(42), entt::type_id<int>());
|
||||
|
||||
ASSERT_EQ(entt::type_id<int>(), entt::type_id<int>());
|
||||
ASSERT_EQ(entt::type_id<int &>(), entt::type_id<int &&>());
|
||||
ASSERT_EQ(entt::type_id<int &>(), entt::type_id<int>());
|
||||
ASSERT_NE(entt::type_id<int>(), entt::type_id<char>());
|
||||
|
||||
ASSERT_EQ(&entt::type_id<int>(), &entt::type_id<int>());
|
||||
ASSERT_NE(&entt::type_id<int>(), &entt::type_id<void>());
|
||||
}
|
224
test/entt/core/type_traits.cpp
Normal file
224
test/entt/core/type_traits.cpp
Normal file
@ -0,0 +1,224 @@
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/core/type_traits.hpp>
|
||||
|
||||
struct not_comparable {
|
||||
bool operator==(const not_comparable &) const = delete;
|
||||
};
|
||||
|
||||
struct nlohmann_json_like final {
|
||||
using value_type = nlohmann_json_like;
|
||||
|
||||
bool operator==(const nlohmann_json_like &) const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct clazz {
|
||||
char foo(int) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int bar(double, float) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
bool quux;
|
||||
};
|
||||
|
||||
int free_function(int, const double &) {
|
||||
return 42;
|
||||
}
|
||||
|
||||
template<typename, typename Type = void>
|
||||
struct multi_argument_operation {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
TEST(SizeOf, Functionalities) {
|
||||
static_assert(entt::size_of_v<void> == 0u);
|
||||
static_assert(entt::size_of_v<char> == sizeof(char));
|
||||
static_assert(entt::size_of_v<int[]> == 0u);
|
||||
static_assert(entt::size_of_v<int[3]> == sizeof(int[3]));
|
||||
}
|
||||
|
||||
TEST(UnpackAsType, Functionalities) {
|
||||
auto test = [](auto &&...args) {
|
||||
return [](entt::unpack_as_type<int, decltype(args)>... value) {
|
||||
return (value + ... + 0);
|
||||
};
|
||||
};
|
||||
|
||||
ASSERT_EQ(test('c', 42., true)(1, 2, 3), 6);
|
||||
}
|
||||
|
||||
TEST(UnpackAsValue, Functionalities) {
|
||||
auto test = [](auto &&...args) {
|
||||
return (entt::unpack_as_value<2, decltype(args)> + ... + 0);
|
||||
};
|
||||
|
||||
ASSERT_EQ(test('c', 42., true), 6);
|
||||
}
|
||||
|
||||
TEST(IntegralConstant, Functionalities) {
|
||||
entt::integral_constant<3> constant{};
|
||||
|
||||
static_assert(std::is_same_v<typename entt::integral_constant<3>::value_type, int>);
|
||||
static_assert(constant.value == 3);
|
||||
}
|
||||
|
||||
TEST(Choice, Functionalities) {
|
||||
static_assert(std::is_base_of_v<entt::choice_t<0>, entt::choice_t<1>>);
|
||||
static_assert(!std::is_base_of_v<entt::choice_t<1>, entt::choice_t<0>>);
|
||||
}
|
||||
|
||||
TEST(TypeList, Functionalities) {
|
||||
using type = entt::type_list<int, char>;
|
||||
using other = entt::type_list<double>;
|
||||
|
||||
static_assert(type::size == 2u);
|
||||
static_assert(other::size == 1u);
|
||||
|
||||
static_assert(std::is_same_v<decltype(type{} + other{}), entt::type_list<int, char, double>>);
|
||||
static_assert(std::is_same_v<entt::type_list_cat_t<type, other, type, other>, entt::type_list<int, char, double, int, char, double>>);
|
||||
static_assert(std::is_same_v<entt::type_list_cat_t<type, other>, entt::type_list<int, char, double>>);
|
||||
static_assert(std::is_same_v<entt::type_list_cat_t<type, type>, entt::type_list<int, char, int, char>>);
|
||||
static_assert(std::is_same_v<entt::type_list_unique_t<entt::type_list_cat_t<type, type>>, entt::type_list<int, char>>);
|
||||
|
||||
static_assert(entt::type_list_contains_v<type, int>);
|
||||
static_assert(entt::type_list_contains_v<type, char>);
|
||||
static_assert(!entt::type_list_contains_v<type, double>);
|
||||
|
||||
static_assert(std::is_same_v<entt::type_list_element_t<0u, type>, int>);
|
||||
static_assert(std::is_same_v<entt::type_list_element_t<1u, type>, char>);
|
||||
static_assert(std::is_same_v<entt::type_list_element_t<0u, other>, double>);
|
||||
|
||||
static_assert(entt::type_list_index_v<int, type> == 0u);
|
||||
static_assert(entt::type_list_index_v<char, type> == 1u);
|
||||
static_assert(entt::type_list_index_v<double, other> == 0u);
|
||||
|
||||
static_assert(std::is_same_v<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<float, bool>>, entt::type_list<int, char, double>>);
|
||||
static_assert(std::is_same_v<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<int, char, double>>, entt::type_list<>>);
|
||||
static_assert(std::is_same_v<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<int, char>>, entt::type_list<double>>);
|
||||
static_assert(std::is_same_v<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<char, double>>, entt::type_list<int>>);
|
||||
static_assert(std::is_same_v<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<char>>, entt::type_list<int, double>>);
|
||||
|
||||
static_assert(std::is_same_v<entt::type_list_transform_t<entt::type_list<int, char>, entt::type_identity>, entt::type_list<int, char>>);
|
||||
static_assert(std::is_same_v<entt::type_list_transform_t<entt::type_list<int, char>, std::add_const>, entt::type_list<const int, const char>>);
|
||||
static_assert(std::is_same_v<entt::type_list_transform_t<entt::type_list<int, char>, multi_argument_operation>, entt::type_list<void, void>>);
|
||||
}
|
||||
|
||||
TEST(ValueList, Functionalities) {
|
||||
using value = entt::value_list<0, 2>;
|
||||
using other = entt::value_list<1>;
|
||||
|
||||
static_assert(value::size == 2u);
|
||||
static_assert(other::size == 1u);
|
||||
|
||||
static_assert(std::is_same_v<decltype(value{} + other{}), entt::value_list<0, 2, 1>>);
|
||||
static_assert(std::is_same_v<entt::value_list_cat_t<value, other, value, other>, entt::value_list<0, 2, 1, 0, 2, 1>>);
|
||||
static_assert(std::is_same_v<entt::value_list_cat_t<value, other>, entt::value_list<0, 2, 1>>);
|
||||
static_assert(std::is_same_v<entt::value_list_cat_t<value, value>, entt::value_list<0, 2, 0, 2>>);
|
||||
|
||||
static_assert(entt::value_list_element_v<0u, value> == 0);
|
||||
static_assert(entt::value_list_element_v<1u, value> == 2);
|
||||
static_assert(entt::value_list_element_v<0u, other> == 1);
|
||||
}
|
||||
|
||||
TEST(IsApplicable, Functionalities) {
|
||||
static_assert(entt::is_applicable_v<void(int, char), std::tuple<double, char>>);
|
||||
static_assert(!entt::is_applicable_v<void(int, char), std::tuple<int>>);
|
||||
|
||||
static_assert(entt::is_applicable_r_v<float, int(int, char), std::tuple<double, char>>);
|
||||
static_assert(!entt::is_applicable_r_v<float, void(int, char), std::tuple<double, char>>);
|
||||
static_assert(!entt::is_applicable_r_v<int, int(int, char), std::tuple<void>>);
|
||||
}
|
||||
|
||||
TEST(IsComplete, Functionalities) {
|
||||
static_assert(!entt::is_complete_v<void>);
|
||||
static_assert(entt::is_complete_v<int>);
|
||||
}
|
||||
|
||||
TEST(IsIterator, Functionalities) {
|
||||
static_assert(!entt::is_iterator_v<void>);
|
||||
static_assert(!entt::is_iterator_v<int>);
|
||||
|
||||
static_assert(!entt::is_iterator_v<void *>);
|
||||
static_assert(entt::is_iterator_v<int *>);
|
||||
|
||||
static_assert(entt::is_iterator_v<std::vector<int>::iterator>);
|
||||
static_assert(entt::is_iterator_v<std::vector<int>::const_iterator>);
|
||||
static_assert(entt::is_iterator_v<std::vector<int>::reverse_iterator>);
|
||||
}
|
||||
|
||||
TEST(IsEBCOEligible, Functionalities) {
|
||||
static_assert(entt::is_ebco_eligible_v<not_comparable>);
|
||||
static_assert(!entt::is_ebco_eligible_v<nlohmann_json_like>);
|
||||
static_assert(!entt::is_ebco_eligible_v<double>);
|
||||
static_assert(!entt::is_ebco_eligible_v<void>);
|
||||
}
|
||||
|
||||
TEST(IsTransparent, Functionalities) {
|
||||
static_assert(!entt::is_transparent_v<std::less<int>>);
|
||||
static_assert(entt::is_transparent_v<std::less<void>>);
|
||||
static_assert(!entt::is_transparent_v<std::logical_not<double>>);
|
||||
static_assert(entt::is_transparent_v<std::logical_not<void>>);
|
||||
}
|
||||
|
||||
TEST(IsEqualityComparable, Functionalities) {
|
||||
static_assert(entt::is_equality_comparable_v<int>);
|
||||
static_assert(entt::is_equality_comparable_v<const int>);
|
||||
static_assert(entt::is_equality_comparable_v<std::vector<int>>);
|
||||
static_assert(entt::is_equality_comparable_v<std::vector<std::vector<int>>>);
|
||||
static_assert(entt::is_equality_comparable_v<std::unordered_map<int, int>>);
|
||||
static_assert(entt::is_equality_comparable_v<std::unordered_map<int, std::unordered_map<int, char>>>);
|
||||
static_assert(entt::is_equality_comparable_v<std::pair<const int, int>>);
|
||||
static_assert(entt::is_equality_comparable_v<std::pair<const int, std::unordered_map<int, char>>>);
|
||||
static_assert(entt::is_equality_comparable_v<std::vector<not_comparable>::iterator>);
|
||||
static_assert(entt::is_equality_comparable_v<nlohmann_json_like>);
|
||||
|
||||
static_assert(!entt::is_equality_comparable_v<not_comparable>);
|
||||
static_assert(!entt::is_equality_comparable_v<const not_comparable>);
|
||||
static_assert(!entt::is_equality_comparable_v<std::vector<not_comparable>>);
|
||||
static_assert(!entt::is_equality_comparable_v<std::vector<std::vector<not_comparable>>>);
|
||||
static_assert(!entt::is_equality_comparable_v<std::unordered_map<int, not_comparable>>);
|
||||
static_assert(!entt::is_equality_comparable_v<std::unordered_map<int, std::unordered_map<int, not_comparable>>>);
|
||||
static_assert(!entt::is_equality_comparable_v<std::pair<const int, not_comparable>>);
|
||||
static_assert(!entt::is_equality_comparable_v<std::pair<const int, std::unordered_map<int, not_comparable>>>);
|
||||
static_assert(!entt::is_equality_comparable_v<void>);
|
||||
}
|
||||
|
||||
TEST(ConstnessAs, Functionalities) {
|
||||
static_assert(std::is_same_v<entt::constness_as_t<int, char>, int>);
|
||||
static_assert(std::is_same_v<entt::constness_as_t<const int, char>, int>);
|
||||
static_assert(std::is_same_v<entt::constness_as_t<int, const char>, const int>);
|
||||
static_assert(std::is_same_v<entt::constness_as_t<const int, const char>, const int>);
|
||||
}
|
||||
|
||||
TEST(MemberClass, Functionalities) {
|
||||
static_assert(std::is_same_v<clazz, entt::member_class_t<decltype(&clazz::foo)>>);
|
||||
static_assert(std::is_same_v<clazz, entt::member_class_t<decltype(&clazz::bar)>>);
|
||||
static_assert(std::is_same_v<clazz, entt::member_class_t<decltype(&clazz::quux)>>);
|
||||
}
|
||||
|
||||
TEST(NthArgument, Functionalities) {
|
||||
static_assert(std::is_same_v<entt::nth_argument_t<0u, &free_function>, int>);
|
||||
static_assert(std::is_same_v<entt::nth_argument_t<1u, &free_function>, const double &>);
|
||||
static_assert(std::is_same_v<entt::nth_argument_t<0u, &clazz::bar>, double>);
|
||||
static_assert(std::is_same_v<entt::nth_argument_t<1u, &clazz::bar>, float>);
|
||||
static_assert(std::is_same_v<entt::nth_argument_t<0u, &clazz::quux>, bool>);
|
||||
|
||||
ASSERT_EQ(free_function(entt::nth_argument_t<0u, &free_function>{}, entt::nth_argument_t<1u, &free_function>{}), 42);
|
||||
}
|
||||
|
||||
TEST(Tag, Functionalities) {
|
||||
using namespace entt::literals;
|
||||
static_assert(entt::tag<"foobar"_hs>::value == entt::hashed_string::value("foobar"));
|
||||
static_assert(std::is_same_v<typename entt::tag<"foobar"_hs>::value_type, entt::id_type>);
|
||||
}
|
61
test/entt/core/utility.cpp
Normal file
61
test/entt/core/utility.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_traits.hpp>
|
||||
#include <entt/core/utility.hpp>
|
||||
|
||||
struct functions {
|
||||
static void foo(int) {}
|
||||
static void foo() {}
|
||||
|
||||
void bar(int) {}
|
||||
void bar() {}
|
||||
};
|
||||
|
||||
TEST(Identity, Functionalities) {
|
||||
entt::identity identity;
|
||||
int value = 42;
|
||||
|
||||
ASSERT_TRUE(entt::is_transparent_v<entt::identity>);
|
||||
ASSERT_EQ(identity(value), value);
|
||||
ASSERT_EQ(&identity(value), &value);
|
||||
}
|
||||
|
||||
TEST(Overload, Functionalities) {
|
||||
ASSERT_EQ(entt::overload<void(int)>(&functions::foo), static_cast<void (*)(int)>(&functions::foo));
|
||||
ASSERT_EQ(entt::overload<void()>(&functions::foo), static_cast<void (*)()>(&functions::foo));
|
||||
|
||||
ASSERT_EQ(entt::overload<void(int)>(&functions::bar), static_cast<void (functions::*)(int)>(&functions::bar));
|
||||
ASSERT_EQ(entt::overload<void()>(&functions::bar), static_cast<void (functions::*)()>(&functions::bar));
|
||||
|
||||
functions instance;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(entt::overload<void(int)>(&functions::foo)(0));
|
||||
ASSERT_NO_FATAL_FAILURE(entt::overload<void()>(&functions::foo)());
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE((instance.*entt::overload<void(int)>(&functions::bar))(0));
|
||||
ASSERT_NO_FATAL_FAILURE((instance.*entt::overload<void()>(&functions::bar))());
|
||||
}
|
||||
|
||||
TEST(Overloaded, Functionalities) {
|
||||
int iv = 0;
|
||||
char cv = '\0';
|
||||
|
||||
entt::overloaded func{
|
||||
[&iv](int value) { iv = value; },
|
||||
[&cv](char value) { cv = value; }};
|
||||
|
||||
func(42);
|
||||
func('c');
|
||||
|
||||
ASSERT_EQ(iv, 42);
|
||||
ASSERT_EQ(cv, 'c');
|
||||
}
|
||||
|
||||
TEST(YCombinator, Functionalities) {
|
||||
entt::y_combinator gauss([](const auto &self, auto value) -> unsigned int {
|
||||
return value ? (value + self(value - 1u)) : 0;
|
||||
});
|
||||
|
||||
ASSERT_EQ(gauss(3u), 3u * 4u / 2u);
|
||||
ASSERT_EQ(std::as_const(gauss)(7u), 7u * 8u / 2u);
|
||||
}
|
79
test/entt/entity/component.cpp
Normal file
79
test/entt/entity/component.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/config/config.h>
|
||||
#include <entt/entity/component.hpp>
|
||||
|
||||
struct empty {};
|
||||
|
||||
struct non_empty {
|
||||
int value;
|
||||
};
|
||||
|
||||
struct non_movable {
|
||||
non_movable() = default;
|
||||
non_movable(const non_movable &) = delete;
|
||||
non_movable &operator=(const non_movable &) = delete;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct self_contained {
|
||||
static constexpr auto in_place_delete = true;
|
||||
static constexpr auto page_size = 4u;
|
||||
};
|
||||
|
||||
struct traits_based {};
|
||||
|
||||
template<>
|
||||
struct entt::component_traits<traits_based> {
|
||||
using type = traits_based;
|
||||
static constexpr auto in_place_delete = false;
|
||||
static constexpr auto page_size = 8u;
|
||||
};
|
||||
|
||||
TEST(Component, VoidType) {
|
||||
using traits = entt::component_traits<void>;
|
||||
|
||||
static_assert(traits::in_place_delete);
|
||||
static_assert(entt::ignore_as_empty_v<typename traits::type>);
|
||||
// we don't really care about this thanks to ignore_as_empty_v
|
||||
static_assert(traits::page_size != 0u);
|
||||
}
|
||||
|
||||
TEST(Component, Empty) {
|
||||
using traits = entt::component_traits<empty>;
|
||||
|
||||
static_assert(!traits::in_place_delete);
|
||||
static_assert(entt::ignore_as_empty_v<typename traits::type>);
|
||||
static_assert(traits::page_size == 0u);
|
||||
}
|
||||
|
||||
TEST(Component, NonEmpty) {
|
||||
using traits = entt::component_traits<non_empty>;
|
||||
|
||||
static_assert(!traits::in_place_delete);
|
||||
static_assert(!entt::ignore_as_empty_v<typename traits::type>);
|
||||
static_assert(traits::page_size == ENTT_PACKED_PAGE);
|
||||
}
|
||||
|
||||
TEST(Component, NonMovable) {
|
||||
using traits = entt::component_traits<non_movable>;
|
||||
|
||||
static_assert(traits::in_place_delete);
|
||||
static_assert(!entt::ignore_as_empty_v<typename traits::type>);
|
||||
static_assert(traits::page_size == ENTT_PACKED_PAGE);
|
||||
}
|
||||
|
||||
TEST(Component, SelfContained) {
|
||||
using traits = entt::component_traits<self_contained>;
|
||||
|
||||
static_assert(traits::in_place_delete);
|
||||
static_assert(!entt::ignore_as_empty_v<typename traits::type>);
|
||||
static_assert(traits::page_size == 4u);
|
||||
}
|
||||
|
||||
TEST(Component, TraitsBased) {
|
||||
using traits = entt::component_traits<traits_based>;
|
||||
|
||||
static_assert(!traits::in_place_delete);
|
||||
static_assert(!entt::ignore_as_empty_v<typename traits::type>);
|
||||
static_assert(traits::page_size == 8u);
|
||||
}
|
92
test/entt/entity/entity.cpp
Normal file
92
test/entt/entity/entity.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
TEST(Entity, Traits) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
constexpr entt::entity tombstone = entt::tombstone;
|
||||
constexpr entt::entity null = entt::null;
|
||||
entt::registry registry{};
|
||||
|
||||
registry.destroy(registry.create());
|
||||
const auto entity = registry.create();
|
||||
const auto other = registry.create();
|
||||
|
||||
ASSERT_EQ(entt::to_integral(entity), entt::to_integral(entity));
|
||||
ASSERT_NE(entt::to_integral(entity), entt::to_integral<entt::entity>(entt::null));
|
||||
ASSERT_NE(entt::to_integral(entity), entt::to_integral(entt::entity{}));
|
||||
|
||||
ASSERT_EQ(entt::to_entity(entity), 0u);
|
||||
ASSERT_EQ(entt::to_version(entity), 1u);
|
||||
ASSERT_EQ(entt::to_entity(other), 1u);
|
||||
ASSERT_EQ(entt::to_version(other), 0u);
|
||||
|
||||
ASSERT_EQ(traits_type::construct(entt::to_entity(entity), entt::to_version(entity)), entity);
|
||||
ASSERT_EQ(traits_type::construct(entt::to_entity(other), entt::to_version(other)), other);
|
||||
ASSERT_NE(traits_type::construct(entt::to_entity(entity), {}), entity);
|
||||
|
||||
ASSERT_EQ(traits_type::construct(entt::to_entity(other), entt::to_version(entity)), traits_type::combine(entt::to_integral(other), entt::to_integral(entity)));
|
||||
|
||||
ASSERT_EQ(traits_type::combine(entt::tombstone, entt::null), tombstone);
|
||||
ASSERT_EQ(traits_type::combine(entt::null, entt::tombstone), null);
|
||||
}
|
||||
|
||||
TEST(Entity, Null) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
constexpr entt::entity null = entt::null;
|
||||
|
||||
ASSERT_FALSE(entt::entity{} == entt::null);
|
||||
ASSERT_TRUE(entt::null == entt::null);
|
||||
ASSERT_FALSE(entt::null != entt::null);
|
||||
|
||||
entt::registry registry{};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_EQ(traits_type::combine(entt::null, entt::to_integral(entity)), (traits_type::construct(entt::to_entity(null), entt::to_version(entity))));
|
||||
ASSERT_EQ(traits_type::combine(entt::null, entt::to_integral(null)), null);
|
||||
ASSERT_EQ(traits_type::combine(entt::null, entt::tombstone), null);
|
||||
|
||||
registry.emplace<int>(entity, 42);
|
||||
|
||||
ASSERT_FALSE(entity == entt::null);
|
||||
ASSERT_FALSE(entt::null == entity);
|
||||
|
||||
ASSERT_TRUE(entity != entt::null);
|
||||
ASSERT_TRUE(entt::null != entity);
|
||||
|
||||
const entt::entity other = entt::null;
|
||||
|
||||
ASSERT_FALSE(registry.valid(other));
|
||||
ASSERT_NE(registry.create(other), other);
|
||||
}
|
||||
|
||||
TEST(Entity, Tombstone) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
constexpr entt::entity tombstone = entt::tombstone;
|
||||
|
||||
ASSERT_FALSE(entt::entity{} == entt::tombstone);
|
||||
ASSERT_TRUE(entt::tombstone == entt::tombstone);
|
||||
ASSERT_FALSE(entt::tombstone != entt::tombstone);
|
||||
|
||||
entt::registry registry{};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_EQ(traits_type::combine(entt::to_integral(entity), entt::tombstone), (traits_type::construct(entt::to_entity(entity), entt::to_version(tombstone))));
|
||||
ASSERT_EQ(traits_type::combine(entt::tombstone, entt::to_integral(tombstone)), tombstone);
|
||||
ASSERT_EQ(traits_type::combine(entt::tombstone, entt::null), tombstone);
|
||||
|
||||
registry.emplace<int>(entity, 42);
|
||||
|
||||
ASSERT_FALSE(entity == entt::tombstone);
|
||||
ASSERT_FALSE(entt::tombstone == entity);
|
||||
|
||||
ASSERT_TRUE(entity != entt::tombstone);
|
||||
ASSERT_TRUE(entt::tombstone != entity);
|
||||
|
||||
constexpr auto vers = entt::to_version(tombstone);
|
||||
const auto other = traits_type::construct(entt::to_entity(entity), vers);
|
||||
|
||||
ASSERT_FALSE(registry.valid(entt::tombstone));
|
||||
ASSERT_NE(registry.destroy(entity, vers), vers);
|
||||
ASSERT_NE(registry.create(other), other);
|
||||
}
|
1468
test/entt/entity/group.cpp
Normal file
1468
test/entt/entity/group.cpp
Normal file
File diff suppressed because it is too large
Load Diff
295
test/entt/entity/handle.cpp
Normal file
295
test/entt/entity/handle.cpp
Normal file
@ -0,0 +1,295 @@
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/handle.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
TEST(BasicHandle, Assumptions) {
|
||||
static_assert(std::is_trivially_copyable_v<entt::handle>);
|
||||
static_assert(std::is_trivially_assignable_v<entt::handle, entt::handle>);
|
||||
static_assert(std::is_trivially_destructible_v<entt::handle>);
|
||||
|
||||
static_assert(std::is_trivially_copyable_v<entt::const_handle>);
|
||||
static_assert(std::is_trivially_assignable_v<entt::const_handle, entt::const_handle>);
|
||||
static_assert(std::is_trivially_destructible_v<entt::const_handle>);
|
||||
}
|
||||
|
||||
TEST(BasicHandle, DeductionGuide) {
|
||||
static_assert(std::is_same_v<decltype(entt::basic_handle{std::declval<entt::registry &>(), {}}), entt::basic_handle<entt::registry>>);
|
||||
static_assert(std::is_same_v<decltype(entt::basic_handle{std::declval<const entt::registry &>(), {}}), entt::basic_handle<const entt::registry>>);
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Construction) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
entt::handle handle{registry, entity};
|
||||
entt::const_handle chandle{std::as_const(registry), entity};
|
||||
|
||||
ASSERT_FALSE(entt::null == handle.entity());
|
||||
ASSERT_EQ(entity, handle);
|
||||
ASSERT_TRUE(handle);
|
||||
|
||||
ASSERT_FALSE(entt::null == chandle.entity());
|
||||
ASSERT_EQ(entity, chandle);
|
||||
ASSERT_TRUE(chandle);
|
||||
|
||||
ASSERT_EQ(handle, chandle);
|
||||
|
||||
static_assert(std::is_same_v<entt::registry *, decltype(handle.registry())>);
|
||||
static_assert(std::is_same_v<const entt::registry *, decltype(chandle.registry())>);
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Invalidation) {
|
||||
entt::handle handle;
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_EQ(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entt::entity{entt::null});
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
handle = {registry, entity};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_NE(handle.entity(), entt::entity{entt::null});
|
||||
|
||||
handle = {};
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_EQ(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entt::entity{entt::null});
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Destruction) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_TRUE(handle.valid());
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entity);
|
||||
|
||||
handle.destroy(traits_type::to_version(entity));
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_FALSE(handle.valid());
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entity);
|
||||
ASSERT_EQ(registry.current(entity), typename entt::registry::version_type{});
|
||||
|
||||
handle = entt::handle{registry, registry.create()};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_TRUE(handle.valid());
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entity);
|
||||
|
||||
handle.destroy();
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_FALSE(handle.valid());
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_EQ(handle.entity(), entity);
|
||||
ASSERT_NE(registry.current(entity), typename entt::registry::version_type{});
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Comparison) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
entt::handle handle{registry, entity};
|
||||
entt::const_handle chandle = handle;
|
||||
|
||||
ASSERT_NE(handle, entt::handle{});
|
||||
ASSERT_FALSE(handle == entt::handle{});
|
||||
ASSERT_TRUE(handle != entt::handle{});
|
||||
|
||||
ASSERT_NE(chandle, entt::const_handle{});
|
||||
ASSERT_FALSE(chandle == entt::const_handle{});
|
||||
ASSERT_TRUE(chandle != entt::const_handle{});
|
||||
|
||||
ASSERT_EQ(handle, chandle);
|
||||
ASSERT_TRUE(handle == chandle);
|
||||
ASSERT_FALSE(handle != chandle);
|
||||
|
||||
ASSERT_EQ(entt::handle{}, entt::const_handle{});
|
||||
ASSERT_TRUE(entt::handle{} == entt::const_handle{});
|
||||
ASSERT_FALSE(entt::handle{} != entt::const_handle{});
|
||||
|
||||
handle = {};
|
||||
chandle = {};
|
||||
|
||||
ASSERT_EQ(handle, entt::handle{});
|
||||
ASSERT_TRUE(handle == entt::handle{});
|
||||
ASSERT_FALSE(handle != entt::handle{});
|
||||
|
||||
ASSERT_EQ(chandle, entt::const_handle{});
|
||||
ASSERT_TRUE(chandle == entt::const_handle{});
|
||||
ASSERT_FALSE(chandle != entt::const_handle{});
|
||||
|
||||
entt::registry other;
|
||||
const auto entt = other.create();
|
||||
|
||||
handle = {registry, entity};
|
||||
chandle = {other, entt};
|
||||
|
||||
ASSERT_NE(handle, chandle);
|
||||
ASSERT_FALSE(chandle == handle);
|
||||
ASSERT_TRUE(chandle != handle);
|
||||
ASSERT_EQ(handle.entity(), chandle.entity());
|
||||
ASSERT_NE(handle.registry(), chandle.registry());
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Component) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
entt::handle_view<int, char, double> handle{registry, entity};
|
||||
|
||||
ASSERT_EQ(3, handle.emplace<int>(3));
|
||||
ASSERT_EQ('c', handle.emplace_or_replace<char>('c'));
|
||||
ASSERT_EQ(.3, handle.emplace_or_replace<double>(.3));
|
||||
|
||||
const auto &patched = handle.patch<int>([](auto &comp) { comp = 42; });
|
||||
|
||||
ASSERT_EQ(42, patched);
|
||||
ASSERT_EQ('a', handle.replace<char>('a'));
|
||||
ASSERT_TRUE((handle.all_of<int, char, double>()));
|
||||
ASSERT_EQ((std::make_tuple(42, 'a', .3)), (handle.get<int, char, double>()));
|
||||
|
||||
handle.erase<char, double>();
|
||||
|
||||
ASSERT_TRUE(registry.storage<char>().empty());
|
||||
ASSERT_TRUE(registry.storage<double>().empty());
|
||||
ASSERT_EQ(0u, (handle.remove<char, double>()));
|
||||
|
||||
for(auto [id, pool]: handle.storage()) {
|
||||
ASSERT_EQ(id, entt::type_id<int>().hash());
|
||||
ASSERT_TRUE(pool.contains(handle.entity()));
|
||||
}
|
||||
|
||||
ASSERT_TRUE((handle.any_of<int, char, double>()));
|
||||
ASSERT_FALSE((handle.all_of<int, char, double>()));
|
||||
ASSERT_FALSE(handle.orphan());
|
||||
|
||||
ASSERT_EQ(1u, (handle.remove<int>()));
|
||||
ASSERT_TRUE(registry.storage<int>().empty());
|
||||
ASSERT_TRUE(handle.orphan());
|
||||
|
||||
ASSERT_EQ(42, handle.get_or_emplace<int>(42));
|
||||
ASSERT_EQ(42, handle.get_or_emplace<int>(1));
|
||||
ASSERT_EQ(42, handle.get<int>());
|
||||
|
||||
ASSERT_EQ(42, *handle.try_get<int>());
|
||||
ASSERT_EQ(nullptr, handle.try_get<char>());
|
||||
ASSERT_EQ(nullptr, std::get<1>(handle.try_get<int, char, double>()));
|
||||
}
|
||||
|
||||
TEST(BasicHandle, FromEntity) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity, 42);
|
||||
registry.emplace<char>(entity, 'c');
|
||||
|
||||
entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_EQ(entity, handle.entity());
|
||||
ASSERT_TRUE((handle.all_of<int, char>()));
|
||||
ASSERT_EQ(handle.get<int>(), 42);
|
||||
ASSERT_EQ(handle.get<char>(), 'c');
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Lifetime) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
auto *handle = new entt::handle{registry, entity};
|
||||
handle->emplace<int>();
|
||||
|
||||
ASSERT_FALSE(registry.storage<int>().empty());
|
||||
ASSERT_FALSE(registry.empty());
|
||||
|
||||
registry.each([handle](const auto e) {
|
||||
ASSERT_EQ(handle->entity(), e);
|
||||
});
|
||||
|
||||
delete handle;
|
||||
|
||||
ASSERT_FALSE(registry.storage<int>().empty());
|
||||
ASSERT_FALSE(registry.empty());
|
||||
}
|
||||
|
||||
TEST(BasicHandle, ImplicitConversions) {
|
||||
entt::registry registry;
|
||||
const entt::handle handle{registry, registry.create()};
|
||||
const entt::const_handle chandle = handle;
|
||||
const entt::handle_view<int, char> vhandle = handle;
|
||||
const entt::const_handle_view<int> cvhandle = vhandle;
|
||||
|
||||
handle.emplace<int>(42);
|
||||
|
||||
ASSERT_EQ(handle.get<int>(), chandle.get<int>());
|
||||
ASSERT_EQ(chandle.get<int>(), vhandle.get<int>());
|
||||
ASSERT_EQ(vhandle.get<int>(), cvhandle.get<int>());
|
||||
ASSERT_EQ(cvhandle.get<int>(), 42);
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Storage) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
entt::handle handle{registry, entity};
|
||||
entt::const_handle chandle{std::as_const(registry), entity};
|
||||
|
||||
static_assert(std::is_same_v<decltype(*handle.storage().begin()), std::pair<entt::id_type, entt::sparse_set &>>);
|
||||
static_assert(std::is_same_v<decltype(*chandle.storage().begin()), std::pair<entt::id_type, const entt::sparse_set &>>);
|
||||
|
||||
ASSERT_EQ(handle.storage().begin(), handle.storage().end());
|
||||
ASSERT_EQ(chandle.storage().begin(), chandle.storage().end());
|
||||
|
||||
registry.storage<double>();
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_NE(handle.storage().begin(), handle.storage().end());
|
||||
ASSERT_NE(chandle.storage().begin(), chandle.storage().end());
|
||||
|
||||
ASSERT_EQ(++handle.storage().begin(), handle.storage().end());
|
||||
ASSERT_EQ(++chandle.storage().begin(), chandle.storage().end());
|
||||
|
||||
ASSERT_EQ(handle.storage().begin()->second.type(), entt::type_id<int>());
|
||||
ASSERT_EQ(chandle.storage().begin()->second.type(), entt::type_id<int>());
|
||||
}
|
||||
|
||||
TEST(BasicHandle, HandleStorageIterator) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<double>(entity);
|
||||
|
||||
auto test = [](auto iterable) {
|
||||
auto end{iterable.begin()};
|
||||
decltype(end) begin{};
|
||||
begin = iterable.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, iterable.cbegin());
|
||||
ASSERT_EQ(end, iterable.cend());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
};
|
||||
|
||||
test(entt::handle{registry, entity}.storage());
|
||||
test(entt::const_handle{std::as_const(registry), entity}.storage());
|
||||
}
|
126
test/entt/entity/helper.cpp
Normal file
126
test/entt/entity/helper.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/helper.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
struct clazz {
|
||||
void func(entt::registry &, entt::entity curr) {
|
||||
entt = curr;
|
||||
}
|
||||
|
||||
entt::entity entt{entt::null};
|
||||
};
|
||||
|
||||
struct stable_type {
|
||||
static constexpr auto in_place_delete = true;
|
||||
int value;
|
||||
};
|
||||
|
||||
TEST(Helper, AsView) {
|
||||
entt::registry registry;
|
||||
const entt::registry cregistry;
|
||||
|
||||
([](entt::view<entt::get_t<int>>) {})(entt::as_view{registry});
|
||||
([](entt::view<entt::get_t<char, double>, entt::exclude_t<int>>) {})(entt::as_view{registry});
|
||||
([](entt::view<entt::get_t<const char, double>, entt::exclude_t<const int>>) {})(entt::as_view{registry});
|
||||
([](entt::view<entt::get_t<const char, const double>, entt::exclude_t<const int>>) {})(entt::as_view{cregistry});
|
||||
}
|
||||
|
||||
TEST(Helper, AsGroup) {
|
||||
entt::registry registry;
|
||||
const entt::registry cregistry;
|
||||
|
||||
([](entt::group<entt::owned_t<double>, entt::get_t<char>, entt::exclude_t<int>>) {})(entt::as_group{registry});
|
||||
([](entt::group<entt::owned_t<double>, entt::get_t<const char>, entt::exclude_t<const int>>) {})(entt::as_group{registry});
|
||||
([](entt::group<entt::owned_t<const double>, entt::get_t<const char>, entt::exclude_t<const int>>) {})(entt::as_group{cregistry});
|
||||
}
|
||||
|
||||
TEST(Helper, Invoke) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.on_construct<clazz>().connect<entt::invoke<&clazz::func>>();
|
||||
registry.emplace<clazz>(entity);
|
||||
|
||||
ASSERT_EQ(entity, registry.get<clazz>(entity).entt);
|
||||
}
|
||||
|
||||
TEST(Helper, ToEntity) {
|
||||
entt::registry registry;
|
||||
const entt::entity null = entt::null;
|
||||
constexpr auto page_size = entt::component_traits<int>::page_size;
|
||||
const int value = 42;
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, 42), null);
|
||||
ASSERT_EQ(entt::to_entity(registry, value), null);
|
||||
|
||||
const auto entity = registry.create();
|
||||
auto &&storage = registry.storage<int>();
|
||||
storage.emplace(entity);
|
||||
|
||||
while(storage.size() < (page_size - 1u)) {
|
||||
storage.emplace(registry.create(), value);
|
||||
}
|
||||
|
||||
const auto other = registry.create();
|
||||
const auto next = registry.create();
|
||||
|
||||
registry.emplace<int>(other);
|
||||
registry.emplace<int>(next);
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(entity)), entity);
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(other)), other);
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(next)), next);
|
||||
|
||||
ASSERT_EQ(®istry.get<int>(entity) + page_size - 1u, ®istry.get<int>(other));
|
||||
|
||||
registry.destroy(other);
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(entity)), entity);
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<int>(next)), next);
|
||||
|
||||
ASSERT_EQ(®istry.get<int>(entity) + page_size - 1u, ®istry.get<int>(next));
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, 42), null);
|
||||
ASSERT_EQ(entt::to_entity(registry, value), null);
|
||||
}
|
||||
|
||||
TEST(Helper, ToEntityStableType) {
|
||||
entt::registry registry;
|
||||
const entt::entity null = entt::null;
|
||||
constexpr auto page_size = entt::component_traits<stable_type>::page_size;
|
||||
const stable_type value{42};
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, stable_type{42}), null);
|
||||
ASSERT_EQ(entt::to_entity(registry, value), null);
|
||||
|
||||
const auto entity = registry.create();
|
||||
auto &&storage = registry.storage<stable_type>();
|
||||
registry.emplace<stable_type>(entity);
|
||||
|
||||
while(storage.size() < (page_size - 2u)) {
|
||||
storage.emplace(registry.create(), value);
|
||||
}
|
||||
|
||||
const auto other = registry.create();
|
||||
const auto next = registry.create();
|
||||
|
||||
registry.emplace<stable_type>(other);
|
||||
registry.emplace<stable_type>(next);
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(entity)), entity);
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(other)), other);
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(next)), next);
|
||||
|
||||
ASSERT_EQ(®istry.get<stable_type>(entity) + page_size - 2u, ®istry.get<stable_type>(other));
|
||||
|
||||
registry.destroy(other);
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(entity)), entity);
|
||||
ASSERT_EQ(entt::to_entity(registry, registry.get<stable_type>(next)), next);
|
||||
|
||||
ASSERT_EQ(®istry.get<stable_type>(entity) + page_size - 1u, ®istry.get<stable_type>(next));
|
||||
|
||||
ASSERT_EQ(entt::to_entity(registry, stable_type{42}), null);
|
||||
ASSERT_EQ(entt::to_entity(registry, value), null);
|
||||
}
|
371
test/entt/entity/observer.cpp
Normal file
371
test/entt/entity/observer.cpp
Normal file
@ -0,0 +1,371 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/observer.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
TEST(Observer, Functionalities) {
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, entt::collector.group<int>()};
|
||||
|
||||
ASSERT_EQ(observer.size(), 0u);
|
||||
ASSERT_TRUE(observer.empty());
|
||||
ASSERT_EQ(observer.begin(), observer.end());
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
ASSERT_NE(observer.begin(), observer.end());
|
||||
ASSERT_EQ(++observer.begin(), observer.end());
|
||||
ASSERT_EQ(*observer.begin(), entity);
|
||||
|
||||
observer.clear();
|
||||
|
||||
ASSERT_EQ(observer.size(), 0u);
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
observer.disconnect();
|
||||
registry.erase<int>(entity);
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 0u);
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, AllOf) {
|
||||
constexpr auto collector =
|
||||
entt::collector
|
||||
.group<int, char>(entt::exclude<float>)
|
||||
.group<int, double>();
|
||||
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, collector};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
registry.emplace<double>(entity);
|
||||
|
||||
ASSERT_FALSE(observer.empty());
|
||||
|
||||
registry.erase<int>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<float>(entity);
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_FALSE(observer.empty());
|
||||
|
||||
registry.erase<double>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<double>(entity);
|
||||
observer.clear();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
observer.disconnect();
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
registry.emplace_or_replace<char>(entity);
|
||||
registry.erase<float>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, AllOfFiltered) {
|
||||
constexpr auto collector =
|
||||
entt::collector
|
||||
.group<int>()
|
||||
.where<char>(entt::exclude<double>);
|
||||
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, collector};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 0u);
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.erase<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
registry.emplace<double>(entity);
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.erase<int>(entity);
|
||||
registry.erase<double>(entity);
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
registry.emplace<double>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.erase<double>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
observer.disconnect();
|
||||
registry.erase<int>(entity);
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, Observe) {
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, entt::collector.update<int>().update<char>()};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
observer.clear();
|
||||
registry.replace<char>(entity);
|
||||
|
||||
ASSERT_FALSE(observer.empty());
|
||||
|
||||
observer.clear();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
observer.disconnect();
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
registry.emplace_or_replace<char>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, ObserveFiltered) {
|
||||
constexpr auto collector =
|
||||
entt::collector
|
||||
.update<int>()
|
||||
.where<char>(entt::exclude<double>);
|
||||
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, collector};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.replace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 0u);
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<char>(entity);
|
||||
registry.emplace<double>(entity);
|
||||
registry.replace<int>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.erase<double>(entity);
|
||||
registry.replace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
registry.emplace<double>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.erase<double>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
observer.disconnect();
|
||||
registry.replace<int>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, AllOfObserve) {
|
||||
entt::registry registry;
|
||||
entt::observer observer{};
|
||||
const auto entity = registry.create();
|
||||
|
||||
observer.connect(registry, entt::collector.group<int>().update<char>());
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
registry.replace<char>(entity);
|
||||
registry.erase<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
registry.erase<char>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.replace<char>(entity);
|
||||
observer.clear();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
observer.disconnect();
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
registry.emplace_or_replace<char>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, CrossRulesCornerCase) {
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, entt::collector.group<int>().group<char>()};
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
observer.clear();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace<char>(entity);
|
||||
registry.erase<int>(entity);
|
||||
|
||||
ASSERT_FALSE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, Each) {
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, entt::collector.group<int>()};
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
|
||||
std::as_const(observer).each([entity](const auto entt) {
|
||||
ASSERT_EQ(entity, entt);
|
||||
});
|
||||
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
|
||||
observer.each([entity](const auto entt) {
|
||||
ASSERT_EQ(entity, entt);
|
||||
});
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
ASSERT_EQ(observer.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Observer, MultipleFilters) {
|
||||
constexpr auto collector =
|
||||
entt::collector
|
||||
.update<int>()
|
||||
.where<char>()
|
||||
.update<double>()
|
||||
.where<float>();
|
||||
|
||||
entt::registry registry;
|
||||
entt::observer observer{registry, collector};
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
observer.clear();
|
||||
registry.emplace<double>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace_or_replace<double>(entity);
|
||||
registry.emplace<float>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace_or_replace<double>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
registry.erase<float>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
|
||||
ASSERT_EQ(observer.size(), 1u);
|
||||
ASSERT_FALSE(observer.empty());
|
||||
ASSERT_EQ(*observer.data(), entity);
|
||||
|
||||
observer.clear();
|
||||
observer.disconnect();
|
||||
|
||||
registry.emplace_or_replace<int>(entity);
|
||||
|
||||
ASSERT_TRUE(observer.empty());
|
||||
}
|
||||
|
||||
TEST(Observer, GroupCornerCase) {
|
||||
constexpr auto add_collector = entt::collector.group<int>(entt::exclude<char>);
|
||||
constexpr auto remove_collector = entt::collector.group<int, char>();
|
||||
|
||||
entt::registry registry;
|
||||
entt::observer add_observer{registry, add_collector};
|
||||
entt::observer remove_observer{registry, remove_collector};
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_FALSE(add_observer.empty());
|
||||
ASSERT_TRUE(remove_observer.empty());
|
||||
|
||||
add_observer.clear();
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_TRUE(add_observer.empty());
|
||||
ASSERT_FALSE(remove_observer.empty());
|
||||
|
||||
remove_observer.clear();
|
||||
registry.erase<char>(entity);
|
||||
|
||||
ASSERT_FALSE(add_observer.empty());
|
||||
ASSERT_TRUE(remove_observer.empty());
|
||||
}
|
432
test/entt/entity/organizer.cpp
Normal file
432
test/entt/entity/organizer.cpp
Normal file
@ -0,0 +1,432 @@
|
||||
#include <cstddef>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/organizer.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
|
||||
void ro_int_rw_char_double(entt::view<entt::get_t<const int, char>>, double &) {}
|
||||
void ro_char_rw_int(entt::view<entt::get_t<int, const char>>) {}
|
||||
void ro_char_rw_double(entt::view<entt::get_t<const char>>, double &) {}
|
||||
void ro_int_double(entt::view<entt::get_t<const int>>, const double &) {}
|
||||
void sync_point(entt::registry &, entt::view<entt::get_t<const int>>) {}
|
||||
|
||||
struct clazz {
|
||||
void ro_int_char_double(entt::view<entt::get_t<const int, const char>>, const double &) {}
|
||||
void rw_int(entt::view<entt::get_t<int>>) {}
|
||||
void rw_int_char(entt::view<entt::get_t<int, char>>) {}
|
||||
void rw_int_char_double(entt::view<entt::get_t<int, char>>, double &) {}
|
||||
|
||||
static void ro_int_with_payload(const clazz &, entt::view<entt::get_t<const int>>) {}
|
||||
static void ro_char_with_payload(const clazz &, entt::view<entt::get_t<const char>>) {}
|
||||
static void ro_int_char_with_payload(clazz &, entt::view<entt::get_t<const int, const char>>) {}
|
||||
};
|
||||
|
||||
void to_args_integrity(entt::view<entt::get_t<int>> view, std::size_t &value, entt::registry ®istry) {
|
||||
value = view.size();
|
||||
}
|
||||
|
||||
TEST(Organizer, EmplaceFreeFunction) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
|
||||
organizer.emplace<&ro_int_rw_char_double>("t1");
|
||||
organizer.emplace<&ro_char_rw_int>("t2");
|
||||
organizer.emplace<&ro_char_rw_double>("t3");
|
||||
organizer.emplace<&ro_int_double>("t4");
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_EQ(graph.size(), 4u);
|
||||
|
||||
ASSERT_STREQ(graph[0u].name(), "t1");
|
||||
ASSERT_STREQ(graph[1u].name(), "t2");
|
||||
ASSERT_STREQ(graph[2u].name(), "t3");
|
||||
ASSERT_STREQ(graph[3u].name(), "t4");
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[1u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[2u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[3u].ro_count(), 2u);
|
||||
|
||||
ASSERT_EQ(graph[0u].rw_count(), 2u);
|
||||
ASSERT_EQ(graph[1u].rw_count(), 1u);
|
||||
ASSERT_EQ(graph[2u].rw_count(), 1u);
|
||||
ASSERT_EQ(graph[3u].rw_count(), 0u);
|
||||
|
||||
ASSERT_NE(graph[0u].info(), graph[1u].info());
|
||||
ASSERT_NE(graph[1u].info(), graph[2u].info());
|
||||
ASSERT_NE(graph[2u].info(), graph[3u].info());
|
||||
|
||||
ASSERT_TRUE(graph[0u].top_level());
|
||||
ASSERT_FALSE(graph[1u].top_level());
|
||||
ASSERT_FALSE(graph[2u].top_level());
|
||||
ASSERT_FALSE(graph[3u].top_level());
|
||||
|
||||
ASSERT_EQ(graph[0u].children().size(), 2u);
|
||||
ASSERT_EQ(graph[1u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].children().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].children()[0u], 1u);
|
||||
ASSERT_EQ(graph[0u].children()[1u], 2u);
|
||||
ASSERT_EQ(graph[1u].children()[0u], 3u);
|
||||
ASSERT_EQ(graph[2u].children()[0u], 3u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
ASSERT_NO_FATAL_FAILURE(vertex.callback()(vertex.data(), registry));
|
||||
}
|
||||
|
||||
organizer.clear();
|
||||
|
||||
ASSERT_EQ(organizer.graph().size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Organizer, EmplaceMemberFunction) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
clazz instance;
|
||||
|
||||
organizer.emplace<&clazz::ro_int_char_double>(instance, "t1");
|
||||
organizer.emplace<&clazz::rw_int>(instance, "t2");
|
||||
organizer.emplace<&clazz::rw_int_char>(instance, "t3");
|
||||
organizer.emplace<&clazz::rw_int_char_double>(instance, "t4");
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_EQ(graph.size(), 4u);
|
||||
|
||||
ASSERT_STREQ(graph[0u].name(), "t1");
|
||||
ASSERT_STREQ(graph[1u].name(), "t2");
|
||||
ASSERT_STREQ(graph[2u].name(), "t3");
|
||||
ASSERT_STREQ(graph[3u].name(), "t4");
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_count(), 3u);
|
||||
ASSERT_EQ(graph[1u].ro_count(), 0u);
|
||||
ASSERT_EQ(graph[2u].ro_count(), 0u);
|
||||
ASSERT_EQ(graph[3u].ro_count(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].rw_count(), 0u);
|
||||
ASSERT_EQ(graph[1u].rw_count(), 1u);
|
||||
ASSERT_EQ(graph[2u].rw_count(), 2u);
|
||||
ASSERT_EQ(graph[3u].rw_count(), 3u);
|
||||
|
||||
ASSERT_NE(graph[0u].info(), graph[1u].info());
|
||||
ASSERT_NE(graph[1u].info(), graph[2u].info());
|
||||
ASSERT_NE(graph[2u].info(), graph[3u].info());
|
||||
|
||||
ASSERT_TRUE(graph[0u].top_level());
|
||||
ASSERT_FALSE(graph[1u].top_level());
|
||||
ASSERT_FALSE(graph[2u].top_level());
|
||||
ASSERT_FALSE(graph[3u].top_level());
|
||||
|
||||
ASSERT_EQ(graph[0u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].children().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].children()[0u], 1u);
|
||||
ASSERT_EQ(graph[1u].children()[0u], 2u);
|
||||
ASSERT_EQ(graph[2u].children()[0u], 3u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
ASSERT_NO_FATAL_FAILURE(vertex.callback()(vertex.data(), registry));
|
||||
}
|
||||
|
||||
organizer.clear();
|
||||
|
||||
ASSERT_EQ(organizer.graph().size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Organizer, EmplaceFreeFunctionWithPayload) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
clazz instance;
|
||||
|
||||
organizer.emplace<&clazz::ro_int_char_double>(instance, "t1");
|
||||
organizer.emplace<&clazz::ro_int_with_payload>(instance, "t2");
|
||||
organizer.emplace<&clazz::ro_char_with_payload, const clazz>(instance, "t3");
|
||||
organizer.emplace<&clazz::ro_int_char_with_payload, clazz>(instance, "t4");
|
||||
organizer.emplace<&clazz::rw_int_char>(instance, "t5");
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_EQ(graph.size(), 5u);
|
||||
|
||||
ASSERT_STREQ(graph[0u].name(), "t1");
|
||||
ASSERT_STREQ(graph[1u].name(), "t2");
|
||||
ASSERT_STREQ(graph[2u].name(), "t3");
|
||||
ASSERT_STREQ(graph[3u].name(), "t4");
|
||||
ASSERT_STREQ(graph[4u].name(), "t5");
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_count(), 3u);
|
||||
ASSERT_EQ(graph[1u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[2u].ro_count(), 2u);
|
||||
ASSERT_EQ(graph[3u].ro_count(), 2u);
|
||||
ASSERT_EQ(graph[4u].ro_count(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].rw_count(), 0u);
|
||||
ASSERT_EQ(graph[1u].rw_count(), 0u);
|
||||
ASSERT_EQ(graph[2u].rw_count(), 0u);
|
||||
ASSERT_EQ(graph[3u].rw_count(), 1u);
|
||||
ASSERT_EQ(graph[4u].rw_count(), 2u);
|
||||
|
||||
ASSERT_NE(graph[0u].info(), graph[1u].info());
|
||||
ASSERT_NE(graph[1u].info(), graph[2u].info());
|
||||
ASSERT_NE(graph[2u].info(), graph[3u].info());
|
||||
ASSERT_NE(graph[3u].info(), graph[4u].info());
|
||||
|
||||
ASSERT_TRUE(graph[0u].top_level());
|
||||
ASSERT_TRUE(graph[1u].top_level());
|
||||
ASSERT_TRUE(graph[2u].top_level());
|
||||
ASSERT_FALSE(graph[3u].top_level());
|
||||
ASSERT_FALSE(graph[4u].top_level());
|
||||
|
||||
ASSERT_EQ(graph[0u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[4u].children().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].children()[0u], 4u);
|
||||
ASSERT_EQ(graph[1u].children()[0u], 4u);
|
||||
ASSERT_EQ(graph[2u].children()[0u], 3u);
|
||||
ASSERT_EQ(graph[3u].children()[0u], 4u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
ASSERT_NO_FATAL_FAILURE(vertex.callback()(vertex.data(), registry));
|
||||
}
|
||||
|
||||
organizer.clear();
|
||||
|
||||
ASSERT_EQ(organizer.graph().size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Organizer, EmplaceDirectFunction) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
clazz instance;
|
||||
|
||||
// no aggressive comdat
|
||||
auto t1 = +[](const void *, entt::registry ®) { reg.clear<int>(); };
|
||||
auto t2 = +[](const void *, entt::registry ®) { reg.clear<char>(); };
|
||||
auto t3 = +[](const void *, entt::registry ®) { reg.clear<double>(); };
|
||||
auto t4 = +[](const void *, entt::registry ®) { reg.clear(); };
|
||||
|
||||
organizer.emplace<int>(t1, nullptr, "t1");
|
||||
organizer.emplace<const int>(t2, &instance, "t2");
|
||||
organizer.emplace<const int, char>(t3, nullptr, "t3");
|
||||
organizer.emplace<int, char, double>(t4, &instance, "t4");
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_EQ(graph.size(), 4u);
|
||||
|
||||
ASSERT_STREQ(graph[0u].name(), "t1");
|
||||
ASSERT_STREQ(graph[1u].name(), "t2");
|
||||
ASSERT_STREQ(graph[2u].name(), "t3");
|
||||
ASSERT_STREQ(graph[3u].name(), "t4");
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_count(), 0u);
|
||||
ASSERT_EQ(graph[1u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[2u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[3u].ro_count(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].rw_count(), 1u);
|
||||
ASSERT_EQ(graph[1u].rw_count(), 0u);
|
||||
ASSERT_EQ(graph[2u].rw_count(), 1u);
|
||||
ASSERT_EQ(graph[3u].rw_count(), 3u);
|
||||
|
||||
ASSERT_TRUE(graph[0u].callback() == t1);
|
||||
ASSERT_TRUE(graph[1u].callback() == t2);
|
||||
ASSERT_TRUE(graph[2u].callback() == t3);
|
||||
ASSERT_TRUE(graph[3u].callback() == t4);
|
||||
|
||||
ASSERT_EQ(graph[0u].data(), nullptr);
|
||||
ASSERT_EQ(graph[1u].data(), &instance);
|
||||
ASSERT_EQ(graph[2u].data(), nullptr);
|
||||
ASSERT_EQ(graph[3u].data(), &instance);
|
||||
|
||||
ASSERT_EQ(graph[0u].info(), entt::type_id<void>());
|
||||
ASSERT_EQ(graph[1u].info(), entt::type_id<void>());
|
||||
ASSERT_EQ(graph[2u].info(), entt::type_id<void>());
|
||||
ASSERT_EQ(graph[3u].info(), entt::type_id<void>());
|
||||
|
||||
ASSERT_TRUE(graph[0u].top_level());
|
||||
ASSERT_FALSE(graph[1u].top_level());
|
||||
ASSERT_FALSE(graph[2u].top_level());
|
||||
ASSERT_FALSE(graph[3u].top_level());
|
||||
|
||||
ASSERT_EQ(graph[0u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].children().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].children()[0u], 1u);
|
||||
ASSERT_EQ(graph[1u].children()[0u], 2u);
|
||||
ASSERT_EQ(graph[2u].children()[0u], 3u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
ASSERT_NO_FATAL_FAILURE(vertex.callback()(vertex.data(), registry));
|
||||
}
|
||||
|
||||
organizer.clear();
|
||||
|
||||
ASSERT_EQ(organizer.graph().size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Organizer, SyncPoint) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
clazz instance;
|
||||
|
||||
organizer.emplace<&ro_int_double>("before");
|
||||
organizer.emplace<&sync_point>("sync_1");
|
||||
organizer.emplace<&clazz::ro_int_char_double>(instance, "mid_1");
|
||||
organizer.emplace<&ro_int_double>("mid_2");
|
||||
organizer.emplace<&sync_point>("sync_2");
|
||||
organizer.emplace<&ro_int_double>("after");
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_EQ(graph.size(), 6u);
|
||||
|
||||
ASSERT_STREQ(graph[0u].name(), "before");
|
||||
ASSERT_STREQ(graph[1u].name(), "sync_1");
|
||||
ASSERT_STREQ(graph[2u].name(), "mid_1");
|
||||
ASSERT_STREQ(graph[3u].name(), "mid_2");
|
||||
ASSERT_STREQ(graph[4u].name(), "sync_2");
|
||||
ASSERT_STREQ(graph[5u].name(), "after");
|
||||
|
||||
ASSERT_TRUE(graph[0u].top_level());
|
||||
ASSERT_FALSE(graph[1u].top_level());
|
||||
ASSERT_FALSE(graph[2u].top_level());
|
||||
ASSERT_FALSE(graph[3u].top_level());
|
||||
ASSERT_FALSE(graph[4u].top_level());
|
||||
ASSERT_FALSE(graph[5u].top_level());
|
||||
|
||||
ASSERT_EQ(graph[0u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].children().size(), 2u);
|
||||
ASSERT_EQ(graph[2u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[4u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[5u].children().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].children()[0u], 1u);
|
||||
ASSERT_EQ(graph[1u].children()[0u], 2u);
|
||||
ASSERT_EQ(graph[1u].children()[1u], 3u);
|
||||
ASSERT_EQ(graph[2u].children()[0u], 4u);
|
||||
ASSERT_EQ(graph[3u].children()[0u], 4u);
|
||||
ASSERT_EQ(graph[4u].children()[0u], 5u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
ASSERT_NO_FATAL_FAILURE(vertex.callback()(vertex.data(), registry));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Organizer, Override) {
|
||||
entt::organizer organizer;
|
||||
|
||||
organizer.emplace<&ro_int_rw_char_double, const char, const double>("t1");
|
||||
organizer.emplace<&ro_char_rw_double, const double>("t2");
|
||||
organizer.emplace<&ro_int_double, double>("t3");
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_EQ(graph.size(), 3u);
|
||||
|
||||
ASSERT_STREQ(graph[0u].name(), "t1");
|
||||
ASSERT_STREQ(graph[1u].name(), "t2");
|
||||
ASSERT_STREQ(graph[2u].name(), "t3");
|
||||
|
||||
ASSERT_TRUE(graph[0u].top_level());
|
||||
ASSERT_TRUE(graph[1u].top_level());
|
||||
ASSERT_FALSE(graph[2u].top_level());
|
||||
|
||||
ASSERT_EQ(graph[0u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].children().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].children().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].children()[0u], 2u);
|
||||
ASSERT_EQ(graph[1u].children()[0u], 2u);
|
||||
}
|
||||
|
||||
TEST(Organizer, Prepare) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
clazz instance;
|
||||
|
||||
organizer.emplace<&ro_int_double>();
|
||||
organizer.emplace<&clazz::rw_int_char>(instance);
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
|
||||
ASSERT_FALSE(registry.ctx().contains<int>());
|
||||
ASSERT_FALSE(registry.ctx().contains<char>());
|
||||
ASSERT_FALSE(registry.ctx().contains<double>());
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
vertex.prepare(registry);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(registry.ctx().contains<int>());
|
||||
ASSERT_FALSE(registry.ctx().contains<char>());
|
||||
ASSERT_TRUE(registry.ctx().contains<double>());
|
||||
}
|
||||
|
||||
TEST(Organizer, Dependencies) {
|
||||
entt::organizer organizer;
|
||||
clazz instance;
|
||||
|
||||
organizer.emplace<&ro_int_double>();
|
||||
organizer.emplace<&clazz::rw_int_char>(instance);
|
||||
organizer.emplace<char, const double>(+[](const void *, entt::registry &) {});
|
||||
|
||||
const auto graph = organizer.graph();
|
||||
const entt::type_info *buffer[5u]{};
|
||||
|
||||
ASSERT_EQ(graph.size(), 3u);
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_count(), 2u);
|
||||
ASSERT_EQ(graph[0u].rw_count(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_dependency(buffer, 0u), 0u);
|
||||
ASSERT_EQ(graph[0u].rw_dependency(buffer, 2u), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_dependency(buffer, 5u), 2u);
|
||||
ASSERT_EQ(*buffer[0u], entt::type_id<int>());
|
||||
ASSERT_EQ(*buffer[1u], entt::type_id<double>());
|
||||
|
||||
ASSERT_EQ(graph[1u].ro_count(), 0u);
|
||||
ASSERT_EQ(graph[1u].rw_count(), 2u);
|
||||
|
||||
ASSERT_EQ(graph[1u].ro_dependency(buffer, 2u), 0u);
|
||||
ASSERT_EQ(graph[1u].rw_dependency(buffer, 0u), 0u);
|
||||
|
||||
ASSERT_EQ(graph[1u].rw_dependency(buffer, 5u), 2u);
|
||||
ASSERT_EQ(*buffer[0u], entt::type_id<int>());
|
||||
ASSERT_EQ(*buffer[1u], entt::type_id<char>());
|
||||
|
||||
ASSERT_EQ(graph[2u].ro_count(), 1u);
|
||||
ASSERT_EQ(graph[2u].rw_count(), 1u);
|
||||
|
||||
ASSERT_EQ(graph[2u].ro_dependency(buffer, 2u), 1u);
|
||||
ASSERT_EQ(graph[2u].rw_dependency(buffer, 0u), 0u);
|
||||
|
||||
ASSERT_EQ(graph[2u].ro_dependency(buffer, 5u), 1u);
|
||||
ASSERT_EQ(*buffer[0u], entt::type_id<double>());
|
||||
|
||||
ASSERT_EQ(graph[2u].rw_dependency(buffer, 5u), 1u);
|
||||
ASSERT_EQ(*buffer[0u], entt::type_id<char>());
|
||||
}
|
||||
|
||||
TEST(Organizer, ToArgsIntegrity) {
|
||||
entt::organizer organizer;
|
||||
entt::registry registry;
|
||||
|
||||
organizer.emplace<&to_args_integrity>();
|
||||
registry.ctx().emplace<std::size_t>(42u);
|
||||
|
||||
auto graph = organizer.graph();
|
||||
graph[0u].callback()(graph[0u].data(), registry);
|
||||
|
||||
ASSERT_EQ(registry.ctx().at<std::size_t>(), 0u);
|
||||
}
|
2206
test/entt/entity/registry.cpp
Normal file
2206
test/entt/entity/registry.cpp
Normal file
File diff suppressed because it is too large
Load Diff
409
test/entt/entity/runtime_view.cpp
Normal file
409
test/entt/entity/runtime_view.cpp
Normal file
@ -0,0 +1,409 @@
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/runtime_view.hpp>
|
||||
|
||||
struct stable_type {
|
||||
static constexpr auto in_place_delete = true;
|
||||
int value;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct RuntimeView: testing::Test {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
using RuntimeViewTypes = ::testing::Types<entt::runtime_view, entt::const_runtime_view>;
|
||||
|
||||
TYPED_TEST_SUITE(RuntimeView, RuntimeViewTypes, );
|
||||
|
||||
TYPED_TEST(RuntimeView, Functionalities) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_FALSE(view.contains(e0));
|
||||
ASSERT_FALSE(view.contains(e1));
|
||||
|
||||
// forces the creation of the pools
|
||||
static_cast<void>(registry.storage<int>());
|
||||
static_cast<void>(registry.storage<char>());
|
||||
|
||||
view.iterate(registry.storage<int>()).iterate(registry.storage<char>());
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 0u);
|
||||
|
||||
registry.emplace<char>(e0);
|
||||
registry.emplace<int>(e1);
|
||||
|
||||
ASSERT_NE(view.size_hint(), 0u);
|
||||
|
||||
registry.emplace<char>(e1);
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 1u);
|
||||
|
||||
auto it = view.begin();
|
||||
|
||||
ASSERT_EQ(*it, e1);
|
||||
ASSERT_EQ(++it, (view.end()));
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE((view.begin()++));
|
||||
ASSERT_NO_FATAL_FAILURE((++view.begin()));
|
||||
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_EQ(view.size_hint(), 1u);
|
||||
|
||||
registry.get<char>(e0) = '1';
|
||||
registry.get<char>(e1) = '2';
|
||||
registry.get<int>(e1) = 42;
|
||||
|
||||
for(auto entity: view) {
|
||||
ASSERT_EQ(registry.get<int>(entity), 42);
|
||||
ASSERT_EQ(registry.get<char>(entity), '2');
|
||||
}
|
||||
|
||||
view.clear();
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Constructors) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
view = runtime_view_type{std::allocator<int>{}};
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
|
||||
runtime_view_type temp{view, view.get_allocator()};
|
||||
runtime_view_type other{std::move(temp), view.get_allocator()};
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_FALSE(temp.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Copy) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
|
||||
runtime_view_type other{view};
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
|
||||
other.iterate(registry.storage<int>()).exclude(registry.storage<char>());
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_FALSE(other.contains(entity));
|
||||
|
||||
other = view;
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Move) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
|
||||
runtime_view_type other{std::move(view)};
|
||||
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
|
||||
view = other;
|
||||
other.iterate(registry.storage<int>()).exclude(registry.storage<char>());
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_FALSE(other.contains(entity));
|
||||
|
||||
other = std::move(view);
|
||||
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Swap) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
runtime_view_type other{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 1u);
|
||||
ASSERT_EQ(other.size_hint(), 0u);
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_FALSE(other.contains(entity));
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_EQ(other.begin(), other.end());
|
||||
|
||||
view.swap(other);
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 0u);
|
||||
ASSERT_EQ(other.size_hint(), 1u);
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_NE(other.begin(), other.end());
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Iterator) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
using iterator = typename runtime_view_type::iterator;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
iterator end{view.begin()};
|
||||
iterator begin{};
|
||||
begin = view.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, view.begin());
|
||||
ASSERT_EQ(end, view.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(begin++, view.begin());
|
||||
ASSERT_EQ(begin--, view.end());
|
||||
|
||||
ASSERT_EQ(++begin, view.end());
|
||||
ASSERT_EQ(--begin, view.begin());
|
||||
|
||||
ASSERT_EQ(*begin, entity);
|
||||
ASSERT_EQ(*begin.operator->(), entity);
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Contains) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
const auto other = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<int>(other);
|
||||
|
||||
registry.destroy(entity);
|
||||
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_TRUE(view.contains(other));
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Empty) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
const auto other = registry.create();
|
||||
|
||||
registry.emplace<double>(entity);
|
||||
registry.emplace<float>(other);
|
||||
|
||||
view.iterate(registry.storage<int>());
|
||||
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_FALSE(view.contains(other));
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_EQ((std::find(view.begin(), view.end(), entity)), view.end());
|
||||
ASSERT_EQ((std::find(view.begin(), view.end(), other)), view.end());
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Each) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
const auto other = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
registry.emplace<char>(other);
|
||||
|
||||
view.iterate(registry.storage<int>()).iterate(registry.storage<char>());
|
||||
|
||||
view.each([entity](const auto entt) {
|
||||
ASSERT_EQ(entt, entity);
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, EachWithHoles) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
const auto e2 = registry.create();
|
||||
|
||||
registry.emplace<char>(e0, '0');
|
||||
registry.emplace<char>(e1, '1');
|
||||
|
||||
registry.emplace<int>(e0, 0);
|
||||
registry.emplace<int>(e2, 2);
|
||||
|
||||
view.iterate(registry.storage<int>()).iterate(registry.storage<char>());
|
||||
|
||||
view.each([e0](auto entt) {
|
||||
ASSERT_EQ(e0, entt);
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, ExcludedComponents) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto e0 = registry.create();
|
||||
registry.emplace<int>(e0);
|
||||
|
||||
const auto e1 = registry.create();
|
||||
registry.emplace<int>(e1);
|
||||
registry.emplace<char>(e1);
|
||||
|
||||
view.iterate(registry.storage<int>())
|
||||
.exclude(registry.storage<char>());
|
||||
|
||||
ASSERT_TRUE(view.contains(e0));
|
||||
ASSERT_FALSE(view.contains(e1));
|
||||
|
||||
view.each([e0](auto entt) {
|
||||
ASSERT_EQ(e0, entt);
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, StableType) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto e0 = registry.create();
|
||||
const auto e1 = registry.create();
|
||||
const auto e2 = registry.create();
|
||||
|
||||
registry.emplace<int>(e0);
|
||||
registry.emplace<int>(e1);
|
||||
registry.emplace<int>(e2);
|
||||
|
||||
registry.emplace<stable_type>(e0);
|
||||
registry.emplace<stable_type>(e1);
|
||||
|
||||
registry.remove<stable_type>(e1);
|
||||
|
||||
view.iterate(registry.storage<int>()).iterate(registry.storage<stable_type>());
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 2u);
|
||||
ASSERT_TRUE(view.contains(e0));
|
||||
ASSERT_FALSE(view.contains(e1));
|
||||
|
||||
ASSERT_EQ(*view.begin(), e0);
|
||||
ASSERT_EQ(++view.begin(), view.end());
|
||||
|
||||
view.each([e0](const auto entt) {
|
||||
ASSERT_EQ(e0, entt);
|
||||
});
|
||||
|
||||
for(auto entt: view) {
|
||||
static_assert(std::is_same_v<decltype(entt), entt::entity>);
|
||||
ASSERT_EQ(e0, entt);
|
||||
}
|
||||
|
||||
registry.compact();
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 1u);
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, StableTypeWithExcludedComponent) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
runtime_view_type view{};
|
||||
|
||||
const auto entity = registry.create();
|
||||
const auto other = registry.create();
|
||||
|
||||
registry.emplace<stable_type>(entity, 0);
|
||||
registry.emplace<stable_type>(other, 42);
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
view.iterate(registry.storage<stable_type>()).exclude(registry.storage<int>());
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 2u);
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_TRUE(view.contains(other));
|
||||
|
||||
registry.destroy(entity);
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 2u);
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_TRUE(view.contains(other));
|
||||
|
||||
for(auto entt: view) {
|
||||
constexpr entt::entity tombstone = entt::tombstone;
|
||||
ASSERT_NE(entt, tombstone);
|
||||
ASSERT_EQ(entt, other);
|
||||
}
|
||||
|
||||
view.each([other](const auto entt) {
|
||||
constexpr entt::entity tombstone = entt::tombstone;
|
||||
ASSERT_NE(entt, tombstone);
|
||||
ASSERT_EQ(entt, other);
|
||||
});
|
||||
}
|
593
test/entt/entity/snapshot.cpp
Normal file
593
test/entt/entity/snapshot.cpp
Normal file
@ -0,0 +1,593 @@
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/snapshot.hpp>
|
||||
|
||||
struct noncopyable_component {
|
||||
noncopyable_component()
|
||||
: value{} {}
|
||||
|
||||
explicit noncopyable_component(int v)
|
||||
: value{v} {}
|
||||
|
||||
noncopyable_component(const noncopyable_component &) = delete;
|
||||
noncopyable_component(noncopyable_component &&) = default;
|
||||
|
||||
noncopyable_component &operator=(const noncopyable_component &) = delete;
|
||||
noncopyable_component &operator=(noncopyable_component &&) = default;
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
template<typename Storage>
|
||||
struct output_archive {
|
||||
output_archive(Storage &instance)
|
||||
: storage{instance} {}
|
||||
|
||||
template<typename... Value>
|
||||
void operator()(const Value &...value) {
|
||||
(std::get<std::queue<Value>>(storage).push(value), ...);
|
||||
}
|
||||
|
||||
void operator()(const entt::entity &entity, const noncopyable_component &instance) {
|
||||
(*this)(entity, instance.value);
|
||||
}
|
||||
|
||||
private:
|
||||
Storage &storage;
|
||||
};
|
||||
|
||||
template<typename Storage>
|
||||
struct input_archive {
|
||||
input_archive(Storage &instance)
|
||||
: storage{instance} {}
|
||||
|
||||
template<typename... Value>
|
||||
void operator()(Value &...value) {
|
||||
auto assign = [this](auto &val) {
|
||||
auto &queue = std::get<std::queue<std::decay_t<decltype(val)>>>(storage);
|
||||
val = queue.front();
|
||||
queue.pop();
|
||||
};
|
||||
|
||||
(assign(value), ...);
|
||||
}
|
||||
|
||||
void operator()(entt::entity &entity, noncopyable_component &instance) {
|
||||
(*this)(entity, instance.value);
|
||||
}
|
||||
|
||||
private:
|
||||
Storage &storage;
|
||||
};
|
||||
|
||||
struct a_component {};
|
||||
|
||||
struct another_component {
|
||||
int key;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct what_a_component {
|
||||
entt::entity bar;
|
||||
std::vector<entt::entity> quux;
|
||||
};
|
||||
|
||||
struct map_component {
|
||||
std::map<entt::entity, int> keys;
|
||||
std::map<int, entt::entity> values;
|
||||
std::map<entt::entity, entt::entity> both;
|
||||
};
|
||||
|
||||
TEST(Snapshot, Dump) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
|
||||
const auto e0 = registry.create();
|
||||
registry.emplace<int>(e0, 42);
|
||||
registry.emplace<char>(e0, 'c');
|
||||
registry.emplace<double>(e0, .1);
|
||||
|
||||
const auto e1 = registry.create();
|
||||
|
||||
const auto e2 = registry.create();
|
||||
registry.emplace<int>(e2, 3);
|
||||
|
||||
const auto e3 = registry.create();
|
||||
registry.emplace<a_component>(e3);
|
||||
registry.emplace<char>(e3, '0');
|
||||
|
||||
registry.destroy(e1);
|
||||
auto v1 = registry.current(e1);
|
||||
|
||||
using storage_type = std::tuple<
|
||||
std::queue<typename traits_type::entity_type>,
|
||||
std::queue<entt::entity>,
|
||||
std::queue<int>,
|
||||
std::queue<char>,
|
||||
std::queue<double>,
|
||||
std::queue<a_component>,
|
||||
std::queue<another_component>>;
|
||||
|
||||
storage_type storage;
|
||||
output_archive<storage_type> output{storage};
|
||||
input_archive<storage_type> input{storage};
|
||||
|
||||
entt::snapshot{registry}.entities(output).component<int, char, double, a_component, another_component>(output);
|
||||
registry.clear();
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_FALSE(registry.valid(e2));
|
||||
ASSERT_FALSE(registry.valid(e3));
|
||||
|
||||
entt::snapshot_loader{registry}.entities(input).component<int, char, double, a_component, another_component>(input).orphans();
|
||||
|
||||
ASSERT_TRUE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_TRUE(registry.valid(e2));
|
||||
ASSERT_TRUE(registry.valid(e3));
|
||||
|
||||
ASSERT_FALSE(registry.orphan(e0));
|
||||
ASSERT_FALSE(registry.orphan(e2));
|
||||
ASSERT_FALSE(registry.orphan(e3));
|
||||
|
||||
ASSERT_EQ(registry.get<int>(e0), 42);
|
||||
ASSERT_EQ(registry.get<char>(e0), 'c');
|
||||
ASSERT_EQ(registry.get<double>(e0), .1);
|
||||
ASSERT_EQ(registry.current(e1), v1);
|
||||
ASSERT_EQ(registry.get<int>(e2), 3);
|
||||
ASSERT_EQ(registry.get<char>(e3), '0');
|
||||
ASSERT_TRUE(registry.all_of<a_component>(e3));
|
||||
|
||||
ASSERT_TRUE(registry.storage<another_component>().empty());
|
||||
}
|
||||
|
||||
TEST(Snapshot, Partial) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
|
||||
const auto e0 = registry.create();
|
||||
registry.emplace<int>(e0, 42);
|
||||
registry.emplace<char>(e0, 'c');
|
||||
registry.emplace<double>(e0, .1);
|
||||
|
||||
const auto e1 = registry.create();
|
||||
|
||||
const auto e2 = registry.create();
|
||||
registry.emplace<int>(e2, 3);
|
||||
|
||||
const auto e3 = registry.create();
|
||||
registry.emplace<char>(e3, '0');
|
||||
|
||||
registry.destroy(e1);
|
||||
auto v1 = registry.current(e1);
|
||||
|
||||
using storage_type = std::tuple<
|
||||
std::queue<typename traits_type::entity_type>,
|
||||
std::queue<entt::entity>,
|
||||
std::queue<int>,
|
||||
std::queue<char>,
|
||||
std::queue<double>>;
|
||||
|
||||
storage_type storage;
|
||||
output_archive<storage_type> output{storage};
|
||||
input_archive<storage_type> input{storage};
|
||||
|
||||
entt::snapshot{registry}.entities(output).component<char, int>(output);
|
||||
registry.clear();
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_FALSE(registry.valid(e2));
|
||||
ASSERT_FALSE(registry.valid(e3));
|
||||
|
||||
entt::snapshot_loader{registry}.entities(input).component<char, int>(input);
|
||||
|
||||
ASSERT_TRUE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_TRUE(registry.valid(e2));
|
||||
ASSERT_TRUE(registry.valid(e3));
|
||||
|
||||
ASSERT_EQ(registry.get<int>(e0), 42);
|
||||
ASSERT_EQ(registry.get<char>(e0), 'c');
|
||||
ASSERT_FALSE(registry.all_of<double>(e0));
|
||||
ASSERT_EQ(registry.current(e1), v1);
|
||||
ASSERT_EQ(registry.get<int>(e2), 3);
|
||||
ASSERT_EQ(registry.get<char>(e3), '0');
|
||||
|
||||
entt::snapshot{registry}.entities(output);
|
||||
registry.clear();
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_FALSE(registry.valid(e2));
|
||||
ASSERT_FALSE(registry.valid(e3));
|
||||
|
||||
entt::snapshot_loader{registry}.entities(input).orphans();
|
||||
|
||||
ASSERT_FALSE(registry.valid(e0));
|
||||
ASSERT_FALSE(registry.valid(e1));
|
||||
ASSERT_FALSE(registry.valid(e2));
|
||||
ASSERT_FALSE(registry.valid(e3));
|
||||
}
|
||||
|
||||
TEST(Snapshot, Iterator) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
|
||||
for(auto i = 0; i < 50; ++i) {
|
||||
const auto entity = registry.create();
|
||||
registry.emplace<another_component>(entity, i, i);
|
||||
registry.emplace<noncopyable_component>(entity, i);
|
||||
|
||||
if(i % 2) {
|
||||
registry.emplace<a_component>(entity);
|
||||
}
|
||||
}
|
||||
|
||||
using storage_type = std::tuple<
|
||||
std::queue<typename traits_type::entity_type>,
|
||||
std::queue<entt::entity>,
|
||||
std::queue<another_component>,
|
||||
std::queue<int>>;
|
||||
|
||||
storage_type storage;
|
||||
output_archive<storage_type> output{storage};
|
||||
input_archive<storage_type> input{storage};
|
||||
|
||||
const auto view = registry.view<a_component>();
|
||||
const auto size = view.size();
|
||||
|
||||
entt::snapshot{registry}.component<another_component, noncopyable_component>(output, view.begin(), view.end());
|
||||
registry.clear();
|
||||
entt::snapshot_loader{registry}.component<another_component, noncopyable_component>(input);
|
||||
|
||||
ASSERT_EQ(registry.view<another_component>().size(), size);
|
||||
|
||||
registry.view<another_component>().each([](const auto entity, const auto &) {
|
||||
ASSERT_NE(entt::to_integral(entity) % 2u, 0u);
|
||||
});
|
||||
}
|
||||
|
||||
TEST(Snapshot, Continuous) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry src;
|
||||
entt::registry dst;
|
||||
|
||||
entt::continuous_loader loader{dst};
|
||||
|
||||
std::vector<entt::entity> entities;
|
||||
entt::entity entity;
|
||||
|
||||
using storage_type = std::tuple<
|
||||
std::queue<typename traits_type::entity_type>,
|
||||
std::queue<entt::entity>,
|
||||
std::queue<another_component>,
|
||||
std::queue<what_a_component>,
|
||||
std::queue<map_component>,
|
||||
std::queue<int>,
|
||||
std::queue<double>>;
|
||||
|
||||
storage_type storage;
|
||||
output_archive<storage_type> output{storage};
|
||||
input_archive<storage_type> input{storage};
|
||||
|
||||
for(int i = 0; i < 10; ++i) {
|
||||
static_cast<void>(src.create());
|
||||
}
|
||||
|
||||
src.clear();
|
||||
|
||||
for(int i = 0; i < 5; ++i) {
|
||||
entity = src.create();
|
||||
entities.push_back(entity);
|
||||
|
||||
src.emplace<a_component>(entity);
|
||||
src.emplace<another_component>(entity, i, i);
|
||||
src.emplace<noncopyable_component>(entity, i);
|
||||
|
||||
if(i % 2) {
|
||||
src.emplace<what_a_component>(entity, entity);
|
||||
} else {
|
||||
src.emplace<map_component>(entity);
|
||||
}
|
||||
}
|
||||
|
||||
src.view<what_a_component>().each([&entities](auto, auto &what_a_component) {
|
||||
what_a_component.quux.insert(what_a_component.quux.begin(), entities.begin(), entities.end());
|
||||
});
|
||||
|
||||
src.view<map_component>().each([&entities](auto, auto &map_component) {
|
||||
for(std::size_t i = 0; i < entities.size(); ++i) {
|
||||
map_component.keys.insert({entities[i], int(i)});
|
||||
map_component.values.insert({int(i), entities[i]});
|
||||
map_component.both.insert({entities[entities.size() - i - 1], entities[i]});
|
||||
}
|
||||
});
|
||||
|
||||
entity = dst.create();
|
||||
dst.emplace<a_component>(entity);
|
||||
dst.emplace<another_component>(entity, -1, -1);
|
||||
dst.emplace<noncopyable_component>(entity, -1);
|
||||
|
||||
entt::snapshot{src}.entities(output).component<a_component, another_component, what_a_component, map_component, noncopyable_component>(output);
|
||||
|
||||
loader.entities(input)
|
||||
.component<a_component, another_component, what_a_component, map_component, noncopyable_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both)
|
||||
.orphans();
|
||||
|
||||
decltype(dst.size()) a_component_cnt{};
|
||||
decltype(dst.size()) another_component_cnt{};
|
||||
decltype(dst.size()) what_a_component_cnt{};
|
||||
decltype(dst.size()) map_component_cnt{};
|
||||
decltype(dst.size()) noncopyable_component_cnt{};
|
||||
|
||||
dst.each([&dst, &a_component_cnt](auto entt) {
|
||||
ASSERT_TRUE(dst.all_of<a_component>(entt));
|
||||
++a_component_cnt;
|
||||
});
|
||||
|
||||
dst.view<another_component>().each([&another_component_cnt](auto, const auto &component) {
|
||||
ASSERT_EQ(component.value, component.key < 0 ? -1 : component.key);
|
||||
++another_component_cnt;
|
||||
});
|
||||
|
||||
dst.view<what_a_component>().each([&dst, &what_a_component_cnt](auto entt, const auto &component) {
|
||||
ASSERT_EQ(entt, component.bar);
|
||||
|
||||
for(auto child: component.quux) {
|
||||
ASSERT_TRUE(dst.valid(child));
|
||||
}
|
||||
|
||||
++what_a_component_cnt;
|
||||
});
|
||||
|
||||
dst.view<map_component>().each([&dst, &map_component_cnt](const auto &component) {
|
||||
for(auto child: component.keys) {
|
||||
ASSERT_TRUE(dst.valid(child.first));
|
||||
}
|
||||
|
||||
for(auto child: component.values) {
|
||||
ASSERT_TRUE(dst.valid(child.second));
|
||||
}
|
||||
|
||||
for(auto child: component.both) {
|
||||
ASSERT_TRUE(dst.valid(child.first));
|
||||
ASSERT_TRUE(dst.valid(child.second));
|
||||
}
|
||||
|
||||
++map_component_cnt;
|
||||
});
|
||||
|
||||
dst.view<noncopyable_component>().each([&dst, &noncopyable_component_cnt](auto, const auto &component) {
|
||||
++noncopyable_component_cnt;
|
||||
ASSERT_EQ(component.value, static_cast<int>(dst.storage<noncopyable_component>().size() - noncopyable_component_cnt - 1u));
|
||||
});
|
||||
|
||||
src.view<another_component>().each([](auto, auto &component) {
|
||||
component.value = 2 * component.key;
|
||||
});
|
||||
|
||||
auto size = dst.size();
|
||||
|
||||
entt::snapshot{src}.entities(output).component<a_component, what_a_component, map_component, another_component>(output);
|
||||
|
||||
loader.entities(input)
|
||||
.component<a_component, what_a_component, map_component, another_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both)
|
||||
.orphans();
|
||||
|
||||
ASSERT_EQ(size, dst.size());
|
||||
|
||||
ASSERT_EQ(dst.storage<a_component>().size(), a_component_cnt);
|
||||
ASSERT_EQ(dst.storage<another_component>().size(), another_component_cnt);
|
||||
ASSERT_EQ(dst.storage<what_a_component>().size(), what_a_component_cnt);
|
||||
ASSERT_EQ(dst.storage<map_component>().size(), map_component_cnt);
|
||||
ASSERT_EQ(dst.storage<noncopyable_component>().size(), noncopyable_component_cnt);
|
||||
|
||||
dst.view<another_component>().each([](auto, auto &component) {
|
||||
ASSERT_EQ(component.value, component.key < 0 ? -1 : (2 * component.key));
|
||||
});
|
||||
|
||||
entity = src.create();
|
||||
|
||||
src.view<what_a_component>().each([entity](auto, auto &component) {
|
||||
component.bar = entity;
|
||||
});
|
||||
|
||||
entt::snapshot{src}.entities(output).component<what_a_component, map_component, a_component, another_component>(output);
|
||||
|
||||
loader.entities(input)
|
||||
.component<what_a_component, map_component, a_component, another_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both)
|
||||
.orphans();
|
||||
|
||||
dst.view<what_a_component>().each([&loader, entity](auto, auto &component) {
|
||||
ASSERT_EQ(component.bar, loader.map(entity));
|
||||
});
|
||||
|
||||
entities.clear();
|
||||
for(auto entt: src.view<a_component>()) {
|
||||
entities.push_back(entt);
|
||||
}
|
||||
|
||||
src.destroy(entity);
|
||||
loader.shrink();
|
||||
|
||||
entt::snapshot{src}.entities(output).component<a_component, another_component, what_a_component, map_component>(output);
|
||||
|
||||
loader.entities(input)
|
||||
.component<a_component, another_component, what_a_component, map_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both)
|
||||
.orphans()
|
||||
.shrink();
|
||||
|
||||
dst.view<what_a_component>().each([&dst](auto, auto &component) {
|
||||
ASSERT_FALSE(dst.valid(component.bar));
|
||||
});
|
||||
|
||||
ASSERT_FALSE(loader.contains(entity));
|
||||
|
||||
entity = src.create();
|
||||
|
||||
src.view<what_a_component>().each([entity](auto, auto &component) {
|
||||
component.bar = entity;
|
||||
});
|
||||
|
||||
dst.clear<a_component>();
|
||||
a_component_cnt = src.storage<a_component>().size();
|
||||
|
||||
entt::snapshot{src}.entities(output).component<a_component, what_a_component, map_component, another_component>(output);
|
||||
|
||||
loader.entities(input)
|
||||
.component<a_component, what_a_component, map_component, another_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both)
|
||||
.orphans();
|
||||
|
||||
ASSERT_EQ(dst.storage<a_component>().size(), a_component_cnt);
|
||||
|
||||
src.clear<a_component>();
|
||||
a_component_cnt = {};
|
||||
|
||||
entt::snapshot{src}.entities(output).component<what_a_component, map_component, a_component, another_component>(output);
|
||||
|
||||
loader.entities(input)
|
||||
.component<what_a_component, map_component, a_component, another_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both)
|
||||
.orphans();
|
||||
|
||||
ASSERT_EQ(dst.storage<a_component>().size(), a_component_cnt);
|
||||
}
|
||||
|
||||
TEST(Snapshot, MoreOnShrink) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry src;
|
||||
entt::registry dst;
|
||||
|
||||
entt::continuous_loader loader{dst};
|
||||
|
||||
using storage_type = std::tuple<
|
||||
std::queue<typename traits_type::entity_type>,
|
||||
std::queue<entt::entity>>;
|
||||
|
||||
storage_type storage;
|
||||
output_archive<storage_type> output{storage};
|
||||
input_archive<storage_type> input{storage};
|
||||
|
||||
auto entity = src.create();
|
||||
entt::snapshot{src}.entities(output);
|
||||
loader.entities(input).shrink();
|
||||
|
||||
ASSERT_TRUE(dst.valid(entity));
|
||||
|
||||
loader.shrink();
|
||||
|
||||
ASSERT_FALSE(dst.valid(entity));
|
||||
}
|
||||
|
||||
TEST(Snapshot, SyncDataMembers) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry src;
|
||||
entt::registry dst;
|
||||
|
||||
entt::continuous_loader loader{dst};
|
||||
|
||||
using storage_type = std::tuple<
|
||||
std::queue<typename traits_type::entity_type>,
|
||||
std::queue<entt::entity>,
|
||||
std::queue<what_a_component>,
|
||||
std::queue<map_component>>;
|
||||
|
||||
storage_type storage;
|
||||
output_archive<storage_type> output{storage};
|
||||
input_archive<storage_type> input{storage};
|
||||
|
||||
static_cast<void>(src.create());
|
||||
static_cast<void>(src.create());
|
||||
|
||||
src.clear();
|
||||
|
||||
auto parent = src.create();
|
||||
auto child = src.create();
|
||||
|
||||
src.emplace<what_a_component>(parent, entt::null);
|
||||
src.emplace<what_a_component>(child, parent).quux.push_back(child);
|
||||
|
||||
src.emplace<map_component>(
|
||||
child,
|
||||
decltype(map_component::keys){{{child, 10}}},
|
||||
decltype(map_component::values){{{10, child}}},
|
||||
decltype(map_component::both){{{child, child}}});
|
||||
|
||||
entt::snapshot{src}.entities(output).component<what_a_component, map_component>(output);
|
||||
|
||||
loader.entities(input).component<what_a_component, map_component>(
|
||||
input,
|
||||
&what_a_component::bar,
|
||||
&what_a_component::quux,
|
||||
&map_component::keys,
|
||||
&map_component::values,
|
||||
&map_component::both);
|
||||
|
||||
ASSERT_FALSE(dst.valid(parent));
|
||||
ASSERT_FALSE(dst.valid(child));
|
||||
|
||||
ASSERT_TRUE(dst.all_of<what_a_component>(loader.map(parent)));
|
||||
ASSERT_TRUE(dst.all_of<what_a_component>(loader.map(child)));
|
||||
|
||||
ASSERT_EQ(dst.get<what_a_component>(loader.map(parent)).bar, static_cast<entt::entity>(entt::null));
|
||||
|
||||
const auto &component = dst.get<what_a_component>(loader.map(child));
|
||||
|
||||
ASSERT_EQ(component.bar, loader.map(parent));
|
||||
ASSERT_EQ(component.quux[0], loader.map(child));
|
||||
|
||||
const auto &foobar = dst.get<map_component>(loader.map(child));
|
||||
ASSERT_EQ(foobar.keys.at(loader.map(child)), 10);
|
||||
ASSERT_EQ(foobar.values.at(10), loader.map(child));
|
||||
ASSERT_EQ(foobar.both.at(loader.map(child)), loader.map(child));
|
||||
}
|
1426
test/entt/entity/sparse_set.cpp
Normal file
1426
test/entt/entity/sparse_set.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1933
test/entt/entity/storage.cpp
Normal file
1933
test/entt/entity/storage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
613
test/entt/entity/storage_mixin.cpp
Normal file
613
test/entt/entity/storage_mixin.cpp
Normal file
@ -0,0 +1,613 @@
|
||||
#include <iterator>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/storage.hpp>
|
||||
#include "../common/throwing_allocator.hpp"
|
||||
#include "../common/throwing_type.hpp"
|
||||
|
||||
struct empty_type {};
|
||||
|
||||
struct stable_type {
|
||||
static constexpr auto in_place_delete = true;
|
||||
int value{};
|
||||
};
|
||||
|
||||
struct non_default_constructible {
|
||||
non_default_constructible() = delete;
|
||||
|
||||
non_default_constructible(int v)
|
||||
: value{v} {}
|
||||
|
||||
int value{};
|
||||
};
|
||||
|
||||
struct counter {
|
||||
int value{};
|
||||
};
|
||||
|
||||
template<typename Registry>
|
||||
void listener(counter &counter, Registry &, typename Registry::entity_type) {
|
||||
++counter.value;
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, GenericType) {
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
entt::sigh_storage_mixin<entt::storage<int>> pool;
|
||||
entt::sparse_set &base = pool;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
ASSERT_NE(base.emplace(entities[0u]), base.end());
|
||||
|
||||
pool.emplace(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 0);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]), 0);
|
||||
ASSERT_EQ(pool.get(entities[1u]), 0);
|
||||
|
||||
base.erase(entities[0u]);
|
||||
pool.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 2);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
ASSERT_NE(base.insert(std::begin(entities), std::end(entities)), base.end());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]), 0);
|
||||
ASSERT_EQ(pool.get(entities[1u]), 0);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
base.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 4);
|
||||
ASSERT_EQ(on_destroy.value, 3);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
base.erase(entities[0u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 4);
|
||||
ASSERT_EQ(on_destroy.value, 4);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
pool.insert(std::begin(entities), std::end(entities), 3);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 4);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]), 3);
|
||||
ASSERT_EQ(pool.get(entities[1u]), 3);
|
||||
|
||||
pool.erase(std::begin(entities), std::end(entities));
|
||||
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 6);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, StableType) {
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
entt::sigh_storage_mixin<entt::storage<stable_type>> pool;
|
||||
entt::sparse_set &base = pool;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
ASSERT_NE(base.emplace(entities[0u]), base.end());
|
||||
|
||||
pool.emplace(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 0);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]).value, 0);
|
||||
ASSERT_EQ(pool.get(entities[1u]).value, 0);
|
||||
|
||||
base.erase(entities[0u]);
|
||||
pool.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 2);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_NE(base.insert(std::begin(entities), std::end(entities)), base.end());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]).value, 0);
|
||||
ASSERT_EQ(pool.get(entities[1u]).value, 0);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
base.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 4);
|
||||
ASSERT_EQ(on_destroy.value, 3);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
base.erase(entities[0u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 4);
|
||||
ASSERT_EQ(on_destroy.value, 4);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
pool.insert(std::begin(entities), std::end(entities), stable_type{3});
|
||||
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 4);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]).value, 3);
|
||||
ASSERT_EQ(pool.get(entities[1u]).value, 3);
|
||||
|
||||
pool.erase(std::begin(entities), std::end(entities));
|
||||
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 6);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, EmptyType) {
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
entt::sigh_storage_mixin<entt::storage<empty_type>> pool;
|
||||
entt::sparse_set &base = pool;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
ASSERT_NE(base.emplace(entities[0u]), base.end());
|
||||
|
||||
pool.emplace(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 0);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_TRUE(pool.contains(entities[0u]));
|
||||
ASSERT_TRUE(pool.contains(entities[1u]));
|
||||
|
||||
base.erase(entities[0u]);
|
||||
pool.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 2);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
ASSERT_NE(base.insert(std::begin(entities), std::end(entities)), base.end());
|
||||
|
||||
ASSERT_TRUE(pool.contains(entities[0u]));
|
||||
ASSERT_TRUE(pool.contains(entities[1u]));
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
base.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 4);
|
||||
ASSERT_EQ(on_destroy.value, 3);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
base.erase(entities[0u]);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 4);
|
||||
ASSERT_EQ(on_destroy.value, 4);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
pool.insert(std::begin(entities), std::end(entities));
|
||||
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 4);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_TRUE(pool.contains(entities[0u]));
|
||||
ASSERT_TRUE(pool.contains(entities[1u]));
|
||||
|
||||
pool.erase(std::begin(entities), std::end(entities));
|
||||
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 6);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, NonDefaultConstructibleType) {
|
||||
entt::entity entities[2u]{entt::entity{3}, entt::entity{42}};
|
||||
entt::sigh_storage_mixin<entt::storage<non_default_constructible>> pool;
|
||||
entt::sparse_set &base = pool;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
ASSERT_EQ(base.emplace(entities[0u]), base.end());
|
||||
|
||||
pool.emplace(entities[1u], 3);
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 0);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_FALSE(pool.contains(entities[0u]));
|
||||
ASSERT_EQ(pool.get(entities[1u]).value, 3);
|
||||
|
||||
base.erase(entities[1u]);
|
||||
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 1);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
ASSERT_EQ(base.insert(std::begin(entities), std::end(entities)), base.end());
|
||||
|
||||
ASSERT_FALSE(pool.contains(entities[0u]));
|
||||
ASSERT_FALSE(pool.contains(entities[1u]));
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
pool.insert(std::begin(entities), std::end(entities), 3);
|
||||
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 1);
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_EQ(pool.get(entities[0u]).value, 3);
|
||||
ASSERT_EQ(pool.get(entities[1u]).value, 3);
|
||||
|
||||
pool.erase(std::begin(entities), std::end(entities));
|
||||
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
ASSERT_EQ(on_construct.value, 6);
|
||||
ASSERT_EQ(on_destroy.value, 3);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, VoidType) {
|
||||
entt::sigh_storage_mixin<entt::storage<void>> pool;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
pool.emplace(entt::entity{99});
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<void>());
|
||||
ASSERT_TRUE(pool.contains(entt::entity{99}));
|
||||
|
||||
entt::sigh_storage_mixin<entt::storage<void>> other{std::move(pool)};
|
||||
|
||||
ASSERT_FALSE(pool.contains(entt::entity{99}));
|
||||
ASSERT_TRUE(other.contains(entt::entity{99}));
|
||||
|
||||
pool = std::move(other);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entt::entity{99}));
|
||||
ASSERT_FALSE(other.contains(entt::entity{99}));
|
||||
|
||||
pool.clear();
|
||||
|
||||
ASSERT_EQ(on_construct.value, 1);
|
||||
ASSERT_EQ(on_destroy.value, 1);
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, Move) {
|
||||
entt::sigh_storage_mixin<entt::storage<int>> pool;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
pool.emplace(entt::entity{3}, 3);
|
||||
|
||||
ASSERT_TRUE(std::is_move_constructible_v<decltype(pool)>);
|
||||
ASSERT_TRUE(std::is_move_assignable_v<decltype(pool)>);
|
||||
ASSERT_EQ(pool.type(), entt::type_id<int>());
|
||||
|
||||
entt::sigh_storage_mixin<entt::storage<int>> other{std::move(pool)};
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_EQ(other.type(), entt::type_id<int>());
|
||||
ASSERT_EQ(pool.at(0u), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_EQ(other.at(0u), entt::entity{3});
|
||||
ASSERT_EQ(other.get(entt::entity{3}), 3);
|
||||
|
||||
pool = std::move(other);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_EQ(pool.at(0u), entt::entity{3});
|
||||
ASSERT_EQ(pool.get(entt::entity{3}), 3);
|
||||
ASSERT_EQ(other.at(0u), static_cast<entt::entity>(entt::null));
|
||||
|
||||
other = entt::sigh_storage_mixin<entt::storage<int>>{};
|
||||
other.bind(entt::forward_as_any(registry));
|
||||
|
||||
other.emplace(entt::entity{42}, 42);
|
||||
other = std::move(pool);
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_EQ(pool.at(0u), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_EQ(other.at(0u), entt::entity{3});
|
||||
ASSERT_EQ(other.get(entt::entity{3}), 3);
|
||||
|
||||
other.clear();
|
||||
|
||||
ASSERT_EQ(on_construct.value, 1);
|
||||
ASSERT_EQ(on_destroy.value, 1);
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, Swap) {
|
||||
entt::sigh_storage_mixin<entt::storage<int>> pool;
|
||||
entt::sigh_storage_mixin<entt::storage<int>> other;
|
||||
entt::registry registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
other.bind(entt::forward_as_any(registry));
|
||||
other.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
other.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
pool.emplace(entt::entity{42}, 41);
|
||||
|
||||
other.emplace(entt::entity{9}, 8);
|
||||
other.emplace(entt::entity{3}, 2);
|
||||
other.erase(entt::entity{9});
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
|
||||
pool.swap(other);
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<int>());
|
||||
ASSERT_EQ(other.type(), entt::type_id<int>());
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
|
||||
ASSERT_EQ(pool.at(0u), entt::entity{3});
|
||||
ASSERT_EQ(pool.get(entt::entity{3}), 2);
|
||||
|
||||
ASSERT_EQ(other.at(0u), entt::entity{42});
|
||||
ASSERT_EQ(other.get(entt::entity{42}), 41);
|
||||
|
||||
pool.clear();
|
||||
other.clear();
|
||||
|
||||
ASSERT_EQ(on_construct.value, 3);
|
||||
ASSERT_EQ(on_destroy.value, 3);
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, CustomAllocator) {
|
||||
auto test = [](auto pool, auto alloc) {
|
||||
using registry_type = typename decltype(pool)::registry_type;
|
||||
registry_type registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().template connect<&listener<registry_type>>(on_construct);
|
||||
pool.on_destroy().template connect<&listener<registry_type>>(on_destroy);
|
||||
|
||||
pool.reserve(1u);
|
||||
|
||||
ASSERT_NE(pool.capacity(), 0u);
|
||||
|
||||
pool.emplace(entt::entity{0});
|
||||
pool.emplace(entt::entity{1});
|
||||
|
||||
decltype(pool) other{std::move(pool), alloc};
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_EQ(pool.capacity(), 0u);
|
||||
ASSERT_NE(other.capacity(), 0u);
|
||||
ASSERT_EQ(other.size(), 2u);
|
||||
|
||||
pool = std::move(other);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_EQ(other.capacity(), 0u);
|
||||
ASSERT_NE(pool.capacity(), 0u);
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
|
||||
pool.swap(other);
|
||||
pool = std::move(other);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_EQ(other.capacity(), 0u);
|
||||
ASSERT_NE(pool.capacity(), 0u);
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
|
||||
pool.clear();
|
||||
|
||||
ASSERT_NE(pool.capacity(), 0u);
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 2);
|
||||
};
|
||||
|
||||
test::throwing_allocator<entt::entity> allocator{};
|
||||
|
||||
test(entt::sigh_storage_mixin<entt::basic_storage<int, entt::entity, test::throwing_allocator<int>>>{allocator}, allocator);
|
||||
test(entt::sigh_storage_mixin<entt::basic_storage<std::true_type, entt::entity, test::throwing_allocator<std::true_type>>>{allocator}, allocator);
|
||||
test(entt::sigh_storage_mixin<entt::basic_storage<stable_type, entt::entity, test::throwing_allocator<stable_type>>>{allocator}, allocator);
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, ThrowingAllocator) {
|
||||
auto test = [](auto pool) {
|
||||
using pool_allocator_type = typename decltype(pool)::allocator_type;
|
||||
using value_type = typename decltype(pool)::value_type;
|
||||
using registry_type = typename decltype(pool)::registry_type;
|
||||
|
||||
typename std::decay_t<decltype(pool)>::base_type &base = pool;
|
||||
constexpr auto packed_page_size = entt::component_traits<typename decltype(pool)::value_type>::page_size;
|
||||
constexpr auto sparse_page_size = entt::entt_traits<typename decltype(pool)::entity_type>::page_size;
|
||||
registry_type registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().template connect<&listener<registry_type>>(on_construct);
|
||||
pool.on_destroy().template connect<&listener<registry_type>>(on_destroy);
|
||||
|
||||
pool_allocator_type::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW(pool.reserve(1u), typename pool_allocator_type::exception_type);
|
||||
ASSERT_EQ(pool.capacity(), 0u);
|
||||
|
||||
pool_allocator_type::trigger_after_allocate = true;
|
||||
|
||||
ASSERT_THROW(pool.reserve(2 * packed_page_size), typename pool_allocator_type::exception_type);
|
||||
ASSERT_EQ(pool.capacity(), packed_page_size);
|
||||
|
||||
pool.shrink_to_fit();
|
||||
|
||||
ASSERT_EQ(pool.capacity(), 0u);
|
||||
|
||||
test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW(pool.emplace(entt::entity{0}, 0), test::throwing_allocator<entt::entity>::exception_type);
|
||||
ASSERT_FALSE(pool.contains(entt::entity{0}));
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW(base.emplace(entt::entity{0}), test::throwing_allocator<entt::entity>::exception_type);
|
||||
ASSERT_FALSE(base.contains(entt::entity{0}));
|
||||
ASSERT_TRUE(base.empty());
|
||||
|
||||
pool_allocator_type::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW(pool.emplace(entt::entity{0}, 0), typename pool_allocator_type::exception_type);
|
||||
ASSERT_FALSE(pool.contains(entt::entity{0}));
|
||||
ASSERT_NO_FATAL_FAILURE(pool.compact());
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
pool.emplace(entt::entity{0}, 0);
|
||||
const entt::entity entities[2u]{entt::entity{1}, entt::entity{sparse_page_size}};
|
||||
test::throwing_allocator<entt::entity>::trigger_after_allocate = true;
|
||||
|
||||
ASSERT_THROW(pool.insert(std::begin(entities), std::end(entities), value_type{0}), test::throwing_allocator<entt::entity>::exception_type);
|
||||
ASSERT_TRUE(pool.contains(entt::entity{1}));
|
||||
ASSERT_FALSE(pool.contains(entt::entity{sparse_page_size}));
|
||||
|
||||
pool.erase(entt::entity{1});
|
||||
const value_type components[2u]{value_type{1}, value_type{sparse_page_size}};
|
||||
test::throwing_allocator<entt::entity>::trigger_on_allocate = true;
|
||||
pool.compact();
|
||||
|
||||
ASSERT_THROW(pool.insert(std::begin(entities), std::end(entities), std::begin(components)), test::throwing_allocator<entt::entity>::exception_type);
|
||||
ASSERT_TRUE(pool.contains(entt::entity{1}));
|
||||
ASSERT_FALSE(pool.contains(entt::entity{sparse_page_size}));
|
||||
|
||||
ASSERT_EQ(on_construct.value, 1);
|
||||
ASSERT_EQ(on_destroy.value, 1);
|
||||
};
|
||||
|
||||
test(entt::sigh_storage_mixin<entt::basic_storage<int, entt::entity, test::throwing_allocator<int>>>{});
|
||||
test(entt::sigh_storage_mixin<entt::basic_storage<stable_type, entt::entity, test::throwing_allocator<stable_type>>>{});
|
||||
}
|
||||
|
||||
TEST(SighStorageMixin, ThrowingComponent) {
|
||||
entt::sigh_storage_mixin<entt::storage<test::throwing_type>> pool;
|
||||
using registry_type = typename decltype(pool)::registry_type;
|
||||
registry_type registry;
|
||||
|
||||
counter on_construct{};
|
||||
counter on_destroy{};
|
||||
|
||||
pool.bind(entt::forward_as_any(registry));
|
||||
pool.on_construct().connect<&listener<registry_type>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<registry_type>>(on_destroy);
|
||||
|
||||
test::throwing_type::trigger_on_value = 42;
|
||||
|
||||
// strong exception safety
|
||||
ASSERT_THROW(pool.emplace(entt::entity{0}, test::throwing_type{42}), typename test::throwing_type::exception_type);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
const entt::entity entities[2u]{entt::entity{42}, entt::entity{1}};
|
||||
const test::throwing_type components[2u]{42, 1};
|
||||
|
||||
// basic exception safety
|
||||
ASSERT_THROW(pool.insert(std::begin(entities), std::end(entities), test::throwing_type{42}), typename test::throwing_type::exception_type);
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
ASSERT_FALSE(pool.contains(entt::entity{1}));
|
||||
|
||||
// basic exception safety
|
||||
ASSERT_THROW(pool.insert(std::begin(entities), std::end(entities), std::begin(components)), typename test::throwing_type::exception_type);
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
ASSERT_FALSE(pool.contains(entt::entity{1}));
|
||||
|
||||
// basic exception safety
|
||||
ASSERT_THROW(pool.insert(std::rbegin(entities), std::rend(entities), std::rbegin(components)), typename test::throwing_type::exception_type);
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_TRUE(pool.contains(entt::entity{1}));
|
||||
ASSERT_EQ(pool.get(entt::entity{1}), 1);
|
||||
|
||||
pool.clear();
|
||||
pool.emplace(entt::entity{1}, 1);
|
||||
pool.emplace(entt::entity{42}, 42);
|
||||
|
||||
// basic exception safety
|
||||
ASSERT_THROW(pool.erase(entt::entity{1}), typename test::throwing_type::exception_type);
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_TRUE(pool.contains(entt::entity{42}));
|
||||
ASSERT_TRUE(pool.contains(entt::entity{1}));
|
||||
ASSERT_EQ(pool.at(0u), entt::entity{1});
|
||||
ASSERT_EQ(pool.at(1u), entt::entity{42});
|
||||
ASSERT_EQ(pool.get(entt::entity{42}), 42);
|
||||
// the element may have been moved but it's still there
|
||||
ASSERT_EQ(pool.get(entt::entity{1}), test::throwing_type::moved_from_value);
|
||||
|
||||
test::throwing_type::trigger_on_value = 99;
|
||||
pool.erase(entt::entity{1});
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_TRUE(pool.contains(entt::entity{42}));
|
||||
ASSERT_FALSE(pool.contains(entt::entity{1}));
|
||||
ASSERT_EQ(pool.at(0u), entt::entity{42});
|
||||
ASSERT_EQ(pool.get(entt::entity{42}), 42);
|
||||
|
||||
ASSERT_EQ(on_construct.value, 2);
|
||||
ASSERT_EQ(on_destroy.value, 3);
|
||||
}
|
1290
test/entt/entity/view.cpp
Normal file
1290
test/entt/entity/view.cpp
Normal file
File diff suppressed because it is too large
Load Diff
432
test/entt/graph/adjacency_matrix.cpp
Normal file
432
test/entt/graph/adjacency_matrix.cpp
Normal file
@ -0,0 +1,432 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/graph/adjacency_matrix.hpp>
|
||||
#include "../common/throwing_allocator.hpp"
|
||||
|
||||
TEST(AdjacencyMatrix, Resize) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{2};
|
||||
adjacency_matrix.insert(1u, 0u);
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 2u);
|
||||
ASSERT_TRUE(adjacency_matrix.contains(1u, 0u));
|
||||
|
||||
adjacency_matrix.resize(3u);
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 3u);
|
||||
ASSERT_TRUE(adjacency_matrix.contains(1u, 0u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Constructors) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{};
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
|
||||
adjacency_matrix = entt::adjacency_matrix<entt::directed_tag>{std::allocator<bool>{}};
|
||||
adjacency_matrix = entt::adjacency_matrix<entt::directed_tag>{3u, std::allocator<bool>{}};
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 3u);
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
entt::adjacency_matrix<entt::directed_tag> temp{adjacency_matrix, adjacency_matrix.get_allocator()};
|
||||
entt::adjacency_matrix<entt::directed_tag> other{std::move(adjacency_matrix), adjacency_matrix.get_allocator()};
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
|
||||
ASSERT_FALSE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_TRUE(other.contains(0u, 1u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Copy) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
entt::adjacency_matrix<entt::directed_tag> other{adjacency_matrix};
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 3u);
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_TRUE(other.contains(0u, 1u));
|
||||
|
||||
adjacency_matrix.resize(4u);
|
||||
adjacency_matrix.insert(0u, 2u);
|
||||
other.insert(1u, 2u);
|
||||
|
||||
other = adjacency_matrix;
|
||||
|
||||
ASSERT_EQ(other.size(), 4u);
|
||||
ASSERT_EQ(adjacency_matrix.size(), 4u);
|
||||
|
||||
ASSERT_TRUE(other.contains(0u, 1u));
|
||||
ASSERT_FALSE(other.contains(1u, 2u));
|
||||
ASSERT_TRUE(other.contains(0u, 2u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Move) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
entt::adjacency_matrix<entt::directed_tag> other{std::move(adjacency_matrix)};
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
|
||||
ASSERT_FALSE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_TRUE(other.contains(0u, 1u));
|
||||
|
||||
adjacency_matrix = {};
|
||||
adjacency_matrix.resize(4u);
|
||||
adjacency_matrix.insert(0u, 2u);
|
||||
other.insert(1u, 2u);
|
||||
|
||||
other = std::move(adjacency_matrix);
|
||||
|
||||
ASSERT_EQ(other.size(), 4u);
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
|
||||
ASSERT_FALSE(other.contains(0u, 1u));
|
||||
ASSERT_FALSE(other.contains(1u, 2u));
|
||||
ASSERT_TRUE(other.contains(0u, 2u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Swap) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||
entt::adjacency_matrix<entt::directed_tag> other{};
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
ASSERT_EQ(other.size(), 0u);
|
||||
ASSERT_EQ(adjacency_matrix.size(), 3u);
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_FALSE(other.contains(0u, 1u));
|
||||
|
||||
adjacency_matrix.swap(other);
|
||||
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
ASSERT_FALSE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_TRUE(other.contains(0u, 1u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, InsertDirected) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||
|
||||
auto first = adjacency_matrix.insert(0u, 1u);
|
||||
auto second = adjacency_matrix.insert(0u, 2u);
|
||||
auto other = adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
ASSERT_TRUE(first.second);
|
||||
ASSERT_TRUE(second.second);
|
||||
ASSERT_FALSE(other.second);
|
||||
|
||||
ASSERT_NE(first.first, second.first);
|
||||
ASSERT_EQ(first.first, other.first);
|
||||
|
||||
ASSERT_EQ(*first.first, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(*second.first, std::make_pair(std::size_t{0u}, std::size_t{2u}));
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_FALSE(adjacency_matrix.contains(2u, 0u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, InsertUndirected) {
|
||||
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
|
||||
|
||||
auto first = adjacency_matrix.insert(0u, 1u);
|
||||
auto second = adjacency_matrix.insert(0u, 2u);
|
||||
auto other = adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
ASSERT_TRUE(first.second);
|
||||
ASSERT_TRUE(second.second);
|
||||
ASSERT_FALSE(other.second);
|
||||
|
||||
ASSERT_NE(first.first, second.first);
|
||||
ASSERT_EQ(first.first, other.first);
|
||||
|
||||
ASSERT_EQ(*first.first, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(*second.first, std::make_pair(std::size_t{0u}, std::size_t{2u}));
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_TRUE(adjacency_matrix.contains(2u, 0u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, EraseDirected) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_FALSE(adjacency_matrix.contains(1u, 0u));
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.erase(0u, 1u), 1u);
|
||||
ASSERT_EQ(adjacency_matrix.erase(0u, 1u), 0u);
|
||||
|
||||
ASSERT_FALSE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_FALSE(adjacency_matrix.contains(1u, 0u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, EraseUndirected) {
|
||||
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_TRUE(adjacency_matrix.contains(1u, 0u));
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.erase(0u, 1u), 1u);
|
||||
ASSERT_EQ(adjacency_matrix.erase(0u, 1u), 0u);
|
||||
|
||||
ASSERT_FALSE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_FALSE(adjacency_matrix.contains(1u, 0u));
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Clear) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(0u, 2u);
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 2u));
|
||||
ASSERT_EQ(adjacency_matrix.size(), 3u);
|
||||
|
||||
adjacency_matrix.clear();
|
||||
|
||||
ASSERT_FALSE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_FALSE(adjacency_matrix.contains(0u, 2u));
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, VertexIterator) {
|
||||
using iterator = typename entt::adjacency_matrix<entt::directed_tag>::vertex_iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, std::size_t>);
|
||||
static_assert(std::is_same_v<iterator::pointer, void>);
|
||||
static_assert(std::is_same_v<iterator::reference, std::size_t>);
|
||||
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{2u};
|
||||
const auto iterable = adjacency_matrix.vertices();
|
||||
|
||||
iterator end{iterable.begin()};
|
||||
iterator begin{};
|
||||
|
||||
begin = iterable.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, iterable.begin());
|
||||
ASSERT_EQ(end, iterable.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(*begin, 0u);
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(*begin, 1u);
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, EdgeIterator) {
|
||||
using iterator = typename entt::adjacency_matrix<entt::directed_tag>::edge_iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, std::pair<std::size_t, std::size_t>>);
|
||||
static_assert(std::is_same_v<iterator::pointer, entt::input_iterator_pointer<std::pair<std::size_t, std::size_t>>>);
|
||||
static_assert(std::is_same_v<iterator::reference, std::pair<std::size_t, std::size_t>>);
|
||||
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(0u, 2u);
|
||||
|
||||
const auto iterable = adjacency_matrix.edges();
|
||||
|
||||
iterator end{iterable.begin()};
|
||||
iterator begin{};
|
||||
|
||||
begin = iterable.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, iterable.begin());
|
||||
ASSERT_EQ(end, iterable.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(*begin, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(*begin.operator->(), std::make_pair(std::size_t{0u}, std::size_t{2u}));
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, Vertices) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{};
|
||||
auto iterable = adjacency_matrix.vertices();
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 0u);
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.resize(2u);
|
||||
iterable = adjacency_matrix.vertices();
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 2u);
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, 0u);
|
||||
ASSERT_EQ(*it, 1u);
|
||||
ASSERT_EQ(++it, iterable.end());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, EdgesDirected) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||
auto iterable = adjacency_matrix.edges();
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(1u, 2u);
|
||||
iterable = adjacency_matrix.edges();
|
||||
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(*it.operator->(), std::make_pair(std::size_t{1u}, std::size_t{2u}));
|
||||
ASSERT_EQ(++it, iterable.end());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, EdgesUndirected) {
|
||||
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
|
||||
auto iterable = adjacency_matrix.edges();
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(1u, 2u);
|
||||
iterable = adjacency_matrix.edges();
|
||||
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(*it.operator->(), std::make_pair(std::size_t{1u}, std::size_t{0u}));
|
||||
ASSERT_EQ(*(++it).operator->(), std::make_pair(std::size_t{1u}, std::size_t{2u}));
|
||||
ASSERT_EQ(*++it, std::make_pair(std::size_t{2u}, std::size_t{1u}));
|
||||
|
||||
ASSERT_EQ(++it, iterable.end());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, OutEdgesDirected) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||
auto iterable = adjacency_matrix.out_edges(0u);
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(1u, 2u);
|
||||
iterable = adjacency_matrix.out_edges(0u);
|
||||
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(it, iterable.end());
|
||||
|
||||
iterable = adjacency_matrix.out_edges(2u);
|
||||
it = iterable.cbegin();
|
||||
|
||||
ASSERT_EQ(it, iterable.cend());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, OutEdgesUndirected) {
|
||||
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
|
||||
auto iterable = adjacency_matrix.out_edges(0u);
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(1u, 2u);
|
||||
iterable = adjacency_matrix.out_edges(0u);
|
||||
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(it, iterable.end());
|
||||
|
||||
iterable = adjacency_matrix.out_edges(2u);
|
||||
it = iterable.cbegin();
|
||||
|
||||
ASSERT_NE(it, iterable.cend());
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{2u}, std::size_t{1u}));
|
||||
ASSERT_EQ(it, iterable.cend());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, InEdgesDirected) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||
auto iterable = adjacency_matrix.in_edges(1u);
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(1u, 2u);
|
||||
iterable = adjacency_matrix.in_edges(1u);
|
||||
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(it, iterable.end());
|
||||
|
||||
iterable = adjacency_matrix.in_edges(0u);
|
||||
it = iterable.cbegin();
|
||||
|
||||
ASSERT_EQ(it, iterable.cend());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, InEdgesUndirected) {
|
||||
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
|
||||
auto iterable = adjacency_matrix.in_edges(1u);
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(1u, 2u);
|
||||
iterable = adjacency_matrix.in_edges(1u);
|
||||
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(it, iterable.end());
|
||||
|
||||
iterable = adjacency_matrix.in_edges(0u);
|
||||
it = iterable.cbegin();
|
||||
|
||||
ASSERT_NE(it, iterable.cend());
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
|
||||
ASSERT_EQ(it, iterable.cend());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, ThrowingAllocator) {
|
||||
using allocator = test::throwing_allocator<std::size_t>;
|
||||
using exception = typename allocator::exception_type;
|
||||
|
||||
entt::adjacency_matrix<entt::directed_tag, allocator> adjacency_matrix{2u};
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
allocator::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 2u);
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
|
||||
ASSERT_THROW(adjacency_matrix.resize(4u), exception);
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 2u);
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
}
|
62
test/entt/graph/dot.cpp
Normal file
62
test/entt/graph/dot.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/graph/adjacency_matrix.hpp>
|
||||
#include <entt/graph/dot.hpp>
|
||||
|
||||
TEST(Dot, DirectedGraph) {
|
||||
std::ostringstream output{};
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(1u, 2u);
|
||||
adjacency_matrix.insert(0u, 2u);
|
||||
|
||||
entt::dot(output, adjacency_matrix);
|
||||
|
||||
const std::string expected = "digraph{0[];1[];2[];0->1;0->2;1->2;}";
|
||||
const auto str = output.str();
|
||||
|
||||
ASSERT_FALSE(str.empty());
|
||||
ASSERT_EQ(str, expected);
|
||||
}
|
||||
|
||||
TEST(Dot, UndirectedGraph) {
|
||||
std::ostringstream output{};
|
||||
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(1u, 2u);
|
||||
adjacency_matrix.insert(0u, 2u);
|
||||
|
||||
entt::dot(output, adjacency_matrix);
|
||||
|
||||
const std::string expected = "graph{0[];1[];2[];0--1;0--2;1--0;1--2;2--0;2--1;}";
|
||||
const auto str = output.str();
|
||||
|
||||
ASSERT_FALSE(str.empty());
|
||||
ASSERT_EQ(str, expected);
|
||||
}
|
||||
|
||||
TEST(Dot, CustomWriter) {
|
||||
std::ostringstream output{};
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.insert(1u, 2u);
|
||||
adjacency_matrix.insert(0u, 2u);
|
||||
|
||||
entt::dot(output, adjacency_matrix, [&adjacency_matrix](std::ostream &out, std::size_t vertex) {
|
||||
out << "label=\"v" << vertex << "\"";
|
||||
|
||||
if(auto in_edges = adjacency_matrix.in_edges(vertex); in_edges.cbegin() == in_edges.cend()) {
|
||||
out << ",shape=\"box\"";
|
||||
}
|
||||
});
|
||||
|
||||
const std::string expected = "digraph{0[label=\"v0\",shape=\"box\"];1[label=\"v1\"];2[label=\"v2\"];0->1;0->2;1->2;}";
|
||||
const auto str = output.str();
|
||||
|
||||
ASSERT_FALSE(str.empty());
|
||||
ASSERT_EQ(str, expected);
|
||||
}
|
289
test/entt/graph/flow.cpp
Normal file
289
test/entt/graph/flow.cpp
Normal file
@ -0,0 +1,289 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/graph/flow.hpp>
|
||||
#include "../common/throwing_allocator.hpp"
|
||||
|
||||
TEST(Flow, Constructors) {
|
||||
entt::flow flow{};
|
||||
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
|
||||
flow = entt::flow{std::allocator<entt::id_type>{}};
|
||||
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
|
||||
flow.bind(0);
|
||||
flow.bind(3);
|
||||
flow.bind(99);
|
||||
|
||||
ASSERT_EQ(flow.size(), 3u);
|
||||
|
||||
entt::flow temp{flow, flow.get_allocator()};
|
||||
entt::flow other{std::move(flow), flow.get_allocator()};
|
||||
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
|
||||
ASSERT_EQ(other[0u], 0);
|
||||
ASSERT_EQ(other[1u], 3);
|
||||
ASSERT_EQ(other[2u], 99);
|
||||
}
|
||||
|
||||
TEST(Flow, Copy) {
|
||||
entt::flow flow{};
|
||||
|
||||
flow.bind(0);
|
||||
flow.bind(3);
|
||||
flow.bind(99);
|
||||
|
||||
entt::flow other{flow};
|
||||
|
||||
ASSERT_EQ(flow.size(), 3u);
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
|
||||
ASSERT_EQ(other[0u], 0);
|
||||
ASSERT_EQ(other[1u], 3);
|
||||
ASSERT_EQ(other[2u], 99);
|
||||
|
||||
flow.bind(1);
|
||||
other.bind(2);
|
||||
|
||||
other = flow;
|
||||
|
||||
ASSERT_EQ(other.size(), 4u);
|
||||
ASSERT_EQ(flow.size(), 4u);
|
||||
|
||||
ASSERT_EQ(other[0u], 0);
|
||||
ASSERT_EQ(other[1u], 3);
|
||||
ASSERT_EQ(other[2u], 99);
|
||||
ASSERT_EQ(other[3u], 1);
|
||||
}
|
||||
|
||||
TEST(Flow, Move) {
|
||||
entt::flow flow{};
|
||||
|
||||
flow.bind(0);
|
||||
flow.bind(3);
|
||||
flow.bind(99);
|
||||
|
||||
entt::flow other{std::move(flow)};
|
||||
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
|
||||
ASSERT_EQ(other[0u], 0);
|
||||
ASSERT_EQ(other[1u], 3);
|
||||
ASSERT_EQ(other[2u], 99);
|
||||
|
||||
flow = {};
|
||||
flow.bind(1);
|
||||
other.bind(2);
|
||||
|
||||
other = std::move(flow);
|
||||
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
|
||||
ASSERT_EQ(other[0u], 1);
|
||||
}
|
||||
|
||||
TEST(Flow, Swap) {
|
||||
entt::flow flow{};
|
||||
entt::flow other{};
|
||||
|
||||
flow.bind(7);
|
||||
|
||||
ASSERT_EQ(other.size(), 0u);
|
||||
ASSERT_EQ(flow.size(), 1u);
|
||||
ASSERT_EQ(flow[0u], 7);
|
||||
|
||||
flow.swap(other);
|
||||
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
ASSERT_EQ(other[0u], 7);
|
||||
}
|
||||
|
||||
TEST(Flow, Clear) {
|
||||
entt::flow flow{};
|
||||
|
||||
flow.bind(0);
|
||||
flow.bind(99);
|
||||
|
||||
ASSERT_EQ(flow.size(), 2u);
|
||||
ASSERT_EQ(flow[0u], 0);
|
||||
ASSERT_EQ(flow[1u], 99);
|
||||
|
||||
flow.clear();
|
||||
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Flow, Set) {
|
||||
entt::flow flow{};
|
||||
flow.bind(0).set(10, true).bind(1).set(10, true).set(11, false);
|
||||
auto graph = flow.graph();
|
||||
|
||||
ASSERT_EQ(flow.size(), 2u);
|
||||
ASSERT_EQ(flow.size(), graph.size());
|
||||
ASSERT_NE(graph.edges().cbegin(), graph.edges().cend());
|
||||
|
||||
ASSERT_TRUE(graph.contains(0u, 1u));
|
||||
ASSERT_FALSE(graph.contains(1u, 0u));
|
||||
}
|
||||
|
||||
TEST(Flow, RO) {
|
||||
entt::flow flow{};
|
||||
flow.bind(0).ro(10).bind(1).ro(10).ro(11);
|
||||
auto graph = flow.graph();
|
||||
|
||||
ASSERT_EQ(flow.size(), 2u);
|
||||
ASSERT_EQ(flow.size(), graph.size());
|
||||
ASSERT_EQ(graph.edges().cbegin(), graph.edges().cend());
|
||||
}
|
||||
|
||||
TEST(Flow, RangeRO) {
|
||||
entt::flow flow{};
|
||||
const entt::id_type res[2u]{10, 11};
|
||||
flow.bind(0).ro(res, res + 1).bind(1).ro(res, res + 2);
|
||||
auto graph = flow.graph();
|
||||
|
||||
ASSERT_EQ(flow.size(), 2u);
|
||||
ASSERT_EQ(flow.size(), graph.size());
|
||||
ASSERT_EQ(graph.edges().cbegin(), graph.edges().cend());
|
||||
}
|
||||
|
||||
TEST(Flow, RW) {
|
||||
entt::flow flow{};
|
||||
flow.bind(0).rw(10).bind(1).rw(10).rw(11);
|
||||
auto graph = flow.graph();
|
||||
|
||||
ASSERT_EQ(flow.size(), 2u);
|
||||
ASSERT_EQ(flow.size(), graph.size());
|
||||
ASSERT_NE(graph.edges().cbegin(), graph.edges().cend());
|
||||
|
||||
ASSERT_TRUE(graph.contains(0u, 1u));
|
||||
ASSERT_FALSE(graph.contains(1u, 0u));
|
||||
}
|
||||
|
||||
TEST(Flow, RangeRW) {
|
||||
entt::flow flow{};
|
||||
const entt::id_type res[2u]{10, 11};
|
||||
flow.bind(0).rw(res, res + 1).bind(1).rw(res, res + 2);
|
||||
auto graph = flow.graph();
|
||||
|
||||
ASSERT_EQ(flow.size(), 2u);
|
||||
ASSERT_EQ(flow.size(), graph.size());
|
||||
ASSERT_NE(graph.edges().cbegin(), graph.edges().cend());
|
||||
|
||||
ASSERT_TRUE(graph.contains(0u, 1u));
|
||||
ASSERT_FALSE(graph.contains(1u, 0u));
|
||||
}
|
||||
|
||||
TEST(Flow, Graph) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::flow flow{};
|
||||
|
||||
flow.bind("task_0"_hs)
|
||||
.ro("resource_0"_hs)
|
||||
.rw("resource_1"_hs);
|
||||
|
||||
flow.bind("task_1"_hs)
|
||||
.ro("resource_0"_hs)
|
||||
.rw("resource_2"_hs);
|
||||
|
||||
flow.bind("task_2"_hs)
|
||||
.ro("resource_1"_hs)
|
||||
.rw("resource_3"_hs);
|
||||
|
||||
flow.bind("task_3"_hs)
|
||||
.rw("resource_1"_hs)
|
||||
.ro("resource_2"_hs);
|
||||
|
||||
flow.bind("task_4"_hs)
|
||||
.rw("resource_0"_hs);
|
||||
|
||||
auto graph = flow.graph();
|
||||
|
||||
ASSERT_EQ(flow.size(), 5u);
|
||||
ASSERT_EQ(flow.size(), graph.size());
|
||||
|
||||
ASSERT_EQ(flow[0u], "task_0"_hs);
|
||||
ASSERT_EQ(flow[1u], "task_1"_hs);
|
||||
ASSERT_EQ(flow[2u], "task_2"_hs);
|
||||
ASSERT_EQ(flow[3u], "task_3"_hs);
|
||||
ASSERT_EQ(flow[4u], "task_4"_hs);
|
||||
|
||||
auto it = graph.edges().cbegin();
|
||||
const auto last = graph.edges().cend();
|
||||
|
||||
ASSERT_NE(it, last);
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{2u}));
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{4u}));
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{3u}));
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{4u}));
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{2u}, std::size_t{3u}));
|
||||
ASSERT_EQ(it, last);
|
||||
}
|
||||
|
||||
TEST(Flow, Sync) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::flow flow{};
|
||||
|
||||
flow.bind("task_0"_hs)
|
||||
.ro("resource_0"_hs);
|
||||
|
||||
flow.bind("task_1"_hs)
|
||||
.rw("resource_1"_hs);
|
||||
|
||||
flow.bind("task_2"_hs)
|
||||
.sync();
|
||||
|
||||
flow.bind("task_3"_hs)
|
||||
.ro("resource_0"_hs)
|
||||
.rw("resource_2"_hs);
|
||||
|
||||
flow.bind("task_4"_hs)
|
||||
.ro("resource_2"_hs);
|
||||
|
||||
auto graph = flow.graph();
|
||||
|
||||
ASSERT_EQ(flow.size(), 5u);
|
||||
ASSERT_EQ(flow.size(), graph.size());
|
||||
|
||||
ASSERT_EQ(flow[0u], "task_0"_hs);
|
||||
ASSERT_EQ(flow[1u], "task_1"_hs);
|
||||
ASSERT_EQ(flow[2u], "task_2"_hs);
|
||||
ASSERT_EQ(flow[3u], "task_3"_hs);
|
||||
ASSERT_EQ(flow[4u], "task_4"_hs);
|
||||
|
||||
auto it = graph.edges().cbegin();
|
||||
const auto last = graph.edges().cend();
|
||||
|
||||
ASSERT_NE(it, last);
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{2u}));
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{2u}));
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{2u}, std::size_t{3u}));
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{3u}, std::size_t{4u}));
|
||||
ASSERT_EQ(it, last);
|
||||
}
|
||||
|
||||
TEST(Flow, ThrowingAllocator) {
|
||||
using allocator = test::throwing_allocator<entt::id_type>;
|
||||
using task_allocator = test::throwing_allocator<std::pair<std::size_t, entt::id_type>>;
|
||||
using task_exception = typename task_allocator::exception_type;
|
||||
|
||||
entt::basic_flow<allocator> flow{};
|
||||
|
||||
task_allocator::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
ASSERT_THROW(flow.bind(1), task_exception);
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
|
||||
flow.bind(1);
|
||||
|
||||
ASSERT_EQ(flow.size(), 1u);
|
||||
}
|
78
test/entt/locator/locator.cpp
Normal file
78
test/entt/locator/locator.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
#include <memory>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/locator/locator.hpp>
|
||||
#include "../common/config.h"
|
||||
|
||||
struct base_service {
|
||||
virtual ~base_service() = default;
|
||||
virtual void invoke() {}
|
||||
};
|
||||
|
||||
struct null_service: base_service {
|
||||
void invoke() override {
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
static inline bool invoked{};
|
||||
};
|
||||
|
||||
struct derived_service: base_service {
|
||||
void invoke() override {
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
static inline bool invoked{};
|
||||
};
|
||||
|
||||
struct ServiceLocator: ::testing::Test {
|
||||
void SetUp() override {
|
||||
null_service::invoked = false;
|
||||
derived_service::invoked = false;
|
||||
}
|
||||
};
|
||||
|
||||
using ServiceLocatorDeathTest = ServiceLocator;
|
||||
|
||||
TEST(ServiceLocator, Functionalities) {
|
||||
ASSERT_FALSE(entt::locator<base_service>::has_value());
|
||||
ASSERT_FALSE(derived_service::invoked);
|
||||
ASSERT_FALSE(null_service::invoked);
|
||||
|
||||
entt::locator<base_service>::value_or<null_service>().invoke();
|
||||
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_TRUE(null_service::invoked);
|
||||
|
||||
auto handle = entt::locator<base_service>::handle();
|
||||
entt::locator<base_service>::reset();
|
||||
|
||||
ASSERT_FALSE(entt::locator<base_service>::has_value());
|
||||
|
||||
entt::locator<base_service>::reset(handle);
|
||||
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
|
||||
entt::locator<base_service>::reset(decltype(handle){});
|
||||
|
||||
ASSERT_FALSE(entt::locator<base_service>::has_value());
|
||||
|
||||
entt::locator<base_service>::emplace<derived_service>();
|
||||
entt::locator<base_service>::value().invoke();
|
||||
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_TRUE(derived_service::invoked);
|
||||
|
||||
derived_service::invoked = false;
|
||||
entt::locator<base_service>::allocate_emplace<derived_service>(std::allocator<derived_service>{}).invoke();
|
||||
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_TRUE(derived_service::invoked);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(ServiceLocatorDeathTest, UninitializedValue) {
|
||||
ASSERT_NO_FATAL_FAILURE(entt::locator<base_service>::value_or().invoke());
|
||||
|
||||
entt::locator<base_service>::reset();
|
||||
|
||||
ASSERT_DEATH(entt::locator<base_service>::value().invoke(), "");
|
||||
}
|
1371
test/entt/meta/meta_any.cpp
Normal file
1371
test/entt/meta/meta_any.cpp
Normal file
File diff suppressed because it is too large
Load Diff
193
test/entt/meta/meta_base.cpp
Normal file
193
test/entt/meta/meta_base.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/locator/locator.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/node.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
|
||||
struct base_1_t {
|
||||
base_1_t() = default;
|
||||
int value_1{};
|
||||
};
|
||||
|
||||
struct base_2_t {
|
||||
base_2_t() = default;
|
||||
|
||||
operator int() const {
|
||||
return value_2;
|
||||
}
|
||||
|
||||
int value_2{};
|
||||
};
|
||||
|
||||
struct base_3_t: base_2_t {
|
||||
base_3_t() = default;
|
||||
int value_3{};
|
||||
};
|
||||
|
||||
struct derived_t: base_1_t, base_3_t {
|
||||
derived_t() = default;
|
||||
int value{};
|
||||
};
|
||||
|
||||
struct MetaBase: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<base_1_t>()
|
||||
.data<&base_1_t::value_1>("value_1"_hs);
|
||||
|
||||
entt::meta<base_2_t>()
|
||||
.conv<int>()
|
||||
.data<&base_2_t::value_2>("value_2"_hs);
|
||||
|
||||
entt::meta<base_3_t>()
|
||||
.base<base_2_t>()
|
||||
.data<&base_3_t::value_3>("value_3"_hs);
|
||||
|
||||
entt::meta<derived_t>()
|
||||
.type("derived"_hs)
|
||||
.base<base_1_t>()
|
||||
.base<base_3_t>()
|
||||
.data<&derived_t::value>("value"_hs);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(MetaBase, Functionalities) {
|
||||
auto any = entt::resolve<derived_t>().construct();
|
||||
any.cast<derived_t &>().value_1 = 42;
|
||||
auto as_derived = any.as_ref();
|
||||
|
||||
ASSERT_TRUE(any.allow_cast<base_1_t &>());
|
||||
|
||||
ASSERT_FALSE(any.allow_cast<char>());
|
||||
ASSERT_FALSE(as_derived.allow_cast<char>());
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<base_1_t &>().value_1, as_derived.cast<derived_t &>().value_1);
|
||||
|
||||
any.cast<base_1_t &>().value_1 = 3;
|
||||
|
||||
ASSERT_EQ(any.cast<const base_1_t &>().value_1, as_derived.cast<const derived_t &>().value_1);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, SetGetWithMutatingThis) {
|
||||
using namespace entt::literals;
|
||||
|
||||
derived_t instance;
|
||||
auto any = entt::forward_as_meta(instance);
|
||||
auto as_cref = std::as_const(any).as_ref();
|
||||
|
||||
ASSERT_NE(static_cast<const void *>(static_cast<const base_1_t *>(&instance)), static_cast<const void *>(static_cast<const base_2_t *>(&instance)));
|
||||
ASSERT_NE(static_cast<const void *>(static_cast<const base_1_t *>(&instance)), static_cast<const void *>(static_cast<const base_3_t *>(&instance)));
|
||||
ASSERT_EQ(static_cast<const void *>(static_cast<const base_2_t *>(&instance)), static_cast<const void *>(static_cast<const base_3_t *>(&instance)));
|
||||
ASSERT_EQ(static_cast<const void *>(&instance), static_cast<const void *>(static_cast<const base_1_t *>(&instance)));
|
||||
|
||||
ASSERT_TRUE(any.set("value"_hs, 42));
|
||||
ASSERT_TRUE(any.set("value_1"_hs, 1));
|
||||
ASSERT_TRUE(any.set("value_2"_hs, 2));
|
||||
ASSERT_TRUE(any.set("value_3"_hs, 3));
|
||||
|
||||
ASSERT_FALSE(as_cref.set("value"_hs, 0));
|
||||
ASSERT_FALSE(as_cref.set("value_1"_hs, 0));
|
||||
ASSERT_FALSE(as_cref.set("value_2"_hs, 0));
|
||||
ASSERT_FALSE(as_cref.set("value_3"_hs, 0));
|
||||
|
||||
ASSERT_EQ(any.get("value"_hs).cast<int>(), 42);
|
||||
ASSERT_EQ(any.get("value_1"_hs).cast<const int>(), 1);
|
||||
ASSERT_EQ(any.get("value_2"_hs).cast<int>(), 2);
|
||||
ASSERT_EQ(any.get("value_3"_hs).cast<const int>(), 3);
|
||||
|
||||
ASSERT_EQ(as_cref.get("value"_hs).cast<const int>(), 42);
|
||||
ASSERT_EQ(as_cref.get("value_1"_hs).cast<int>(), 1);
|
||||
ASSERT_EQ(as_cref.get("value_2"_hs).cast<const int>(), 2);
|
||||
ASSERT_EQ(as_cref.get("value_3"_hs).cast<int>(), 3);
|
||||
|
||||
ASSERT_EQ(instance.value, 42);
|
||||
ASSERT_EQ(instance.value_1, 1);
|
||||
ASSERT_EQ(instance.value_2, 2);
|
||||
ASSERT_EQ(instance.value_3, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, ConvWithMutatingThis) {
|
||||
entt::meta_any any{derived_t{}};
|
||||
auto &&ref = any.cast<derived_t &>();
|
||||
auto as_cref = std::as_const(any).as_ref();
|
||||
ref.value_2 = 42;
|
||||
|
||||
auto conv = std::as_const(any).allow_cast<int>();
|
||||
auto from_cref = std::as_const(as_cref).allow_cast<int>();
|
||||
|
||||
ASSERT_TRUE(conv);
|
||||
ASSERT_TRUE(from_cref);
|
||||
ASSERT_EQ(conv.cast<int>(), 42);
|
||||
ASSERT_EQ(from_cref.cast<int>(), 42);
|
||||
|
||||
ASSERT_TRUE(as_cref.allow_cast<int>());
|
||||
ASSERT_TRUE(any.allow_cast<int>());
|
||||
|
||||
ASSERT_EQ(as_cref.cast<int>(), 42);
|
||||
ASSERT_EQ(any.cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, OpaqueConvWithMutatingThis) {
|
||||
entt::meta_any any{derived_t{}};
|
||||
auto as_cref = std::as_const(any).as_ref();
|
||||
any.cast<derived_t &>().value_2 = 42;
|
||||
|
||||
auto conv = std::as_const(any).allow_cast(entt::resolve<int>());
|
||||
auto from_cref = std::as_const(as_cref).allow_cast(entt::resolve<int>());
|
||||
|
||||
ASSERT_TRUE(conv);
|
||||
ASSERT_TRUE(from_cref);
|
||||
ASSERT_EQ(conv.cast<int>(), 42);
|
||||
ASSERT_EQ(from_cref.cast<int>(), 42);
|
||||
|
||||
ASSERT_TRUE(as_cref.allow_cast(entt::resolve<int>()));
|
||||
ASSERT_TRUE(any.allow_cast(entt::resolve<int>()));
|
||||
|
||||
ASSERT_EQ(as_cref.cast<int>(), 42);
|
||||
ASSERT_EQ(any.cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, AssignWithMutatingThis) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_any dst{base_2_t{}};
|
||||
entt::meta_any src{derived_t{}};
|
||||
|
||||
dst.cast<base_2_t &>().value_2 = 0;
|
||||
src.cast<derived_t &>().value_2 = 42;
|
||||
|
||||
ASSERT_TRUE(dst.assign(src));
|
||||
ASSERT_EQ(dst.get("value_2"_hs).cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, TransferWithMutatingThis) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_any dst{base_2_t{}};
|
||||
entt::meta_any src{derived_t{}};
|
||||
|
||||
dst.cast<base_2_t &>().value_2 = 0;
|
||||
src.cast<derived_t &>().value_2 = 42;
|
||||
|
||||
ASSERT_TRUE(dst.assign(std::move(src)));
|
||||
ASSERT_EQ(dst.get("value_2"_hs).cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, ReRegistration) {
|
||||
SetUp();
|
||||
|
||||
auto &&node = entt::internal::resolve<derived_t>(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()));
|
||||
|
||||
ASSERT_TRUE(node.details);
|
||||
ASSERT_FALSE(node.details->base.empty());
|
||||
ASSERT_EQ(node.details->base.size(), 2u);
|
||||
}
|
757
test/entt/meta/meta_container.cpp
Normal file
757
test/entt/meta/meta_container.cpp
Normal file
@ -0,0 +1,757 @@
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/meta/container.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include "../common/config.h"
|
||||
|
||||
struct invalid_type {};
|
||||
|
||||
struct MetaContainer: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<double>()
|
||||
.type("double"_hs);
|
||||
|
||||
entt::meta<int>()
|
||||
.type("int"_hs);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
using MetaContainerDeathTest = MetaContainer;
|
||||
|
||||
TEST_F(MetaContainer, InvalidContainer) {
|
||||
ASSERT_FALSE(entt::meta_any{42}.as_sequence_container());
|
||||
ASSERT_FALSE(entt::meta_any{42}.as_associative_container());
|
||||
|
||||
ASSERT_FALSE((entt::meta_any{std::map<int, char>{}}.as_sequence_container()));
|
||||
ASSERT_FALSE(entt::meta_any{std::vector<int>{}}.as_associative_container());
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, EmptySequenceContainer) {
|
||||
entt::meta_sequence_container container{};
|
||||
|
||||
ASSERT_FALSE(container);
|
||||
|
||||
entt::meta_any any{std::vector<int>{}};
|
||||
container = any.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(container);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, EmptyAssociativeContainer) {
|
||||
entt::meta_associative_container container{};
|
||||
|
||||
ASSERT_FALSE(container);
|
||||
|
||||
entt::meta_any any{std::map<int, char>{}};
|
||||
container = any.as_associative_container();
|
||||
|
||||
ASSERT_TRUE(container);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, SequenceContainerIterator) {
|
||||
std::vector<int> vec{2, 3, 4};
|
||||
auto any = entt::forward_as_meta(vec);
|
||||
entt::meta_sequence_container::iterator first{};
|
||||
auto view = any.as_sequence_container();
|
||||
|
||||
ASSERT_FALSE(first);
|
||||
|
||||
first = view.begin();
|
||||
const auto last = view.end();
|
||||
|
||||
ASSERT_TRUE(first);
|
||||
ASSERT_TRUE(last);
|
||||
|
||||
ASSERT_FALSE(first == last);
|
||||
ASSERT_TRUE(first != last);
|
||||
|
||||
ASSERT_EQ((first++)->cast<int>(), 2);
|
||||
ASSERT_EQ((++first)->cast<int>(), 4);
|
||||
|
||||
ASSERT_NE(first++, last);
|
||||
ASSERT_TRUE(first == last);
|
||||
ASSERT_FALSE(first != last);
|
||||
ASSERT_EQ(first--, last);
|
||||
|
||||
ASSERT_EQ((first--)->cast<int>(), 4);
|
||||
ASSERT_EQ((--first)->cast<int>(), 2);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, AssociativeContainerIterator) {
|
||||
std::map<int, char> map{{2, 'c'}, {3, 'd'}, {4, 'e'}};
|
||||
auto any = entt::forward_as_meta(map);
|
||||
entt::meta_associative_container::iterator first{};
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
ASSERT_FALSE(first);
|
||||
|
||||
first = view.begin();
|
||||
const auto last = view.end();
|
||||
|
||||
ASSERT_TRUE(first);
|
||||
ASSERT_TRUE(last);
|
||||
|
||||
ASSERT_FALSE(first == last);
|
||||
ASSERT_TRUE(first != last);
|
||||
|
||||
ASSERT_NE(first, last);
|
||||
ASSERT_EQ((first++)->first.cast<int>(), 2);
|
||||
ASSERT_EQ((++first)->second.cast<char>(), 'e');
|
||||
ASSERT_NE(first++, last);
|
||||
ASSERT_EQ(first, last);
|
||||
|
||||
ASSERT_TRUE(first == last);
|
||||
ASSERT_FALSE(first != last);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, StdVector) {
|
||||
std::vector<int> vec{};
|
||||
auto any = entt::forward_as_meta(vec);
|
||||
auto view = any.as_sequence_container();
|
||||
auto cview = std::as_const(any).as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.value_type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_TRUE(view.resize(3u));
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
|
||||
view[0].cast<int &>() = 2;
|
||||
view[1].cast<int &>() = 3;
|
||||
view[2].cast<int &>() = 4;
|
||||
|
||||
ASSERT_EQ(view[1u].cast<int>(), 3);
|
||||
|
||||
auto it = view.begin();
|
||||
auto ret = view.insert(it, 0);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_FALSE(view.insert(ret, invalid_type{}));
|
||||
ASSERT_TRUE(view.insert(++ret, 1.));
|
||||
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ(view.begin()->cast<int>(), 0);
|
||||
ASSERT_EQ((++view.begin())->cast<int>(), 1);
|
||||
|
||||
ret = view.insert(cview.end(), 42);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(*ret, 42);
|
||||
|
||||
it = view.begin();
|
||||
ret = view.erase(it);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ(ret->cast<int>(), 1);
|
||||
|
||||
ret = view.erase(cview.begin());
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(view.size(), 4u);
|
||||
ASSERT_EQ(ret->cast<int>(), 2);
|
||||
|
||||
ASSERT_TRUE(view.clear());
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, StdArray) {
|
||||
std::array<int, 3> arr{};
|
||||
auto any = entt::forward_as_meta(arr);
|
||||
auto view = any.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.value_type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_FALSE(view.resize(5u));
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
|
||||
view[0].cast<int &>() = 2;
|
||||
view[1].cast<int &>() = 3;
|
||||
view[2].cast<int &>() = 4;
|
||||
|
||||
ASSERT_EQ(view[1u].cast<int>(), 3);
|
||||
|
||||
auto it = view.begin();
|
||||
auto ret = view.insert(it, 0);
|
||||
|
||||
ASSERT_FALSE(ret);
|
||||
ASSERT_FALSE(view.insert(it, 'c'));
|
||||
ASSERT_FALSE(view.insert(++it, 1.));
|
||||
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
ASSERT_EQ(view.begin()->cast<int>(), 2);
|
||||
ASSERT_EQ((++view.begin())->cast<int>(), 3);
|
||||
|
||||
it = view.begin();
|
||||
ret = view.erase(it);
|
||||
|
||||
ASSERT_FALSE(ret);
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
ASSERT_EQ(it->cast<int>(), 2);
|
||||
|
||||
ASSERT_FALSE(view.clear());
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, StdList) {
|
||||
std::list<int> list{};
|
||||
auto any = entt::forward_as_meta(list);
|
||||
auto view = any.as_sequence_container();
|
||||
auto cview = std::as_const(any).as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.value_type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_TRUE(view.resize(3u));
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
|
||||
view[0].cast<int &>() = 2;
|
||||
view[1].cast<int &>() = 3;
|
||||
view[2].cast<int &>() = 4;
|
||||
|
||||
ASSERT_EQ(view[1u].cast<int>(), 3);
|
||||
|
||||
auto it = view.begin();
|
||||
auto ret = view.insert(it, 0);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_FALSE(view.insert(ret, invalid_type{}));
|
||||
ASSERT_TRUE(view.insert(++ret, 1.));
|
||||
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ(view.begin()->cast<int>(), 0);
|
||||
ASSERT_EQ((++view.begin())->cast<int>(), 1);
|
||||
|
||||
ret = view.insert(cview.end(), 42);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(*ret, 42);
|
||||
|
||||
it = view.begin();
|
||||
ret = view.erase(it);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ(ret->cast<int>(), 1);
|
||||
|
||||
ret = view.erase(cview.begin());
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(view.size(), 4u);
|
||||
ASSERT_EQ(ret->cast<int>(), 2);
|
||||
|
||||
ASSERT_TRUE(view.clear());
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, StdDeque) {
|
||||
std::deque<int> deque{};
|
||||
auto any = entt::forward_as_meta(deque);
|
||||
auto view = any.as_sequence_container();
|
||||
auto cview = std::as_const(any).as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.value_type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_TRUE(view.resize(3u));
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
|
||||
view[0].cast<int &>() = 2;
|
||||
view[1].cast<int &>() = 3;
|
||||
view[2].cast<int &>() = 4;
|
||||
|
||||
ASSERT_EQ(view[1u].cast<int>(), 3);
|
||||
|
||||
auto it = view.begin();
|
||||
auto ret = view.insert(it, 0);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_FALSE(view.insert(ret, invalid_type{}));
|
||||
ASSERT_TRUE(view.insert(++ret, 1.));
|
||||
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ(view.begin()->cast<int>(), 0);
|
||||
ASSERT_EQ((++view.begin())->cast<int>(), 1);
|
||||
|
||||
ret = view.insert(cview.end(), 42);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(*ret, 42);
|
||||
|
||||
it = view.begin();
|
||||
ret = view.erase(it);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ(ret->cast<int>(), 1);
|
||||
|
||||
ret = view.erase(cview.begin());
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(view.size(), 4u);
|
||||
ASSERT_EQ(ret->cast<int>(), 2);
|
||||
|
||||
ASSERT_TRUE(view.clear());
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, StdMap) {
|
||||
std::map<int, char> map{{2, 'c'}, {3, 'd'}, {4, 'e'}};
|
||||
auto any = entt::forward_as_meta(map);
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_FALSE(view.key_only());
|
||||
ASSERT_EQ(view.key_type(), entt::resolve<int>());
|
||||
ASSERT_EQ(view.mapped_type(), entt::resolve<char>());
|
||||
ASSERT_EQ(view.value_type(), (entt::resolve<std::pair<const int, char>>()));
|
||||
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
|
||||
ASSERT_EQ(view.find(3)->second.cast<char>(), 'd');
|
||||
|
||||
ASSERT_FALSE(view.insert(invalid_type{}, 'a'));
|
||||
ASSERT_FALSE(view.insert(1, invalid_type{}));
|
||||
|
||||
ASSERT_TRUE(view.insert(0, 'a'));
|
||||
ASSERT_TRUE(view.insert(1., static_cast<int>('b')));
|
||||
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ(view.find(0)->second.cast<char>(), 'a');
|
||||
ASSERT_EQ(view.find(1.)->second.cast<char>(), 'b');
|
||||
|
||||
ASSERT_EQ(view.erase(invalid_type{}), 0u);
|
||||
ASSERT_FALSE(view.find(invalid_type{}));
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
|
||||
ASSERT_EQ(view.erase(0), 1u);
|
||||
ASSERT_EQ(view.size(), 4u);
|
||||
ASSERT_EQ(view.find(0), view.end());
|
||||
|
||||
view.find(1.)->second.cast<char &>() = 'f';
|
||||
|
||||
ASSERT_EQ(view.find(1.f)->second.cast<char>(), 'f');
|
||||
|
||||
ASSERT_EQ(view.erase(1.), 1u);
|
||||
ASSERT_TRUE(view.clear());
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, StdSet) {
|
||||
std::set<int> set{2, 3, 4};
|
||||
auto any = entt::forward_as_meta(set);
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_TRUE(view.key_only());
|
||||
ASSERT_EQ(view.key_type(), entt::resolve<int>());
|
||||
ASSERT_EQ(view.mapped_type(), entt::meta_type{});
|
||||
ASSERT_EQ(view.value_type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
|
||||
ASSERT_EQ(view.find(3)->first.cast<int>(), 3);
|
||||
|
||||
ASSERT_FALSE(view.insert(invalid_type{}));
|
||||
|
||||
ASSERT_TRUE(view.insert(.0));
|
||||
ASSERT_TRUE(view.insert(1));
|
||||
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ(view.find(0)->first.cast<int>(), 0);
|
||||
ASSERT_EQ(view.find(1.)->first.cast<int>(), 1);
|
||||
|
||||
ASSERT_EQ(view.erase(invalid_type{}), 0u);
|
||||
ASSERT_FALSE(view.find(invalid_type{}));
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
|
||||
ASSERT_EQ(view.erase(0), 1u);
|
||||
ASSERT_EQ(view.size(), 4u);
|
||||
ASSERT_EQ(view.find(0), view.end());
|
||||
|
||||
ASSERT_EQ(view.find(1.f)->first.try_cast<int>(), nullptr);
|
||||
ASSERT_NE(view.find(1.)->first.try_cast<const int>(), nullptr);
|
||||
ASSERT_EQ(view.find(true)->first.cast<const int &>(), 1);
|
||||
|
||||
ASSERT_EQ(view.erase(1.), 1u);
|
||||
ASSERT_TRUE(view.clear());
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, DenseMap) {
|
||||
entt::dense_map<int, char> map{};
|
||||
auto any = entt::forward_as_meta(map);
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
map.emplace(2, 'c');
|
||||
map.emplace(3, 'd');
|
||||
map.emplace(4, '3');
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_FALSE(view.key_only());
|
||||
ASSERT_EQ(view.key_type(), entt::resolve<int>());
|
||||
ASSERT_EQ(view.mapped_type(), entt::resolve<char>());
|
||||
ASSERT_EQ(view.value_type(), (entt::resolve<std::pair<const int, char>>()));
|
||||
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
|
||||
ASSERT_EQ(view.find(3)->second.cast<char>(), 'd');
|
||||
|
||||
ASSERT_FALSE(view.insert(invalid_type{}, 'a'));
|
||||
ASSERT_FALSE(view.insert(1, invalid_type{}));
|
||||
|
||||
ASSERT_TRUE(view.insert(0, 'a'));
|
||||
ASSERT_TRUE(view.insert(1., static_cast<int>('b')));
|
||||
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ(view.find(0)->second.cast<char>(), 'a');
|
||||
ASSERT_EQ(view.find(1.)->second.cast<char>(), 'b');
|
||||
|
||||
ASSERT_EQ(view.erase(invalid_type{}), 0u);
|
||||
ASSERT_FALSE(view.find(invalid_type{}));
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
|
||||
ASSERT_EQ(view.erase(0), 1u);
|
||||
ASSERT_EQ(view.size(), 4u);
|
||||
ASSERT_EQ(view.find(0), view.end());
|
||||
|
||||
view.find(1.)->second.cast<char &>() = 'f';
|
||||
|
||||
ASSERT_EQ(view.find(1.f)->second.cast<char>(), 'f');
|
||||
|
||||
ASSERT_EQ(view.erase(1.), 1u);
|
||||
ASSERT_TRUE(view.clear());
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, DenseSet) {
|
||||
entt::dense_set<int> set{};
|
||||
auto any = entt::forward_as_meta(set);
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
set.emplace(2);
|
||||
set.emplace(3);
|
||||
set.emplace(4);
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_TRUE(view.key_only());
|
||||
ASSERT_EQ(view.key_type(), entt::resolve<int>());
|
||||
ASSERT_EQ(view.mapped_type(), entt::meta_type{});
|
||||
ASSERT_EQ(view.value_type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
|
||||
ASSERT_EQ(view.find(3)->first.cast<int>(), 3);
|
||||
|
||||
ASSERT_FALSE(view.insert(invalid_type{}));
|
||||
|
||||
ASSERT_TRUE(view.insert(.0));
|
||||
ASSERT_TRUE(view.insert(1));
|
||||
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ(view.find(0)->first.cast<int>(), 0);
|
||||
ASSERT_EQ(view.find(1.)->first.cast<int>(), 1);
|
||||
|
||||
ASSERT_EQ(view.erase(invalid_type{}), 0u);
|
||||
ASSERT_FALSE(view.find(invalid_type{}));
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
|
||||
ASSERT_EQ(view.erase(0), 1u);
|
||||
ASSERT_EQ(view.size(), 4u);
|
||||
ASSERT_EQ(view.find(0), view.end());
|
||||
|
||||
ASSERT_EQ(view.find(1.f)->first.try_cast<int>(), nullptr);
|
||||
ASSERT_NE(view.find(1.)->first.try_cast<const int>(), nullptr);
|
||||
ASSERT_EQ(view.find(true)->first.cast<const int &>(), 1);
|
||||
|
||||
ASSERT_EQ(view.erase(1.), 1u);
|
||||
ASSERT_TRUE(view.clear());
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, ConstSequenceContainer) {
|
||||
std::vector<int> vec{};
|
||||
auto any = entt::forward_as_meta(std::as_const(vec));
|
||||
auto view = any.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.value_type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_FALSE(view.resize(3u));
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
|
||||
vec.push_back(42);
|
||||
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_EQ(view[0].cast<const int &>(), 42);
|
||||
|
||||
auto it = view.begin();
|
||||
auto ret = view.insert(it, 0);
|
||||
|
||||
ASSERT_FALSE(ret);
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
ASSERT_EQ(it->cast<int>(), 42);
|
||||
ASSERT_EQ(++it, view.end());
|
||||
|
||||
it = view.begin();
|
||||
ret = view.erase(it);
|
||||
|
||||
ASSERT_FALSE(ret);
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
|
||||
ASSERT_FALSE(view.clear());
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaContainerDeathTest, ConstSequenceContainer) {
|
||||
std::vector<int> vec{};
|
||||
auto any = entt::forward_as_meta(std::as_const(vec));
|
||||
auto view = any.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_DEATH(view[0].cast<int &>() = 2, "");
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, ConstKeyValueAssociativeContainer) {
|
||||
std::map<int, char> map{};
|
||||
auto any = entt::forward_as_meta(std::as_const(map));
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_FALSE(view.key_only());
|
||||
ASSERT_EQ(view.key_type(), entt::resolve<int>());
|
||||
ASSERT_EQ(view.mapped_type(), entt::resolve<char>());
|
||||
ASSERT_EQ(view.value_type(), (entt::resolve<std::pair<const int, char>>()));
|
||||
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
|
||||
map[2] = 'c';
|
||||
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_EQ(view.find(2)->second.cast<const char &>(), 'c');
|
||||
|
||||
ASSERT_FALSE(view.insert(0, 'a'));
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
ASSERT_EQ(view.find(0), view.end());
|
||||
ASSERT_EQ(view.find(2)->second.cast<char>(), 'c');
|
||||
|
||||
ASSERT_EQ(view.erase(2), 0u);
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
ASSERT_NE(view.find(2), view.end());
|
||||
|
||||
ASSERT_FALSE(view.clear());
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaContainerDeathTest, ConstKeyValueAssociativeContainer) {
|
||||
std::map<int, char> map{};
|
||||
auto any = entt::forward_as_meta(std::as_const(map));
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_DEATH(view.find(2)->second.cast<char &>() = 'a', "");
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, ConstKeyOnlyAssociativeContainer) {
|
||||
std::set<int> set{};
|
||||
auto any = entt::forward_as_meta(std::as_const(set));
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_TRUE(view.key_only());
|
||||
ASSERT_EQ(view.key_type(), entt::resolve<int>());
|
||||
ASSERT_EQ(view.mapped_type(), entt::meta_type{});
|
||||
ASSERT_EQ(view.value_type(), (entt::resolve<int>()));
|
||||
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
|
||||
set.insert(2);
|
||||
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
|
||||
ASSERT_EQ(view.find(2)->first.try_cast<int>(), nullptr);
|
||||
ASSERT_NE(view.find(2)->first.try_cast<const int>(), nullptr);
|
||||
ASSERT_EQ(view.find(2)->first.cast<int>(), 2);
|
||||
ASSERT_EQ(view.find(2)->first.cast<const int &>(), 2);
|
||||
|
||||
ASSERT_FALSE(view.insert(0));
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
ASSERT_EQ(view.find(0), view.end());
|
||||
ASSERT_EQ(view.find(2)->first.cast<int>(), 2);
|
||||
|
||||
ASSERT_EQ(view.erase(2), 0u);
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
ASSERT_NE(view.find(2), view.end());
|
||||
|
||||
ASSERT_FALSE(view.clear());
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, SequenceContainerConstMetaAny) {
|
||||
auto test = [](const entt::meta_any any) {
|
||||
auto view = any.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.value_type(), entt::resolve<int>());
|
||||
ASSERT_EQ(view[0].cast<const int &>(), 42);
|
||||
};
|
||||
|
||||
std::vector<int> vec{42};
|
||||
|
||||
test(vec);
|
||||
test(entt::forward_as_meta(vec));
|
||||
test(entt::forward_as_meta(std::as_const(vec)));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaContainerDeathTest, SequenceContainerConstMetaAny) {
|
||||
auto test = [](const entt::meta_any any) {
|
||||
auto view = any.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_DEATH(view[0].cast<int &>() = 2, "");
|
||||
};
|
||||
|
||||
std::vector<int> vec{42};
|
||||
|
||||
test(vec);
|
||||
test(entt::forward_as_meta(vec));
|
||||
test(entt::forward_as_meta(std::as_const(vec)));
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, KeyValueAssociativeContainerConstMetaAny) {
|
||||
auto test = [](const entt::meta_any any) {
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.value_type(), (entt::resolve<std::pair<const int, char>>()));
|
||||
ASSERT_EQ(view.find(2)->second.cast<const char &>(), 'c');
|
||||
};
|
||||
|
||||
std::map<int, char> map{{2, 'c'}};
|
||||
|
||||
test(map);
|
||||
test(entt::forward_as_meta(map));
|
||||
test(entt::forward_as_meta(std::as_const(map)));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaContainerDeathTest, KeyValueAssociativeContainerConstMetaAny) {
|
||||
auto test = [](const entt::meta_any any) {
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_DEATH(view.find(2)->second.cast<char &>() = 'a', "");
|
||||
};
|
||||
|
||||
std::map<int, char> map{{2, 'c'}};
|
||||
|
||||
test(map);
|
||||
test(entt::forward_as_meta(map));
|
||||
test(entt::forward_as_meta(std::as_const(map)));
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, KeyOnlyAssociativeContainerConstMetaAny) {
|
||||
auto test = [](const entt::meta_any any) {
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.value_type(), (entt::resolve<int>()));
|
||||
|
||||
ASSERT_EQ(view.find(2)->first.try_cast<int>(), nullptr);
|
||||
ASSERT_NE(view.find(2)->first.try_cast<const int>(), nullptr);
|
||||
ASSERT_EQ(view.find(2)->first.cast<int>(), 2);
|
||||
ASSERT_EQ(view.find(2)->first.cast<const int &>(), 2);
|
||||
};
|
||||
|
||||
std::set<int> set{2};
|
||||
|
||||
test(set);
|
||||
test(entt::forward_as_meta(set));
|
||||
test(entt::forward_as_meta(std::as_const(set)));
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, StdVectorBool) {
|
||||
using proxy_type = typename std::vector<bool>::reference;
|
||||
using const_proxy_type = typename std::vector<bool>::const_reference;
|
||||
|
||||
std::vector<bool> vec{};
|
||||
auto any = entt::forward_as_meta(vec);
|
||||
auto cany = std::as_const(any).as_ref();
|
||||
|
||||
auto view = any.as_sequence_container();
|
||||
auto cview = cany.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.value_type(), entt::resolve<bool>());
|
||||
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_TRUE(view.resize(3u));
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
|
||||
view[0].cast<proxy_type>() = true;
|
||||
view[1].cast<proxy_type>() = true;
|
||||
view[2].cast<proxy_type>() = false;
|
||||
|
||||
ASSERT_EQ(cview[1u].cast<const_proxy_type>(), true);
|
||||
|
||||
auto it = view.begin();
|
||||
auto ret = view.insert(it, true);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_FALSE(view.insert(ret, invalid_type{}));
|
||||
ASSERT_TRUE(view.insert(++ret, false));
|
||||
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ(view.begin()->cast<proxy_type>(), true);
|
||||
ASSERT_EQ((++cview.begin())->cast<const_proxy_type>(), false);
|
||||
|
||||
it = view.begin();
|
||||
ret = view.erase(it);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(view.size(), 4u);
|
||||
ASSERT_EQ(ret->cast<proxy_type>(), false);
|
||||
|
||||
ASSERT_TRUE(view.clear());
|
||||
ASSERT_EQ(cview.size(), 0u);
|
||||
}
|
505
test/entt/meta/meta_context.cpp
Normal file
505
test/entt/meta/meta_context.cpp
Normal file
@ -0,0 +1,505 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/meta/container.hpp>
|
||||
#include <entt/meta/context.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/pointer.hpp>
|
||||
#include <entt/meta/template.hpp>
|
||||
|
||||
struct base {
|
||||
base() = default;
|
||||
|
||||
base(char v)
|
||||
: value{v} {}
|
||||
|
||||
char get() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
char value;
|
||||
};
|
||||
|
||||
struct clazz: base {
|
||||
clazz() = default;
|
||||
|
||||
clazz(int v)
|
||||
: base{},
|
||||
value{v} {}
|
||||
|
||||
clazz(char c, int v)
|
||||
: base{c},
|
||||
value{v} {}
|
||||
|
||||
int func(int v) {
|
||||
return (value = v);
|
||||
}
|
||||
|
||||
int cfunc(int v) const {
|
||||
return v;
|
||||
}
|
||||
|
||||
static void move_to_bucket(const clazz &instance) {
|
||||
bucket = instance.value;
|
||||
}
|
||||
|
||||
int value{};
|
||||
static inline int bucket{};
|
||||
};
|
||||
|
||||
struct local_only {};
|
||||
|
||||
struct argument {
|
||||
argument(int val)
|
||||
: value{val} {}
|
||||
|
||||
int get() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
int get_mul() const {
|
||||
return value * 2;
|
||||
}
|
||||
|
||||
private:
|
||||
int value{};
|
||||
};
|
||||
|
||||
template<typename...>
|
||||
struct template_clazz {};
|
||||
|
||||
class MetaContext: public ::testing::Test {
|
||||
void init_global_context() {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<int>()
|
||||
.data<global_marker>("marker"_hs);
|
||||
|
||||
entt::meta<argument>()
|
||||
.conv<&argument::get>();
|
||||
|
||||
entt::meta<clazz>()
|
||||
.type("foo"_hs)
|
||||
.prop("prop"_hs, prop_value)
|
||||
.ctor<int>()
|
||||
.data<&clazz::value>("value"_hs)
|
||||
.data<&clazz::value>("rw"_hs)
|
||||
.func<&clazz::func>("func"_hs);
|
||||
|
||||
entt::meta<template_clazz<int>>()
|
||||
.type("template"_hs);
|
||||
}
|
||||
|
||||
void init_local_context() {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<int>(context)
|
||||
.data<local_marker>("marker"_hs);
|
||||
|
||||
entt::meta<local_only>(context)
|
||||
.type("quux"_hs);
|
||||
|
||||
entt::meta<argument>(context)
|
||||
.conv<&argument::get_mul>();
|
||||
|
||||
entt::meta<base>(context)
|
||||
.data<&base::value>("char"_hs)
|
||||
.func<&base::get>("get"_hs);
|
||||
|
||||
entt::meta<clazz>(context)
|
||||
.type("bar"_hs)
|
||||
.prop("prop"_hs, prop_value)
|
||||
.base<base>()
|
||||
.ctor<char, int>()
|
||||
.dtor<&clazz::move_to_bucket>()
|
||||
.data<nullptr, &clazz::value>("value"_hs)
|
||||
.data<&clazz::value>("rw"_hs)
|
||||
.func<&clazz::cfunc>("func"_hs);
|
||||
|
||||
entt::meta<template_clazz<int, char>>(context)
|
||||
.type("template"_hs);
|
||||
}
|
||||
|
||||
public:
|
||||
void SetUp() override {
|
||||
init_global_context();
|
||||
init_local_context();
|
||||
|
||||
clazz::bucket = bucket_value;
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset(context);
|
||||
entt::meta_reset();
|
||||
}
|
||||
|
||||
protected:
|
||||
static constexpr int global_marker = 1;
|
||||
static constexpr int local_marker = 42;
|
||||
static constexpr int bucket_value = 99;
|
||||
static constexpr int prop_value = 3;
|
||||
entt::meta_ctx context{};
|
||||
};
|
||||
|
||||
TEST_F(MetaContext, Resolve) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz>());
|
||||
ASSERT_TRUE(entt::resolve<clazz>(context));
|
||||
|
||||
ASSERT_TRUE(entt::resolve<local_only>());
|
||||
ASSERT_TRUE(entt::resolve<local_only>(context));
|
||||
|
||||
ASSERT_TRUE(entt::resolve(entt::type_id<clazz>()));
|
||||
ASSERT_TRUE(entt::resolve(context, entt::type_id<clazz>()));
|
||||
|
||||
ASSERT_FALSE(entt::resolve(entt::type_id<local_only>()));
|
||||
ASSERT_TRUE(entt::resolve(context, entt::type_id<local_only>()));
|
||||
|
||||
ASSERT_TRUE(entt::resolve("foo"_hs));
|
||||
ASSERT_FALSE(entt::resolve(context, "foo"_hs));
|
||||
|
||||
ASSERT_FALSE(entt::resolve("bar"_hs));
|
||||
ASSERT_TRUE(entt::resolve(context, "bar"_hs));
|
||||
|
||||
ASSERT_FALSE(entt::resolve("quux"_hs));
|
||||
ASSERT_TRUE(entt::resolve(context, "quux"_hs));
|
||||
|
||||
ASSERT_EQ((std::distance(entt::resolve().cbegin(), entt::resolve().cend())), 4);
|
||||
ASSERT_EQ((std::distance(entt::resolve(context).cbegin(), entt::resolve(context).cend())), 6);
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaType) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const auto global = entt::resolve<clazz>();
|
||||
const auto local = entt::resolve<clazz>(context);
|
||||
|
||||
ASSERT_TRUE(global);
|
||||
ASSERT_TRUE(local);
|
||||
|
||||
ASSERT_NE(global, local);
|
||||
|
||||
ASSERT_EQ(global, entt::resolve("foo"_hs));
|
||||
ASSERT_EQ(local, entt::resolve(context, "bar"_hs));
|
||||
|
||||
ASSERT_EQ(global.id(), "foo"_hs);
|
||||
ASSERT_EQ(local.id(), "bar"_hs);
|
||||
|
||||
clazz instance{'c', 99};
|
||||
const argument value{2};
|
||||
|
||||
ASSERT_NE(instance.value, value.get());
|
||||
ASSERT_EQ(global.invoke("func"_hs, instance, value).cast<int>(), value.get());
|
||||
ASSERT_EQ(instance.value, value.get());
|
||||
|
||||
ASSERT_NE(instance.value, value.get_mul());
|
||||
ASSERT_EQ(local.invoke("func"_hs, instance, value).cast<int>(), value.get_mul());
|
||||
ASSERT_NE(instance.value, value.get_mul());
|
||||
|
||||
ASSERT_FALSE(global.invoke("get"_hs, instance));
|
||||
ASSERT_EQ(local.invoke("get"_hs, instance).cast<char>(), 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaBase) {
|
||||
const auto global = entt::resolve<clazz>();
|
||||
const auto local = entt::resolve<clazz>(context);
|
||||
|
||||
ASSERT_EQ((std::distance(global.base().cbegin(), global.base().cend())), 0);
|
||||
ASSERT_EQ((std::distance(local.base().cbegin(), local.base().cend())), 1);
|
||||
|
||||
ASSERT_EQ(local.base().cbegin()->second.info(), entt::type_id<base>());
|
||||
|
||||
ASSERT_FALSE(entt::resolve(entt::type_id<base>()));
|
||||
ASSERT_TRUE(entt::resolve(context, entt::type_id<base>()));
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaData) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const auto global = entt::resolve<clazz>();
|
||||
const auto local = entt::resolve<clazz>(context);
|
||||
|
||||
ASSERT_TRUE(global.data("value"_hs));
|
||||
ASSERT_TRUE(local.data("value"_hs));
|
||||
|
||||
ASSERT_FALSE(global.data("value"_hs).is_const());
|
||||
ASSERT_TRUE(local.data("value"_hs).is_const());
|
||||
|
||||
ASSERT_EQ(global.data("value"_hs).type().data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ(local.data("value"_hs).type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
|
||||
ASSERT_EQ(global.data("rw"_hs).arg(0u).data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ(local.data("rw"_hs).arg(0u).data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
|
||||
clazz instance{'c', 99};
|
||||
const argument value{2};
|
||||
|
||||
ASSERT_NE(instance.value, value.get());
|
||||
ASSERT_TRUE(global.data("rw"_hs).set(instance, value));
|
||||
ASSERT_EQ(instance.value, value.get());
|
||||
|
||||
ASSERT_NE(instance.value, value.get_mul());
|
||||
ASSERT_TRUE(local.data("rw"_hs).set(instance, value));
|
||||
ASSERT_EQ(instance.value, value.get_mul());
|
||||
|
||||
ASSERT_FALSE(global.data("char"_hs));
|
||||
ASSERT_EQ(local.data("char"_hs).get(instance).cast<char>(), 'c');
|
||||
ASSERT_TRUE(local.data("char"_hs).set(instance, 'x'));
|
||||
ASSERT_EQ(instance.base::value, 'x');
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaFunc) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const auto global = entt::resolve<clazz>();
|
||||
const auto local = entt::resolve<clazz>(context);
|
||||
|
||||
ASSERT_TRUE(global.func("func"_hs));
|
||||
ASSERT_TRUE(local.func("func"_hs));
|
||||
|
||||
ASSERT_FALSE(global.func("func"_hs).is_const());
|
||||
ASSERT_TRUE(local.func("func"_hs).is_const());
|
||||
|
||||
ASSERT_EQ(global.func("func"_hs).arg(0u).data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ(local.func("func"_hs).arg(0u).data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
|
||||
ASSERT_EQ(global.func("func"_hs).ret().data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ(local.func("func"_hs).ret().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
|
||||
clazz instance{'c', 99};
|
||||
const argument value{2};
|
||||
|
||||
ASSERT_NE(instance.value, value.get());
|
||||
ASSERT_EQ(global.func("func"_hs).invoke(instance, value).cast<int>(), value.get());
|
||||
ASSERT_EQ(instance.value, value.get());
|
||||
|
||||
ASSERT_NE(instance.value, value.get_mul());
|
||||
ASSERT_EQ(local.func("func"_hs).invoke(instance, value).cast<int>(), value.get_mul());
|
||||
ASSERT_NE(instance.value, value.get_mul());
|
||||
|
||||
ASSERT_FALSE(global.func("get"_hs));
|
||||
ASSERT_EQ(local.func("get"_hs).invoke(instance).cast<char>(), 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaCtor) {
|
||||
const auto global = entt::resolve<clazz>();
|
||||
const auto local = entt::resolve<clazz>(context);
|
||||
|
||||
auto any = global.construct();
|
||||
auto other = local.construct();
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(other);
|
||||
|
||||
ASSERT_EQ(any.cast<const clazz &>().value, 0);
|
||||
ASSERT_EQ(other.cast<const clazz &>().value, 0);
|
||||
|
||||
argument argument{2};
|
||||
|
||||
any = global.construct(argument);
|
||||
other = local.construct(argument);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(other);
|
||||
ASSERT_EQ(any.cast<const clazz &>().value, 2);
|
||||
|
||||
any = global.construct('c', argument);
|
||||
other = local.construct('c', argument);
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_EQ(other.cast<const clazz &>().value, 4);
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaConv) {
|
||||
argument value{2};
|
||||
|
||||
auto global = entt::forward_as_meta(value);
|
||||
auto local = entt::forward_as_meta(context, value);
|
||||
|
||||
ASSERT_TRUE(global.allow_cast<int>());
|
||||
ASSERT_TRUE(local.allow_cast<int>());
|
||||
|
||||
ASSERT_EQ(global.cast<int>(), value.get());
|
||||
ASSERT_EQ(local.cast<int>(), value.get_mul());
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaDtor) {
|
||||
auto global = entt::resolve<clazz>().construct();
|
||||
auto local = entt::resolve<clazz>(context).construct();
|
||||
|
||||
ASSERT_EQ(clazz::bucket, bucket_value);
|
||||
|
||||
global.reset();
|
||||
|
||||
ASSERT_EQ(clazz::bucket, bucket_value);
|
||||
|
||||
local.reset();
|
||||
|
||||
ASSERT_NE(clazz::bucket, bucket_value);
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaProp) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const auto global = entt::resolve<clazz>();
|
||||
const auto local = entt::resolve<clazz>(context);
|
||||
|
||||
ASSERT_TRUE(global.prop("prop"_hs));
|
||||
ASSERT_TRUE(local.prop("prop"_hs));
|
||||
|
||||
ASSERT_EQ(global.prop("prop"_hs).value().type(), entt::resolve<int>());
|
||||
ASSERT_EQ(local.prop("prop"_hs).value().type(), entt::resolve<int>(context));
|
||||
|
||||
ASSERT_EQ(global.prop("prop"_hs).value().cast<int>(), prop_value);
|
||||
ASSERT_EQ(local.prop("prop"_hs).value().cast<int>(), prop_value);
|
||||
|
||||
ASSERT_EQ(global.prop("prop"_hs).value().type().data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ(local.prop("prop"_hs).value().type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaTemplate) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const auto global = entt::resolve("template"_hs);
|
||||
const auto local = entt::resolve(context, "template"_hs);
|
||||
|
||||
ASSERT_TRUE(global.is_template_specialization());
|
||||
ASSERT_TRUE(local.is_template_specialization());
|
||||
|
||||
ASSERT_EQ(global.template_arity(), 1u);
|
||||
ASSERT_EQ(local.template_arity(), 2u);
|
||||
|
||||
ASSERT_EQ(global.template_arg(0u), entt::resolve<int>());
|
||||
ASSERT_EQ(local.template_arg(0u), entt::resolve<int>(context));
|
||||
ASSERT_EQ(local.template_arg(1u), entt::resolve<char>(context));
|
||||
|
||||
ASSERT_EQ(global.template_arg(0u).data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ(local.template_arg(0u).data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaPointer) {
|
||||
using namespace entt::literals;
|
||||
|
||||
int value = 42;
|
||||
|
||||
const entt::meta_any global{&value};
|
||||
const entt::meta_any local{context, &value};
|
||||
|
||||
ASSERT_TRUE(global.type().is_pointer());
|
||||
ASSERT_TRUE(local.type().is_pointer());
|
||||
|
||||
ASSERT_TRUE(global.type().is_pointer_like());
|
||||
ASSERT_TRUE(local.type().is_pointer_like());
|
||||
|
||||
ASSERT_EQ((*global).type().data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ((*local).type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaAssociativeContainer) {
|
||||
using namespace entt::literals;
|
||||
|
||||
std::unordered_map<int, int> map{{{0, 0}}};
|
||||
|
||||
auto global = entt::forward_as_meta(map).as_associative_container();
|
||||
auto local = entt::forward_as_meta(context, map).as_associative_container();
|
||||
|
||||
ASSERT_TRUE(global);
|
||||
ASSERT_TRUE(local);
|
||||
|
||||
ASSERT_EQ(global.size(), 1u);
|
||||
ASSERT_EQ(local.size(), 1u);
|
||||
|
||||
ASSERT_EQ(global.key_type().data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ(local.key_type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
|
||||
ASSERT_EQ(global.mapped_type().data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ(local.mapped_type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
|
||||
ASSERT_EQ((*global.begin()).first.type().data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ((*local.begin()).first.type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
|
||||
ASSERT_EQ((*global.begin()).second.type().data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ((*local.begin()).second.type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaSequenceContainer) {
|
||||
using namespace entt::literals;
|
||||
|
||||
std::vector<int> vec{0};
|
||||
|
||||
auto global = entt::forward_as_meta(vec).as_sequence_container();
|
||||
auto local = entt::forward_as_meta(context, vec).as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(global);
|
||||
ASSERT_TRUE(local);
|
||||
|
||||
ASSERT_EQ(global.size(), 1u);
|
||||
ASSERT_EQ(local.size(), 1u);
|
||||
|
||||
ASSERT_EQ(global.value_type().data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ(local.value_type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
|
||||
ASSERT_EQ((*global.begin()).type().data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ((*local.begin()).type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaAny) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_any global{42};
|
||||
entt::meta_any ctx_value{context, 42};
|
||||
entt::meta_any in_place{context, std::in_place_type<int>, 42};
|
||||
entt::meta_any two_step_local{entt::meta_ctx_arg, context};
|
||||
|
||||
ASSERT_TRUE(global);
|
||||
ASSERT_TRUE(ctx_value);
|
||||
ASSERT_TRUE(in_place);
|
||||
ASSERT_FALSE(two_step_local);
|
||||
|
||||
two_step_local = 42;
|
||||
|
||||
ASSERT_TRUE(two_step_local);
|
||||
|
||||
ASSERT_EQ(global.type().data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ(ctx_value.type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
ASSERT_EQ(in_place.type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
ASSERT_EQ(two_step_local.type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaHandle) {
|
||||
using namespace entt::literals;
|
||||
|
||||
int value = 42;
|
||||
|
||||
entt::meta_handle global{value};
|
||||
entt::meta_handle ctx_value{context, value};
|
||||
entt::meta_handle two_step_local{entt::meta_ctx_arg, context};
|
||||
|
||||
ASSERT_TRUE(global);
|
||||
ASSERT_TRUE(ctx_value);
|
||||
ASSERT_FALSE(two_step_local);
|
||||
|
||||
two_step_local->emplace<int &>(value);
|
||||
|
||||
ASSERT_TRUE(two_step_local);
|
||||
|
||||
ASSERT_EQ(global->type().data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ(ctx_value->type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
ASSERT_EQ(two_step_local->type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, ForwardAsMeta) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const auto global = entt::forward_as_meta(42);
|
||||
const auto local = entt::forward_as_meta(context, 42);
|
||||
|
||||
ASSERT_TRUE(global);
|
||||
ASSERT_TRUE(local);
|
||||
|
||||
ASSERT_EQ(global.type().data("marker"_hs).get({}).cast<int>(), global_marker);
|
||||
ASSERT_EQ(local.type().data("marker"_hs).get({}).cast<int>(), local_marker);
|
||||
}
|
71
test/entt/meta/meta_conv.cpp
Normal file
71
test/entt/meta/meta_conv.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/locator/locator.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/node.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
|
||||
struct clazz_t {
|
||||
clazz_t() = default;
|
||||
|
||||
operator int() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
bool to_bool() const {
|
||||
return (value != 0);
|
||||
}
|
||||
|
||||
int value{};
|
||||
};
|
||||
|
||||
double conv_to_double(const clazz_t &instance) {
|
||||
return instance.value * 2.;
|
||||
}
|
||||
|
||||
struct MetaConv: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<clazz_t>()
|
||||
.type("clazz"_hs)
|
||||
.conv<int>()
|
||||
.conv<&clazz_t::to_bool>()
|
||||
.conv<conv_to_double>();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(MetaConv, Functionalities) {
|
||||
auto any = entt::resolve<clazz_t>().construct();
|
||||
any.cast<clazz_t &>().value = 42;
|
||||
|
||||
const auto as_int = std::as_const(any).allow_cast<int>();
|
||||
const auto as_bool = std::as_const(any).allow_cast<bool>();
|
||||
const auto as_double = std::as_const(any).allow_cast<double>();
|
||||
|
||||
ASSERT_FALSE(any.allow_cast<char>());
|
||||
|
||||
ASSERT_TRUE(as_int);
|
||||
ASSERT_TRUE(as_bool);
|
||||
ASSERT_TRUE(as_double);
|
||||
|
||||
ASSERT_EQ(as_int.cast<int>(), any.cast<clazz_t &>().operator int());
|
||||
ASSERT_EQ(as_bool.cast<bool>(), any.cast<clazz_t &>().to_bool());
|
||||
ASSERT_EQ(as_double.cast<double>(), conv_to_double(any.cast<clazz_t &>()));
|
||||
}
|
||||
|
||||
TEST_F(MetaConv, ReRegistration) {
|
||||
SetUp();
|
||||
|
||||
auto &&node = entt::internal::resolve<clazz_t>(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()));
|
||||
|
||||
ASSERT_TRUE(node.details);
|
||||
ASSERT_FALSE(node.details->conv.empty());
|
||||
ASSERT_EQ(node.details->conv.size(), 3u);
|
||||
}
|
215
test/entt/meta/meta_ctor.cpp
Normal file
215
test/entt/meta/meta_ctor.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/core/utility.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/locator/locator.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
|
||||
struct base_t {
|
||||
base_t()
|
||||
: value{'c'} {}
|
||||
|
||||
char value;
|
||||
};
|
||||
|
||||
struct derived_t: base_t {
|
||||
derived_t()
|
||||
: base_t{} {}
|
||||
};
|
||||
|
||||
struct clazz_t {
|
||||
clazz_t(const base_t &other, int &iv)
|
||||
: clazz_t{iv, other.value} {}
|
||||
|
||||
clazz_t(const int &iv, char cv)
|
||||
: i{iv}, c{cv} {}
|
||||
|
||||
operator int() const {
|
||||
return i;
|
||||
}
|
||||
|
||||
static clazz_t factory(int value) {
|
||||
return {value, 'c'};
|
||||
}
|
||||
|
||||
static clazz_t factory(base_t other, int value, int mul) {
|
||||
return {value * mul, other.value};
|
||||
}
|
||||
|
||||
int i{};
|
||||
char c{};
|
||||
};
|
||||
|
||||
double double_factory() {
|
||||
return 42.;
|
||||
}
|
||||
|
||||
struct MetaCtor: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<double>()
|
||||
.type("double"_hs)
|
||||
.ctor<double_factory>();
|
||||
|
||||
entt::meta<derived_t>()
|
||||
.type("derived"_hs)
|
||||
.base<base_t>();
|
||||
|
||||
entt::meta<clazz_t>()
|
||||
.type("clazz"_hs)
|
||||
.ctor<&entt::registry::emplace_or_replace<clazz_t, const int &, const char &>, entt::as_ref_t>()
|
||||
.ctor<const base_t &, int &>()
|
||||
.ctor<const int &, char>()
|
||||
.ctor<entt::overload<clazz_t(int)>(clazz_t::factory)>()
|
||||
.ctor<entt::overload<clazz_t(base_t, int, int)>(clazz_t::factory)>()
|
||||
.conv<int>();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(MetaCtor, Functionalities) {
|
||||
auto any = entt::resolve<clazz_t>().construct(42, 'c');
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 42);
|
||||
ASSERT_EQ(any.cast<clazz_t>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, Func) {
|
||||
auto any = entt::resolve<clazz_t>().construct(42);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 42);
|
||||
ASSERT_EQ(any.cast<clazz_t>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, MetaAnyArgs) {
|
||||
auto any = entt::resolve<clazz_t>().construct(entt::meta_any{42}, entt::meta_any{'c'});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 42);
|
||||
ASSERT_EQ(any.cast<clazz_t>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, InvalidArgs) {
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().construct(entt::meta_any{}, derived_t{}));
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, CastAndConvert) {
|
||||
auto any = entt::resolve<clazz_t>().construct(derived_t{}, clazz_t{42, 'd'});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 42);
|
||||
ASSERT_EQ(any.cast<clazz_t>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, ArithmeticConversion) {
|
||||
auto any = entt::resolve<clazz_t>().construct(true, 4.2);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 1);
|
||||
ASSERT_EQ(any.cast<clazz_t>().c, char{4});
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, ConstNonConstRefArgs) {
|
||||
int ivalue = 42;
|
||||
const char cvalue = 'c';
|
||||
auto any = entt::resolve<clazz_t>().construct(entt::forward_as_meta(ivalue), entt::forward_as_meta(cvalue));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 42);
|
||||
ASSERT_EQ(any.cast<clazz_t>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, WrongConstness) {
|
||||
int value = 42;
|
||||
auto any = entt::resolve<clazz_t>().construct(derived_t{}, entt::forward_as_meta(value));
|
||||
auto other = entt::resolve<clazz_t>().construct(derived_t{}, entt::forward_as_meta(std::as_const(value)));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(other);
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 42);
|
||||
ASSERT_EQ(any.cast<clazz_t>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, FuncMetaAnyArgs) {
|
||||
auto any = entt::resolve<clazz_t>().construct(entt::meta_any{42});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 42);
|
||||
ASSERT_EQ(any.cast<clazz_t>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, FuncCastAndConvert) {
|
||||
auto any = entt::resolve<clazz_t>().construct(derived_t{}, 3., clazz_t{3, 'd'});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 9);
|
||||
ASSERT_EQ(any.cast<clazz_t>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, FuncArithmeticConversion) {
|
||||
auto any = entt::resolve<clazz_t>().construct(4.2);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 4);
|
||||
ASSERT_EQ(any.cast<clazz_t>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, FuncConstNonConstRefArgs) {
|
||||
int ivalue = 42;
|
||||
auto any = entt::resolve<clazz_t>().construct(entt::forward_as_meta(ivalue));
|
||||
auto other = entt::resolve<clazz_t>().construct(entt::forward_as_meta(std::as_const(ivalue)));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 42);
|
||||
ASSERT_EQ(other.cast<clazz_t>().i, 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, ExternalMemberFunction) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_FALSE(registry.all_of<clazz_t>(entity));
|
||||
|
||||
const auto any = entt::resolve<clazz_t>().construct(entt::forward_as_meta(registry), entity, 3, 'c');
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(registry.all_of<clazz_t>(entity));
|
||||
ASSERT_EQ(registry.get<clazz_t>(entity).i, 3);
|
||||
ASSERT_EQ(registry.get<clazz_t>(entity).c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, OverrideImplicitlyGeneratedDefaultConstructor) {
|
||||
auto type = entt::resolve<double>();
|
||||
auto any = type.construct();
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<double>());
|
||||
ASSERT_EQ(any.cast<double>(), 42.);
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, NonDefaultConstructibleType) {
|
||||
auto type = entt::resolve<clazz_t>();
|
||||
// no implicitly generated default constructor
|
||||
ASSERT_FALSE(type.construct());
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, ReRegistration) {
|
||||
SetUp();
|
||||
|
||||
auto &&node = entt::internal::resolve<double>(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()));
|
||||
|
||||
ASSERT_TRUE(node.details);
|
||||
ASSERT_FALSE(node.details->ctor.empty());
|
||||
// implicitly generated default constructor is not cleared
|
||||
ASSERT_NE(node.default_constructor, nullptr);
|
||||
}
|
678
test/entt/meta/meta_data.cpp
Normal file
678
test/entt/meta/meta_data.cpp
Normal file
@ -0,0 +1,678 @@
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/core/type_traits.hpp>
|
||||
#include <entt/locator/locator.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/node.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include "../common/config.h"
|
||||
|
||||
struct base_t {
|
||||
virtual ~base_t() = default;
|
||||
|
||||
static void destroy(base_t &) {
|
||||
++counter;
|
||||
}
|
||||
|
||||
inline static int counter = 0;
|
||||
int value{3};
|
||||
};
|
||||
|
||||
struct derived_t: base_t {
|
||||
derived_t() {}
|
||||
};
|
||||
|
||||
struct clazz_t {
|
||||
clazz_t()
|
||||
: i{0},
|
||||
j{1},
|
||||
base{} {}
|
||||
|
||||
operator int() const {
|
||||
return h;
|
||||
}
|
||||
|
||||
int i{0};
|
||||
const int j{1};
|
||||
base_t base{};
|
||||
inline static int h{2};
|
||||
inline static const int k{3};
|
||||
};
|
||||
|
||||
struct setter_getter_t {
|
||||
setter_getter_t()
|
||||
: value{0} {}
|
||||
|
||||
int setter(double val) {
|
||||
return value = static_cast<int>(val);
|
||||
}
|
||||
|
||||
int getter() {
|
||||
return value;
|
||||
}
|
||||
|
||||
int setter_with_ref(const int &val) {
|
||||
return value = val;
|
||||
}
|
||||
|
||||
const int &getter_with_ref() {
|
||||
return value;
|
||||
}
|
||||
|
||||
static int static_setter(setter_getter_t &type, int value) {
|
||||
return type.value = value;
|
||||
}
|
||||
|
||||
static int static_getter(const setter_getter_t &type) {
|
||||
return type.value;
|
||||
}
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
struct multi_setter_t {
|
||||
multi_setter_t()
|
||||
: value{0} {}
|
||||
|
||||
void from_double(double val) {
|
||||
value = val;
|
||||
}
|
||||
|
||||
void from_string(const char *val) {
|
||||
value = std::atoi(val);
|
||||
}
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
struct array_t {
|
||||
static inline int global[3];
|
||||
int local[5];
|
||||
};
|
||||
|
||||
enum class property_t : entt::id_type {
|
||||
random,
|
||||
value
|
||||
};
|
||||
|
||||
struct MetaData: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<double>()
|
||||
.type("double"_hs);
|
||||
|
||||
entt::meta<base_t>()
|
||||
.type("base"_hs)
|
||||
.dtor<base_t::destroy>()
|
||||
.data<&base_t::value>("value"_hs);
|
||||
|
||||
entt::meta<derived_t>()
|
||||
.type("derived"_hs)
|
||||
.base<base_t>()
|
||||
.dtor<derived_t::destroy>()
|
||||
.data<&base_t::value>("value_from_base"_hs);
|
||||
|
||||
entt::meta<clazz_t>()
|
||||
.type("clazz"_hs)
|
||||
.data<&clazz_t::i, entt::as_ref_t>("i"_hs)
|
||||
.prop(3u, 0)
|
||||
.data<&clazz_t::i, entt::as_cref_t>("ci"_hs)
|
||||
.data<&clazz_t::j>("j"_hs)
|
||||
.prop("true"_hs, 1)
|
||||
.data<&clazz_t::h>("h"_hs)
|
||||
.prop(static_cast<entt::id_type>(property_t::random), 2)
|
||||
.data<&clazz_t::k>("k"_hs)
|
||||
.prop(static_cast<entt::id_type>(property_t::value), 3)
|
||||
.data<&clazz_t::base>("base"_hs)
|
||||
.data<&clazz_t::i, entt::as_void_t>("void"_hs)
|
||||
.conv<int>();
|
||||
|
||||
entt::meta<setter_getter_t>()
|
||||
.type("setter_getter"_hs)
|
||||
.data<&setter_getter_t::static_setter, &setter_getter_t::static_getter>("x"_hs)
|
||||
.data<&setter_getter_t::setter, &setter_getter_t::getter>("y"_hs)
|
||||
.data<&setter_getter_t::static_setter, &setter_getter_t::getter>("z"_hs)
|
||||
.data<&setter_getter_t::setter_with_ref, &setter_getter_t::getter_with_ref>("w"_hs)
|
||||
.data<nullptr, &setter_getter_t::getter>("z_ro"_hs)
|
||||
.data<nullptr, &setter_getter_t::value>("value"_hs);
|
||||
|
||||
entt::meta<multi_setter_t>()
|
||||
.type("multi_setter"_hs)
|
||||
.data<entt::value_list<&multi_setter_t::from_double, &multi_setter_t::from_string>, &multi_setter_t::value>("value"_hs);
|
||||
|
||||
entt::meta<array_t>()
|
||||
.type("array"_hs)
|
||||
.data<&array_t::global>("global"_hs)
|
||||
.data<&array_t::local>("local"_hs);
|
||||
|
||||
base_t::counter = 0;
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
using MetaDataDeathTest = MetaData;
|
||||
|
||||
TEST_F(MetaData, Functionalities) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<clazz_t>().data("i"_hs);
|
||||
clazz_t instance{};
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int>());
|
||||
ASSERT_FALSE(data.is_const());
|
||||
ASSERT_FALSE(data.is_static());
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 0);
|
||||
ASSERT_TRUE(data.set(instance, 42));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 42);
|
||||
|
||||
for(auto curr: data.prop()) {
|
||||
ASSERT_EQ(curr.first, 3u);
|
||||
ASSERT_EQ(curr.second.value(), 0);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(data.prop(2));
|
||||
ASSERT_FALSE(data.prop('c'));
|
||||
|
||||
auto prop = data.prop(3u);
|
||||
|
||||
ASSERT_TRUE(prop);
|
||||
ASSERT_EQ(prop.value(), 0);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, Const) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<clazz_t>().data("j"_hs);
|
||||
clazz_t instance{};
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int>());
|
||||
ASSERT_TRUE(data.is_const());
|
||||
ASSERT_FALSE(data.is_static());
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 1);
|
||||
ASSERT_FALSE(data.set(instance, 42));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 1);
|
||||
|
||||
for(auto curr: data.prop()) {
|
||||
ASSERT_EQ(curr.first, "true"_hs);
|
||||
ASSERT_EQ(curr.second.value(), 1);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(data.prop(false));
|
||||
ASSERT_FALSE(data.prop('c'));
|
||||
|
||||
auto prop = data.prop("true"_hs);
|
||||
|
||||
ASSERT_TRUE(prop);
|
||||
ASSERT_EQ(prop.value(), 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, Static) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<clazz_t>().data("h"_hs);
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int>());
|
||||
ASSERT_FALSE(data.is_const());
|
||||
ASSERT_TRUE(data.is_static());
|
||||
ASSERT_EQ(data.get({}).cast<int>(), 2);
|
||||
ASSERT_TRUE(data.set({}, 42));
|
||||
ASSERT_EQ(data.get({}).cast<int>(), 42);
|
||||
|
||||
for(auto curr: data.prop()) {
|
||||
ASSERT_EQ(curr.first, static_cast<entt::id_type>(property_t::random));
|
||||
ASSERT_EQ(curr.second.value(), 2);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(data.prop(static_cast<entt::id_type>(property_t::value)));
|
||||
ASSERT_FALSE(data.prop('c'));
|
||||
|
||||
auto prop = data.prop(static_cast<entt::id_type>(property_t::random));
|
||||
|
||||
ASSERT_TRUE(prop);
|
||||
ASSERT_EQ(prop.value(), 2);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, ConstStatic) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<clazz_t>().data("k"_hs);
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int>());
|
||||
ASSERT_TRUE(data.is_const());
|
||||
ASSERT_TRUE(data.is_static());
|
||||
ASSERT_EQ(data.get({}).cast<int>(), 3);
|
||||
ASSERT_FALSE(data.set({}, 42));
|
||||
ASSERT_EQ(data.get({}).cast<int>(), 3);
|
||||
|
||||
for(auto curr: data.prop()) {
|
||||
ASSERT_EQ(curr.first, static_cast<entt::id_type>(property_t::value));
|
||||
ASSERT_EQ(curr.second.value(), 3);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(data.prop(static_cast<entt::id_type>(property_t::random)));
|
||||
ASSERT_FALSE(data.prop('c'));
|
||||
|
||||
auto prop = data.prop(static_cast<entt::id_type>(property_t::value));
|
||||
|
||||
ASSERT_TRUE(prop);
|
||||
ASSERT_EQ(prop.value(), 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, GetMetaAnyArg) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_any any{clazz_t{}};
|
||||
any.cast<clazz_t &>().i = 99;
|
||||
const auto value = entt::resolve<clazz_t>().data("i"_hs).get(any);
|
||||
|
||||
ASSERT_TRUE(value);
|
||||
ASSERT_TRUE(static_cast<bool>(value.cast<int>()));
|
||||
ASSERT_EQ(value.cast<int>(), 99);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, GetInvalidArg) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto instance = 0;
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().data("i"_hs).get(instance));
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetMetaAnyArg) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_any any{clazz_t{}};
|
||||
entt::meta_any value{42};
|
||||
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 0);
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, value));
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetInvalidArg) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().data("i"_hs).set({}, 'c'));
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetCast) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz_t instance{};
|
||||
|
||||
ASSERT_EQ(base_t::counter, 0);
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("base"_hs).set(instance, derived_t{}));
|
||||
ASSERT_EQ(base_t::counter, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetConvert) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz_t instance{};
|
||||
instance.h = 42;
|
||||
|
||||
ASSERT_EQ(instance.i, 0);
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(instance, instance));
|
||||
ASSERT_EQ(instance.i, 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetByRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_any any{clazz_t{}};
|
||||
int value{42};
|
||||
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 0);
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, entt::forward_as_meta(value)));
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 42);
|
||||
|
||||
value = 3;
|
||||
auto wrapper = entt::forward_as_meta(value);
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, wrapper.as_ref()));
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetByConstRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_any any{clazz_t{}};
|
||||
int value{42};
|
||||
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 0);
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, entt::forward_as_meta(std::as_const(value))));
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 42);
|
||||
|
||||
value = 3;
|
||||
auto wrapper = entt::forward_as_meta(std::as_const(value));
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(any, wrapper.as_ref()));
|
||||
ASSERT_EQ(any.cast<clazz_t>().i, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetterGetterAsFreeFunctions) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<setter_getter_t>().data("x"_hs);
|
||||
setter_getter_t instance{};
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int>());
|
||||
ASSERT_FALSE(data.is_const());
|
||||
ASSERT_FALSE(data.is_static());
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 0);
|
||||
ASSERT_TRUE(data.set(instance, 42));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetterGetterAsMemberFunctions) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<setter_getter_t>().data("y"_hs);
|
||||
setter_getter_t instance{};
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<double>());
|
||||
ASSERT_FALSE(data.is_const());
|
||||
ASSERT_FALSE(data.is_static());
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 0);
|
||||
ASSERT_TRUE(data.set(instance, 42.));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 42);
|
||||
ASSERT_TRUE(data.set(instance, 3));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetterGetterWithRefAsMemberFunctions) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<setter_getter_t>().data("w"_hs);
|
||||
setter_getter_t instance{};
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int>());
|
||||
ASSERT_FALSE(data.is_const());
|
||||
ASSERT_FALSE(data.is_static());
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 0);
|
||||
ASSERT_TRUE(data.set(instance, 42));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetterGetterMixed) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<setter_getter_t>().data("z"_hs);
|
||||
setter_getter_t instance{};
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int>());
|
||||
ASSERT_FALSE(data.is_const());
|
||||
ASSERT_FALSE(data.is_static());
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 0);
|
||||
ASSERT_TRUE(data.set(instance, 42));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetterGetterReadOnly) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<setter_getter_t>().data("z_ro"_hs);
|
||||
setter_getter_t instance{};
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 0u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::meta_type{});
|
||||
ASSERT_TRUE(data.is_const());
|
||||
ASSERT_FALSE(data.is_static());
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 0);
|
||||
ASSERT_FALSE(data.set(instance, 42));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 0);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetterGetterReadOnlyDataMember) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<setter_getter_t>().data("value"_hs);
|
||||
setter_getter_t instance{};
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 0u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::meta_type{});
|
||||
ASSERT_TRUE(data.is_const());
|
||||
ASSERT_FALSE(data.is_static());
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 0);
|
||||
ASSERT_FALSE(data.set(instance, 42));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 0);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, MultiSetter) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<multi_setter_t>().data("value"_hs);
|
||||
multi_setter_t instance{};
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 2u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<double>());
|
||||
ASSERT_EQ(data.arg(1u), entt::resolve<const char *>());
|
||||
ASSERT_EQ(data.arg(2u), entt::meta_type{});
|
||||
ASSERT_FALSE(data.is_const());
|
||||
ASSERT_FALSE(data.is_static());
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 0);
|
||||
ASSERT_TRUE(data.set(instance, 42));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 42);
|
||||
ASSERT_TRUE(data.set(instance, 3.));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 3);
|
||||
ASSERT_FALSE(data.set(instance, std::string{"99"}));
|
||||
ASSERT_TRUE(data.set(instance, std::string{"99"}.c_str()));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 99);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, ConstInstance) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz_t instance{};
|
||||
|
||||
ASSERT_NE(entt::resolve<clazz_t>().data("i"_hs).get(instance).try_cast<int>(), nullptr);
|
||||
ASSERT_NE(entt::resolve<clazz_t>().data("i"_hs).get(instance).try_cast<const int>(), nullptr);
|
||||
ASSERT_EQ(entt::resolve<clazz_t>().data("i"_hs).get(std::as_const(instance)).try_cast<int>(), nullptr);
|
||||
// as_ref_t adapts to the constness of the passed object and returns const references in case
|
||||
ASSERT_NE(entt::resolve<clazz_t>().data("i"_hs).get(std::as_const(instance)).try_cast<const int>(), nullptr);
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).get(instance));
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).set(instance, 3));
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("i"_hs).get(std::as_const(instance)));
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().data("i"_hs).set(std::as_const(instance), 3));
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("ci"_hs).get(instance));
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("ci"_hs).set(instance, 3));
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("ci"_hs).get(std::as_const(instance)));
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().data("ci"_hs).set(std::as_const(instance), 3));
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("j"_hs).get(instance));
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().data("j"_hs).set(instance, 3));
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("j"_hs).get(std::as_const(instance)));
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().data("j"_hs).set(std::as_const(instance), 3));
|
||||
}
|
||||
|
||||
TEST_F(MetaData, ArrayStatic) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<array_t>().data("global"_hs);
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int[3]>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int[3]>());
|
||||
ASSERT_FALSE(data.is_const());
|
||||
ASSERT_TRUE(data.is_static());
|
||||
ASSERT_TRUE(data.type().is_array());
|
||||
ASSERT_FALSE(data.get({}));
|
||||
}
|
||||
|
||||
TEST_F(MetaData, Array) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<array_t>().data("local"_hs);
|
||||
array_t instance{};
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int[5]>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int[5]>());
|
||||
ASSERT_FALSE(data.is_const());
|
||||
ASSERT_FALSE(data.is_static());
|
||||
ASSERT_TRUE(data.type().is_array());
|
||||
ASSERT_FALSE(data.get(instance));
|
||||
}
|
||||
|
||||
TEST_F(MetaData, AsVoid) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<clazz_t>().data("void"_hs);
|
||||
clazz_t instance{};
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int>());
|
||||
ASSERT_TRUE(data.set(instance, 42));
|
||||
ASSERT_EQ(instance.i, 42);
|
||||
ASSERT_EQ(data.get(instance), entt::meta_any{std::in_place_type<void>});
|
||||
}
|
||||
|
||||
TEST_F(MetaData, AsRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz_t instance{};
|
||||
auto data = entt::resolve<clazz_t>().data("i"_hs);
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int>());
|
||||
ASSERT_NE(data.prop().cbegin(), data.prop().cend());
|
||||
ASSERT_EQ(instance.i, 0);
|
||||
|
||||
data.get(instance).cast<int &>() = 3;
|
||||
|
||||
ASSERT_EQ(instance.i, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, AsConstRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz_t instance{};
|
||||
auto data = entt::resolve<clazz_t>().data("ci"_hs);
|
||||
|
||||
ASSERT_EQ(instance.i, 0);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int>());
|
||||
ASSERT_EQ(data.get(instance).cast<const int &>(), 0);
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 0);
|
||||
ASSERT_EQ(data.prop().cbegin(), data.prop().cend());
|
||||
ASSERT_EQ(instance.i, 0);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaDataDeathTest, AsConstRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz_t instance{};
|
||||
auto data = entt::resolve<clazz_t>().data("ci"_hs);
|
||||
|
||||
ASSERT_DEATH(data.get(instance).cast<int &>() = 3, "");
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetGetBaseData) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<derived_t>();
|
||||
derived_t instance{};
|
||||
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
ASSERT_TRUE(type.data("value"_hs).set(instance, 42));
|
||||
ASSERT_EQ(type.data("value"_hs).get(instance).cast<int>(), 42);
|
||||
ASSERT_EQ(instance.value, 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetGetFromBase) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<derived_t>();
|
||||
derived_t instance{};
|
||||
|
||||
ASSERT_TRUE(type.data("value_from_base"_hs));
|
||||
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
ASSERT_TRUE(type.data("value_from_base"_hs).set(instance, 42));
|
||||
ASSERT_EQ(type.data("value_from_base"_hs).get(instance).cast<int>(), 42);
|
||||
ASSERT_EQ(instance.value, 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, ReRegistration) {
|
||||
using namespace entt::literals;
|
||||
|
||||
SetUp();
|
||||
|
||||
auto &&node = entt::internal::resolve<base_t>(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()));
|
||||
auto type = entt::resolve<base_t>();
|
||||
|
||||
ASSERT_TRUE(node.details);
|
||||
ASSERT_FALSE(node.details->data.empty());
|
||||
ASSERT_EQ(node.details->data.size(), 1u);
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
|
||||
entt::meta<base_t>().data<&base_t::value>("field"_hs);
|
||||
|
||||
ASSERT_TRUE(node.details);
|
||||
ASSERT_EQ(node.details->data.size(), 2u);
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
ASSERT_TRUE(type.data("field"_hs));
|
||||
}
|
||||
|
||||
TEST_F(MetaData, CollisionAndReuse) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("j"_hs));
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().data("cj"_hs));
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("j"_hs).is_const());
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(entt::meta<clazz_t>().data<&clazz_t::i>("j"_hs));
|
||||
ASSERT_NO_FATAL_FAILURE(entt::meta<clazz_t>().data<&clazz_t::j>("cj"_hs));
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("j"_hs));
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("cj"_hs));
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().data("j"_hs).is_const());
|
||||
}
|
113
test/entt/meta/meta_dtor.cpp
Normal file
113
test/entt/meta/meta_dtor.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/locator/locator.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/node.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
|
||||
struct clazz_t {
|
||||
clazz_t() {
|
||||
++counter;
|
||||
}
|
||||
|
||||
static void destroy_decr(clazz_t &) {
|
||||
--counter;
|
||||
}
|
||||
|
||||
void destroy_incr() const {
|
||||
++counter;
|
||||
}
|
||||
|
||||
inline static int counter = 0;
|
||||
};
|
||||
|
||||
struct MetaDtor: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<clazz_t>()
|
||||
.type("clazz"_hs)
|
||||
.dtor<clazz_t::destroy_decr>();
|
||||
|
||||
clazz_t::counter = 0;
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(MetaDtor, Functionalities) {
|
||||
ASSERT_EQ(clazz_t::counter, 0);
|
||||
|
||||
auto any = entt::resolve<clazz_t>().construct();
|
||||
auto cref = std::as_const(any).as_ref();
|
||||
auto ref = any.as_ref();
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(cref);
|
||||
ASSERT_TRUE(ref);
|
||||
|
||||
ASSERT_EQ(clazz_t::counter, 1);
|
||||
|
||||
cref.reset();
|
||||
ref.reset();
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(cref);
|
||||
ASSERT_FALSE(ref);
|
||||
|
||||
ASSERT_EQ(clazz_t::counter, 1);
|
||||
|
||||
any.reset();
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_FALSE(cref);
|
||||
ASSERT_FALSE(ref);
|
||||
|
||||
ASSERT_EQ(clazz_t::counter, 0);
|
||||
}
|
||||
|
||||
TEST_F(MetaDtor, AsRefConstruction) {
|
||||
ASSERT_EQ(clazz_t::counter, 0);
|
||||
|
||||
clazz_t instance{};
|
||||
auto any = entt::forward_as_meta(instance);
|
||||
auto cany = entt::forward_as_meta(std::as_const(instance));
|
||||
auto cref = cany.as_ref();
|
||||
auto ref = any.as_ref();
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(cany);
|
||||
ASSERT_TRUE(cref);
|
||||
ASSERT_TRUE(ref);
|
||||
|
||||
ASSERT_EQ(clazz_t::counter, 1);
|
||||
|
||||
any.reset();
|
||||
cany.reset();
|
||||
cref.reset();
|
||||
ref.reset();
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_FALSE(cany);
|
||||
ASSERT_FALSE(cref);
|
||||
ASSERT_FALSE(ref);
|
||||
|
||||
ASSERT_EQ(clazz_t::counter, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaDtor, ReRegistration) {
|
||||
SetUp();
|
||||
|
||||
auto &&node = entt::internal::resolve<clazz_t>(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()));
|
||||
|
||||
ASSERT_NE(node.dtor.dtor, nullptr);
|
||||
|
||||
entt::meta<clazz_t>().dtor<&clazz_t::destroy_incr>();
|
||||
entt::resolve<clazz_t>().construct().reset();
|
||||
|
||||
ASSERT_EQ(clazz_t::counter, 2);
|
||||
}
|
608
test/entt/meta/meta_func.cpp
Normal file
608
test/entt/meta/meta_func.cpp
Normal file
@ -0,0 +1,608 @@
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/core/utility.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include "../common/config.h"
|
||||
|
||||
struct base_t {
|
||||
base_t() {}
|
||||
virtual ~base_t() = default;
|
||||
|
||||
static void destroy(base_t &) {
|
||||
++counter;
|
||||
}
|
||||
|
||||
void setter(int v) {
|
||||
value = v;
|
||||
}
|
||||
|
||||
int getter() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
static void static_setter(base_t &ref, int v) {
|
||||
ref.value = v;
|
||||
}
|
||||
|
||||
inline static int counter = 0;
|
||||
int value{3};
|
||||
};
|
||||
|
||||
void fake_member(base_t &instance, int value) {
|
||||
instance.value = value;
|
||||
}
|
||||
|
||||
int fake_const_member(const base_t &instance) {
|
||||
return instance.value;
|
||||
}
|
||||
|
||||
struct derived_t: base_t {
|
||||
derived_t()
|
||||
: base_t{} {}
|
||||
};
|
||||
|
||||
struct func_t {
|
||||
int f(const base_t &, int a, int b) {
|
||||
return f(a, b);
|
||||
}
|
||||
|
||||
int f(int a, int b) {
|
||||
value = a;
|
||||
return b * b;
|
||||
}
|
||||
|
||||
int f(int v) const {
|
||||
return v * v;
|
||||
}
|
||||
|
||||
void g(int v) {
|
||||
value = v * v;
|
||||
}
|
||||
|
||||
static int h(int &v) {
|
||||
return (v *= value);
|
||||
}
|
||||
|
||||
static void k(int v) {
|
||||
value = v;
|
||||
}
|
||||
|
||||
int v(int v) const {
|
||||
return (value = v);
|
||||
}
|
||||
|
||||
int &a() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
operator int() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
inline static int value = 0;
|
||||
};
|
||||
|
||||
struct MetaFunc: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<double>()
|
||||
.type("double"_hs);
|
||||
|
||||
entt::meta<base_t>()
|
||||
.type("base"_hs)
|
||||
.dtor<base_t::destroy>()
|
||||
.func<&base_t::setter>("setter"_hs)
|
||||
.func<fake_member>("fake_member"_hs)
|
||||
.func<fake_const_member>("fake_const_member"_hs);
|
||||
|
||||
entt::meta<derived_t>()
|
||||
.type("derived"_hs)
|
||||
.base<base_t>()
|
||||
.func<&base_t::setter>("setter_from_base"_hs)
|
||||
.func<&base_t::getter>("getter_from_base"_hs)
|
||||
.func<&base_t::static_setter>("static_setter_from_base"_hs)
|
||||
.dtor<derived_t::destroy>();
|
||||
|
||||
entt::meta<func_t>()
|
||||
.type("func"_hs)
|
||||
.func<&entt::registry::emplace_or_replace<func_t>>("emplace"_hs)
|
||||
.func<entt::overload<int(const base_t &, int, int)>(&func_t::f)>("f3"_hs)
|
||||
.func<entt::overload<int(int, int)>(&func_t::f)>("f2"_hs)
|
||||
.prop("true"_hs, false)
|
||||
.func<entt::overload<int(int) const>(&func_t::f)>("f1"_hs)
|
||||
.prop("true"_hs, false)
|
||||
.func<&func_t::g>("g"_hs)
|
||||
.prop("true"_hs, false)
|
||||
.func<func_t::h>("h"_hs)
|
||||
.prop("true"_hs, false)
|
||||
.func<func_t::k>("k"_hs)
|
||||
.prop("true"_hs, false)
|
||||
.func<&func_t::v, entt::as_void_t>("v"_hs)
|
||||
.func<&func_t::a, entt::as_ref_t>("a"_hs)
|
||||
.func<&func_t::a, entt::as_cref_t>("ca"_hs)
|
||||
.conv<int>();
|
||||
|
||||
base_t::counter = 0;
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
|
||||
std::size_t reset_and_check() {
|
||||
std::size_t count = 0;
|
||||
|
||||
for(auto func: entt::resolve<func_t>().func()) {
|
||||
for(auto curr = func.second; curr; curr = curr.next()) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
SetUp();
|
||||
|
||||
for(auto func: entt::resolve<func_t>().func()) {
|
||||
for(auto curr = func.second; curr; curr = curr.next()) {
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
};
|
||||
};
|
||||
|
||||
using MetaFuncDeathTest = MetaFunc;
|
||||
|
||||
TEST_F(MetaFunc, Functionalities) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<func_t>().func("f2"_hs);
|
||||
func_t instance{};
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 2u);
|
||||
ASSERT_FALSE(func.is_const());
|
||||
ASSERT_FALSE(func.is_static());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<int>());
|
||||
ASSERT_EQ(func.arg(0u), entt::resolve<int>());
|
||||
ASSERT_EQ(func.arg(1u), entt::resolve<int>());
|
||||
ASSERT_FALSE(func.arg(2u));
|
||||
|
||||
auto any = func.invoke(instance, 3, 2);
|
||||
auto empty = func.invoke(instance);
|
||||
|
||||
ASSERT_FALSE(empty);
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 4);
|
||||
ASSERT_EQ(func_t::value, 3);
|
||||
|
||||
for(auto curr: func.prop()) {
|
||||
ASSERT_EQ(curr.first, "true"_hs);
|
||||
ASSERT_FALSE(curr.second.value().template cast<bool>());
|
||||
}
|
||||
|
||||
ASSERT_FALSE(func.prop(false));
|
||||
ASSERT_FALSE(func.prop('c'));
|
||||
|
||||
auto prop = func.prop("true"_hs);
|
||||
|
||||
ASSERT_TRUE(prop);
|
||||
ASSERT_FALSE(prop.value().cast<bool>());
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, Const) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<func_t>().func("f1"_hs);
|
||||
func_t instance{};
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 1u);
|
||||
ASSERT_TRUE(func.is_const());
|
||||
ASSERT_FALSE(func.is_static());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<int>());
|
||||
ASSERT_EQ(func.arg(0u), entt::resolve<int>());
|
||||
ASSERT_FALSE(func.arg(1u));
|
||||
|
||||
auto any = func.invoke(instance, 4);
|
||||
auto empty = func.invoke(instance, derived_t{});
|
||||
|
||||
ASSERT_FALSE(empty);
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 16);
|
||||
|
||||
for(auto curr: func.prop()) {
|
||||
ASSERT_EQ(curr.first, "true"_hs);
|
||||
ASSERT_FALSE(curr.second.value().template cast<bool>());
|
||||
}
|
||||
|
||||
ASSERT_FALSE(func.prop(false));
|
||||
ASSERT_FALSE(func.prop('c'));
|
||||
|
||||
auto prop = func.prop("true"_hs);
|
||||
|
||||
ASSERT_TRUE(prop);
|
||||
ASSERT_FALSE(prop.value().cast<bool>());
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, RetVoid) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<func_t>().func("g"_hs);
|
||||
func_t instance{};
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 1u);
|
||||
ASSERT_FALSE(func.is_const());
|
||||
ASSERT_FALSE(func.is_static());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<void>());
|
||||
ASSERT_EQ(func.arg(0u), entt::resolve<int>());
|
||||
ASSERT_FALSE(func.arg(1u));
|
||||
|
||||
auto any = func.invoke(instance, 5);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(func_t::value, 25);
|
||||
|
||||
for(auto curr: func.prop()) {
|
||||
ASSERT_EQ(curr.first, "true"_hs);
|
||||
ASSERT_FALSE(curr.second.value().template cast<bool>());
|
||||
}
|
||||
|
||||
ASSERT_FALSE(func.prop(false));
|
||||
ASSERT_FALSE(func.prop('c'));
|
||||
|
||||
auto prop = func.prop("true"_hs);
|
||||
|
||||
ASSERT_TRUE(prop);
|
||||
ASSERT_FALSE(prop.value().cast<bool>());
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, Static) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<func_t>().func("h"_hs);
|
||||
func_t::value = 2;
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 1u);
|
||||
ASSERT_FALSE(func.is_const());
|
||||
ASSERT_TRUE(func.is_static());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<int>());
|
||||
ASSERT_EQ(func.arg(0u), entt::resolve<int>());
|
||||
ASSERT_FALSE(func.arg(1u));
|
||||
|
||||
auto any = func.invoke({}, 3);
|
||||
auto empty = func.invoke({}, derived_t{});
|
||||
|
||||
ASSERT_FALSE(empty);
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 6);
|
||||
|
||||
for(auto curr: func.prop()) {
|
||||
ASSERT_EQ(curr.first, "true"_hs);
|
||||
ASSERT_FALSE(curr.second.value().template cast<bool>());
|
||||
}
|
||||
|
||||
ASSERT_FALSE(func.prop(false));
|
||||
ASSERT_FALSE(func.prop('c'));
|
||||
|
||||
auto prop = func.prop("true"_hs);
|
||||
|
||||
ASSERT_TRUE(prop);
|
||||
ASSERT_FALSE(prop.value().cast<bool>());
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, StaticRetVoid) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<func_t>().func("k"_hs);
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 1u);
|
||||
ASSERT_FALSE(func.is_const());
|
||||
ASSERT_TRUE(func.is_static());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<void>());
|
||||
ASSERT_EQ(func.arg(0u), entt::resolve<int>());
|
||||
ASSERT_FALSE(func.arg(1u));
|
||||
|
||||
auto any = func.invoke({}, 42);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(func_t::value, 42);
|
||||
|
||||
for(auto curr: func.prop()) {
|
||||
ASSERT_EQ(curr.first, "true"_hs);
|
||||
ASSERT_FALSE(curr.second.value().template cast<bool>());
|
||||
}
|
||||
|
||||
ASSERT_FALSE(func.prop(false));
|
||||
ASSERT_FALSE(func.prop('c'));
|
||||
|
||||
auto prop = func.prop("true"_hs);
|
||||
|
||||
ASSERT_TRUE(prop);
|
||||
ASSERT_FALSE(prop.value().cast<bool>());
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, StaticAsMember) {
|
||||
using namespace entt::literals;
|
||||
|
||||
base_t instance{};
|
||||
auto func = entt::resolve<base_t>().func("fake_member"_hs);
|
||||
auto any = func.invoke(instance, 42);
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 1u);
|
||||
ASSERT_FALSE(func.is_const());
|
||||
ASSERT_FALSE(func.is_static());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<void>());
|
||||
ASSERT_EQ(func.arg(0u), entt::resolve<int>());
|
||||
ASSERT_FALSE(func.arg(1u));
|
||||
|
||||
ASSERT_EQ(func.prop().cbegin(), func.prop().cend());
|
||||
|
||||
ASSERT_FALSE(func.invoke({}, 42));
|
||||
ASSERT_FALSE(func.invoke(std::as_const(instance), 42));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(instance.value, 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, StaticAsConstMember) {
|
||||
using namespace entt::literals;
|
||||
|
||||
base_t instance{};
|
||||
auto func = entt::resolve<base_t>().func("fake_const_member"_hs);
|
||||
auto any = func.invoke(std::as_const(instance));
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 0u);
|
||||
ASSERT_TRUE(func.is_const());
|
||||
ASSERT_FALSE(func.is_static());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<int>());
|
||||
ASSERT_FALSE(func.arg(0u));
|
||||
|
||||
ASSERT_EQ(func.prop().cbegin(), func.prop().cend());
|
||||
|
||||
ASSERT_FALSE(func.invoke({}));
|
||||
ASSERT_TRUE(func.invoke(instance));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, MetaAnyArgs) {
|
||||
using namespace entt::literals;
|
||||
|
||||
func_t instance;
|
||||
auto any = entt::resolve<func_t>().func("f1"_hs).invoke(instance, 3);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 9);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, InvalidArgs) {
|
||||
using namespace entt::literals;
|
||||
|
||||
int value = 3;
|
||||
ASSERT_FALSE(entt::resolve<func_t>().func("f1"_hs).invoke(value, 'c'));
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, CastAndConvert) {
|
||||
using namespace entt::literals;
|
||||
|
||||
func_t instance;
|
||||
instance.value = 3;
|
||||
auto any = entt::resolve<func_t>().func("f3"_hs).invoke(instance, derived_t{}, 0, instance);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 9);
|
||||
ASSERT_EQ(instance.value, 0);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, ArithmeticConversion) {
|
||||
using namespace entt::literals;
|
||||
|
||||
func_t instance;
|
||||
auto any = entt::resolve<func_t>().func("f2"_hs).invoke(instance, true, 4.2);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 16);
|
||||
ASSERT_EQ(instance.value, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, ArgsByRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<func_t>().func("h"_hs);
|
||||
func_t::value = 2;
|
||||
entt::meta_any any{3};
|
||||
int value = 4;
|
||||
|
||||
ASSERT_EQ(func.invoke({}, entt::forward_as_meta(value)).cast<int>(), 8);
|
||||
ASSERT_EQ(func.invoke({}, any.as_ref()).cast<int>(), 6);
|
||||
ASSERT_EQ(any.cast<int>(), 6);
|
||||
ASSERT_EQ(value, 8);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, ArgsByConstRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
func_t instance{};
|
||||
auto func = entt::resolve<func_t>().func("g"_hs);
|
||||
entt::meta_any any{2};
|
||||
int value = 3;
|
||||
|
||||
ASSERT_TRUE(func.invoke(instance, entt::forward_as_meta(std::as_const(value))));
|
||||
ASSERT_EQ(func_t::value, 9);
|
||||
|
||||
ASSERT_TRUE(func.invoke(instance, std::as_const(any).as_ref()));
|
||||
ASSERT_EQ(func_t::value, 4);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, ConstInstance) {
|
||||
using namespace entt::literals;
|
||||
|
||||
func_t instance{};
|
||||
auto any = entt::resolve<func_t>().func("f1"_hs).invoke(std::as_const(instance), 2);
|
||||
|
||||
ASSERT_FALSE(entt::resolve<func_t>().func("g"_hs).invoke(std::as_const(instance), 42));
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<int>(), 4);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, AsVoid) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<func_t>().func("v"_hs);
|
||||
func_t instance{};
|
||||
|
||||
ASSERT_EQ(func.invoke(instance, 42), entt::meta_any{std::in_place_type<void>});
|
||||
ASSERT_EQ(func.ret(), entt::resolve<void>());
|
||||
ASSERT_EQ(instance.value, 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, AsRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
func_t instance{};
|
||||
auto func = entt::resolve<func_t>().func("a"_hs);
|
||||
func.invoke(instance).cast<int &>() = 3;
|
||||
|
||||
ASSERT_EQ(func.ret(), entt::resolve<int>());
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, AsConstRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
func_t instance{};
|
||||
auto func = entt::resolve<func_t>().func("ca"_hs);
|
||||
|
||||
ASSERT_EQ(func.ret(), entt::resolve<int>());
|
||||
ASSERT_EQ(func.invoke(instance).cast<const int &>(), 3);
|
||||
ASSERT_EQ(func.invoke(instance).cast<int>(), 3);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaFuncDeathTest, AsConstRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
func_t instance{};
|
||||
auto func = entt::resolve<func_t>().func("ca"_hs);
|
||||
|
||||
ASSERT_DEATH((func.invoke(instance).cast<int &>() = 3), "");
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, InvokeBaseFunction) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<derived_t>();
|
||||
derived_t instance{};
|
||||
|
||||
ASSERT_TRUE(type.func("setter"_hs));
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
|
||||
type.func("setter"_hs).invoke(instance, 42);
|
||||
|
||||
ASSERT_EQ(instance.value, 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, InvokeFromBase) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<derived_t>();
|
||||
derived_t instance{};
|
||||
|
||||
auto setter_from_base = type.func("setter_from_base"_hs);
|
||||
|
||||
ASSERT_TRUE(setter_from_base);
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
|
||||
setter_from_base.invoke(instance, 42);
|
||||
|
||||
ASSERT_EQ(instance.value, 42);
|
||||
|
||||
auto getter_from_base = type.func("getter_from_base"_hs);
|
||||
|
||||
ASSERT_TRUE(getter_from_base);
|
||||
ASSERT_EQ(getter_from_base.invoke(instance).cast<int>(), 42);
|
||||
|
||||
auto static_setter_from_base = type.func("static_setter_from_base"_hs);
|
||||
|
||||
ASSERT_TRUE(static_setter_from_base);
|
||||
ASSERT_EQ(instance.value, 42);
|
||||
|
||||
static_setter_from_base.invoke(instance, 3);
|
||||
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, ExternalMemberFunction) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<func_t>().func("emplace"_hs);
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 2u);
|
||||
ASSERT_FALSE(func.is_const());
|
||||
ASSERT_TRUE(func.is_static());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<void>());
|
||||
ASSERT_EQ(func.arg(0u), entt::resolve<entt::registry>());
|
||||
ASSERT_EQ(func.arg(1u), entt::resolve<entt::entity>());
|
||||
ASSERT_FALSE(func.arg(2u));
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_FALSE(registry.all_of<func_t>(entity));
|
||||
|
||||
func.invoke({}, entt::forward_as_meta(registry), entity);
|
||||
|
||||
ASSERT_TRUE(registry.all_of<func_t>(entity));
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, ReRegistration) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_EQ(reset_and_check(), 0u);
|
||||
|
||||
func_t instance{};
|
||||
auto type = entt::resolve<func_t>();
|
||||
|
||||
ASSERT_TRUE(type.func("f2"_hs));
|
||||
ASSERT_FALSE(type.invoke("f2"_hs, instance, 0));
|
||||
ASSERT_TRUE(type.invoke("f2"_hs, instance, 0, 0));
|
||||
|
||||
ASSERT_TRUE(type.func("f1"_hs));
|
||||
ASSERT_TRUE(type.invoke("f1"_hs, instance, 0));
|
||||
ASSERT_FALSE(type.invoke("f1"_hs, instance, 0, 0));
|
||||
|
||||
entt::meta<func_t>()
|
||||
.func<entt::overload<int(int, int)>(&func_t::f)>("f"_hs)
|
||||
.func<entt::overload<int(int) const>(&func_t::f)>("f"_hs);
|
||||
|
||||
ASSERT_TRUE(type.func("f1"_hs));
|
||||
ASSERT_TRUE(type.func("f2"_hs));
|
||||
ASSERT_TRUE(type.func("f"_hs));
|
||||
|
||||
ASSERT_TRUE(type.invoke("f"_hs, instance, 0));
|
||||
ASSERT_TRUE(type.invoke("f"_hs, instance, 0, 0));
|
||||
|
||||
ASSERT_EQ(reset_and_check(), 0u);
|
||||
}
|
66
test/entt/meta/meta_handle.cpp
Normal file
66
test/entt/meta/meta_handle.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
|
||||
struct clazz_t {
|
||||
clazz_t()
|
||||
: value{} {}
|
||||
|
||||
void incr() {
|
||||
++value;
|
||||
}
|
||||
|
||||
void decr() {
|
||||
--value;
|
||||
}
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
struct MetaHandle: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<clazz_t>()
|
||||
.type("clazz"_hs)
|
||||
.func<&clazz_t::incr>("incr"_hs)
|
||||
.func<&clazz_t::decr>("decr"_hs);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(MetaHandle, Functionalities) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz_t instance{};
|
||||
entt::meta_handle handle{};
|
||||
entt::meta_handle chandle{};
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_FALSE(chandle);
|
||||
|
||||
handle = entt::meta_handle{instance};
|
||||
chandle = entt::meta_handle{std::as_const(instance)};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_TRUE(chandle);
|
||||
|
||||
ASSERT_TRUE(handle->invoke("incr"_hs));
|
||||
ASSERT_FALSE(chandle->invoke("incr"_hs));
|
||||
ASSERT_FALSE(std::as_const(handle)->invoke("incr"_hs));
|
||||
ASSERT_EQ(instance.value, 1);
|
||||
|
||||
auto any = entt::forward_as_meta(instance);
|
||||
handle = entt::meta_handle{any};
|
||||
chandle = entt::meta_handle{std::as_const(any)};
|
||||
|
||||
ASSERT_TRUE(handle->invoke("decr"_hs));
|
||||
ASSERT_FALSE(chandle->invoke("decr"_hs));
|
||||
ASSERT_FALSE(std::as_const(handle)->invoke("decr"_hs));
|
||||
ASSERT_EQ(instance.value, 0);
|
||||
}
|
414
test/entt/meta/meta_pointer.cpp
Normal file
414
test/entt/meta/meta_pointer.cpp
Normal file
@ -0,0 +1,414 @@
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/pointer.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include "../common/config.h"
|
||||
|
||||
template<typename Type>
|
||||
struct wrapped_shared_ptr {
|
||||
wrapped_shared_ptr(Type init)
|
||||
: ptr{new Type{init}} {}
|
||||
|
||||
Type &deref() const {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Type> ptr;
|
||||
};
|
||||
|
||||
struct self_ptr {
|
||||
using element_type = self_ptr;
|
||||
|
||||
self_ptr(int v)
|
||||
: value{v} {}
|
||||
|
||||
const self_ptr &operator*() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
struct proxy_ptr {
|
||||
using element_type = proxy_ptr;
|
||||
|
||||
proxy_ptr(int &v)
|
||||
: value{&v} {}
|
||||
|
||||
proxy_ptr operator*() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
int *value;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct adl_wrapped_shared_ptr: wrapped_shared_ptr<Type> {};
|
||||
|
||||
template<typename Type>
|
||||
struct spec_wrapped_shared_ptr: wrapped_shared_ptr<Type> {};
|
||||
|
||||
template<typename Type>
|
||||
struct entt::is_meta_pointer_like<adl_wrapped_shared_ptr<Type>>: std::true_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct entt::is_meta_pointer_like<spec_wrapped_shared_ptr<Type>>: std::true_type {};
|
||||
|
||||
template<>
|
||||
struct entt::is_meta_pointer_like<self_ptr>: std::true_type {};
|
||||
|
||||
template<>
|
||||
struct entt::is_meta_pointer_like<proxy_ptr>: std::true_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct entt::adl_meta_pointer_like<spec_wrapped_shared_ptr<Type>> {
|
||||
static decltype(auto) dereference(const spec_wrapped_shared_ptr<Type> &ptr) {
|
||||
return ptr.deref();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
Type &dereference_meta_pointer_like(const adl_wrapped_shared_ptr<Type> &ptr) {
|
||||
return ptr.deref();
|
||||
}
|
||||
|
||||
int test_function() {
|
||||
return 42;
|
||||
}
|
||||
|
||||
struct not_copyable_t {
|
||||
not_copyable_t() = default;
|
||||
not_copyable_t(const not_copyable_t &) = delete;
|
||||
not_copyable_t(not_copyable_t &&) = default;
|
||||
not_copyable_t &operator=(const not_copyable_t &) = delete;
|
||||
not_copyable_t &operator=(not_copyable_t &&) = default;
|
||||
};
|
||||
|
||||
TEST(MetaPointerLike, DereferenceOperatorInvalidType) {
|
||||
int value = 0;
|
||||
entt::meta_any any{value};
|
||||
|
||||
ASSERT_FALSE(any.type().is_pointer());
|
||||
ASSERT_FALSE(any.type().is_pointer_like());
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_FALSE(deref);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceOperatorConstType) {
|
||||
const int value = 42;
|
||||
entt::meta_any any{&value};
|
||||
|
||||
ASSERT_TRUE(any.type().is_pointer());
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
ASSERT_EQ(any.type(), entt::resolve<const int *>());
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_FALSE(deref.type().is_pointer());
|
||||
ASSERT_FALSE(deref.type().is_pointer_like());
|
||||
ASSERT_EQ(deref.type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_EQ(deref.try_cast<int>(), nullptr);
|
||||
ASSERT_EQ(deref.try_cast<const int>(), &value);
|
||||
ASSERT_EQ(deref.cast<const int &>(), 42);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(MetaPointerLikeDeathTest, DereferenceOperatorConstType) {
|
||||
const int value = 42;
|
||||
entt::meta_any any{&value};
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_DEATH(deref.cast<int &>() = 0, "");
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceOperatorConstAnyNonConstType) {
|
||||
int value = 42;
|
||||
const entt::meta_any any{&value};
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_FALSE(deref.type().is_pointer());
|
||||
ASSERT_FALSE(deref.type().is_pointer_like());
|
||||
ASSERT_EQ(deref.type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_NE(deref.try_cast<int>(), nullptr);
|
||||
ASSERT_NE(deref.try_cast<const int>(), nullptr);
|
||||
ASSERT_EQ(deref.cast<int &>(), 42);
|
||||
ASSERT_EQ(deref.cast<const int &>(), 42);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceOperatorConstAnyConstType) {
|
||||
const int value = 42;
|
||||
const entt::meta_any any{&value};
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_FALSE(deref.type().is_pointer());
|
||||
ASSERT_FALSE(deref.type().is_pointer_like());
|
||||
ASSERT_EQ(deref.type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_EQ(deref.try_cast<int>(), nullptr);
|
||||
ASSERT_NE(deref.try_cast<const int>(), nullptr);
|
||||
ASSERT_EQ(deref.cast<const int &>(), 42);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(MetaPointerLikeDeathTest, DereferenceOperatorConstAnyConstType) {
|
||||
const int value = 42;
|
||||
const entt::meta_any any{&value};
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_DEATH(deref.cast<int &>() = 0, "");
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceOperatorRawPointer) {
|
||||
int value = 0;
|
||||
entt::meta_any any{&value};
|
||||
|
||||
ASSERT_TRUE(any.type().is_pointer());
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
ASSERT_EQ(any.type(), entt::resolve<int *>());
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_FALSE(deref.type().is_pointer());
|
||||
ASSERT_FALSE(deref.type().is_pointer_like());
|
||||
ASSERT_EQ(deref.type(), entt::resolve<int>());
|
||||
|
||||
deref.cast<int &>() = 42;
|
||||
|
||||
ASSERT_EQ(*any.cast<int *>(), 42);
|
||||
ASSERT_EQ(value, 42);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceOperatorSmartPointer) {
|
||||
auto value = std::make_shared<int>(0);
|
||||
entt::meta_any any{value};
|
||||
|
||||
ASSERT_FALSE(any.type().is_pointer());
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
ASSERT_EQ(any.type(), entt::resolve<std::shared_ptr<int>>());
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_FALSE(deref.type().is_pointer());
|
||||
ASSERT_FALSE(deref.type().is_pointer_like());
|
||||
ASSERT_EQ(deref.type(), entt::resolve<int>());
|
||||
|
||||
deref.cast<int &>() = 42;
|
||||
|
||||
ASSERT_EQ(*any.cast<std::shared_ptr<int>>(), 42);
|
||||
ASSERT_EQ(*value, 42);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, PointerToConstMoveOnlyType) {
|
||||
const not_copyable_t instance;
|
||||
entt::meta_any any{&instance};
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(deref);
|
||||
|
||||
ASSERT_EQ(deref.try_cast<not_copyable_t>(), nullptr);
|
||||
ASSERT_NE(deref.try_cast<const not_copyable_t>(), nullptr);
|
||||
ASSERT_EQ(&deref.cast<const not_copyable_t &>(), &instance);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, AsRef) {
|
||||
int value = 0;
|
||||
int *ptr = &value;
|
||||
entt::meta_any any{entt::forward_as_meta(ptr)};
|
||||
|
||||
ASSERT_TRUE(any.type().is_pointer());
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
ASSERT_EQ(any.type(), entt::resolve<int *>());
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_FALSE(deref.type().is_pointer());
|
||||
ASSERT_FALSE(deref.type().is_pointer_like());
|
||||
ASSERT_EQ(deref.type(), entt::resolve<int>());
|
||||
|
||||
deref.cast<int &>() = 42;
|
||||
|
||||
ASSERT_EQ(*any.cast<int *>(), 42);
|
||||
ASSERT_EQ(value, 42);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, AsConstRef) {
|
||||
int value = 42;
|
||||
int *const ptr = &value;
|
||||
entt::meta_any any{entt::forward_as_meta(ptr)};
|
||||
|
||||
ASSERT_TRUE(any.type().is_pointer());
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
ASSERT_EQ(any.type(), entt::resolve<int *>());
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_FALSE(deref.type().is_pointer());
|
||||
ASSERT_FALSE(deref.type().is_pointer_like());
|
||||
ASSERT_EQ(deref.type(), entt::resolve<int>());
|
||||
|
||||
deref.cast<int &>() = 42;
|
||||
|
||||
ASSERT_EQ(*any.cast<int *>(), 42);
|
||||
ASSERT_EQ(value, 42);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceOverload) {
|
||||
auto test = [](entt::meta_any any) {
|
||||
ASSERT_FALSE(any.type().is_pointer());
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_FALSE(deref.type().is_pointer());
|
||||
ASSERT_FALSE(deref.type().is_pointer_like());
|
||||
ASSERT_EQ(deref.type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_EQ(deref.cast<int &>(), 42);
|
||||
ASSERT_EQ(deref.cast<const int &>(), 42);
|
||||
};
|
||||
|
||||
test(adl_wrapped_shared_ptr<int>{42});
|
||||
test(spec_wrapped_shared_ptr<int>{42});
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferencePointerToConstOverload) {
|
||||
auto test = [](entt::meta_any any) {
|
||||
ASSERT_FALSE(any.type().is_pointer());
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_FALSE(deref.type().is_pointer());
|
||||
ASSERT_FALSE(deref.type().is_pointer_like());
|
||||
ASSERT_EQ(deref.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(deref.cast<const int &>(), 42);
|
||||
};
|
||||
|
||||
test(adl_wrapped_shared_ptr<const int>{42});
|
||||
test(spec_wrapped_shared_ptr<const int>{42});
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(MetaPointerLikeDeathTest, DereferencePointerToConstOverload) {
|
||||
auto test = [](entt::meta_any any) {
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_DEATH(deref.cast<int &>() = 42, "");
|
||||
};
|
||||
|
||||
test(adl_wrapped_shared_ptr<const int>{42});
|
||||
test(spec_wrapped_shared_ptr<const int>{42});
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferencePointerToVoid) {
|
||||
auto test = [](entt::meta_any any) {
|
||||
ASSERT_TRUE(any.type().is_pointer());
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_FALSE(deref);
|
||||
};
|
||||
|
||||
test(static_cast<void *>(nullptr));
|
||||
test(static_cast<const void *>(nullptr));
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceSmartPointerToVoid) {
|
||||
auto test = [](entt::meta_any any) {
|
||||
ASSERT_TRUE(any.type().is_class());
|
||||
ASSERT_FALSE(any.type().is_pointer());
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_FALSE(deref);
|
||||
};
|
||||
|
||||
test(std::shared_ptr<void>{});
|
||||
test(std::unique_ptr<void, void (*)(void *)>{nullptr, nullptr});
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferencePointerToFunction) {
|
||||
auto test = [](entt::meta_any any) {
|
||||
ASSERT_TRUE(any.type().is_pointer());
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
ASSERT_NE(any.try_cast<int (*)()>(), nullptr);
|
||||
ASSERT_EQ(any.cast<int (*)()>()(), 42);
|
||||
};
|
||||
|
||||
entt::meta_any func{&test_function};
|
||||
|
||||
test(func);
|
||||
test(*func);
|
||||
test(**func);
|
||||
test(*std::as_const(func));
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceSelfPointer) {
|
||||
self_ptr obj{42};
|
||||
entt::meta_any any{entt::forward_as_meta(obj)};
|
||||
entt::meta_any deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
ASSERT_EQ(deref.cast<const self_ptr &>().value, obj.value);
|
||||
ASSERT_FALSE(deref.try_cast<self_ptr>());
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceProxyPointer) {
|
||||
int value = 3;
|
||||
proxy_ptr obj{value};
|
||||
entt::meta_any any{obj};
|
||||
entt::meta_any deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
ASSERT_EQ(*deref.cast<const proxy_ptr &>().value, value);
|
||||
ASSERT_TRUE(deref.try_cast<proxy_ptr>());
|
||||
|
||||
*deref.cast<proxy_ptr &>().value = 42;
|
||||
|
||||
ASSERT_EQ(value, 42);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceArray) {
|
||||
entt::meta_any array{std::in_place_type<int[3]>};
|
||||
entt::meta_any array_of_array{std::in_place_type<int[3][3]>};
|
||||
|
||||
ASSERT_EQ(array.type(), entt::resolve<int[3]>());
|
||||
ASSERT_EQ(array_of_array.type(), entt::resolve<int[3][3]>());
|
||||
|
||||
ASSERT_FALSE(*array);
|
||||
ASSERT_FALSE(*array_of_array);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceVerifiableNullPointerLike) {
|
||||
auto test = [](entt::meta_any any) {
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(*any);
|
||||
};
|
||||
|
||||
test(entt::meta_any{static_cast<int *>(nullptr)});
|
||||
test(entt::meta_any{std::shared_ptr<int>{}});
|
||||
test(entt::meta_any{std::unique_ptr<int>{}});
|
||||
}
|
111
test/entt/meta/meta_prop.cpp
Normal file
111
test/entt/meta/meta_prop.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
#include <cstring>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/locator/locator.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
|
||||
struct base_1_t {};
|
||||
struct base_2_t {};
|
||||
struct base_3_t {};
|
||||
struct derived_t: base_1_t, base_2_t, base_3_t {};
|
||||
|
||||
struct MetaProp: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<base_1_t>()
|
||||
.type("base_1"_hs)
|
||||
.prop("int"_hs, 42);
|
||||
|
||||
entt::meta<base_2_t>()
|
||||
.type("base_2"_hs)
|
||||
.prop("bool"_hs, false)
|
||||
.prop("char[]"_hs, "char[]");
|
||||
|
||||
entt::meta<base_3_t>()
|
||||
.type("base_3"_hs)
|
||||
.prop("key_only"_hs)
|
||||
.prop("key"_hs, 42);
|
||||
|
||||
entt::meta<derived_t>()
|
||||
.type("derived"_hs)
|
||||
.base<base_1_t>()
|
||||
.base<base_2_t>()
|
||||
.base<base_3_t>();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(MetaProp, Functionalities) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto prop = entt::resolve<base_1_t>().prop("int"_hs);
|
||||
|
||||
ASSERT_TRUE(prop);
|
||||
ASSERT_EQ(prop.value(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaProp, FromBase) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<derived_t>();
|
||||
auto prop_bool = type.prop("bool"_hs);
|
||||
auto prop_int = type.prop("int"_hs);
|
||||
auto key_only = type.prop("key_only"_hs);
|
||||
auto key_value = type.prop("key"_hs);
|
||||
|
||||
ASSERT_TRUE(prop_bool);
|
||||
ASSERT_TRUE(prop_int);
|
||||
ASSERT_TRUE(key_only);
|
||||
ASSERT_TRUE(key_value);
|
||||
|
||||
ASSERT_FALSE(prop_bool.value().cast<bool>());
|
||||
ASSERT_EQ(prop_int.value().cast<int>(), 42);
|
||||
ASSERT_FALSE(key_only.value());
|
||||
ASSERT_EQ(key_value.value().cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaProp, DeducedArrayType) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto prop = entt::resolve<base_2_t>().prop("char[]"_hs);
|
||||
|
||||
ASSERT_TRUE(prop);
|
||||
ASSERT_EQ(prop.value().type(), entt::resolve<const char *>());
|
||||
ASSERT_EQ(strcmp(prop.value().cast<const char *>(), "char[]"), 0);
|
||||
}
|
||||
|
||||
TEST_F(MetaProp, ReRegistration) {
|
||||
using namespace entt::literals;
|
||||
|
||||
SetUp();
|
||||
|
||||
auto &&node = entt::internal::resolve<base_1_t>(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()));
|
||||
auto type = entt::resolve<base_1_t>();
|
||||
|
||||
ASSERT_TRUE(node.details);
|
||||
ASSERT_FALSE(node.details->prop.empty());
|
||||
ASSERT_EQ(node.details->prop.size(), 1u);
|
||||
|
||||
ASSERT_TRUE(type.prop("int"_hs));
|
||||
ASSERT_EQ(type.prop("int"_hs).value().cast<int>(), 42);
|
||||
|
||||
entt::meta<base_1_t>().prop("int"_hs, 0);
|
||||
entt::meta<base_1_t>().prop("double"_hs, 3.);
|
||||
|
||||
ASSERT_TRUE(node.details);
|
||||
ASSERT_FALSE(node.details->prop.empty());
|
||||
ASSERT_EQ(node.details->prop.size(), 2u);
|
||||
|
||||
ASSERT_TRUE(type.prop("int"_hs));
|
||||
ASSERT_TRUE(type.prop("double"_hs));
|
||||
ASSERT_EQ(type.prop("int"_hs).value().cast<int>(), 0);
|
||||
ASSERT_EQ(type.prop("double"_hs).value().cast<double>(), 3.);
|
||||
}
|
95
test/entt/meta/meta_range.cpp
Normal file
95
test/entt/meta/meta_range.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
#include <type_traits>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/locator/locator.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/range.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
|
||||
struct MetaRange: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<int>().type("int"_hs).data<42>("answer"_hs);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(MetaRange, EmptyRange) {
|
||||
entt::meta_reset();
|
||||
auto range = entt::resolve();
|
||||
ASSERT_EQ(range.begin(), range.end());
|
||||
}
|
||||
|
||||
TEST_F(MetaRange, Iterator) {
|
||||
using namespace entt::literals;
|
||||
|
||||
using iterator = typename decltype(entt::resolve())::iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, std::pair<entt::id_type, entt::meta_type>>);
|
||||
static_assert(std::is_same_v<iterator::pointer, entt::input_iterator_pointer<std::pair<entt::id_type, entt::meta_type>>>);
|
||||
static_assert(std::is_same_v<iterator::reference, std::pair<entt::id_type, entt::meta_type>>);
|
||||
|
||||
auto range = entt::resolve();
|
||||
|
||||
iterator end{range.begin()};
|
||||
iterator begin{};
|
||||
begin = range.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, range.begin());
|
||||
ASSERT_EQ(end, range.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(begin++, range.begin());
|
||||
ASSERT_EQ(begin--, range.end());
|
||||
|
||||
ASSERT_EQ(begin + 1, range.end());
|
||||
ASSERT_EQ(end - 1, range.begin());
|
||||
|
||||
ASSERT_EQ(++begin, range.end());
|
||||
ASSERT_EQ(--begin, range.begin());
|
||||
|
||||
ASSERT_EQ(begin += 1, range.end());
|
||||
ASSERT_EQ(begin -= 1, range.begin());
|
||||
|
||||
ASSERT_EQ(begin + (end - begin), range.end());
|
||||
ASSERT_EQ(begin - (begin - end), range.end());
|
||||
|
||||
ASSERT_EQ(end - (end - begin), range.begin());
|
||||
ASSERT_EQ(end + (begin - end), range.begin());
|
||||
|
||||
ASSERT_EQ(begin[0u].first, range.begin()->first);
|
||||
ASSERT_EQ(begin[0u].second, (*range.begin()).second);
|
||||
|
||||
ASSERT_LT(begin, end);
|
||||
ASSERT_LE(begin, range.begin());
|
||||
|
||||
ASSERT_GT(end, begin);
|
||||
ASSERT_GE(end, range.end());
|
||||
|
||||
entt::meta<double>().type("double"_hs);
|
||||
range = entt::resolve();
|
||||
begin = range.begin();
|
||||
|
||||
ASSERT_EQ(begin[0u].first, entt::resolve<int>().info().hash());
|
||||
ASSERT_EQ(begin[1u].second, entt::resolve("double"_hs));
|
||||
}
|
||||
|
||||
TEST_F(MetaRange, DirectValue) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<int>();
|
||||
auto range = type.data();
|
||||
|
||||
ASSERT_NE(range.cbegin(), range.cend());
|
||||
|
||||
for(auto &&[id, data]: range) {
|
||||
ASSERT_EQ(id, "answer"_hs);
|
||||
ASSERT_EQ(data.get({}).cast<int>(), 42);
|
||||
}
|
||||
}
|
49
test/entt/meta/meta_template.cpp
Normal file
49
test/entt/meta/meta_template.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_traits.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include <entt/meta/template.hpp>
|
||||
|
||||
template<typename>
|
||||
struct function_type;
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
struct function_type<Ret(Args...)> {};
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
struct entt::meta_template_traits<function_type<Ret(Args...)>> {
|
||||
using class_type = meta_class_template_tag<function_type>;
|
||||
using args_type = type_list<Ret, Args...>;
|
||||
};
|
||||
|
||||
TEST(MetaTemplate, Invalid) {
|
||||
const auto type = entt::resolve<int>();
|
||||
|
||||
ASSERT_FALSE(type.is_template_specialization());
|
||||
ASSERT_EQ(type.template_arity(), 0u);
|
||||
ASSERT_EQ(type.template_type(), entt::meta_type{});
|
||||
ASSERT_EQ(type.template_arg(0u), entt::meta_type{});
|
||||
}
|
||||
|
||||
TEST(MetaTemplate, Valid) {
|
||||
const auto type = entt::resolve<entt::type_list<int, char>>();
|
||||
|
||||
ASSERT_TRUE(type.is_template_specialization());
|
||||
ASSERT_EQ(type.template_arity(), 2u);
|
||||
ASSERT_EQ(type.template_type(), entt::resolve<entt::meta_class_template_tag<entt::type_list>>());
|
||||
ASSERT_EQ(type.template_arg(0u), entt::resolve<int>());
|
||||
ASSERT_EQ(type.template_arg(1u), entt::resolve<char>());
|
||||
ASSERT_EQ(type.template_arg(2u), entt::meta_type{});
|
||||
}
|
||||
|
||||
TEST(MetaTemplate, CustomTraits) {
|
||||
const auto type = entt::resolve<function_type<void(int, const char &)>>();
|
||||
|
||||
ASSERT_TRUE(type.is_template_specialization());
|
||||
ASSERT_EQ(type.template_arity(), 3u);
|
||||
ASSERT_EQ(type.template_type(), entt::resolve<entt::meta_class_template_tag<function_type>>());
|
||||
ASSERT_EQ(type.template_arg(0u), entt::resolve<void>());
|
||||
ASSERT_EQ(type.template_arg(1u), entt::resolve<int>());
|
||||
ASSERT_EQ(type.template_arg(2u), entt::resolve<char>());
|
||||
ASSERT_EQ(type.template_arg(3u), entt::meta_type{});
|
||||
}
|
765
test/entt/meta/meta_type.cpp
Normal file
765
test/entt/meta/meta_type.cpp
Normal file
@ -0,0 +1,765 @@
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/core/utility.hpp>
|
||||
#include <entt/locator/locator.hpp>
|
||||
#include <entt/meta/container.hpp>
|
||||
#include <entt/meta/context.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/pointer.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include <entt/meta/template.hpp>
|
||||
#include "../common/config.h"
|
||||
|
||||
template<typename Type>
|
||||
void set(Type &prop, Type value) {
|
||||
prop = value;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
Type get(Type &prop) {
|
||||
return prop;
|
||||
}
|
||||
|
||||
struct base_t {
|
||||
base_t()
|
||||
: value{'c'} {};
|
||||
|
||||
char value;
|
||||
};
|
||||
|
||||
struct derived_t: base_t {
|
||||
derived_t()
|
||||
: base_t{} {}
|
||||
};
|
||||
|
||||
struct abstract_t {
|
||||
virtual ~abstract_t() = default;
|
||||
|
||||
virtual void func(int) {}
|
||||
void base_only(int) {}
|
||||
};
|
||||
|
||||
struct concrete_t: base_t, abstract_t {
|
||||
void func(int v) override {
|
||||
abstract_t::func(v);
|
||||
value = v;
|
||||
}
|
||||
|
||||
int value{3};
|
||||
};
|
||||
|
||||
struct clazz_t {
|
||||
clazz_t() = default;
|
||||
|
||||
clazz_t(const base_t &, int v)
|
||||
: value{v} {}
|
||||
|
||||
void member() {}
|
||||
static void func() {}
|
||||
|
||||
operator int() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
int value{};
|
||||
};
|
||||
|
||||
struct overloaded_func_t {
|
||||
int e(int v) const {
|
||||
return v + v;
|
||||
}
|
||||
|
||||
int f(const base_t &, int a, int b) {
|
||||
return f(a, b);
|
||||
}
|
||||
|
||||
int f(int a, int b) {
|
||||
value = a;
|
||||
return g(b);
|
||||
}
|
||||
|
||||
int f(int v) {
|
||||
return 2 * std::as_const(*this).f(v);
|
||||
}
|
||||
|
||||
int f(int v) const {
|
||||
return g(v);
|
||||
}
|
||||
|
||||
float f(int a, float b) {
|
||||
value = a;
|
||||
return static_cast<float>(e(static_cast<int>(b)));
|
||||
}
|
||||
|
||||
int g(int v) const {
|
||||
return v * v;
|
||||
}
|
||||
|
||||
inline static int value = 0;
|
||||
};
|
||||
|
||||
enum class property_t : entt::id_type {
|
||||
random,
|
||||
value,
|
||||
key_only,
|
||||
list
|
||||
};
|
||||
|
||||
struct MetaType: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta<double>()
|
||||
.type("double"_hs)
|
||||
.data<set<double>, get<double>>("var"_hs);
|
||||
|
||||
entt::meta<unsigned int>()
|
||||
.type("unsigned int"_hs)
|
||||
.data<0u>("min"_hs)
|
||||
.data<100u>("max"_hs);
|
||||
|
||||
entt::meta<base_t>()
|
||||
.type("base"_hs)
|
||||
.data<&base_t::value>("value"_hs);
|
||||
|
||||
entt::meta<derived_t>()
|
||||
.type("derived"_hs)
|
||||
.base<base_t>();
|
||||
|
||||
entt::meta<abstract_t>()
|
||||
.type("abstract"_hs)
|
||||
.func<&abstract_t::func>("func"_hs)
|
||||
.func<&abstract_t::base_only>("base_only"_hs);
|
||||
|
||||
entt::meta<concrete_t>()
|
||||
.type("concrete"_hs)
|
||||
.base<base_t>()
|
||||
.base<abstract_t>();
|
||||
|
||||
entt::meta<overloaded_func_t>()
|
||||
.type("overloaded_func"_hs)
|
||||
.func<&overloaded_func_t::e>("e"_hs)
|
||||
.func<entt::overload<int(const base_t &, int, int)>(&overloaded_func_t::f)>("f"_hs)
|
||||
.func<entt::overload<int(int, int)>(&overloaded_func_t::f)>("f"_hs)
|
||||
.func<entt::overload<int(int)>(&overloaded_func_t::f)>("f"_hs)
|
||||
.func<entt::overload<int(int) const>(&overloaded_func_t::f)>("f"_hs)
|
||||
.func<entt::overload<float(int, float)>(&overloaded_func_t::f)>("f"_hs)
|
||||
.func<&overloaded_func_t::g>("g"_hs);
|
||||
|
||||
entt::meta<property_t>()
|
||||
.type("property"_hs)
|
||||
.data<property_t::random>("random"_hs)
|
||||
.prop(static_cast<entt::id_type>(property_t::random), 0)
|
||||
.prop(static_cast<entt::id_type>(property_t::value), 3)
|
||||
.data<property_t::value>("value"_hs)
|
||||
.prop(static_cast<entt::id_type>(property_t::random), true)
|
||||
.prop(static_cast<entt::id_type>(property_t::value), 0)
|
||||
.prop(static_cast<entt::id_type>(property_t::key_only))
|
||||
.prop(static_cast<entt::id_type>(property_t::list))
|
||||
.data<property_t::key_only>("key_only"_hs)
|
||||
.prop(static_cast<entt::id_type>(property_t::key_only))
|
||||
.data<property_t::list>("list"_hs)
|
||||
.prop(static_cast<entt::id_type>(property_t::random), false)
|
||||
.prop(static_cast<entt::id_type>(property_t::value), 0)
|
||||
.prop(static_cast<entt::id_type>(property_t::key_only))
|
||||
.data<set<property_t>, get<property_t>>("var"_hs);
|
||||
|
||||
entt::meta<clazz_t>()
|
||||
.type("clazz"_hs)
|
||||
.prop(static_cast<entt::id_type>(property_t::value), 42)
|
||||
.ctor<const base_t &, int>()
|
||||
.data<&clazz_t::value>("value"_hs)
|
||||
.func<&clazz_t::member>("member"_hs)
|
||||
.func<clazz_t::func>("func"_hs)
|
||||
.conv<int>();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
using MetaTypeDeathTest = MetaType;
|
||||
|
||||
TEST_F(MetaType, Resolve) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_EQ(entt::resolve<double>(), entt::resolve("double"_hs));
|
||||
ASSERT_EQ(entt::resolve<double>(), entt::resolve(entt::type_id<double>()));
|
||||
ASSERT_FALSE(entt::resolve(entt::type_id<void>()));
|
||||
|
||||
auto range = entt::resolve();
|
||||
// it could be "char"_hs rather than entt::hashed_string::value("char") if it weren't for a bug in VS2017
|
||||
const auto it = std::find_if(range.begin(), range.end(), [](auto curr) { return curr.second.id() == entt::hashed_string::value("clazz"); });
|
||||
|
||||
ASSERT_NE(it, range.end());
|
||||
ASSERT_EQ(it->second, entt::resolve<clazz_t>());
|
||||
|
||||
bool found = false;
|
||||
|
||||
for(auto curr: entt::resolve()) {
|
||||
found = found || curr.second == entt::resolve<double>();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(found);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Functionalities) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<clazz_t>();
|
||||
|
||||
ASSERT_TRUE(type);
|
||||
ASSERT_NE(type, entt::meta_type{});
|
||||
ASSERT_EQ(type.id(), "clazz"_hs);
|
||||
ASSERT_EQ(type.info(), entt::type_id<clazz_t>());
|
||||
|
||||
for(auto curr: type.prop()) {
|
||||
ASSERT_EQ(curr.first, static_cast<entt::id_type>(property_t::value));
|
||||
ASSERT_EQ(curr.second.value(), 42);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(type.prop(static_cast<entt::id_type>(property_t::key_only)));
|
||||
ASSERT_FALSE(type.prop("property"_hs));
|
||||
|
||||
auto prop = type.prop(static_cast<entt::id_type>(property_t::value));
|
||||
|
||||
ASSERT_TRUE(prop);
|
||||
ASSERT_EQ(prop.value(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, SizeOf) {
|
||||
ASSERT_EQ(entt::resolve<void>().size_of(), 0u);
|
||||
ASSERT_EQ(entt::resolve<int>().size_of(), sizeof(int));
|
||||
ASSERT_EQ(entt::resolve<int[]>().size_of(), 0u);
|
||||
ASSERT_EQ(entt::resolve<int[3]>().size_of(), sizeof(int[3]));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Traits) {
|
||||
ASSERT_TRUE(entt::resolve<bool>().is_arithmetic());
|
||||
ASSERT_TRUE(entt::resolve<double>().is_arithmetic());
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().is_arithmetic());
|
||||
|
||||
ASSERT_TRUE(entt::resolve<int>().is_integral());
|
||||
ASSERT_FALSE(entt::resolve<double>().is_integral());
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().is_integral());
|
||||
|
||||
ASSERT_TRUE(entt::resolve<long>().is_signed());
|
||||
ASSERT_FALSE(entt::resolve<unsigned int>().is_signed());
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().is_signed());
|
||||
|
||||
ASSERT_TRUE(entt::resolve<int[5]>().is_array());
|
||||
ASSERT_TRUE(entt::resolve<int[5][3]>().is_array());
|
||||
ASSERT_FALSE(entt::resolve<int>().is_array());
|
||||
|
||||
ASSERT_TRUE(entt::resolve<property_t>().is_enum());
|
||||
ASSERT_FALSE(entt::resolve<char>().is_enum());
|
||||
|
||||
ASSERT_TRUE(entt::resolve<derived_t>().is_class());
|
||||
ASSERT_FALSE(entt::resolve<double>().is_class());
|
||||
|
||||
ASSERT_TRUE(entt::resolve<int *>().is_pointer());
|
||||
ASSERT_FALSE(entt::resolve<int>().is_pointer());
|
||||
|
||||
ASSERT_TRUE(entt::resolve<int *>().is_pointer_like());
|
||||
ASSERT_TRUE(entt::resolve<std::shared_ptr<int>>().is_pointer_like());
|
||||
ASSERT_FALSE(entt::resolve<int>().is_pointer_like());
|
||||
|
||||
ASSERT_FALSE((entt::resolve<int>().is_sequence_container()));
|
||||
ASSERT_TRUE(entt::resolve<std::vector<int>>().is_sequence_container());
|
||||
ASSERT_FALSE((entt::resolve<std::map<int, char>>().is_sequence_container()));
|
||||
|
||||
ASSERT_FALSE((entt::resolve<int>().is_associative_container()));
|
||||
ASSERT_TRUE((entt::resolve<std::map<int, char>>().is_associative_container()));
|
||||
ASSERT_FALSE(entt::resolve<std::vector<int>>().is_associative_container());
|
||||
}
|
||||
|
||||
TEST_F(MetaType, RemovePointer) {
|
||||
ASSERT_EQ(entt::resolve<void *>().remove_pointer(), entt::resolve<void>());
|
||||
ASSERT_EQ(entt::resolve<char **>().remove_pointer(), entt::resolve<char *>());
|
||||
ASSERT_EQ(entt::resolve<int (*)(char, double)>().remove_pointer(), entt::resolve<int(char, double)>());
|
||||
ASSERT_EQ(entt::resolve<derived_t>().remove_pointer(), entt::resolve<derived_t>());
|
||||
}
|
||||
|
||||
TEST_F(MetaType, TemplateInfo) {
|
||||
ASSERT_FALSE(entt::resolve<int>().is_template_specialization());
|
||||
ASSERT_EQ(entt::resolve<int>().template_arity(), 0u);
|
||||
ASSERT_EQ(entt::resolve<int>().template_type(), entt::meta_type{});
|
||||
ASSERT_EQ(entt::resolve<int>().template_arg(0u), entt::meta_type{});
|
||||
|
||||
ASSERT_TRUE(entt::resolve<std::shared_ptr<int>>().is_template_specialization());
|
||||
ASSERT_EQ(entt::resolve<std::shared_ptr<int>>().template_arity(), 1u);
|
||||
ASSERT_EQ(entt::resolve<std::shared_ptr<int>>().template_type(), entt::resolve<entt::meta_class_template_tag<std::shared_ptr>>());
|
||||
ASSERT_EQ(entt::resolve<std::shared_ptr<int>>().template_arg(0u), entt::resolve<int>());
|
||||
ASSERT_EQ(entt::resolve<std::shared_ptr<int>>().template_arg(1u), entt::meta_type{});
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Base) {
|
||||
using namespace entt::literals;
|
||||
auto type = entt::resolve<derived_t>();
|
||||
|
||||
ASSERT_NE(type.base().cbegin(), type.base().cend());
|
||||
|
||||
for(auto curr: type.base()) {
|
||||
ASSERT_EQ(curr.first, entt::type_id<base_t>().hash());
|
||||
ASSERT_EQ(curr.second, entt::resolve<base_t>());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Ctor) {
|
||||
derived_t derived;
|
||||
base_t &base = derived;
|
||||
auto type = entt::resolve<clazz_t>();
|
||||
|
||||
ASSERT_TRUE((type.construct(entt::forward_as_meta(derived), 42)));
|
||||
ASSERT_TRUE((type.construct(entt::forward_as_meta(base), 42)));
|
||||
|
||||
// use the implicitly generated default constructor
|
||||
auto any = type.construct();
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<clazz_t>());
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Data) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<clazz_t>();
|
||||
int counter{};
|
||||
|
||||
for([[maybe_unused]] auto curr: type.data()) {
|
||||
++counter;
|
||||
}
|
||||
|
||||
ASSERT_EQ(counter, 1);
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
|
||||
type = entt::resolve<void>();
|
||||
|
||||
ASSERT_TRUE(type);
|
||||
ASSERT_EQ(type.data().cbegin(), type.data().cend());
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Func) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<clazz_t>();
|
||||
clazz_t instance{};
|
||||
int counter{};
|
||||
|
||||
for([[maybe_unused]] auto curr: type.func()) {
|
||||
++counter;
|
||||
}
|
||||
|
||||
ASSERT_EQ(counter, 2);
|
||||
ASSERT_TRUE(type.func("member"_hs));
|
||||
ASSERT_TRUE(type.func("func"_hs));
|
||||
ASSERT_TRUE(type.func("member"_hs).invoke(instance));
|
||||
ASSERT_TRUE(type.func("func"_hs).invoke({}));
|
||||
|
||||
type = entt::resolve<void>();
|
||||
|
||||
ASSERT_TRUE(type);
|
||||
ASSERT_EQ(type.func().cbegin(), type.func().cend());
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Invoke) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<clazz_t>();
|
||||
clazz_t instance{};
|
||||
|
||||
ASSERT_TRUE(type.invoke("member"_hs, instance));
|
||||
ASSERT_FALSE(type.invoke("rebmem"_hs, {}));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, InvokeFromBase) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<concrete_t>();
|
||||
concrete_t instance{};
|
||||
|
||||
ASSERT_TRUE(type.invoke("base_only"_hs, instance, 42));
|
||||
ASSERT_FALSE(type.invoke("ylno_esab"_hs, {}, 'c'));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, OverloadedFunc) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const auto type = entt::resolve<overloaded_func_t>();
|
||||
overloaded_func_t instance{};
|
||||
entt::meta_any res{};
|
||||
|
||||
ASSERT_TRUE(type.func("f"_hs));
|
||||
ASSERT_TRUE(type.func("e"_hs));
|
||||
ASSERT_TRUE(type.func("g"_hs));
|
||||
|
||||
res = type.invoke("f"_hs, instance, base_t{}, 1, 2);
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_EQ(overloaded_func_t::value, 1);
|
||||
ASSERT_NE(res.try_cast<int>(), nullptr);
|
||||
ASSERT_EQ(res.cast<int>(), 4);
|
||||
|
||||
res = type.invoke("f"_hs, instance, 3, 4);
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_EQ(overloaded_func_t::value, 3);
|
||||
ASSERT_NE(res.try_cast<int>(), nullptr);
|
||||
ASSERT_EQ(res.cast<int>(), 16);
|
||||
|
||||
res = type.invoke("f"_hs, instance, 5);
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_EQ(overloaded_func_t::value, 3);
|
||||
ASSERT_NE(res.try_cast<int>(), nullptr);
|
||||
ASSERT_EQ(res.cast<int>(), 50);
|
||||
|
||||
res = type.invoke("f"_hs, std::as_const(instance), 5);
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_EQ(overloaded_func_t::value, 3);
|
||||
ASSERT_NE(res.try_cast<int>(), nullptr);
|
||||
ASSERT_EQ(res.cast<int>(), 25);
|
||||
|
||||
res = type.invoke("f"_hs, instance, 6, 7.f);
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_EQ(overloaded_func_t::value, 6);
|
||||
ASSERT_NE(res.try_cast<float>(), nullptr);
|
||||
ASSERT_EQ(res.cast<float>(), 14.f);
|
||||
|
||||
res = type.invoke("f"_hs, instance, 8, 9.f);
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_EQ(overloaded_func_t::value, 8);
|
||||
ASSERT_NE(res.try_cast<float>(), nullptr);
|
||||
ASSERT_EQ(res.cast<float>(), 18.f);
|
||||
|
||||
// it fails as an ambiguous call
|
||||
ASSERT_FALSE(type.invoke("f"_hs, instance, 8, 9.));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Construct) {
|
||||
auto any = entt::resolve<clazz_t>().construct(base_t{}, 42);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz_t>().value, 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ConstructNoArgs) {
|
||||
// this should work, no other tests required
|
||||
auto any = entt::resolve<clazz_t>().construct();
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ConstructMetaAnyArgs) {
|
||||
auto any = entt::resolve<clazz_t>().construct(entt::meta_any{base_t{}}, entt::meta_any{42});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz_t>().value, 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ConstructInvalidArgs) {
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().construct('c', base_t{}));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, LessArgs) {
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().construct(base_t{}));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ConstructCastAndConvert) {
|
||||
auto any = entt::resolve<clazz_t>().construct(derived_t{}, clazz_t{derived_t{}, 42});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz_t>().value, 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ConstructArithmeticConversion) {
|
||||
auto any = entt::resolve<clazz_t>().construct(derived_t{}, clazz_t{derived_t{}, true});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz_t>().value, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, FromVoid) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_FALSE(entt::resolve<double>().from_void(static_cast<double *>(nullptr)));
|
||||
ASSERT_FALSE(entt::resolve<double>().from_void(static_cast<const double *>(nullptr)));
|
||||
|
||||
auto type = entt::resolve<double>();
|
||||
double value = 4.2;
|
||||
|
||||
ASSERT_FALSE(entt::resolve<void>().from_void(static_cast<void *>(&value)));
|
||||
ASSERT_FALSE(entt::resolve<void>().from_void(static_cast<const void *>(&value)));
|
||||
|
||||
auto as_void = type.from_void(static_cast<void *>(&value));
|
||||
auto as_const_void = type.from_void(static_cast<const void *>(&value));
|
||||
|
||||
ASSERT_TRUE(as_void);
|
||||
ASSERT_TRUE(as_const_void);
|
||||
|
||||
ASSERT_EQ(as_void.type(), entt::resolve<double>());
|
||||
ASSERT_NE(as_void.try_cast<double>(), nullptr);
|
||||
|
||||
ASSERT_EQ(as_const_void.type(), entt::resolve<double>());
|
||||
ASSERT_EQ(as_const_void.try_cast<double>(), nullptr);
|
||||
ASSERT_NE(as_const_void.try_cast<const double>(), nullptr);
|
||||
|
||||
value = 1.2;
|
||||
|
||||
ASSERT_EQ(as_void.cast<double>(), as_const_void.cast<double>());
|
||||
ASSERT_EQ(as_void.cast<double>(), 1.2);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Reset) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_TRUE(entt::resolve("clazz"_hs));
|
||||
ASSERT_EQ(entt::resolve<clazz_t>().id(), "clazz"_hs);
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().prop(static_cast<entt::id_type>(property_t::value)));
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().data("value"_hs));
|
||||
ASSERT_TRUE((entt::resolve<clazz_t>().construct(derived_t{}, clazz_t{})));
|
||||
// implicitly generated default constructor
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().construct());
|
||||
|
||||
entt::meta_reset("clazz"_hs);
|
||||
|
||||
ASSERT_FALSE(entt::resolve("clazz"_hs));
|
||||
ASSERT_NE(entt::resolve<clazz_t>().id(), "clazz"_hs);
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().prop(static_cast<entt::id_type>(property_t::value)));
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().data("value"_hs));
|
||||
ASSERT_FALSE((entt::resolve<clazz_t>().construct(derived_t{}, clazz_t{})));
|
||||
// implicitly generated default constructor is not cleared
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().construct());
|
||||
|
||||
entt::meta<clazz_t>().type("clazz"_hs);
|
||||
|
||||
ASSERT_TRUE(entt::resolve("clazz"_hs));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ResetLast) {
|
||||
auto id = (entt::resolve().cend() - 1u)->second.id();
|
||||
|
||||
ASSERT_TRUE(entt::resolve(id));
|
||||
|
||||
entt::meta_reset(id);
|
||||
|
||||
ASSERT_FALSE(entt::resolve(id));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ResetAll) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_NE(entt::resolve().begin(), entt::resolve().end());
|
||||
|
||||
ASSERT_TRUE(entt::resolve("clazz"_hs));
|
||||
ASSERT_TRUE(entt::resolve("overloaded_func"_hs));
|
||||
ASSERT_TRUE(entt::resolve("double"_hs));
|
||||
|
||||
entt::meta_reset();
|
||||
|
||||
ASSERT_FALSE(entt::resolve("clazz"_hs));
|
||||
ASSERT_FALSE(entt::resolve("overloaded_func"_hs));
|
||||
ASSERT_FALSE(entt::resolve("double"_hs));
|
||||
|
||||
ASSERT_EQ(entt::resolve().begin(), entt::resolve().end());
|
||||
}
|
||||
|
||||
TEST_F(MetaType, AbstractClass) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<abstract_t>();
|
||||
concrete_t instance;
|
||||
|
||||
ASSERT_EQ(type.info(), entt::type_id<abstract_t>());
|
||||
ASSERT_EQ(instance.base_t::value, 'c');
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
|
||||
type.func("func"_hs).invoke(instance, 42);
|
||||
|
||||
ASSERT_EQ(instance.base_t::value, 'c');
|
||||
ASSERT_EQ(instance.value, 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, EnumAndNamedConstants) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<property_t>();
|
||||
|
||||
ASSERT_TRUE(type.data("random"_hs));
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
|
||||
ASSERT_EQ(type.data("random"_hs).type(), type);
|
||||
ASSERT_EQ(type.data("value"_hs).type(), type);
|
||||
|
||||
ASSERT_FALSE(type.data("random"_hs).set({}, property_t::value));
|
||||
ASSERT_FALSE(type.data("value"_hs).set({}, property_t::random));
|
||||
|
||||
ASSERT_EQ(type.data("random"_hs).get({}).cast<property_t>(), property_t::random);
|
||||
ASSERT_EQ(type.data("value"_hs).get({}).cast<property_t>(), property_t::value);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ArithmeticTypeAndNamedConstants) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<unsigned int>();
|
||||
|
||||
ASSERT_TRUE(type.data("min"_hs));
|
||||
ASSERT_TRUE(type.data("max"_hs));
|
||||
|
||||
ASSERT_EQ(type.data("min"_hs).type(), type);
|
||||
ASSERT_EQ(type.data("max"_hs).type(), type);
|
||||
|
||||
ASSERT_FALSE(type.data("min"_hs).set({}, 100u));
|
||||
ASSERT_FALSE(type.data("max"_hs).set({}, 0u));
|
||||
|
||||
ASSERT_EQ(type.data("min"_hs).get({}).cast<unsigned int>(), 0u);
|
||||
ASSERT_EQ(type.data("max"_hs).get({}).cast<unsigned int>(), 100u);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Variables) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto p_data = entt::resolve<property_t>().data("var"_hs);
|
||||
auto d_data = entt::resolve("double"_hs).data("var"_hs);
|
||||
|
||||
property_t prop{property_t::key_only};
|
||||
double d = 3.;
|
||||
|
||||
p_data.set(prop, property_t::random);
|
||||
d_data.set(d, 42.);
|
||||
|
||||
ASSERT_EQ(p_data.get(prop).cast<property_t>(), property_t::random);
|
||||
ASSERT_EQ(d_data.get(d).cast<double>(), 42.);
|
||||
ASSERT_EQ(prop, property_t::random);
|
||||
ASSERT_EQ(d, 42.);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, PropertiesAndCornerCases) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<property_t>();
|
||||
|
||||
ASSERT_EQ(type.prop().cbegin(), type.prop().cend());
|
||||
|
||||
ASSERT_EQ(type.data("random"_hs).prop(static_cast<entt::id_type>(property_t::random)).value().cast<int>(), 0);
|
||||
ASSERT_EQ(type.data("random"_hs).prop(static_cast<entt::id_type>(property_t::value)).value().cast<int>(), 3);
|
||||
|
||||
ASSERT_EQ(type.data("value"_hs).prop(static_cast<entt::id_type>(property_t::random)).value().cast<bool>(), true);
|
||||
ASSERT_EQ(type.data("value"_hs).prop(static_cast<entt::id_type>(property_t::value)).value().cast<int>(), 0);
|
||||
ASSERT_TRUE(type.data("value"_hs).prop(static_cast<entt::id_type>(property_t::key_only)));
|
||||
ASSERT_FALSE(type.data("value"_hs).prop(static_cast<entt::id_type>(property_t::key_only)).value());
|
||||
|
||||
ASSERT_TRUE(type.data("key_only"_hs).prop(static_cast<entt::id_type>(property_t::key_only)));
|
||||
ASSERT_FALSE(type.data("key_only"_hs).prop(static_cast<entt::id_type>(property_t::key_only)).value());
|
||||
|
||||
ASSERT_EQ(type.data("list"_hs).prop(static_cast<entt::id_type>(property_t::random)).value().cast<bool>(), false);
|
||||
ASSERT_EQ(type.data("list"_hs).prop(static_cast<entt::id_type>(property_t::value)).value().cast<int>(), 0);
|
||||
ASSERT_TRUE(type.data("list"_hs).prop(static_cast<entt::id_type>(property_t::key_only)));
|
||||
ASSERT_FALSE(type.data("list"_hs).prop(static_cast<entt::id_type>(property_t::key_only)).value());
|
||||
|
||||
type = entt::resolve<void>();
|
||||
|
||||
ASSERT_EQ(type.prop().cbegin(), type.prop().cend());
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ResetAndReRegistrationAfterReset) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_FALSE(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()).value.empty());
|
||||
|
||||
entt::meta_reset<double>();
|
||||
entt::meta_reset<unsigned int>();
|
||||
entt::meta_reset<base_t>();
|
||||
entt::meta_reset<derived_t>();
|
||||
entt::meta_reset<abstract_t>();
|
||||
entt::meta_reset<concrete_t>();
|
||||
entt::meta_reset<overloaded_func_t>();
|
||||
entt::meta_reset<property_t>();
|
||||
entt::meta_reset<clazz_t>();
|
||||
|
||||
ASSERT_FALSE(entt::resolve("double"_hs));
|
||||
ASSERT_FALSE(entt::resolve("base"_hs));
|
||||
ASSERT_FALSE(entt::resolve("derived"_hs));
|
||||
ASSERT_FALSE(entt::resolve("clazz"_hs));
|
||||
|
||||
ASSERT_TRUE(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()).value.empty());
|
||||
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().prop(static_cast<entt::id_type>(property_t::value)));
|
||||
// implicitly generated default constructor is not cleared
|
||||
ASSERT_TRUE(entt::resolve<clazz_t>().construct());
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().data("value"_hs));
|
||||
ASSERT_FALSE(entt::resolve<clazz_t>().func("member"_hs));
|
||||
|
||||
entt::meta<double>().type("double"_hs);
|
||||
entt::meta_any any{42.};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(any.allow_cast<int>());
|
||||
ASSERT_TRUE(any.allow_cast<float>());
|
||||
|
||||
ASSERT_FALSE(entt::resolve("derived"_hs));
|
||||
ASSERT_TRUE(entt::resolve("double"_hs));
|
||||
|
||||
entt::meta<property_t>()
|
||||
.type("property"_hs)
|
||||
.data<property_t::random>("rand"_hs)
|
||||
.prop(static_cast<entt::id_type>(property_t::value), 42)
|
||||
.prop(static_cast<entt::id_type>(property_t::random), 3);
|
||||
|
||||
ASSERT_TRUE(entt::resolve<property_t>().data("rand"_hs).prop(static_cast<entt::id_type>(property_t::value)));
|
||||
ASSERT_TRUE(entt::resolve<property_t>().data("rand"_hs).prop(static_cast<entt::id_type>(property_t::random)));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ReRegistration) {
|
||||
using namespace entt::literals;
|
||||
|
||||
int count = 0;
|
||||
|
||||
for([[maybe_unused]] auto type: entt::resolve()) {
|
||||
++count;
|
||||
}
|
||||
|
||||
SetUp();
|
||||
|
||||
for([[maybe_unused]] auto type: entt::resolve()) {
|
||||
--count;
|
||||
}
|
||||
|
||||
ASSERT_EQ(count, 0);
|
||||
ASSERT_TRUE(entt::resolve("double"_hs));
|
||||
|
||||
entt::meta<double>().type("real"_hs);
|
||||
|
||||
ASSERT_FALSE(entt::resolve("double"_hs));
|
||||
ASSERT_TRUE(entt::resolve("real"_hs));
|
||||
ASSERT_TRUE(entt::resolve("real"_hs).data("var"_hs));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, NameCollision) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(entt::meta<clazz_t>().type("clazz"_hs));
|
||||
ASSERT_TRUE(entt::resolve("clazz"_hs));
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(entt::meta<clazz_t>().type("quux"_hs));
|
||||
ASSERT_FALSE(entt::resolve("clazz"_hs));
|
||||
ASSERT_TRUE(entt::resolve("quux"_hs));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaTypeDeathTest, NameCollision) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_DEATH(entt::meta<clazz_t>().type("abstract"_hs), "");
|
||||
}
|
268
test/entt/meta/meta_utility.cpp
Normal file
268
test/entt/meta/meta_utility.cpp
Normal file
@ -0,0 +1,268 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_traits.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include <entt/meta/utility.hpp>
|
||||
#include "../common/config.h"
|
||||
|
||||
struct clazz {
|
||||
void setter(int v) {
|
||||
member = v;
|
||||
}
|
||||
|
||||
int getter() const {
|
||||
return member;
|
||||
}
|
||||
|
||||
static void static_setter(clazz &instance, int v) {
|
||||
instance.member = v;
|
||||
}
|
||||
|
||||
static int static_getter(const clazz &instance) {
|
||||
return instance.member;
|
||||
}
|
||||
|
||||
static void reset_value() {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
static int get_value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
static clazz factory(int v) {
|
||||
clazz instance{};
|
||||
instance.member = v;
|
||||
return instance;
|
||||
}
|
||||
|
||||
int member{};
|
||||
const int cmember{};
|
||||
inline static int value{};
|
||||
inline static const int cvalue{};
|
||||
inline static int arr[3u]{};
|
||||
};
|
||||
|
||||
struct dummy {};
|
||||
|
||||
struct MetaUtility: ::testing::Test {
|
||||
void SetUp() override {
|
||||
clazz::value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
using MetaUtilityDeathTest = MetaUtility;
|
||||
|
||||
TEST_F(MetaUtility, MetaDispatch) {
|
||||
int value = 42;
|
||||
|
||||
auto as_void = entt::meta_dispatch<entt::as_void_t>(value);
|
||||
auto as_ref = entt::meta_dispatch<entt::as_ref_t>(value);
|
||||
auto as_cref = entt::meta_dispatch<entt::as_cref_t>(value);
|
||||
auto as_is = entt::meta_dispatch(value);
|
||||
|
||||
ASSERT_EQ(as_void.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(as_ref.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(as_cref.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(as_is.type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_NE(as_is.try_cast<int>(), nullptr);
|
||||
ASSERT_NE(as_ref.try_cast<int>(), nullptr);
|
||||
ASSERT_EQ(as_cref.try_cast<int>(), nullptr);
|
||||
ASSERT_NE(as_cref.try_cast<const int>(), nullptr);
|
||||
|
||||
ASSERT_EQ(as_is.cast<int>(), 42);
|
||||
ASSERT_EQ(as_ref.cast<int>(), 42);
|
||||
ASSERT_EQ(as_cref.cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaDispatchMetaAny) {
|
||||
entt::meta_any any{42};
|
||||
|
||||
auto from_any = entt::meta_dispatch(any);
|
||||
auto from_const_any = entt::meta_dispatch(std::as_const(any));
|
||||
|
||||
ASSERT_EQ(from_any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(from_const_any.type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_NE(from_any.try_cast<int>(), nullptr);
|
||||
ASSERT_NE(from_const_any.try_cast<int>(), nullptr);
|
||||
|
||||
ASSERT_EQ(from_any.cast<int>(), 42);
|
||||
ASSERT_EQ(from_const_any.cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaDispatchMetaAnyAsRef) {
|
||||
entt::meta_any any{42};
|
||||
|
||||
auto from_any = entt::meta_dispatch(any.as_ref());
|
||||
auto from_const_any = entt::meta_dispatch(std::as_const(any).as_ref());
|
||||
|
||||
ASSERT_EQ(from_any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(from_const_any.type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_NE(from_any.try_cast<int>(), nullptr);
|
||||
ASSERT_EQ(from_const_any.try_cast<int>(), nullptr);
|
||||
ASSERT_NE(from_const_any.try_cast<const int>(), nullptr);
|
||||
|
||||
ASSERT_EQ(from_any.cast<int>(), 42);
|
||||
ASSERT_EQ(from_const_any.cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaArg) {
|
||||
ASSERT_EQ((entt::meta_arg<entt::type_list<int, char>>(0u)), entt::resolve<int>());
|
||||
ASSERT_EQ((entt::meta_arg<entt::type_list<int, char>>(1u)), entt::resolve<char>());
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaUtilityDeathTest, MetaArg) {
|
||||
ASSERT_DEATH([[maybe_unused]] auto type = entt::meta_arg<entt::type_list<>>(0u), "");
|
||||
ASSERT_DEATH([[maybe_unused]] auto type = entt::meta_arg<entt::type_list<int>>(3u), "");
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaSetter) {
|
||||
const int invalid{};
|
||||
clazz instance{};
|
||||
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::static_setter>(instance, instance)));
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::static_setter>(std::as_const(instance), 42)));
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::static_setter>(invalid, 42)));
|
||||
ASSERT_TRUE((entt::meta_setter<clazz, &clazz::static_setter>(instance, 42)));
|
||||
ASSERT_EQ(instance.member, 42);
|
||||
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::setter>(instance, instance)));
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::setter>(std::as_const(instance), 3)));
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::setter>(invalid, 3)));
|
||||
ASSERT_TRUE((entt::meta_setter<clazz, &clazz::setter>(instance, 3)));
|
||||
ASSERT_EQ(instance.member, 3);
|
||||
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::member>(instance, instance)));
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::member>(invalid, 99)));
|
||||
ASSERT_TRUE((entt::meta_setter<clazz, &clazz::member>(instance, 99)));
|
||||
ASSERT_EQ(instance.member, 99);
|
||||
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::cmember>(instance, 99)));
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::cmember>(invalid, 99)));
|
||||
ASSERT_EQ(instance.cmember, 0);
|
||||
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::value>(instance, instance)));
|
||||
ASSERT_TRUE((entt::meta_setter<clazz, &clazz::value>(invalid, 1)));
|
||||
ASSERT_TRUE((entt::meta_setter<clazz, &clazz::value>(instance, 2)));
|
||||
ASSERT_EQ(clazz::value, 2);
|
||||
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::cvalue>(instance, 1)));
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::cvalue>(invalid, 1)));
|
||||
ASSERT_EQ(clazz::cvalue, 0);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaGetter) {
|
||||
const int invalid{};
|
||||
clazz instance{};
|
||||
|
||||
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::static_getter>(invalid)));
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::static_getter>(instance)).cast<int>(), 0);
|
||||
|
||||
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::getter>(invalid)));
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::getter>(instance)).cast<int>(), 0);
|
||||
|
||||
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::member>(invalid)));
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::member>(instance)).cast<int>(), 0);
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::member>(std::as_const(instance))).cast<int>(), 0);
|
||||
|
||||
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::cmember>(invalid)));
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::cmember>(instance)).cast<int>(), 0);
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::cmember>(std::as_const(instance))).cast<int>(), 0);
|
||||
|
||||
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::arr>(invalid)));
|
||||
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::arr>(instance)));
|
||||
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::value>(invalid)).cast<int>(), 0);
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::value>(instance)).cast<int>(), 0);
|
||||
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::cvalue>(invalid)).cast<int>(), 0);
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::cvalue>(instance)).cast<int>(), 0);
|
||||
|
||||
ASSERT_EQ((entt::meta_getter<clazz, 42>(invalid)).cast<int>(), 42);
|
||||
ASSERT_EQ((entt::meta_getter<clazz, 42>(instance)).cast<int>(), 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaInvokeWithCandidate) {
|
||||
entt::meta_any args[2u]{clazz{}, 42};
|
||||
args[0u].cast<clazz &>().value = 99;
|
||||
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz>({}, &clazz::setter, nullptr)));
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz>({}, &clazz::getter, nullptr)));
|
||||
|
||||
ASSERT_TRUE((entt::meta_invoke<clazz>(args[0u], &clazz::setter, args + 1u)));
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz>(args[0u], &clazz::setter, args)));
|
||||
ASSERT_EQ((entt::meta_invoke<clazz>(args[0u], &clazz::getter, nullptr)).cast<int>(), 42);
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz>(args[1u], &clazz::getter, nullptr)));
|
||||
|
||||
ASSERT_EQ((entt::meta_invoke<clazz>({}, &clazz::get_value, nullptr)).cast<int>(), 99);
|
||||
ASSERT_TRUE((entt::meta_invoke<clazz>({}, &clazz::reset_value, nullptr)));
|
||||
ASSERT_EQ(args[0u].cast<clazz &>().value, 0);
|
||||
|
||||
const auto setter = [](int &value) { value = 3; };
|
||||
const auto getter = [](int value) { return value * 2; };
|
||||
|
||||
ASSERT_TRUE(entt::meta_invoke<dummy>({}, setter, args + 1u));
|
||||
ASSERT_EQ(entt::meta_invoke<dummy>({}, getter, args + 1u).cast<int>(), 6);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaInvoke) {
|
||||
entt::meta_any args[2u]{clazz{}, 42};
|
||||
args[0u].cast<clazz &>().value = 99;
|
||||
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::setter>({}, nullptr)));
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::getter>({}, nullptr)));
|
||||
|
||||
ASSERT_TRUE((entt::meta_invoke<clazz, &clazz::setter>(args[0u], args + 1u)));
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::setter>(args[0u], args)));
|
||||
ASSERT_EQ((entt::meta_invoke<clazz, &clazz::getter>(args[0u], nullptr)).cast<int>(), 42);
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::getter>(args[1u], nullptr)));
|
||||
|
||||
ASSERT_EQ((entt::meta_invoke<clazz, &clazz::get_value>({}, nullptr)).cast<int>(), 99);
|
||||
ASSERT_TRUE((entt::meta_invoke<clazz, &clazz::reset_value>({}, nullptr)));
|
||||
ASSERT_EQ(args[0u].cast<clazz &>().value, 0);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaConstructArgsOnly) {
|
||||
entt::meta_any args[2u]{clazz{}, 42};
|
||||
const auto any = entt::meta_construct<clazz, int>(args + 1u);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE((entt::meta_construct<clazz, int>(args)));
|
||||
ASSERT_EQ(any.cast<const clazz &>().member, 42);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaConstructWithCandidate) {
|
||||
entt::meta_any args[2u]{clazz{}, 42};
|
||||
const auto any = entt::meta_construct<clazz>(&clazz::factory, args + 1u);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE((entt::meta_construct<clazz>(&clazz::factory, args)));
|
||||
ASSERT_EQ(any.cast<const clazz &>().member, 42);
|
||||
|
||||
ASSERT_EQ(args[0u].cast<const clazz &>().member, 0);
|
||||
ASSERT_TRUE((entt::meta_construct<clazz>(&clazz::static_setter, args)));
|
||||
ASSERT_EQ(args[0u].cast<const clazz &>().member, 42);
|
||||
|
||||
const auto setter = [](int &value) { value = 3; };
|
||||
const auto builder = [](int value) { return value * 2; };
|
||||
|
||||
ASSERT_TRUE(entt::meta_construct<dummy>(setter, args + 1u));
|
||||
ASSERT_EQ(entt::meta_construct<dummy>(builder, args + 1u).cast<int>(), 6);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaConstruct) {
|
||||
entt::meta_any args[2u]{clazz{}, 42};
|
||||
const auto any = entt::meta_construct<clazz, &clazz::factory>(args + 1u);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE((entt::meta_construct<clazz, &clazz::factory>(args)));
|
||||
ASSERT_EQ(any.cast<const clazz &>().member, 42);
|
||||
|
||||
ASSERT_EQ(args[0u].cast<const clazz &>().member, 0);
|
||||
ASSERT_TRUE((entt::meta_construct<clazz, &clazz::static_setter>(args)));
|
||||
ASSERT_EQ(args[0u].cast<const clazz &>().member, 42);
|
||||
}
|
417
test/entt/poly/poly.cpp
Normal file
417
test/entt/poly/poly.cpp
Normal file
@ -0,0 +1,417 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/core/type_traits.hpp>
|
||||
#include <entt/poly/poly.hpp>
|
||||
#include "../common/config.h"
|
||||
|
||||
template<typename Base>
|
||||
struct common_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 entt::poly_call<4>(*this, v);
|
||||
}
|
||||
|
||||
int rand() const {
|
||||
return entt::poly_call<5>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct common_members {
|
||||
static void decr(Type &self) {
|
||||
self.set(self.get() - 1);
|
||||
}
|
||||
|
||||
static double mul(const Type &self, double v) {
|
||||
return v * self.get();
|
||||
}
|
||||
};
|
||||
|
||||
static int absolutely_random() {
|
||||
return 42;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
using common_impl = entt::value_list<
|
||||
&Type::incr,
|
||||
&Type::set,
|
||||
&Type::get,
|
||||
&common_members<Type>::decr,
|
||||
&common_members<Type>::mul,
|
||||
&absolutely_random>;
|
||||
|
||||
struct Deduced
|
||||
: entt::type_list<> {
|
||||
template<typename Base>
|
||||
using type = common_type<Base>;
|
||||
|
||||
template<typename Type>
|
||||
using members = common_members<Type>;
|
||||
|
||||
template<typename Type>
|
||||
using impl = common_impl<Type>;
|
||||
};
|
||||
|
||||
struct Defined
|
||||
: entt::type_list<
|
||||
void(),
|
||||
void(int),
|
||||
int() const,
|
||||
void(),
|
||||
int(int) const,
|
||||
int() const> {
|
||||
template<typename Base>
|
||||
using type = common_type<Base>;
|
||||
|
||||
template<typename Type>
|
||||
using members = common_members<Type>;
|
||||
|
||||
template<typename Type>
|
||||
using impl = common_impl<Type>;
|
||||
};
|
||||
|
||||
struct DeducedEmbedded
|
||||
: entt::type_list<> {
|
||||
template<typename Base>
|
||||
struct type: Base {
|
||||
int get() const {
|
||||
return entt::poly_call<0>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using impl = entt::value_list<&Type::get>;
|
||||
};
|
||||
|
||||
struct DefinedEmbedded
|
||||
: entt::type_list<int()> {
|
||||
template<typename Base>
|
||||
struct type: Base {
|
||||
// non-const get on purpose
|
||||
int get() {
|
||||
return entt::poly_call<0>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using impl = entt::value_list<&Type::get>;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
impl() = default;
|
||||
|
||||
impl(int v)
|
||||
: value{v} {}
|
||||
|
||||
void incr() {
|
||||
++value;
|
||||
}
|
||||
|
||||
void set(int v) {
|
||||
value = v;
|
||||
}
|
||||
|
||||
int get() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
int value{};
|
||||
};
|
||||
|
||||
struct alignas(64u) over_aligned: impl {};
|
||||
|
||||
template<typename Type>
|
||||
struct Poly: testing::Test {
|
||||
template<std::size_t... Args>
|
||||
using type = entt::basic_poly<Type, Args...>;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using PolyDeathTest = Poly<Type>;
|
||||
|
||||
using PolyTypes = ::testing::Types<Deduced, Defined>;
|
||||
|
||||
TYPED_TEST_SUITE(Poly, PolyTypes, );
|
||||
TYPED_TEST_SUITE(PolyDeathTest, PolyTypes, );
|
||||
|
||||
template<typename Type>
|
||||
struct PolyEmbedded: testing::Test {
|
||||
using type = entt::basic_poly<Type>;
|
||||
};
|
||||
|
||||
using PolyEmbeddedTypes = ::testing::Types<DeducedEmbedded, DefinedEmbedded>;
|
||||
|
||||
TYPED_TEST_SUITE(PolyEmbedded, PolyEmbeddedTypes, );
|
||||
|
||||
TYPED_TEST(Poly, Functionalities) {
|
||||
using poly_type = typename TestFixture::template type<>;
|
||||
|
||||
impl instance{};
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
ASSERT_EQ(value->rand(), 42);
|
||||
|
||||
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(std::as_const(empty)->get(), 3);
|
||||
|
||||
poly_type 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);
|
||||
|
||||
poly_type null{};
|
||||
std::swap(empty, null);
|
||||
|
||||
ASSERT_FALSE(empty);
|
||||
|
||||
poly_type copy = in_place;
|
||||
|
||||
ASSERT_TRUE(copy);
|
||||
ASSERT_EQ(copy->get(), 3);
|
||||
|
||||
poly_type 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>());
|
||||
}
|
||||
|
||||
TYPED_TEST(PolyEmbedded, EmbeddedVtable) {
|
||||
using poly_type = typename TestFixture::type;
|
||||
|
||||
poly_type 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(poly->get(), 0);
|
||||
|
||||
ptr->value = 2;
|
||||
|
||||
ASSERT_EQ(poly->get(), 2);
|
||||
}
|
||||
|
||||
TYPED_TEST(Poly, Owned) {
|
||||
using poly_type = typename TestFixture::template type<>;
|
||||
|
||||
poly_type 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(std::as_const(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);
|
||||
}
|
||||
|
||||
TYPED_TEST(Poly, Reference) {
|
||||
using poly_type = typename TestFixture::template type<>;
|
||||
|
||||
impl instance{};
|
||||
poly_type 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(std::as_const(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);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(Poly, ConstReference) {
|
||||
using poly_type = typename TestFixture::template type<>;
|
||||
|
||||
impl instance{};
|
||||
poly_type 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(std::as_const(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);
|
||||
}
|
||||
|
||||
TYPED_TEST(PolyDeathTest, ConstReference) {
|
||||
using poly_type = typename TestFixture::template type<>;
|
||||
|
||||
impl instance{};
|
||||
poly_type poly{std::in_place_type<const impl &>, instance};
|
||||
|
||||
ASSERT_TRUE(poly);
|
||||
ASSERT_DEATH(poly->set(1), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(Poly, AsRef) {
|
||||
using poly_type = typename TestFixture::template type<>;
|
||||
|
||||
poly_type 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);
|
||||
}
|
||||
|
||||
TYPED_TEST(Poly, SBOVsZeroedSBOSize) {
|
||||
using poly_type = typename TestFixture::template type<>;
|
||||
using zeroed_type = typename TestFixture::template type<0u>;
|
||||
|
||||
poly_type poly{impl{}};
|
||||
const auto broken = poly.data();
|
||||
poly_type other = std::move(poly);
|
||||
|
||||
ASSERT_NE(broken, other.data());
|
||||
|
||||
zeroed_type dyn{impl{}};
|
||||
const auto valid = dyn.data();
|
||||
zeroed_type same = std::move(dyn);
|
||||
|
||||
ASSERT_EQ(valid, same.data());
|
||||
|
||||
// everything works as expected
|
||||
same->incr();
|
||||
|
||||
ASSERT_EQ(same->get(), 1);
|
||||
}
|
||||
|
||||
TYPED_TEST(Poly, SboAlignment) {
|
||||
static constexpr auto alignment = alignof(over_aligned);
|
||||
typename TestFixture::template type<alignment, alignment> sbo[2]{over_aligned{}, over_aligned{}};
|
||||
const auto *data = sbo[0].data();
|
||||
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[0u].data()) % alignment) == 0u);
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[1u].data()) % alignment) == 0u);
|
||||
|
||||
std::swap(sbo[0], sbo[1]);
|
||||
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[0u].data()) % alignment) == 0u);
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[1u].data()) % alignment) == 0u);
|
||||
|
||||
ASSERT_NE(data, sbo[1].data());
|
||||
}
|
||||
|
||||
TYPED_TEST(Poly, NoSboAlignment) {
|
||||
static constexpr auto alignment = alignof(over_aligned);
|
||||
typename TestFixture::template type<alignment> nosbo[2]{over_aligned{}, over_aligned{}};
|
||||
const auto *data = nosbo[0].data();
|
||||
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[0u].data()) % alignment) == 0u);
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[1u].data()) % alignment) == 0u);
|
||||
|
||||
std::swap(nosbo[0], nosbo[1]);
|
||||
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[0u].data()) % alignment) == 0u);
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[1u].data()) % alignment) == 0u);
|
||||
|
||||
ASSERT_EQ(data, nosbo[1].data());
|
||||
}
|
269
test/entt/process/process.cpp
Normal file
269
test/entt/process/process.cpp
Normal file
@ -0,0 +1,269 @@
|
||||
#include <cstdint>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/process/process.hpp>
|
||||
|
||||
struct fake_delta {};
|
||||
|
||||
template<typename Delta>
|
||||
struct fake_process: entt::process<fake_process<Delta>, Delta> {
|
||||
using process_type = entt::process<fake_process<Delta>, Delta>;
|
||||
using delta_type = typename process_type::delta_type;
|
||||
|
||||
fake_process()
|
||||
: init_invoked{false},
|
||||
update_invoked{false},
|
||||
succeeded_invoked{false},
|
||||
failed_invoked{false},
|
||||
aborted_invoked{false} {}
|
||||
|
||||
void succeed() noexcept {
|
||||
process_type::succeed();
|
||||
}
|
||||
|
||||
void fail() noexcept {
|
||||
process_type::fail();
|
||||
}
|
||||
|
||||
void pause() noexcept {
|
||||
process_type::pause();
|
||||
}
|
||||
|
||||
void unpause() noexcept {
|
||||
process_type::unpause();
|
||||
}
|
||||
|
||||
void init() {
|
||||
init_invoked = true;
|
||||
}
|
||||
|
||||
void succeeded() {
|
||||
succeeded_invoked = true;
|
||||
}
|
||||
|
||||
void failed() {
|
||||
failed_invoked = true;
|
||||
}
|
||||
|
||||
void aborted() {
|
||||
aborted_invoked = true;
|
||||
}
|
||||
|
||||
void update(typename entt::process<fake_process<Delta>, Delta>::delta_type, void *data) {
|
||||
if(data) {
|
||||
(*static_cast<int *>(data))++;
|
||||
}
|
||||
|
||||
update_invoked = true;
|
||||
}
|
||||
|
||||
bool init_invoked;
|
||||
bool update_invoked;
|
||||
bool succeeded_invoked;
|
||||
bool failed_invoked;
|
||||
bool aborted_invoked;
|
||||
};
|
||||
|
||||
TEST(Process, Basics) {
|
||||
fake_process<int> process{};
|
||||
|
||||
ASSERT_FALSE(process.alive());
|
||||
ASSERT_FALSE(process.finished());
|
||||
ASSERT_FALSE(process.paused());
|
||||
ASSERT_FALSE(process.rejected());
|
||||
|
||||
process.succeed();
|
||||
process.fail();
|
||||
process.abort();
|
||||
process.pause();
|
||||
process.unpause();
|
||||
|
||||
ASSERT_FALSE(process.alive());
|
||||
ASSERT_FALSE(process.finished());
|
||||
ASSERT_FALSE(process.paused());
|
||||
ASSERT_FALSE(process.rejected());
|
||||
|
||||
process.tick(0);
|
||||
|
||||
ASSERT_TRUE(process.alive());
|
||||
ASSERT_FALSE(process.finished());
|
||||
ASSERT_FALSE(process.paused());
|
||||
ASSERT_FALSE(process.rejected());
|
||||
|
||||
process.pause();
|
||||
|
||||
ASSERT_TRUE(process.alive());
|
||||
ASSERT_FALSE(process.finished());
|
||||
ASSERT_TRUE(process.paused());
|
||||
ASSERT_FALSE(process.rejected());
|
||||
|
||||
process.unpause();
|
||||
|
||||
ASSERT_TRUE(process.alive());
|
||||
ASSERT_FALSE(process.finished());
|
||||
ASSERT_FALSE(process.paused());
|
||||
ASSERT_FALSE(process.rejected());
|
||||
|
||||
process.fail();
|
||||
|
||||
ASSERT_FALSE(process.alive());
|
||||
ASSERT_FALSE(process.finished());
|
||||
ASSERT_FALSE(process.paused());
|
||||
ASSERT_FALSE(process.rejected());
|
||||
|
||||
process.tick(0);
|
||||
|
||||
ASSERT_FALSE(process.alive());
|
||||
ASSERT_FALSE(process.finished());
|
||||
ASSERT_FALSE(process.paused());
|
||||
ASSERT_TRUE(process.rejected());
|
||||
}
|
||||
|
||||
TEST(Process, Succeeded) {
|
||||
fake_process<fake_delta> process{};
|
||||
|
||||
process.tick({});
|
||||
process.tick({});
|
||||
process.succeed();
|
||||
process.tick({});
|
||||
|
||||
ASSERT_FALSE(process.alive());
|
||||
ASSERT_TRUE(process.finished());
|
||||
ASSERT_FALSE(process.paused());
|
||||
ASSERT_FALSE(process.rejected());
|
||||
|
||||
ASSERT_TRUE(process.init_invoked);
|
||||
ASSERT_TRUE(process.update_invoked);
|
||||
ASSERT_TRUE(process.succeeded_invoked);
|
||||
ASSERT_FALSE(process.failed_invoked);
|
||||
ASSERT_FALSE(process.aborted_invoked);
|
||||
}
|
||||
|
||||
TEST(Process, Fail) {
|
||||
fake_process<int> process{};
|
||||
|
||||
process.tick(0);
|
||||
process.tick(0);
|
||||
process.fail();
|
||||
process.tick(0);
|
||||
|
||||
ASSERT_FALSE(process.alive());
|
||||
ASSERT_FALSE(process.finished());
|
||||
ASSERT_FALSE(process.paused());
|
||||
ASSERT_TRUE(process.rejected());
|
||||
|
||||
ASSERT_TRUE(process.init_invoked);
|
||||
ASSERT_TRUE(process.update_invoked);
|
||||
ASSERT_FALSE(process.succeeded_invoked);
|
||||
ASSERT_TRUE(process.failed_invoked);
|
||||
ASSERT_FALSE(process.aborted_invoked);
|
||||
}
|
||||
|
||||
TEST(Process, Data) {
|
||||
fake_process<fake_delta> process{};
|
||||
int value = 0;
|
||||
|
||||
process.tick({});
|
||||
process.tick({}, &value);
|
||||
process.succeed();
|
||||
process.tick({}, &value);
|
||||
|
||||
ASSERT_FALSE(process.alive());
|
||||
ASSERT_TRUE(process.finished());
|
||||
ASSERT_FALSE(process.paused());
|
||||
ASSERT_FALSE(process.rejected());
|
||||
|
||||
ASSERT_EQ(value, 1);
|
||||
ASSERT_TRUE(process.init_invoked);
|
||||
ASSERT_TRUE(process.update_invoked);
|
||||
ASSERT_TRUE(process.succeeded_invoked);
|
||||
ASSERT_FALSE(process.failed_invoked);
|
||||
ASSERT_FALSE(process.aborted_invoked);
|
||||
}
|
||||
|
||||
TEST(Process, AbortNextTick) {
|
||||
fake_process<int> process{};
|
||||
|
||||
process.tick(0);
|
||||
process.abort();
|
||||
process.tick(0);
|
||||
|
||||
ASSERT_FALSE(process.alive());
|
||||
ASSERT_FALSE(process.finished());
|
||||
ASSERT_FALSE(process.paused());
|
||||
ASSERT_TRUE(process.rejected());
|
||||
|
||||
ASSERT_TRUE(process.init_invoked);
|
||||
ASSERT_FALSE(process.update_invoked);
|
||||
ASSERT_FALSE(process.succeeded_invoked);
|
||||
ASSERT_FALSE(process.failed_invoked);
|
||||
ASSERT_TRUE(process.aborted_invoked);
|
||||
}
|
||||
|
||||
TEST(Process, AbortImmediately) {
|
||||
fake_process<fake_delta> process{};
|
||||
|
||||
process.tick({});
|
||||
process.abort(true);
|
||||
|
||||
ASSERT_FALSE(process.alive());
|
||||
ASSERT_FALSE(process.finished());
|
||||
ASSERT_FALSE(process.paused());
|
||||
ASSERT_TRUE(process.rejected());
|
||||
|
||||
ASSERT_TRUE(process.init_invoked);
|
||||
ASSERT_FALSE(process.update_invoked);
|
||||
ASSERT_FALSE(process.succeeded_invoked);
|
||||
ASSERT_FALSE(process.failed_invoked);
|
||||
ASSERT_TRUE(process.aborted_invoked);
|
||||
}
|
||||
|
||||
TEST(ProcessAdaptor, Resolved) {
|
||||
bool updated = false;
|
||||
auto lambda = [&updated](std::uint64_t, void *, auto resolve, auto) {
|
||||
ASSERT_FALSE(updated);
|
||||
updated = true;
|
||||
resolve();
|
||||
};
|
||||
|
||||
auto process = entt::process_adaptor<decltype(lambda), std::uint64_t>{lambda};
|
||||
|
||||
process.tick(0);
|
||||
process.tick(0);
|
||||
|
||||
ASSERT_TRUE(process.finished());
|
||||
ASSERT_TRUE(updated);
|
||||
}
|
||||
|
||||
TEST(ProcessAdaptor, Rejected) {
|
||||
bool updated = false;
|
||||
auto lambda = [&updated](std::uint64_t, void *, auto, auto rejected) {
|
||||
ASSERT_FALSE(updated);
|
||||
updated = true;
|
||||
rejected();
|
||||
};
|
||||
|
||||
auto process = entt::process_adaptor<decltype(lambda), std::uint64_t>{lambda};
|
||||
|
||||
process.tick(0);
|
||||
process.tick(0);
|
||||
|
||||
ASSERT_TRUE(process.rejected());
|
||||
ASSERT_TRUE(updated);
|
||||
}
|
||||
|
||||
TEST(ProcessAdaptor, Data) {
|
||||
int value = 0;
|
||||
|
||||
auto lambda = [](std::uint64_t, void *data, auto resolve, auto) {
|
||||
*static_cast<int *>(data) = 42;
|
||||
resolve();
|
||||
};
|
||||
|
||||
auto process = entt::process_adaptor<decltype(lambda), std::uint64_t>{lambda};
|
||||
|
||||
process.tick(0);
|
||||
process.tick(0, &value);
|
||||
|
||||
ASSERT_TRUE(process.finished());
|
||||
ASSERT_EQ(value, 42);
|
||||
}
|
154
test/entt/process/scheduler.cpp
Normal file
154
test/entt/process/scheduler.cpp
Normal file
@ -0,0 +1,154 @@
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/process/process.hpp>
|
||||
#include <entt/process/scheduler.hpp>
|
||||
|
||||
struct foo_process: entt::process<foo_process, int> {
|
||||
foo_process(std::function<void()> upd, std::function<void()> abort)
|
||||
: on_update{upd}, on_aborted{abort} {}
|
||||
|
||||
void update(delta_type, void *) {
|
||||
on_update();
|
||||
}
|
||||
|
||||
void aborted() {
|
||||
on_aborted();
|
||||
}
|
||||
|
||||
std::function<void()> on_update;
|
||||
std::function<void()> on_aborted;
|
||||
};
|
||||
|
||||
struct succeeded_process: entt::process<succeeded_process, int> {
|
||||
void update(delta_type, void *) {
|
||||
++invoked;
|
||||
succeed();
|
||||
}
|
||||
|
||||
static inline unsigned int invoked;
|
||||
};
|
||||
|
||||
struct failed_process: entt::process<failed_process, int> {
|
||||
void update(delta_type, void *) {
|
||||
++invoked;
|
||||
fail();
|
||||
}
|
||||
|
||||
static inline unsigned int invoked;
|
||||
};
|
||||
|
||||
struct Scheduler: ::testing::Test {
|
||||
void SetUp() override {
|
||||
succeeded_process::invoked = 0u;
|
||||
failed_process::invoked = 0u;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Scheduler, Functionalities) {
|
||||
entt::scheduler<int> scheduler{};
|
||||
|
||||
bool updated = false;
|
||||
bool aborted = false;
|
||||
|
||||
ASSERT_EQ(scheduler.size(), 0u);
|
||||
ASSERT_TRUE(scheduler.empty());
|
||||
|
||||
scheduler.attach<foo_process>(
|
||||
[&updated]() { updated = true; },
|
||||
[&aborted]() { aborted = true; });
|
||||
|
||||
ASSERT_NE(scheduler.size(), 0u);
|
||||
ASSERT_FALSE(scheduler.empty());
|
||||
|
||||
scheduler.update(0);
|
||||
scheduler.abort(true);
|
||||
|
||||
ASSERT_TRUE(updated);
|
||||
ASSERT_TRUE(aborted);
|
||||
|
||||
ASSERT_NE(scheduler.size(), 0u);
|
||||
ASSERT_FALSE(scheduler.empty());
|
||||
|
||||
scheduler.clear();
|
||||
|
||||
ASSERT_EQ(scheduler.size(), 0u);
|
||||
ASSERT_TRUE(scheduler.empty());
|
||||
}
|
||||
|
||||
TEST_F(Scheduler, Then) {
|
||||
entt::scheduler<int> scheduler;
|
||||
|
||||
// failing process with successor
|
||||
scheduler.attach<succeeded_process>()
|
||||
.then<succeeded_process>()
|
||||
.then<failed_process>()
|
||||
.then<succeeded_process>();
|
||||
|
||||
// failing process without successor
|
||||
scheduler.attach<succeeded_process>()
|
||||
.then<succeeded_process>()
|
||||
.then<failed_process>();
|
||||
|
||||
// non-failing process
|
||||
scheduler.attach<succeeded_process>()
|
||||
.then<succeeded_process>();
|
||||
|
||||
ASSERT_EQ(succeeded_process::invoked, 0u);
|
||||
ASSERT_EQ(failed_process::invoked, 0u);
|
||||
|
||||
while(!scheduler.empty()) {
|
||||
scheduler.update(0);
|
||||
}
|
||||
|
||||
ASSERT_EQ(succeeded_process::invoked, 6u);
|
||||
ASSERT_EQ(failed_process::invoked, 2u);
|
||||
}
|
||||
|
||||
TEST_F(Scheduler, Functor) {
|
||||
entt::scheduler<int> scheduler;
|
||||
|
||||
bool first_functor = false;
|
||||
bool second_functor = false;
|
||||
|
||||
auto attach = [&first_functor](auto, void *, auto resolve, auto) {
|
||||
ASSERT_FALSE(first_functor);
|
||||
first_functor = true;
|
||||
resolve();
|
||||
};
|
||||
|
||||
auto then = [&second_functor](auto, void *, auto, auto reject) {
|
||||
ASSERT_FALSE(second_functor);
|
||||
second_functor = true;
|
||||
reject();
|
||||
};
|
||||
|
||||
scheduler.attach(std::move(attach)).then(std::move(then)).then([](auto...) { FAIL(); });
|
||||
|
||||
while(!scheduler.empty()) {
|
||||
scheduler.update(0);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(first_functor);
|
||||
ASSERT_TRUE(second_functor);
|
||||
ASSERT_TRUE(scheduler.empty());
|
||||
}
|
||||
|
||||
TEST_F(Scheduler, SpawningProcess) {
|
||||
entt::scheduler<int> scheduler;
|
||||
|
||||
scheduler.attach([&scheduler](auto, void *, auto resolve, auto) {
|
||||
scheduler.attach<succeeded_process>().then<failed_process>();
|
||||
resolve();
|
||||
});
|
||||
|
||||
ASSERT_EQ(succeeded_process::invoked, 0u);
|
||||
ASSERT_EQ(failed_process::invoked, 0u);
|
||||
|
||||
while(!scheduler.empty()) {
|
||||
scheduler.update(0);
|
||||
}
|
||||
|
||||
ASSERT_EQ(succeeded_process::invoked, 1u);
|
||||
ASSERT_EQ(failed_process::invoked, 1u);
|
||||
}
|
144
test/entt/resource/resource.cpp
Normal file
144
test/entt/resource/resource.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/resource/resource.hpp>
|
||||
|
||||
struct base {
|
||||
virtual ~base() = default;
|
||||
|
||||
virtual const entt::type_info &type() const noexcept {
|
||||
return entt::type_id<base>();
|
||||
}
|
||||
};
|
||||
|
||||
struct derived: base {
|
||||
const entt::type_info &type() const noexcept override {
|
||||
return entt::type_id<derived>();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type, typename Other>
|
||||
entt::resource<Type> dynamic_resource_cast(const entt::resource<Other> &other) {
|
||||
if(other->type() == entt::type_id<Type>()) {
|
||||
return entt::resource<Type>{other, static_cast<Type &>(*other)};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
TEST(Resource, Functionalities) {
|
||||
entt::resource<derived> resource{};
|
||||
|
||||
ASSERT_FALSE(resource);
|
||||
ASSERT_EQ(resource.operator->(), nullptr);
|
||||
ASSERT_EQ(resource.handle().use_count(), 0l);
|
||||
|
||||
const auto value = std::make_shared<derived>();
|
||||
entt::resource<derived> other{value};
|
||||
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_EQ(other.operator->(), value.get());
|
||||
ASSERT_EQ(&static_cast<derived &>(other), value.get());
|
||||
ASSERT_EQ(&*other, value.get());
|
||||
ASSERT_EQ(other.handle().use_count(), 2l);
|
||||
|
||||
entt::resource<derived> copy{resource};
|
||||
entt::resource<derived> move{std::move(other)};
|
||||
|
||||
ASSERT_FALSE(copy);
|
||||
ASSERT_TRUE(move);
|
||||
|
||||
copy = std::move(move);
|
||||
move = copy;
|
||||
|
||||
ASSERT_TRUE(copy);
|
||||
ASSERT_TRUE(move);
|
||||
ASSERT_EQ(copy, move);
|
||||
}
|
||||
|
||||
TEST(Resource, DerivedToBase) {
|
||||
entt::resource<derived> resource{std::make_shared<derived>()};
|
||||
entt::resource<base> other{resource};
|
||||
entt::resource<const base> cother{resource};
|
||||
|
||||
ASSERT_TRUE(resource);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_TRUE(cother);
|
||||
ASSERT_EQ(resource, other);
|
||||
ASSERT_EQ(other, cother);
|
||||
|
||||
other = resource;
|
||||
cother = resource;
|
||||
|
||||
ASSERT_EQ(resource, other);
|
||||
ASSERT_EQ(other, cother);
|
||||
}
|
||||
|
||||
TEST(Resource, ConstNonConstAndAllInBetween) {
|
||||
entt::resource<derived> resource{std::make_shared<derived>()};
|
||||
entt::resource<derived> other{resource};
|
||||
|
||||
static_assert(std::is_same_v<decltype(*resource), derived &>);
|
||||
static_assert(std::is_same_v<decltype(*entt::resource<const derived>{other}), const derived &>);
|
||||
static_assert(std::is_same_v<decltype(*std::as_const(resource)), derived &>);
|
||||
|
||||
entt::resource<const derived> copy{resource};
|
||||
entt::resource<const derived> move{std::move(other)};
|
||||
|
||||
ASSERT_TRUE(resource);
|
||||
ASSERT_FALSE(other);
|
||||
|
||||
ASSERT_TRUE(copy);
|
||||
ASSERT_EQ(copy, resource);
|
||||
ASSERT_NE(copy, entt::resource<derived>{});
|
||||
ASSERT_EQ(copy.handle().use_count(), 3u);
|
||||
|
||||
ASSERT_TRUE(move);
|
||||
ASSERT_EQ(move, resource);
|
||||
ASSERT_NE(move, entt::resource<derived>{});
|
||||
ASSERT_EQ(move.handle().use_count(), 3u);
|
||||
|
||||
copy = resource;
|
||||
move = std::move(resource);
|
||||
|
||||
ASSERT_FALSE(resource);
|
||||
ASSERT_FALSE(other);
|
||||
|
||||
ASSERT_TRUE(copy);
|
||||
ASSERT_TRUE(move);
|
||||
ASSERT_EQ(copy.handle().use_count(), 2u);
|
||||
}
|
||||
|
||||
TEST(Resource, DynamicResourceHandleCast) {
|
||||
entt::resource<derived> resource{std::make_shared<derived>()};
|
||||
entt::resource<const base> other = resource;
|
||||
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_EQ(resource.handle().use_count(), 2u);
|
||||
ASSERT_EQ(resource, other);
|
||||
|
||||
entt::resource<const derived> cast = dynamic_resource_cast<const derived>(other);
|
||||
|
||||
ASSERT_TRUE(cast);
|
||||
ASSERT_EQ(resource.handle().use_count(), 3u);
|
||||
ASSERT_EQ(resource, cast);
|
||||
|
||||
other = entt::resource<base>{std::make_shared<base>()};
|
||||
cast = dynamic_resource_cast<const derived>(other);
|
||||
|
||||
ASSERT_FALSE(cast);
|
||||
ASSERT_EQ(resource.handle().use_count(), 1u);
|
||||
}
|
||||
|
||||
TEST(Resource, Comparison) {
|
||||
entt::resource<derived> resource{std::make_shared<derived>()};
|
||||
entt::resource<const base> other = resource;
|
||||
|
||||
ASSERT_TRUE(resource == other);
|
||||
ASSERT_FALSE(resource != other);
|
||||
|
||||
ASSERT_FALSE(resource < other);
|
||||
ASSERT_FALSE(resource > other);
|
||||
|
||||
ASSERT_TRUE(resource <= other);
|
||||
ASSERT_TRUE(resource >= other);
|
||||
}
|
428
test/entt/resource/resource_cache.cpp
Normal file
428
test/entt/resource/resource_cache.cpp
Normal file
@ -0,0 +1,428 @@
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/resource/cache.hpp>
|
||||
#include <entt/resource/loader.hpp>
|
||||
#include "../common/throwing_allocator.hpp"
|
||||
|
||||
struct broken_tag {};
|
||||
struct with_callback {};
|
||||
|
||||
template<typename Type>
|
||||
struct loader {
|
||||
using result_type = std::shared_ptr<Type>;
|
||||
|
||||
template<typename... Args>
|
||||
result_type operator()(Args &&...args) const {
|
||||
return std::make_shared<Type>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
result_type operator()(with_callback, Func &&func) const {
|
||||
return std::forward<Func>(func)();
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
result_type operator()(broken_tag, Args &&...) const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
TEST(ResourceCache, Functionalities) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<int> cache;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE([[maybe_unused]] auto alloc = cache.get_allocator());
|
||||
|
||||
ASSERT_TRUE(cache.empty());
|
||||
ASSERT_EQ(cache.size(), 0u);
|
||||
|
||||
ASSERT_EQ(cache.begin(), cache.end());
|
||||
ASSERT_EQ(std::as_const(cache).begin(), std::as_const(cache).end());
|
||||
ASSERT_EQ(cache.cbegin(), cache.cend());
|
||||
|
||||
ASSERT_FALSE(cache.contains("resource"_hs));
|
||||
|
||||
cache.load("resource"_hs, 42);
|
||||
|
||||
ASSERT_FALSE(cache.empty());
|
||||
ASSERT_EQ(cache.size(), 1u);
|
||||
|
||||
ASSERT_NE(cache.begin(), cache.end());
|
||||
ASSERT_NE(std::as_const(cache).begin(), std::as_const(cache).end());
|
||||
ASSERT_NE(cache.cbegin(), cache.cend());
|
||||
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
|
||||
cache.clear();
|
||||
|
||||
ASSERT_TRUE(cache.empty());
|
||||
ASSERT_EQ(cache.size(), 0u);
|
||||
|
||||
ASSERT_EQ(cache.begin(), cache.end());
|
||||
ASSERT_EQ(std::as_const(cache).begin(), std::as_const(cache).end());
|
||||
ASSERT_EQ(cache.cbegin(), cache.cend());
|
||||
|
||||
ASSERT_FALSE(cache.contains("resource"_hs));
|
||||
}
|
||||
|
||||
TEST(ResourceCache, Constructors) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<int> cache;
|
||||
|
||||
cache = entt::resource_cache<int>{std::allocator<int>{}};
|
||||
cache = entt::resource_cache<int>{entt::resource_loader<int>{}, std::allocator<float>{}};
|
||||
|
||||
cache.load("resource"_hs, 42u);
|
||||
|
||||
entt::resource_cache<int> temp{cache, cache.get_allocator()};
|
||||
entt::resource_cache<int> other{std::move(temp), cache.get_allocator()};
|
||||
|
||||
ASSERT_EQ(cache.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, Copy) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<std::size_t> cache;
|
||||
cache.load("resource"_hs, 42u);
|
||||
|
||||
entt::resource_cache<std::size_t> other{cache};
|
||||
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
ASSERT_TRUE(other.contains("resource"_hs));
|
||||
|
||||
cache.load("foo"_hs, 99u);
|
||||
cache.load("bar"_hs, 77u);
|
||||
other.load("quux"_hs, 0u);
|
||||
other = cache;
|
||||
|
||||
ASSERT_TRUE(other.contains("resource"_hs));
|
||||
ASSERT_TRUE(other.contains("foo"_hs));
|
||||
ASSERT_TRUE(other.contains("bar"_hs));
|
||||
ASSERT_FALSE(other.contains("quux"_hs));
|
||||
|
||||
ASSERT_EQ(other["resource"_hs], 42u);
|
||||
ASSERT_EQ(other["foo"_hs], 99u);
|
||||
ASSERT_EQ(other["bar"_hs], 77u);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, Move) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<std::size_t> cache;
|
||||
cache.load("resource"_hs, 42u);
|
||||
|
||||
entt::resource_cache<std::size_t> other{std::move(cache)};
|
||||
|
||||
ASSERT_EQ(cache.size(), 0u);
|
||||
ASSERT_TRUE(other.contains("resource"_hs));
|
||||
|
||||
cache = other;
|
||||
cache.load("foo"_hs, 99u);
|
||||
cache.load("bar"_hs, 77u);
|
||||
other.load("quux"_hs, 0u);
|
||||
other = std::move(cache);
|
||||
|
||||
ASSERT_EQ(cache.size(), 0u);
|
||||
ASSERT_TRUE(other.contains("resource"_hs));
|
||||
ASSERT_TRUE(other.contains("foo"_hs));
|
||||
ASSERT_TRUE(other.contains("bar"_hs));
|
||||
ASSERT_FALSE(other.contains("quux"_hs));
|
||||
|
||||
ASSERT_EQ(other["resource"_hs], 42u);
|
||||
ASSERT_EQ(other["foo"_hs], 99u);
|
||||
ASSERT_EQ(other["bar"_hs], 77u);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, Iterator) {
|
||||
using namespace entt::literals;
|
||||
|
||||
using iterator = typename entt::resource_cache<int>::iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, std::pair<entt::id_type, entt::resource<int>>>);
|
||||
static_assert(std::is_same_v<iterator::pointer, entt::input_iterator_pointer<std::pair<entt::id_type, entt::resource<int>>>>);
|
||||
static_assert(std::is_same_v<iterator::reference, std::pair<entt::id_type, entt::resource<int>>>);
|
||||
|
||||
entt::resource_cache<int> cache;
|
||||
cache.load("resource"_hs, 42);
|
||||
|
||||
iterator end{cache.begin()};
|
||||
iterator begin{};
|
||||
begin = cache.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, cache.begin());
|
||||
ASSERT_EQ(end, cache.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(begin++, cache.begin());
|
||||
ASSERT_EQ(begin--, cache.end());
|
||||
|
||||
ASSERT_EQ(begin + 1, cache.end());
|
||||
ASSERT_EQ(end - 1, cache.begin());
|
||||
|
||||
ASSERT_EQ(++begin, cache.end());
|
||||
ASSERT_EQ(--begin, cache.begin());
|
||||
|
||||
ASSERT_EQ(begin += 1, cache.end());
|
||||
ASSERT_EQ(begin -= 1, cache.begin());
|
||||
|
||||
ASSERT_EQ(begin + (end - begin), cache.end());
|
||||
ASSERT_EQ(begin - (begin - end), cache.end());
|
||||
|
||||
ASSERT_EQ(end - (end - begin), cache.begin());
|
||||
ASSERT_EQ(end + (begin - end), cache.begin());
|
||||
|
||||
ASSERT_EQ(begin[0u].first, cache.begin()->first);
|
||||
ASSERT_EQ(begin[0u].second, (*cache.begin()).second);
|
||||
|
||||
ASSERT_LT(begin, end);
|
||||
ASSERT_LE(begin, cache.begin());
|
||||
|
||||
ASSERT_GT(end, begin);
|
||||
ASSERT_GE(end, cache.end());
|
||||
|
||||
cache.load("other"_hs, 3);
|
||||
begin = cache.begin();
|
||||
|
||||
ASSERT_EQ(begin[0u].first, "resource"_hs);
|
||||
ASSERT_EQ(begin[1u].second, 3);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, ConstIterator) {
|
||||
using namespace entt::literals;
|
||||
|
||||
using iterator = typename entt::resource_cache<int>::const_iterator;
|
||||
|
||||
static_assert(std::is_same_v<iterator::value_type, std::pair<entt::id_type, entt::resource<const int>>>);
|
||||
static_assert(std::is_same_v<iterator::pointer, entt::input_iterator_pointer<std::pair<entt::id_type, entt::resource<const int>>>>);
|
||||
static_assert(std::is_same_v<iterator::reference, std::pair<entt::id_type, entt::resource<const int>>>);
|
||||
|
||||
entt::resource_cache<int> cache;
|
||||
cache.load("resource"_hs, 42);
|
||||
|
||||
iterator cend{cache.cbegin()};
|
||||
iterator cbegin{};
|
||||
cbegin = cache.cend();
|
||||
std::swap(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin, cache.cbegin());
|
||||
ASSERT_EQ(cend, cache.cend());
|
||||
ASSERT_NE(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin++, cache.cbegin());
|
||||
ASSERT_EQ(cbegin--, cache.cend());
|
||||
|
||||
ASSERT_EQ(cbegin + 1, cache.cend());
|
||||
ASSERT_EQ(cend - 1, cache.cbegin());
|
||||
|
||||
ASSERT_EQ(++cbegin, cache.cend());
|
||||
ASSERT_EQ(--cbegin, cache.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin += 1, cache.cend());
|
||||
ASSERT_EQ(cbegin -= 1, cache.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin + (cend - cbegin), cache.cend());
|
||||
ASSERT_EQ(cbegin - (cbegin - cend), cache.cend());
|
||||
|
||||
ASSERT_EQ(cend - (cend - cbegin), cache.cbegin());
|
||||
ASSERT_EQ(cend + (cbegin - cend), cache.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin[0u].first, cache.cbegin()->first);
|
||||
ASSERT_EQ(cbegin[0u].second, (*cache.cbegin()).second);
|
||||
|
||||
ASSERT_LT(cbegin, cend);
|
||||
ASSERT_LE(cbegin, cache.cbegin());
|
||||
|
||||
ASSERT_GT(cend, cbegin);
|
||||
ASSERT_GE(cend, cache.cend());
|
||||
|
||||
cache.load("other"_hs, 3);
|
||||
cbegin = cache.cbegin();
|
||||
|
||||
ASSERT_EQ(cbegin[0u].first, "resource"_hs);
|
||||
ASSERT_EQ(cbegin[1u].second, 3);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, IteratorConversion) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<int> cache;
|
||||
cache.load("resource"_hs, 42);
|
||||
|
||||
typename entt::resource_cache<int>::iterator it = cache.begin();
|
||||
typename entt::resource_cache<int>::const_iterator cit = it;
|
||||
|
||||
static_assert(std::is_same_v<decltype(*it), std::pair<entt::id_type, entt::resource<int>>>);
|
||||
static_assert(std::is_same_v<decltype(*cit), std::pair<entt::id_type, entt::resource<const int>>>);
|
||||
|
||||
ASSERT_EQ(it->first, "resource"_hs);
|
||||
ASSERT_EQ((*it).second, 42);
|
||||
ASSERT_EQ(it->first, cit->first);
|
||||
ASSERT_EQ((*it).second, (*cit).second);
|
||||
|
||||
ASSERT_EQ(it - cit, 0);
|
||||
ASSERT_EQ(cit - it, 0);
|
||||
ASSERT_LE(it, cit);
|
||||
ASSERT_LE(cit, it);
|
||||
ASSERT_GE(it, cit);
|
||||
ASSERT_GE(cit, it);
|
||||
ASSERT_EQ(it, cit);
|
||||
ASSERT_NE(++cit, it);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, Load) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<int> cache;
|
||||
typename entt::resource_cache<int>::iterator it;
|
||||
bool result;
|
||||
|
||||
ASSERT_TRUE(cache.empty());
|
||||
ASSERT_EQ(cache.size(), 0u);
|
||||
ASSERT_EQ(cache["resource"_hs], entt::resource<int>{});
|
||||
ASSERT_EQ(std::as_const(cache)["resource"_hs], entt::resource<const int>{});
|
||||
ASSERT_FALSE(cache.contains("resource"_hs));
|
||||
|
||||
std::tie(it, result) = cache.load("resource"_hs, 1);
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(cache.size(), 1u);
|
||||
ASSERT_EQ(it, --cache.end());
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
ASSERT_NE(cache["resource"_hs], entt::resource<int>{});
|
||||
ASSERT_NE(std::as_const(cache)["resource"_hs], entt::resource<const int>{});
|
||||
ASSERT_EQ(it->first, "resource"_hs);
|
||||
ASSERT_EQ(it->second, 1);
|
||||
|
||||
std::tie(it, result) = cache.load("resource"_hs, 2);
|
||||
|
||||
ASSERT_FALSE(result);
|
||||
ASSERT_EQ(cache.size(), 1u);
|
||||
ASSERT_EQ(it, --cache.end());
|
||||
ASSERT_EQ(it->second, 1);
|
||||
|
||||
std::tie(it, result) = cache.force_load("resource"_hs, 3);
|
||||
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_EQ(cache.size(), 1u);
|
||||
ASSERT_EQ(it, --cache.end());
|
||||
ASSERT_EQ(it->second, 3);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, Erase) {
|
||||
static constexpr std::size_t resource_count = 8u;
|
||||
entt::resource_cache<std::size_t> cache;
|
||||
|
||||
for(std::size_t next{}, last = resource_count + 1u; next < last; ++next) {
|
||||
cache.load(next, next);
|
||||
}
|
||||
|
||||
ASSERT_EQ(cache.size(), resource_count + 1u);
|
||||
|
||||
for(std::size_t next{}, last = resource_count + 1u; next < last; ++next) {
|
||||
ASSERT_TRUE(cache.contains(next));
|
||||
}
|
||||
|
||||
auto it = cache.erase(++cache.begin());
|
||||
it = cache.erase(it, it + 1);
|
||||
|
||||
ASSERT_EQ((--cache.end())->first, 6u);
|
||||
ASSERT_EQ(cache.erase(6u), 1u);
|
||||
ASSERT_EQ(cache.erase(6u), 0u);
|
||||
|
||||
ASSERT_EQ(cache.size(), resource_count + 1u - 3u);
|
||||
|
||||
ASSERT_EQ(it, ++cache.begin());
|
||||
ASSERT_EQ(it->first, 7u);
|
||||
ASSERT_EQ((--cache.end())->first, 5u);
|
||||
|
||||
for(std::size_t next{}, last = resource_count + 1u; next < last; ++next) {
|
||||
if(next == 1u || next == 8u || next == 6u) {
|
||||
ASSERT_FALSE(cache.contains(next));
|
||||
} else {
|
||||
ASSERT_TRUE(cache.contains(next));
|
||||
}
|
||||
}
|
||||
|
||||
cache.erase(cache.begin(), cache.end());
|
||||
|
||||
for(std::size_t next{}, last = resource_count + 1u; next < last; ++next) {
|
||||
ASSERT_FALSE(cache.contains(next));
|
||||
}
|
||||
|
||||
ASSERT_EQ(cache.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, Indexing) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<int> cache;
|
||||
|
||||
ASSERT_FALSE(cache.contains("resource"_hs));
|
||||
ASSERT_FALSE(cache["resource"_hs]);
|
||||
ASSERT_FALSE(std::as_const(cache)["resource"_hs]);
|
||||
|
||||
cache.load("resource"_hs, 99);
|
||||
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
ASSERT_EQ(cache[std::move("resource"_hs)], 99);
|
||||
ASSERT_EQ(std::as_const(cache)["resource"_hs], 99);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, LoaderDispatching) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<int, loader<int>> cache;
|
||||
cache.force_load("resource"_hs, 99);
|
||||
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
ASSERT_EQ(cache["resource"_hs], 99);
|
||||
|
||||
cache.force_load("resource"_hs, with_callback{}, []() { return std::make_shared<int>(42); });
|
||||
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
ASSERT_EQ(cache["resource"_hs], 42);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, BrokenLoader) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<int, loader<int>> cache;
|
||||
cache.load("resource"_hs, broken_tag{});
|
||||
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
ASSERT_FALSE(cache["resource"_hs]);
|
||||
|
||||
cache.force_load("resource"_hs, 42);
|
||||
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
ASSERT_TRUE(cache["resource"_hs]);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, ThrowingAllocator) {
|
||||
using namespace entt::literals;
|
||||
|
||||
using allocator = test::throwing_allocator<std::size_t>;
|
||||
using packed_allocator = test::throwing_allocator<entt::internal::dense_map_node<entt::id_type, std::shared_ptr<std::size_t>>>;
|
||||
using packed_exception = typename packed_allocator::exception_type;
|
||||
|
||||
entt::resource_cache<std::size_t, entt::resource_loader<std::size_t>, allocator> cache{};
|
||||
|
||||
packed_allocator::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW(cache.load("resource"_hs), packed_exception);
|
||||
ASSERT_FALSE(cache.contains("resource"_hs));
|
||||
|
||||
packed_allocator::trigger_on_allocate = true;
|
||||
|
||||
ASSERT_THROW(cache.force_load("resource"_hs), packed_exception);
|
||||
ASSERT_FALSE(cache.contains("resource"_hs));
|
||||
}
|
13
test/entt/resource/resource_loader.cpp
Normal file
13
test/entt/resource/resource_loader.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include <type_traits>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/resource/loader.hpp>
|
||||
|
||||
TEST(ResourceLoader, Functionalities) {
|
||||
using loader_type = entt::resource_loader<int>;
|
||||
const auto resource = loader_type{}(42);
|
||||
|
||||
static_assert(std::is_same_v<typename loader_type::result_type, std::shared_ptr<int>>);
|
||||
|
||||
ASSERT_TRUE(resource);
|
||||
ASSERT_EQ(*resource, 42);
|
||||
}
|
433
test/entt/signal/delegate.cpp
Normal file
433
test/entt/signal/delegate.cpp
Normal file
@ -0,0 +1,433 @@
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/signal/delegate.hpp>
|
||||
#include "../common/config.h"
|
||||
|
||||
int delegate_function(const int &i) {
|
||||
return i * i;
|
||||
}
|
||||
|
||||
int curried_by_ref(const int &i, int j) {
|
||||
return i + j;
|
||||
}
|
||||
|
||||
int curried_by_ptr(const int *i, int j) {
|
||||
return (*i) * j;
|
||||
}
|
||||
|
||||
int non_const_reference(int &i) {
|
||||
return i *= i;
|
||||
}
|
||||
|
||||
int move_only_type(std::unique_ptr<int> ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
struct delegate_functor {
|
||||
int operator()(int i) {
|
||||
return i + i;
|
||||
}
|
||||
|
||||
int identity(int i) const {
|
||||
return i;
|
||||
}
|
||||
|
||||
static const int static_value = 3;
|
||||
const int data_member = 42;
|
||||
};
|
||||
|
||||
struct const_nonconst_noexcept {
|
||||
void f() {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void g() noexcept {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void h() const {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void i() const noexcept {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
int u{};
|
||||
const int v{};
|
||||
mutable int cnt{0};
|
||||
};
|
||||
|
||||
TEST(Delegate, Functionalities) {
|
||||
entt::delegate<int(int)> ff_del;
|
||||
entt::delegate<int(int)> mf_del;
|
||||
entt::delegate<int(int)> lf_del;
|
||||
delegate_functor functor;
|
||||
|
||||
ASSERT_FALSE(ff_del);
|
||||
ASSERT_FALSE(mf_del);
|
||||
ASSERT_EQ(ff_del, mf_del);
|
||||
|
||||
ff_del.connect<&delegate_function>();
|
||||
mf_del.connect<&delegate_functor::operator()>(functor);
|
||||
lf_del.connect([](const void *ptr, int value) { return static_cast<const delegate_functor *>(ptr)->identity(value); }, &functor);
|
||||
|
||||
ASSERT_TRUE(ff_del);
|
||||
ASSERT_TRUE(mf_del);
|
||||
ASSERT_TRUE(lf_del);
|
||||
|
||||
ASSERT_EQ(ff_del(3), 9);
|
||||
ASSERT_EQ(mf_del(3), 6);
|
||||
ASSERT_EQ(lf_del(3), 3);
|
||||
|
||||
ff_del.reset();
|
||||
|
||||
ASSERT_FALSE(ff_del);
|
||||
|
||||
ASSERT_EQ(ff_del, entt::delegate<int(int)>{});
|
||||
ASSERT_NE(mf_del, entt::delegate<int(int)>{});
|
||||
ASSERT_NE(lf_del, entt::delegate<int(int)>{});
|
||||
|
||||
ASSERT_NE(ff_del, mf_del);
|
||||
ASSERT_NE(ff_del, lf_del);
|
||||
ASSERT_NE(mf_del, lf_del);
|
||||
|
||||
mf_del.reset();
|
||||
|
||||
ASSERT_FALSE(ff_del);
|
||||
ASSERT_FALSE(mf_del);
|
||||
ASSERT_TRUE(lf_del);
|
||||
|
||||
ASSERT_EQ(ff_del, entt::delegate<int(int)>{});
|
||||
ASSERT_EQ(mf_del, entt::delegate<int(int)>{});
|
||||
ASSERT_NE(lf_del, entt::delegate<int(int)>{});
|
||||
|
||||
ASSERT_EQ(ff_del, mf_del);
|
||||
ASSERT_NE(ff_del, lf_del);
|
||||
ASSERT_NE(mf_del, lf_del);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(DelegateDeathTest, InvokeEmpty) {
|
||||
entt::delegate<int(int)> del;
|
||||
|
||||
ASSERT_FALSE(del);
|
||||
ASSERT_DEATH(del(42), "");
|
||||
ASSERT_DEATH(std::as_const(del)(42), "");
|
||||
}
|
||||
|
||||
TEST(Delegate, DataMembers) {
|
||||
entt::delegate<double()> delegate;
|
||||
delegate_functor functor;
|
||||
|
||||
delegate.connect<&delegate_functor::data_member>(functor);
|
||||
|
||||
ASSERT_EQ(delegate(), 42);
|
||||
}
|
||||
|
||||
TEST(Delegate, Comparison) {
|
||||
entt::delegate<int(int)> lhs;
|
||||
entt::delegate<int(int)> rhs;
|
||||
delegate_functor functor;
|
||||
delegate_functor other;
|
||||
const int value = 0;
|
||||
|
||||
ASSERT_EQ(lhs, entt::delegate<int(int)>{});
|
||||
ASSERT_FALSE(lhs != rhs);
|
||||
ASSERT_TRUE(lhs == rhs);
|
||||
ASSERT_EQ(lhs, rhs);
|
||||
|
||||
lhs.connect<&delegate_function>();
|
||||
|
||||
ASSERT_EQ(lhs, entt::delegate<int(int)>{entt::connect_arg<&delegate_function>});
|
||||
ASSERT_TRUE(lhs != rhs);
|
||||
ASSERT_FALSE(lhs == rhs);
|
||||
ASSERT_NE(lhs, rhs);
|
||||
|
||||
rhs.connect<&delegate_function>();
|
||||
|
||||
ASSERT_EQ(rhs, entt::delegate<int(int)>{entt::connect_arg<&delegate_function>});
|
||||
ASSERT_FALSE(lhs != rhs);
|
||||
ASSERT_TRUE(lhs == rhs);
|
||||
ASSERT_EQ(lhs, rhs);
|
||||
|
||||
lhs.connect<&curried_by_ref>(value);
|
||||
|
||||
ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&curried_by_ref>, value}));
|
||||
ASSERT_TRUE(lhs != rhs);
|
||||
ASSERT_FALSE(lhs == rhs);
|
||||
ASSERT_NE(lhs, rhs);
|
||||
|
||||
rhs.connect<&curried_by_ref>(value);
|
||||
|
||||
ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&curried_by_ref>, value}));
|
||||
ASSERT_FALSE(lhs != rhs);
|
||||
ASSERT_TRUE(lhs == rhs);
|
||||
ASSERT_EQ(lhs, rhs);
|
||||
|
||||
lhs.connect<&curried_by_ptr>(&value);
|
||||
|
||||
ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&curried_by_ptr>, &value}));
|
||||
ASSERT_TRUE(lhs != rhs);
|
||||
ASSERT_FALSE(lhs == rhs);
|
||||
ASSERT_NE(lhs, rhs);
|
||||
|
||||
rhs.connect<&curried_by_ptr>(&value);
|
||||
|
||||
ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&curried_by_ptr>, &value}));
|
||||
ASSERT_FALSE(lhs != rhs);
|
||||
ASSERT_TRUE(lhs == rhs);
|
||||
ASSERT_EQ(lhs, rhs);
|
||||
|
||||
lhs.connect<&delegate_functor::operator()>(functor);
|
||||
|
||||
ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&delegate_functor::operator()>, functor}));
|
||||
ASSERT_TRUE(lhs != rhs);
|
||||
ASSERT_FALSE(lhs == rhs);
|
||||
ASSERT_NE(lhs, rhs);
|
||||
|
||||
rhs.connect<&delegate_functor::operator()>(functor);
|
||||
|
||||
ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&delegate_functor::operator()>, functor}));
|
||||
ASSERT_FALSE(lhs != rhs);
|
||||
ASSERT_TRUE(lhs == rhs);
|
||||
ASSERT_EQ(lhs, rhs);
|
||||
|
||||
lhs.connect<&delegate_functor::operator()>(other);
|
||||
|
||||
ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&delegate_functor::operator()>, other}));
|
||||
ASSERT_NE(lhs.data(), rhs.data());
|
||||
ASSERT_TRUE(lhs != rhs);
|
||||
ASSERT_FALSE(lhs == rhs);
|
||||
ASSERT_NE(lhs, rhs);
|
||||
|
||||
lhs.connect([](const void *ptr, int val) { return static_cast<const delegate_functor *>(ptr)->identity(val) * val; }, &functor);
|
||||
|
||||
ASSERT_NE(lhs, (entt::delegate<int(int)>{[](const void *, int val) { return val + val; }, &functor}));
|
||||
ASSERT_TRUE(lhs != rhs);
|
||||
ASSERT_FALSE(lhs == rhs);
|
||||
ASSERT_NE(lhs, rhs);
|
||||
|
||||
rhs.connect([](const void *ptr, int val) { return static_cast<const delegate_functor *>(ptr)->identity(val) + val; }, &functor);
|
||||
|
||||
ASSERT_NE(rhs, (entt::delegate<int(int)>{[](const void *, int val) { return val * val; }, &functor}));
|
||||
ASSERT_TRUE(lhs != rhs);
|
||||
ASSERT_FALSE(lhs == rhs);
|
||||
ASSERT_NE(lhs, rhs);
|
||||
|
||||
lhs.reset();
|
||||
|
||||
ASSERT_EQ(lhs, (entt::delegate<int(int)>{}));
|
||||
ASSERT_TRUE(lhs != rhs);
|
||||
ASSERT_FALSE(lhs == rhs);
|
||||
ASSERT_NE(lhs, rhs);
|
||||
|
||||
rhs.reset();
|
||||
|
||||
ASSERT_EQ(rhs, (entt::delegate<int(int)>{}));
|
||||
ASSERT_FALSE(lhs != rhs);
|
||||
ASSERT_TRUE(lhs == rhs);
|
||||
ASSERT_EQ(lhs, rhs);
|
||||
}
|
||||
|
||||
TEST(Delegate, ConstNonConstNoExcept) {
|
||||
entt::delegate<void()> delegate;
|
||||
const_nonconst_noexcept functor;
|
||||
|
||||
delegate.connect<&const_nonconst_noexcept::f>(functor);
|
||||
delegate();
|
||||
|
||||
delegate.connect<&const_nonconst_noexcept::g>(functor);
|
||||
delegate();
|
||||
|
||||
delegate.connect<&const_nonconst_noexcept::h>(functor);
|
||||
delegate();
|
||||
|
||||
delegate.connect<&const_nonconst_noexcept::i>(functor);
|
||||
delegate();
|
||||
|
||||
ASSERT_EQ(functor.cnt, 4);
|
||||
}
|
||||
|
||||
TEST(Delegate, DeductionGuide) {
|
||||
const_nonconst_noexcept functor;
|
||||
int value = 0;
|
||||
|
||||
entt::delegate func{entt::connect_arg<&delegate_function>};
|
||||
entt::delegate curried_func_with_ref{entt::connect_arg<&curried_by_ref>, value};
|
||||
entt::delegate curried_func_with_const_ref{entt::connect_arg<&curried_by_ref>, std::as_const(value)};
|
||||
entt::delegate curried_func_with_ptr{entt::connect_arg<&curried_by_ptr>, &value};
|
||||
entt::delegate curried_func_with_const_ptr{entt::connect_arg<&curried_by_ptr>, &std::as_const(value)};
|
||||
entt::delegate member_func_f{entt::connect_arg<&const_nonconst_noexcept::f>, functor};
|
||||
entt::delegate member_func_g{entt::connect_arg<&const_nonconst_noexcept::g>, functor};
|
||||
entt::delegate member_func_h{entt::connect_arg<&const_nonconst_noexcept::h>, &functor};
|
||||
entt::delegate member_func_h_const{entt::connect_arg<&const_nonconst_noexcept::h>, &std::as_const(functor)};
|
||||
entt::delegate member_func_i{entt::connect_arg<&const_nonconst_noexcept::i>, functor};
|
||||
entt::delegate member_func_i_const{entt::connect_arg<&const_nonconst_noexcept::i>, std::as_const(functor)};
|
||||
entt::delegate data_member_u{entt::connect_arg<&const_nonconst_noexcept::u>, functor};
|
||||
entt::delegate data_member_v{entt::connect_arg<&const_nonconst_noexcept::v>, &functor};
|
||||
entt::delegate data_member_v_const{entt::connect_arg<&const_nonconst_noexcept::v>, &std::as_const(functor)};
|
||||
entt::delegate lambda{+[](const void *, int) { return 0; }};
|
||||
|
||||
static_assert(std::is_same_v<typename decltype(func)::type, int(const int &)>);
|
||||
static_assert(std::is_same_v<typename decltype(curried_func_with_ref)::type, int(int)>);
|
||||
static_assert(std::is_same_v<typename decltype(curried_func_with_const_ref)::type, int(int)>);
|
||||
static_assert(std::is_same_v<typename decltype(curried_func_with_ptr)::type, int(int)>);
|
||||
static_assert(std::is_same_v<typename decltype(curried_func_with_const_ptr)::type, int(int)>);
|
||||
static_assert(std::is_same_v<typename decltype(member_func_f)::type, void()>);
|
||||
static_assert(std::is_same_v<typename decltype(member_func_g)::type, void()>);
|
||||
static_assert(std::is_same_v<typename decltype(member_func_h)::type, void()>);
|
||||
static_assert(std::is_same_v<typename decltype(member_func_h_const)::type, void()>);
|
||||
static_assert(std::is_same_v<typename decltype(member_func_i)::type, void()>);
|
||||
static_assert(std::is_same_v<typename decltype(member_func_i_const)::type, void()>);
|
||||
static_assert(std::is_same_v<typename decltype(data_member_u)::type, int()>);
|
||||
static_assert(std::is_same_v<typename decltype(data_member_v)::type, const int()>);
|
||||
static_assert(std::is_same_v<typename decltype(data_member_v_const)::type, const int()>);
|
||||
static_assert(std::is_same_v<typename decltype(lambda)::type, int(int)>);
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_TRUE(curried_func_with_ref);
|
||||
ASSERT_TRUE(curried_func_with_const_ref);
|
||||
ASSERT_TRUE(curried_func_with_ptr);
|
||||
ASSERT_TRUE(curried_func_with_const_ptr);
|
||||
ASSERT_TRUE(member_func_f);
|
||||
ASSERT_TRUE(member_func_g);
|
||||
ASSERT_TRUE(member_func_h);
|
||||
ASSERT_TRUE(member_func_h_const);
|
||||
ASSERT_TRUE(member_func_i);
|
||||
ASSERT_TRUE(member_func_i_const);
|
||||
ASSERT_TRUE(data_member_u);
|
||||
ASSERT_TRUE(data_member_v);
|
||||
ASSERT_TRUE(data_member_v_const);
|
||||
ASSERT_TRUE(lambda);
|
||||
}
|
||||
|
||||
TEST(Delegate, ConstInstance) {
|
||||
entt::delegate<int(int)> delegate;
|
||||
const delegate_functor functor;
|
||||
|
||||
ASSERT_FALSE(delegate);
|
||||
|
||||
delegate.connect<&delegate_functor::identity>(functor);
|
||||
|
||||
ASSERT_TRUE(delegate);
|
||||
ASSERT_EQ(delegate(3), 3);
|
||||
|
||||
delegate.reset();
|
||||
|
||||
ASSERT_FALSE(delegate);
|
||||
ASSERT_EQ(delegate, entt::delegate<int(int)>{});
|
||||
}
|
||||
|
||||
TEST(Delegate, NonConstReference) {
|
||||
entt::delegate<int(int &)> delegate;
|
||||
delegate.connect<&non_const_reference>();
|
||||
int value = 3;
|
||||
|
||||
ASSERT_EQ(delegate(value), value);
|
||||
ASSERT_EQ(value, 9);
|
||||
}
|
||||
|
||||
TEST(Delegate, MoveOnlyType) {
|
||||
entt::delegate<int(std::unique_ptr<int>)> delegate;
|
||||
auto ptr = std::make_unique<int>(3);
|
||||
delegate.connect<&move_only_type>();
|
||||
|
||||
ASSERT_EQ(delegate(std::move(ptr)), 3);
|
||||
ASSERT_FALSE(ptr);
|
||||
}
|
||||
|
||||
TEST(Delegate, CurriedFunction) {
|
||||
entt::delegate<int(int)> delegate;
|
||||
const auto value = 3;
|
||||
|
||||
delegate.connect<&curried_by_ref>(value);
|
||||
|
||||
ASSERT_TRUE(delegate);
|
||||
ASSERT_EQ(delegate(1), 4);
|
||||
|
||||
delegate.connect<&curried_by_ptr>(&value);
|
||||
|
||||
ASSERT_TRUE(delegate);
|
||||
ASSERT_EQ(delegate(2), 6);
|
||||
}
|
||||
|
||||
TEST(Delegate, Constructors) {
|
||||
delegate_functor functor;
|
||||
const auto value = 2;
|
||||
|
||||
entt::delegate<int(int)> empty{};
|
||||
entt::delegate<int(int)> func{entt::connect_arg<&delegate_function>};
|
||||
entt::delegate<int(int)> ref{entt::connect_arg<&curried_by_ref>, value};
|
||||
entt::delegate<int(int)> ptr{entt::connect_arg<&curried_by_ptr>, &value};
|
||||
entt::delegate<int(int)> member{entt::connect_arg<&delegate_functor::operator()>, functor};
|
||||
|
||||
ASSERT_FALSE(empty);
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(9, func(3));
|
||||
|
||||
ASSERT_TRUE(ref);
|
||||
ASSERT_EQ(5, ref(3));
|
||||
|
||||
ASSERT_TRUE(ptr);
|
||||
ASSERT_EQ(6, ptr(3));
|
||||
|
||||
ASSERT_TRUE(member);
|
||||
ASSERT_EQ(6, member(3));
|
||||
}
|
||||
|
||||
TEST(Delegate, VoidVsNonVoidReturnType) {
|
||||
delegate_functor functor;
|
||||
|
||||
entt::delegate<void(int)> func{entt::connect_arg<&delegate_function>};
|
||||
entt::delegate<void(int)> member{entt::connect_arg<&delegate_functor::operator()>, &functor};
|
||||
entt::delegate<void(int)> cmember{entt::connect_arg<&delegate_functor::identity>, &std::as_const(functor)};
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_TRUE(member);
|
||||
ASSERT_TRUE(cmember);
|
||||
}
|
||||
|
||||
TEST(Delegate, UnboundDataMember) {
|
||||
entt::delegate<int(const delegate_functor &)> delegate;
|
||||
delegate.connect<&delegate_functor::data_member>();
|
||||
delegate_functor functor;
|
||||
|
||||
ASSERT_EQ(delegate(functor), 42);
|
||||
}
|
||||
|
||||
TEST(Delegate, UnboundMemberFunction) {
|
||||
entt::delegate<int(delegate_functor *, const int &i)> delegate;
|
||||
delegate.connect<&delegate_functor::operator()>();
|
||||
delegate_functor functor;
|
||||
|
||||
ASSERT_EQ(delegate(&functor, 3), 6);
|
||||
}
|
||||
|
||||
TEST(Delegate, TheLessTheBetter) {
|
||||
entt::delegate<int(int, char)> bound;
|
||||
entt::delegate<int(delegate_functor &, int, char)> unbound;
|
||||
delegate_functor functor;
|
||||
|
||||
// int delegate_function(const int &);
|
||||
bound.connect<&delegate_function>();
|
||||
|
||||
ASSERT_EQ(bound(3, 'c'), 9);
|
||||
|
||||
// int delegate_functor::operator()(int);
|
||||
bound.connect<&delegate_functor::operator()>(functor);
|
||||
|
||||
ASSERT_EQ(bound(3, 'c'), 6);
|
||||
|
||||
// int delegate_functor::operator()(int);
|
||||
bound.connect<&delegate_functor::identity>(&functor);
|
||||
|
||||
ASSERT_EQ(bound(3, 'c'), 3);
|
||||
|
||||
// int delegate_functor::operator()(int);
|
||||
unbound.connect<&delegate_functor::operator()>();
|
||||
|
||||
ASSERT_EQ(unbound(functor, 3, 'c'), 6);
|
||||
}
|
200
test/entt/signal/dispatcher.cpp
Normal file
200
test/entt/signal/dispatcher.cpp
Normal file
@ -0,0 +1,200 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/signal/dispatcher.hpp>
|
||||
|
||||
struct an_event {};
|
||||
struct another_event {};
|
||||
|
||||
// makes the type non-aggregate
|
||||
struct one_more_event {
|
||||
one_more_event(int) {}
|
||||
};
|
||||
|
||||
struct receiver {
|
||||
static void forward(entt::dispatcher &dispatcher, an_event &event) {
|
||||
dispatcher.enqueue(event);
|
||||
}
|
||||
|
||||
void receive(const an_event &) {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
int cnt{0};
|
||||
};
|
||||
|
||||
TEST(Dispatcher, Functionalities) {
|
||||
entt::dispatcher dispatcher;
|
||||
entt::dispatcher other;
|
||||
receiver receiver;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(entt::dispatcher{std::move(dispatcher)});
|
||||
ASSERT_NO_FATAL_FAILURE(dispatcher = std::move(other));
|
||||
|
||||
ASSERT_EQ(dispatcher.size<an_event>(), 0u);
|
||||
ASSERT_EQ(dispatcher.size(), 0u);
|
||||
|
||||
dispatcher.trigger(one_more_event{42});
|
||||
dispatcher.enqueue<one_more_event>(42);
|
||||
dispatcher.update<one_more_event>();
|
||||
|
||||
dispatcher.sink<an_event>().connect<&receiver::receive>(receiver);
|
||||
dispatcher.trigger<an_event>();
|
||||
dispatcher.enqueue<an_event>();
|
||||
|
||||
ASSERT_EQ(dispatcher.size<one_more_event>(), 0u);
|
||||
ASSERT_EQ(dispatcher.size<an_event>(), 1u);
|
||||
ASSERT_EQ(dispatcher.size(), 1u);
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
|
||||
dispatcher.enqueue(another_event{});
|
||||
dispatcher.update<another_event>();
|
||||
|
||||
ASSERT_EQ(dispatcher.size<another_event>(), 0u);
|
||||
ASSERT_EQ(dispatcher.size<an_event>(), 1u);
|
||||
ASSERT_EQ(dispatcher.size(), 1u);
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
|
||||
dispatcher.update<an_event>();
|
||||
dispatcher.trigger<an_event>();
|
||||
|
||||
ASSERT_EQ(dispatcher.size<an_event>(), 0u);
|
||||
ASSERT_EQ(dispatcher.size(), 0u);
|
||||
ASSERT_EQ(receiver.cnt, 3);
|
||||
|
||||
dispatcher.enqueue<an_event>();
|
||||
dispatcher.clear<an_event>();
|
||||
dispatcher.update();
|
||||
|
||||
dispatcher.enqueue(an_event{});
|
||||
dispatcher.clear();
|
||||
dispatcher.update();
|
||||
|
||||
ASSERT_EQ(dispatcher.size<an_event>(), 0u);
|
||||
ASSERT_EQ(dispatcher.size(), 0u);
|
||||
ASSERT_EQ(receiver.cnt, 3);
|
||||
|
||||
receiver.reset();
|
||||
|
||||
an_event event{};
|
||||
|
||||
dispatcher.sink<an_event>().disconnect<&receiver::receive>(receiver);
|
||||
dispatcher.trigger<an_event>();
|
||||
dispatcher.enqueue(event);
|
||||
dispatcher.update();
|
||||
dispatcher.trigger(std::as_const(event));
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 0);
|
||||
}
|
||||
|
||||
TEST(Dispatcher, Swap) {
|
||||
entt::dispatcher dispatcher;
|
||||
entt::dispatcher other;
|
||||
receiver receiver;
|
||||
|
||||
dispatcher.sink<an_event>().connect<&receiver::receive>(receiver);
|
||||
dispatcher.enqueue<an_event>();
|
||||
|
||||
ASSERT_EQ(dispatcher.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 0u);
|
||||
ASSERT_EQ(receiver.cnt, 0);
|
||||
|
||||
dispatcher.swap(other);
|
||||
dispatcher.update();
|
||||
|
||||
ASSERT_EQ(dispatcher.size(), 0u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
ASSERT_EQ(receiver.cnt, 0);
|
||||
|
||||
other.update();
|
||||
|
||||
ASSERT_EQ(dispatcher.size(), 0u);
|
||||
ASSERT_EQ(other.size(), 0u);
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
}
|
||||
|
||||
TEST(Dispatcher, StopAndGo) {
|
||||
entt::dispatcher dispatcher;
|
||||
receiver receiver;
|
||||
|
||||
dispatcher.sink<an_event>().connect<&receiver::forward>(dispatcher);
|
||||
dispatcher.sink<an_event>().connect<&receiver::receive>(receiver);
|
||||
|
||||
dispatcher.enqueue<an_event>();
|
||||
dispatcher.update();
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
|
||||
dispatcher.sink<an_event>().disconnect<&receiver::forward>(dispatcher);
|
||||
dispatcher.update();
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 2);
|
||||
}
|
||||
|
||||
TEST(Dispatcher, OpaqueDisconnect) {
|
||||
entt::dispatcher dispatcher;
|
||||
receiver receiver;
|
||||
|
||||
dispatcher.sink<an_event>().connect<&receiver::receive>(receiver);
|
||||
dispatcher.trigger<an_event>();
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
|
||||
dispatcher.disconnect(receiver);
|
||||
dispatcher.trigger<an_event>();
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
}
|
||||
|
||||
TEST(Dispatcher, NamedQueue) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::dispatcher dispatcher;
|
||||
receiver receiver;
|
||||
|
||||
dispatcher.sink<an_event>("named"_hs).connect<&receiver::receive>(receiver);
|
||||
dispatcher.trigger<an_event>();
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 0);
|
||||
|
||||
dispatcher.trigger("named"_hs, an_event{});
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
|
||||
dispatcher.enqueue<an_event>();
|
||||
dispatcher.enqueue(an_event{});
|
||||
dispatcher.enqueue_hint<an_event>("named"_hs);
|
||||
dispatcher.enqueue_hint("named"_hs, an_event{});
|
||||
dispatcher.update<an_event>();
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
|
||||
dispatcher.clear<an_event>();
|
||||
dispatcher.update<an_event>("named"_hs);
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 3);
|
||||
|
||||
dispatcher.enqueue_hint<an_event>("named"_hs);
|
||||
dispatcher.clear<an_event>("named"_hs);
|
||||
dispatcher.update<an_event>("named"_hs);
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 3);
|
||||
}
|
||||
|
||||
TEST(Dispatcher, CustomAllocator) {
|
||||
std::allocator<void> allocator;
|
||||
entt::dispatcher dispatcher{allocator};
|
||||
|
||||
ASSERT_EQ(dispatcher.get_allocator(), allocator);
|
||||
ASSERT_FALSE(dispatcher.get_allocator() != allocator);
|
||||
|
||||
dispatcher.enqueue<an_event>();
|
||||
decltype(dispatcher) other{std::move(dispatcher), allocator};
|
||||
|
||||
ASSERT_EQ(other.size<an_event>(), 1u);
|
||||
}
|
170
test/entt/signal/emitter.cpp
Normal file
170
test/entt/signal/emitter.cpp
Normal file
@ -0,0 +1,170 @@
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/signal/emitter.hpp>
|
||||
|
||||
struct test_emitter: entt::emitter<test_emitter> {
|
||||
using entt::emitter<test_emitter>::emitter;
|
||||
};
|
||||
|
||||
struct foo_event {
|
||||
int i;
|
||||
};
|
||||
|
||||
struct bar_event {};
|
||||
struct quux_event {};
|
||||
|
||||
TEST(Emitter, Move) {
|
||||
test_emitter emitter;
|
||||
emitter.on<foo_event>([](auto &, const auto &) {});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<foo_event>());
|
||||
|
||||
test_emitter other{std::move(emitter)};
|
||||
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_TRUE(other.contains<foo_event>());
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
|
||||
emitter = std::move(other);
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<foo_event>());
|
||||
ASSERT_TRUE(other.empty());
|
||||
}
|
||||
|
||||
TEST(Emitter, Swap) {
|
||||
test_emitter emitter;
|
||||
test_emitter other;
|
||||
int value{};
|
||||
|
||||
emitter.on<foo_event>([&value](auto &event, const auto &) {
|
||||
value = event.i;
|
||||
});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
|
||||
emitter.swap(other);
|
||||
emitter.publish(foo_event{42});
|
||||
|
||||
ASSERT_EQ(value, 0);
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
|
||||
other.publish(foo_event{42});
|
||||
|
||||
ASSERT_EQ(value, 42);
|
||||
}
|
||||
|
||||
TEST(Emitter, Clear) {
|
||||
test_emitter emitter;
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
|
||||
emitter.on<foo_event>([](auto &, const auto &) {});
|
||||
emitter.on<quux_event>([](const auto &, const auto &) {});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<foo_event>());
|
||||
ASSERT_TRUE(emitter.contains<quux_event>());
|
||||
ASSERT_FALSE(emitter.contains<bar_event>());
|
||||
|
||||
emitter.erase<bar_event>();
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<foo_event>());
|
||||
ASSERT_TRUE(emitter.contains<quux_event>());
|
||||
ASSERT_FALSE(emitter.contains<bar_event>());
|
||||
|
||||
emitter.erase<foo_event>();
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_FALSE(emitter.contains<foo_event>());
|
||||
ASSERT_TRUE(emitter.contains<quux_event>());
|
||||
ASSERT_FALSE(emitter.contains<bar_event>());
|
||||
|
||||
emitter.on<foo_event>([](auto &, const auto &) {});
|
||||
emitter.on<bar_event>([](const auto &, const auto &) {});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<foo_event>());
|
||||
ASSERT_TRUE(emitter.contains<quux_event>());
|
||||
ASSERT_TRUE(emitter.contains<bar_event>());
|
||||
|
||||
emitter.clear();
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
ASSERT_FALSE(emitter.contains<foo_event>());
|
||||
ASSERT_FALSE(emitter.contains<bar_event>());
|
||||
}
|
||||
|
||||
TEST(Emitter, ClearFromCallback) {
|
||||
test_emitter emitter;
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
|
||||
emitter.on<foo_event>([](auto &, auto &owner) {
|
||||
owner.template on<foo_event>([](auto &, auto &) {});
|
||||
owner.template erase<foo_event>();
|
||||
});
|
||||
|
||||
emitter.on<bar_event>([](const auto &, auto &owner) {
|
||||
owner.template on<bar_event>([](const auto &, auto &) {});
|
||||
owner.template erase<bar_event>();
|
||||
});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
|
||||
emitter.publish(foo_event{});
|
||||
emitter.publish(bar_event{});
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
}
|
||||
|
||||
TEST(Emitter, On) {
|
||||
test_emitter emitter;
|
||||
int value{};
|
||||
|
||||
emitter.on<foo_event>([&value](auto &event, const auto &) {
|
||||
value = event.i;
|
||||
});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<foo_event>());
|
||||
ASSERT_EQ(value, 0);
|
||||
|
||||
emitter.publish(foo_event{42});
|
||||
|
||||
ASSERT_EQ(value, 42);
|
||||
}
|
||||
|
||||
TEST(Emitter, OnAndErase) {
|
||||
test_emitter emitter;
|
||||
std::function<void(bar_event &, test_emitter &)> func{};
|
||||
|
||||
emitter.on(func);
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<bar_event>());
|
||||
|
||||
emitter.erase<bar_event>();
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
ASSERT_FALSE(emitter.contains<bar_event>());
|
||||
}
|
||||
|
||||
TEST(Emitter, CustomAllocator) {
|
||||
std::allocator<void> allocator;
|
||||
test_emitter emitter{allocator};
|
||||
|
||||
ASSERT_EQ(emitter.get_allocator(), allocator);
|
||||
ASSERT_FALSE(emitter.get_allocator() != allocator);
|
||||
|
||||
emitter.on<foo_event>([](auto &, const auto &) {});
|
||||
decltype(emitter) other{std::move(emitter), allocator};
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
}
|
577
test/entt/signal/sigh.cpp
Normal file
577
test/entt/signal/sigh.cpp
Normal file
@ -0,0 +1,577 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/signal/sigh.hpp>
|
||||
|
||||
struct sigh_listener {
|
||||
static void f(int &v) {
|
||||
v = 42;
|
||||
}
|
||||
|
||||
bool g(int) {
|
||||
k = !k;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool h(const int &) {
|
||||
return k;
|
||||
}
|
||||
|
||||
// useless definition just because msvc does weird things if both are empty
|
||||
void l() {
|
||||
k = true && k;
|
||||
}
|
||||
|
||||
bool k{false};
|
||||
};
|
||||
|
||||
struct before_after {
|
||||
void add(int v) {
|
||||
value += v;
|
||||
}
|
||||
|
||||
void mul(int v) {
|
||||
value *= v;
|
||||
}
|
||||
|
||||
static void static_add(int v) {
|
||||
before_after::value += v;
|
||||
}
|
||||
|
||||
static void static_mul(before_after &instance, int v) {
|
||||
instance.value *= v;
|
||||
}
|
||||
|
||||
static inline int value{};
|
||||
};
|
||||
|
||||
struct SigH: ::testing::Test {
|
||||
void SetUp() override {
|
||||
before_after::value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct const_nonconst_noexcept {
|
||||
void f() {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void g() noexcept {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void h() const {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void i() const noexcept {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
mutable int cnt{0};
|
||||
};
|
||||
|
||||
TEST_F(SigH, Lifetime) {
|
||||
using signal = entt::sigh<void(void)>;
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(signal{});
|
||||
|
||||
signal src{}, other{};
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(signal{src});
|
||||
ASSERT_NO_FATAL_FAILURE(signal{std::move(other)});
|
||||
ASSERT_NO_FATAL_FAILURE(src = other);
|
||||
ASSERT_NO_FATAL_FAILURE(src = std::move(other));
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(delete new signal{});
|
||||
}
|
||||
|
||||
TEST_F(SigH, Clear) {
|
||||
entt::sigh<void(int &)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
sink.connect<&sigh_listener::f>();
|
||||
|
||||
ASSERT_FALSE(sink.empty());
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
|
||||
sink.disconnect(static_cast<const void *>(nullptr));
|
||||
|
||||
ASSERT_FALSE(sink.empty());
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
|
||||
sink.disconnect();
|
||||
|
||||
ASSERT_TRUE(sink.empty());
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
}
|
||||
|
||||
TEST_F(SigH, Swap) {
|
||||
entt::sigh<void(int &)> sigh1;
|
||||
entt::sigh<void(int &)> sigh2;
|
||||
entt::sink sink1{sigh1};
|
||||
entt::sink sink2{sigh2};
|
||||
|
||||
sink1.connect<&sigh_listener::f>();
|
||||
|
||||
ASSERT_FALSE(sink1.empty());
|
||||
ASSERT_TRUE(sink2.empty());
|
||||
|
||||
ASSERT_FALSE(sigh1.empty());
|
||||
ASSERT_TRUE(sigh2.empty());
|
||||
|
||||
sigh1.swap(sigh2);
|
||||
|
||||
ASSERT_TRUE(sink1.empty());
|
||||
ASSERT_FALSE(sink2.empty());
|
||||
|
||||
ASSERT_TRUE(sigh1.empty());
|
||||
ASSERT_FALSE(sigh2.empty());
|
||||
}
|
||||
|
||||
TEST_F(SigH, Functions) {
|
||||
entt::sigh<void(int &)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
int v = 0;
|
||||
|
||||
sink.connect<&sigh_listener::f>();
|
||||
sigh.publish(v);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(1u, sigh.size());
|
||||
ASSERT_EQ(42, v);
|
||||
|
||||
v = 0;
|
||||
sink.disconnect<&sigh_listener::f>();
|
||||
sigh.publish(v);
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_EQ(0u, sigh.size());
|
||||
ASSERT_EQ(v, 0);
|
||||
}
|
||||
|
||||
TEST_F(SigH, FunctionsWithPayload) {
|
||||
entt::sigh<void()> sigh;
|
||||
entt::sink sink{sigh};
|
||||
int v = 0;
|
||||
|
||||
sink.connect<&sigh_listener::f>(v);
|
||||
sigh.publish();
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(1u, sigh.size());
|
||||
ASSERT_EQ(42, v);
|
||||
|
||||
v = 0;
|
||||
sink.disconnect<&sigh_listener::f>(v);
|
||||
sigh.publish();
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_EQ(0u, sigh.size());
|
||||
ASSERT_EQ(v, 0);
|
||||
|
||||
sink.connect<&sigh_listener::f>(v);
|
||||
sink.disconnect(v);
|
||||
sigh.publish();
|
||||
|
||||
ASSERT_EQ(v, 0);
|
||||
}
|
||||
|
||||
TEST_F(SigH, Members) {
|
||||
sigh_listener l1, l2;
|
||||
entt::sigh<bool(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
sink.connect<&sigh_listener::g>(l1);
|
||||
sigh.publish(42);
|
||||
|
||||
ASSERT_TRUE(l1.k);
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(1u, sigh.size());
|
||||
|
||||
sink.disconnect<&sigh_listener::g>(l1);
|
||||
sigh.publish(42);
|
||||
|
||||
ASSERT_TRUE(l1.k);
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_EQ(0u, sigh.size());
|
||||
|
||||
sink.connect<&sigh_listener::g>(&l1);
|
||||
sink.connect<&sigh_listener::h>(l2);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(2u, sigh.size());
|
||||
|
||||
sink.disconnect(static_cast<const void *>(nullptr));
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(2u, sigh.size());
|
||||
|
||||
sink.disconnect(&l1);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(1u, sigh.size());
|
||||
}
|
||||
|
||||
TEST_F(SigH, Collector) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<bool(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
int cnt = 0;
|
||||
|
||||
sink.connect<&sigh_listener::g>(&listener);
|
||||
sink.connect<&sigh_listener::h>(listener);
|
||||
|
||||
auto no_return = [&listener, &cnt](bool value) {
|
||||
ASSERT_TRUE(value);
|
||||
listener.k = true;
|
||||
++cnt;
|
||||
};
|
||||
|
||||
listener.k = true;
|
||||
sigh.collect(std::move(no_return), 42);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(cnt, 2);
|
||||
|
||||
auto bool_return = [&cnt](bool value) {
|
||||
// gtest and its macro hell are sometimes really annoying...
|
||||
[](auto v) { ASSERT_TRUE(v); }(value);
|
||||
++cnt;
|
||||
return true;
|
||||
};
|
||||
|
||||
cnt = 0;
|
||||
sigh.collect(std::move(bool_return), 42);
|
||||
|
||||
ASSERT_EQ(cnt, 1);
|
||||
}
|
||||
|
||||
TEST_F(SigH, CollectorVoid) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<void(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
int cnt = 0;
|
||||
|
||||
sink.connect<&sigh_listener::g>(&listener);
|
||||
sink.connect<&sigh_listener::h>(listener);
|
||||
sigh.collect([&cnt]() { ++cnt; }, 42);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(cnt, 2);
|
||||
|
||||
auto test = [&cnt]() {
|
||||
++cnt;
|
||||
return true;
|
||||
};
|
||||
|
||||
cnt = 0;
|
||||
sigh.collect(std::move(test), 42);
|
||||
|
||||
ASSERT_EQ(cnt, 1);
|
||||
}
|
||||
|
||||
TEST_F(SigH, Connection) {
|
||||
entt::sigh<void(int &)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
int v = 0;
|
||||
|
||||
auto conn = sink.connect<&sigh_listener::f>();
|
||||
sigh.publish(v);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_TRUE(conn);
|
||||
ASSERT_EQ(42, v);
|
||||
|
||||
v = 0;
|
||||
conn.release();
|
||||
sigh.publish(v);
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_FALSE(conn);
|
||||
ASSERT_EQ(0, v);
|
||||
}
|
||||
|
||||
TEST_F(SigH, ScopedConnection) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<void(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
{
|
||||
ASSERT_FALSE(listener.k);
|
||||
|
||||
entt::scoped_connection conn = sink.connect<&sigh_listener::g>(listener);
|
||||
sigh.publish(42);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_TRUE(listener.k);
|
||||
ASSERT_TRUE(conn);
|
||||
}
|
||||
|
||||
sigh.publish(42);
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_TRUE(listener.k);
|
||||
}
|
||||
|
||||
TEST_F(SigH, ScopedConnectionMove) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<void(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
entt::scoped_connection outer{sink.connect<&sigh_listener::g>(listener)};
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_TRUE(outer);
|
||||
|
||||
{
|
||||
entt::scoped_connection inner{std::move(outer)};
|
||||
|
||||
ASSERT_FALSE(listener.k);
|
||||
ASSERT_FALSE(outer);
|
||||
ASSERT_TRUE(inner);
|
||||
|
||||
sigh.publish(42);
|
||||
|
||||
ASSERT_TRUE(listener.k);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
|
||||
outer = sink.connect<&sigh_listener::g>(listener);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_TRUE(outer);
|
||||
|
||||
{
|
||||
entt::scoped_connection inner{};
|
||||
|
||||
ASSERT_TRUE(listener.k);
|
||||
ASSERT_TRUE(outer);
|
||||
ASSERT_FALSE(inner);
|
||||
|
||||
inner = std::move(outer);
|
||||
|
||||
ASSERT_FALSE(outer);
|
||||
ASSERT_TRUE(inner);
|
||||
|
||||
sigh.publish(42);
|
||||
|
||||
ASSERT_FALSE(listener.k);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
}
|
||||
|
||||
TEST_F(SigH, ScopedConnectionConstructorsAndOperators) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<void(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
{
|
||||
entt::scoped_connection inner{};
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_FALSE(listener.k);
|
||||
ASSERT_FALSE(inner);
|
||||
|
||||
inner = sink.connect<&sigh_listener::g>(listener);
|
||||
sigh.publish(42);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_TRUE(listener.k);
|
||||
ASSERT_TRUE(inner);
|
||||
|
||||
inner.release();
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_FALSE(inner);
|
||||
|
||||
auto basic = sink.connect<&sigh_listener::g>(listener);
|
||||
inner = std::as_const(basic);
|
||||
sigh.publish(42);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_FALSE(listener.k);
|
||||
ASSERT_TRUE(inner);
|
||||
}
|
||||
|
||||
sigh.publish(42);
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_FALSE(listener.k);
|
||||
}
|
||||
|
||||
TEST_F(SigH, ConstNonConstNoExcept) {
|
||||
entt::sigh<void()> sigh;
|
||||
entt::sink sink{sigh};
|
||||
const_nonconst_noexcept functor;
|
||||
const const_nonconst_noexcept cfunctor;
|
||||
|
||||
sink.connect<&const_nonconst_noexcept::f>(functor);
|
||||
sink.connect<&const_nonconst_noexcept::g>(&functor);
|
||||
sink.connect<&const_nonconst_noexcept::h>(cfunctor);
|
||||
sink.connect<&const_nonconst_noexcept::i>(&cfunctor);
|
||||
sigh.publish();
|
||||
|
||||
ASSERT_EQ(functor.cnt, 2);
|
||||
ASSERT_EQ(cfunctor.cnt, 2);
|
||||
|
||||
sink.disconnect<&const_nonconst_noexcept::f>(functor);
|
||||
sink.disconnect<&const_nonconst_noexcept::g>(&functor);
|
||||
sink.disconnect<&const_nonconst_noexcept::h>(cfunctor);
|
||||
sink.disconnect<&const_nonconst_noexcept::i>(&cfunctor);
|
||||
sigh.publish();
|
||||
|
||||
ASSERT_EQ(functor.cnt, 2);
|
||||
ASSERT_EQ(cfunctor.cnt, 2);
|
||||
}
|
||||
|
||||
TEST_F(SigH, BeforeFunction) {
|
||||
entt::sigh<void(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
before_after functor;
|
||||
|
||||
sink.connect<&before_after::add>(functor);
|
||||
sink.connect<&before_after::static_add>();
|
||||
sink.before<&before_after::static_add>().connect<&before_after::mul>(functor);
|
||||
sigh.publish(2);
|
||||
|
||||
ASSERT_EQ(functor.value, 6);
|
||||
}
|
||||
|
||||
TEST_F(SigH, BeforeMemberFunction) {
|
||||
entt::sigh<void(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
before_after functor;
|
||||
|
||||
sink.connect<&before_after::static_add>();
|
||||
sink.connect<&before_after::add>(functor);
|
||||
sink.before<&before_after::add>(functor).connect<&before_after::mul>(functor);
|
||||
sigh.publish(2);
|
||||
|
||||
ASSERT_EQ(functor.value, 6);
|
||||
}
|
||||
|
||||
TEST_F(SigH, BeforeFunctionWithPayload) {
|
||||
entt::sigh<void(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
before_after functor;
|
||||
|
||||
sink.connect<&before_after::static_add>();
|
||||
sink.connect<&before_after::static_mul>(functor);
|
||||
sink.before<&before_after::static_mul>(functor).connect<&before_after::add>(functor);
|
||||
sigh.publish(2);
|
||||
|
||||
ASSERT_EQ(functor.value, 8);
|
||||
}
|
||||
|
||||
TEST_F(SigH, BeforeInstanceOrPayload) {
|
||||
entt::sigh<void(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
before_after functor;
|
||||
|
||||
sink.connect<&before_after::static_mul>(functor);
|
||||
sink.connect<&before_after::add>(functor);
|
||||
sink.before(functor).connect<&before_after::static_add>();
|
||||
sigh.publish(2);
|
||||
|
||||
ASSERT_EQ(functor.value, 6);
|
||||
}
|
||||
|
||||
TEST_F(SigH, BeforeAnythingElse) {
|
||||
entt::sigh<void(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
before_after functor;
|
||||
|
||||
sink.connect<&before_after::add>(functor);
|
||||
sink.before().connect<&before_after::mul>(functor);
|
||||
sigh.publish(2);
|
||||
|
||||
ASSERT_EQ(functor.value, 2);
|
||||
}
|
||||
|
||||
TEST_F(SigH, BeforeListenerNotPresent) {
|
||||
entt::sigh<void(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
before_after functor;
|
||||
|
||||
sink.connect<&before_after::mul>(functor);
|
||||
sink.before<&before_after::add>(&functor).connect<&before_after::add>(functor);
|
||||
sigh.publish(2);
|
||||
|
||||
ASSERT_EQ(functor.value, 2);
|
||||
}
|
||||
|
||||
TEST_F(SigH, UnboundDataMember) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<bool &(sigh_listener &)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
ASSERT_FALSE(listener.k);
|
||||
|
||||
sink.connect<&sigh_listener::k>();
|
||||
sigh.collect([](bool &value) { value = !value; }, listener);
|
||||
|
||||
ASSERT_TRUE(listener.k);
|
||||
}
|
||||
|
||||
TEST_F(SigH, UnboundMemberFunction) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<void(sigh_listener *, int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
ASSERT_FALSE(listener.k);
|
||||
|
||||
sink.connect<&sigh_listener::g>();
|
||||
sigh.publish(&listener, 42);
|
||||
|
||||
ASSERT_TRUE(listener.k);
|
||||
}
|
||||
|
||||
TEST_F(SigH, CustomAllocator) {
|
||||
std::allocator<void (*)(int)> allocator;
|
||||
entt::sigh<void(int), decltype(allocator)> sigh{allocator};
|
||||
|
||||
ASSERT_EQ(sigh.get_allocator(), allocator);
|
||||
ASSERT_FALSE(sigh.get_allocator() != allocator);
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
|
||||
entt::sink sink{sigh};
|
||||
sigh_listener listener;
|
||||
sink.template connect<&sigh_listener::g>(listener);
|
||||
|
||||
decltype(sigh) copy{sigh, allocator};
|
||||
sink.disconnect(listener);
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_FALSE(copy.empty());
|
||||
|
||||
sigh = copy;
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_FALSE(copy.empty());
|
||||
|
||||
decltype(sigh) move{std::move(copy), allocator};
|
||||
|
||||
ASSERT_TRUE(copy.empty());
|
||||
ASSERT_FALSE(move.empty());
|
||||
|
||||
sink = entt::sink{move};
|
||||
sink.disconnect(&listener);
|
||||
|
||||
ASSERT_TRUE(copy.empty());
|
||||
ASSERT_TRUE(move.empty());
|
||||
|
||||
sink.template connect<&sigh_listener::g>(listener);
|
||||
copy.swap(move);
|
||||
|
||||
ASSERT_FALSE(copy.empty());
|
||||
ASSERT_TRUE(move.empty());
|
||||
|
||||
sink = entt::sink{copy};
|
||||
sink.disconnect();
|
||||
|
||||
ASSERT_TRUE(copy.empty());
|
||||
ASSERT_TRUE(move.empty());
|
||||
}
|
Reference in New Issue
Block a user