Initial commit - restart from existing code
This commit is contained in:
9
lib/All/entt/test/entt/config/version.cpp
Normal file
9
lib/All/entt/test/entt/config/version.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <regex>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/config/macro.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]+$"}));
|
||||
}
|
||||
1248
lib/All/entt/test/entt/container/dense_map.cpp
Normal file
1248
lib/All/entt/test/entt/container/dense_map.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1042
lib/All/entt/test/entt/container/dense_set.cpp
Normal file
1042
lib/All/entt/test/entt/container/dense_set.cpp
Normal file
File diff suppressed because it is too large
Load Diff
540
lib/All/entt/test/entt/container/table.cpp
Normal file
540
lib/All/entt/test/entt/container/table.cpp
Normal file
@@ -0,0 +1,540 @@
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/container/table.hpp>
|
||||
#include <entt/core/iterator.hpp>
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/linter.hpp"
|
||||
#include "../../common/throwing_allocator.hpp"
|
||||
|
||||
TEST(Table, Constructors) {
|
||||
const std::vector<int> vec_of_int{1};
|
||||
const std::vector<char> vec_of_char{'a'};
|
||||
entt::table<int, char> table{};
|
||||
|
||||
ASSERT_TRUE(table.empty());
|
||||
|
||||
table = entt::table<int, char>{std::allocator<void>{}};
|
||||
|
||||
ASSERT_TRUE(table.empty());
|
||||
|
||||
table = entt::table<int, char>{vec_of_int, vec_of_char};
|
||||
|
||||
ASSERT_EQ(table.size(), 1);
|
||||
|
||||
table = entt::table<int, char>{std::vector<int>{1, 2}, std::vector<char>{'a', 'b'}};
|
||||
|
||||
ASSERT_EQ(table.size(), 2);
|
||||
|
||||
table = entt::table<int, char>{vec_of_int, vec_of_char, std::allocator<void>{}};
|
||||
|
||||
ASSERT_EQ(table.size(), 1);
|
||||
|
||||
table = entt::table<int, char>{std::vector<int>{1, 2}, std::vector<char>{'a', 'b'}, std::allocator<void>{}};
|
||||
|
||||
ASSERT_EQ(table.size(), 2);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(TableDeathTest, Constructors) {
|
||||
const std::vector<int> vec_of_int{0};
|
||||
const std::vector<char> vec_of_char{};
|
||||
entt::table<int, char> table{};
|
||||
|
||||
ASSERT_DEATH((table = entt::table<int, char>{vec_of_int, vec_of_char}), "");
|
||||
ASSERT_DEATH((table = entt::table<int, char>{std::vector<int>{}, std::vector<char>{'\0'}}), "");
|
||||
|
||||
ASSERT_DEATH((table = entt::table<int, char>{vec_of_int, vec_of_char, std::allocator<void>{}}), "");
|
||||
ASSERT_DEATH((table = entt::table<int, char>{std::vector<int>{}, std::vector<char>{'\0'}, std::allocator<void>{}}), "");
|
||||
}
|
||||
|
||||
TEST(Table, Move) {
|
||||
entt::table<int, char> table;
|
||||
|
||||
table.emplace(3, 'c');
|
||||
|
||||
static_assert(std::is_move_constructible_v<decltype(table)>, "Move constructible type required");
|
||||
static_assert(std::is_move_assignable_v<decltype(table)>, "Move assignable type required");
|
||||
|
||||
entt::table<int, char> other{std::move(table)};
|
||||
|
||||
test::is_initialized(table);
|
||||
|
||||
ASSERT_TRUE(table.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
|
||||
ASSERT_EQ(other[0u], std::make_tuple(3, 'c'));
|
||||
|
||||
entt::table<int, char> extended{std::move(other), std::allocator<void>{}};
|
||||
|
||||
test::is_initialized(other);
|
||||
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_FALSE(extended.empty());
|
||||
|
||||
ASSERT_EQ(extended[0u], std::make_tuple(3, 'c'));
|
||||
|
||||
table = std::move(extended);
|
||||
test::is_initialized(extended);
|
||||
|
||||
ASSERT_FALSE(table.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_TRUE(extended.empty());
|
||||
|
||||
ASSERT_EQ(table[0u], std::make_tuple(3, 'c'));
|
||||
|
||||
other = entt::table<int, char>{};
|
||||
other.emplace(1, 'a');
|
||||
other = std::move(table);
|
||||
test::is_initialized(table);
|
||||
|
||||
ASSERT_FALSE(table.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
|
||||
ASSERT_EQ(other[0u], std::make_tuple(3, 'c'));
|
||||
}
|
||||
|
||||
TEST(Table, Swap) {
|
||||
entt::table<int, char> table;
|
||||
entt::table<int, char> other;
|
||||
|
||||
table.emplace(3, 'c');
|
||||
|
||||
other.emplace(1, 'a');
|
||||
other.emplace(0, '\0');
|
||||
other.erase(0u);
|
||||
|
||||
ASSERT_EQ(table.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
|
||||
table.swap(other);
|
||||
|
||||
ASSERT_EQ(table.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
|
||||
ASSERT_EQ(table[0u], std::make_tuple(0, '\0'));
|
||||
ASSERT_EQ(other[0u], std::make_tuple(3, 'c'));
|
||||
}
|
||||
|
||||
TEST(Table, Capacity) {
|
||||
entt::table<int, char> table;
|
||||
|
||||
ASSERT_EQ(table.capacity(), 0u);
|
||||
ASSERT_TRUE(table.empty());
|
||||
|
||||
table.reserve(64u);
|
||||
|
||||
ASSERT_EQ(table.capacity(), 64u);
|
||||
ASSERT_TRUE(table.empty());
|
||||
|
||||
table.reserve(0);
|
||||
|
||||
ASSERT_EQ(table.capacity(), 64u);
|
||||
ASSERT_TRUE(table.empty());
|
||||
}
|
||||
|
||||
TEST(Table, ShrinkToFit) {
|
||||
entt::table<int, char> table;
|
||||
|
||||
table.reserve(64u);
|
||||
table.emplace(3, 'c');
|
||||
|
||||
ASSERT_EQ(table.capacity(), 64u);
|
||||
ASSERT_FALSE(table.empty());
|
||||
|
||||
table.shrink_to_fit();
|
||||
|
||||
ASSERT_EQ(table.capacity(), 1u);
|
||||
ASSERT_FALSE(table.empty());
|
||||
|
||||
table.clear();
|
||||
|
||||
ASSERT_EQ(table.capacity(), 1u);
|
||||
ASSERT_TRUE(table.empty());
|
||||
|
||||
table.shrink_to_fit();
|
||||
|
||||
ASSERT_EQ(table.capacity(), 0u);
|
||||
ASSERT_TRUE(table.empty());
|
||||
}
|
||||
|
||||
TEST(Table, Iterator) {
|
||||
using iterator = typename entt::table<int, char>::iterator;
|
||||
|
||||
testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<int &, char &>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<int &, char &>>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::reference, std::tuple<int &, char &>>();
|
||||
|
||||
entt::table<int, char> table;
|
||||
table.emplace(3, 'c');
|
||||
|
||||
iterator end{table.begin()};
|
||||
iterator begin{};
|
||||
|
||||
begin = table.end();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, table.begin());
|
||||
ASSERT_EQ(end, table.end());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(begin++, table.begin());
|
||||
ASSERT_EQ(begin--, table.end());
|
||||
|
||||
ASSERT_EQ(begin + 1, table.end());
|
||||
ASSERT_EQ(end - 1, table.begin());
|
||||
|
||||
ASSERT_EQ(++begin, table.end());
|
||||
ASSERT_EQ(--begin, table.begin());
|
||||
|
||||
ASSERT_EQ(begin += 1, table.end());
|
||||
ASSERT_EQ(begin -= 1, table.begin());
|
||||
|
||||
ASSERT_EQ(begin + (end - begin), table.end());
|
||||
ASSERT_EQ(begin - (begin - end), table.end());
|
||||
|
||||
ASSERT_EQ(end - (end - begin), table.begin());
|
||||
ASSERT_EQ(end + (begin - end), table.begin());
|
||||
|
||||
ASSERT_EQ(begin[0u], *table.begin().operator->());
|
||||
|
||||
ASSERT_LT(begin, end);
|
||||
ASSERT_LE(begin, table.begin());
|
||||
|
||||
ASSERT_GT(end, begin);
|
||||
ASSERT_GE(end, table.end());
|
||||
|
||||
table.emplace(0, '\0');
|
||||
begin = table.begin();
|
||||
|
||||
ASSERT_EQ(begin[0u], std::make_tuple(3, 'c'));
|
||||
ASSERT_EQ(begin[1u], std::make_tuple(0, '\0'));
|
||||
}
|
||||
|
||||
TEST(Table, ConstIterator) {
|
||||
using iterator = typename entt::table<int, char>::const_iterator;
|
||||
|
||||
testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<const int &, const char &>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<const int &, const char &>>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::reference, std::tuple<const int &, const char &>>();
|
||||
|
||||
entt::table<int, char> table;
|
||||
table.emplace(3, 'c');
|
||||
|
||||
iterator cend{table.cbegin()};
|
||||
iterator cbegin{};
|
||||
|
||||
cbegin = table.cend();
|
||||
std::swap(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin, std::as_const(table).begin());
|
||||
ASSERT_EQ(cend, std::as_const(table).end());
|
||||
ASSERT_EQ(cbegin, table.cbegin());
|
||||
ASSERT_EQ(cend, table.cend());
|
||||
ASSERT_NE(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin++, table.cbegin());
|
||||
ASSERT_EQ(cbegin--, table.cend());
|
||||
|
||||
ASSERT_EQ(cbegin + 1, table.cend());
|
||||
ASSERT_EQ(cend - 1, table.cbegin());
|
||||
|
||||
ASSERT_EQ(++cbegin, table.cend());
|
||||
ASSERT_EQ(--cbegin, table.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin += 1, table.cend());
|
||||
ASSERT_EQ(cbegin -= 1, table.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin + (cend - cbegin), table.cend());
|
||||
ASSERT_EQ(cbegin - (cbegin - cend), table.cend());
|
||||
|
||||
ASSERT_EQ(cend - (cend - cbegin), table.cbegin());
|
||||
ASSERT_EQ(cend + (cbegin - cend), table.cbegin());
|
||||
|
||||
ASSERT_EQ(cbegin[0u], *table.cbegin().operator->());
|
||||
|
||||
ASSERT_LT(cbegin, cend);
|
||||
ASSERT_LE(cbegin, table.cbegin());
|
||||
|
||||
ASSERT_GT(cend, cbegin);
|
||||
ASSERT_GE(cend, table.cend());
|
||||
|
||||
table.emplace(0, '\0');
|
||||
cbegin = table.cbegin();
|
||||
|
||||
ASSERT_EQ(cbegin[0u], std::make_tuple(3, 'c'));
|
||||
ASSERT_EQ(cbegin[1u], std::make_tuple(0, '\0'));
|
||||
}
|
||||
|
||||
TEST(Table, ReverseIterator) {
|
||||
using reverse_iterator = typename entt::table<int, char>::reverse_iterator;
|
||||
|
||||
testing::StaticAssertTypeEq<typename reverse_iterator::value_type, std::tuple<int &, char &>>();
|
||||
testing::StaticAssertTypeEq<typename reverse_iterator::pointer, entt::input_iterator_pointer<std::tuple<int &, char &>>>();
|
||||
testing::StaticAssertTypeEq<typename reverse_iterator::reference, std::tuple<int &, char &>>();
|
||||
|
||||
entt::table<int, char> table;
|
||||
table.emplace(3, 'c');
|
||||
|
||||
reverse_iterator end{table.rbegin()};
|
||||
reverse_iterator begin{};
|
||||
|
||||
begin = table.rend();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, table.rbegin());
|
||||
ASSERT_EQ(end, table.rend());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(begin++, table.rbegin());
|
||||
ASSERT_EQ(begin--, table.rend());
|
||||
|
||||
ASSERT_EQ(begin + 1, table.rend());
|
||||
ASSERT_EQ(end - 1, table.rbegin());
|
||||
|
||||
ASSERT_EQ(++begin, table.rend());
|
||||
ASSERT_EQ(--begin, table.rbegin());
|
||||
|
||||
ASSERT_EQ(begin += 1, table.rend());
|
||||
ASSERT_EQ(begin -= 1, table.rbegin());
|
||||
|
||||
ASSERT_EQ(begin + (end - begin), table.rend());
|
||||
ASSERT_EQ(begin - (begin - end), table.rend());
|
||||
|
||||
ASSERT_EQ(end - (end - begin), table.rbegin());
|
||||
ASSERT_EQ(end + (begin - end), table.rbegin());
|
||||
|
||||
ASSERT_EQ(begin[0u], *table.rbegin().operator->());
|
||||
|
||||
ASSERT_LT(begin, end);
|
||||
ASSERT_LE(begin, table.rbegin());
|
||||
|
||||
ASSERT_GT(end, begin);
|
||||
ASSERT_GE(end, table.rend());
|
||||
|
||||
table.emplace(0, '\0');
|
||||
begin = table.rbegin();
|
||||
|
||||
ASSERT_EQ(begin[0u], std::make_tuple(0, '\0'));
|
||||
ASSERT_EQ(begin[1u], std::make_tuple(3, 'c'));
|
||||
}
|
||||
|
||||
TEST(Table, ConstReverseIterator) {
|
||||
using const_reverse_iterator = typename entt::table<int, char>::const_reverse_iterator;
|
||||
|
||||
testing::StaticAssertTypeEq<typename const_reverse_iterator::value_type, std::tuple<const int &, const char &>>();
|
||||
testing::StaticAssertTypeEq<typename const_reverse_iterator::pointer, entt::input_iterator_pointer<std::tuple<const int &, const char &>>>();
|
||||
testing::StaticAssertTypeEq<typename const_reverse_iterator::reference, std::tuple<const int &, const char &>>();
|
||||
|
||||
entt::table<int, char> table;
|
||||
table.emplace(3, 'c');
|
||||
|
||||
const_reverse_iterator cend{table.crbegin()};
|
||||
const_reverse_iterator cbegin{};
|
||||
|
||||
cbegin = table.crend();
|
||||
std::swap(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin, std::as_const(table).rbegin());
|
||||
ASSERT_EQ(cend, std::as_const(table).rend());
|
||||
ASSERT_EQ(cbegin, table.crbegin());
|
||||
ASSERT_EQ(cend, table.crend());
|
||||
ASSERT_NE(cbegin, cend);
|
||||
|
||||
ASSERT_EQ(cbegin++, table.crbegin());
|
||||
ASSERT_EQ(cbegin--, table.crend());
|
||||
|
||||
ASSERT_EQ(cbegin + 1, table.crend());
|
||||
ASSERT_EQ(cend - 1, table.crbegin());
|
||||
|
||||
ASSERT_EQ(++cbegin, table.crend());
|
||||
ASSERT_EQ(--cbegin, table.crbegin());
|
||||
|
||||
ASSERT_EQ(cbegin += 1, table.crend());
|
||||
ASSERT_EQ(cbegin -= 1, table.crbegin());
|
||||
|
||||
ASSERT_EQ(cbegin + (cend - cbegin), table.crend());
|
||||
ASSERT_EQ(cbegin - (cbegin - cend), table.crend());
|
||||
|
||||
ASSERT_EQ(cend - (cend - cbegin), table.crbegin());
|
||||
ASSERT_EQ(cend + (cbegin - cend), table.crbegin());
|
||||
|
||||
ASSERT_EQ(cbegin[0u], *table.crbegin().operator->());
|
||||
|
||||
ASSERT_LT(cbegin, cend);
|
||||
ASSERT_LE(cbegin, table.crbegin());
|
||||
|
||||
ASSERT_GT(cend, cbegin);
|
||||
ASSERT_GE(cend, table.crend());
|
||||
|
||||
table.emplace(0, '\0');
|
||||
cbegin = table.crbegin();
|
||||
|
||||
ASSERT_EQ(cbegin[0u], std::make_tuple(0, '\0'));
|
||||
ASSERT_EQ(cbegin[1u], std::make_tuple(3, 'c'));
|
||||
}
|
||||
|
||||
TEST(Table, IteratorConversion) {
|
||||
entt::table<int, char> table;
|
||||
|
||||
table.emplace(3, 'c');
|
||||
|
||||
const typename entt::table<int, char>::iterator it = table.begin();
|
||||
typename entt::table<int, char>::const_iterator cit = it;
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(*it), std::tuple<int &, char &>>();
|
||||
testing::StaticAssertTypeEq<decltype(*cit), std::tuple<const int &, const char &>>();
|
||||
|
||||
ASSERT_EQ(*it.operator->(), std::make_tuple(3, 'c'));
|
||||
ASSERT_EQ(*it.operator->(), *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(Table, Emplace) {
|
||||
entt::table<int, char> table;
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(table.emplace()), std::tuple<int &, char &>>();
|
||||
|
||||
ASSERT_EQ(table.emplace(), std::make_tuple(int{}, char{}));
|
||||
ASSERT_EQ(table.emplace(3, 'c'), std::make_tuple(3, 'c'));
|
||||
}
|
||||
|
||||
TEST(Table, Erase) {
|
||||
entt::table<int, char> table;
|
||||
|
||||
table.emplace(3, 'c');
|
||||
table.emplace(0, '\0');
|
||||
table.erase(table.begin());
|
||||
|
||||
ASSERT_EQ(table.size(), 1u);
|
||||
ASSERT_EQ(table[0u], std::make_tuple(0, '\0'));
|
||||
|
||||
table.emplace(3, 'c');
|
||||
table.erase(1u);
|
||||
|
||||
ASSERT_EQ(table.size(), 1u);
|
||||
ASSERT_EQ(table[0u], std::make_tuple(0, '\0'));
|
||||
|
||||
table.erase(0u);
|
||||
|
||||
ASSERT_EQ(table.size(), 0u);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(TableDeathTest, Erase) {
|
||||
entt::table<int, char> table;
|
||||
|
||||
ASSERT_DEATH(table.erase(0u), "");
|
||||
|
||||
table.emplace(3, 'c');
|
||||
|
||||
ASSERT_DEATH(table.erase(1u), "");
|
||||
}
|
||||
|
||||
TEST(Table, Indexing) {
|
||||
entt::table<int, char> table;
|
||||
|
||||
table.emplace(3, 'c');
|
||||
table.emplace(0, '\0');
|
||||
|
||||
ASSERT_EQ(table[0u], std::make_tuple(3, 'c'));
|
||||
ASSERT_EQ(std::as_const(table)[1u], std::make_tuple(0, '\0'));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(TableDeathTest, Indexing) {
|
||||
entt::table<int, char> table;
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] auto value = table[0u], "");
|
||||
ASSERT_DEATH([[maybe_unused]] auto value = std::as_const(table)[0u], "");
|
||||
}
|
||||
|
||||
TEST(Table, Clear) {
|
||||
entt::table<int, char> table;
|
||||
|
||||
table.emplace(3, 'c');
|
||||
table.emplace(0, '\0');
|
||||
|
||||
ASSERT_EQ(table.size(), 2u);
|
||||
|
||||
table.clear();
|
||||
|
||||
ASSERT_EQ(table.size(), 0u);
|
||||
|
||||
table.emplace(3, 'c');
|
||||
table.emplace(0, '\0');
|
||||
table.erase(0u);
|
||||
|
||||
ASSERT_EQ(table.size(), 1u);
|
||||
|
||||
table.clear();
|
||||
|
||||
ASSERT_EQ(table.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Table, CustomAllocator) {
|
||||
const test::throwing_allocator<void> allocator{};
|
||||
entt::basic_table<std::vector<int, test::throwing_allocator<int>>, std::vector<char, test::throwing_allocator<char>>> table{allocator};
|
||||
|
||||
table.reserve(1u);
|
||||
|
||||
ASSERT_NE(table.capacity(), 0u);
|
||||
|
||||
table.emplace(3, 'c');
|
||||
table.emplace(0, '\0');
|
||||
|
||||
decltype(table) other{std::move(table), allocator};
|
||||
|
||||
test::is_initialized(table);
|
||||
|
||||
ASSERT_TRUE(table.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_NE(other.capacity(), 0u);
|
||||
ASSERT_EQ(other.size(), 2u);
|
||||
|
||||
table = std::move(other);
|
||||
test::is_initialized(other);
|
||||
|
||||
ASSERT_FALSE(table.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_NE(table.capacity(), 0u);
|
||||
ASSERT_EQ(table.size(), 2u);
|
||||
|
||||
other = {};
|
||||
table.swap(other);
|
||||
table = std::move(other);
|
||||
test::is_initialized(other);
|
||||
|
||||
ASSERT_FALSE(table.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_NE(table.capacity(), 0u);
|
||||
ASSERT_EQ(table.size(), 2u);
|
||||
|
||||
table.clear();
|
||||
|
||||
ASSERT_NE(table.capacity(), 0u);
|
||||
ASSERT_EQ(table.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Table, ThrowingAllocator) {
|
||||
test::throwing_allocator<void> allocator{};
|
||||
entt::basic_table<std::vector<int, test::throwing_allocator<int>>, std::vector<char, test::throwing_allocator<char>>> table{allocator};
|
||||
|
||||
allocator.throw_counter<int>(0u);
|
||||
|
||||
ASSERT_THROW(table.reserve(1u), test::throwing_allocator_exception);
|
||||
|
||||
allocator.throw_counter<int>(0u);
|
||||
allocator.throw_counter<char>(0u);
|
||||
|
||||
ASSERT_THROW(table.emplace(), test::throwing_allocator_exception);
|
||||
ASSERT_THROW(table.emplace(3, 'c'), test::throwing_allocator_exception);
|
||||
}
|
||||
91
lib/All/entt/test/entt/core/algorithm.cpp
Normal file
91
lib/All/entt/test/entt/core/algorithm.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/algorithm.hpp>
|
||||
#include "../../common/boxed_type.h"
|
||||
|
||||
TEST(Algorithm, StdSort) {
|
||||
// well, I'm pretty sure it works, it's std::sort!!
|
||||
std::array arr{4, 1, 3, 2, 0};
|
||||
const entt::std_sort sort;
|
||||
|
||||
sort(arr.begin(), arr.end());
|
||||
|
||||
ASSERT_TRUE(std::is_sorted(arr.begin(), arr.end()));
|
||||
}
|
||||
|
||||
TEST(Algorithm, StdSortBoxedInt) {
|
||||
// well, I'm pretty sure it works, it's std::sort!!
|
||||
std::array arr{test::boxed_int{4}, test::boxed_int{1}, test::boxed_int{3}, test::boxed_int{2}, test::boxed_int{0}, test::boxed_int{8}};
|
||||
const entt::std_sort sort;
|
||||
|
||||
sort(arr.begin(), arr.end(), [](const auto &lhs, const auto &rhs) {
|
||||
return lhs.value > rhs.value;
|
||||
});
|
||||
|
||||
ASSERT_TRUE(std::is_sorted(arr.rbegin(), arr.rend()));
|
||||
}
|
||||
|
||||
TEST(Algorithm, StdSortEmptyContainer) {
|
||||
std::vector<int> vec{};
|
||||
const entt::std_sort sort;
|
||||
// this should crash with asan enabled if we break the constraint
|
||||
sort(vec.begin(), vec.end());
|
||||
}
|
||||
|
||||
TEST(Algorithm, InsertionSort) {
|
||||
std::array arr{4, 1, 3, 2, 0};
|
||||
const entt::insertion_sort sort;
|
||||
|
||||
sort(arr.begin(), arr.end());
|
||||
|
||||
ASSERT_TRUE(std::is_sorted(arr.begin(), arr.end()));
|
||||
}
|
||||
|
||||
TEST(Algorithm, InsertionSortBoxedInt) {
|
||||
std::array arr{test::boxed_int{4}, test::boxed_int{1}, test::boxed_int{3}, test::boxed_int{2}, test::boxed_int{0}, test::boxed_int{8}};
|
||||
const entt::insertion_sort sort;
|
||||
|
||||
sort(arr.begin(), arr.end(), [](const auto &lhs, const auto &rhs) {
|
||||
return lhs.value > rhs.value;
|
||||
});
|
||||
|
||||
ASSERT_TRUE(std::is_sorted(arr.rbegin(), arr.rend()));
|
||||
}
|
||||
|
||||
TEST(Algorithm, InsertionSortEmptyContainer) {
|
||||
std::vector<int> vec{};
|
||||
const 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 arr{4u, 1u, 3u, 2u, 0u};
|
||||
const entt::radix_sort<8, 32> sort;
|
||||
|
||||
sort(arr.begin(), arr.end(), [](const auto &value) {
|
||||
return value;
|
||||
});
|
||||
|
||||
ASSERT_TRUE(std::is_sorted(arr.begin(), arr.end()));
|
||||
}
|
||||
|
||||
TEST(Algorithm, RadixSortBoxedInt) {
|
||||
std::array arr{test::boxed_int{4}, test::boxed_int{1}, test::boxed_int{3}, test::boxed_int{2}, test::boxed_int{0}, test::boxed_int{8}};
|
||||
const entt::radix_sort<2, 6> sort;
|
||||
|
||||
sort(arr.rbegin(), arr.rend(), [](const auto &instance) {
|
||||
return instance.value;
|
||||
});
|
||||
|
||||
ASSERT_TRUE(std::is_sorted(arr.rbegin(), arr.rend()));
|
||||
}
|
||||
|
||||
TEST(Algorithm, RadixSortEmptyContainer) {
|
||||
std::vector<int> vec{};
|
||||
const entt::radix_sort<8, 32> sort;
|
||||
// this should crash with asan enabled if we break the constraint
|
||||
sort(vec.begin(), vec.end());
|
||||
}
|
||||
1812
lib/All/entt/test/entt/core/any.cpp
Normal file
1812
lib/All/entt/test/entt/core/any.cpp
Normal file
File diff suppressed because it is too large
Load Diff
60
lib/All/entt/test/entt/core/bit.cpp
Normal file
60
lib/All/entt/test/entt/core/bit.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/bit.hpp>
|
||||
#include "../../common/config.h"
|
||||
|
||||
TEST(PopCount, Functionalities) {
|
||||
// constexpr-ness guaranteed
|
||||
constexpr auto zero_popcount = entt::popcount(0u);
|
||||
|
||||
ASSERT_EQ(zero_popcount, 0u);
|
||||
ASSERT_EQ(entt::popcount(1u), 1u);
|
||||
ASSERT_EQ(entt::popcount(2u), 1u);
|
||||
ASSERT_EQ(entt::popcount(3u), 2u);
|
||||
ASSERT_EQ(entt::popcount(7u), 3u);
|
||||
ASSERT_EQ(entt::popcount(128u), 1u);
|
||||
ASSERT_EQ(entt::popcount(201u), 4u);
|
||||
}
|
||||
|
||||
TEST(HasSingleBit, Functionalities) {
|
||||
// constexpr-ness guaranteed
|
||||
constexpr auto zero_is_power_of_two = entt::has_single_bit(0u);
|
||||
|
||||
ASSERT_FALSE(zero_is_power_of_two);
|
||||
ASSERT_TRUE(entt::has_single_bit(1u));
|
||||
ASSERT_TRUE(entt::has_single_bit(2u));
|
||||
ASSERT_TRUE(entt::has_single_bit(4u));
|
||||
ASSERT_FALSE(entt::has_single_bit(7u));
|
||||
ASSERT_TRUE(entt::has_single_bit(128u));
|
||||
ASSERT_FALSE(entt::has_single_bit(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(static_cast<std::size_t>(std::pow(2, 16))), static_cast<std::size_t>(std::pow(2, 16)));
|
||||
ASSERT_EQ(entt::next_power_of_two(static_cast<std::size_t>(std::pow(2, 16) + 1u)), static_cast<std::size_t>(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);
|
||||
}
|
||||
149
lib/All/entt/test/entt/core/compressed_pair.cpp
Normal file
149
lib/All/entt/test/entt/core/compressed_pair.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/compressed_pair.hpp>
|
||||
#include "../../common/empty.h"
|
||||
#include "../../common/non_default_constructible.h"
|
||||
|
||||
TEST(CompressedPair, Size) {
|
||||
struct local {
|
||||
int value;
|
||||
test::empty empty;
|
||||
};
|
||||
|
||||
ASSERT_EQ(sizeof(entt::compressed_pair<int, int>), sizeof(int) * 2u);
|
||||
ASSERT_EQ(sizeof(entt::compressed_pair<test::empty, int>), sizeof(int));
|
||||
ASSERT_EQ(sizeof(entt::compressed_pair<int, test::empty>), sizeof(int));
|
||||
ASSERT_LT(sizeof(entt::compressed_pair<int, test::empty>), sizeof(local));
|
||||
ASSERT_LT(sizeof(entt::compressed_pair<int, test::empty>), sizeof(std::pair<int, test::empty>));
|
||||
}
|
||||
|
||||
TEST(CompressedPair, ConstructCopyMove) {
|
||||
static_assert(!std::is_default_constructible_v<entt::compressed_pair<test::non_default_constructible, test::empty>>, "Default constructible type not allowed");
|
||||
static_assert(std::is_default_constructible_v<entt::compressed_pair<std::unique_ptr<int>, test::empty>>, "Default constructible type required");
|
||||
|
||||
static_assert(std::is_copy_constructible_v<entt::compressed_pair<test::non_default_constructible, test::empty>>, "Copy constructible type required");
|
||||
static_assert(!std::is_copy_constructible_v<entt::compressed_pair<std::unique_ptr<int>, test::empty>>, "Copy constructible type not allowed");
|
||||
static_assert(std::is_copy_assignable_v<entt::compressed_pair<test::non_default_constructible, test::empty>>, "Copy assignable type required");
|
||||
static_assert(!std::is_copy_assignable_v<entt::compressed_pair<std::unique_ptr<int>, test::empty>>, "Copy assignable type not allowed");
|
||||
|
||||
static_assert(std::is_move_constructible_v<entt::compressed_pair<std::unique_ptr<int>, test::empty>>, "Move constructible type required");
|
||||
static_assert(std::is_move_assignable_v<entt::compressed_pair<std::unique_ptr<int>, test::empty>>, "Move assignable type required");
|
||||
|
||||
entt::compressed_pair copyable{test::non_default_constructible{2}, test::empty{}};
|
||||
auto by_copy{copyable};
|
||||
|
||||
ASSERT_EQ(by_copy.first().value, 2);
|
||||
|
||||
by_copy.first().value = 3;
|
||||
copyable = by_copy;
|
||||
|
||||
ASSERT_EQ(copyable.first().value, 3);
|
||||
|
||||
entt::compressed_pair<test::empty, std::unique_ptr<int>> movable{test::empty{}, std::make_unique<int>(1)};
|
||||
auto by_move{std::move(movable)};
|
||||
|
||||
ASSERT_TRUE(by_move.second());
|
||||
ASSERT_EQ(*by_move.second(), 1);
|
||||
|
||||
*by_move.second() = 3;
|
||||
movable = std::move(by_move);
|
||||
|
||||
ASSERT_TRUE(movable.second());
|
||||
ASSERT_EQ(*movable.second(), 3);
|
||||
}
|
||||
|
||||
TEST(CompressedPair, PiecewiseConstruct) {
|
||||
const entt::compressed_pair<test::empty, test::empty> empty{std::piecewise_construct, std::make_tuple(), std::make_tuple()};
|
||||
const entt::compressed_pair<std::vector<int>, std::size_t> pair{std::piecewise_construct, std::forward_as_tuple(std::vector<int>{2}), std::make_tuple(sizeof(empty))};
|
||||
|
||||
ASSERT_EQ(pair.first().size(), 1u);
|
||||
ASSERT_EQ(pair.second(), sizeof(empty));
|
||||
}
|
||||
|
||||
TEST(CompressedPair, DeductionGuide) {
|
||||
const int value = 2;
|
||||
const test::empty empty{};
|
||||
entt::compressed_pair pair{value, 3};
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(entt::compressed_pair{test::empty{}, empty}), entt::compressed_pair<test::empty, test::empty>>();
|
||||
testing::StaticAssertTypeEq<decltype(pair), entt::compressed_pair<int, int>>();
|
||||
|
||||
ASSERT_EQ(pair.first(), 2);
|
||||
ASSERT_EQ(pair.second(), 3);
|
||||
}
|
||||
|
||||
TEST(CompressedPair, Getters) {
|
||||
entt::compressed_pair pair{3, test::empty{}};
|
||||
const auto &cpair = pair;
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(pair.first()), int &>();
|
||||
testing::StaticAssertTypeEq<decltype(pair.second()), test::empty &>();
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(cpair.first()), const int &>();
|
||||
testing::StaticAssertTypeEq<decltype(cpair.second()), const test::empty &>();
|
||||
|
||||
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);
|
||||
|
||||
// NOLINTNEXTLINE(readability-qualified-auto)
|
||||
auto &[cfirst, csecond] = std::as_const(pair);
|
||||
|
||||
ASSERT_EQ(cfirst, 3);
|
||||
ASSERT_EQ(csecond, 4);
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(cfirst), const int>();
|
||||
testing::StaticAssertTypeEq<decltype(csecond), const int>();
|
||||
|
||||
auto [tfirst, tsecond] = entt::compressed_pair{32, 64};
|
||||
|
||||
ASSERT_EQ(tfirst, 32);
|
||||
ASSERT_EQ(tsecond, 64);
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(cfirst), const int>();
|
||||
testing::StaticAssertTypeEq<decltype(csecond), const int>();
|
||||
}
|
||||
53
lib/All/entt/test/entt/core/enum.cpp
Normal file
53
lib/All/entt/test/entt/core/enum.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/enum.hpp>
|
||||
#include "../../common/bitmask.h"
|
||||
|
||||
template<typename Type>
|
||||
struct Enum: testing::Test {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
using EnumTypes = ::testing::Types<test::enum_is_bitmask, test::enum_as_bitmask>;
|
||||
|
||||
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
lib/All/entt/test/entt/core/family.cpp
Normal file
22
lib/All/entt/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 &>);
|
||||
}
|
||||
218
lib/All/entt/test/entt/core/hashed_string.cpp
Normal file
218
lib/All/entt/test/entt/core/hashed_string.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
|
||||
struct BasicHashedString: ::testing::Test {
|
||||
static constexpr auto expected = std::conditional_t<
|
||||
std::is_same_v<entt::id_type, std::uint32_t>,
|
||||
std::integral_constant<std::uint32_t, 0xbf9cf968>,
|
||||
std::integral_constant<std::uint64_t, 0x85944171f73967e8>>::value;
|
||||
};
|
||||
|
||||
using HashedString = BasicHashedString;
|
||||
using HashedWString = BasicHashedString;
|
||||
|
||||
TEST_F(BasicHashedString, DeductionGuide) {
|
||||
testing::StaticAssertTypeEq<decltype(entt::basic_hashed_string{"foo"}), entt::hashed_string>();
|
||||
testing::StaticAssertTypeEq<decltype(entt::basic_hashed_string{L"foo"}), entt::hashed_wstring>();
|
||||
}
|
||||
|
||||
TEST_F(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);
|
||||
|
||||
const entt::hashed_string hs{"foobar"};
|
||||
|
||||
ASSERT_EQ(static_cast<hash_type>(hs), expected);
|
||||
ASSERT_EQ(hs.value(), expected);
|
||||
|
||||
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_F(HashedString, Empty) {
|
||||
using hash_type = entt::hashed_string::hash_type;
|
||||
|
||||
const entt::hashed_string hs{};
|
||||
|
||||
ASSERT_EQ(hs.size(), 0u);
|
||||
ASSERT_EQ(static_cast<hash_type>(hs), entt::internal::fnv_1a_params<>::offset);
|
||||
ASSERT_EQ(static_cast<const char *>(hs), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(HashedString, Correctness) {
|
||||
const char *foobar = "foobar";
|
||||
const std::string_view view{"foobar__", 6};
|
||||
|
||||
ASSERT_EQ(entt::hashed_string{foobar}, expected);
|
||||
ASSERT_EQ((entt::hashed_string{view.data(), view.size()}), expected);
|
||||
ASSERT_EQ(entt::hashed_string{"foobar"}, expected);
|
||||
|
||||
ASSERT_EQ(entt::hashed_string::value(foobar), expected);
|
||||
ASSERT_EQ(entt::hashed_string::value(view.data(), view.size()), expected);
|
||||
ASSERT_EQ(entt::hashed_string::value("foobar"), expected);
|
||||
|
||||
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_F(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_F(HashedString, Constexprness) {
|
||||
using namespace entt::literals;
|
||||
constexpr std::string_view view{"foobar__", 6};
|
||||
|
||||
ASSERT_EQ(entt::hashed_string{"quux"}, "quux"_hs);
|
||||
ASSERT_EQ(entt::hashed_string{"foobar"}, expected);
|
||||
|
||||
ASSERT_EQ(entt::hashed_string::value("quux"), "quux"_hs);
|
||||
ASSERT_EQ(entt::hashed_string::value("foobar"), expected);
|
||||
|
||||
ASSERT_EQ((entt::hashed_string{"quux", 4}), "quux"_hs);
|
||||
ASSERT_EQ((entt::hashed_string{view.data(), view.size()}), expected);
|
||||
|
||||
ASSERT_EQ((entt::hashed_string::value("quux", 4)), "quux"_hs);
|
||||
ASSERT_EQ((entt::hashed_string::value(view.data(), view.size())), expected);
|
||||
|
||||
ASSERT_LT(entt::hashed_string{"bar"}, "foo"_hs);
|
||||
ASSERT_LE(entt::hashed_string{"bar"}, "bar"_hs);
|
||||
|
||||
ASSERT_GT(entt::hashed_string{"foo"}, "bar"_hs);
|
||||
ASSERT_GE(entt::hashed_string{"foo"}, "foo"_hs);
|
||||
}
|
||||
|
||||
TEST_F(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);
|
||||
|
||||
const entt::hashed_wstring hws{L"foobar"};
|
||||
|
||||
ASSERT_EQ(static_cast<hash_type>(hws), expected);
|
||||
ASSERT_EQ(hws.value(), expected);
|
||||
|
||||
ASSERT_EQ(foo_hws, L"foo"_hws);
|
||||
ASSERT_NE(bar_hws, L"foo"_hws);
|
||||
}
|
||||
|
||||
TEST_F(HashedWString, Empty) {
|
||||
using hash_type = entt::hashed_wstring::hash_type;
|
||||
|
||||
const entt::hashed_wstring hws{};
|
||||
|
||||
ASSERT_EQ(hws.size(), 0u);
|
||||
ASSERT_EQ(static_cast<hash_type>(hws), entt::internal::fnv_1a_params<>::offset);
|
||||
ASSERT_EQ(static_cast<const wchar_t *>(hws), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(HashedWString, Correctness) {
|
||||
const wchar_t *foobar = L"foobar";
|
||||
const std::wstring_view view{L"foobar__", 6};
|
||||
|
||||
ASSERT_EQ(entt::hashed_wstring{foobar}, expected);
|
||||
ASSERT_EQ((entt::hashed_wstring{view.data(), view.size()}), expected);
|
||||
ASSERT_EQ(entt::hashed_wstring{L"foobar"}, expected);
|
||||
|
||||
ASSERT_EQ(entt::hashed_wstring::value(foobar), expected);
|
||||
ASSERT_EQ(entt::hashed_wstring::value(view.data(), view.size()), expected);
|
||||
ASSERT_EQ(entt::hashed_wstring::value(L"foobar"), expected);
|
||||
|
||||
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_F(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_F(HashedWString, Constexprness) {
|
||||
using namespace entt::literals;
|
||||
constexpr std::wstring_view view{L"foobar__", 6};
|
||||
|
||||
ASSERT_EQ(entt::hashed_wstring{L"quux"}, L"quux"_hws);
|
||||
ASSERT_EQ(entt::hashed_wstring{L"foobar"}, expected);
|
||||
|
||||
ASSERT_EQ(entt::hashed_wstring::value(L"quux"), L"quux"_hws);
|
||||
ASSERT_EQ(entt::hashed_wstring::value(L"foobar"), expected);
|
||||
|
||||
ASSERT_EQ((entt::hashed_wstring{L"quux", 4}), L"quux"_hws);
|
||||
ASSERT_EQ((entt::hashed_wstring{view.data(), view.size()}), expected);
|
||||
|
||||
ASSERT_EQ((entt::hashed_wstring::value(L"quux", 4)), L"quux"_hws);
|
||||
ASSERT_EQ((entt::hashed_wstring::value(view.data(), view.size())), expected);
|
||||
|
||||
ASSERT_LT(entt::hashed_wstring{L"bar"}, L"foo"_hws);
|
||||
ASSERT_LE(entt::hashed_wstring{L"bar"}, L"bar"_hws);
|
||||
|
||||
ASSERT_GT(entt::hashed_wstring{L"foo"}, L"bar"_hws);
|
||||
ASSERT_GE(entt::hashed_wstring{L"foo"}, L"foo"_hws);
|
||||
}
|
||||
33
lib/All/entt/test/entt/core/ident.cpp
Normal file
33
lib/All/entt/test/entt/core/ident.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <type_traits>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/ident.hpp>
|
||||
#include "../../common/boxed_type.h"
|
||||
#include "../../common/empty.h"
|
||||
|
||||
TEST(Ident, Uniqueness) {
|
||||
using id = entt::ident<test::empty, test::boxed_int>;
|
||||
constexpr test::empty instance;
|
||||
constexpr test::boxed_int other;
|
||||
|
||||
ASSERT_NE(id::value<test::empty>, id::value<test::boxed_int>);
|
||||
ASSERT_EQ(id::value<test::empty>, id::value<decltype(instance)>);
|
||||
ASSERT_NE(id::value<test::empty>, id::value<decltype(other)>);
|
||||
ASSERT_EQ(id::value<test::empty>, id::value<test::empty>);
|
||||
ASSERT_EQ(id::value<test::boxed_int>, id::value<test::boxed_int>);
|
||||
|
||||
// test uses in constant expressions
|
||||
switch(id::value<test::boxed_int>) {
|
||||
case id::value<test::boxed_int>:
|
||||
SUCCEED();
|
||||
break;
|
||||
case id::value<test::empty>:
|
||||
default:
|
||||
FAIL();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Identifier, SingleType) {
|
||||
using id = entt::ident<test::empty>;
|
||||
[[maybe_unused]] const std::integral_constant<id::value_type, id::value<test::empty>> ic;
|
||||
}
|
||||
52
lib/All/entt/test/entt/core/iterator.cpp
Normal file
52
lib/All/entt/test/entt/core/iterator.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/iterator.hpp>
|
||||
#include "../../common/boxed_type.h"
|
||||
|
||||
TEST(InputIteratorPointer, Functionalities) {
|
||||
entt::input_iterator_pointer ptr{test::boxed_int{0}};
|
||||
|
||||
ASSERT_EQ(ptr->value, 0);
|
||||
|
||||
ptr->value = 2;
|
||||
|
||||
ASSERT_EQ(ptr->value, 2);
|
||||
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_THROW(other = iterable);
|
||||
ASSERT_NO_THROW(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[1u]}) {
|
||||
ASSERT_EQ(value, 1);
|
||||
}
|
||||
}
|
||||
206
lib/All/entt/test/entt/core/memory.cpp
Normal file
206
lib/All/entt/test/entt/core/memory.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#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) {
|
||||
const std::shared_ptr<int> shared = std::make_shared<int>();
|
||||
auto *plain = &*shared;
|
||||
|
||||
ASSERT_EQ(entt::to_address(shared), plain);
|
||||
ASSERT_EQ(entt::to_address(plain), plain);
|
||||
}
|
||||
|
||||
TEST(PoccaPocmaAndPocs, Functionalities) {
|
||||
test::basic_test_allocator<int> lhs;
|
||||
test::basic_test_allocator<int> rhs;
|
||||
test::basic_test_allocator<int, std::false_type> no_pocs;
|
||||
|
||||
// code coverage purposes
|
||||
ASSERT_FALSE(lhs == rhs);
|
||||
ASSERT_NO_THROW(entt::propagate_on_container_swap(no_pocs, no_pocs));
|
||||
|
||||
// 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) {
|
||||
test::basic_test_allocator<int, std::false_type> lhs;
|
||||
test::basic_test_allocator<int, std::false_type> rhs;
|
||||
|
||||
ASSERT_DEATH(entt::propagate_on_container_swap(lhs, rhs), "");
|
||||
}
|
||||
|
||||
TEST(AllocateUnique, Functionalities) {
|
||||
test::throwing_allocator<test::throwing_type> allocator{};
|
||||
|
||||
allocator.throw_counter<test::throwing_type>(0u);
|
||||
|
||||
ASSERT_THROW((entt::allocate_unique<test::throwing_type>(allocator, false)), test::throwing_allocator_exception);
|
||||
ASSERT_THROW((entt::allocate_unique<test::throwing_type>(allocator, test::throwing_type{true})), test::throwing_type_exception);
|
||||
|
||||
std::unique_ptr<test::throwing_type, entt::allocation_deleter<test::throwing_allocator<test::throwing_type>>> ptr = entt::allocate_unique<test::throwing_type>(allocator, false);
|
||||
|
||||
ASSERT_TRUE(ptr);
|
||||
ASSERT_EQ(*ptr, false);
|
||||
|
||||
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>>>;
|
||||
[[maybe_unused]] const 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>>>;
|
||||
[[maybe_unused]] const 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 = 4;
|
||||
const auto args = entt::uses_allocator_construction_args<int>(std::allocator<int>{}, value);
|
||||
|
||||
ASSERT_EQ(std::tuple_size_v<decltype(args)>, 1u);
|
||||
testing::StaticAssertTypeEq<decltype(args), const std::tuple<const int &>>();
|
||||
ASSERT_EQ(std::get<0>(args), value);
|
||||
}
|
||||
|
||||
TEST(UsesAllocatorConstructionArgs, LeadingAllocatorConvention) {
|
||||
const auto value = 4;
|
||||
const auto args = entt::uses_allocator_construction_args<std::tuple<int, char>>(std::allocator<int>{}, value, 'c');
|
||||
|
||||
ASSERT_EQ(std::tuple_size_v<decltype(args)>, 4u);
|
||||
testing::StaticAssertTypeEq<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 = 4u;
|
||||
const auto args = entt::uses_allocator_construction_args<std::vector<int>>(std::allocator<int>{}, size);
|
||||
|
||||
ASSERT_EQ(std::tuple_size_v<decltype(args)>, 2u);
|
||||
testing::StaticAssertTypeEq<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 = 4u;
|
||||
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);
|
||||
|
||||
ASSERT_EQ(std::tuple_size_v<decltype(args)>, 3u);
|
||||
testing::StaticAssertTypeEq<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>{});
|
||||
|
||||
ASSERT_EQ(std::tuple_size_v<decltype(args)>, 3u);
|
||||
testing::StaticAssertTypeEq<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<>, std::tuple<const std::allocator<int> &>>>();
|
||||
}
|
||||
|
||||
TEST(UsesAllocatorConstructionArgs, PairValues) {
|
||||
const auto size = 4u;
|
||||
const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, 3, size);
|
||||
|
||||
ASSERT_EQ(std::tuple_size_v<decltype(args)>, 3u);
|
||||
testing::StaticAssertTypeEq<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, 4u);
|
||||
const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, value);
|
||||
|
||||
ASSERT_EQ(std::tuple_size_v<decltype(args)>, 3u);
|
||||
testing::StaticAssertTypeEq<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)), 4u);
|
||||
}
|
||||
|
||||
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, 4u));
|
||||
|
||||
ASSERT_EQ(std::tuple_size_v<decltype(args)>, 3u);
|
||||
testing::StaticAssertTypeEq<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 = 4u;
|
||||
test::throwing_allocator<int> allocator{};
|
||||
|
||||
allocator.throw_counter<int>(0u);
|
||||
|
||||
ASSERT_THROW((entt::make_obj_using_allocator<std::vector<int, test::throwing_allocator<int>>>(allocator, size)), test::throwing_allocator_exception);
|
||||
|
||||
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::array<std::byte, sizeof(int)> storage{};
|
||||
const std::allocator<int> allocator{};
|
||||
|
||||
// NOLINTNEXTLINE(*-reinterpret-cast)
|
||||
int *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<int *>(storage.data()), allocator, 1);
|
||||
|
||||
ASSERT_EQ(*value, 1);
|
||||
}
|
||||
|
||||
#if defined(ENTT_HAS_TRACKED_MEMORY_RESOURCE)
|
||||
# include <memory_resource>
|
||||
|
||||
TEST(UninitializedConstructUsingAllocator, UsesAllocatorConstruction) {
|
||||
using string_type = typename test::tracked_memory_resource::string_type;
|
||||
|
||||
test::tracked_memory_resource memory_resource{};
|
||||
const std::pmr::polymorphic_allocator<string_type> allocator{&memory_resource};
|
||||
alignas(string_type) std::array<std::byte, sizeof(string_type)> storage{};
|
||||
|
||||
// NOLINTNEXTLINE(*-reinterpret-cast)
|
||||
string_type *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<string_type *>(storage.data()), 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
lib/All/entt/test/entt/core/monostate.cpp
Normal file
22
lib/All/entt/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> = 2;
|
||||
|
||||
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, 2);
|
||||
}
|
||||
48
lib/All/entt/test/entt/core/tuple.cpp
Normal file
48
lib/All/entt/test/entt/core/tuple.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/tuple.hpp>
|
||||
|
||||
TEST(Tuple, IsTuple) {
|
||||
ASSERT_FALSE(entt::is_tuple_v<int>);
|
||||
ASSERT_TRUE(entt::is_tuple_v<std::tuple<>>);
|
||||
ASSERT_TRUE(entt::is_tuple_v<std::tuple<int>>);
|
||||
ASSERT_TRUE((entt::is_tuple_v<std::tuple<int, char>>));
|
||||
}
|
||||
|
||||
TEST(Tuple, UnwrapTuple) {
|
||||
auto single = std::make_tuple(2);
|
||||
auto multi = std::make_tuple(2, 'c');
|
||||
auto ref = std::forward_as_tuple(std::get<0>(single));
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(entt::unwrap_tuple(single)), int &>();
|
||||
testing::StaticAssertTypeEq<decltype(entt::unwrap_tuple(multi)), std::tuple<int, char> &>();
|
||||
testing::StaticAssertTypeEq<decltype(entt::unwrap_tuple(ref)), int &>();
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(entt::unwrap_tuple(std::move(single))), int &&>();
|
||||
testing::StaticAssertTypeEq<decltype(entt::unwrap_tuple(std::move(multi))), std::tuple<int, char> &&>();
|
||||
testing::StaticAssertTypeEq<decltype(entt::unwrap_tuple(std::move(ref))), int &>();
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(entt::unwrap_tuple(std::as_const(single))), const int &>();
|
||||
testing::StaticAssertTypeEq<decltype(entt::unwrap_tuple(std::as_const(multi))), const std::tuple<int, char> &>();
|
||||
testing::StaticAssertTypeEq<decltype(entt::unwrap_tuple(std::as_const(ref))), int &>();
|
||||
|
||||
ASSERT_EQ(entt::unwrap_tuple(single), 2);
|
||||
ASSERT_EQ(entt::unwrap_tuple(multi), multi);
|
||||
ASSERT_EQ(entt::unwrap_tuple(std::move(ref)), 2);
|
||||
}
|
||||
|
||||
TEST(Tuple, ForwardApply) {
|
||||
entt::forward_apply first{[](auto &&...args) { return sizeof...(args); }};
|
||||
entt::forward_apply second{[](int value) { return value; }};
|
||||
entt::forward_apply third{[](auto... args) { return (args + ...); }};
|
||||
|
||||
ASSERT_EQ(first(std::make_tuple()), 0u);
|
||||
ASSERT_EQ(std::as_const(first)(std::make_tuple()), 0u);
|
||||
|
||||
ASSERT_EQ(second(std::make_tuple(2)), 2);
|
||||
ASSERT_EQ(std::as_const(second)(std::make_tuple(2)), 2);
|
||||
|
||||
ASSERT_EQ(third(std::make_tuple('a', 1)), 'b');
|
||||
ASSERT_EQ(std::as_const(third)(std::make_tuple('a', 1)), 'b');
|
||||
}
|
||||
102
lib/All/entt/test/entt/core/type_info.cpp
Normal file
102
lib/All/entt/test/entt/core/type_info.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#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>, "Copy constructible type required");
|
||||
static_assert(std::is_move_constructible_v<entt::type_info>, "Move constructible type required");
|
||||
static_assert(std::is_copy_assignable_v<entt::type_info>, "Copy assignable type required");
|
||||
static_assert(std::is_move_assignable_v<entt::type_info>, "Move assignable type required");
|
||||
|
||||
const 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());
|
||||
}
|
||||
|
||||
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 = 4;
|
||||
|
||||
ASSERT_EQ(entt::type_id(value), entt::type_id<int>());
|
||||
ASSERT_EQ(entt::type_id(4), 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>());
|
||||
}
|
||||
279
lib/All/entt/test/entt/core/type_traits.cpp
Normal file
279
lib/All/entt/test/entt/core/type_traits.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#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>
|
||||
#include "../../common/non_comparable.h"
|
||||
|
||||
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 value) {
|
||||
return static_cast<char>(quux = (value != 0));
|
||||
}
|
||||
|
||||
[[nodiscard]] int bar(double, float) const {
|
||||
return static_cast<int>(quux);
|
||||
}
|
||||
|
||||
bool quux;
|
||||
};
|
||||
|
||||
int free_function(int, const double &) {
|
||||
return 64;
|
||||
}
|
||||
|
||||
template<typename, typename Type = void>
|
||||
struct multi_argument_operation {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
struct UnpackAsType: ::testing::Test {
|
||||
template<typename Type, typename... Args>
|
||||
static auto test_for() {
|
||||
return [](entt::unpack_as_type<Type, Args>... value) {
|
||||
return (value + ... + Type{});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct UnpackAsValue: ::testing::Test {
|
||||
template<auto Value>
|
||||
static auto test_for() {
|
||||
return [](auto &&...args) {
|
||||
return (entt::unpack_as_value<Value, decltype(args)> + ... + 0);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
TEST(SizeOf, Functionalities) {
|
||||
ASSERT_EQ(entt::size_of_v<void>, 0u);
|
||||
ASSERT_EQ(entt::size_of_v<char>, sizeof(char));
|
||||
// NOLINTBEGIN(*-avoid-c-arrays)
|
||||
ASSERT_EQ(entt::size_of_v<int[]>, 0u);
|
||||
ASSERT_EQ(entt::size_of_v<int[3]>, sizeof(int[3]));
|
||||
// NOLINTEND(*-avoid-c-arrays)
|
||||
}
|
||||
|
||||
TEST_F(UnpackAsType, Functionalities) {
|
||||
ASSERT_EQ((this->test_for<int, char, double, bool>()(1, 2, 3)), 6);
|
||||
ASSERT_EQ((this->test_for<float, void, int>()(2.f, 2.2f)), 4.2f);
|
||||
}
|
||||
|
||||
TEST_F(UnpackAsValue, Functionalities) {
|
||||
ASSERT_EQ((this->test_for<2>()('c', 1., true)), 6);
|
||||
ASSERT_EQ((this->test_for<true>()('c', 2.)), 2);
|
||||
}
|
||||
|
||||
TEST(IntegralConstant, Functionalities) {
|
||||
const entt::integral_constant<3> constant{};
|
||||
|
||||
testing::StaticAssertTypeEq<typename entt::integral_constant<3>::value_type, int>();
|
||||
ASSERT_EQ(constant.value, 3);
|
||||
}
|
||||
|
||||
TEST(Choice, Functionalities) {
|
||||
static_assert(std::is_base_of_v<entt::choice_t<0>, entt::choice_t<1>>, "Base type required");
|
||||
static_assert(!std::is_base_of_v<entt::choice_t<1>, entt::choice_t<0>>, "Base type not allowed");
|
||||
}
|
||||
|
||||
TEST(TypeList, Functionalities) {
|
||||
using type = entt::type_list<int, char>;
|
||||
using other = entt::type_list<double>;
|
||||
|
||||
ASSERT_EQ(type::size, 2u);
|
||||
ASSERT_EQ(other::size, 1u);
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(type{} + other{}), entt::type_list<int, char, double>>();
|
||||
testing::StaticAssertTypeEq<entt::type_list_cat_t<type, other, type, other>, entt::type_list<int, char, double, int, char, double>>();
|
||||
testing::StaticAssertTypeEq<entt::type_list_cat_t<type, other>, entt::type_list<int, char, double>>();
|
||||
testing::StaticAssertTypeEq<entt::type_list_cat_t<type, type>, entt::type_list<int, char, int, char>>();
|
||||
testing::StaticAssertTypeEq<entt::type_list_unique_t<entt::type_list_cat_t<type, type>>, type>();
|
||||
|
||||
ASSERT_TRUE((entt::type_list_contains_v<type, int>));
|
||||
ASSERT_TRUE((entt::type_list_contains_v<type, char>));
|
||||
ASSERT_FALSE((entt::type_list_contains_v<type, double>));
|
||||
|
||||
testing::StaticAssertTypeEq<entt::type_list_element_t<0u, type>, int>();
|
||||
testing::StaticAssertTypeEq<entt::type_list_element_t<1u, type>, char>();
|
||||
testing::StaticAssertTypeEq<entt::type_list_element_t<0u, other>, double>();
|
||||
|
||||
ASSERT_EQ((entt::type_list_index_v<int, type>), 0u);
|
||||
ASSERT_EQ((entt::type_list_index_v<char, type>), 1u);
|
||||
ASSERT_EQ((entt::type_list_index_v<double, other>), 0u);
|
||||
|
||||
testing::StaticAssertTypeEq<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<float, bool>>, entt::type_list<int, char, double>>();
|
||||
testing::StaticAssertTypeEq<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<int, char, double>>, entt::type_list<>>();
|
||||
testing::StaticAssertTypeEq<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<int, char>>, entt::type_list<double>>();
|
||||
testing::StaticAssertTypeEq<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<char, double>>, entt::type_list<int>>();
|
||||
testing::StaticAssertTypeEq<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<char>>, entt::type_list<int, double>>();
|
||||
|
||||
testing::StaticAssertTypeEq<entt::type_list_transform_t<entt::type_list<int, char>, entt::type_identity>, entt::type_list<int, char>>();
|
||||
testing::StaticAssertTypeEq<entt::type_list_transform_t<entt::type_list<int, char>, std::add_const>, entt::type_list<const int, const char>>();
|
||||
testing::StaticAssertTypeEq<entt::type_list_transform_t<entt::type_list<int, char>, multi_argument_operation>, entt::type_list<void, void>>();
|
||||
|
||||
ASSERT_EQ(std::tuple_size_v<entt::type_list<>>, 0u);
|
||||
ASSERT_EQ(std::tuple_size_v<entt::type_list<int>>, 1u);
|
||||
ASSERT_EQ((std::tuple_size_v<entt::type_list<int, float>>), 2u);
|
||||
|
||||
testing::StaticAssertTypeEq<int, std::tuple_element_t<0, entt::type_list<int>>>();
|
||||
testing::StaticAssertTypeEq<int, std::tuple_element_t<0, entt::type_list<int, float>>>();
|
||||
testing::StaticAssertTypeEq<float, std::tuple_element_t<1, entt::type_list<int, float>>>();
|
||||
}
|
||||
|
||||
TEST(ValueList, Functionalities) {
|
||||
using value = entt::value_list<0, 2>;
|
||||
using other = entt::value_list<1>;
|
||||
|
||||
ASSERT_EQ(value::size, 2u);
|
||||
ASSERT_EQ(other::size, 1u);
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(value{} + other{}), entt::value_list<0, 2, 1>>();
|
||||
testing::StaticAssertTypeEq<entt::value_list_cat_t<value, other, value, other>, entt::value_list<0, 2, 1, 0, 2, 1>>();
|
||||
testing::StaticAssertTypeEq<entt::value_list_cat_t<value, other>, entt::value_list<0, 2, 1>>();
|
||||
testing::StaticAssertTypeEq<entt::value_list_cat_t<value, value>, entt::value_list<0, 2, 0, 2>>();
|
||||
testing::StaticAssertTypeEq<entt::value_list_unique_t<entt::value_list_cat_t<value, value>>, value>();
|
||||
|
||||
ASSERT_TRUE((entt::value_list_contains_v<value, 0>));
|
||||
ASSERT_TRUE((entt::value_list_contains_v<value, 2>));
|
||||
ASSERT_FALSE((entt::value_list_contains_v<value, 1>));
|
||||
|
||||
ASSERT_EQ((entt::value_list_element_v<0u, value>), 0);
|
||||
ASSERT_EQ((entt::value_list_element_v<1u, value>), 2);
|
||||
ASSERT_EQ((entt::value_list_element_v<0u, other>), 1);
|
||||
|
||||
ASSERT_EQ((entt::value_list_index_v<0, value>), 0u);
|
||||
ASSERT_EQ((entt::value_list_index_v<2, value>), 1u);
|
||||
ASSERT_EQ((entt::value_list_index_v<1, other>), 0u);
|
||||
|
||||
testing::StaticAssertTypeEq<entt::value_list_diff_t<entt::value_list<0, 1, 2>, entt::value_list<3, 4>>, entt::value_list<0, 1, 2>>();
|
||||
testing::StaticAssertTypeEq<entt::value_list_diff_t<entt::value_list<0, 1, 2>, entt::value_list<0, 1, 2>>, entt::value_list<>>();
|
||||
testing::StaticAssertTypeEq<entt::value_list_diff_t<entt::value_list<0, 1, 2>, entt::value_list<0, 1>>, entt::value_list<2>>();
|
||||
testing::StaticAssertTypeEq<entt::value_list_diff_t<entt::value_list<0, 1, 2>, entt::value_list<1, 2>>, entt::value_list<0>>();
|
||||
testing::StaticAssertTypeEq<entt::value_list_diff_t<entt::value_list<0, 1, 2>, entt::value_list<1>>, entt::value_list<0, 2>>();
|
||||
|
||||
ASSERT_EQ((std::tuple_size_v<entt::value_list<>>), 0u);
|
||||
ASSERT_EQ((std::tuple_size_v<entt::value_list<4>>), 1u);
|
||||
ASSERT_EQ((std::tuple_size_v<entt::value_list<4, 'a'>>), 2u);
|
||||
|
||||
testing::StaticAssertTypeEq<int, std::tuple_element_t<0, entt::value_list<4>>>();
|
||||
testing::StaticAssertTypeEq<int, std::tuple_element_t<0, entt::value_list<4, 'a'>>>();
|
||||
testing::StaticAssertTypeEq<char, std::tuple_element_t<1, entt::value_list<4, 'a'>>>();
|
||||
}
|
||||
|
||||
TEST(IsApplicable, Functionalities) {
|
||||
ASSERT_TRUE((entt::is_applicable_v<void(int, char), std::tuple<double, char>>));
|
||||
ASSERT_FALSE((entt::is_applicable_v<void(int, char), std::tuple<int>>));
|
||||
|
||||
ASSERT_TRUE((entt::is_applicable_r_v<float, int(int, char), std::tuple<double, char>>));
|
||||
ASSERT_FALSE((entt::is_applicable_r_v<float, void(int, char), std::tuple<double, char>>));
|
||||
ASSERT_FALSE((entt::is_applicable_r_v<int, int(int, char), std::tuple<void>>));
|
||||
}
|
||||
|
||||
TEST(IsComplete, Functionalities) {
|
||||
ASSERT_FALSE(entt::is_complete_v<void>);
|
||||
ASSERT_TRUE(entt::is_complete_v<int>);
|
||||
}
|
||||
|
||||
TEST(IsIterator, Functionalities) {
|
||||
ASSERT_FALSE(entt::is_iterator_v<void>);
|
||||
ASSERT_FALSE(entt::is_iterator_v<int>);
|
||||
|
||||
ASSERT_FALSE(entt::is_iterator_v<void *>);
|
||||
ASSERT_TRUE(entt::is_iterator_v<int *>);
|
||||
|
||||
ASSERT_TRUE(entt::is_iterator_v<std::vector<int>::iterator>);
|
||||
ASSERT_TRUE(entt::is_iterator_v<std::vector<int>::const_iterator>);
|
||||
ASSERT_TRUE(entt::is_iterator_v<std::vector<int>::reverse_iterator>);
|
||||
}
|
||||
|
||||
TEST(IsEBCOEligible, Functionalities) {
|
||||
ASSERT_TRUE(entt::is_ebco_eligible_v<test::non_comparable>);
|
||||
ASSERT_FALSE(entt::is_ebco_eligible_v<nlohmann_json_like>);
|
||||
ASSERT_FALSE(entt::is_ebco_eligible_v<double>);
|
||||
ASSERT_FALSE(entt::is_ebco_eligible_v<void>);
|
||||
}
|
||||
|
||||
TEST(IsTransparent, Functionalities) {
|
||||
ASSERT_FALSE(entt::is_transparent_v<std::less<int>>);
|
||||
ASSERT_TRUE(entt::is_transparent_v<std::less<void>>);
|
||||
ASSERT_FALSE(entt::is_transparent_v<std::logical_not<double>>);
|
||||
ASSERT_TRUE(entt::is_transparent_v<std::logical_not<void>>);
|
||||
}
|
||||
|
||||
TEST(IsEqualityComparable, Functionalities) {
|
||||
ASSERT_TRUE(entt::is_equality_comparable_v<int>);
|
||||
ASSERT_TRUE(entt::is_equality_comparable_v<const int>);
|
||||
ASSERT_TRUE(entt::is_equality_comparable_v<std::vector<int>>);
|
||||
ASSERT_TRUE(entt::is_equality_comparable_v<std::vector<std::vector<int>>>);
|
||||
ASSERT_TRUE((entt::is_equality_comparable_v<std::unordered_map<int, int>>));
|
||||
ASSERT_TRUE((entt::is_equality_comparable_v<std::unordered_map<int, std::unordered_map<int, char>>>));
|
||||
ASSERT_TRUE((entt::is_equality_comparable_v<std::pair<const int, int>>));
|
||||
ASSERT_TRUE((entt::is_equality_comparable_v<std::pair<const int, std::unordered_map<int, char>>>));
|
||||
ASSERT_TRUE(entt::is_equality_comparable_v<std::vector<test::non_comparable>::iterator>);
|
||||
ASSERT_TRUE((entt::is_equality_comparable_v<std::optional<int>>));
|
||||
ASSERT_TRUE(entt::is_equality_comparable_v<nlohmann_json_like>);
|
||||
|
||||
// NOLINTNEXTLINE(*-avoid-c-arrays)
|
||||
ASSERT_FALSE(entt::is_equality_comparable_v<int[3u]>);
|
||||
ASSERT_FALSE(entt::is_equality_comparable_v<test::non_comparable>);
|
||||
ASSERT_FALSE(entt::is_equality_comparable_v<const test::non_comparable>);
|
||||
ASSERT_FALSE(entt::is_equality_comparable_v<std::vector<test::non_comparable>>);
|
||||
ASSERT_FALSE(entt::is_equality_comparable_v<std::vector<std::vector<test::non_comparable>>>);
|
||||
ASSERT_FALSE((entt::is_equality_comparable_v<std::unordered_map<int, test::non_comparable>>));
|
||||
ASSERT_FALSE((entt::is_equality_comparable_v<std::unordered_map<int, std::unordered_map<int, test::non_comparable>>>));
|
||||
ASSERT_FALSE((entt::is_equality_comparable_v<std::pair<const int, test::non_comparable>>));
|
||||
ASSERT_FALSE((entt::is_equality_comparable_v<std::pair<const int, std::unordered_map<int, test::non_comparable>>>));
|
||||
ASSERT_FALSE((entt::is_equality_comparable_v<std::optional<test::non_comparable>>));
|
||||
ASSERT_FALSE(entt::is_equality_comparable_v<void>);
|
||||
}
|
||||
|
||||
TEST(ConstnessAs, Functionalities) {
|
||||
testing::StaticAssertTypeEq<entt::constness_as_t<int, char>, int>();
|
||||
testing::StaticAssertTypeEq<entt::constness_as_t<const int, char>, int>();
|
||||
testing::StaticAssertTypeEq<entt::constness_as_t<int, const char>, const int>();
|
||||
testing::StaticAssertTypeEq<entt::constness_as_t<const int, const char>, const int>();
|
||||
}
|
||||
|
||||
TEST(MemberClass, Functionalities) {
|
||||
testing::StaticAssertTypeEq<clazz, entt::member_class_t<decltype(&clazz::foo)>>();
|
||||
testing::StaticAssertTypeEq<clazz, entt::member_class_t<decltype(&clazz::bar)>>();
|
||||
testing::StaticAssertTypeEq<clazz, entt::member_class_t<decltype(&clazz::quux)>>();
|
||||
}
|
||||
|
||||
TEST(NthArgument, Functionalities) {
|
||||
testing::StaticAssertTypeEq<entt::nth_argument_t<0u, void(int, char, bool)>, int>();
|
||||
testing::StaticAssertTypeEq<entt::nth_argument_t<1u, void(int, char, bool)>, char>();
|
||||
testing::StaticAssertTypeEq<entt::nth_argument_t<2u, void(int, char, bool)>, bool>();
|
||||
|
||||
testing::StaticAssertTypeEq<entt::nth_argument_t<0u, decltype(&free_function)>, int>();
|
||||
testing::StaticAssertTypeEq<entt::nth_argument_t<1u, decltype(&free_function)>, const double &>();
|
||||
|
||||
testing::StaticAssertTypeEq<entt::nth_argument_t<0u, decltype(&clazz::bar)>, double>();
|
||||
testing::StaticAssertTypeEq<entt::nth_argument_t<1u, decltype(&clazz::bar)>, float>();
|
||||
testing::StaticAssertTypeEq<entt::nth_argument_t<0u, decltype(&clazz::quux)>, bool>();
|
||||
|
||||
ASSERT_EQ(free_function(entt::nth_argument_t<0u, decltype(&free_function)>{}, entt::nth_argument_t<1u, decltype(&free_function)>{}), 64);
|
||||
|
||||
[[maybe_unused]] auto lambda = [value = 0u](int, float &) { return value; };
|
||||
|
||||
testing::StaticAssertTypeEq<entt::nth_argument_t<0u, decltype(lambda)>, int>();
|
||||
testing::StaticAssertTypeEq<entt::nth_argument_t<1u, decltype(lambda)>, float &>();
|
||||
}
|
||||
|
||||
TEST(Tag, Functionalities) {
|
||||
using namespace entt::literals;
|
||||
ASSERT_EQ(entt::tag<"foobar"_hs>::value, entt::hashed_string::value("foobar"));
|
||||
testing::StaticAssertTypeEq<typename entt::tag<"foobar"_hs>::value_type, entt::id_type>();
|
||||
}
|
||||
62
lib/All/entt/test/entt/core/utility.cpp
Normal file
62
lib/All/entt/test/entt/core/utility.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#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) {
|
||||
const entt::identity identity;
|
||||
int value = 2;
|
||||
|
||||
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;
|
||||
instance.bar(0); // makes the linter happy
|
||||
|
||||
ASSERT_NO_THROW(entt::overload<void(int)>(&functions::foo)(0));
|
||||
ASSERT_NO_THROW(entt::overload<void()>(&functions::foo)());
|
||||
|
||||
ASSERT_NO_THROW((instance.*entt::overload<void(int)>(&functions::bar))(0));
|
||||
ASSERT_NO_THROW((instance.*entt::overload<void()>(&functions::bar))());
|
||||
}
|
||||
|
||||
TEST(Overloaded, Functionalities) {
|
||||
int iv = 0;
|
||||
char cv = '\0';
|
||||
|
||||
const entt::overloaded func{
|
||||
[&iv](int value) { iv = value; },
|
||||
[&cv](char value) { cv = value; }};
|
||||
|
||||
func(2);
|
||||
func('c');
|
||||
|
||||
ASSERT_EQ(iv, 2);
|
||||
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);
|
||||
}
|
||||
35
lib/All/entt/test/entt/entity/BUILD.bazel
Normal file
35
lib/All/entt/test/entt/entity/BUILD.bazel
Normal file
@@ -0,0 +1,35 @@
|
||||
load("@entt//bazel:copts.bzl", "COPTS")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_test")
|
||||
|
||||
# buildifier: keep sorted
|
||||
_TESTS = [
|
||||
"component",
|
||||
"entity",
|
||||
"group",
|
||||
"handle",
|
||||
"helper",
|
||||
"organizer",
|
||||
"reactive_mixin",
|
||||
"registry",
|
||||
"runtime_view",
|
||||
"sigh_mixin",
|
||||
"snapshot",
|
||||
"sparse_set",
|
||||
"storage",
|
||||
"storage_entity",
|
||||
"storage_no_instance",
|
||||
"storage_utility",
|
||||
"view",
|
||||
]
|
||||
|
||||
[cc_test(
|
||||
name = test,
|
||||
srcs = ["{}.cpp".format(test)],
|
||||
copts = COPTS,
|
||||
deps = [
|
||||
"//common",
|
||||
"@entt",
|
||||
"@googletest//:gtest",
|
||||
"@googletest//:gtest_main",
|
||||
],
|
||||
) for test in _TESTS]
|
||||
107
lib/All/entt/test/entt/entity/component.cpp
Normal file
107
lib/All/entt/test/entt/entity/component.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
#include <type_traits>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/config/config.h>
|
||||
#include <entt/entity/component.hpp>
|
||||
#include "../../common/boxed_type.h"
|
||||
#include "../../common/empty.h"
|
||||
#include "../../common/entity.h"
|
||||
#include "../../common/non_movable.h"
|
||||
|
||||
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 /*, entt::entity */> {
|
||||
using entity_type = entt::entity;
|
||||
using element_type = traits_based;
|
||||
|
||||
static constexpr auto in_place_delete = true;
|
||||
static constexpr auto page_size = 8u;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct entt::component_traits<traits_based, test::entity> {
|
||||
using entity_type = test::entity;
|
||||
using element_type = traits_based;
|
||||
|
||||
static constexpr auto in_place_delete = false;
|
||||
static constexpr auto page_size = 16u;
|
||||
};
|
||||
|
||||
template<typename Entity>
|
||||
struct entt::component_traits<traits_based, Entity> {
|
||||
using entity_type = Entity;
|
||||
using element_type = traits_based;
|
||||
|
||||
static constexpr auto in_place_delete = true;
|
||||
static constexpr auto page_size = 32u;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct Component: testing::Test {
|
||||
using entity_type = Type;
|
||||
};
|
||||
|
||||
using EntityTypes = ::testing::Types<entt::entity, test::entity, test::other_entity>;
|
||||
|
||||
TYPED_TEST_SUITE(Component, EntityTypes, );
|
||||
|
||||
TYPED_TEST(Component, VoidType) {
|
||||
using entity_type = typename TestFixture::entity_type;
|
||||
using traits_type = entt::component_traits<void, entity_type>;
|
||||
|
||||
ASSERT_FALSE(traits_type::in_place_delete);
|
||||
ASSERT_EQ(traits_type::page_size, 0u);
|
||||
}
|
||||
|
||||
TYPED_TEST(Component, Empty) {
|
||||
using entity_type = typename TestFixture::entity_type;
|
||||
using traits_type = entt::component_traits<test::empty, entity_type>;
|
||||
|
||||
ASSERT_FALSE(traits_type::in_place_delete);
|
||||
ASSERT_EQ(traits_type::page_size, 0u);
|
||||
}
|
||||
|
||||
TYPED_TEST(Component, NonEmpty) {
|
||||
using entity_type = typename TestFixture::entity_type;
|
||||
using traits_type = entt::component_traits<test::boxed_int, entity_type>;
|
||||
|
||||
ASSERT_FALSE(traits_type::in_place_delete);
|
||||
ASSERT_EQ(traits_type::page_size, ENTT_PACKED_PAGE);
|
||||
}
|
||||
|
||||
TYPED_TEST(Component, NonMovable) {
|
||||
using entity_type = typename TestFixture::entity_type;
|
||||
using traits_type = entt::component_traits<test::non_movable, entity_type>;
|
||||
|
||||
ASSERT_TRUE(traits_type::in_place_delete);
|
||||
ASSERT_EQ(traits_type::page_size, ENTT_PACKED_PAGE);
|
||||
}
|
||||
|
||||
TYPED_TEST(Component, SelfContained) {
|
||||
using entity_type = typename TestFixture::entity_type;
|
||||
using traits_type = entt::component_traits<self_contained, entity_type>;
|
||||
|
||||
ASSERT_TRUE(traits_type::in_place_delete);
|
||||
ASSERT_EQ(traits_type::page_size, 4u);
|
||||
}
|
||||
|
||||
TYPED_TEST(Component, TraitsBased) {
|
||||
using entity_type = typename TestFixture::entity_type;
|
||||
using traits_type = entt::component_traits<traits_based, entity_type>;
|
||||
|
||||
if constexpr(std::is_same_v<entity_type, entt::entity>) {
|
||||
ASSERT_TRUE(traits_type::in_place_delete);
|
||||
ASSERT_EQ(traits_type::page_size, 8u);
|
||||
} else if constexpr(std::is_same_v<entity_type, test::entity>) {
|
||||
ASSERT_FALSE(traits_type::in_place_delete);
|
||||
ASSERT_EQ(traits_type::page_size, 16u);
|
||||
} else {
|
||||
ASSERT_TRUE(traits_type::in_place_delete);
|
||||
ASSERT_EQ(traits_type::page_size, 32u);
|
||||
}
|
||||
}
|
||||
163
lib/All/entt/test/entt/entity/entity.cpp
Normal file
163
lib/All/entt/test/entt/entity/entity.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/config/config.h>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include "../../common/entity.h"
|
||||
|
||||
struct entity_traits {
|
||||
using value_type = test::entity;
|
||||
using entity_type = std::uint32_t;
|
||||
using version_type = std::uint16_t;
|
||||
static constexpr entity_type entity_mask = 0x3FFFF; // 18b
|
||||
static constexpr entity_type version_mask = 0x0FFF; // 12b
|
||||
};
|
||||
|
||||
struct other_entity_traits {
|
||||
using value_type = test::other_entity;
|
||||
using entity_type = std::uint32_t;
|
||||
using version_type = std::uint16_t;
|
||||
static constexpr entity_type entity_mask = 0xFFFFFFFF; // 32b
|
||||
static constexpr entity_type version_mask = 0x00; // 0b
|
||||
};
|
||||
|
||||
template<>
|
||||
struct entt::entt_traits<test::entity>: entt::basic_entt_traits<entity_traits> {
|
||||
static constexpr std::size_t page_size = ENTT_SPARSE_PAGE;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct entt::entt_traits<test::other_entity>: entt::basic_entt_traits<other_entity_traits> {
|
||||
static constexpr std::size_t page_size = ENTT_SPARSE_PAGE;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct Entity: testing::Test {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
using EntityTypes = ::testing::Types<entt::entity, test::entity, test::other_entity>;
|
||||
|
||||
TYPED_TEST_SUITE(Entity, EntityTypes, );
|
||||
|
||||
TYPED_TEST(Entity, Traits) {
|
||||
using entity_type = typename TestFixture::type;
|
||||
using traits_type = entt::entt_traits<entity_type>;
|
||||
|
||||
constexpr entity_type tombstone{entt::tombstone};
|
||||
constexpr entity_type null{entt::null};
|
||||
|
||||
const entity_type entity = traits_type::construct(4u, 1u);
|
||||
const entity_type other = traits_type::construct(3u, 0u);
|
||||
|
||||
ASSERT_EQ(entt::to_integral(entity), entt::to_integral(entity));
|
||||
ASSERT_NE(entt::to_integral(entity), entt::to_integral<entity_type>(entt::null));
|
||||
ASSERT_NE(entt::to_integral(entity), entt::to_integral(entity_type{}));
|
||||
|
||||
ASSERT_EQ(entt::to_entity(entity), 4u);
|
||||
ASSERT_EQ(entt::to_version(entity), !!traits_type::version_mask);
|
||||
|
||||
ASSERT_EQ(entt::to_entity(other), 3u);
|
||||
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);
|
||||
|
||||
if constexpr(traits_type::version_mask == 0u) {
|
||||
ASSERT_EQ(traits_type::construct(entt::to_entity(entity), entt::to_version(other)), entity);
|
||||
} else {
|
||||
ASSERT_NE(traits_type::construct(entt::to_entity(entity), entt::to_version(other)), 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);
|
||||
|
||||
ASSERT_EQ(traits_type::next(entity), traits_type::construct(entt::to_integral(entity), entt::to_version(entity) + 1u));
|
||||
ASSERT_EQ(traits_type::next(other), traits_type::construct(entt::to_integral(other), entt::to_version(other) + 1u));
|
||||
|
||||
ASSERT_EQ(traits_type::next(entt::tombstone), traits_type::construct(entt::null, {}));
|
||||
ASSERT_EQ(traits_type::next(entt::null), traits_type::construct(entt::null, {}));
|
||||
|
||||
if constexpr(traits_type::to_integral(tombstone) != ~typename traits_type::entity_type{}) {
|
||||
// test reserved bits, if any
|
||||
constexpr entity_type reserved{traits_type::to_integral(entity) | (traits_type::to_integral(tombstone) + 1u)};
|
||||
|
||||
ASSERT_NE(reserved, entity);
|
||||
|
||||
ASSERT_NE(traits_type::to_integral(null), ~typename traits_type::entity_type{});
|
||||
ASSERT_NE(traits_type::to_integral(tombstone), ~typename traits_type::entity_type{});
|
||||
|
||||
ASSERT_EQ(traits_type::to_entity(reserved), traits_type::to_entity(entity));
|
||||
ASSERT_EQ(traits_type::to_version(reserved), traits_type::to_version(entity));
|
||||
|
||||
ASSERT_EQ(traits_type::to_version(null), traits_type::version_mask);
|
||||
ASSERT_EQ(traits_type::to_version(tombstone), traits_type::version_mask);
|
||||
|
||||
ASSERT_EQ(traits_type::to_version(traits_type::next(null)), 0u);
|
||||
ASSERT_EQ(traits_type::to_version(traits_type::next(tombstone)), 0u);
|
||||
|
||||
ASSERT_EQ(traits_type::construct(traits_type::to_integral(entity), traits_type::version_mask + 1u), entity_type{traits_type::to_entity(entity)});
|
||||
|
||||
ASSERT_EQ(traits_type::construct(traits_type::to_integral(null), traits_type::to_version(null) + 1u), entity_type{traits_type::to_entity(null)});
|
||||
ASSERT_EQ(traits_type::construct(traits_type::to_integral(tombstone), traits_type::to_version(tombstone) + 1u), entity_type{traits_type::to_entity(tombstone)});
|
||||
|
||||
ASSERT_EQ(traits_type::next(reserved), traits_type::next(entity));
|
||||
|
||||
ASSERT_EQ(traits_type::next(null), traits_type::combine(null, entity_type{}));
|
||||
ASSERT_EQ(traits_type::next(tombstone), traits_type::combine(tombstone, entity_type{}));
|
||||
|
||||
ASSERT_EQ(traits_type::combine(entity, reserved), entity);
|
||||
ASSERT_NE(traits_type::combine(entity, reserved), reserved);
|
||||
|
||||
ASSERT_EQ(traits_type::combine(reserved, entity), entity);
|
||||
ASSERT_NE(traits_type::combine(reserved, entity), reserved);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(Entity, Null) {
|
||||
using entity_type = typename TestFixture::type;
|
||||
using traits_type = entt::entt_traits<entity_type>;
|
||||
|
||||
constexpr entity_type null{entt::null};
|
||||
|
||||
ASSERT_FALSE(entity_type{} == entt::null);
|
||||
ASSERT_TRUE(entt::null == entt::null);
|
||||
ASSERT_FALSE(entt::null != entt::null);
|
||||
|
||||
const entity_type entity{4u};
|
||||
|
||||
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);
|
||||
|
||||
ASSERT_FALSE(entity == entt::null);
|
||||
ASSERT_FALSE(entt::null == entity);
|
||||
|
||||
ASSERT_TRUE(entity != entt::null);
|
||||
ASSERT_TRUE(entt::null != entity);
|
||||
}
|
||||
|
||||
TYPED_TEST(Entity, Tombstone) {
|
||||
using entity_type = typename TestFixture::type;
|
||||
using traits_type = entt::entt_traits<entity_type>;
|
||||
|
||||
constexpr entity_type tombstone{entt::tombstone};
|
||||
|
||||
ASSERT_FALSE(entity_type{} == entt::tombstone);
|
||||
ASSERT_TRUE(entt::tombstone == entt::tombstone);
|
||||
ASSERT_FALSE(entt::tombstone != entt::tombstone);
|
||||
|
||||
const entity_type entity{4u};
|
||||
|
||||
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);
|
||||
|
||||
ASSERT_FALSE(entity == entt::tombstone);
|
||||
ASSERT_FALSE(entt::tombstone == entity);
|
||||
|
||||
ASSERT_TRUE(entity != entt::tombstone);
|
||||
ASSERT_TRUE(entt::tombstone != entity);
|
||||
}
|
||||
1631
lib/All/entt/test/entt/entity/group.cpp
Normal file
1631
lib/All/entt/test/entt/entity/group.cpp
Normal file
File diff suppressed because it is too large
Load Diff
620
lib/All/entt/test/entt/entity/handle.cpp
Normal file
620
lib/All/entt/test/entt/entity/handle.cpp
Normal file
@@ -0,0 +1,620 @@
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/core/type_traits.hpp>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/handle.hpp>
|
||||
#include <entt/entity/mixin.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/storage.hpp>
|
||||
#include "../../common/config.h"
|
||||
|
||||
template<typename Type>
|
||||
struct BasicHandle: testing::Test {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using BasicHandleDeathTest = BasicHandle<Type>;
|
||||
|
||||
using BasicHandleTypes = ::testing::Types<entt::handle, entt::const_handle>;
|
||||
|
||||
TYPED_TEST_SUITE(BasicHandle, BasicHandleTypes, );
|
||||
TYPED_TEST_SUITE(BasicHandleDeathTest, BasicHandleTypes, );
|
||||
|
||||
TYPED_TEST(BasicHandle, Assumptions) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
static_assert(std::is_trivially_copyable_v<handle_type>, "Trivially copyable type required");
|
||||
static_assert((std::is_trivially_assignable_v<handle_type, handle_type>), "Trivially assignable type required");
|
||||
static_assert(std::is_trivially_destructible_v<handle_type>, "Trivially destructible type required");
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, DeductionGuide) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
testing::StaticAssertTypeEq<decltype(entt::basic_handle{std::declval<typename handle_type::registry_type &>(), {}}), handle_type>();
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Construction) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
handle_type handle{};
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_FALSE(handle.valid());
|
||||
|
||||
ASSERT_TRUE(handle == entt::null);
|
||||
ASSERT_EQ(handle.registry(), nullptr);
|
||||
|
||||
ASSERT_NE(handle, (entt::handle{registry, entity}));
|
||||
ASSERT_NE(handle, (entt::const_handle{registry, entity}));
|
||||
|
||||
handle = handle_type{registry, entity};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_TRUE(handle.valid());
|
||||
|
||||
ASSERT_FALSE(handle == entt::null);
|
||||
ASSERT_EQ(handle.registry(), ®istry);
|
||||
|
||||
ASSERT_EQ(handle, (entt::handle{registry, entity}));
|
||||
ASSERT_EQ(handle, (entt::const_handle{registry, entity}));
|
||||
|
||||
handle = {};
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_FALSE(handle.valid());
|
||||
|
||||
ASSERT_TRUE(handle == entt::null);
|
||||
ASSERT_EQ(handle.registry(), nullptr);
|
||||
|
||||
ASSERT_NE(handle, (entt::handle{registry, entity}));
|
||||
ASSERT_NE(handle, (entt::const_handle{registry, entity}));
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Storage) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const handle_type handle{registry, entity};
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(*handle.storage().begin()), std::pair<entt::id_type, entt::constness_as_t<entt::sparse_set, typename handle_type::registry_type> &>>();
|
||||
|
||||
ASSERT_EQ(handle.storage().begin(), handle.storage().end());
|
||||
|
||||
registry.storage<double>();
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_NE(handle.storage().begin(), handle.storage().end());
|
||||
ASSERT_EQ(++handle.storage().begin(), handle.storage().end());
|
||||
ASSERT_EQ(handle.storage().begin()->second.type(), entt::type_id<int>());
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(BasicHandleDeathTest, Storage) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
const handle_type handle{};
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] auto iterable = handle.storage(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, HandleStorageIterator) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<double>(entity);
|
||||
// required to test the find-first initialization step
|
||||
registry.storage<entt::entity>().erase(entity);
|
||||
|
||||
const handle_type handle{registry, entity};
|
||||
auto iterable = handle.storage();
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity));
|
||||
ASSERT_FALSE(handle);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Entity) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
handle_type handle{};
|
||||
|
||||
ASSERT_TRUE(handle == entt::null);
|
||||
ASSERT_NE(handle.entity(), entity);
|
||||
ASSERT_NE(handle, entity);
|
||||
|
||||
handle = handle_type{registry, entity};
|
||||
|
||||
ASSERT_FALSE(handle == entt::null);
|
||||
ASSERT_EQ(handle.entity(), entity);
|
||||
ASSERT_EQ(handle, entity);
|
||||
}
|
||||
|
||||
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_EQ(handle.registry(), ®istry);
|
||||
ASSERT_EQ(handle.entity(), entity);
|
||||
|
||||
handle.destroy(traits_type::to_version(entity));
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_EQ(handle.registry(), ®istry);
|
||||
ASSERT_EQ(handle.entity(), entt::entity{entt::null});
|
||||
ASSERT_EQ(registry.current(entity), traits_type::to_version(entity));
|
||||
|
||||
handle = entt::handle{registry, registry.create()};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_EQ(handle.registry(), ®istry);
|
||||
ASSERT_EQ(handle.entity(), entity);
|
||||
|
||||
handle.destroy();
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_NE(handle.registry(), nullptr);
|
||||
ASSERT_NE(registry.current(entity), traits_type::to_version(entity));
|
||||
ASSERT_EQ(handle.entity(), entt::entity{entt::null});
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, Destruction) {
|
||||
entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.destroy(0u);, "");
|
||||
ASSERT_DEATH(handle.destroy();, "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Emplace) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_FALSE(registry.all_of<int>(entity));
|
||||
|
||||
ASSERT_EQ(handle.emplace<int>(3), 3);
|
||||
|
||||
ASSERT_TRUE(registry.all_of<int>(entity));
|
||||
ASSERT_EQ(registry.get<int>(entity), 3);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, Emplace) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.emplace<int>(3);, "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, EmplaceOrReplace) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_FALSE(registry.all_of<int>(entity));
|
||||
|
||||
ASSERT_EQ(handle.emplace_or_replace<int>(3), 3);
|
||||
|
||||
ASSERT_TRUE(registry.all_of<int>(entity));
|
||||
ASSERT_EQ(registry.get<int>(entity), 3);
|
||||
|
||||
ASSERT_EQ(handle.emplace_or_replace<int>(1), 1);
|
||||
|
||||
ASSERT_EQ(registry.get<int>(entity), 1);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, EmplaceOrReplace) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.emplace_or_replace<int>(3);, "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Patch) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
registry.emplace<int>(entity, 3);
|
||||
|
||||
ASSERT_TRUE(handle.all_of<int>());
|
||||
ASSERT_EQ(handle.patch<int>([](auto &comp) { comp = 1; }), 1);
|
||||
|
||||
ASSERT_EQ(registry.get<int>(entity), 1);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, Patch) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.patch<int>([](auto &comp) { comp = 1; });, "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Replace) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
registry.emplace<int>(entity, 3);
|
||||
|
||||
ASSERT_TRUE(handle.all_of<int>());
|
||||
ASSERT_EQ(handle.replace<int>(1), 1);
|
||||
|
||||
ASSERT_EQ(registry.get<int>(entity), 1);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, Replace) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.replace<int>(3);, "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Remove) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_FALSE(handle.all_of<int>());
|
||||
ASSERT_EQ(handle.remove<int>(), 0u);
|
||||
|
||||
registry.emplace<int>(entity, 3);
|
||||
|
||||
ASSERT_TRUE(handle.all_of<int>());
|
||||
ASSERT_EQ(handle.remove<int>(), 1u);
|
||||
|
||||
ASSERT_FALSE(handle.all_of<int>());
|
||||
ASSERT_EQ(handle.remove<int>(), 0u);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, Remove) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.remove<int>();, "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Erase) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
registry.emplace<int>(entity, 3);
|
||||
|
||||
ASSERT_TRUE(handle.all_of<int>());
|
||||
|
||||
handle.erase<int>();
|
||||
|
||||
ASSERT_FALSE(handle.all_of<int>());
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, Erase) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH(handle.erase<int>();, "");
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, AllAnyOf) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_FALSE((handle.all_of<int, char>()));
|
||||
ASSERT_FALSE((handle.any_of<int, char>()));
|
||||
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_FALSE((handle.all_of<int, char>()));
|
||||
ASSERT_TRUE((handle.any_of<int, char>()));
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
|
||||
ASSERT_TRUE((handle.all_of<int, char>()));
|
||||
ASSERT_TRUE((handle.any_of<int, char>()));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(BasicHandleDeathTest, AllAnyOf) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
const handle_type handle{};
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const auto all_of = handle.template all_of<int>(), "");
|
||||
ASSERT_DEATH([[maybe_unused]] const auto any_of = handle.template any_of<int>(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Get) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
registry.emplace<int>(entity, 3);
|
||||
registry.emplace<char>(entity, 'c');
|
||||
|
||||
ASSERT_EQ(handle.get<int>(), 3);
|
||||
ASSERT_EQ((handle.get<int, const char>()), (std::make_tuple(3, 'c')));
|
||||
|
||||
std::get<0>(handle.get<int, char>()) = 1;
|
||||
std::get<1>(handle.get<int, char>()) = '\0';
|
||||
|
||||
ASSERT_EQ(registry.get<int>(entity), 1);
|
||||
ASSERT_EQ(registry.get<char>(entity), '\0');
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(BasicHandleDeathTest, Get) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
const handle_type handle{};
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const auto &elem = handle.template get<int>(), "");
|
||||
}
|
||||
|
||||
TEST(BasicHandle, GetOrEmplace) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_FALSE(registry.all_of<int>(entity));
|
||||
|
||||
ASSERT_EQ(handle.get_or_emplace<int>(3), 3);
|
||||
|
||||
ASSERT_TRUE(registry.all_of<int>(entity));
|
||||
ASSERT_EQ(registry.get<int>(entity), 3);
|
||||
|
||||
ASSERT_EQ(handle.get_or_emplace<int>(1), 3);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicHandleDeathTest, GetOrEmplace) {
|
||||
const entt::handle handle{};
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] auto &&elem = handle.template get_or_emplace<int>(3), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, TryGet) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_EQ((handle.try_get<int, const char>()), (std::make_tuple(nullptr, nullptr)));
|
||||
|
||||
registry.emplace<int>(entity, 3);
|
||||
|
||||
ASSERT_NE(handle.try_get<int>(), nullptr);
|
||||
ASSERT_EQ(handle.try_get<char>(), nullptr);
|
||||
|
||||
ASSERT_EQ((*std::get<0>(handle.try_get<int, const char>())), 3);
|
||||
ASSERT_EQ((std::get<1>(handle.try_get<int, const char>())), nullptr);
|
||||
|
||||
*std::get<0>(handle.try_get<int, const char>()) = 1;
|
||||
|
||||
ASSERT_EQ(registry.get<int>(entity), 1);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(BasicHandleDeathTest, TryGet) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
const handle_type handle{};
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const auto *elem = handle.template try_get<int>(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Orphan) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const entt::handle handle{registry, entity};
|
||||
|
||||
ASSERT_TRUE(handle.orphan());
|
||||
|
||||
registry.emplace<int>(entity);
|
||||
registry.emplace<char>(entity);
|
||||
|
||||
ASSERT_FALSE(handle.orphan());
|
||||
|
||||
registry.erase<char>(entity);
|
||||
|
||||
ASSERT_FALSE(handle.orphan());
|
||||
|
||||
registry.erase<int>(entity);
|
||||
|
||||
ASSERT_TRUE(handle.orphan());
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(BasicHandleDeathTest, Orphan) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
const handle_type handle{};
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const auto result = handle.orphan(), "");
|
||||
}
|
||||
|
||||
/*
|
||||
TEST(BasicHandle, Component) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
const 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 = 2; });
|
||||
|
||||
ASSERT_EQ(2, patched);
|
||||
ASSERT_EQ('a', handle.replace<char>('a'));
|
||||
ASSERT_TRUE((handle.all_of<int, char, double>()));
|
||||
ASSERT_EQ((std::make_tuple(2, '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(2, handle.get_or_emplace<int>(2));
|
||||
ASSERT_EQ(2, handle.get_or_emplace<int>(1));
|
||||
ASSERT_EQ(2, handle.get<int>());
|
||||
|
||||
ASSERT_EQ(2, *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, ImplicitConversion) {
|
||||
entt::registry registry;
|
||||
const entt::handle handle{registry, registry.create()};
|
||||
const entt::const_handle const_handle = handle;
|
||||
const entt::handle_view<int, char> handle_view = handle;
|
||||
const entt::const_handle_view<int> const_handle_view = handle_view;
|
||||
|
||||
handle.emplace<int>(2);
|
||||
|
||||
ASSERT_EQ(handle.get<int>(), const_handle.get<int>());
|
||||
ASSERT_EQ(const_handle.get<int>(), handle_view.get<int>());
|
||||
ASSERT_EQ(handle_view.get<int>(), const_handle_view.get<int>());
|
||||
ASSERT_EQ(const_handle_view.get<int>(), 2);
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Comparison) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
handle_type handle{};
|
||||
|
||||
ASSERT_EQ(handle, entt::handle{});
|
||||
ASSERT_TRUE(handle == entt::handle{});
|
||||
ASSERT_FALSE(handle != entt::handle{});
|
||||
|
||||
ASSERT_EQ(handle, entt::const_handle{});
|
||||
ASSERT_TRUE(handle == entt::const_handle{});
|
||||
ASSERT_FALSE(handle != entt::const_handle{});
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
handle = handle_type{registry, entity};
|
||||
|
||||
ASSERT_NE(handle, entt::handle{});
|
||||
ASSERT_FALSE(handle == entt::handle{});
|
||||
ASSERT_TRUE(handle != entt::handle{});
|
||||
|
||||
ASSERT_NE(handle, entt::const_handle{});
|
||||
ASSERT_FALSE(handle == entt::const_handle{});
|
||||
ASSERT_TRUE(handle != entt::const_handle{});
|
||||
|
||||
handle = {};
|
||||
|
||||
ASSERT_EQ(handle, entt::handle{});
|
||||
ASSERT_TRUE(handle == entt::handle{});
|
||||
ASSERT_FALSE(handle != entt::handle{});
|
||||
|
||||
ASSERT_EQ(handle, entt::const_handle{});
|
||||
ASSERT_TRUE(handle == entt::const_handle{});
|
||||
ASSERT_FALSE(handle != entt::const_handle{});
|
||||
|
||||
entt::registry diff;
|
||||
handle = {registry, entity};
|
||||
const handle_type other = {diff, diff.create()};
|
||||
|
||||
ASSERT_NE(handle, other);
|
||||
ASSERT_FALSE(other == handle);
|
||||
ASSERT_TRUE(other != handle);
|
||||
ASSERT_EQ(handle.entity(), other.entity());
|
||||
ASSERT_NE(handle.registry(), other.registry());
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, Null) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
handle_type handle{};
|
||||
|
||||
ASSERT_TRUE(handle == entt::null);
|
||||
ASSERT_TRUE(entt::null == handle);
|
||||
|
||||
ASSERT_FALSE(handle != entt::null);
|
||||
ASSERT_FALSE(entt::null != handle);
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
handle = handle_type{registry, entity};
|
||||
|
||||
ASSERT_FALSE(handle == entt::null);
|
||||
ASSERT_FALSE(entt::null == handle);
|
||||
|
||||
ASSERT_TRUE(handle != entt::null);
|
||||
ASSERT_TRUE(entt::null != handle);
|
||||
|
||||
if constexpr(!std::is_const_v<typename handle_type::registry_type>) {
|
||||
handle.destroy();
|
||||
|
||||
ASSERT_TRUE(handle == entt::null);
|
||||
ASSERT_TRUE(entt::null == handle);
|
||||
|
||||
ASSERT_FALSE(handle != entt::null);
|
||||
ASSERT_FALSE(entt::null != handle);
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(BasicHandle, FromEntity) {
|
||||
using handle_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
registry.emplace<int>(entity, 2);
|
||||
registry.emplace<char>(entity, 'c');
|
||||
|
||||
const handle_type handle{registry, entity};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_EQ(entity, handle.entity());
|
||||
ASSERT_TRUE((handle.template all_of<int, char>()));
|
||||
ASSERT_EQ(handle.template get<int>(), 2);
|
||||
ASSERT_EQ(handle.template get<char>(), 'c');
|
||||
}
|
||||
|
||||
TEST(BasicHandle, Lifetime) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
auto handle = std::make_unique<entt::handle>(registry, entity);
|
||||
handle->emplace<int>();
|
||||
|
||||
ASSERT_FALSE(registry.storage<int>().empty());
|
||||
ASSERT_NE(registry.storage<entt::entity>().free_list(), 0u);
|
||||
|
||||
for(auto [entt]: registry.storage<entt::entity>().each()) {
|
||||
ASSERT_EQ(handle->entity(), entt);
|
||||
}
|
||||
|
||||
handle.reset();
|
||||
|
||||
ASSERT_FALSE(registry.storage<int>().empty());
|
||||
ASSERT_NE(registry.storage<entt::entity>().free_list(), 0u);
|
||||
}
|
||||
162
lib/All/entt/test/entt/entity/helper.cpp
Normal file
162
lib/All/entt/test/entt/entity/helper.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/entity/component.hpp>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/helper.hpp>
|
||||
#include <entt/entity/mixin.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/storage.hpp>
|
||||
#include <entt/entity/view.hpp>
|
||||
#include <entt/signal/sigh.hpp>
|
||||
#include "../../common/pointer_stable.h"
|
||||
|
||||
struct clazz {
|
||||
void func(entt::registry &, entt::entity curr) {
|
||||
entt = curr;
|
||||
}
|
||||
|
||||
entt::entity entt{entt::null};
|
||||
};
|
||||
|
||||
void sigh_callback(int &value) {
|
||||
++value;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
struct ToEntity: testing::Test {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using ToEntityDeprecated = ToEntity<Type>;
|
||||
|
||||
using ToEntityTypes = ::testing::Types<int, test::pointer_stable>;
|
||||
|
||||
TYPED_TEST_SUITE(ToEntity, ToEntityTypes, );
|
||||
TYPED_TEST_SUITE(ToEntityDeprecated, ToEntityTypes, );
|
||||
|
||||
TEST(AsView, Functionalities) {
|
||||
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(AsGroup, Functionalities) {
|
||||
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(Invoke, Functionalities) {
|
||||
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);
|
||||
}
|
||||
|
||||
TYPED_TEST(ToEntity, Functionalities) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using traits_type = entt::component_traits<value_type>;
|
||||
|
||||
entt::registry registry;
|
||||
const entt::entity null = entt::null;
|
||||
|
||||
auto &storage = registry.storage<value_type>();
|
||||
const value_type value{4};
|
||||
|
||||
ASSERT_EQ(entt::to_entity(storage, value), null);
|
||||
|
||||
const auto entity = registry.create();
|
||||
storage.emplace(entity);
|
||||
|
||||
while(storage.size() < (traits_type::page_size - (1u + traits_type::in_place_delete))) {
|
||||
storage.emplace(registry.create(), value);
|
||||
}
|
||||
|
||||
const auto other = registry.create();
|
||||
const auto next = registry.create();
|
||||
|
||||
storage.emplace(other);
|
||||
storage.emplace(next);
|
||||
|
||||
ASSERT_EQ(entt::to_entity(storage, storage.get(entity)), entity);
|
||||
ASSERT_EQ(entt::to_entity(storage, storage.get(other)), other);
|
||||
ASSERT_EQ(entt::to_entity(storage, storage.get(next)), next);
|
||||
|
||||
ASSERT_EQ(*storage.entt::sparse_set::rbegin(), entity);
|
||||
ASSERT_EQ(&*(storage.rbegin() + traits_type::page_size - (1u + traits_type::in_place_delete)), &storage.get(other));
|
||||
|
||||
// erase in the middle
|
||||
storage.erase(other);
|
||||
|
||||
ASSERT_EQ(entt::to_entity(storage, storage.get(entity)), entity);
|
||||
ASSERT_EQ(entt::to_entity(storage, storage.get(next)), next);
|
||||
|
||||
ASSERT_EQ(*storage.entt::sparse_set::rbegin(), entity);
|
||||
ASSERT_EQ(&*(storage.rbegin() + traits_type::page_size - 1u), &storage.get(next));
|
||||
|
||||
ASSERT_EQ(entt::to_entity(storage, value), null);
|
||||
|
||||
storage.clear();
|
||||
|
||||
storage.emplace(entity);
|
||||
storage.emplace(other);
|
||||
storage.emplace(next);
|
||||
|
||||
// erase first
|
||||
storage.erase(entity);
|
||||
|
||||
ASSERT_EQ(entt::to_entity(storage, value), null);
|
||||
ASSERT_EQ(entt::to_entity(storage, storage.get(other)), other);
|
||||
}
|
||||
|
||||
TEST(SighHelper, Functionalities) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::registry registry{};
|
||||
const auto entt = registry.create();
|
||||
entt::sigh_helper helper{registry};
|
||||
int counter{};
|
||||
|
||||
ASSERT_EQ(&helper.registry(), ®istry);
|
||||
|
||||
helper.with<int>()
|
||||
.on_construct<&sigh_callback>(counter)
|
||||
.on_update<&sigh_callback>(counter)
|
||||
.on_destroy<&sigh_callback>(counter);
|
||||
|
||||
ASSERT_EQ(counter, 0);
|
||||
|
||||
registry.emplace<int>(entt);
|
||||
registry.replace<int>(entt);
|
||||
registry.erase<int>(entt);
|
||||
|
||||
ASSERT_EQ(counter, 3);
|
||||
|
||||
helper.with<double>("other"_hs)
|
||||
.on_construct<&sigh_callback>(counter)
|
||||
.on_update<&sigh_callback>(counter)
|
||||
.on_destroy<&sigh_callback>(counter);
|
||||
|
||||
registry.emplace<double>(entt);
|
||||
registry.replace<double>(entt);
|
||||
registry.erase<double>(entt);
|
||||
|
||||
ASSERT_EQ(counter, 3);
|
||||
|
||||
registry.storage<double>("other"_hs).emplace(entt);
|
||||
registry.storage<double>("other"_hs).patch(entt);
|
||||
registry.storage<double>("other"_hs).erase(entt);
|
||||
|
||||
ASSERT_EQ(counter, 6);
|
||||
}
|
||||
505
lib/All/entt/test/entt/entity/organizer.cpp
Normal file
505
lib/All/entt/test/entt/entity/organizer.cpp
Normal file
@@ -0,0 +1,505 @@
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/entity/group.hpp>
|
||||
#include <entt/entity/mixin.hpp>
|
||||
#include <entt/entity/organizer.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/view.hpp>
|
||||
|
||||
void ro_int_rw_char_double(entt::view<entt::get_t<const int, char>>, double &) {}
|
||||
void ro_char_rw_int(entt::group<entt::owned_t<int>, entt::get_t<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::group<entt::owned_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 &) {
|
||||
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].in_edges().size(), 0u);
|
||||
ASSERT_EQ(graph[1u].in_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].in_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].in_edges().size(), 2u);
|
||||
|
||||
ASSERT_EQ(graph[1u].in_edges()[0u], 0u);
|
||||
ASSERT_EQ(graph[2u].in_edges()[0u], 0u);
|
||||
ASSERT_EQ(graph[3u].in_edges()[0u], 1u);
|
||||
ASSERT_EQ(graph[3u].in_edges()[1u], 2u);
|
||||
|
||||
ASSERT_EQ(graph[0u].out_edges().size(), 2u);
|
||||
ASSERT_EQ(graph[1u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].out_edges().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].out_edges()[0u], 1u);
|
||||
ASSERT_EQ(graph[0u].out_edges()[1u], 2u);
|
||||
ASSERT_EQ(graph[1u].out_edges()[0u], 3u);
|
||||
ASSERT_EQ(graph[2u].out_edges()[0u], 3u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
typename entt::organizer::function_type *cb = vertex.callback();
|
||||
ASSERT_NO_THROW(cb(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].in_edges().size(), 0u);
|
||||
ASSERT_EQ(graph[1u].in_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].in_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].in_edges().size(), 1u);
|
||||
|
||||
ASSERT_EQ(graph[1u].in_edges()[0u], 0u);
|
||||
ASSERT_EQ(graph[2u].in_edges()[0u], 1u);
|
||||
ASSERT_EQ(graph[3u].in_edges()[0u], 2u);
|
||||
|
||||
ASSERT_EQ(graph[0u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].out_edges().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].out_edges()[0u], 1u);
|
||||
ASSERT_EQ(graph[1u].out_edges()[0u], 2u);
|
||||
ASSERT_EQ(graph[2u].out_edges()[0u], 3u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
typename entt::organizer::function_type *cb = vertex.callback();
|
||||
ASSERT_NO_THROW(cb(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[3u].in_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[4u].in_edges().size(), 3u);
|
||||
|
||||
ASSERT_EQ(graph[3u].in_edges()[0u], 2u);
|
||||
ASSERT_EQ(graph[4u].in_edges()[0u], 0u);
|
||||
ASSERT_EQ(graph[4u].in_edges()[1u], 1u);
|
||||
ASSERT_EQ(graph[4u].in_edges()[2u], 3u);
|
||||
|
||||
ASSERT_EQ(graph[0u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[4u].out_edges().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].out_edges()[0u], 4u);
|
||||
ASSERT_EQ(graph[1u].out_edges()[0u], 4u);
|
||||
ASSERT_EQ(graph[2u].out_edges()[0u], 3u);
|
||||
ASSERT_EQ(graph[3u].out_edges()[0u], 4u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
typename entt::organizer::function_type *cb = vertex.callback();
|
||||
ASSERT_NO_THROW(cb(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[1u].in_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].in_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].in_edges().size(), 1u);
|
||||
|
||||
ASSERT_EQ(graph[1u].in_edges()[0u], 0u);
|
||||
ASSERT_EQ(graph[2u].in_edges()[0u], 1u);
|
||||
ASSERT_EQ(graph[3u].in_edges()[0u], 2u);
|
||||
|
||||
ASSERT_EQ(graph[0u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].out_edges().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].out_edges()[0u], 1u);
|
||||
ASSERT_EQ(graph[1u].out_edges()[0u], 2u);
|
||||
ASSERT_EQ(graph[2u].out_edges()[0u], 3u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
typename entt::organizer::function_type *cb = vertex.callback();
|
||||
ASSERT_NO_THROW(cb(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[1u].in_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].in_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].in_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[4u].in_edges().size(), 2u);
|
||||
ASSERT_EQ(graph[5u].in_edges().size(), 1u);
|
||||
|
||||
ASSERT_EQ(graph[1u].in_edges()[0u], 0u);
|
||||
ASSERT_EQ(graph[2u].in_edges()[0u], 1u);
|
||||
ASSERT_EQ(graph[3u].in_edges()[0u], 1u);
|
||||
ASSERT_EQ(graph[4u].in_edges()[0u], 2u);
|
||||
ASSERT_EQ(graph[4u].in_edges()[1u], 3u);
|
||||
ASSERT_EQ(graph[5u].in_edges()[0u], 4u);
|
||||
|
||||
ASSERT_EQ(graph[0u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].out_edges().size(), 2u);
|
||||
ASSERT_EQ(graph[2u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[3u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[4u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[5u].out_edges().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].out_edges()[0u], 1u);
|
||||
ASSERT_EQ(graph[1u].out_edges()[0u], 2u);
|
||||
ASSERT_EQ(graph[1u].out_edges()[1u], 3u);
|
||||
ASSERT_EQ(graph[2u].out_edges()[0u], 4u);
|
||||
ASSERT_EQ(graph[3u].out_edges()[0u], 4u);
|
||||
ASSERT_EQ(graph[4u].out_edges()[0u], 5u);
|
||||
|
||||
for(auto &&vertex: graph) {
|
||||
typename entt::organizer::function_type *cb = vertex.callback();
|
||||
ASSERT_NO_THROW(cb(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[2u].in_edges().size(), 2u);
|
||||
|
||||
ASSERT_EQ(graph[2u].in_edges()[0u], 0u);
|
||||
ASSERT_EQ(graph[2u].in_edges()[1u], 1u);
|
||||
|
||||
ASSERT_EQ(graph[0u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[1u].out_edges().size(), 1u);
|
||||
ASSERT_EQ(graph[2u].out_edges().size(), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].out_edges()[0u], 2u);
|
||||
ASSERT_EQ(graph[1u].out_edges()[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>());
|
||||
|
||||
ASSERT_EQ(std::as_const(registry).storage<int>(), nullptr);
|
||||
ASSERT_EQ(std::as_const(registry).storage<char>(), nullptr);
|
||||
ASSERT_EQ(std::as_const(registry).storage<double>(), nullptr);
|
||||
|
||||
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>());
|
||||
|
||||
ASSERT_NE(std::as_const(registry).storage<int>(), nullptr);
|
||||
ASSERT_NE(std::as_const(registry).storage<char>(), nullptr);
|
||||
ASSERT_EQ(std::as_const(registry).storage<double>(), nullptr);
|
||||
}
|
||||
|
||||
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();
|
||||
constexpr auto number_of_elements = 5u;
|
||||
std::array<const entt::type_info *, number_of_elements> buffer{};
|
||||
|
||||
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.data(), 0u), 0u);
|
||||
ASSERT_EQ(graph[0u].rw_dependency(buffer.data(), 2u), 0u);
|
||||
|
||||
ASSERT_EQ(graph[0u].ro_dependency(buffer.data(), 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.data(), 2u), 0u);
|
||||
ASSERT_EQ(graph[1u].rw_dependency(buffer.data(), 0u), 0u);
|
||||
|
||||
ASSERT_EQ(graph[1u].rw_dependency(buffer.data(), 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.data(), 2u), 1u);
|
||||
ASSERT_EQ(graph[2u].rw_dependency(buffer.data(), 0u), 0u);
|
||||
|
||||
ASSERT_EQ(graph[2u].ro_dependency(buffer.data(), 5u), 1u);
|
||||
ASSERT_EQ(*buffer[0u], entt::type_id<double>());
|
||||
|
||||
ASSERT_EQ(graph[2u].rw_dependency(buffer.data(), 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>(2u);
|
||||
|
||||
auto graph = organizer.graph();
|
||||
graph[0u].callback()(graph[0u].data(), registry);
|
||||
|
||||
ASSERT_EQ(registry.ctx().get<std::size_t>(), 0u);
|
||||
}
|
||||
656
lib/All/entt/test/entt/entity/reactive_mixin.cpp
Normal file
656
lib/All/entt/test/entt/entity/reactive_mixin.cpp
Normal file
@@ -0,0 +1,656 @@
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/entity/component.hpp>
|
||||
#include <entt/entity/mixin.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/storage.hpp>
|
||||
#include <entt/signal/sigh.hpp>
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/empty.h"
|
||||
#include "../../common/entity.h"
|
||||
#include "../../common/linter.hpp"
|
||||
#include "../../common/registry.h"
|
||||
#include "../../common/throwing_allocator.hpp"
|
||||
|
||||
template<typename Type, std::size_t Value>
|
||||
void emplace(Type &storage, const typename Type::registry_type &, const typename Type::entity_type entity) {
|
||||
if((entity == typename Type::entity_type{Value}) && !storage.contains(entity)) {
|
||||
storage.emplace(entity);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
void remove(Type &storage, const typename Type::registry_type &, const typename Type::entity_type entity) {
|
||||
storage.remove(entity);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
struct entt::storage_type<Type, test::entity, std::allocator<Type>, std::enable_if_t<!std::is_same_v<Type, test::entity>>> {
|
||||
using type = entt::basic_sigh_mixin<entt::basic_storage<Type, test::entity>, test::custom_registry<test::entity>>;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct ReactiveMixin: testing::Test {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using ReactiveMixinDeathTest = ReactiveMixin<Type>;
|
||||
|
||||
using ReactiveMixinTypes = ::testing::Types<void, bool>;
|
||||
|
||||
TYPED_TEST_SUITE(ReactiveMixin, ReactiveMixinTypes, );
|
||||
TYPED_TEST_SUITE(ReactiveMixinDeathTest, ReactiveMixinTypes, );
|
||||
|
||||
TYPED_TEST(ReactiveMixin, Constructors) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using traits_type = entt::component_traits<value_type>;
|
||||
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
|
||||
ASSERT_EQ(pool.policy(), entt::deletion_policy{traits_type::in_place_delete});
|
||||
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
|
||||
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
|
||||
|
||||
pool = entt::reactive_mixin<entt::storage<value_type>>{std::allocator<value_type>{}};
|
||||
|
||||
ASSERT_EQ(pool.policy(), entt::deletion_policy{traits_type::in_place_delete});
|
||||
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
|
||||
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, Move) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
const std::array entity{registry.create(), registry.create()};
|
||||
|
||||
pool.bind(registry);
|
||||
pool.template on_construct<test::empty>().template on_update<test::empty>();
|
||||
registry.emplace<test::empty>(entity[0u]);
|
||||
|
||||
static_assert(std::is_move_constructible_v<decltype(pool)>, "Move constructible type required");
|
||||
static_assert(std::is_move_assignable_v<decltype(pool)>, "Move assignable type required");
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity[0u]));
|
||||
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
|
||||
|
||||
entt::reactive_mixin<entt::storage<value_type>> other{std::move(pool)};
|
||||
|
||||
test::is_initialized(pool);
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
|
||||
ASSERT_EQ(other.type(), entt::type_id<value_type>());
|
||||
|
||||
ASSERT_EQ(other.index(entity[0u]), 0u);
|
||||
ASSERT_EQ(&other.registry(), ®istry);
|
||||
|
||||
other.clear();
|
||||
registry.replace<test::empty>(entity[0u]);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
|
||||
std::swap(other, pool);
|
||||
pool = std::move(other);
|
||||
test::is_initialized(other);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
|
||||
ASSERT_EQ(pool.index(entity[0u]), 0u);
|
||||
ASSERT_EQ(&pool.registry(), ®istry);
|
||||
|
||||
other = entt::reactive_mixin<entt::storage<value_type>>{};
|
||||
other.bind(registry);
|
||||
other.template on_construct<test::empty>();
|
||||
registry.on_construct<test::empty>().disconnect(&pool);
|
||||
|
||||
registry.emplace<test::empty>(entity[1u]);
|
||||
other = std::move(pool);
|
||||
test::is_initialized(pool);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
|
||||
ASSERT_EQ(other.index(entity[0u]), 0u);
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, Swap) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
entt::reactive_mixin<entt::storage<value_type>> other;
|
||||
const std::array entity{registry.create(), registry.create()};
|
||||
|
||||
registry.emplace<test::empty>(entity[0u]);
|
||||
|
||||
pool.bind(registry);
|
||||
pool.template on_construct<test::empty>();
|
||||
|
||||
other.bind(registry);
|
||||
other.template on_destroy<test::empty>();
|
||||
|
||||
registry.emplace<test::empty>(entity[1u]);
|
||||
registry.erase<test::empty>(entity[0u]);
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
|
||||
pool.swap(other);
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
|
||||
ASSERT_EQ(other.type(), entt::type_id<value_type>());
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
|
||||
ASSERT_EQ(pool.index(entity[0u]), 0u);
|
||||
ASSERT_EQ(other.index(entity[1u]), 0u);
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, OnConstruct) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
const entt::entity entity{registry.create()};
|
||||
|
||||
pool.bind(registry);
|
||||
registry.emplace<test::empty>(entity);
|
||||
|
||||
ASSERT_FALSE(pool.contains(entity));
|
||||
|
||||
registry.clear<test::empty>();
|
||||
pool.template on_construct<test::other_empty>();
|
||||
registry.emplace<test::empty>(entity);
|
||||
|
||||
ASSERT_FALSE(pool.contains(entity));
|
||||
|
||||
registry.on_construct<test::other_empty>().disconnect(&pool);
|
||||
registry.clear<test::empty>();
|
||||
pool.template on_construct<test::empty>();
|
||||
registry.emplace<test::empty>(entity);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
registry.clear<test::empty>();
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
registry.emplace<test::empty>(entity);
|
||||
registry.emplace_or_replace<test::empty>(entity);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
registry.destroy(entity);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, OnConstructCallback) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
const std::array entity{registry.create(), registry.create(entt::entity{3})};
|
||||
|
||||
pool.bind(registry);
|
||||
pool.template on_construct<test::empty, &emplace<entt::reactive_mixin<entt::storage<value_type>>, 3u>>();
|
||||
registry.emplace<test::empty>(entity[0u]);
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
registry.emplace<test::empty>(entity[1u]);
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_TRUE(pool.contains(entity[1u]));
|
||||
|
||||
pool.clear();
|
||||
registry.clear<test::empty>();
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
registry.insert<test::empty>(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_TRUE(pool.contains(entity[1u]));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(ReactiveMixinDeathTest, OnConstruct) {
|
||||
using value_type = typename TestFixture::type;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
ASSERT_DEATH(pool.template on_construct<test::empty>(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, OnUpdate) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
const entt::entity entity{registry.create()};
|
||||
|
||||
pool.bind(registry);
|
||||
registry.emplace<test::empty>(entity);
|
||||
registry.patch<test::empty>(entity);
|
||||
|
||||
ASSERT_FALSE(pool.contains(entity));
|
||||
|
||||
pool.template on_update<test::other_empty>();
|
||||
registry.patch<test::empty>(entity);
|
||||
|
||||
ASSERT_FALSE(pool.contains(entity));
|
||||
|
||||
registry.on_update<test::other_empty>().disconnect(&pool);
|
||||
pool.template on_update<test::empty>();
|
||||
registry.patch<test::empty>(entity);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
registry.clear<test::empty>();
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
registry.emplace<test::empty>(entity);
|
||||
registry.emplace_or_replace<test::empty>(entity);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
registry.destroy(entity);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, OnUpdateCallback) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
const std::array entity{registry.create(), registry.create(entt::entity{3})};
|
||||
|
||||
pool.bind(registry);
|
||||
pool.template on_update<test::empty, &emplace<entt::reactive_mixin<entt::storage<value_type>>, 3u>>();
|
||||
registry.insert<test::empty>(entity.begin(), entity.end());
|
||||
registry.patch<test::empty>(entity[0u]);
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
registry.patch<test::empty>(entity[1u]);
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_TRUE(pool.contains(entity[1u]));
|
||||
|
||||
pool.clear();
|
||||
registry.clear<test::empty>();
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
registry.insert<test::empty>(entity.begin(), entity.end());
|
||||
registry.patch<test::empty>(entity[0u]);
|
||||
registry.patch<test::empty>(entity[1u]);
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_TRUE(pool.contains(entity[1u]));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(ReactiveMixinDeathTest, OnUpdate) {
|
||||
using value_type = typename TestFixture::type;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
ASSERT_DEATH(pool.template on_update<test::empty>(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, OnDestroy) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
const entt::entity entity{registry.create()};
|
||||
|
||||
pool.bind(registry);
|
||||
registry.emplace<test::empty>(entity);
|
||||
registry.erase<test::empty>(entity);
|
||||
|
||||
ASSERT_FALSE(pool.contains(entity));
|
||||
|
||||
pool.template on_destroy<test::other_empty>();
|
||||
registry.emplace<test::empty>(entity);
|
||||
registry.erase<test::empty>(entity);
|
||||
|
||||
ASSERT_FALSE(pool.contains(entity));
|
||||
|
||||
registry.on_destroy<test::other_empty>().disconnect(&pool);
|
||||
pool.template on_destroy<test::empty>();
|
||||
registry.emplace<test::empty>(entity);
|
||||
registry.erase<test::empty>(entity);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
registry.clear<test::empty>();
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
registry.emplace<test::empty>(entity);
|
||||
registry.erase<test::empty>(entity);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
registry.destroy(entity);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, OnDestroyCallback) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
const std::array entity{registry.create(), registry.create(entt::entity{3})};
|
||||
|
||||
pool.bind(registry);
|
||||
pool.template on_destroy<test::empty, &emplace<entt::reactive_mixin<entt::storage<value_type>>, 3u>>();
|
||||
registry.insert<test::empty>(entity.begin(), entity.end());
|
||||
registry.erase<test::empty>(entity[0u]);
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
registry.erase<test::empty>(entity[1u]);
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_TRUE(pool.contains(entity[1u]));
|
||||
|
||||
pool.clear();
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
registry.insert<test::empty>(entity.begin(), entity.end());
|
||||
registry.erase<test::empty>(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_TRUE(pool.contains(entity[1u]));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(ReactiveMixinDeathTest, OnDestroy) {
|
||||
using value_type = typename TestFixture::type;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
ASSERT_DEATH(pool.template on_destroy<test::empty>(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, EntityLifecycle) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
const entt::entity entity{registry.create()};
|
||||
|
||||
pool.bind(registry);
|
||||
pool.template on_construct<test::empty>().template on_destroy<entt::entity, &remove<decltype(pool)>>();
|
||||
|
||||
ASSERT_FALSE(pool.contains(entity));
|
||||
|
||||
registry.emplace<test::empty>(entity);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
registry.erase<test::empty>(entity);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
registry.emplace<test::empty>(entity);
|
||||
registry.destroy(entity);
|
||||
|
||||
ASSERT_FALSE(pool.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, ManagedStorage) {
|
||||
entt::registry registry;
|
||||
entt::storage_for_t<entt::reactive> &pool = registry.storage<entt::reactive>();
|
||||
const entt::entity entity{registry.create()};
|
||||
|
||||
pool.template on_construct<test::empty>();
|
||||
registry.emplace<test::empty>(entity);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
registry.erase<test::empty>(entity);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
registry.emplace<test::empty>(entity);
|
||||
registry.destroy(entity);
|
||||
|
||||
ASSERT_FALSE(pool.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, Registry) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
|
||||
ASSERT_FALSE(pool);
|
||||
|
||||
pool.bind(registry);
|
||||
|
||||
ASSERT_TRUE(pool);
|
||||
ASSERT_EQ(&pool.registry(), ®istry);
|
||||
ASSERT_EQ(&std::as_const(pool).registry(), ®istry);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(ReactiveMixinDeathTest, Registry) {
|
||||
using value_type = typename TestFixture::type;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
ASSERT_DEATH([[maybe_unused]] auto ®istry = pool.registry(), "");
|
||||
ASSERT_DEATH([[maybe_unused]] const auto ®istry = std::as_const(pool).registry(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, CustomRegistry) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using registry_type = test::custom_registry<test::entity>;
|
||||
|
||||
registry_type registry;
|
||||
entt::basic_reactive_mixin<entt::basic_storage<value_type, test::entity>, registry_type> pool;
|
||||
const std::array entity{registry.create(), registry.create()};
|
||||
|
||||
ASSERT_FALSE(pool);
|
||||
|
||||
pool.bind(registry);
|
||||
|
||||
ASSERT_TRUE(pool);
|
||||
|
||||
pool.template on_construct<test::empty>();
|
||||
registry.insert<test::empty>(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_TRUE(pool.contains(entity[0u]));
|
||||
ASSERT_TRUE(pool.contains(entity[1u]));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(ReactiveMixinDeathTest, CustomRegistry) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using registry_type = test::custom_registry<test::entity>;
|
||||
entt::basic_reactive_mixin<entt::basic_storage<value_type, test::entity>, registry_type> pool;
|
||||
ASSERT_DEATH([[maybe_unused]] auto ®istry = pool.registry(), "");
|
||||
ASSERT_DEATH([[maybe_unused]] const auto ®istry = std::as_const(pool).registry(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, View) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
const std::array entity{registry.create(), registry.create()};
|
||||
|
||||
pool.bind(registry);
|
||||
pool.template on_construct<test::empty>();
|
||||
registry.insert<test::empty>(entity.begin(), entity.end());
|
||||
registry.insert<double>(entity.begin(), entity.end());
|
||||
registry.emplace<int>(entity[1u], 1);
|
||||
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_TRUE(pool.contains(entity[0u]));
|
||||
ASSERT_TRUE(pool.contains(entity[1u]));
|
||||
|
||||
const auto view = pool.view();
|
||||
const auto cview = std::as_const(pool).view();
|
||||
|
||||
ASSERT_EQ(view.size(), 2u);
|
||||
ASSERT_EQ(view.front(), entity[1u]);
|
||||
ASSERT_EQ(view.back(), entity[0u]);
|
||||
|
||||
ASSERT_EQ(cview.size(), view.size());
|
||||
|
||||
for(const auto entt: cview) {
|
||||
ASSERT_TRUE(view.contains(entt));
|
||||
}
|
||||
|
||||
const auto filtered = pool.template view<double>(entt::exclude<int>);
|
||||
const auto cfiltered = std::as_const(pool).template view<double>(entt::exclude<int>);
|
||||
|
||||
ASSERT_EQ(filtered.size_hint(), 2u);
|
||||
ASSERT_EQ(std::distance(filtered.begin(), filtered.end()), 1);
|
||||
ASSERT_TRUE(filtered.contains(entity[0u]));
|
||||
ASSERT_FALSE(filtered.contains(entity[1u]));
|
||||
|
||||
ASSERT_NE(std::distance(cfiltered.begin(), cfiltered.end()), 0);
|
||||
|
||||
for(const auto entt: cfiltered) {
|
||||
ASSERT_TRUE(filtered.contains(entt));
|
||||
}
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(ReactiveMixinDeathTest, View) {
|
||||
using value_type = typename TestFixture::type;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
ASSERT_DEATH([[maybe_unused]] const auto view = pool.view(), "");
|
||||
ASSERT_DEATH([[maybe_unused]] const auto cview = std::as_const(pool).view(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, AutoDisconnection) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
entt::reactive_mixin<entt::storage<value_type>> pool;
|
||||
const std::array entity{registry.create(), registry.create(), registry.create()};
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
ASSERT_TRUE(registry.on_construct<test::empty>().empty());
|
||||
ASSERT_TRUE(registry.on_update<test::empty>().empty());
|
||||
ASSERT_TRUE(registry.on_destroy<test::empty>().empty());
|
||||
|
||||
pool.bind(registry);
|
||||
pool.template on_construct<test::empty>();
|
||||
pool.template on_update<test::empty>();
|
||||
pool.template on_destroy<test::empty>();
|
||||
registry.emplace<test::empty>(entity[0u]);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_FALSE(registry.on_construct<test::empty>().empty());
|
||||
ASSERT_FALSE(registry.on_update<test::empty>().empty());
|
||||
ASSERT_FALSE(registry.on_destroy<test::empty>().empty());
|
||||
|
||||
pool.reset();
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
|
||||
ASSERT_TRUE(registry.on_construct<test::empty>().empty());
|
||||
ASSERT_TRUE(registry.on_update<test::empty>().empty());
|
||||
ASSERT_TRUE(registry.on_destroy<test::empty>().empty());
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, CustomAllocator) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using storage_type = entt::reactive_mixin<entt::basic_storage<value_type, entt::entity, test::throwing_allocator<value_type>>>;
|
||||
using registry_type = typename storage_type::registry_type;
|
||||
|
||||
const test::throwing_allocator<entt::entity> allocator{};
|
||||
storage_type pool{allocator};
|
||||
registry_type registry;
|
||||
const std::array entity{registry.create(), registry.create()};
|
||||
|
||||
pool.bind(registry);
|
||||
pool.template on_construct<test::empty>();
|
||||
|
||||
pool.reserve(1u);
|
||||
|
||||
ASSERT_NE(pool.capacity(), 0u);
|
||||
|
||||
registry.template emplace<test::empty>(entity[0u]);
|
||||
registry.template emplace<test::empty>(entity[1u]);
|
||||
|
||||
decltype(pool) other{std::move(pool), allocator};
|
||||
|
||||
test::is_initialized(pool);
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_NE(other.capacity(), 0u);
|
||||
ASSERT_EQ(other.size(), 2u);
|
||||
|
||||
pool = std::move(other);
|
||||
test::is_initialized(other);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_NE(pool.capacity(), 0u);
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
|
||||
other = {};
|
||||
pool.swap(other);
|
||||
pool = std::move(other);
|
||||
test::is_initialized(other);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_NE(pool.capacity(), 0u);
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
|
||||
pool.clear();
|
||||
|
||||
ASSERT_NE(pool.capacity(), 0u);
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
}
|
||||
|
||||
TYPED_TEST(ReactiveMixin, ThrowingAllocator) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using storage_type = entt::reactive_mixin<entt::basic_storage<value_type, entt::entity, test::throwing_allocator<value_type>>>;
|
||||
using registry_type = typename storage_type::registry_type;
|
||||
|
||||
storage_type pool{};
|
||||
registry_type registry;
|
||||
const std::array entity{registry.create(), registry.create()};
|
||||
|
||||
pool.bind(registry);
|
||||
pool.template on_construct<test::empty>();
|
||||
|
||||
pool.get_allocator().template throw_counter<entt::entity>(0u);
|
||||
|
||||
ASSERT_THROW(pool.reserve(1u), test::throwing_allocator_exception);
|
||||
ASSERT_EQ(pool.capacity(), 0u);
|
||||
|
||||
pool.get_allocator().template throw_counter<entt::entity>(1u);
|
||||
|
||||
ASSERT_THROW(registry.template emplace<test::empty>(entity[0u]), test::throwing_allocator_exception);
|
||||
ASSERT_TRUE(registry.template all_of<test::empty>(entity[0u]));
|
||||
ASSERT_FALSE(pool.contains(entity[0u]));
|
||||
|
||||
registry.template clear<test::empty>();
|
||||
pool.get_allocator().template throw_counter<entt::entity>(1u);
|
||||
|
||||
ASSERT_THROW(registry.template insert<test::empty>(entity.begin(), entity.end()), test::throwing_allocator_exception);
|
||||
ASSERT_TRUE(registry.template all_of<test::empty>(entity[0u]));
|
||||
ASSERT_TRUE(registry.template all_of<test::empty>(entity[1u]));
|
||||
ASSERT_TRUE(pool.contains(entity[0u]));
|
||||
ASSERT_FALSE(pool.contains(entity[1u]));
|
||||
}
|
||||
2568
lib/All/entt/test/entt/entity/registry.cpp
Normal file
2568
lib/All/entt/test/entt/entity/registry.cpp
Normal file
File diff suppressed because it is too large
Load Diff
420
lib/All/entt/test/entt/entity/runtime_view.cpp
Normal file
420
lib/All/entt/test/entt/entity/runtime_view.cpp
Normal file
@@ -0,0 +1,420 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/runtime_view.hpp>
|
||||
#include <entt/entity/storage.hpp>
|
||||
#include "../../common/linter.hpp"
|
||||
#include "../../common/pointer_stable.h"
|
||||
|
||||
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;
|
||||
|
||||
std::tuple<entt::storage<int>, entt::storage<char>> storage{};
|
||||
const std::array entity{entt::entity{1}, entt::entity{3}};
|
||||
runtime_view_type view{};
|
||||
|
||||
ASSERT_FALSE(view);
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_FALSE(view.contains(entity[0u]));
|
||||
ASSERT_FALSE(view.contains(entity[1u]));
|
||||
|
||||
view.iterate(std::get<0>(storage)).iterate(std::get<1>(storage));
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.size_hint(), 0u);
|
||||
|
||||
std::get<1>(storage).emplace(entity[0u]);
|
||||
std::get<0>(storage).emplace(entity[1u]);
|
||||
|
||||
ASSERT_NE(view.size_hint(), 0u);
|
||||
|
||||
std::get<1>(storage).emplace(entity[1u]);
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 1u);
|
||||
|
||||
auto it = view.begin();
|
||||
|
||||
ASSERT_EQ(*it, entity[1u]);
|
||||
ASSERT_EQ(++it, (view.end()));
|
||||
|
||||
ASSERT_NO_THROW((view.begin()++));
|
||||
ASSERT_NO_THROW((++view.begin()));
|
||||
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_EQ(view.size_hint(), 1u);
|
||||
|
||||
std::get<1>(storage).get(entity[0u]) = '1';
|
||||
std::get<1>(storage).get(entity[1u]) = '2';
|
||||
std::get<0>(storage).get(entity[1u]) = 3;
|
||||
|
||||
for(auto entt: view) {
|
||||
ASSERT_EQ(std::get<0>(storage).get(entt), 3);
|
||||
ASSERT_EQ(std::get<1>(storage).get(entt), '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::storage<int> storage{};
|
||||
const entt::entity entity{0};
|
||||
runtime_view_type view{};
|
||||
|
||||
ASSERT_FALSE(view);
|
||||
|
||||
storage.emplace(entity);
|
||||
|
||||
view = runtime_view_type{std::allocator<int>{}};
|
||||
view.iterate(storage);
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
|
||||
runtime_view_type temp{view, view.get_allocator()};
|
||||
const runtime_view_type other{std::move(temp), view.get_allocator()};
|
||||
|
||||
test::is_initialized(temp);
|
||||
|
||||
ASSERT_FALSE(temp);
|
||||
ASSERT_TRUE(other);
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Copy) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
std::tuple<entt::storage<int>, entt::storage<char>> storage{};
|
||||
const entt::entity entity{0};
|
||||
runtime_view_type view{};
|
||||
|
||||
ASSERT_FALSE(view);
|
||||
|
||||
std::get<0>(storage).emplace(entity);
|
||||
std::get<1>(storage).emplace(entity);
|
||||
|
||||
view.iterate(std::get<0>(storage));
|
||||
|
||||
runtime_view_type other{view};
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_TRUE(other);
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
|
||||
other.iterate(std::get<0>(storage)).exclude(std::get<1>(storage));
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_FALSE(other.contains(entity));
|
||||
|
||||
other = view;
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_TRUE(other);
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Move) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
std::tuple<entt::storage<int>, entt::storage<char>> storage{};
|
||||
const entt::entity entity{0};
|
||||
runtime_view_type view{};
|
||||
|
||||
ASSERT_FALSE(view);
|
||||
|
||||
std::get<0>(storage).emplace(entity);
|
||||
std::get<1>(storage).emplace(entity);
|
||||
|
||||
view.iterate(std::get<0>(storage));
|
||||
|
||||
runtime_view_type other{std::move(view)};
|
||||
|
||||
test::is_initialized(view);
|
||||
|
||||
ASSERT_FALSE(view);
|
||||
ASSERT_TRUE(other);
|
||||
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
|
||||
view = other;
|
||||
other.iterate(std::get<0>(storage)).exclude(std::get<1>(storage));
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_TRUE(other);
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_FALSE(other.contains(entity));
|
||||
|
||||
other = std::move(view);
|
||||
test::is_initialized(view);
|
||||
|
||||
ASSERT_FALSE(view);
|
||||
ASSERT_TRUE(other);
|
||||
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Swap) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<int> storage{};
|
||||
const entt::entity entity{0};
|
||||
runtime_view_type view{};
|
||||
runtime_view_type other{};
|
||||
|
||||
ASSERT_FALSE(view);
|
||||
ASSERT_FALSE(other);
|
||||
|
||||
storage.emplace(entity);
|
||||
view.iterate(storage);
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_FALSE(other);
|
||||
|
||||
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_FALSE(view);
|
||||
ASSERT_TRUE(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::storage<int> storage{};
|
||||
const entt::entity entity{0};
|
||||
runtime_view_type view{};
|
||||
|
||||
storage.emplace(entity);
|
||||
view.iterate(storage);
|
||||
|
||||
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::storage<int> storage{};
|
||||
const std::array entity{entt::entity{1}, entt::entity{3}};
|
||||
runtime_view_type view{};
|
||||
|
||||
storage.emplace(entity[0u]);
|
||||
storage.emplace(entity[1u]);
|
||||
|
||||
storage.erase(entity[0u]);
|
||||
|
||||
view.iterate(storage);
|
||||
|
||||
ASSERT_FALSE(view.contains(entity[0u]));
|
||||
ASSERT_TRUE(view.contains(entity[1u]));
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Empty) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<int> storage{};
|
||||
const entt::entity entity{0};
|
||||
runtime_view_type view{};
|
||||
|
||||
view.iterate(storage);
|
||||
|
||||
ASSERT_FALSE(view.contains(entity));
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_EQ((std::find(view.begin(), view.end(), entity)), view.end());
|
||||
|
||||
storage.emplace(entity);
|
||||
|
||||
ASSERT_TRUE(view.contains(entity));
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_NE((std::find(view.begin(), view.end(), entity)), view.end());
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, Each) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
std::tuple<entt::storage<int>, entt::storage<char>> storage{};
|
||||
const std::array entity{entt::entity{1}, entt::entity{3}};
|
||||
runtime_view_type view{};
|
||||
|
||||
std::get<0>(storage).emplace(entity[0u]);
|
||||
std::get<1>(storage).emplace(entity[0u]);
|
||||
std::get<1>(storage).emplace(entity[1u]);
|
||||
|
||||
view.iterate(std::get<0>(storage)).iterate(std::get<1>(storage));
|
||||
|
||||
view.each([&](const auto entt) {
|
||||
ASSERT_EQ(entt, entity[0u]);
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, EachWithHoles) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
std::tuple<entt::storage<int>, entt::storage<char>> storage{};
|
||||
const std::array entity{entt::entity{0}, entt::entity{1}, entt::entity{3}};
|
||||
runtime_view_type view{};
|
||||
|
||||
std::get<1>(storage).emplace(entity[0u], '0');
|
||||
std::get<1>(storage).emplace(entity[1u], '1');
|
||||
|
||||
std::get<0>(storage).emplace(entity[0u], 0);
|
||||
std::get<0>(storage).emplace(entity[2u], 2);
|
||||
|
||||
view.iterate(std::get<0>(storage)).iterate(std::get<1>(storage));
|
||||
|
||||
view.each([&](auto entt) {
|
||||
ASSERT_EQ(entt, entity[0u]);
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, ExcludedComponents) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
std::tuple<entt::storage<int>, entt::storage<char>> storage{};
|
||||
const std::array entity{entt::entity{1}, entt::entity{3}};
|
||||
runtime_view_type view{};
|
||||
|
||||
std::get<0>(storage).emplace(entity[0u]);
|
||||
|
||||
std::get<0>(storage).emplace(entity[1u]);
|
||||
std::get<1>(storage).emplace(entity[1u]);
|
||||
|
||||
view.iterate(std::get<0>(storage)).exclude(std::get<1>(storage));
|
||||
|
||||
ASSERT_TRUE(view.contains(entity[0u]));
|
||||
ASSERT_FALSE(view.contains(entity[1u]));
|
||||
|
||||
view.each([&](auto entt) {
|
||||
ASSERT_EQ(entt, entity[0u]);
|
||||
});
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, StableType) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
std::tuple<entt::storage<int>, entt::storage<test::pointer_stable>> storage{};
|
||||
const std::array entity{entt::entity{0}, entt::entity{1}, entt::entity{3}};
|
||||
runtime_view_type view{};
|
||||
|
||||
std::get<0>(storage).emplace(entity[0u]);
|
||||
std::get<0>(storage).emplace(entity[1u]);
|
||||
std::get<0>(storage).emplace(entity[2u]);
|
||||
|
||||
std::get<1>(storage).emplace(entity[0u]);
|
||||
std::get<1>(storage).emplace(entity[1u]);
|
||||
|
||||
std::get<1>(storage).remove(entity[1u]);
|
||||
|
||||
view.iterate(std::get<0>(storage)).iterate(std::get<1>(storage));
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 2u);
|
||||
ASSERT_TRUE(view.contains(entity[0u]));
|
||||
ASSERT_FALSE(view.contains(entity[1u]));
|
||||
|
||||
ASSERT_EQ(*view.begin(), entity[0u]);
|
||||
ASSERT_EQ(++view.begin(), view.end());
|
||||
|
||||
view.each([&](const auto entt) {
|
||||
ASSERT_EQ(entt, entity[0u]);
|
||||
});
|
||||
|
||||
for(auto entt: view) {
|
||||
testing::StaticAssertTypeEq<decltype(entt), entt::entity>();
|
||||
ASSERT_EQ(entt, entity[0u]);
|
||||
}
|
||||
|
||||
std::get<1>(storage).compact();
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 1u);
|
||||
}
|
||||
|
||||
TYPED_TEST(RuntimeView, StableTypeWithExcludedComponent) {
|
||||
using runtime_view_type = typename TestFixture::type;
|
||||
|
||||
constexpr entt::entity tombstone = entt::tombstone;
|
||||
std::tuple<entt::storage<int>, entt::storage<test::pointer_stable>> storage{};
|
||||
const std::array entity{entt::entity{1}, entt::entity{3}};
|
||||
runtime_view_type view{};
|
||||
|
||||
std::get<1>(storage).emplace(entity[0u], 0);
|
||||
std::get<1>(storage).emplace(entity[1u], 1);
|
||||
std::get<0>(storage).emplace(entity[0u]);
|
||||
|
||||
view.iterate(std::get<1>(storage)).exclude(std::get<0>(storage));
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 2u);
|
||||
ASSERT_FALSE(view.contains(entity[0u]));
|
||||
ASSERT_TRUE(view.contains(entity[1u]));
|
||||
|
||||
std::get<0>(storage).erase(entity[0u]);
|
||||
std::get<1>(storage).erase(entity[0u]);
|
||||
|
||||
ASSERT_EQ(view.size_hint(), 2u);
|
||||
ASSERT_FALSE(view.contains(entity[0u]));
|
||||
ASSERT_TRUE(view.contains(entity[1u]));
|
||||
|
||||
for(auto entt: view) {
|
||||
ASSERT_NE(entt, tombstone);
|
||||
ASSERT_EQ(entt, entity[1u]);
|
||||
}
|
||||
|
||||
view.each([&](const auto entt) {
|
||||
ASSERT_NE(entt, tombstone);
|
||||
ASSERT_EQ(entt, entity[1u]);
|
||||
});
|
||||
}
|
||||
720
lib/All/entt/test/entt/entity/sigh_mixin.cpp
Normal file
720
lib/All/entt/test/entt/entity/sigh_mixin.cpp
Normal file
@@ -0,0 +1,720 @@
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/entity/component.hpp>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/mixin.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/storage.hpp>
|
||||
#include <entt/signal/sigh.hpp>
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/entity.h"
|
||||
#include "../../common/linter.hpp"
|
||||
#include "../../common/non_default_constructible.h"
|
||||
#include "../../common/pointer_stable.h"
|
||||
#include "../../common/registry.h"
|
||||
#include "../../common/throwing_allocator.hpp"
|
||||
#include "../../common/throwing_type.hpp"
|
||||
|
||||
struct auto_signal final {
|
||||
auto_signal(bool &cflag, bool &uflag, bool &dflag)
|
||||
: created{&cflag},
|
||||
updated{&uflag},
|
||||
destroyed{&dflag} {}
|
||||
|
||||
static void on_construct(entt::registry ®istry, const entt::entity entt) {
|
||||
*registry.get<auto_signal>(entt).created = true;
|
||||
}
|
||||
|
||||
static void on_update(entt::registry ®istry, const entt::entity entt) {
|
||||
*registry.get<auto_signal>(entt).updated = true;
|
||||
}
|
||||
|
||||
static void on_destroy(entt::registry ®istry, const entt::entity entt) {
|
||||
*registry.get<auto_signal>(entt).destroyed = true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool *created{};
|
||||
bool *updated{};
|
||||
bool *destroyed{};
|
||||
};
|
||||
|
||||
template<typename Registry>
|
||||
void listener(std::size_t &counter, Registry &, typename Registry::entity_type) {
|
||||
++counter;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
struct SighMixin: testing::Test {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using SighMixinDeathTest = SighMixin<Type>;
|
||||
|
||||
using SighMixinTypes = ::testing::Types<int, test::pointer_stable>;
|
||||
|
||||
TYPED_TEST_SUITE(SighMixin, SighMixinTypes, );
|
||||
TYPED_TEST_SUITE(SighMixinDeathTest, SighMixinTypes, );
|
||||
|
||||
TYPED_TEST(SighMixin, Functionalities) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using traits_type = entt::component_traits<value_type>;
|
||||
|
||||
entt::registry registry;
|
||||
auto &pool = registry.storage<value_type>();
|
||||
const std::array entity{registry.create(), registry.create()};
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(pool), entt::sigh_mixin<entt::storage<value_type>> &>();
|
||||
|
||||
std::size_t on_construct{};
|
||||
std::size_t on_destroy{};
|
||||
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
|
||||
pool.insert(entity.begin(), entity.begin() + 1u);
|
||||
pool.erase(entity[0u]);
|
||||
|
||||
ASSERT_EQ(pool.size(), traits_type::in_place_delete);
|
||||
ASSERT_EQ(on_construct, 0u);
|
||||
ASSERT_EQ(on_destroy, 0u);
|
||||
|
||||
pool.on_construct().template connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().template connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
ASSERT_NE(pool.push(entity[0u]), pool.entt::sparse_set::end());
|
||||
|
||||
pool.emplace(entity[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct, 2u);
|
||||
ASSERT_EQ(on_destroy, 0u);
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
|
||||
ASSERT_EQ(pool.get(entity[0u]), value_type{0});
|
||||
ASSERT_EQ(pool.get(entity[1u]), value_type{0});
|
||||
|
||||
pool.erase(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_EQ(on_construct, 2u);
|
||||
ASSERT_EQ(on_destroy, 2u);
|
||||
ASSERT_EQ(pool.size(), 2u * traits_type::in_place_delete);
|
||||
|
||||
ASSERT_NE(pool.push(entity.begin(), entity.end()), pool.entt::sparse_set::end());
|
||||
|
||||
ASSERT_EQ(pool.get(entity[0u]), value_type{0});
|
||||
ASSERT_EQ(pool.get(entity[1u]), value_type{0});
|
||||
ASSERT_EQ(pool.size(), traits_type::in_place_delete ? 4u : 2u);
|
||||
|
||||
pool.erase(entity[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct, 4u);
|
||||
ASSERT_EQ(on_destroy, 3u);
|
||||
ASSERT_EQ(pool.size(), traits_type::in_place_delete ? 4u : 1u);
|
||||
|
||||
pool.erase(entity[0u]);
|
||||
|
||||
ASSERT_EQ(on_construct, 4u);
|
||||
ASSERT_EQ(on_destroy, 4u);
|
||||
ASSERT_EQ(pool.size(), traits_type::in_place_delete ? 4u : 0u);
|
||||
|
||||
pool.insert(entity.begin(), entity.end(), value_type{3});
|
||||
|
||||
ASSERT_EQ(on_construct, 6u);
|
||||
ASSERT_EQ(on_destroy, 4u);
|
||||
ASSERT_EQ(pool.size(), traits_type::in_place_delete ? 6u : 2u);
|
||||
|
||||
ASSERT_EQ(pool.get(entity[0u]), value_type{3});
|
||||
ASSERT_EQ(pool.get(entity[1u]), value_type{3});
|
||||
|
||||
pool.clear();
|
||||
|
||||
ASSERT_EQ(on_construct, 6u);
|
||||
ASSERT_EQ(on_destroy, 6u);
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
}
|
||||
|
||||
TYPED_TEST(SighMixin, InsertWeakRange) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
auto &pool = registry.storage<value_type>();
|
||||
const auto view = registry.view<entt::entity>(entt::exclude<value_type>);
|
||||
[[maybe_unused]] const std::array entity{registry.create(), registry.create()};
|
||||
std::size_t on_construct{};
|
||||
|
||||
ASSERT_EQ(on_construct, 0u);
|
||||
|
||||
pool.on_construct().template connect<&listener<entt::registry>>(on_construct);
|
||||
pool.insert(view.begin(), view.end());
|
||||
|
||||
ASSERT_EQ(on_construct, 2u);
|
||||
}
|
||||
|
||||
TEST(SighMixin, NonDefaultConstructibleType) {
|
||||
entt::registry registry;
|
||||
auto &pool = registry.storage<test::non_default_constructible>();
|
||||
const std::array entity{registry.create(), registry.create()};
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(pool), entt::sigh_mixin<entt::storage<test::non_default_constructible>> &>();
|
||||
|
||||
std::size_t on_construct{};
|
||||
std::size_t on_destroy{};
|
||||
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
|
||||
pool.insert(entity.begin(), entity.begin() + 1u, 0);
|
||||
pool.erase(entity[0u]);
|
||||
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
ASSERT_EQ(on_construct, 0u);
|
||||
ASSERT_EQ(on_destroy, 0u);
|
||||
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
ASSERT_EQ(pool.push(entity[0u]), pool.entt::sparse_set::end());
|
||||
|
||||
pool.emplace(entity[1u], 3);
|
||||
|
||||
ASSERT_EQ(on_construct, 1u);
|
||||
ASSERT_EQ(on_destroy, 0u);
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
|
||||
ASSERT_FALSE(pool.contains(entity[0u]));
|
||||
ASSERT_EQ(pool.get(entity[1u]).value, 3);
|
||||
|
||||
pool.erase(entity[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct, 1u);
|
||||
ASSERT_EQ(on_destroy, 1u);
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
|
||||
ASSERT_EQ(pool.push(entity.begin(), entity.end()), pool.entt::sparse_set::end());
|
||||
|
||||
ASSERT_FALSE(pool.contains(entity[0u]));
|
||||
ASSERT_FALSE(pool.contains(entity[1u]));
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
|
||||
pool.insert(entity.begin(), entity.end(), 3);
|
||||
|
||||
ASSERT_EQ(on_construct, 3u);
|
||||
ASSERT_EQ(on_destroy, 1u);
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
|
||||
ASSERT_EQ(pool.get(entity[0u]).value, 3);
|
||||
ASSERT_EQ(pool.get(entity[1u]).value, 3);
|
||||
|
||||
pool.erase(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_EQ(on_construct, 3u);
|
||||
ASSERT_EQ(on_destroy, 3u);
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(SighMixin, VoidType) {
|
||||
entt::registry registry;
|
||||
auto &pool = registry.storage<void>();
|
||||
const auto entity = registry.create();
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(pool), entt::sigh_mixin<entt::storage<void>> &>();
|
||||
|
||||
std::size_t on_construct{};
|
||||
std::size_t on_destroy{};
|
||||
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
pool.emplace(entity);
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<void>());
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
|
||||
entt::sigh_mixin<entt::storage<void>> other{std::move(pool)};
|
||||
|
||||
test::is_initialized(pool);
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_TRUE(other.contains(entity));
|
||||
|
||||
pool = std::move(other);
|
||||
test::is_initialized(other);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity));
|
||||
ASSERT_TRUE(other.empty());
|
||||
|
||||
pool.clear();
|
||||
|
||||
ASSERT_EQ(on_construct, 1u);
|
||||
ASSERT_EQ(on_destroy, 1u);
|
||||
}
|
||||
|
||||
TEST(SighMixin, StorageEntity) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
auto &pool = registry.storage<entt::entity>();
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(pool), entt::sigh_mixin<entt::storage<entt::entity>> &>();
|
||||
|
||||
std::size_t on_construct{};
|
||||
std::size_t on_destroy{};
|
||||
|
||||
pool.on_construct().connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
pool.push(entt::entity{1});
|
||||
|
||||
ASSERT_EQ(on_construct, 1u);
|
||||
ASSERT_EQ(on_destroy, 0u);
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(pool.free_list(), 1u);
|
||||
|
||||
pool.erase(entt::entity{1});
|
||||
|
||||
ASSERT_EQ(on_construct, 1u);
|
||||
ASSERT_EQ(on_destroy, 1u);
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(pool.free_list(), 0u);
|
||||
|
||||
pool.push(traits_type::construct(0, 2));
|
||||
pool.push(traits_type::construct(2, 1));
|
||||
|
||||
ASSERT_TRUE(pool.contains(traits_type::construct(0, 2)));
|
||||
ASSERT_TRUE(pool.contains(traits_type::construct(1, 1)));
|
||||
ASSERT_TRUE(pool.contains(traits_type::construct(2, 1)));
|
||||
|
||||
ASSERT_EQ(on_construct, 3u);
|
||||
ASSERT_EQ(on_destroy, 1u);
|
||||
ASSERT_EQ(pool.size(), 3u);
|
||||
ASSERT_EQ(pool.free_list(), 2u);
|
||||
|
||||
pool.clear();
|
||||
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
ASSERT_EQ(pool.free_list(), 0u);
|
||||
|
||||
ASSERT_EQ(on_construct, 3u);
|
||||
ASSERT_EQ(on_destroy, 3u);
|
||||
|
||||
pool.generate();
|
||||
pool.generate(entt::entity{0});
|
||||
|
||||
std::array<entt::entity, 1u> entity{};
|
||||
pool.generate(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_EQ(on_construct, 6u);
|
||||
ASSERT_EQ(on_destroy, 3u);
|
||||
ASSERT_EQ(pool.size(), 3u);
|
||||
ASSERT_EQ(pool.free_list(), 3u);
|
||||
|
||||
pool.clear();
|
||||
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
ASSERT_EQ(pool.free_list(), 0u);
|
||||
}
|
||||
|
||||
TYPED_TEST(SighMixin, Move) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::sigh_mixin<entt::storage<value_type>> pool;
|
||||
entt::registry registry;
|
||||
|
||||
std::size_t on_construct{};
|
||||
std::size_t on_destroy{};
|
||||
|
||||
pool.bind(registry);
|
||||
pool.on_construct().template connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().template connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
pool.emplace(entt::entity{3}, 3);
|
||||
|
||||
static_assert(std::is_move_constructible_v<decltype(pool)>, "Move constructible type required");
|
||||
static_assert(std::is_move_assignable_v<decltype(pool)>, "Move assignable type required");
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
|
||||
|
||||
entt::sigh_mixin<entt::storage<value_type>> other{std::move(pool)};
|
||||
|
||||
test::is_initialized(pool);
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
|
||||
ASSERT_EQ(other.type(), entt::type_id<value_type>());
|
||||
|
||||
ASSERT_EQ(other.index(entt::entity{3}), 0u);
|
||||
ASSERT_EQ(other.get(entt::entity{3}), value_type{3});
|
||||
|
||||
pool = std::move(other);
|
||||
test::is_initialized(other);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
|
||||
ASSERT_EQ(pool.index(entt::entity{3}), 0u);
|
||||
ASSERT_EQ(pool.get(entt::entity{3}), value_type{3});
|
||||
|
||||
other = entt::sigh_mixin<entt::storage<value_type>>{};
|
||||
other.bind(registry);
|
||||
|
||||
other.emplace(entt::entity{1}, 1);
|
||||
other = std::move(pool);
|
||||
test::is_initialized(pool);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
|
||||
ASSERT_EQ(other.index(entt::entity{3}), 0u);
|
||||
ASSERT_EQ(other.get(entt::entity{3}), value_type{3});
|
||||
|
||||
other.clear();
|
||||
|
||||
ASSERT_EQ(on_construct, 1u);
|
||||
ASSERT_EQ(on_destroy, 1u);
|
||||
}
|
||||
|
||||
TYPED_TEST(SighMixin, Swap) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using traits_type = entt::component_traits<value_type>;
|
||||
|
||||
entt::sigh_mixin<entt::storage<value_type>> pool;
|
||||
entt::sigh_mixin<entt::storage<value_type>> other;
|
||||
entt::registry registry;
|
||||
|
||||
std::size_t on_construct{};
|
||||
std::size_t on_destroy{};
|
||||
|
||||
pool.bind(registry);
|
||||
pool.on_construct().template connect<&listener<entt::registry>>(on_construct);
|
||||
pool.on_destroy().template connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
other.bind(registry);
|
||||
other.on_construct().template connect<&listener<entt::registry>>(on_construct);
|
||||
other.on_destroy().template connect<&listener<entt::registry>>(on_destroy);
|
||||
|
||||
pool.emplace(entt::entity{4}, 1);
|
||||
|
||||
other.emplace(entt::entity{2}, 2);
|
||||
other.emplace(entt::entity{1}, 3);
|
||||
other.erase(entt::entity{2});
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 1u + traits_type::in_place_delete);
|
||||
|
||||
pool.swap(other);
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
|
||||
ASSERT_EQ(other.type(), entt::type_id<value_type>());
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u + traits_type::in_place_delete);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
|
||||
ASSERT_EQ(pool.index(entt::entity{1}), traits_type::in_place_delete);
|
||||
ASSERT_EQ(other.index(entt::entity{4}), 0u);
|
||||
|
||||
ASSERT_EQ(pool.get(entt::entity{1}), value_type{3});
|
||||
ASSERT_EQ(other.get(entt::entity{4}), value_type{1});
|
||||
|
||||
pool.clear();
|
||||
other.clear();
|
||||
|
||||
ASSERT_EQ(on_construct, 3u);
|
||||
ASSERT_EQ(on_destroy, 3u);
|
||||
}
|
||||
|
||||
TEST(SighMixin, AutoSignal) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
bool created{};
|
||||
bool updated{};
|
||||
bool destroyed{};
|
||||
|
||||
registry.emplace<auto_signal>(entity, created, updated, destroyed);
|
||||
registry.replace<auto_signal>(entity, created, updated, destroyed);
|
||||
registry.erase<auto_signal>(entity);
|
||||
|
||||
ASSERT_TRUE(created);
|
||||
ASSERT_TRUE(updated);
|
||||
ASSERT_TRUE(destroyed);
|
||||
|
||||
ASSERT_TRUE(registry.storage<auto_signal>().empty());
|
||||
ASSERT_TRUE(registry.valid(entity));
|
||||
|
||||
created = updated = destroyed = false;
|
||||
|
||||
registry.emplace<auto_signal>(entity, created, updated, destroyed);
|
||||
registry.replace<auto_signal>(entity, created, updated, destroyed);
|
||||
registry.destroy(entity);
|
||||
|
||||
ASSERT_TRUE(created);
|
||||
ASSERT_TRUE(updated);
|
||||
ASSERT_TRUE(destroyed);
|
||||
|
||||
ASSERT_TRUE(registry.storage<auto_signal>().empty());
|
||||
ASSERT_FALSE(registry.valid(entity));
|
||||
}
|
||||
|
||||
TYPED_TEST(SighMixin, Registry) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::registry registry;
|
||||
entt::sigh_mixin<entt::storage<value_type>> pool;
|
||||
|
||||
ASSERT_FALSE(pool);
|
||||
|
||||
pool.bind(registry);
|
||||
|
||||
ASSERT_TRUE(pool);
|
||||
ASSERT_EQ(&pool.registry(), ®istry);
|
||||
ASSERT_EQ(&std::as_const(pool).registry(), ®istry);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(SighMixinDeathTest, Registry) {
|
||||
using value_type = typename TestFixture::type;
|
||||
entt::sigh_mixin<entt::storage<value_type>> pool;
|
||||
ASSERT_DEATH([[maybe_unused]] auto ®istry = pool.registry(), "");
|
||||
ASSERT_DEATH([[maybe_unused]] const auto ®istry = std::as_const(pool).registry(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(SighMixin, CustomRegistry) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using registry_type = test::custom_registry<test::entity>;
|
||||
|
||||
registry_type registry;
|
||||
entt::basic_sigh_mixin<entt::basic_storage<value_type, test::entity>, registry_type> pool;
|
||||
const std::array entity{registry.create(), registry.create()};
|
||||
|
||||
ASSERT_FALSE(pool);
|
||||
|
||||
pool.bind(registry);
|
||||
|
||||
ASSERT_TRUE(pool);
|
||||
|
||||
std::size_t on_construct{};
|
||||
std::size_t on_destroy{};
|
||||
|
||||
pool.on_construct().template connect<&listener<registry_type>>(on_construct);
|
||||
pool.on_destroy().template connect<&listener<registry_type>>(on_destroy);
|
||||
|
||||
pool.emplace(entity[0u]);
|
||||
pool.emplace(entity[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct, 2u);
|
||||
ASSERT_EQ(on_destroy, 0u);
|
||||
|
||||
pool.clear();
|
||||
|
||||
ASSERT_EQ(on_construct, 2u);
|
||||
ASSERT_EQ(on_destroy, 2u);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(SighMixinDeathTest, CustomRegistry) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using registry_type = test::custom_registry<test::entity>;
|
||||
entt::basic_sigh_mixin<entt::basic_storage<value_type, test::entity>, registry_type> pool;
|
||||
ASSERT_DEATH([[maybe_unused]] auto ®istry = pool.registry(), "");
|
||||
ASSERT_DEATH([[maybe_unused]] const auto ®istry = std::as_const(pool).registry(), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(SighMixin, CustomAllocator) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using storage_type = entt::sigh_mixin<entt::basic_storage<value_type, entt::entity, test::throwing_allocator<value_type>>>;
|
||||
using registry_type = typename storage_type::registry_type;
|
||||
|
||||
const test::throwing_allocator<entt::entity> allocator{};
|
||||
storage_type pool{allocator};
|
||||
registry_type registry;
|
||||
|
||||
std::size_t on_construct{};
|
||||
std::size_t on_destroy{};
|
||||
|
||||
pool.bind(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), allocator};
|
||||
|
||||
test::is_initialized(pool);
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_NE(other.capacity(), 0u);
|
||||
ASSERT_EQ(other.size(), 2u);
|
||||
|
||||
pool = std::move(other);
|
||||
test::is_initialized(other);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_NE(pool.capacity(), 0u);
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
|
||||
other = {};
|
||||
pool.swap(other);
|
||||
pool = std::move(other);
|
||||
test::is_initialized(other);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
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, 2u);
|
||||
ASSERT_EQ(on_destroy, 2u);
|
||||
}
|
||||
|
||||
TYPED_TEST(SighMixin, ThrowingAllocator) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using storage_type = entt::sigh_mixin<entt::basic_storage<value_type, entt::entity, test::throwing_allocator<value_type>>>;
|
||||
using registry_type = typename storage_type::registry_type;
|
||||
|
||||
storage_type pool{};
|
||||
typename storage_type::base_type &base = pool;
|
||||
registry_type registry;
|
||||
|
||||
constexpr auto packed_page_size = entt::component_traits<value_type>::page_size;
|
||||
constexpr auto sparse_page_size = entt::entt_traits<entt::entity>::page_size;
|
||||
|
||||
std::size_t on_construct{};
|
||||
std::size_t on_destroy{};
|
||||
|
||||
pool.bind(registry);
|
||||
pool.on_construct().template connect<&listener<registry_type>>(on_construct);
|
||||
pool.on_destroy().template connect<&listener<registry_type>>(on_destroy);
|
||||
|
||||
pool.get_allocator().template throw_counter<value_type>(0u);
|
||||
|
||||
ASSERT_THROW(pool.reserve(1u), test::throwing_allocator_exception);
|
||||
ASSERT_EQ(pool.capacity(), 0u);
|
||||
|
||||
pool.get_allocator().template throw_counter<value_type>(1u);
|
||||
|
||||
ASSERT_THROW(pool.reserve(2 * packed_page_size), test::throwing_allocator_exception);
|
||||
ASSERT_EQ(pool.capacity(), packed_page_size);
|
||||
|
||||
pool.shrink_to_fit();
|
||||
|
||||
ASSERT_EQ(pool.capacity(), 0u);
|
||||
|
||||
pool.get_allocator().template throw_counter<entt::entity>(0u);
|
||||
|
||||
ASSERT_THROW(pool.emplace(entt::entity{0}, 0), test::throwing_allocator_exception);
|
||||
ASSERT_FALSE(pool.contains(entt::entity{0}));
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
pool.get_allocator().template throw_counter<entt::entity>(0u);
|
||||
|
||||
ASSERT_THROW(base.push(entt::entity{0}), test::throwing_allocator_exception);
|
||||
ASSERT_FALSE(base.contains(entt::entity{0}));
|
||||
ASSERT_TRUE(base.empty());
|
||||
|
||||
pool.get_allocator().template throw_counter<value_type>(0u);
|
||||
|
||||
ASSERT_THROW(pool.emplace(entt::entity{0}, 0), test::throwing_allocator_exception);
|
||||
ASSERT_FALSE(pool.contains(entt::entity{0}));
|
||||
ASSERT_NO_THROW(pool.compact());
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
pool.emplace(entt::entity{0}, 0);
|
||||
const std::array entity{entt::entity{1}, entt::entity{sparse_page_size}};
|
||||
pool.get_allocator().template throw_counter<entt::entity>(1u);
|
||||
|
||||
ASSERT_THROW(pool.insert(entity.begin(), entity.end(), value_type{0}), test::throwing_allocator_exception);
|
||||
ASSERT_TRUE(pool.contains(entt::entity{1}));
|
||||
ASSERT_FALSE(pool.contains(entt::entity{sparse_page_size}));
|
||||
|
||||
pool.erase(entt::entity{1});
|
||||
const std::array component{value_type{1}, value_type{sparse_page_size}};
|
||||
pool.get_allocator().template throw_counter<entt::entity>(0u);
|
||||
pool.compact();
|
||||
|
||||
ASSERT_THROW(pool.insert(entity.begin(), entity.end(), component.begin()), test::throwing_allocator_exception);
|
||||
ASSERT_TRUE(pool.contains(entt::entity{1}));
|
||||
ASSERT_FALSE(pool.contains(entt::entity{sparse_page_size}));
|
||||
|
||||
ASSERT_EQ(on_construct, 1u);
|
||||
ASSERT_EQ(on_destroy, 1u);
|
||||
}
|
||||
|
||||
TEST(SighMixin, ThrowingComponent) {
|
||||
using storage_type = entt::sigh_mixin<entt::storage<test::throwing_type>>;
|
||||
using registry_type = typename storage_type::registry_type;
|
||||
|
||||
storage_type pool;
|
||||
registry_type registry;
|
||||
|
||||
std::size_t on_construct{};
|
||||
std::size_t on_destroy{};
|
||||
|
||||
pool.bind(registry);
|
||||
pool.on_construct().connect<&listener<registry_type>>(on_construct);
|
||||
pool.on_destroy().connect<&listener<registry_type>>(on_destroy);
|
||||
|
||||
const std::array entity{entt::entity{3}, entt::entity{1}};
|
||||
const std::array<test::throwing_type, 2u> value{true, false};
|
||||
|
||||
// strong exception safety
|
||||
ASSERT_THROW(pool.emplace(entity[0u], value[0u]), test::throwing_type_exception);
|
||||
ASSERT_TRUE(pool.empty());
|
||||
|
||||
// basic exception safety
|
||||
ASSERT_THROW(pool.insert(entity.begin(), entity.end(), value[0u]), test::throwing_type_exception);
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
ASSERT_FALSE(pool.contains(entity[1u]));
|
||||
|
||||
// basic exception safety
|
||||
ASSERT_THROW(pool.insert(entity.begin(), entity.end(), value.begin()), test::throwing_type_exception);
|
||||
ASSERT_EQ(pool.size(), 0u);
|
||||
ASSERT_FALSE(pool.contains(entity[1u]));
|
||||
|
||||
// basic exception safety
|
||||
ASSERT_THROW(pool.insert(entity.rbegin(), entity.rend(), value.rbegin()), test::throwing_type_exception);
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_TRUE(pool.contains(entity[1u]));
|
||||
ASSERT_EQ(pool.get(entity[1u]), value[1u]);
|
||||
|
||||
pool.clear();
|
||||
pool.emplace(entity[1u], value[0u].throw_on_copy());
|
||||
pool.emplace(entity[0u], value[1u].throw_on_copy());
|
||||
|
||||
// basic exception safety
|
||||
ASSERT_THROW(pool.erase(entity[1u]), test::throwing_type_exception);
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_TRUE(pool.contains(entity[0u]));
|
||||
ASSERT_TRUE(pool.contains(entity[1u]));
|
||||
ASSERT_EQ(pool.index(entity[0u]), 1u);
|
||||
ASSERT_EQ(pool.index(entity[1u]), 0u);
|
||||
ASSERT_EQ(pool.get(entity[0u]), value[1u]);
|
||||
// the element may have been moved but it's still there
|
||||
ASSERT_EQ(pool.get(entity[1u]), value[0u]);
|
||||
|
||||
pool.get(entity[1u]).throw_on_copy(false);
|
||||
pool.erase(entity[1u]);
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_TRUE(pool.contains(entity[0u]));
|
||||
ASSERT_FALSE(pool.contains(entity[1u]));
|
||||
ASSERT_EQ(pool.index(entity[0u]), 0u);
|
||||
ASSERT_EQ(pool.get(entity[0u]), value[1u]);
|
||||
|
||||
ASSERT_EQ(on_construct, 2u);
|
||||
ASSERT_EQ(on_destroy, 3u);
|
||||
}
|
||||
992
lib/All/entt/test/entt/entity/snapshot.cpp
Normal file
992
lib/All/entt/test/entt/entity/snapshot.cpp
Normal file
@@ -0,0 +1,992 @@
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/any.hpp>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/mixin.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <entt/entity/snapshot.hpp>
|
||||
#include <entt/signal/sigh.hpp>
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/empty.h"
|
||||
#include "../../common/pointer_stable.h"
|
||||
|
||||
struct shadow {
|
||||
entt::entity target{entt::null};
|
||||
|
||||
static void listener(entt::entity &elem, entt::registry ®istry, const entt::entity entt) {
|
||||
elem = registry.get<shadow>(entt).target;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(BasicSnapshot, Constructors) {
|
||||
static_assert(!std::is_default_constructible_v<entt::basic_snapshot<entt::registry>>, "Default constructible type not allowed");
|
||||
static_assert(!std::is_copy_constructible_v<entt::basic_snapshot<entt::registry>>, "Copy constructible type not allowed");
|
||||
static_assert(!std::is_copy_assignable_v<entt::basic_snapshot<entt::registry>>, "Copy assignable type not allowed");
|
||||
static_assert(std::is_move_constructible_v<entt::basic_snapshot<entt::registry>>, "Move constructible type required");
|
||||
static_assert(std::is_move_assignable_v<entt::basic_snapshot<entt::registry>>, "Move assignable type required");
|
||||
|
||||
const entt::registry registry;
|
||||
entt::basic_snapshot snapshot{registry};
|
||||
entt::basic_snapshot other{std::move(snapshot)};
|
||||
|
||||
ASSERT_NO_THROW(snapshot = std::move(other));
|
||||
}
|
||||
|
||||
TEST(BasicSnapshot, GetEntityType) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
const entt::basic_snapshot snapshot{registry};
|
||||
const auto &storage = registry.storage<entt::entity>();
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data](auto &&elem) { data.emplace_back(std::forward<decltype(elem)>(elem)); };
|
||||
|
||||
snapshot.get<entt::entity>(archive);
|
||||
|
||||
ASSERT_EQ(data.size(), 2u);
|
||||
|
||||
ASSERT_NE(entt::any_cast<typename traits_type::entity_type>(data.data()), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<typename traits_type::entity_type>(data[0u]), storage.size());
|
||||
|
||||
ASSERT_NE(entt::any_cast<typename traits_type::entity_type>(&data[1u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<typename traits_type::entity_type>(data[1u]), storage.free_list());
|
||||
|
||||
constexpr auto number_of_entities = 3u;
|
||||
std::array<entt::entity, number_of_entities> entity{};
|
||||
|
||||
registry.create(entity.begin(), entity.end());
|
||||
registry.destroy(entity[1u]);
|
||||
|
||||
data.clear();
|
||||
snapshot.get<entt::entity>(archive);
|
||||
|
||||
ASSERT_EQ(data.size(), 5u);
|
||||
|
||||
ASSERT_NE(entt::any_cast<typename traits_type::entity_type>(data.data()), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<typename traits_type::entity_type>(data[0u]), storage.size());
|
||||
|
||||
ASSERT_NE(entt::any_cast<typename traits_type::entity_type>(&data[1u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<typename traits_type::entity_type>(data[1u]), storage.free_list());
|
||||
|
||||
ASSERT_NE(entt::any_cast<entt::entity>(&data[2u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<entt::entity>(data[2u]), storage.data()[0u]);
|
||||
|
||||
ASSERT_NE(entt::any_cast<entt::entity>(&data[3u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<entt::entity>(data[3u]), storage.data()[1u]);
|
||||
|
||||
ASSERT_NE(entt::any_cast<entt::entity>(&data[4u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<entt::entity>(data[4u]), storage.data()[2u]);
|
||||
}
|
||||
|
||||
TEST(BasicSnapshot, GetType) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
const entt::basic_snapshot snapshot{registry};
|
||||
const auto &storage = registry.storage<int>();
|
||||
constexpr auto number_of_entities = 3u;
|
||||
|
||||
std::array<entt::entity, number_of_entities> entity{};
|
||||
const std::array value{1, 2, 3};
|
||||
|
||||
registry.create(entity.begin(), entity.end());
|
||||
registry.insert<int>(entity.begin(), entity.end(), value.begin());
|
||||
registry.destroy(entity[1u]);
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data](auto &&elem) { data.emplace_back(std::forward<decltype(elem)>(elem)); };
|
||||
|
||||
snapshot.get<int>(archive, "other"_hs);
|
||||
|
||||
ASSERT_EQ(data.size(), 1u);
|
||||
|
||||
ASSERT_NE(entt::any_cast<typename traits_type::entity_type>(data.data()), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<typename traits_type::entity_type>(data[0u]), 0u);
|
||||
|
||||
data.clear();
|
||||
snapshot.get<int>(archive);
|
||||
|
||||
ASSERT_EQ(data.size(), 5u);
|
||||
|
||||
ASSERT_NE(entt::any_cast<typename traits_type::entity_type>(data.data()), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<typename traits_type::entity_type>(data[0u]), storage.size());
|
||||
|
||||
ASSERT_NE(entt::any_cast<entt::entity>(&data[1u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<entt::entity>(data[1u]), entity[0u]);
|
||||
|
||||
ASSERT_NE(entt::any_cast<int>(&data[2u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<int>(data[2u]), value[0u]);
|
||||
|
||||
ASSERT_NE(entt::any_cast<entt::entity>(&data[3u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<entt::entity>(data[3u]), entity[2u]);
|
||||
|
||||
ASSERT_NE(entt::any_cast<int>(&data[4u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<int>(data[4u]), value[2u]);
|
||||
}
|
||||
|
||||
TEST(BasicSnapshot, GetPointerStableType) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
const entt::basic_snapshot snapshot{registry};
|
||||
const auto &storage = registry.storage<test::pointer_stable>();
|
||||
constexpr auto number_of_entities = 3u;
|
||||
|
||||
std::array<entt::entity, number_of_entities> entity{};
|
||||
const std::array value{test::pointer_stable{1}, test::pointer_stable{2}, test::pointer_stable{3}};
|
||||
|
||||
registry.create(entity.begin(), entity.end());
|
||||
registry.insert<test::pointer_stable>(entity.begin(), entity.end(), value.begin());
|
||||
registry.destroy(entity[1u]);
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data](auto &&elem) { data.emplace_back(std::forward<decltype(elem)>(elem)); };
|
||||
|
||||
snapshot.get<test::pointer_stable>(archive, "other"_hs);
|
||||
|
||||
ASSERT_EQ(data.size(), 1u);
|
||||
|
||||
ASSERT_NE(entt::any_cast<typename traits_type::entity_type>(data.data()), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<typename traits_type::entity_type>(data[0u]), 0u);
|
||||
|
||||
data.clear();
|
||||
snapshot.get<test::pointer_stable>(archive);
|
||||
|
||||
ASSERT_EQ(data.size(), 6u);
|
||||
|
||||
ASSERT_NE(entt::any_cast<typename traits_type::entity_type>(data.data()), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<typename traits_type::entity_type>(data[0u]), storage.size());
|
||||
|
||||
ASSERT_NE(entt::any_cast<entt::entity>(&data[1u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<entt::entity>(data[1u]), entity[0u]);
|
||||
|
||||
ASSERT_NE(entt::any_cast<test::pointer_stable>(&data[2u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<test::pointer_stable>(data[2u]), value[0u]);
|
||||
|
||||
ASSERT_NE(entt::any_cast<entt::entity>(&data[3u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<entt::entity>(data[3u]), static_cast<entt::entity>(entt::null));
|
||||
|
||||
ASSERT_NE(entt::any_cast<entt::entity>(&data[4u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<entt::entity>(data[4u]), entity[2u]);
|
||||
|
||||
ASSERT_NE(entt::any_cast<test::pointer_stable>(&data[5u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<test::pointer_stable>(data[5u]), value[2u]);
|
||||
}
|
||||
|
||||
TEST(BasicSnapshot, GetEmptyType) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
const entt::basic_snapshot snapshot{registry};
|
||||
const auto &storage = registry.storage<test::empty>();
|
||||
constexpr auto number_of_entities = 3u;
|
||||
|
||||
std::array<entt::entity, number_of_entities> entity{};
|
||||
|
||||
registry.create(entity.begin(), entity.end());
|
||||
registry.insert<test::empty>(entity.begin(), entity.end());
|
||||
registry.destroy(entity[1u]);
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data](auto &&elem) { data.emplace_back(std::forward<decltype(elem)>(elem)); };
|
||||
|
||||
snapshot.get<test::empty>(archive, "other"_hs);
|
||||
|
||||
ASSERT_EQ(data.size(), 1u);
|
||||
|
||||
ASSERT_NE(entt::any_cast<typename traits_type::entity_type>(data.data()), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<typename traits_type::entity_type>(data[0u]), 0u);
|
||||
|
||||
data.clear();
|
||||
snapshot.get<test::empty>(archive);
|
||||
|
||||
ASSERT_EQ(data.size(), 3u);
|
||||
|
||||
ASSERT_NE(entt::any_cast<typename traits_type::entity_type>(data.data()), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<typename traits_type::entity_type>(data[0u]), storage.size());
|
||||
|
||||
ASSERT_NE(entt::any_cast<entt::entity>(&data[1u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<entt::entity>(data[1u]), entity[0u]);
|
||||
|
||||
ASSERT_NE(entt::any_cast<entt::entity>(&data[2u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<entt::entity>(data[2u]), entity[2u]);
|
||||
}
|
||||
|
||||
TEST(BasicSnapshot, GetTypeSparse) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
const entt::basic_snapshot snapshot{registry};
|
||||
constexpr auto number_of_entities = 3u;
|
||||
|
||||
std::array<entt::entity, number_of_entities> entity{};
|
||||
const std::array value{1, 2, 3};
|
||||
|
||||
registry.create(entity.begin(), entity.end());
|
||||
registry.insert<int>(entity.begin(), entity.end(), value.begin());
|
||||
registry.destroy(entity[1u]);
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data](auto &&elem) { data.emplace_back(std::forward<decltype(elem)>(elem)); };
|
||||
|
||||
snapshot.get<int>(archive, entity.begin(), entity.end(), "other"_hs);
|
||||
|
||||
ASSERT_EQ(data.size(), 1u);
|
||||
|
||||
ASSERT_NE(entt::any_cast<typename traits_type::entity_type>(data.data()), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<typename traits_type::entity_type>(data[0u]), 0u);
|
||||
|
||||
data.clear();
|
||||
snapshot.get<int>(archive, entity.begin(), entity.end());
|
||||
|
||||
ASSERT_EQ(data.size(), 6u);
|
||||
|
||||
ASSERT_NE(entt::any_cast<typename traits_type::entity_type>(data.data()), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<typename traits_type::entity_type>(data[0u]), static_cast<typename traits_type::entity_type>(std::distance(entity.begin(), entity.end())));
|
||||
|
||||
ASSERT_NE(entt::any_cast<entt::entity>(&data[1u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<entt::entity>(data[1u]), entity[0u]);
|
||||
|
||||
ASSERT_NE(entt::any_cast<int>(&data[2u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<int>(data[2u]), value[0u]);
|
||||
|
||||
ASSERT_NE(entt::any_cast<entt::entity>(&data[3u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<entt::entity>(data[3u]), static_cast<entt::entity>(entt::null));
|
||||
|
||||
ASSERT_NE(entt::any_cast<entt::entity>(&data[4u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<entt::entity>(data[4u]), entity[2u]);
|
||||
|
||||
ASSERT_NE(entt::any_cast<int>(&data[5u]), nullptr);
|
||||
ASSERT_EQ(entt::any_cast<int>(data[5u]), value[2u]);
|
||||
}
|
||||
|
||||
TEST(BasicSnapshotLoader, Constructors) {
|
||||
static_assert(!std::is_default_constructible_v<entt::basic_snapshot_loader<entt::registry>>, "Default constructible type not allowed");
|
||||
static_assert(!std::is_copy_constructible_v<entt::basic_snapshot_loader<entt::registry>>, "Copy constructible type not allowed");
|
||||
static_assert(!std::is_copy_assignable_v<entt::basic_snapshot_loader<entt::registry>>, "Copy assignable type not allowed");
|
||||
static_assert(std::is_move_constructible_v<entt::basic_snapshot_loader<entt::registry>>, "Move constructible type required");
|
||||
static_assert(std::is_move_assignable_v<entt::basic_snapshot_loader<entt::registry>>, "Move assignable type required");
|
||||
|
||||
entt::registry registry;
|
||||
|
||||
// helps stress the check in the constructor
|
||||
registry.emplace<int>(registry.create(), 0);
|
||||
registry.clear();
|
||||
|
||||
entt::basic_snapshot_loader loader{registry};
|
||||
entt::basic_snapshot_loader other{std::move(loader)};
|
||||
|
||||
ASSERT_NO_THROW(loader = std::move(other));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(BasicSnapshotLoaderDeathTest, Constructors) {
|
||||
entt::registry registry;
|
||||
registry.emplace<int>(registry.create());
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const entt::basic_snapshot_loader loader{registry}, "");
|
||||
}
|
||||
|
||||
TEST(BasicSnapshotLoader, GetEntityType) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_snapshot_loader loader{registry};
|
||||
const auto &storage = registry.storage<entt::entity>();
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data, pos = 0u](auto &elem) mutable { elem = entt::any_cast<std::remove_reference_t<decltype(elem)>>(data[pos++]); };
|
||||
const std::array entity{traits_type::construct(0u, 0u), traits_type::construct(2u, 0u), traits_type::construct(1u, 1u)};
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
ASSERT_FALSE(registry.valid(entity[2u]));
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(0u));
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(0u));
|
||||
|
||||
loader.get<entt::entity>(archive);
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
ASSERT_FALSE(registry.valid(entity[2u]));
|
||||
|
||||
ASSERT_EQ(storage.size(), 0u);
|
||||
ASSERT_EQ(storage.free_list(), 0u);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(3u));
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(entity[1u]);
|
||||
data.emplace_back(entity[2u]);
|
||||
|
||||
loader.get<entt::entity>(archive);
|
||||
|
||||
ASSERT_TRUE(registry.valid(entity[0u]));
|
||||
ASSERT_TRUE(registry.valid(entity[1u]));
|
||||
ASSERT_FALSE(registry.valid(entity[2u]));
|
||||
|
||||
ASSERT_EQ(storage.size(), 3u);
|
||||
ASSERT_EQ(storage.free_list(), 2u);
|
||||
|
||||
ASSERT_EQ(storage[0u], entity[0u]);
|
||||
ASSERT_EQ(storage[1u], entity[1u]);
|
||||
ASSERT_EQ(storage[2u], entity[2u]);
|
||||
|
||||
ASSERT_EQ(registry.create(), entity[2u]);
|
||||
}
|
||||
|
||||
TEST(BasicSnapshotLoader, GetType) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_snapshot_loader loader{registry};
|
||||
const auto &storage = registry.storage<int>();
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data, pos = 0u](auto &elem) mutable { elem = entt::any_cast<std::remove_reference_t<decltype(elem)>>(data[pos++]); };
|
||||
const std::array entity{traits_type::construct(0u, 0u), traits_type::construct(2u, 0u)};
|
||||
const std::array value{1, 3};
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(1u));
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(value[0u]);
|
||||
|
||||
loader.get<int>(archive, "other"_hs);
|
||||
|
||||
ASSERT_TRUE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
|
||||
ASSERT_EQ(storage.size(), 0u);
|
||||
ASSERT_EQ(registry.storage<int>("other"_hs).size(), 1u);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(value[0u]);
|
||||
|
||||
data.emplace_back(entity[1u]);
|
||||
data.emplace_back(value[1u]);
|
||||
|
||||
loader.get<int>(archive);
|
||||
|
||||
ASSERT_TRUE(registry.valid(entity[0u]));
|
||||
ASSERT_TRUE(registry.valid(entity[1u]));
|
||||
|
||||
ASSERT_EQ(storage.size(), 2u);
|
||||
ASSERT_TRUE(storage.contains(entity[0u]));
|
||||
ASSERT_TRUE(storage.contains(entity[1u]));
|
||||
ASSERT_EQ(storage.get(entity[0u]), value[0u]);
|
||||
ASSERT_EQ(storage.get(entity[1u]), value[1u]);
|
||||
}
|
||||
|
||||
TEST(BasicSnapshotLoader, GetEmptyType) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_snapshot_loader loader{registry};
|
||||
const auto &storage = registry.storage<test::empty>();
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data, pos = 0u](auto &elem) mutable { elem = entt::any_cast<std::remove_reference_t<decltype(elem)>>(data[pos++]); };
|
||||
const std::array entity{traits_type::construct(0u, 0u), traits_type::construct(2u, 0u)};
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(1u));
|
||||
data.emplace_back(entity[0u]);
|
||||
|
||||
loader.get<test::empty>(archive, "other"_hs);
|
||||
|
||||
ASSERT_TRUE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
|
||||
ASSERT_EQ(storage.size(), 0u);
|
||||
ASSERT_EQ(registry.storage<test::empty>("other"_hs).size(), 1u);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(entity[1u]);
|
||||
|
||||
loader.get<test::empty>(archive);
|
||||
|
||||
ASSERT_TRUE(registry.valid(entity[0u]));
|
||||
ASSERT_TRUE(registry.valid(entity[1u]));
|
||||
|
||||
ASSERT_EQ(storage.size(), 2u);
|
||||
ASSERT_TRUE(storage.contains(entity[0u]));
|
||||
ASSERT_TRUE(storage.contains(entity[1u]));
|
||||
}
|
||||
|
||||
TEST(BasicSnapshotLoader, GetTypeSparse) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_snapshot_loader loader{registry};
|
||||
const auto &storage = registry.storage<int>();
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data, pos = 0u](auto &elem) mutable { elem = entt::any_cast<std::remove_reference_t<decltype(elem)>>(data[pos++]); };
|
||||
const std::array entity{traits_type::construct(0u, 0u), traits_type::construct(2u, 0u)};
|
||||
const std::array value{1, 3};
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
data.emplace_back(static_cast<entt::entity>(entt::null));
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(value[0u]);
|
||||
|
||||
loader.get<int>(archive, "other"_hs);
|
||||
|
||||
ASSERT_TRUE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
|
||||
ASSERT_EQ(storage.size(), 0u);
|
||||
ASSERT_EQ(registry.storage<int>("other"_hs).size(), 1u);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(3u));
|
||||
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(value[0u]);
|
||||
|
||||
data.emplace_back(static_cast<entt::entity>(entt::null));
|
||||
|
||||
data.emplace_back(entity[1u]);
|
||||
data.emplace_back(value[1u]);
|
||||
|
||||
loader.get<int>(archive);
|
||||
|
||||
ASSERT_TRUE(registry.valid(entity[0u]));
|
||||
ASSERT_TRUE(registry.valid(entity[1u]));
|
||||
|
||||
ASSERT_EQ(storage.size(), 2u);
|
||||
ASSERT_TRUE(storage.contains(entity[0u]));
|
||||
ASSERT_TRUE(storage.contains(entity[1u]));
|
||||
ASSERT_EQ(storage.get(entity[0u]), value[0u]);
|
||||
ASSERT_EQ(storage.get(entity[1u]), value[1u]);
|
||||
}
|
||||
|
||||
TEST(BasicSnapshotLoader, GetTypeWithListener) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_snapshot_loader loader{registry};
|
||||
entt::entity check{entt::null};
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data, pos = 0u](auto &value) mutable { value = entt::any_cast<std::remove_reference_t<decltype(value)>>(data[pos++]); };
|
||||
const auto entity{traits_type::construct(1u, 1u)};
|
||||
const shadow value{entity};
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity));
|
||||
ASSERT_EQ(check, static_cast<entt::entity>(entt::null));
|
||||
|
||||
registry.on_construct<shadow>().connect<&shadow::listener>(check);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(1u));
|
||||
data.emplace_back(entity);
|
||||
data.emplace_back(value);
|
||||
|
||||
loader.get<shadow>(archive);
|
||||
|
||||
ASSERT_TRUE(registry.valid(entity));
|
||||
ASSERT_EQ(check, entity);
|
||||
}
|
||||
|
||||
TEST(BasicSnapshotLoader, Orphans) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_snapshot_loader loader{registry};
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data, pos = 0u](auto &elem) mutable { elem = entt::any_cast<std::remove_reference_t<decltype(elem)>>(data[pos++]); };
|
||||
const std::array entity{traits_type::construct(0u, 0u), traits_type::construct(2u, 0u)};
|
||||
const int value = 3;
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(entity[1u]);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(1u));
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(value);
|
||||
|
||||
loader.get<entt::entity>(archive);
|
||||
loader.get<int>(archive);
|
||||
|
||||
ASSERT_TRUE(registry.valid(entity[0u]));
|
||||
ASSERT_TRUE(registry.valid(entity[1u]));
|
||||
|
||||
loader.orphans();
|
||||
|
||||
ASSERT_TRUE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
}
|
||||
|
||||
TEST(BasicContinuousLoader, Constructors) {
|
||||
static_assert(!std::is_default_constructible_v<entt::basic_continuous_loader<entt::registry>>, "Default constructible type not allowed");
|
||||
static_assert(!std::is_copy_constructible_v<entt::basic_continuous_loader<entt::registry>>, "Copy constructible type not allowed");
|
||||
static_assert(!std::is_copy_assignable_v<entt::basic_continuous_loader<entt::registry>>, "Copy assignable type not allowed");
|
||||
static_assert(std::is_move_constructible_v<entt::basic_continuous_loader<entt::registry>>, "Move constructible type required");
|
||||
static_assert(std::is_move_assignable_v<entt::basic_continuous_loader<entt::registry>>, "Move assignable type required");
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_continuous_loader loader{registry};
|
||||
entt::basic_continuous_loader other{std::move(loader)};
|
||||
|
||||
ASSERT_NO_THROW(loader = std::move(other));
|
||||
}
|
||||
|
||||
TEST(BasicContinuousLoader, GetEntityType) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_continuous_loader loader{registry};
|
||||
const auto &storage = registry.storage<entt::entity>();
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data, pos = 0u](auto &elem) mutable { elem = entt::any_cast<std::remove_reference_t<decltype(elem)>>(data[pos++]); };
|
||||
const std::array entity{traits_type::construct(1u, 0u), traits_type::construct(0u, 0u), traits_type::construct(2u, 0u)};
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
ASSERT_FALSE(registry.valid(entity[2u]));
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(0u));
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(0u));
|
||||
|
||||
loader.get<entt::entity>(archive);
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
ASSERT_FALSE(registry.valid(entity[2u]));
|
||||
|
||||
ASSERT_FALSE(loader.contains(entity[0u]));
|
||||
ASSERT_FALSE(loader.contains(entity[1u]));
|
||||
ASSERT_FALSE(loader.contains(entity[2u]));
|
||||
|
||||
ASSERT_EQ(loader.map(entity[0u]), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_EQ(loader.map(entity[1u]), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_EQ(loader.map(entity[2u]), static_cast<entt::entity>(entt::null));
|
||||
|
||||
ASSERT_EQ(storage.size(), 0u);
|
||||
ASSERT_EQ(storage.free_list(), 0u);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(3u));
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(entity[1u]);
|
||||
data.emplace_back(entity[2u]);
|
||||
|
||||
loader.get<entt::entity>(archive);
|
||||
|
||||
ASSERT_TRUE(loader.contains(entity[0u]));
|
||||
ASSERT_TRUE(loader.contains(entity[1u]));
|
||||
ASSERT_FALSE(loader.contains(entity[2u]));
|
||||
|
||||
ASSERT_NE(loader.map(entity[0u]), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_NE(loader.map(entity[1u]), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_EQ(loader.map(entity[2u]), static_cast<entt::entity>(entt::null));
|
||||
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
ASSERT_EQ(storage.size(), 2u);
|
||||
ASSERT_EQ(storage.free_list(), 2u);
|
||||
|
||||
ASSERT_EQ(storage[0u], loader.map(entity[0u]));
|
||||
ASSERT_EQ(storage[1u], loader.map(entity[1u]));
|
||||
|
||||
ASSERT_EQ(registry.create(), entity[2u]);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(3u));
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(3u));
|
||||
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(entity[1u]);
|
||||
data.emplace_back(entity[2u]);
|
||||
|
||||
loader.get<entt::entity>(archive);
|
||||
|
||||
ASSERT_TRUE(loader.contains(entity[0u]));
|
||||
ASSERT_TRUE(loader.contains(entity[1u]));
|
||||
ASSERT_TRUE(loader.contains(entity[2u]));
|
||||
|
||||
ASSERT_NE(loader.map(entity[0u]), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_NE(loader.map(entity[1u]), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_NE(loader.map(entity[2u]), static_cast<entt::entity>(entt::null));
|
||||
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[1u])));
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[2u])));
|
||||
|
||||
ASSERT_EQ(storage.size(), 4u);
|
||||
ASSERT_EQ(storage.free_list(), 4u);
|
||||
|
||||
ASSERT_EQ(storage[0u], loader.map(entity[0u]));
|
||||
ASSERT_EQ(storage[1u], loader.map(entity[1u]));
|
||||
ASSERT_EQ(storage[3u], loader.map(entity[2u]));
|
||||
|
||||
registry.destroy(loader.map(entity[1u]));
|
||||
|
||||
ASSERT_TRUE(loader.contains(entity[1u]));
|
||||
ASSERT_NE(loader.map(entity[1u]), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(1u));
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(1u));
|
||||
|
||||
data.emplace_back(entity[1u]);
|
||||
|
||||
loader.get<entt::entity>(archive);
|
||||
|
||||
ASSERT_TRUE(loader.contains(entity[1u]));
|
||||
ASSERT_NE(loader.map(entity[1u]), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[1u])));
|
||||
ASSERT_EQ(storage[3u], loader.map(entity[1u]));
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(3u));
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(1u));
|
||||
|
||||
data.emplace_back(entity[1u]);
|
||||
data.emplace_back(entity[2u]);
|
||||
data.emplace_back(entity[0u]);
|
||||
|
||||
loader.get<entt::entity>(archive);
|
||||
|
||||
ASSERT_FALSE(loader.contains(entity[0u]));
|
||||
ASSERT_TRUE(loader.contains(entity[1u]));
|
||||
ASSERT_FALSE(loader.contains(entity[2u]));
|
||||
|
||||
ASSERT_EQ(loader.map(entity[0u]), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_NE(loader.map(entity[1u]), static_cast<entt::entity>(entt::null));
|
||||
ASSERT_EQ(loader.map(entity[2u]), static_cast<entt::entity>(entt::null));
|
||||
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
ASSERT_EQ(storage.size(), 4u);
|
||||
ASSERT_EQ(storage.free_list(), 2u);
|
||||
|
||||
ASSERT_EQ(storage[1u], loader.map(entity[1u]));
|
||||
}
|
||||
|
||||
TEST(BasicContinuousLoader, GetType) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_continuous_loader loader{registry};
|
||||
const auto &storage = registry.storage<int>();
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data, pos = 0u](auto &elem) mutable { elem = entt::any_cast<std::remove_reference_t<decltype(elem)>>(data[pos++]); };
|
||||
const std::array entity{traits_type::construct(0u, 0u), traits_type::construct(2u, 0u)};
|
||||
const std::array value{1, 3};
|
||||
|
||||
ASSERT_FALSE(loader.contains(entity[0u]));
|
||||
ASSERT_FALSE(loader.contains(entity[1u]));
|
||||
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(1u));
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(value[0u]);
|
||||
|
||||
loader.get<int>(archive, "other"_hs);
|
||||
|
||||
ASSERT_TRUE(loader.contains(entity[0u]));
|
||||
ASSERT_FALSE(loader.contains(entity[1u]));
|
||||
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
ASSERT_EQ(storage.size(), 0u);
|
||||
ASSERT_EQ(registry.storage<int>("other"_hs).size(), 1u);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(value[0u]);
|
||||
|
||||
data.emplace_back(entity[1u]);
|
||||
data.emplace_back(value[1u]);
|
||||
|
||||
loader.get<int>(archive);
|
||||
|
||||
ASSERT_TRUE(loader.contains(entity[0u]));
|
||||
ASSERT_TRUE(loader.contains(entity[1u]));
|
||||
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
ASSERT_EQ(storage.size(), 2u);
|
||||
ASSERT_TRUE(storage.contains(loader.map(entity[0u])));
|
||||
ASSERT_TRUE(storage.contains(loader.map(entity[1u])));
|
||||
ASSERT_EQ(storage.get(loader.map(entity[0u])), value[0u]);
|
||||
ASSERT_EQ(storage.get(loader.map(entity[1u])), value[1u]);
|
||||
}
|
||||
|
||||
TEST(BasicContinuousLoader, GetTypeExtended) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_continuous_loader loader{registry};
|
||||
const auto &storage = registry.storage<shadow>();
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
const std::array entity{traits_type::construct(0u, 1u), traits_type::construct(1u, 1u)};
|
||||
const shadow value{entity[0u]};
|
||||
|
||||
auto archive = [&loader, &data, pos = 0u](auto &elem) mutable {
|
||||
elem = entt::any_cast<std::remove_reference_t<decltype(elem)>>(data[pos++]);
|
||||
|
||||
if constexpr(std::is_same_v<std::remove_reference_t<decltype(elem)>, shadow>) {
|
||||
elem.target = loader.map(elem.target);
|
||||
}
|
||||
};
|
||||
|
||||
ASSERT_FALSE(loader.contains(entity[0u]));
|
||||
ASSERT_FALSE(loader.contains(entity[1u]));
|
||||
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(entity[1u]);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(1u));
|
||||
data.emplace_back(entity[1u]);
|
||||
data.emplace_back(value);
|
||||
|
||||
loader.get<entt::entity>(archive);
|
||||
loader.get<shadow>(archive);
|
||||
|
||||
ASSERT_TRUE(loader.contains(entity[0u]));
|
||||
ASSERT_TRUE(loader.contains(entity[1u]));
|
||||
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
|
||||
ASSERT_EQ(storage.size(), 1u);
|
||||
ASSERT_TRUE(storage.contains(loader.map(entity[1u])));
|
||||
ASSERT_EQ(storage.get(loader.map(entity[1u])).target, loader.map(entity[0u]));
|
||||
}
|
||||
|
||||
TEST(BasicContinuousLoader, GetEmptyType) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_continuous_loader loader{registry};
|
||||
const auto &storage = registry.storage<test::empty>();
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data, pos = 0u](auto &elem) mutable { elem = entt::any_cast<std::remove_reference_t<decltype(elem)>>(data[pos++]); };
|
||||
const std::array entity{traits_type::construct(0u, 0u), traits_type::construct(2u, 0u)};
|
||||
|
||||
ASSERT_FALSE(loader.contains(entity[0u]));
|
||||
ASSERT_FALSE(loader.contains(entity[1u]));
|
||||
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(1u));
|
||||
data.emplace_back(entity[0u]);
|
||||
|
||||
loader.get<test::empty>(archive, "other"_hs);
|
||||
|
||||
ASSERT_TRUE(loader.contains(entity[0u]));
|
||||
ASSERT_FALSE(loader.contains(entity[1u]));
|
||||
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
ASSERT_EQ(storage.size(), 0u);
|
||||
ASSERT_EQ(registry.storage<test::empty>("other"_hs).size(), 1u);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(entity[1u]);
|
||||
|
||||
loader.get<test::empty>(archive);
|
||||
|
||||
ASSERT_TRUE(loader.contains(entity[0u]));
|
||||
ASSERT_TRUE(loader.contains(entity[1u]));
|
||||
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
ASSERT_EQ(storage.size(), 2u);
|
||||
ASSERT_TRUE(storage.contains(loader.map(entity[0u])));
|
||||
ASSERT_TRUE(storage.contains(loader.map(entity[1u])));
|
||||
}
|
||||
|
||||
TEST(BasicContinuousLoader, GetTypeSparse) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_continuous_loader loader{registry};
|
||||
const auto &storage = registry.storage<int>();
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data, pos = 0u](auto &elem) mutable { elem = entt::any_cast<std::remove_reference_t<decltype(elem)>>(data[pos++]); };
|
||||
const std::array entity{traits_type::construct(0u, 0u), traits_type::construct(2u, 0u)};
|
||||
const std::array value{1, 3};
|
||||
|
||||
ASSERT_FALSE(loader.contains(entity[0u]));
|
||||
ASSERT_FALSE(loader.contains(entity[1u]));
|
||||
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
data.emplace_back(static_cast<entt::entity>(entt::null));
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(value[0u]);
|
||||
|
||||
loader.get<int>(archive, "other"_hs);
|
||||
|
||||
ASSERT_TRUE(loader.contains(entity[0u]));
|
||||
ASSERT_FALSE(loader.contains(entity[1u]));
|
||||
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
ASSERT_EQ(storage.size(), 0u);
|
||||
ASSERT_EQ(registry.storage<int>("other"_hs).size(), 1u);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(3u));
|
||||
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(value[0u]);
|
||||
|
||||
data.emplace_back(static_cast<entt::entity>(entt::null));
|
||||
|
||||
data.emplace_back(entity[1u]);
|
||||
data.emplace_back(value[1u]);
|
||||
|
||||
loader.get<int>(archive);
|
||||
|
||||
ASSERT_TRUE(loader.contains(entity[0u]));
|
||||
ASSERT_TRUE(loader.contains(entity[1u]));
|
||||
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
ASSERT_EQ(storage.size(), 2u);
|
||||
ASSERT_TRUE(storage.contains(loader.map(entity[0u])));
|
||||
ASSERT_TRUE(storage.contains(loader.map(entity[1u])));
|
||||
ASSERT_EQ(storage.get(loader.map(entity[0u])), value[0u]);
|
||||
ASSERT_EQ(storage.get(loader.map(entity[1u])), value[1u]);
|
||||
}
|
||||
|
||||
TEST(BasicContinuousLoader, GetTypeWithListener) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_continuous_loader loader{registry};
|
||||
entt::entity check{entt::null};
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data, pos = 0u](auto &value) mutable { value = entt::any_cast<std::remove_reference_t<decltype(value)>>(data[pos++]); };
|
||||
const auto entity{traits_type::construct(1u, 1u)};
|
||||
const shadow value{entity};
|
||||
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity)));
|
||||
ASSERT_EQ(check, static_cast<entt::entity>(entt::null));
|
||||
|
||||
registry.on_construct<shadow>().connect<&shadow::listener>(check);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(1u));
|
||||
data.emplace_back(entity);
|
||||
data.emplace_back(value);
|
||||
|
||||
loader.get<shadow>(archive);
|
||||
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity)));
|
||||
ASSERT_EQ(check, entity);
|
||||
}
|
||||
|
||||
TEST(BasicContinuousLoader, Orphans) {
|
||||
using namespace entt::literals;
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::registry registry;
|
||||
entt::basic_continuous_loader loader{registry};
|
||||
|
||||
std::vector<entt::any> data{};
|
||||
auto archive = [&data, pos = 0u](auto &elem) mutable { elem = entt::any_cast<std::remove_reference_t<decltype(elem)>>(data[pos++]); };
|
||||
const std::array entity{traits_type::construct(0u, 0u), traits_type::construct(2u, 0u)};
|
||||
const int value = 3;
|
||||
|
||||
ASSERT_FALSE(registry.valid(entity[0u]));
|
||||
ASSERT_FALSE(registry.valid(entity[1u]));
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(2u));
|
||||
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(entity[1u]);
|
||||
|
||||
data.emplace_back(static_cast<typename traits_type::entity_type>(1u));
|
||||
data.emplace_back(entity[0u]);
|
||||
data.emplace_back(value);
|
||||
|
||||
loader.get<entt::entity>(archive);
|
||||
loader.get<int>(archive);
|
||||
|
||||
ASSERT_TRUE(loader.contains(entity[0u]));
|
||||
ASSERT_TRUE(loader.contains(entity[1u]));
|
||||
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[1u])));
|
||||
|
||||
loader.orphans();
|
||||
|
||||
ASSERT_TRUE(loader.contains(entity[0u]));
|
||||
ASSERT_TRUE(loader.contains(entity[1u]));
|
||||
|
||||
ASSERT_TRUE(registry.valid(loader.map(entity[0u])));
|
||||
ASSERT_FALSE(registry.valid(loader.map(entity[1u])));
|
||||
}
|
||||
2241
lib/All/entt/test/entt/entity/sparse_set.cpp
Normal file
2241
lib/All/entt/test/entt/entity/sparse_set.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1926
lib/All/entt/test/entt/entity/storage.cpp
Normal file
1926
lib/All/entt/test/entt/entity/storage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
747
lib/All/entt/test/entt/entity/storage_entity.cpp
Normal file
747
lib/All/entt/test/entt/entity/storage_entity.cpp
Normal file
@@ -0,0 +1,747 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/iterator.hpp>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/storage.hpp>
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/linter.hpp"
|
||||
|
||||
TEST(StorageEntity, Constructors) {
|
||||
entt::storage<entt::entity> pool;
|
||||
|
||||
ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_only);
|
||||
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
|
||||
ASSERT_EQ(pool.type(), entt::type_id<void>());
|
||||
|
||||
pool = entt::storage<entt::entity>{std::allocator<entt::entity>{}};
|
||||
|
||||
ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_only);
|
||||
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
|
||||
ASSERT_EQ(pool.type(), entt::type_id<void>());
|
||||
}
|
||||
|
||||
TEST(StorageEntity, Move) {
|
||||
entt::storage<entt::entity> pool;
|
||||
const std::array entity{entt::entity{3}, entt::entity{2}};
|
||||
|
||||
pool.generate(entity[0u]);
|
||||
|
||||
static_assert(std::is_move_constructible_v<decltype(pool)>, "Move constructible type required");
|
||||
static_assert(std::is_move_assignable_v<decltype(pool)>, "Move assignable type required");
|
||||
|
||||
entt::storage<entt::entity> other{std::move(pool)};
|
||||
|
||||
test::is_initialized(pool);
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
|
||||
ASSERT_EQ(other.type(), entt::type_id<void>());
|
||||
ASSERT_EQ(other.index(entity[0u]), 0u);
|
||||
|
||||
entt::storage<entt::entity> extended{std::move(other), std::allocator<entt::entity>{}};
|
||||
|
||||
test::is_initialized(other);
|
||||
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_FALSE(extended.empty());
|
||||
|
||||
ASSERT_EQ(extended.type(), entt::type_id<void>());
|
||||
ASSERT_EQ(extended.index(entity[0u]), 0u);
|
||||
|
||||
pool = std::move(extended);
|
||||
test::is_initialized(extended);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_TRUE(extended.empty());
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<void>());
|
||||
ASSERT_EQ(pool.index(entity[0u]), 0u);
|
||||
|
||||
other = entt::storage<entt::entity>{};
|
||||
other.generate(entity[1u]);
|
||||
other = std::move(pool);
|
||||
test::is_initialized(pool);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
|
||||
ASSERT_EQ(other.type(), entt::type_id<void>());
|
||||
ASSERT_EQ(other.index(entity[0u]), 0u);
|
||||
}
|
||||
|
||||
TEST(StorageEntity, Swap) {
|
||||
entt::storage<entt::entity> pool;
|
||||
entt::storage<entt::entity> other;
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<void>());
|
||||
ASSERT_EQ(other.type(), entt::type_id<void>());
|
||||
|
||||
pool.generate(entt::entity{4});
|
||||
|
||||
other.generate(entt::entity{2});
|
||||
other.generate(entt::entity{1});
|
||||
other.erase(entt::entity{2});
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 2u);
|
||||
|
||||
pool.swap(other);
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<void>());
|
||||
ASSERT_EQ(other.type(), entt::type_id<void>());
|
||||
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
|
||||
ASSERT_EQ(pool.index(entt::entity{1}), 0u);
|
||||
ASSERT_EQ(other.index(entt::entity{4}), 0u);
|
||||
}
|
||||
|
||||
TEST(StorageEntity, Getters) {
|
||||
entt::storage<entt::entity> pool;
|
||||
const entt::entity entity{4};
|
||||
|
||||
pool.generate(entity);
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(pool.get({})), void>();
|
||||
testing::StaticAssertTypeEq<decltype(std::as_const(pool).get({})), void>();
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(pool.get_as_tuple({})), std::tuple<>>();
|
||||
testing::StaticAssertTypeEq<decltype(std::as_const(pool).get_as_tuple({})), std::tuple<>>();
|
||||
|
||||
ASSERT_NO_THROW(pool.get(entity));
|
||||
ASSERT_NO_THROW(std::as_const(pool).get(entity));
|
||||
|
||||
ASSERT_EQ(pool.get_as_tuple(entity), std::make_tuple());
|
||||
ASSERT_EQ(std::as_const(pool).get_as_tuple(entity), std::make_tuple());
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(StorageEntityDeathTest, Getters) {
|
||||
entt::storage<entt::entity> pool;
|
||||
const entt::entity entity{4};
|
||||
|
||||
ASSERT_DEATH(pool.get(entity), "");
|
||||
ASSERT_DEATH(std::as_const(pool).get(entity), "");
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const auto value = pool.get_as_tuple(entity), "");
|
||||
ASSERT_DEATH([[maybe_unused]] const auto value = std::as_const(pool).get_as_tuple(entity), "");
|
||||
}
|
||||
|
||||
TEST(StorageEntity, Generate) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::storage<entt::entity> pool;
|
||||
std::array<entt::entity, 2u> entity{};
|
||||
|
||||
ASSERT_EQ(pool.emplace(), entt::entity{0});
|
||||
ASSERT_EQ(pool.generate(entt::null), entt::entity{1});
|
||||
ASSERT_EQ(pool.generate(entt::tombstone), entt::entity{2});
|
||||
ASSERT_EQ(pool.emplace(entt::entity{0}), entt::entity{3});
|
||||
ASSERT_EQ(pool.generate(traits_type::construct(1, 1)), entt::entity{4});
|
||||
ASSERT_EQ(pool.generate(traits_type::construct(6, 3)), traits_type::construct(6, 3));
|
||||
|
||||
ASSERT_LT(pool.index(entt::entity{0}), pool.free_list());
|
||||
ASSERT_LT(pool.index(entt::entity{1}), pool.free_list());
|
||||
ASSERT_LT(pool.index(entt::entity{2}), pool.free_list());
|
||||
ASSERT_LT(pool.index(entt::entity{3}), pool.free_list());
|
||||
ASSERT_LT(pool.index(entt::entity{4}), pool.free_list());
|
||||
ASSERT_EQ(pool.current(entt::entity{5}), traits_type::to_version(entt::tombstone));
|
||||
ASSERT_LT(pool.index(traits_type::construct(6, 3)), pool.free_list());
|
||||
|
||||
ASSERT_EQ(pool.generate(traits_type::construct(5, 2)), traits_type::construct(5, 2));
|
||||
ASSERT_EQ(pool.generate(traits_type::construct(5, 3)), entt::entity{7});
|
||||
|
||||
pool.erase(entt::entity{2});
|
||||
|
||||
ASSERT_EQ(pool.generate(), traits_type::construct(2, 1));
|
||||
|
||||
pool.erase(traits_type::construct(2, 1));
|
||||
pool.generate(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_EQ(entity[0u], traits_type::construct(2, 2));
|
||||
ASSERT_EQ(entity[1u], entt::entity{8});
|
||||
}
|
||||
|
||||
TEST(StorageEntity, GenerateFrom) {
|
||||
entt::storage<entt::entity> pool;
|
||||
std::array entity{entt::entity{0}, entt::entity{1}, entt::entity{2}};
|
||||
|
||||
ASSERT_EQ(pool.generate(), entity[0u]);
|
||||
|
||||
pool.start_from(entity[2u]);
|
||||
|
||||
ASSERT_EQ(pool.generate(), entity[2u]);
|
||||
ASSERT_FALSE(pool.contains(entity[1u]));
|
||||
}
|
||||
|
||||
TEST(StorageEntity, GenerateInUse) {
|
||||
entt::storage<entt::entity> pool;
|
||||
std::array<entt::entity, 2u> entity{};
|
||||
const entt::entity other{1};
|
||||
|
||||
ASSERT_EQ(pool.generate(other), other);
|
||||
ASSERT_EQ(pool.generate(), entt::entity{0});
|
||||
ASSERT_EQ(pool.generate(), entt::entity{2});
|
||||
|
||||
pool.clear();
|
||||
|
||||
ASSERT_EQ(pool.generate(other), other);
|
||||
|
||||
pool.generate(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_EQ(entity[0u], entt::entity{0});
|
||||
ASSERT_EQ(entity[1u], entt::entity{2});
|
||||
}
|
||||
|
||||
TEST(StorageEntity, TryGenerate) {
|
||||
using traits_type = entt::entt_traits<entt::entity>;
|
||||
|
||||
entt::storage<entt::entity> pool;
|
||||
|
||||
ASSERT_EQ(*pool.push(entt::null), entt::entity{0});
|
||||
ASSERT_EQ(*pool.push(entt::tombstone), entt::entity{1});
|
||||
ASSERT_EQ(*pool.push(entt::entity{0}), entt::entity{2});
|
||||
ASSERT_EQ(*pool.push(traits_type::construct(1, 1)), entt::entity{3});
|
||||
ASSERT_EQ(*pool.push(traits_type::construct(5, 3)), traits_type::construct(5, 3));
|
||||
|
||||
ASSERT_LT(pool.index(entt::entity{0}), pool.free_list());
|
||||
ASSERT_LT(pool.index(entt::entity{1}), pool.free_list());
|
||||
ASSERT_LT(pool.index(entt::entity{2}), pool.free_list());
|
||||
ASSERT_LT(pool.index(entt::entity{3}), pool.free_list());
|
||||
ASSERT_EQ(pool.current(entt::entity{4}), traits_type::to_version(entt::tombstone));
|
||||
ASSERT_LT(pool.index(traits_type::construct(5, 3)), pool.free_list());
|
||||
|
||||
ASSERT_EQ(*pool.push(traits_type::construct(4, 2)), traits_type::construct(4, 2));
|
||||
ASSERT_EQ(*pool.push(traits_type::construct(4, 3)), entt::entity{6});
|
||||
|
||||
const std::array entity{entt::entity{1}, traits_type::construct(5, 3)};
|
||||
|
||||
pool.erase(entity.begin(), entity.end());
|
||||
pool.erase(entt::entity{2});
|
||||
|
||||
ASSERT_EQ(pool.current(entity[0u]), 1);
|
||||
ASSERT_EQ(pool.current(entity[1u]), 4);
|
||||
ASSERT_EQ(pool.current(entt::entity{2}), 1);
|
||||
|
||||
ASSERT_LT(pool.index(entt::entity{0}), pool.free_list());
|
||||
ASSERT_GE(pool.index(traits_type::construct(1, 1)), pool.free_list());
|
||||
ASSERT_GE(pool.index(traits_type::construct(2, 1)), pool.free_list());
|
||||
ASSERT_LT(pool.index(entt::entity{3}), pool.free_list());
|
||||
ASSERT_LT(pool.index(traits_type::construct(4, 2)), pool.free_list());
|
||||
ASSERT_GE(pool.index(traits_type::construct(5, 4)), pool.free_list());
|
||||
|
||||
ASSERT_EQ(*pool.push(entt::null), traits_type::construct(2, 1));
|
||||
ASSERT_EQ(*pool.push(traits_type::construct(1, 3)), traits_type::construct(1, 3));
|
||||
ASSERT_EQ(*pool.push(entt::null), traits_type::construct(5, 4));
|
||||
ASSERT_EQ(*pool.push(entt::null), entt::entity{7});
|
||||
}
|
||||
|
||||
TEST(StorageEntity, TryGenerateInUse) {
|
||||
entt::storage<entt::entity> pool;
|
||||
std::array<entt::entity, 2u> entity{entt::entity{0}, entt::entity{0}};
|
||||
const entt::entity other{1};
|
||||
|
||||
ASSERT_EQ(*pool.push(other), other);
|
||||
ASSERT_EQ(*pool.push(other), entt::entity{0});
|
||||
ASSERT_EQ(*pool.push(other), entt::entity{2});
|
||||
|
||||
pool.clear();
|
||||
|
||||
ASSERT_EQ(*pool.push(other), other);
|
||||
|
||||
auto it = pool.push(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_EQ(*it, entt::entity{2});
|
||||
ASSERT_EQ(*(++it), entt::entity{0});
|
||||
}
|
||||
|
||||
TEST(StorageEntity, Patch) {
|
||||
entt::storage<entt::entity> pool;
|
||||
const auto entity = pool.generate();
|
||||
|
||||
int counter = 0;
|
||||
auto callback = [&counter]() { ++counter; };
|
||||
|
||||
ASSERT_EQ(counter, 0);
|
||||
|
||||
pool.patch(entity);
|
||||
pool.patch(entity, callback);
|
||||
pool.patch(entity, callback, callback);
|
||||
|
||||
ASSERT_EQ(counter, 3);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(StorageEntityDeathTest, Patch) {
|
||||
entt::storage<entt::entity> pool;
|
||||
|
||||
ASSERT_DEATH(pool.patch(entt::null), "");
|
||||
}
|
||||
|
||||
TEST(StorageEntity, Insert) {
|
||||
entt::storage<entt::entity> pool;
|
||||
std::array<entt::entity, 2u> entity{};
|
||||
|
||||
pool.insert(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity[0u]));
|
||||
ASSERT_TRUE(pool.contains(entity[1u]));
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_EQ(pool.free_list(), 2u);
|
||||
|
||||
pool.erase(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_EQ(pool.free_list(), 0u);
|
||||
|
||||
pool.generate(entity.begin(), entity.begin() + 1u);
|
||||
|
||||
ASSERT_TRUE(pool.contains(entity[0u]));
|
||||
ASSERT_FALSE(pool.contains(entity[1u]));
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_EQ(pool.free_list(), 1u);
|
||||
}
|
||||
|
||||
TEST(StorageEntity, Pack) {
|
||||
entt::storage<entt::entity> pool;
|
||||
std::array entity{entt::entity{1}, entt::entity{3}, entt::entity{4}, entt::entity{2}};
|
||||
|
||||
pool.push(entity.begin(), entity.end());
|
||||
pool.erase(entity[3u]);
|
||||
|
||||
std::swap(entity[0u], entity[1u]);
|
||||
|
||||
const auto to = pool.sort_as(entity.begin() + 1u, entity.end());
|
||||
auto from = pool.each().cbegin().base();
|
||||
|
||||
ASSERT_NE(from, pool.cbegin());
|
||||
ASSERT_NE(from, pool.cend());
|
||||
|
||||
ASSERT_NE(to, pool.cend());
|
||||
ASSERT_EQ(to + 1u, pool.cend());
|
||||
|
||||
ASSERT_EQ(*from++, entity[1u]);
|
||||
ASSERT_EQ(*from++, entity[2u]);
|
||||
|
||||
ASSERT_NE(from, pool.cend());
|
||||
ASSERT_EQ(*from++, entity[0u]);
|
||||
ASSERT_EQ(from, pool.cend());
|
||||
}
|
||||
|
||||
TEST(StorageEntity, FreeList) {
|
||||
entt::storage<entt::entity> pool;
|
||||
|
||||
pool.generate(entt::entity{0});
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(pool.free_list(), 1u);
|
||||
|
||||
pool.free_list(0u);
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(pool.free_list(), 0u);
|
||||
|
||||
pool.free_list(1u);
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(pool.free_list(), 1u);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(StorageEntityDeathTest, FreeList) {
|
||||
entt::storage<entt::entity> pool;
|
||||
|
||||
pool.generate(entt::entity{0});
|
||||
|
||||
ASSERT_DEATH(pool.free_list(2u), "");
|
||||
}
|
||||
|
||||
TEST(StorageEntity, Iterable) {
|
||||
using iterator = typename entt::storage<entt::entity>::iterable::iterator;
|
||||
|
||||
testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<entt::entity>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity>>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::reference, typename iterator::value_type>();
|
||||
|
||||
entt::storage<entt::entity> pool;
|
||||
|
||||
pool.generate(entt::entity{1});
|
||||
pool.generate(entt::entity{3});
|
||||
pool.generate(entt::entity{4});
|
||||
|
||||
pool.erase(entt::entity{3});
|
||||
|
||||
auto iterable = pool.each();
|
||||
|
||||
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_NE(begin.base(), pool.begin());
|
||||
ASSERT_EQ(begin.base(), pool.end() - static_cast<typename iterator::difference_type>(pool.free_list()));
|
||||
ASSERT_EQ(end.base(), pool.end());
|
||||
|
||||
ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{4});
|
||||
ASSERT_EQ(std::get<0>(*begin), entt::entity{4});
|
||||
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(begin.base(), pool.end() - 1);
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
ASSERT_EQ(begin.base(), pool.end());
|
||||
|
||||
for(auto [entity]: iterable) {
|
||||
testing::StaticAssertTypeEq<decltype(entity), entt::entity>();
|
||||
ASSERT_TRUE(entity != entt::entity{3});
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StorageEntity, ConstIterable) {
|
||||
using iterator = typename entt::storage<entt::entity>::const_iterable::iterator;
|
||||
|
||||
testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<entt::entity>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity>>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::reference, typename iterator::value_type>();
|
||||
|
||||
entt::storage<entt::entity> pool;
|
||||
|
||||
pool.generate(entt::entity{1});
|
||||
pool.generate(entt::entity{3});
|
||||
pool.generate(entt::entity{4});
|
||||
|
||||
pool.erase(entt::entity{3});
|
||||
|
||||
auto iterable = std::as_const(pool).each();
|
||||
|
||||
iterator end{iterable.cbegin()};
|
||||
iterator begin{};
|
||||
begin = iterable.cend();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, iterable.cbegin());
|
||||
ASSERT_EQ(end, iterable.cend());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_NE(begin.base(), pool.begin());
|
||||
ASSERT_EQ(begin.base(), pool.end() - static_cast<typename iterator::difference_type>(pool.free_list()));
|
||||
ASSERT_EQ(end.base(), pool.end());
|
||||
|
||||
ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{4});
|
||||
ASSERT_EQ(std::get<0>(*begin), entt::entity{4});
|
||||
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(begin.base(), pool.end() - 1);
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
ASSERT_EQ(begin.base(), pool.end());
|
||||
|
||||
for(auto [entity]: iterable) {
|
||||
testing::StaticAssertTypeEq<decltype(entity), entt::entity>();
|
||||
ASSERT_TRUE(entity != entt::entity{3});
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StorageEntity, IterableIteratorConversion) {
|
||||
entt::storage<entt::entity> pool;
|
||||
pool.generate(entt::entity{3});
|
||||
|
||||
const typename entt::storage<entt::entity>::iterable::iterator it = pool.each().begin();
|
||||
typename entt::storage<entt::entity>::const_iterable::iterator cit = it;
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(*it), std::tuple<entt::entity>>();
|
||||
testing::StaticAssertTypeEq<decltype(*cit), std::tuple<entt::entity>>();
|
||||
|
||||
ASSERT_EQ(it, cit);
|
||||
ASSERT_NE(++cit, it);
|
||||
}
|
||||
|
||||
TEST(StorageEntity, IterableAlgorithmCompatibility) {
|
||||
entt::storage<entt::entity> pool;
|
||||
pool.generate(entt::entity{3});
|
||||
|
||||
const auto iterable = pool.each();
|
||||
const auto it = std::find_if(iterable.begin(), iterable.end(), [](auto args) { return std::get<0>(args) == entt::entity{3}; });
|
||||
|
||||
ASSERT_EQ(std::get<0>(*it), entt::entity{3});
|
||||
}
|
||||
|
||||
TEST(StorageEntity, ReverseIterable) {
|
||||
using iterator = typename entt::storage<entt::entity>::reverse_iterable::iterator;
|
||||
|
||||
testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<entt::entity>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity>>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::reference, typename iterator::value_type>();
|
||||
|
||||
entt::storage<entt::entity> pool;
|
||||
|
||||
pool.generate(entt::entity{1});
|
||||
pool.generate(entt::entity{3});
|
||||
pool.generate(entt::entity{4});
|
||||
|
||||
pool.erase(entt::entity{3});
|
||||
|
||||
auto iterable = pool.reach();
|
||||
|
||||
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.base(), pool.rbegin());
|
||||
ASSERT_EQ(end.base(), pool.rbegin() + static_cast<typename iterator::difference_type>(pool.free_list()));
|
||||
ASSERT_NE(end.base(), pool.rend());
|
||||
|
||||
ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{1});
|
||||
ASSERT_EQ(std::get<0>(*begin), entt::entity{1});
|
||||
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(begin.base(), pool.rbegin() + 1);
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
ASSERT_EQ(begin.base(), pool.rbegin() + 2);
|
||||
|
||||
for(auto [entity]: iterable) {
|
||||
testing::StaticAssertTypeEq<decltype(entity), entt::entity>();
|
||||
ASSERT_TRUE(entity != entt::entity{3});
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StorageEntity, ReverseConstIterable) {
|
||||
using iterator = typename entt::storage<entt::entity>::const_reverse_iterable::iterator;
|
||||
|
||||
testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<entt::entity>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity>>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::reference, typename iterator::value_type>();
|
||||
|
||||
entt::storage<entt::entity> pool;
|
||||
|
||||
pool.generate(entt::entity{1});
|
||||
pool.generate(entt::entity{3});
|
||||
pool.generate(entt::entity{4});
|
||||
|
||||
pool.erase(entt::entity{3});
|
||||
|
||||
auto iterable = std::as_const(pool).reach();
|
||||
|
||||
iterator end{iterable.cbegin()};
|
||||
iterator begin{};
|
||||
begin = iterable.cend();
|
||||
std::swap(begin, end);
|
||||
|
||||
ASSERT_EQ(begin, iterable.cbegin());
|
||||
ASSERT_EQ(end, iterable.cend());
|
||||
ASSERT_NE(begin, end);
|
||||
|
||||
ASSERT_EQ(begin.base(), pool.rbegin());
|
||||
ASSERT_EQ(end.base(), pool.rbegin() + static_cast<typename iterator::difference_type>(pool.free_list()));
|
||||
ASSERT_NE(end.base(), pool.rend());
|
||||
|
||||
ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{1});
|
||||
ASSERT_EQ(std::get<0>(*begin), entt::entity{1});
|
||||
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(begin.base(), pool.rbegin() + 1);
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
ASSERT_EQ(begin.base(), pool.rbegin() + 2);
|
||||
|
||||
for(auto [entity]: iterable) {
|
||||
testing::StaticAssertTypeEq<decltype(entity), entt::entity>();
|
||||
ASSERT_TRUE(entity != entt::entity{3});
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StorageEntity, ReverseIterableIteratorConversion) {
|
||||
entt::storage<entt::entity> pool;
|
||||
pool.generate(entt::entity{3});
|
||||
|
||||
const typename entt::storage<entt::entity>::reverse_iterable::iterator it = pool.reach().begin();
|
||||
typename entt::storage<entt::entity>::const_reverse_iterable::iterator cit = it;
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(*it), std::tuple<entt::entity>>();
|
||||
testing::StaticAssertTypeEq<decltype(*cit), std::tuple<entt::entity>>();
|
||||
|
||||
ASSERT_EQ(it, cit);
|
||||
ASSERT_NE(++cit, it);
|
||||
}
|
||||
|
||||
TEST(StorageEntity, ReverseIterableAlgorithmCompatibility) {
|
||||
entt::storage<entt::entity> pool;
|
||||
pool.generate(entt::entity{3});
|
||||
|
||||
const auto iterable = pool.reach();
|
||||
const auto it = std::find_if(iterable.begin(), iterable.end(), [](auto args) { return std::get<0>(args) == entt::entity{3}; });
|
||||
|
||||
ASSERT_EQ(std::get<0>(*it), entt::entity{3});
|
||||
}
|
||||
|
||||
TEST(StorageEntity, SortOrdered) {
|
||||
entt::storage<entt::entity> pool;
|
||||
const std::array entity{entt::entity{16}, entt::entity{8}, entt::entity{4}, entt::entity{2}, entt::entity{1}};
|
||||
|
||||
pool.push(entity.begin(), entity.end());
|
||||
pool.sort(std::less{});
|
||||
|
||||
ASSERT_TRUE(std::equal(entity.rbegin(), entity.rend(), pool.begin(), pool.end()));
|
||||
}
|
||||
|
||||
TEST(StorageEntity, SortReverse) {
|
||||
entt::storage<entt::entity> pool;
|
||||
const std::array entity{entt::entity{1}, entt::entity{2}, entt::entity{4}, entt::entity{8}, entt::entity{16}};
|
||||
|
||||
pool.push(entity.begin(), entity.end());
|
||||
pool.sort(std::less{});
|
||||
|
||||
ASSERT_TRUE(std::equal(entity.begin(), entity.end(), pool.begin(), pool.end()));
|
||||
}
|
||||
|
||||
TEST(StorageEntity, SortUnordered) {
|
||||
entt::storage<entt::entity> pool;
|
||||
const std::array entity{entt::entity{4}, entt::entity{2}, entt::entity{1}, entt::entity{8}, entt::entity{16}};
|
||||
|
||||
pool.push(entity.begin(), entity.end());
|
||||
pool.sort(std::less{});
|
||||
|
||||
ASSERT_EQ(pool.data()[0u], entity[4u]);
|
||||
ASSERT_EQ(pool.data()[1u], entity[3u]);
|
||||
ASSERT_EQ(pool.data()[2u], entity[0u]);
|
||||
ASSERT_EQ(pool.data()[3u], entity[1u]);
|
||||
ASSERT_EQ(pool.data()[4u], entity[2u]);
|
||||
}
|
||||
|
||||
TEST(StorageEntity, SortN) {
|
||||
entt::storage<entt::entity> pool;
|
||||
const std::array entity{entt::entity{2}, entt::entity{4}, entt::entity{1}, entt::entity{8}, entt::entity{16}};
|
||||
|
||||
pool.push(entity.begin(), entity.end());
|
||||
pool.sort_n(0u, std::less{});
|
||||
|
||||
ASSERT_TRUE(std::equal(entity.rbegin(), entity.rend(), pool.begin(), pool.end()));
|
||||
|
||||
pool.sort_n(2u, std::less{});
|
||||
|
||||
ASSERT_EQ(pool.data()[0u], entity[1u]);
|
||||
ASSERT_EQ(pool.data()[1u], entity[0u]);
|
||||
ASSERT_EQ(pool.data()[2u], entity[2u]);
|
||||
|
||||
const auto length = 5u;
|
||||
pool.sort_n(length, std::less{});
|
||||
|
||||
ASSERT_EQ(pool.data()[0u], entity[4u]);
|
||||
ASSERT_EQ(pool.data()[1u], entity[3u]);
|
||||
ASSERT_EQ(pool.data()[2u], entity[1u]);
|
||||
ASSERT_EQ(pool.data()[3u], entity[0u]);
|
||||
ASSERT_EQ(pool.data()[4u], entity[2u]);
|
||||
}
|
||||
|
||||
TEST(StorageEntity, SortAsDisjoint) {
|
||||
entt::storage<entt::entity> lhs;
|
||||
const entt::storage<entt::entity> rhs;
|
||||
const std::array entity{entt::entity{1}, entt::entity{2}, entt::entity{4}};
|
||||
|
||||
lhs.push(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(entity.rbegin(), entity.rend(), lhs.begin(), lhs.end()));
|
||||
|
||||
lhs.sort_as(rhs.begin(), rhs.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(entity.rbegin(), entity.rend(), lhs.begin(), lhs.end()));
|
||||
}
|
||||
|
||||
TEST(StorageEntity, SortAsOverlap) {
|
||||
entt::storage<entt::entity> lhs;
|
||||
entt::storage<entt::entity> rhs;
|
||||
const std::array lhs_entity{entt::entity{1}, entt::entity{2}, entt::entity{4}};
|
||||
const std::array rhs_entity{entt::entity{2}};
|
||||
|
||||
lhs.push(lhs_entity.begin(), lhs_entity.end());
|
||||
rhs.push(rhs_entity.begin(), rhs_entity.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(lhs_entity.rbegin(), lhs_entity.rend(), lhs.begin(), lhs.end()));
|
||||
ASSERT_TRUE(std::equal(rhs_entity.rbegin(), rhs_entity.rend(), rhs.begin(), rhs.end()));
|
||||
|
||||
lhs.sort_as(rhs.begin(), rhs.end());
|
||||
|
||||
ASSERT_EQ(lhs.data()[0u], lhs_entity[0u]);
|
||||
ASSERT_EQ(lhs.data()[1u], lhs_entity[2u]);
|
||||
ASSERT_EQ(lhs.data()[2u], lhs_entity[1u]);
|
||||
}
|
||||
|
||||
TEST(StorageEntity, SortAsOrdered) {
|
||||
entt::storage<entt::entity> lhs;
|
||||
entt::storage<entt::entity> rhs;
|
||||
const std::array lhs_entity{entt::entity{1}, entt::entity{2}, entt::entity{4}, entt::entity{8}, entt::entity{16}};
|
||||
const std::array rhs_entity{entt::entity{32}, entt::entity{1}, entt::entity{2}, entt::entity{4}, entt::entity{8}, entt::entity{16}};
|
||||
|
||||
lhs.push(lhs_entity.begin(), lhs_entity.end());
|
||||
rhs.push(rhs_entity.begin(), rhs_entity.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(lhs_entity.rbegin(), lhs_entity.rend(), lhs.begin(), lhs.end()));
|
||||
ASSERT_TRUE(std::equal(rhs_entity.rbegin(), rhs_entity.rend(), rhs.begin(), rhs.end()));
|
||||
|
||||
rhs.sort_as(lhs.begin(), lhs.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(rhs_entity.rbegin(), rhs_entity.rend(), rhs.begin(), rhs.end()));
|
||||
}
|
||||
|
||||
TEST(StorageEntity, SortAsReverse) {
|
||||
entt::storage<entt::entity> lhs;
|
||||
entt::storage<entt::entity> rhs;
|
||||
const std::array lhs_entity{entt::entity{1}, entt::entity{2}, entt::entity{4}, entt::entity{8}, entt::entity{16}};
|
||||
const std::array rhs_entity{entt::entity{16}, entt::entity{8}, entt::entity{4}, entt::entity{2}, entt::entity{1}, entt::entity{32}};
|
||||
|
||||
lhs.push(lhs_entity.begin(), lhs_entity.end());
|
||||
rhs.push(rhs_entity.begin(), rhs_entity.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(lhs_entity.rbegin(), lhs_entity.rend(), lhs.begin(), lhs.end()));
|
||||
ASSERT_TRUE(std::equal(rhs_entity.rbegin(), rhs_entity.rend(), rhs.begin(), rhs.end()));
|
||||
|
||||
rhs.sort_as(lhs.begin(), lhs.end());
|
||||
|
||||
ASSERT_EQ(rhs.data()[0u], rhs_entity[5u]);
|
||||
ASSERT_EQ(rhs.data()[1u], rhs_entity[4u]);
|
||||
ASSERT_EQ(rhs.data()[2u], rhs_entity[3u]);
|
||||
ASSERT_EQ(rhs.data()[3u], rhs_entity[2u]);
|
||||
ASSERT_EQ(rhs.data()[4u], rhs_entity[1u]);
|
||||
ASSERT_EQ(rhs.data()[5u], rhs_entity[0u]);
|
||||
}
|
||||
|
||||
TEST(StorageEntity, SortAsUnordered) {
|
||||
entt::storage<entt::entity> lhs;
|
||||
entt::storage<entt::entity> rhs;
|
||||
const std::array lhs_entity{entt::entity{1}, entt::entity{2}, entt::entity{4}, entt::entity{8}, entt::entity{16}};
|
||||
const std::array rhs_entity{entt::entity{4}, entt::entity{2}, entt::entity{32}, entt::entity{1}, entt::entity{8}, entt::entity{16}};
|
||||
|
||||
lhs.push(lhs_entity.begin(), lhs_entity.end());
|
||||
rhs.push(rhs_entity.begin(), rhs_entity.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(lhs_entity.rbegin(), lhs_entity.rend(), lhs.begin(), lhs.end()));
|
||||
ASSERT_TRUE(std::equal(rhs_entity.rbegin(), rhs_entity.rend(), rhs.begin(), rhs.end()));
|
||||
|
||||
rhs.sort_as(lhs.begin(), lhs.end());
|
||||
|
||||
ASSERT_EQ(rhs.data()[0u], rhs_entity[2u]);
|
||||
ASSERT_EQ(rhs.data()[1u], rhs_entity[3u]);
|
||||
ASSERT_EQ(rhs.data()[2u], rhs_entity[1u]);
|
||||
ASSERT_EQ(rhs.data()[3u], rhs_entity[0u]);
|
||||
ASSERT_EQ(rhs.data()[4u], rhs_entity[4u]);
|
||||
ASSERT_EQ(rhs.data()[5u], rhs_entity[5u]);
|
||||
}
|
||||
730
lib/All/entt/test/entt/entity/storage_no_instance.cpp
Normal file
730
lib/All/entt/test/entt/entity/storage_no_instance.cpp
Normal file
@@ -0,0 +1,730 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/iterator.hpp>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/entity/component.hpp>
|
||||
#include <entt/entity/entity.hpp>
|
||||
#include <entt/entity/storage.hpp>
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/empty.h"
|
||||
#include "../../common/linter.hpp"
|
||||
|
||||
template<typename Type>
|
||||
struct StorageNoInstance: testing::Test {
|
||||
static_assert(entt::component_traits<Type>::page_size == 0u, "Non-empty type not allowed");
|
||||
|
||||
using type = Type;
|
||||
|
||||
static auto emplace_instance(entt::storage<type> &pool, const entt::entity entt) {
|
||||
if constexpr(std::is_void_v<type>) {
|
||||
return pool.emplace(entt);
|
||||
} else {
|
||||
return pool.emplace(entt, type{});
|
||||
}
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
static auto insert_instance(entt::storage<type> &pool, const It from, const It to) {
|
||||
if constexpr(std::is_void_v<type>) {
|
||||
return pool.insert(from, to);
|
||||
} else {
|
||||
const std::array<type, 2u> value{};
|
||||
return pool.insert(from, to, value.begin());
|
||||
}
|
||||
}
|
||||
|
||||
static auto push_instance(entt::storage<type> &pool, const entt::entity entt) {
|
||||
if constexpr(std::is_void_v<type>) {
|
||||
return pool.push(entt, nullptr);
|
||||
} else {
|
||||
type instance{};
|
||||
return pool.push(entt, &instance);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using StorageNoInstanceDeathTest = StorageNoInstance<Type>;
|
||||
|
||||
using StorageNoInstanceTypes = ::testing::Types<test::empty, void>;
|
||||
|
||||
TYPED_TEST_SUITE(StorageNoInstance, StorageNoInstanceTypes, );
|
||||
TYPED_TEST_SUITE(StorageNoInstanceDeathTest, StorageNoInstanceTypes, );
|
||||
|
||||
TYPED_TEST(StorageNoInstance, Constructors) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
|
||||
ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_and_pop);
|
||||
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
|
||||
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
|
||||
|
||||
pool = entt::storage<value_type>{std::allocator<value_type>{}};
|
||||
|
||||
ASSERT_EQ(pool.policy(), entt::deletion_policy::swap_and_pop);
|
||||
ASSERT_NO_THROW([[maybe_unused]] auto alloc = pool.get_allocator());
|
||||
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, Move) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const std::array entity{entt::entity{3}, entt::entity{2}};
|
||||
|
||||
pool.emplace(entity[0u]);
|
||||
|
||||
static_assert(std::is_move_constructible_v<decltype(pool)>, "Move constructible type required");
|
||||
static_assert(std::is_move_assignable_v<decltype(pool)>, "Move assignable type required");
|
||||
|
||||
entt::storage<value_type> other{std::move(pool)};
|
||||
|
||||
test::is_initialized(pool);
|
||||
|
||||
ASSERT_TRUE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
|
||||
ASSERT_EQ(other.type(), entt::type_id<value_type>());
|
||||
ASSERT_EQ(other.index(entity[0u]), 0u);
|
||||
|
||||
entt::storage<value_type> extended{std::move(other), std::allocator<value_type>{}};
|
||||
|
||||
test::is_initialized(other);
|
||||
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_FALSE(extended.empty());
|
||||
|
||||
ASSERT_EQ(extended.type(), entt::type_id<value_type>());
|
||||
ASSERT_EQ(extended.index(entity[0u]), 0u);
|
||||
|
||||
pool = std::move(extended);
|
||||
test::is_initialized(extended);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
ASSERT_TRUE(extended.empty());
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
|
||||
ASSERT_EQ(pool.index(entity[0u]), 0u);
|
||||
|
||||
other = entt::storage<value_type>{};
|
||||
other.emplace(entity[1u], 2);
|
||||
other = std::move(pool);
|
||||
test::is_initialized(pool);
|
||||
|
||||
ASSERT_FALSE(pool.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
|
||||
ASSERT_EQ(other.type(), entt::type_id<value_type>());
|
||||
ASSERT_EQ(other.index(entity[0u]), 0u);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, Swap) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
entt::storage<value_type> other;
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
|
||||
ASSERT_EQ(other.type(), entt::type_id<value_type>());
|
||||
|
||||
pool.emplace(entt::entity{4});
|
||||
|
||||
other.emplace(entt::entity{2});
|
||||
other.emplace(entt::entity{1});
|
||||
other.erase(entt::entity{2});
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
|
||||
pool.swap(other);
|
||||
|
||||
ASSERT_EQ(pool.type(), entt::type_id<value_type>());
|
||||
ASSERT_EQ(other.type(), entt::type_id<value_type>());
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
|
||||
ASSERT_EQ(pool.index(entt::entity{1}), 0u);
|
||||
ASSERT_EQ(other.index(entt::entity{4}), 0u);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, Getters) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const entt::entity entity{4};
|
||||
|
||||
pool.emplace(entity, 3);
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(pool.get({})), void>();
|
||||
testing::StaticAssertTypeEq<decltype(std::as_const(pool).get({})), void>();
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(pool.get_as_tuple({})), std::tuple<>>();
|
||||
testing::StaticAssertTypeEq<decltype(std::as_const(pool).get_as_tuple({})), std::tuple<>>();
|
||||
|
||||
ASSERT_NO_THROW(pool.get(entity));
|
||||
ASSERT_NO_THROW(std::as_const(pool).get(entity));
|
||||
|
||||
ASSERT_EQ(pool.get_as_tuple(entity), std::make_tuple());
|
||||
ASSERT_EQ(std::as_const(pool).get_as_tuple(entity), std::make_tuple());
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(StorageNoInstanceDeathTest, Getters) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const entt::entity entity{4};
|
||||
|
||||
ASSERT_DEATH(pool.get(entity), "");
|
||||
ASSERT_DEATH(std::as_const(pool).get(entity), "");
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const auto value = pool.get_as_tuple(entity), "");
|
||||
ASSERT_DEATH([[maybe_unused]] const auto value = std::as_const(pool).get_as_tuple(entity), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, Value) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const entt::entity entity{4};
|
||||
|
||||
pool.emplace(entity);
|
||||
|
||||
ASSERT_EQ(pool.value(entt::entity{4}), nullptr);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(StorageNoInstanceDeathTest, Value) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const void *value = pool.value(entt::entity{4}), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, Emplace) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const std::array entity{entt::entity{1}, entt::entity{3}};
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(pool.emplace({})), void>();
|
||||
|
||||
ASSERT_NO_THROW(pool.emplace(entity[0u]));
|
||||
ASSERT_NO_THROW(this->emplace_instance(pool, entity[1u]));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(StorageNoInstanceDeathTest, Emplace) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const entt::entity entity{4};
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(pool.emplace({})), void>();
|
||||
|
||||
pool.emplace(entity);
|
||||
|
||||
ASSERT_DEATH(pool.emplace(entity), "");
|
||||
ASSERT_DEATH(this->emplace_instance(pool, entity), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, TryEmplace) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
entt::sparse_set &base = pool;
|
||||
const std::array entity{entt::entity{1}, entt::entity{3}};
|
||||
|
||||
ASSERT_NE(this->push_instance(pool, entity[0u]), base.end());
|
||||
|
||||
ASSERT_EQ(pool.size(), 1u);
|
||||
ASSERT_EQ(base.index(entity[0u]), 0u);
|
||||
|
||||
base.erase(entity[0u]);
|
||||
|
||||
ASSERT_NE(base.push(entity.begin(), entity.end()), base.end());
|
||||
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_EQ(base.index(entity[0u]), 0u);
|
||||
ASSERT_EQ(base.index(entity[1u]), 1u);
|
||||
|
||||
base.erase(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_NE(base.push(entity.rbegin(), entity.rend()), base.end());
|
||||
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_EQ(base.index(entity[0u]), 1u);
|
||||
ASSERT_EQ(base.index(entity[1u]), 0u);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, Patch) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const entt::entity entity{4};
|
||||
|
||||
int counter = 0;
|
||||
auto callback = [&counter]() { ++counter; };
|
||||
|
||||
pool.emplace(entity);
|
||||
|
||||
ASSERT_EQ(counter, 0);
|
||||
|
||||
pool.patch(entity);
|
||||
pool.patch(entity, callback);
|
||||
pool.patch(entity, callback, callback);
|
||||
|
||||
ASSERT_EQ(counter, 3);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(StorageNoInstanceDeathTest, Patch) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
|
||||
ASSERT_DEATH(pool.patch(entt::null), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, Insert) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const std::array entity{entt::entity{1}, entt::entity{3}};
|
||||
|
||||
pool.insert(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_EQ(pool.index(entity[0u]), 0u);
|
||||
ASSERT_EQ(pool.index(entity[1u]), 1u);
|
||||
|
||||
pool.erase(entity.begin(), entity.end());
|
||||
this->insert_instance(pool, entity.rbegin(), entity.rend());
|
||||
|
||||
ASSERT_EQ(pool.size(), 2u);
|
||||
ASSERT_EQ(pool.index(entity[0u]), 1u);
|
||||
ASSERT_EQ(pool.index(entity[1u]), 0u);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TYPED_TEST(StorageNoInstanceDeathTest, Insert) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const std::array entity{entt::entity{1}, entt::entity{3}};
|
||||
|
||||
pool.insert(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_DEATH(pool.insert(entity.begin(), entity.end()), "");
|
||||
ASSERT_DEATH(this->insert_instance(pool, entity.begin(), entity.end()), "");
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, Iterable) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using iterator = typename entt::storage<value_type>::iterable::iterator;
|
||||
|
||||
testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<entt::entity>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity>>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::reference, typename iterator::value_type>();
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const entt::sparse_set &base = pool;
|
||||
|
||||
pool.emplace(entt::entity{1});
|
||||
pool.emplace(entt::entity{3});
|
||||
|
||||
auto iterable = pool.each();
|
||||
|
||||
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.base(), base.begin());
|
||||
ASSERT_EQ(end.base(), base.end());
|
||||
|
||||
ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{3});
|
||||
ASSERT_EQ(std::get<0>(*begin), entt::entity{3});
|
||||
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(begin.base(), ++base.begin());
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
ASSERT_EQ(begin.base(), base.end());
|
||||
|
||||
for(auto [entity]: iterable) {
|
||||
testing::StaticAssertTypeEq<decltype(entity), entt::entity>();
|
||||
ASSERT_TRUE(entity == entt::entity{1} || entity == entt::entity{3});
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, ConstIterable) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using iterator = typename entt::storage<value_type>::const_iterable::iterator;
|
||||
|
||||
testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<entt::entity>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity>>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::reference, typename iterator::value_type>();
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const entt::sparse_set &base = pool;
|
||||
|
||||
pool.emplace(entt::entity{1});
|
||||
pool.emplace(entt::entity{3});
|
||||
|
||||
auto iterable = std::as_const(pool).each();
|
||||
|
||||
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.base(), base.begin());
|
||||
ASSERT_EQ(end.base(), base.end());
|
||||
|
||||
ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{3});
|
||||
ASSERT_EQ(std::get<0>(*begin), entt::entity{3});
|
||||
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(begin.base(), ++base.begin());
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
ASSERT_EQ(begin.base(), base.end());
|
||||
|
||||
for(auto [entity]: iterable) {
|
||||
testing::StaticAssertTypeEq<decltype(entity), entt::entity>();
|
||||
ASSERT_TRUE(entity == entt::entity{1} || entity == entt::entity{3});
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, IterableIteratorConversion) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
|
||||
pool.emplace(entt::entity{3});
|
||||
|
||||
const typename entt::storage<value_type>::iterable::iterator it = pool.each().begin();
|
||||
typename entt::storage<value_type>::const_iterable::iterator cit = it;
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(*it), std::tuple<entt::entity>>();
|
||||
testing::StaticAssertTypeEq<decltype(*cit), std::tuple<entt::entity>>();
|
||||
|
||||
ASSERT_EQ(it, cit);
|
||||
ASSERT_NE(++cit, it);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, IterableAlgorithmCompatibility) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const entt::entity entity{3};
|
||||
|
||||
pool.emplace(entity);
|
||||
|
||||
const auto iterable = pool.each();
|
||||
const auto it = std::find_if(iterable.begin(), iterable.end(), [entity](auto args) { return std::get<0>(args) == entity; });
|
||||
|
||||
ASSERT_EQ(std::get<0>(*it), entity);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, ReverseIterable) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using iterator = typename entt::storage<value_type>::reverse_iterable::iterator;
|
||||
|
||||
testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<entt::entity>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity>>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::reference, typename iterator::value_type>();
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const entt::sparse_set &base = pool;
|
||||
|
||||
pool.emplace(entt::entity{1});
|
||||
pool.emplace(entt::entity{3});
|
||||
|
||||
auto iterable = pool.reach();
|
||||
|
||||
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.base(), base.rbegin());
|
||||
ASSERT_EQ(end.base(), base.rend());
|
||||
|
||||
ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{1});
|
||||
ASSERT_EQ(std::get<0>(*begin), entt::entity{1});
|
||||
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(begin.base(), ++base.rbegin());
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
ASSERT_EQ(begin.base(), base.rend());
|
||||
|
||||
for(auto [entity]: iterable) {
|
||||
testing::StaticAssertTypeEq<decltype(entity), entt::entity>();
|
||||
ASSERT_TRUE(entity == entt::entity{1} || entity == entt::entity{3});
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, ConstReverseIterable) {
|
||||
using value_type = typename TestFixture::type;
|
||||
using iterator = typename entt::storage<value_type>::const_reverse_iterable::iterator;
|
||||
|
||||
testing::StaticAssertTypeEq<typename iterator::value_type, std::tuple<entt::entity>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::pointer, entt::input_iterator_pointer<std::tuple<entt::entity>>>();
|
||||
testing::StaticAssertTypeEq<typename iterator::reference, typename iterator::value_type>();
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const entt::sparse_set &base = pool;
|
||||
|
||||
pool.emplace(entt::entity{1});
|
||||
pool.emplace(entt::entity{3});
|
||||
|
||||
auto iterable = std::as_const(pool).reach();
|
||||
|
||||
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.base(), base.rbegin());
|
||||
ASSERT_EQ(end.base(), base.rend());
|
||||
|
||||
ASSERT_EQ(std::get<0>(*begin.operator->().operator->()), entt::entity{1});
|
||||
ASSERT_EQ(std::get<0>(*begin), entt::entity{1});
|
||||
|
||||
ASSERT_EQ(begin++, iterable.begin());
|
||||
ASSERT_EQ(begin.base(), ++base.rbegin());
|
||||
ASSERT_EQ(++begin, iterable.end());
|
||||
ASSERT_EQ(begin.base(), base.rend());
|
||||
|
||||
for(auto [entity]: iterable) {
|
||||
testing::StaticAssertTypeEq<decltype(entity), entt::entity>();
|
||||
ASSERT_TRUE(entity == entt::entity{1} || entity == entt::entity{3});
|
||||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, ReverseIterableIteratorConversion) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
|
||||
pool.emplace(entt::entity{3});
|
||||
|
||||
const typename entt::storage<value_type>::reverse_iterable::iterator it = pool.reach().begin();
|
||||
typename entt::storage<value_type>::const_reverse_iterable::iterator cit = it;
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(*it), std::tuple<entt::entity>>();
|
||||
testing::StaticAssertTypeEq<decltype(*cit), std::tuple<entt::entity>>();
|
||||
|
||||
ASSERT_EQ(it, cit);
|
||||
ASSERT_NE(++cit, it);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, ReverseIterableAlgorithmCompatibility) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const entt::entity entity{3};
|
||||
|
||||
pool.emplace(entity);
|
||||
|
||||
const auto iterable = pool.reach();
|
||||
const auto it = std::find_if(iterable.begin(), iterable.end(), [entity](auto args) { return std::get<0>(args) == entity; });
|
||||
|
||||
ASSERT_EQ(std::get<0>(*it), entity);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, SortOrdered) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const std::array entity{entt::entity{16}, entt::entity{8}, entt::entity{4}, entt::entity{2}, entt::entity{1}};
|
||||
|
||||
pool.insert(entity.begin(), entity.end());
|
||||
pool.sort(std::less{});
|
||||
|
||||
ASSERT_TRUE(std::equal(entity.rbegin(), entity.rend(), pool.begin(), pool.end()));
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, SortReverse) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const std::array entity{entt::entity{1}, entt::entity{2}, entt::entity{4}, entt::entity{8}, entt::entity{16}};
|
||||
|
||||
pool.insert(entity.begin(), entity.end());
|
||||
pool.sort(std::less{});
|
||||
|
||||
ASSERT_TRUE(std::equal(entity.begin(), entity.end(), pool.begin(), pool.end()));
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, SortUnordered) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const std::array entity{entt::entity{4}, entt::entity{2}, entt::entity{1}, entt::entity{8}, entt::entity{16}};
|
||||
|
||||
pool.insert(entity.begin(), entity.end());
|
||||
pool.sort(std::less{});
|
||||
|
||||
ASSERT_EQ(pool.data()[0u], entity[4u]);
|
||||
ASSERT_EQ(pool.data()[1u], entity[3u]);
|
||||
ASSERT_EQ(pool.data()[2u], entity[0u]);
|
||||
ASSERT_EQ(pool.data()[3u], entity[1u]);
|
||||
ASSERT_EQ(pool.data()[4u], entity[2u]);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, SortN) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> pool;
|
||||
const std::array entity{entt::entity{2}, entt::entity{4}, entt::entity{1}, entt::entity{8}, entt::entity{16}};
|
||||
|
||||
pool.insert(entity.begin(), entity.end());
|
||||
pool.sort_n(0u, std::less{});
|
||||
|
||||
ASSERT_TRUE(std::equal(entity.rbegin(), entity.rend(), pool.begin(), pool.end()));
|
||||
|
||||
pool.sort_n(2u, std::less{});
|
||||
|
||||
ASSERT_EQ(pool.data()[0u], entity[1u]);
|
||||
ASSERT_EQ(pool.data()[1u], entity[0u]);
|
||||
ASSERT_EQ(pool.data()[2u], entity[2u]);
|
||||
|
||||
const auto length = 5u;
|
||||
pool.sort_n(length, std::less{});
|
||||
|
||||
ASSERT_EQ(pool.data()[0u], entity[4u]);
|
||||
ASSERT_EQ(pool.data()[1u], entity[3u]);
|
||||
ASSERT_EQ(pool.data()[2u], entity[1u]);
|
||||
ASSERT_EQ(pool.data()[3u], entity[0u]);
|
||||
ASSERT_EQ(pool.data()[4u], entity[2u]);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, SortAsDisjoint) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> lhs;
|
||||
const entt::storage<value_type> rhs;
|
||||
const std::array entity{entt::entity{1}, entt::entity{2}, entt::entity{4}};
|
||||
|
||||
lhs.insert(entity.begin(), entity.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(entity.rbegin(), entity.rend(), lhs.begin(), lhs.end()));
|
||||
|
||||
lhs.sort_as(rhs.begin(), rhs.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(entity.rbegin(), entity.rend(), lhs.begin(), lhs.end()));
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, SortAsOverlap) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> lhs;
|
||||
entt::storage<value_type> rhs;
|
||||
const std::array lhs_entity{entt::entity{1}, entt::entity{2}, entt::entity{4}};
|
||||
const std::array rhs_entity{entt::entity{2}};
|
||||
|
||||
lhs.insert(lhs_entity.begin(), lhs_entity.end());
|
||||
rhs.insert(rhs_entity.begin(), rhs_entity.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(lhs_entity.rbegin(), lhs_entity.rend(), lhs.begin(), lhs.end()));
|
||||
ASSERT_TRUE(std::equal(rhs_entity.rbegin(), rhs_entity.rend(), rhs.begin(), rhs.end()));
|
||||
|
||||
lhs.sort_as(rhs.begin(), rhs.end());
|
||||
|
||||
ASSERT_EQ(lhs.data()[0u], lhs_entity[0u]);
|
||||
ASSERT_EQ(lhs.data()[1u], lhs_entity[2u]);
|
||||
ASSERT_EQ(lhs.data()[2u], lhs_entity[1u]);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, SortAsOrdered) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> lhs;
|
||||
entt::storage<value_type> rhs;
|
||||
const std::array lhs_entity{entt::entity{1}, entt::entity{2}, entt::entity{4}, entt::entity{8}, entt::entity{16}};
|
||||
const std::array rhs_entity{entt::entity{32}, entt::entity{1}, entt::entity{2}, entt::entity{4}, entt::entity{8}, entt::entity{16}};
|
||||
|
||||
lhs.insert(lhs_entity.begin(), lhs_entity.end());
|
||||
rhs.insert(rhs_entity.begin(), rhs_entity.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(lhs_entity.rbegin(), lhs_entity.rend(), lhs.begin(), lhs.end()));
|
||||
ASSERT_TRUE(std::equal(rhs_entity.rbegin(), rhs_entity.rend(), rhs.begin(), rhs.end()));
|
||||
|
||||
rhs.sort_as(lhs.begin(), lhs.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(rhs_entity.rbegin(), rhs_entity.rend(), rhs.begin(), rhs.end()));
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, SortAsReverse) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> lhs;
|
||||
entt::storage<value_type> rhs;
|
||||
const std::array lhs_entity{entt::entity{1}, entt::entity{2}, entt::entity{4}, entt::entity{8}, entt::entity{16}};
|
||||
const std::array rhs_entity{entt::entity{16}, entt::entity{8}, entt::entity{4}, entt::entity{2}, entt::entity{1}, entt::entity{32}};
|
||||
|
||||
lhs.insert(lhs_entity.begin(), lhs_entity.end());
|
||||
rhs.insert(rhs_entity.begin(), rhs_entity.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(lhs_entity.rbegin(), lhs_entity.rend(), lhs.begin(), lhs.end()));
|
||||
ASSERT_TRUE(std::equal(rhs_entity.rbegin(), rhs_entity.rend(), rhs.begin(), rhs.end()));
|
||||
|
||||
rhs.sort_as(lhs.begin(), lhs.end());
|
||||
|
||||
ASSERT_EQ(rhs.data()[0u], rhs_entity[5u]);
|
||||
ASSERT_EQ(rhs.data()[1u], rhs_entity[4u]);
|
||||
ASSERT_EQ(rhs.data()[2u], rhs_entity[3u]);
|
||||
ASSERT_EQ(rhs.data()[3u], rhs_entity[2u]);
|
||||
ASSERT_EQ(rhs.data()[4u], rhs_entity[1u]);
|
||||
ASSERT_EQ(rhs.data()[5u], rhs_entity[0u]);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageNoInstance, SortAsUnordered) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
entt::storage<value_type> lhs;
|
||||
entt::storage<value_type> rhs;
|
||||
const std::array lhs_entity{entt::entity{1}, entt::entity{2}, entt::entity{4}, entt::entity{8}, entt::entity{16}};
|
||||
const std::array rhs_entity{entt::entity{4}, entt::entity{2}, entt::entity{32}, entt::entity{1}, entt::entity{8}, entt::entity{16}};
|
||||
|
||||
lhs.insert(lhs_entity.begin(), lhs_entity.end());
|
||||
rhs.insert(rhs_entity.begin(), rhs_entity.end());
|
||||
|
||||
ASSERT_TRUE(std::equal(lhs_entity.rbegin(), lhs_entity.rend(), lhs.begin(), lhs.end()));
|
||||
ASSERT_TRUE(std::equal(rhs_entity.rbegin(), rhs_entity.rend(), rhs.begin(), rhs.end()));
|
||||
|
||||
rhs.sort_as(lhs.begin(), lhs.end());
|
||||
|
||||
ASSERT_EQ(rhs.data()[0u], rhs_entity[2u]);
|
||||
ASSERT_EQ(rhs.data()[1u], rhs_entity[3u]);
|
||||
ASSERT_EQ(rhs.data()[2u], rhs_entity[1u]);
|
||||
ASSERT_EQ(rhs.data()[3u], rhs_entity[0u]);
|
||||
ASSERT_EQ(rhs.data()[4u], rhs_entity[4u]);
|
||||
ASSERT_EQ(rhs.data()[5u], rhs_entity[5u]);
|
||||
}
|
||||
41
lib/All/entt/test/entt/entity/storage_utility.cpp
Normal file
41
lib/All/entt/test/entt/entity/storage_utility.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/entity/storage.hpp>
|
||||
|
||||
template<typename Type>
|
||||
struct StorageUtility: testing::Test {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
using StorageUtilityTypes = ::testing::Types<int, char, double, void>;
|
||||
|
||||
TYPED_TEST_SUITE(StorageUtility, StorageUtilityTypes, );
|
||||
|
||||
TYPED_TEST(StorageUtility, StorageType) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
// just a bunch of static asserts to avoid regressions
|
||||
#ifdef ENTT_NO_MIXIN
|
||||
testing::StaticAssertTypeEq<entt::storage_type_t<value_type, entt::entity>, entt::basic_storage<value_type, entt::entity>>();
|
||||
testing::StaticAssertTypeEq<entt::storage_type_t<value_type>, entt::storage<value_type>>();
|
||||
#else
|
||||
testing::StaticAssertTypeEq<entt::storage_type_t<value_type, entt::entity>, entt::sigh_mixin<entt::basic_storage<value_type, entt::entity>>>();
|
||||
testing::StaticAssertTypeEq<entt::storage_type_t<value_type>, entt::sigh_mixin<entt::storage<value_type>>>();
|
||||
#endif // ENTT_NO_MIXIN
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageUtility, StorageFor) {
|
||||
using value_type = typename TestFixture::type;
|
||||
|
||||
// just a bunch of static asserts to avoid regressions
|
||||
#ifdef ENTT_NO_MIXIN
|
||||
testing::StaticAssertTypeEq<entt::storage_for_t<const value_type, entt::entity>, const entt::basic_storage<value_type, entt::entity>>();
|
||||
testing::StaticAssertTypeEq<entt::storage_for_t<value_type, entt::entity>, entt::basic_storage<value_type, entt::entity>>();
|
||||
testing::StaticAssertTypeEq<entt::storage_for_t<const value_type>, const entt::storage<value_type>>();
|
||||
testing::StaticAssertTypeEq<entt::storage_for_t<value_type>, entt::storage<value_type>>();
|
||||
#else
|
||||
testing::StaticAssertTypeEq<entt::storage_for_t<const value_type, entt::entity>, const entt::sigh_mixin<entt::basic_storage<value_type, entt::entity>>>();
|
||||
testing::StaticAssertTypeEq<entt::storage_for_t<value_type, entt::entity>, entt::sigh_mixin<entt::basic_storage<value_type, entt::entity>>>();
|
||||
testing::StaticAssertTypeEq<entt::storage_for_t<const value_type>, const entt::sigh_mixin<entt::storage<value_type>>>();
|
||||
testing::StaticAssertTypeEq<entt::storage_for_t<value_type>, entt::sigh_mixin<entt::storage<value_type>>>();
|
||||
#endif
|
||||
}
|
||||
1611
lib/All/entt/test/entt/entity/view.cpp
Normal file
1611
lib/All/entt/test/entt/entity/view.cpp
Normal file
File diff suppressed because it is too large
Load Diff
574
lib/All/entt/test/entt/graph/adjacency_matrix.cpp
Normal file
574
lib/All/entt/test/entt/graph/adjacency_matrix.cpp
Normal file
@@ -0,0 +1,574 @@
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/graph/adjacency_matrix.hpp>
|
||||
#include "../../common/linter.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_TRUE(adjacency_matrix.empty());
|
||||
ASSERT_EQ(adjacency_matrix.size(), 3u);
|
||||
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
|
||||
ASSERT_FALSE(adjacency_matrix.empty());
|
||||
|
||||
const entt::adjacency_matrix<entt::directed_tag> temp{adjacency_matrix, adjacency_matrix.get_allocator()};
|
||||
const entt::adjacency_matrix<entt::directed_tag> other{std::move(adjacency_matrix), adjacency_matrix.get_allocator()};
|
||||
|
||||
test::is_initialized(adjacency_matrix);
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.empty());
|
||||
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
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_FALSE(adjacency_matrix.empty());
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
ASSERT_TRUE(other.contains(0u, 1u));
|
||||
|
||||
adjacency_matrix.resize(4u);
|
||||
adjacency_matrix.insert(0u, 2u);
|
||||
other.insert(1u, 2u);
|
||||
|
||||
other = adjacency_matrix;
|
||||
|
||||
ASSERT_FALSE(adjacency_matrix.empty());
|
||||
ASSERT_EQ(adjacency_matrix.size(), 4u);
|
||||
|
||||
ASSERT_EQ(other.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)};
|
||||
|
||||
test::is_initialized(adjacency_matrix);
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.empty());
|
||||
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
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);
|
||||
test::is_initialized(adjacency_matrix);
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.empty());
|
||||
|
||||
ASSERT_EQ(other.size(), 4u);
|
||||
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));
|
||||
|
||||
ASSERT_FALSE(adjacency_matrix.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
|
||||
adjacency_matrix.swap(other);
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
|
||||
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_FALSE(adjacency_matrix.empty());
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 2u));
|
||||
ASSERT_EQ(adjacency_matrix.size(), 3u);
|
||||
|
||||
adjacency_matrix.clear();
|
||||
|
||||
ASSERT_TRUE(adjacency_matrix.empty());
|
||||
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;
|
||||
|
||||
testing::StaticAssertTypeEq<iterator::value_type, std::size_t>();
|
||||
testing::StaticAssertTypeEq<iterator::pointer, void>();
|
||||
testing::StaticAssertTypeEq<iterator::reference, std::size_t>();
|
||||
|
||||
const 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;
|
||||
|
||||
testing::StaticAssertTypeEq<iterator::value_type, std::pair<std::size_t, std::size_t>>();
|
||||
testing::StaticAssertTypeEq<iterator::pointer, entt::input_iterator_pointer<std::pair<std::size_t, std::size_t>>>();
|
||||
testing::StaticAssertTypeEq<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, EdgesBackwardOnlyDirected) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{2u};
|
||||
auto iterable = adjacency_matrix.edges();
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(1u, 0u);
|
||||
iterable = adjacency_matrix.edges();
|
||||
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
|
||||
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, EdgesBackwardOnlyUndirected) {
|
||||
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{2u};
|
||||
auto iterable = adjacency_matrix.edges();
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(1u, 0u);
|
||||
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++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
|
||||
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, OutEdgesBackwardOnlyDirected) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{2u};
|
||||
auto iterable = adjacency_matrix.out_edges(1u);
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(1u, 0u);
|
||||
iterable = adjacency_matrix.out_edges(1u);
|
||||
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
|
||||
ASSERT_EQ(it, iterable.end());
|
||||
|
||||
iterable = adjacency_matrix.out_edges(0u);
|
||||
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, OutEdgesBackwardOnlyUndirected) {
|
||||
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{2u};
|
||||
auto iterable = adjacency_matrix.out_edges(1u);
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(1u, 0u);
|
||||
iterable = adjacency_matrix.out_edges(1u);
|
||||
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
|
||||
ASSERT_EQ(it, iterable.end());
|
||||
|
||||
iterable = adjacency_matrix.out_edges(0u);
|
||||
it = iterable.cbegin();
|
||||
|
||||
ASSERT_NE(it, iterable.cend());
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, 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, InEdgesBackwardOnlyDirected) {
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{2u};
|
||||
auto iterable = adjacency_matrix.in_edges(0u);
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(1u, 0u);
|
||||
iterable = adjacency_matrix.in_edges(0u);
|
||||
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
|
||||
ASSERT_EQ(it, iterable.end());
|
||||
|
||||
iterable = adjacency_matrix.in_edges(1u);
|
||||
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++, std::make_pair(std::size_t{2u}, 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, InEdgesBackwardOnlyUndirected) {
|
||||
entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{2u};
|
||||
auto iterable = adjacency_matrix.in_edges(0u);
|
||||
|
||||
ASSERT_EQ(iterable.begin(), iterable.end());
|
||||
|
||||
adjacency_matrix.insert(1u, 0u);
|
||||
iterable = adjacency_matrix.in_edges(0u);
|
||||
|
||||
ASSERT_NE(iterable.begin(), iterable.end());
|
||||
|
||||
auto it = iterable.begin();
|
||||
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
|
||||
ASSERT_EQ(it, iterable.end());
|
||||
|
||||
iterable = adjacency_matrix.in_edges(1u);
|
||||
it = iterable.cbegin();
|
||||
|
||||
ASSERT_NE(it, iterable.cend());
|
||||
ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
|
||||
ASSERT_EQ(it, iterable.cend());
|
||||
}
|
||||
|
||||
TEST(AdjacencyMatrix, ThrowingAllocator) {
|
||||
entt::adjacency_matrix<entt::directed_tag, test::throwing_allocator<std::size_t>> adjacency_matrix{2u};
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
adjacency_matrix.get_allocator().throw_counter<std::size_t>(0u);
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 2u);
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
|
||||
ASSERT_THROW(adjacency_matrix.resize(4u), test::throwing_allocator_exception);
|
||||
|
||||
ASSERT_EQ(adjacency_matrix.size(), 2u);
|
||||
ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
|
||||
}
|
||||
63
lib/All/entt/test/entt/graph/dot.cpp
Normal file
63
lib/All/entt/test/entt/graph/dot.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include <cstddef>
|
||||
#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 = R"(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);
|
||||
}
|
||||
350
lib/All/entt/test/entt/graph/flow.cpp
Normal file
350
lib/All/entt/test/entt/graph/flow.cpp
Normal file
@@ -0,0 +1,350 @@
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/graph/flow.hpp>
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/linter.hpp"
|
||||
#include "../../common/throwing_allocator.hpp"
|
||||
|
||||
TEST(Flow, Constructors) {
|
||||
entt::flow flow{};
|
||||
|
||||
ASSERT_TRUE(flow.empty());
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
|
||||
flow = entt::flow{std::allocator<entt::id_type>{}};
|
||||
|
||||
ASSERT_TRUE(flow.empty());
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
|
||||
flow.bind(2);
|
||||
flow.bind(4);
|
||||
flow.bind(8);
|
||||
|
||||
ASSERT_FALSE(flow.empty());
|
||||
ASSERT_EQ(flow.size(), 3u);
|
||||
|
||||
const entt::flow temp{flow, flow.get_allocator()};
|
||||
const entt::flow other{std::move(flow), flow.get_allocator()};
|
||||
|
||||
test::is_initialized(flow);
|
||||
|
||||
ASSERT_TRUE(flow.empty());
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
|
||||
ASSERT_EQ(other[0u], 2);
|
||||
ASSERT_EQ(other[1u], 4);
|
||||
ASSERT_EQ(other[2u], 8);
|
||||
}
|
||||
|
||||
TEST(Flow, Copy) {
|
||||
entt::flow flow{};
|
||||
|
||||
flow.bind(2);
|
||||
flow.bind(4);
|
||||
flow.bind(8);
|
||||
|
||||
entt::flow other{flow};
|
||||
|
||||
ASSERT_EQ(flow.size(), 3u);
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
|
||||
ASSERT_EQ(other[0u], 2);
|
||||
ASSERT_EQ(other[1u], 4);
|
||||
ASSERT_EQ(other[2u], 8);
|
||||
|
||||
flow.bind(1);
|
||||
other.bind(3);
|
||||
|
||||
other = flow;
|
||||
|
||||
ASSERT_EQ(other.size(), 4u);
|
||||
ASSERT_EQ(flow.size(), 4u);
|
||||
|
||||
ASSERT_EQ(other[0u], 2);
|
||||
ASSERT_EQ(other[1u], 4);
|
||||
ASSERT_EQ(other[2u], 8);
|
||||
ASSERT_EQ(other[3u], 1);
|
||||
}
|
||||
|
||||
TEST(Flow, Move) {
|
||||
entt::flow flow{};
|
||||
|
||||
flow.bind(2);
|
||||
flow.bind(4);
|
||||
flow.bind(8);
|
||||
|
||||
entt::flow other{std::move(flow)};
|
||||
|
||||
test::is_initialized(flow);
|
||||
|
||||
ASSERT_TRUE(flow.empty());
|
||||
ASSERT_EQ(other.size(), 3u);
|
||||
|
||||
ASSERT_EQ(other[0u], 2);
|
||||
ASSERT_EQ(other[1u], 4);
|
||||
ASSERT_EQ(other[2u], 8);
|
||||
|
||||
flow = {};
|
||||
flow.bind(1);
|
||||
other.bind(3);
|
||||
|
||||
other = std::move(flow);
|
||||
test::is_initialized(flow);
|
||||
|
||||
ASSERT_TRUE(flow.empty());
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
|
||||
ASSERT_EQ(other[0u], 1);
|
||||
}
|
||||
|
||||
TEST(Flow, Swap) {
|
||||
entt::flow flow{};
|
||||
entt::flow other{};
|
||||
|
||||
flow.bind(8);
|
||||
|
||||
ASSERT_EQ(other.size(), 0u);
|
||||
ASSERT_EQ(flow.size(), 1u);
|
||||
ASSERT_EQ(flow[0u], 8);
|
||||
|
||||
flow.swap(other);
|
||||
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
ASSERT_EQ(other[0u], 8);
|
||||
}
|
||||
|
||||
TEST(Flow, Clear) {
|
||||
entt::flow flow{};
|
||||
|
||||
flow.bind(0);
|
||||
flow.bind(4);
|
||||
|
||||
ASSERT_EQ(flow.size(), 2u);
|
||||
ASSERT_EQ(flow[0u], 0);
|
||||
ASSERT_EQ(flow[1u], 4);
|
||||
|
||||
flow.clear();
|
||||
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Flow, Set) {
|
||||
entt::flow flow{};
|
||||
flow.bind(0).set(2, true).bind(1).set(2, true).set(3, 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(2).bind(1).ro(2).ro(3);
|
||||
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 std::array<entt::id_type, 2u> res{10, 11};
|
||||
flow.bind(0).ro(res.begin(), res.begin() + 1u).bind(1).ro(res.begin(), res.end());
|
||||
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(2).bind(1).rw(2).rw(3);
|
||||
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 std::array<entt::id_type, 2u> res{10, 11};
|
||||
flow.bind(0).rw(res.begin(), res.begin() + 1u).bind(1).rw(res.begin(), res.end());
|
||||
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);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(FlowDeathTest, NoBind) {
|
||||
entt::flow flow{};
|
||||
|
||||
ASSERT_DEATH(flow.ro(4), "");
|
||||
ASSERT_DEATH(flow.rw(4), "");
|
||||
|
||||
flow.bind(0);
|
||||
|
||||
ASSERT_NO_THROW(flow.ro(1));
|
||||
ASSERT_NO_THROW(flow.rw(2));
|
||||
}
|
||||
|
||||
TEST(Flow, DirectRebind) {
|
||||
entt::flow flow{};
|
||||
flow.bind(0).ro(2).rw(2).bind(1).ro(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, DeferredRebind) {
|
||||
entt::flow flow{};
|
||||
flow.bind(0).ro(2).bind(1).ro(2).bind(0).rw(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_FALSE(graph.contains(0u, 1u));
|
||||
ASSERT_TRUE(graph.contains(1u, 0u));
|
||||
}
|
||||
|
||||
TEST(Flow, Loop) {
|
||||
entt::flow flow{};
|
||||
flow.bind(0).rw(2).bind(1).ro(2).bind(0).rw(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_TRUE(graph.contains(1u, 0u));
|
||||
}
|
||||
|
||||
TEST(Flow, ThrowingAllocator) {
|
||||
entt::basic_flow<test::throwing_allocator<entt::id_type>> flow{};
|
||||
|
||||
flow.get_allocator().throw_counter<std::pair<std::size_t, entt::id_type>>(0u);
|
||||
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
ASSERT_THROW(flow.bind(1), test::throwing_allocator_exception);
|
||||
ASSERT_EQ(flow.size(), 0u);
|
||||
|
||||
flow.bind(1);
|
||||
|
||||
ASSERT_EQ(flow.size(), 1u);
|
||||
}
|
||||
90
lib/All/entt/test/entt/locator/locator.cpp
Normal file
90
lib/All/entt/test/entt/locator/locator.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <memory>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/locator/locator.hpp>
|
||||
#include "../../common/config.h"
|
||||
|
||||
struct base_service {
|
||||
virtual ~base_service() = default;
|
||||
virtual int invoke(int) = 0;
|
||||
};
|
||||
|
||||
struct derived_service: base_service {
|
||||
derived_service(int val)
|
||||
: value{val} {}
|
||||
|
||||
int invoke(int other) override {
|
||||
return value + other;
|
||||
}
|
||||
|
||||
private:
|
||||
int value;
|
||||
};
|
||||
|
||||
struct ServiceLocator: ::testing::Test {
|
||||
void SetUp() override {
|
||||
entt::locator<base_service>::reset();
|
||||
}
|
||||
};
|
||||
|
||||
using ServiceLocatorDeathTest = ServiceLocator;
|
||||
|
||||
TEST_F(ServiceLocator, ValueAndTheLike) {
|
||||
ASSERT_FALSE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::value_or<derived_service>(1).invoke(3), 4);
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::value().invoke(9), 10);
|
||||
}
|
||||
|
||||
TEST_F(ServiceLocator, Emplace) {
|
||||
ASSERT_FALSE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::emplace<derived_service>(5).invoke(1), 6);
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 8);
|
||||
|
||||
entt::locator<base_service>::reset();
|
||||
|
||||
ASSERT_FALSE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::emplace<derived_service>(std::allocator_arg, std::allocator<derived_service>{}, 5).invoke(1), 6);
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 8);
|
||||
}
|
||||
|
||||
TEST_F(ServiceLocator, ResetHandle) {
|
||||
entt::locator<base_service>::emplace<derived_service>(1);
|
||||
auto handle = entt::locator<base_service>::handle();
|
||||
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 4);
|
||||
|
||||
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());
|
||||
ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 4);
|
||||
}
|
||||
|
||||
TEST_F(ServiceLocator, ElementWithDeleter) {
|
||||
derived_service service{1};
|
||||
entt::locator<base_service>::reset(&service, [&service](base_service *serv) {
|
||||
ASSERT_EQ(serv, &service);
|
||||
service = derived_service{2};
|
||||
});
|
||||
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::value().invoke(1), 2);
|
||||
|
||||
entt::locator<base_service>::reset();
|
||||
|
||||
ASSERT_EQ(service.invoke(1), 3);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(ServiceLocatorDeathTest, UninitializedValue) {
|
||||
ASSERT_EQ(entt::locator<base_service>::value_or<derived_service>(1).invoke(1), 2);
|
||||
|
||||
entt::locator<base_service>::reset();
|
||||
|
||||
ASSERT_DEATH(entt::locator<base_service>::value().invoke(4), "");
|
||||
}
|
||||
35
lib/All/entt/test/entt/meta/BUILD.bazel
Normal file
35
lib/All/entt/test/entt/meta/BUILD.bazel
Normal file
@@ -0,0 +1,35 @@
|
||||
load("@entt//bazel:copts.bzl", "COPTS")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_test")
|
||||
|
||||
# buildifier: keep sorted
|
||||
_TESTS = [
|
||||
"meta_any",
|
||||
"meta_base",
|
||||
"meta_container",
|
||||
"meta_context",
|
||||
"meta_conv",
|
||||
"meta_ctor",
|
||||
"meta_custom",
|
||||
"meta_data",
|
||||
"meta_dtor",
|
||||
"meta_factory",
|
||||
"meta_func",
|
||||
"meta_handle",
|
||||
"meta_pointer",
|
||||
"meta_range",
|
||||
"meta_template",
|
||||
"meta_type",
|
||||
"meta_utility",
|
||||
]
|
||||
|
||||
[cc_test(
|
||||
name = test,
|
||||
srcs = ["{}.cpp".format(test)],
|
||||
copts = COPTS,
|
||||
deps = [
|
||||
"//common",
|
||||
"@entt",
|
||||
"@googletest//:gtest",
|
||||
"@googletest//:gtest_main",
|
||||
],
|
||||
) for test in _TESTS]
|
||||
1596
lib/All/entt/test/entt/meta/meta_any.cpp
Normal file
1596
lib/All/entt/test/entt/meta/meta_any.cpp
Normal file
File diff suppressed because it is too large
Load Diff
194
lib/All/entt/test/entt/meta/meta_base.cpp
Normal file
194
lib/All/entt/test/entt/meta/meta_base.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/locator/locator.hpp>
|
||||
#include <entt/meta/context.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/node.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
|
||||
struct base_1 {
|
||||
base_1() = default;
|
||||
int value_1{};
|
||||
};
|
||||
|
||||
struct base_2 {
|
||||
base_2() = default;
|
||||
|
||||
operator int() const {
|
||||
return value_2;
|
||||
}
|
||||
|
||||
int value_2{};
|
||||
};
|
||||
|
||||
struct base_3: base_2 {
|
||||
base_3() = default;
|
||||
int value_3{};
|
||||
};
|
||||
|
||||
struct derived: base_1, base_3 {
|
||||
derived() = default;
|
||||
int value{};
|
||||
};
|
||||
|
||||
struct MetaBase: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<base_1>{}
|
||||
.data<&base_1::value_1>("value_1"_hs);
|
||||
|
||||
entt::meta_factory<base_2>{}
|
||||
.conv<int>()
|
||||
.data<&base_2::value_2>("value_2"_hs);
|
||||
|
||||
entt::meta_factory<base_3>{}
|
||||
.base<base_2>()
|
||||
.data<&base_3::value_3>("value_3"_hs);
|
||||
|
||||
entt::meta_factory<derived>{}
|
||||
.type("derived"_hs)
|
||||
.base<base_1>()
|
||||
.base<base_3>()
|
||||
.data<&derived::value>("value"_hs);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(MetaBase, Base) {
|
||||
auto any = entt::resolve<derived>().construct();
|
||||
any.cast<derived &>().value_1 = 2;
|
||||
auto as_derived = any.as_ref();
|
||||
|
||||
ASSERT_TRUE(any.allow_cast<base_1 &>());
|
||||
|
||||
ASSERT_FALSE(any.allow_cast<char>());
|
||||
ASSERT_FALSE(as_derived.allow_cast<char>());
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<base_1 &>().value_1, as_derived.cast<derived &>().value_1);
|
||||
|
||||
any.cast<base_1 &>().value_1 = 3;
|
||||
|
||||
ASSERT_EQ(any.cast<const base_1 &>().value_1, as_derived.cast<const derived &>().value_1);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, SetGetWithMutatingThis) {
|
||||
using namespace entt::literals;
|
||||
|
||||
derived 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 *>(&instance)), static_cast<const void *>(static_cast<const base_2 *>(&instance)));
|
||||
ASSERT_NE(static_cast<const void *>(static_cast<const base_1 *>(&instance)), static_cast<const void *>(static_cast<const base_3 *>(&instance)));
|
||||
ASSERT_EQ(static_cast<const void *>(static_cast<const base_2 *>(&instance)), static_cast<const void *>(static_cast<const base_3 *>(&instance)));
|
||||
ASSERT_EQ(static_cast<const void *>(&instance), static_cast<const void *>(static_cast<const base_1 *>(&instance)));
|
||||
|
||||
ASSERT_TRUE(any.set("value"_hs, 0));
|
||||
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, 4));
|
||||
ASSERT_FALSE(as_cref.set("value_1"_hs, 4));
|
||||
ASSERT_FALSE(as_cref.set("value_2"_hs, 4));
|
||||
ASSERT_FALSE(as_cref.set("value_3"_hs, 4));
|
||||
|
||||
ASSERT_EQ(any.get("value"_hs).cast<int>(), 0);
|
||||
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>(), 0);
|
||||
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, 0);
|
||||
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{}};
|
||||
auto &&ref = any.cast<derived &>();
|
||||
auto as_cref = std::as_const(any).as_ref();
|
||||
ref.value_2 = 2;
|
||||
|
||||
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>(), 2);
|
||||
ASSERT_EQ(from_cref.cast<int>(), 2);
|
||||
|
||||
ASSERT_TRUE(as_cref.allow_cast<int>());
|
||||
ASSERT_TRUE(any.allow_cast<int>());
|
||||
|
||||
ASSERT_EQ(as_cref.cast<int>(), 2);
|
||||
ASSERT_EQ(any.cast<int>(), 2);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, OpaqueConvWithMutatingThis) {
|
||||
entt::meta_any any{derived{}};
|
||||
auto as_cref = std::as_const(any).as_ref();
|
||||
any.cast<derived &>().value_2 = 2;
|
||||
|
||||
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>(), 2);
|
||||
ASSERT_EQ(from_cref.cast<int>(), 2);
|
||||
|
||||
ASSERT_TRUE(as_cref.allow_cast(entt::resolve<int>()));
|
||||
ASSERT_TRUE(any.allow_cast(entt::resolve<int>()));
|
||||
|
||||
ASSERT_EQ(as_cref.cast<int>(), 2);
|
||||
ASSERT_EQ(any.cast<int>(), 2);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, AssignWithMutatingThis) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_any dst{base_2{}};
|
||||
entt::meta_any src{derived{}};
|
||||
|
||||
dst.cast<base_2 &>().value_2 = 0;
|
||||
src.cast<derived &>().value_2 = 1;
|
||||
|
||||
ASSERT_TRUE(dst.assign(src));
|
||||
ASSERT_EQ(dst.get("value_2"_hs).cast<int>(), 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, TransferWithMutatingThis) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_any dst{base_2{}};
|
||||
entt::meta_any src{derived{}};
|
||||
|
||||
dst.cast<base_2 &>().value_2 = 0;
|
||||
src.cast<derived &>().value_2 = 1;
|
||||
|
||||
ASSERT_TRUE(dst.assign(std::move(src)));
|
||||
ASSERT_EQ(dst.get("value_2"_hs).cast<int>(), 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaBase, ReRegistration) {
|
||||
SetUp();
|
||||
|
||||
auto &&node = entt::internal::resolve<derived>(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);
|
||||
}
|
||||
827
lib/All/entt/test/entt/meta/meta_container.cpp
Normal file
827
lib/All/entt/test/entt/meta/meta_container.cpp
Normal file
@@ -0,0 +1,827 @@
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/container/dense_map.hpp>
|
||||
#include <entt/container/dense_set.hpp>
|
||||
#include <entt/meta/container.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/empty.h"
|
||||
#include "../../common/non_default_constructible.h"
|
||||
|
||||
TEST(MetaContainer, Invalid) {
|
||||
ASSERT_FALSE(entt::meta_any{0}.as_sequence_container());
|
||||
ASSERT_FALSE(entt::meta_any{0}.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(SequenceContainer, Empty) {
|
||||
entt::meta_sequence_container container{};
|
||||
|
||||
ASSERT_FALSE(container);
|
||||
|
||||
entt::meta_any any{std::vector<int>{}};
|
||||
container = any.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(container);
|
||||
}
|
||||
|
||||
TEST(SequenceContainer, Iterator) {
|
||||
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(SequenceContainer, 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, test::empty{}));
|
||||
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(), 64);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(*ret, 64);
|
||||
|
||||
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_TRUE(view.reserve(8u));
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(SequenceContainer, 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, test::empty{}));
|
||||
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_TRUE(view.reserve(8u));
|
||||
ASSERT_EQ(cview.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(SequenceContainer, 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_FALSE(view.reserve(8u));
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
}
|
||||
|
||||
TEST(SequenceContainer, 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, test::empty{}));
|
||||
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(), 64);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(*ret, 64);
|
||||
|
||||
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_FALSE(view.reserve(8u));
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(SequenceContainer, 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, test::empty{}));
|
||||
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(), 64);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(*ret, 64);
|
||||
|
||||
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_FALSE(view.reserve(8u));
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(SequenceContainer, NonDefaultConstructible) {
|
||||
std::vector<test::non_default_constructible> vec{};
|
||||
auto any = entt::forward_as_meta(vec);
|
||||
auto view = any.as_sequence_container();
|
||||
|
||||
ASSERT_FALSE(view.resize(5u));
|
||||
}
|
||||
|
||||
TEST(SequenceContainer, Constness) {
|
||||
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(64);
|
||||
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
ASSERT_EQ(view[0].cast<const int &>(), 64);
|
||||
|
||||
auto it = view.begin();
|
||||
auto ret = view.insert(it, 0);
|
||||
|
||||
ASSERT_FALSE(ret);
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
ASSERT_EQ(it->cast<int>(), 64);
|
||||
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_FALSE(view.reserve(8u));
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(SequenceContainerDeathTest, Constness) {
|
||||
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(SequenceContainer, FromConstAny) {
|
||||
const std::vector<int> vec{64};
|
||||
const entt::meta_any any{vec};
|
||||
auto view = any.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.value_type(), entt::resolve<int>());
|
||||
ASSERT_EQ(view[0].cast<const int &>(), 64);
|
||||
}
|
||||
|
||||
TEST(SequenceContainer, FromConstAnyRef) {
|
||||
std::vector<int> vec{64};
|
||||
const entt::meta_any any = entt::forward_as_meta(vec);
|
||||
auto view = any.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.value_type(), entt::resolve<int>());
|
||||
ASSERT_EQ(view[0].cast<const int &>(), 64);
|
||||
}
|
||||
|
||||
TEST(SequenceContainer, FromConstAnyConstRef) {
|
||||
std::vector<int> vec{64};
|
||||
const entt::meta_any 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[0].cast<const int &>(), 64);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(SequenceContainerDeathTest, FromConstAny) {
|
||||
const std::vector<int> vec{64};
|
||||
const entt::meta_any any{vec};
|
||||
auto view = any.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_DEATH(view[0].cast<int &>() = 2, "");
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(SequenceContainerDeathTest, FromConstAnyRef) {
|
||||
std::vector<int> vec{64};
|
||||
const entt::meta_any any = entt::forward_as_meta(vec);
|
||||
auto view = any.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_DEATH(view[0].cast<int &>() = 2, "");
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(SequenceContainerDeathTest, FromConstAnyConstRef) {
|
||||
std::vector<int> vec{64};
|
||||
const entt::meta_any 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(AssociativeContainer, Empty) {
|
||||
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(AssociativeContainer, Iterator) {
|
||||
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(AssociativeContainer, 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_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(test::empty{}, 'a'));
|
||||
ASSERT_FALSE(view.insert(1, test::empty{}));
|
||||
|
||||
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(test::empty{}), 0u);
|
||||
ASSERT_FALSE(view.find(test::empty{}));
|
||||
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_FALSE(view.reserve(8u));
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(AssociativeContainer, 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_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(test::empty{}));
|
||||
|
||||
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(test::empty{}), 0u);
|
||||
ASSERT_FALSE(view.find(test::empty{}));
|
||||
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_FALSE(view.reserve(8u));
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(AssociativeContainer, 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_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(test::empty{}, 'a'));
|
||||
ASSERT_FALSE(view.insert(1, test::empty{}));
|
||||
|
||||
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(test::empty{}), 0u);
|
||||
ASSERT_FALSE(view.find(test::empty{}));
|
||||
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_TRUE(view.reserve(8u));
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(AssociativeContainer, 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_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(test::empty{}));
|
||||
|
||||
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(test::empty{}), 0u);
|
||||
ASSERT_FALSE(view.find(test::empty{}));
|
||||
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_TRUE(view.reserve(8u));
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(KeyValueAssociativeContainer, Constness) {
|
||||
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_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_FALSE(view.reserve(8u));
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(KeyValueAssociativeContainerDeathTest, Constness) {
|
||||
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(KeyOnlyAssociativeContainer, Constness) {
|
||||
std::set<int> set{};
|
||||
auto any = entt::forward_as_meta(std::as_const(set));
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
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_FALSE(view.reserve(8u));
|
||||
ASSERT_EQ(view.size(), 1u);
|
||||
}
|
||||
|
||||
TEST(KeyValueAssociativeContainer, FromConstAny) {
|
||||
const std::map<int, char> map{{2, 'c'}};
|
||||
const entt::meta_any any{map};
|
||||
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');
|
||||
}
|
||||
|
||||
TEST(KeyValueAssociativeContainer, FromConstAnyRef) {
|
||||
std::map<int, char> map{{2, 'c'}};
|
||||
const entt::meta_any any = entt::forward_as_meta(map);
|
||||
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');
|
||||
}
|
||||
|
||||
TEST(KeyValueAssociativeContainer, FromConstAnyConstRef) {
|
||||
std::map<int, char> map{{2, 'c'}};
|
||||
const entt::meta_any any = entt::forward_as_meta(std::as_const(map));
|
||||
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');
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(KeyValueAssociativeContainerDeathTest, FromConstAny) {
|
||||
const std::map<int, char> map{{2, 'c'}};
|
||||
const entt::meta_any any{map};
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_DEATH(view.find(2)->second.cast<char &>() = 'a', "");
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(KeyValueAssociativeContainerDeathTest, FromConstAnyRef) {
|
||||
std::map<int, char> map{{2, 'c'}};
|
||||
const entt::meta_any any = entt::forward_as_meta(map);
|
||||
auto view = any.as_associative_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_DEATH(view.find(2)->second.cast<char &>() = 'a', "");
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(KeyValueAssociativeContainerDeathTest, FromConstAnyConstRef) {
|
||||
std::map<int, char> map{{2, 'c'}};
|
||||
const entt::meta_any 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(KeyOnlyAssociativeContainer, FromConstAny) {
|
||||
const std::set<int> set{2};
|
||||
const entt::meta_any any{set};
|
||||
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);
|
||||
}
|
||||
|
||||
TEST(KeyOnlyAssociativeContainer, FromConstAnyRef) {
|
||||
std::set<int> set{2};
|
||||
const entt::meta_any any = entt::forward_as_meta(set);
|
||||
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);
|
||||
}
|
||||
|
||||
TEST(KeyOnlyAssociativeContainer, FromConstAnyConstRef) {
|
||||
std::set<int> set{2};
|
||||
const entt::meta_any any = entt::forward_as_meta(std::as_const(set));
|
||||
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);
|
||||
}
|
||||
509
lib/All/entt/test/entt/meta/meta_context.cpp
Normal file
509
lib/All/entt/test/entt/meta/meta_context.cpp
Normal file
@@ -0,0 +1,509 @@
|
||||
#include <iterator>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/core/type_info.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/empty.h"
|
||||
|
||||
struct base {
|
||||
base() = default;
|
||||
|
||||
base(char cv)
|
||||
: value{cv} {}
|
||||
|
||||
[[nodiscard]] char get() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
char value;
|
||||
};
|
||||
|
||||
struct clazz: base {
|
||||
clazz()
|
||||
: base{} {}
|
||||
|
||||
clazz(int iv)
|
||||
: base{},
|
||||
value{iv} {}
|
||||
|
||||
clazz(char cv, int iv) // NOLINT
|
||||
: base{cv},
|
||||
value{iv} {}
|
||||
|
||||
[[nodiscard]] int func(int iv) {
|
||||
return (value = iv);
|
||||
}
|
||||
|
||||
[[nodiscard]] int cfunc(int) const {
|
||||
return value;
|
||||
}
|
||||
|
||||
static void move_to_bucket(const clazz &instance) {
|
||||
bucket = instance.value;
|
||||
}
|
||||
|
||||
int value{};
|
||||
inline static int bucket{}; // NOLINT
|
||||
};
|
||||
|
||||
struct argument {
|
||||
argument(int val)
|
||||
: value{val} {}
|
||||
|
||||
[[nodiscard]] int get() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] int get_mul() const {
|
||||
return value * 2;
|
||||
}
|
||||
|
||||
private:
|
||||
int value{};
|
||||
};
|
||||
|
||||
template<typename...>
|
||||
struct template_clazz {};
|
||||
|
||||
class MetaContext: public ::testing::Test {
|
||||
static void init_global_context() {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<int>{}
|
||||
.data<global_marker>("marker"_hs);
|
||||
|
||||
entt::meta_factory<argument>{}
|
||||
.conv<&argument::get>();
|
||||
|
||||
entt::meta_factory<clazz>{}
|
||||
.type("foo"_hs)
|
||||
.custom<int>(3)
|
||||
.ctor<int>()
|
||||
.data<&clazz::value>("value"_hs)
|
||||
.data<&clazz::value>("rw"_hs)
|
||||
.func<&clazz::func>("func"_hs);
|
||||
|
||||
entt::meta_factory<template_clazz<int>>{}
|
||||
.type("template"_hs);
|
||||
}
|
||||
|
||||
void init_local_context() {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<int>{context}
|
||||
.data<local_marker>("marker"_hs);
|
||||
|
||||
entt::meta_factory<test::empty>{context}
|
||||
.type("quux"_hs);
|
||||
|
||||
entt::meta_factory<argument>{context}
|
||||
.conv<&argument::get_mul>();
|
||||
|
||||
entt::meta_factory<base>{context}
|
||||
.data<&base::value>("char"_hs)
|
||||
.func<&base::get>("get"_hs);
|
||||
|
||||
entt::meta_factory<clazz>{context}
|
||||
.type("bar"_hs)
|
||||
.custom<char>('c')
|
||||
.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_factory<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();
|
||||
}
|
||||
|
||||
[[nodiscard]] const entt::meta_ctx &ctx() const noexcept {
|
||||
return context;
|
||||
}
|
||||
|
||||
protected:
|
||||
static constexpr int global_marker = 1;
|
||||
static constexpr int local_marker = 4;
|
||||
static constexpr int bucket_value = 2;
|
||||
|
||||
private:
|
||||
entt::meta_ctx context{};
|
||||
};
|
||||
|
||||
TEST_F(MetaContext, Resolve) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz>());
|
||||
ASSERT_TRUE(entt::resolve<clazz>(ctx()));
|
||||
|
||||
ASSERT_TRUE(entt::resolve<test::empty>());
|
||||
ASSERT_TRUE(entt::resolve<test::empty>(ctx()));
|
||||
|
||||
ASSERT_TRUE(entt::resolve(entt::type_id<clazz>()));
|
||||
ASSERT_TRUE(entt::resolve(ctx(), entt::type_id<clazz>()));
|
||||
|
||||
ASSERT_FALSE(entt::resolve(entt::type_id<test::empty>()));
|
||||
ASSERT_TRUE(entt::resolve(ctx(), entt::type_id<test::empty>()));
|
||||
|
||||
ASSERT_TRUE(entt::resolve("foo"_hs));
|
||||
ASSERT_FALSE(entt::resolve(ctx(), "foo"_hs));
|
||||
|
||||
ASSERT_FALSE(entt::resolve("bar"_hs));
|
||||
ASSERT_TRUE(entt::resolve(ctx(), "bar"_hs));
|
||||
|
||||
ASSERT_FALSE(entt::resolve("quux"_hs));
|
||||
ASSERT_TRUE(entt::resolve(ctx(), "quux"_hs));
|
||||
|
||||
ASSERT_EQ((std::distance(entt::resolve().cbegin(), entt::resolve().cend())), 4);
|
||||
ASSERT_EQ((std::distance(entt::resolve(ctx()).cbegin(), entt::resolve(ctx()).cend())), 6);
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaType) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const auto global = entt::resolve<clazz>();
|
||||
const auto local = entt::resolve<clazz>(ctx());
|
||||
|
||||
ASSERT_TRUE(global);
|
||||
ASSERT_TRUE(local);
|
||||
|
||||
ASSERT_NE(global, local);
|
||||
|
||||
ASSERT_EQ(global, entt::resolve("foo"_hs));
|
||||
ASSERT_EQ(local, entt::resolve(ctx(), "bar"_hs));
|
||||
|
||||
ASSERT_EQ(global.id(), "foo"_hs);
|
||||
ASSERT_EQ(local.id(), "bar"_hs);
|
||||
|
||||
clazz instance{'c', 8};
|
||||
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>(), instance.value);
|
||||
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>(ctx());
|
||||
|
||||
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(ctx(), entt::type_id<base>()));
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaData) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const auto global = entt::resolve<clazz>();
|
||||
const auto local = entt::resolve<clazz>(ctx());
|
||||
|
||||
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', 8};
|
||||
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>(ctx());
|
||||
|
||||
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', 8};
|
||||
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>(), instance.value);
|
||||
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>(ctx());
|
||||
|
||||
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);
|
||||
|
||||
const 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(ctx(), 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>(ctx()).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, MetaCustom) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const auto global = entt::resolve<clazz>();
|
||||
const auto local = entt::resolve<clazz>(ctx());
|
||||
|
||||
ASSERT_NE(static_cast<const int *>(global.custom()), nullptr);
|
||||
ASSERT_NE(static_cast<const char *>(local.custom()), nullptr);
|
||||
|
||||
ASSERT_EQ(static_cast<int>(global.custom()), 3);
|
||||
ASSERT_EQ(static_cast<char>(local.custom()), 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaContext, MetaTemplate) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const auto global = entt::resolve("template"_hs);
|
||||
const auto local = entt::resolve(ctx(), "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>(ctx()));
|
||||
ASSERT_EQ(local.template_arg(1u), entt::resolve<char>(ctx()));
|
||||
|
||||
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 = 2;
|
||||
|
||||
const entt::meta_any global{&value};
|
||||
const entt::meta_any local{ctx(), &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(ctx(), 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(ctx(), 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;
|
||||
|
||||
const entt::meta_any global{2};
|
||||
const entt::meta_any ctx_value{ctx(), 2};
|
||||
const entt::meta_any in_place{ctx(), std::in_place_type<int>, 2};
|
||||
entt::meta_any two_step_local{entt::meta_ctx_arg, ctx()};
|
||||
|
||||
ASSERT_TRUE(global);
|
||||
ASSERT_TRUE(ctx_value);
|
||||
ASSERT_TRUE(in_place);
|
||||
ASSERT_FALSE(two_step_local);
|
||||
|
||||
two_step_local = 2;
|
||||
|
||||
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 = 2;
|
||||
|
||||
entt::meta_handle global{value};
|
||||
entt::meta_handle ctx_value{ctx(), value};
|
||||
entt::meta_handle two_step_local{entt::meta_ctx_arg, ctx()};
|
||||
|
||||
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(2);
|
||||
const auto local = entt::forward_as_meta(ctx(), 2);
|
||||
|
||||
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);
|
||||
}
|
||||
72
lib/All/entt/test/entt/meta/meta_conv.cpp
Normal file
72
lib/All/entt/test/entt/meta/meta_conv.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/locator/locator.hpp>
|
||||
#include <entt/meta/context.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/node.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
|
||||
struct clazz {
|
||||
clazz() = default;
|
||||
|
||||
operator int() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool to_bool() const {
|
||||
return (value != 0);
|
||||
}
|
||||
|
||||
int value{};
|
||||
};
|
||||
|
||||
double conv_to_double(const clazz &instance) {
|
||||
return instance.value * 2.;
|
||||
}
|
||||
|
||||
struct MetaConv: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<clazz>{}
|
||||
.type("clazz"_hs)
|
||||
.conv<int>()
|
||||
.conv<&clazz::to_bool>()
|
||||
.conv<conv_to_double>();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(MetaConv, Conv) {
|
||||
auto any = entt::resolve<clazz>().construct();
|
||||
any.cast<clazz &>().value = 2;
|
||||
|
||||
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 &>().operator int());
|
||||
ASSERT_EQ(as_bool.cast<bool>(), any.cast<clazz &>().to_bool());
|
||||
ASSERT_EQ(as_double.cast<double>(), conv_to_double(any.cast<clazz &>()));
|
||||
}
|
||||
|
||||
TEST_F(MetaConv, ReRegistration) {
|
||||
SetUp();
|
||||
|
||||
auto &&node = entt::internal::resolve<clazz>(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);
|
||||
}
|
||||
214
lib/All/entt/test/entt/meta/meta_ctor.cpp
Normal file
214
lib/All/entt/test/entt/meta/meta_ctor.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
#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/context.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/policy.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
|
||||
struct base {
|
||||
char value{'c'};
|
||||
};
|
||||
|
||||
struct derived: base {
|
||||
derived()
|
||||
: base{} {}
|
||||
};
|
||||
|
||||
struct clazz {
|
||||
clazz(const base &other, int &iv)
|
||||
: clazz{iv, other.value} {}
|
||||
|
||||
clazz(const int &iv, char cv)
|
||||
: i{iv}, c{cv} {}
|
||||
|
||||
operator int() const {
|
||||
return i;
|
||||
}
|
||||
|
||||
static clazz factory(int value) {
|
||||
return {value, 'c'};
|
||||
}
|
||||
|
||||
static clazz factory(base other, int value, int mul) {
|
||||
return {value * mul, other.value};
|
||||
}
|
||||
|
||||
int i{};
|
||||
char c{};
|
||||
};
|
||||
|
||||
double double_factory() {
|
||||
return 1.;
|
||||
}
|
||||
|
||||
struct MetaCtor: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<double>{}
|
||||
.type("double"_hs)
|
||||
.ctor<double_factory>();
|
||||
|
||||
entt::meta_factory<derived>{}
|
||||
.type("derived"_hs)
|
||||
.base<base>();
|
||||
|
||||
entt::meta_factory<clazz>{}
|
||||
.type("clazz"_hs)
|
||||
.ctor<&entt::registry::emplace_or_replace<clazz, const int &, const char &>, entt::as_ref_t>()
|
||||
.ctor<const base &, int &>()
|
||||
.ctor<const int &, char>()
|
||||
.ctor<entt::overload<clazz(int)>(clazz::factory)>()
|
||||
.ctor<entt::overload<clazz(base, int, int)>(clazz::factory)>()
|
||||
.conv<int>();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(MetaCtor, Ctor) {
|
||||
auto any = entt::resolve<clazz>().construct(1, 'c');
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz>().i, 1);
|
||||
ASSERT_EQ(any.cast<clazz>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, Func) {
|
||||
auto any = entt::resolve<clazz>().construct(1);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz>().i, 1);
|
||||
ASSERT_EQ(any.cast<clazz>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, MetaAnyArgs) {
|
||||
auto any = entt::resolve<clazz>().construct(entt::meta_any{1}, entt::meta_any{'c'});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz>().i, 1);
|
||||
ASSERT_EQ(any.cast<clazz>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, InvalidArgs) {
|
||||
ASSERT_FALSE(entt::resolve<clazz>().construct(entt::meta_any{}, derived{}));
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, CastAndConvert) {
|
||||
auto any = entt::resolve<clazz>().construct(derived{}, clazz{1, 'd'});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz>().i, 1);
|
||||
ASSERT_EQ(any.cast<clazz>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, ArithmeticConversion) {
|
||||
auto any = entt::resolve<clazz>().construct(true, 4.2);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz>().i, 1);
|
||||
ASSERT_EQ(any.cast<clazz>().c, char{4});
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, ConstNonConstRefArgs) {
|
||||
int ivalue = 1;
|
||||
const char cvalue = 'c';
|
||||
auto any = entt::resolve<clazz>().construct(entt::forward_as_meta(ivalue), entt::forward_as_meta(cvalue));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz>().i, 1);
|
||||
ASSERT_EQ(any.cast<clazz>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, WrongConstness) {
|
||||
int value = 1;
|
||||
auto any = entt::resolve<clazz>().construct(derived{}, entt::forward_as_meta(value));
|
||||
auto other = entt::resolve<clazz>().construct(derived{}, entt::forward_as_meta(std::as_const(value)));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(other);
|
||||
ASSERT_EQ(any.cast<clazz>().i, 1);
|
||||
ASSERT_EQ(any.cast<clazz>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, FuncMetaAnyArgs) {
|
||||
auto any = entt::resolve<clazz>().construct(entt::meta_any{1});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz>().i, 1);
|
||||
ASSERT_EQ(any.cast<clazz>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, FuncCastAndConvert) {
|
||||
auto any = entt::resolve<clazz>().construct(derived{}, 3., clazz{3, 'd'});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz>().i, 9);
|
||||
ASSERT_EQ(any.cast<clazz>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, FuncArithmeticConversion) {
|
||||
auto any = entt::resolve<clazz>().construct(4.2);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz>().i, 4);
|
||||
ASSERT_EQ(any.cast<clazz>().c, 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, FuncConstNonConstRefArgs) {
|
||||
int ivalue = 1;
|
||||
auto any = entt::resolve<clazz>().construct(entt::forward_as_meta(ivalue));
|
||||
auto other = entt::resolve<clazz>().construct(entt::forward_as_meta(std::as_const(ivalue)));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_EQ(any.cast<clazz>().i, 1);
|
||||
ASSERT_EQ(other.cast<clazz>().i, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, ExternalMemberFunction) {
|
||||
entt::registry registry;
|
||||
const auto entity = registry.create();
|
||||
|
||||
ASSERT_FALSE(registry.all_of<clazz>(entity));
|
||||
|
||||
const auto any = entt::resolve<clazz>().construct(entt::forward_as_meta(registry), entity, 3, 'c');
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(registry.all_of<clazz>(entity));
|
||||
ASSERT_EQ(registry.get<clazz>(entity).i, 3);
|
||||
ASSERT_EQ(registry.get<clazz>(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>(), 1.);
|
||||
}
|
||||
|
||||
TEST_F(MetaCtor, NonDefaultConstructibleType) {
|
||||
auto type = entt::resolve<clazz>();
|
||||
// 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);
|
||||
}
|
||||
141
lib/All/entt/test/entt/meta/meta_custom.cpp
Normal file
141
lib/All/entt/test/entt/meta/meta_custom.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include "../../common/config.h"
|
||||
|
||||
struct clazz {
|
||||
int i{2};
|
||||
char j{'c'};
|
||||
|
||||
[[nodiscard]] int f(int) const {
|
||||
return i;
|
||||
}
|
||||
|
||||
[[nodiscard]] char g(char) const {
|
||||
return j;
|
||||
}
|
||||
};
|
||||
|
||||
struct MetaCustom: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<clazz>{}
|
||||
.type("clazz"_hs)
|
||||
.custom<char>('c')
|
||||
.data<&clazz::i>("i"_hs)
|
||||
.custom<int>(0)
|
||||
.data<&clazz::j>("j"_hs)
|
||||
.func<&clazz::f>("f"_hs)
|
||||
.custom<int>(1)
|
||||
.func<&clazz::g>("g"_hs);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
using MetaCustomDeathTest = MetaCustom;
|
||||
|
||||
TEST_F(MetaCustom, Custom) {
|
||||
entt::meta_custom custom{};
|
||||
|
||||
ASSERT_EQ(static_cast<const char *>(custom), nullptr);
|
||||
|
||||
custom = entt::resolve<clazz>().custom();
|
||||
|
||||
ASSERT_NE(static_cast<const char *>(custom), nullptr);
|
||||
|
||||
ASSERT_EQ(*static_cast<const char *>(custom), 'c');
|
||||
ASSERT_EQ(static_cast<const char &>(custom), 'c');
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaCustomDeathTest, Custom) {
|
||||
entt::meta_custom custom{};
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const char &value = custom, "");
|
||||
|
||||
custom = entt::resolve<clazz>().custom();
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const int &value = custom, "");
|
||||
}
|
||||
|
||||
TEST_F(MetaCustom, Type) {
|
||||
ASSERT_NE(static_cast<const char *>(entt::resolve<clazz>().custom()), nullptr);
|
||||
ASSERT_EQ(*static_cast<const char *>(entt::resolve<clazz>().custom()), 'c');
|
||||
ASSERT_EQ(static_cast<const char &>(entt::resolve<clazz>().custom()), 'c');
|
||||
|
||||
ASSERT_EQ(static_cast<const int *>(entt::resolve<clazz>().custom()), nullptr);
|
||||
ASSERT_EQ(static_cast<const char *>(entt::resolve<int>().custom()), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(MetaCustom, Data) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const clazz instance{};
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("i"_hs));
|
||||
ASSERT_EQ(entt::resolve<clazz>().get("i"_hs, instance).cast<int>(), 2);
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("j"_hs));
|
||||
ASSERT_EQ(entt::resolve<clazz>().get("j"_hs, instance).cast<char>(), 'c');
|
||||
|
||||
ASSERT_NE(static_cast<const int *>(entt::resolve<clazz>().data("i"_hs).custom()), nullptr);
|
||||
ASSERT_EQ(*static_cast<const int *>(entt::resolve<clazz>().data("i"_hs).custom()), 0);
|
||||
ASSERT_EQ(static_cast<const int &>(entt::resolve<clazz>().data("i"_hs).custom()), 0);
|
||||
|
||||
ASSERT_EQ(static_cast<const char *>(entt::resolve<clazz>().data("i"_hs).custom()), nullptr);
|
||||
ASSERT_EQ(static_cast<const int *>(entt::resolve<clazz>().data("j"_hs).custom()), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(MetaCustom, Func) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const clazz instance{};
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz>().func("f"_hs));
|
||||
ASSERT_EQ(entt::resolve<clazz>().invoke("f"_hs, instance, 0).cast<int>(), 2);
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz>().func("g"_hs));
|
||||
ASSERT_EQ(entt::resolve<clazz>().invoke("g"_hs, instance, 'c').cast<char>(), 'c');
|
||||
|
||||
ASSERT_NE(static_cast<const int *>(entt::resolve<clazz>().func("f"_hs).custom()), nullptr);
|
||||
ASSERT_EQ(*static_cast<const int *>(entt::resolve<clazz>().func("f"_hs).custom()), 1);
|
||||
ASSERT_EQ(static_cast<const int &>(entt::resolve<clazz>().func("f"_hs).custom()), 1);
|
||||
|
||||
ASSERT_EQ(static_cast<const char *>(entt::resolve<clazz>().func("f"_hs).custom()), nullptr);
|
||||
ASSERT_EQ(static_cast<const int *>(entt::resolve<clazz>().func("g"_hs).custom()), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(MetaCustom, ConstNonConstAndAllInBetween) {
|
||||
testing::StaticAssertTypeEq<decltype(static_cast<int *>(entt::meta_custom{})), int *>();
|
||||
testing::StaticAssertTypeEq<decltype(static_cast<int &>(entt::meta_custom{})), int &>();
|
||||
testing::StaticAssertTypeEq<decltype(static_cast<const int *>(entt::meta_custom{})), const int *>();
|
||||
testing::StaticAssertTypeEq<decltype(static_cast<const int &>(entt::meta_custom{})), const int &>();
|
||||
|
||||
static_cast<char &>(entt::resolve<clazz>().custom()) = '\n';
|
||||
|
||||
ASSERT_EQ(*static_cast<const char *>(entt::resolve<clazz>().custom()), '\n');
|
||||
}
|
||||
|
||||
TEST_F(MetaCustom, ReRegistration) {
|
||||
using namespace entt::literals;
|
||||
|
||||
SetUp();
|
||||
|
||||
auto type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_EQ(static_cast<const int *>(type.custom()), nullptr);
|
||||
ASSERT_NE(static_cast<const char *>(type.custom()), nullptr);
|
||||
ASSERT_EQ(*static_cast<const char *>(type.custom()), 'c');
|
||||
|
||||
entt::meta_factory<clazz>{}.custom<int>(1);
|
||||
type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_NE(static_cast<const int *>(type.custom()), nullptr);
|
||||
ASSERT_EQ(static_cast<const char *>(type.custom()), nullptr);
|
||||
ASSERT_EQ(*static_cast<const int *>(type.custom()), 1);
|
||||
}
|
||||
707
lib/All/entt/test/entt/meta/meta_data.cpp
Normal file
707
lib/All/entt/test/entt/meta/meta_data.cpp
Normal file
@@ -0,0 +1,707 @@
|
||||
#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/context.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/node.hpp>
|
||||
#include <entt/meta/policy.hpp>
|
||||
#include <entt/meta/range.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/meta_traits.h"
|
||||
|
||||
struct base {
|
||||
virtual ~base() = default;
|
||||
|
||||
static void destroy(base &) {
|
||||
++counter;
|
||||
}
|
||||
|
||||
inline static int counter = 0; // NOLINT
|
||||
int value{3};
|
||||
};
|
||||
|
||||
struct derived: base {
|
||||
derived() = default;
|
||||
};
|
||||
|
||||
struct clazz {
|
||||
operator int() const {
|
||||
return h;
|
||||
}
|
||||
|
||||
int i{0};
|
||||
const int j{1}; // NOLINT
|
||||
base instance{};
|
||||
inline static int h{2}; // NOLINT
|
||||
inline static const int k{3}; // NOLINT
|
||||
};
|
||||
|
||||
struct setter_getter {
|
||||
int setter(double val) {
|
||||
return value = static_cast<int>(val);
|
||||
}
|
||||
|
||||
[[nodiscard]] int getter() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
int setter_with_ref(const int &val) {
|
||||
return value = val;
|
||||
}
|
||||
|
||||
[[nodiscard]] const int &getter_with_ref() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
static int static_setter(setter_getter &type, int value) {
|
||||
return type.value = value;
|
||||
}
|
||||
|
||||
static int static_getter(const setter_getter &type) {
|
||||
return type.value;
|
||||
}
|
||||
|
||||
int value{0};
|
||||
};
|
||||
|
||||
struct multi_setter {
|
||||
void from_double(double val) {
|
||||
value = static_cast<int>(val);
|
||||
}
|
||||
|
||||
void from_string(const char *val) {
|
||||
value = std::atoi(val);
|
||||
}
|
||||
|
||||
int value{0};
|
||||
};
|
||||
|
||||
struct array {
|
||||
inline static int global[2]; // NOLINT
|
||||
int local[4]; // NOLINT
|
||||
};
|
||||
|
||||
struct MetaData: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<base>{}
|
||||
.type("base"_hs)
|
||||
.dtor<base::destroy>()
|
||||
.data<&base::value>("value"_hs);
|
||||
|
||||
entt::meta_factory<derived>{}
|
||||
.type("derived"_hs)
|
||||
.base<base>()
|
||||
.dtor<derived::destroy>()
|
||||
.data<&base::value>("value_from_base"_hs);
|
||||
|
||||
entt::meta_factory<clazz>{}
|
||||
.type("clazz"_hs)
|
||||
.data<&clazz::i, entt::as_ref_t>("i"_hs)
|
||||
.custom<char>('c')
|
||||
.traits(test::meta_traits::one | test::meta_traits::two | test::meta_traits::three)
|
||||
.data<&clazz::i, entt::as_cref_t>("ci"_hs)
|
||||
.data<&clazz::j>("j"_hs)
|
||||
.traits(test::meta_traits::one)
|
||||
.data<&clazz::h>("h"_hs)
|
||||
.traits(test::meta_traits::two)
|
||||
.data<&clazz::k>("k"_hs)
|
||||
.traits(test::meta_traits::three)
|
||||
.data<'c'>("l"_hs)
|
||||
.data<&clazz::instance>("base"_hs)
|
||||
.data<&clazz::i, entt::as_void_t>("void"_hs)
|
||||
.conv<int>();
|
||||
|
||||
entt::meta_factory<setter_getter>{}
|
||||
.type("setter_getter"_hs)
|
||||
.data<&setter_getter::static_setter, &setter_getter::static_getter>("x"_hs)
|
||||
.data<&setter_getter::setter, &setter_getter::getter>("y"_hs)
|
||||
.data<&setter_getter::static_setter, &setter_getter::getter>("z"_hs)
|
||||
.data<&setter_getter::setter_with_ref, &setter_getter::getter_with_ref>("w"_hs)
|
||||
.data<nullptr, &setter_getter::getter>("z_ro"_hs)
|
||||
.data<nullptr, &setter_getter::value>("value"_hs);
|
||||
|
||||
entt::meta_factory<multi_setter>{}
|
||||
.type("multi_setter"_hs)
|
||||
.data<entt::value_list<&multi_setter::from_double, &multi_setter::from_string>, &multi_setter::value>("value"_hs);
|
||||
|
||||
entt::meta_factory<array>{}
|
||||
.type("array"_hs)
|
||||
.data<&array::global>("global"_hs)
|
||||
.data<&array::local>("local"_hs);
|
||||
|
||||
base::counter = 0;
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
using MetaDataDeathTest = MetaData;
|
||||
|
||||
TEST_F(MetaData, SafeWhenEmpty) {
|
||||
const entt::meta_data data{};
|
||||
|
||||
ASSERT_FALSE(data);
|
||||
ASSERT_EQ(data, entt::meta_data{});
|
||||
ASSERT_EQ(data.arity(), 0u);
|
||||
ASSERT_FALSE(data.is_const());
|
||||
ASSERT_FALSE(data.is_static());
|
||||
ASSERT_EQ(data.type(), entt::meta_type{});
|
||||
ASSERT_FALSE(data.set({}, 0));
|
||||
ASSERT_FALSE(data.get({}));
|
||||
ASSERT_EQ(data.arg(0u), entt::meta_type{});
|
||||
ASSERT_EQ(data.traits<test::meta_traits>(), test::meta_traits::none);
|
||||
ASSERT_EQ(static_cast<const char *>(data.custom()), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, UserTraits) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_EQ(entt::resolve<clazz>().data("ci"_hs).traits<test::meta_traits>(), test::meta_traits::none);
|
||||
ASSERT_EQ(entt::resolve<clazz>().data("base"_hs).traits<test::meta_traits>(), test::meta_traits::none);
|
||||
|
||||
ASSERT_EQ(entt::resolve<clazz>().data("i"_hs).traits<test::meta_traits>(), test::meta_traits::one | test::meta_traits::two | test::meta_traits::three);
|
||||
ASSERT_EQ(entt::resolve<clazz>().data("j"_hs).traits<test::meta_traits>(), test::meta_traits::one);
|
||||
ASSERT_EQ(entt::resolve<clazz>().data("h"_hs).traits<test::meta_traits>(), test::meta_traits::two);
|
||||
ASSERT_EQ(entt::resolve<clazz>().data("k"_hs).traits<test::meta_traits>(), test::meta_traits::three);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaDataDeathTest, UserTraits) {
|
||||
using namespace entt::literals;
|
||||
|
||||
using traits_type = entt::internal::meta_traits;
|
||||
constexpr auto value = traits_type{static_cast<std::underlying_type_t<traits_type>>(traits_type::_user_defined_traits) + 1u};
|
||||
ASSERT_DEATH(entt::meta_factory<clazz>{}.data<&clazz::i>("j"_hs).traits(value), "");
|
||||
}
|
||||
|
||||
TEST_F(MetaData, Custom) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_EQ(*static_cast<const char *>(entt::resolve<clazz>().data("i"_hs).custom()), 'c');
|
||||
ASSERT_EQ(static_cast<const char &>(entt::resolve<clazz>().data("i"_hs).custom()), 'c');
|
||||
|
||||
ASSERT_EQ(static_cast<const int *>(entt::resolve<clazz>().data("i"_hs).custom()), nullptr);
|
||||
ASSERT_EQ(static_cast<const int *>(entt::resolve<clazz>().data("j"_hs).custom()), nullptr);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaDataDeathTest, Custom) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const int value = entt::resolve<clazz>().data("i"_hs).custom(), "");
|
||||
ASSERT_DEATH([[maybe_unused]] const char value = entt::resolve<clazz>().data("j"_hs).custom(), "");
|
||||
}
|
||||
|
||||
TEST_F(MetaData, Comparison) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<clazz>().data("i"_hs);
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
|
||||
ASSERT_EQ(data, data);
|
||||
ASSERT_NE(data, entt::meta_data{});
|
||||
ASSERT_FALSE(data != data);
|
||||
ASSERT_TRUE(data == data);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, NonConst) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<clazz>().data("i"_hs);
|
||||
clazz 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, 1));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, Const) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<clazz>().data("j"_hs);
|
||||
clazz 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, 1));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, Static) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<clazz>().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({}, 1));
|
||||
ASSERT_EQ(data.get({}).cast<int>(), 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, ConstStatic) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<clazz>().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({}, 1));
|
||||
ASSERT_EQ(data.get({}).cast<int>(), 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, Literal) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<clazz>().data("l"_hs);
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
ASSERT_EQ(data.type(), entt::resolve<char>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<char>());
|
||||
ASSERT_TRUE(data.is_const());
|
||||
ASSERT_TRUE(data.is_static());
|
||||
ASSERT_EQ(data.get({}).cast<char>(), 'c');
|
||||
ASSERT_FALSE(data.set({}, 'a'));
|
||||
ASSERT_EQ(data.get({}).cast<char>(), 'c');
|
||||
}
|
||||
|
||||
TEST_F(MetaData, GetMetaAnyArg) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_any any{clazz{}};
|
||||
any.cast<clazz &>().i = 3;
|
||||
const auto value = entt::resolve<clazz>().data("i"_hs).get(any);
|
||||
|
||||
ASSERT_TRUE(value);
|
||||
ASSERT_TRUE(static_cast<bool>(value.cast<int>()));
|
||||
ASSERT_EQ(value.cast<int>(), 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, GetInvalidArg) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto instance = 0;
|
||||
ASSERT_FALSE(entt::resolve<clazz>().data("i"_hs).get(instance));
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetMetaAnyArg) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_any any{clazz{}};
|
||||
const entt::meta_any value{1};
|
||||
|
||||
ASSERT_EQ(any.cast<clazz>().i, 0);
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("i"_hs).set(any, value));
|
||||
ASSERT_EQ(any.cast<clazz>().i, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetInvalidArg) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_FALSE(entt::resolve<clazz>().data("i"_hs).set({}, 'c'));
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetCast) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz instance{};
|
||||
|
||||
ASSERT_EQ(base::counter, 0);
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("base"_hs).set(instance, derived{}));
|
||||
ASSERT_EQ(base::counter, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetConvert) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz instance{};
|
||||
clazz::h = 1;
|
||||
|
||||
ASSERT_EQ(instance.i, 0);
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("i"_hs).set(instance, instance));
|
||||
ASSERT_EQ(instance.i, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetByRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_any any{clazz{}};
|
||||
int value{1};
|
||||
|
||||
ASSERT_EQ(any.cast<clazz>().i, 0);
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("i"_hs).set(any, entt::forward_as_meta(value)));
|
||||
ASSERT_EQ(any.cast<clazz>().i, 1);
|
||||
|
||||
value = 3;
|
||||
auto wrapper = entt::forward_as_meta(value);
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("i"_hs).set(any, wrapper.as_ref()));
|
||||
ASSERT_EQ(any.cast<clazz>().i, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetByConstRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_any any{clazz{}};
|
||||
int value{1};
|
||||
|
||||
ASSERT_EQ(any.cast<clazz>().i, 0);
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("i"_hs).set(any, entt::forward_as_meta(std::as_const(value))));
|
||||
ASSERT_EQ(any.cast<clazz>().i, 1);
|
||||
|
||||
value = 3;
|
||||
auto wrapper = entt::forward_as_meta(std::as_const(value));
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("i"_hs).set(any, wrapper.as_ref()));
|
||||
ASSERT_EQ(any.cast<clazz>().i, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetterGetterAsFreeFunctions) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<setter_getter>().data("x"_hs);
|
||||
setter_getter 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, 1));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetterGetterAsMemberFunctions) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<setter_getter>().data("y"_hs);
|
||||
setter_getter 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, 1.));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 1);
|
||||
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>().data("w"_hs);
|
||||
setter_getter 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, 1));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetterGetterMixed) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<setter_getter>().data("z"_hs);
|
||||
setter_getter 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, 1));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetterGetterReadOnly) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<setter_getter>().data("z_ro"_hs);
|
||||
setter_getter 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, 1));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 0);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetterGetterReadOnlyDataMember) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<setter_getter>().data("value"_hs);
|
||||
setter_getter 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, 1));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 0);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, MultiSetter) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<multi_setter>().data("value"_hs);
|
||||
multi_setter 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, 1));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 1);
|
||||
ASSERT_TRUE(data.set(instance, 2.));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 2);
|
||||
ASSERT_FALSE(data.set(instance, std::string{"3"}));
|
||||
ASSERT_TRUE(data.set(instance, std::string{"3"}.c_str()));
|
||||
ASSERT_EQ(data.get(instance).cast<int>(), 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, ConstInstance) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz instance{};
|
||||
|
||||
ASSERT_NE(entt::resolve<clazz>().data("i"_hs).get(instance).try_cast<int>(), nullptr);
|
||||
ASSERT_NE(entt::resolve<clazz>().data("i"_hs).get(instance).try_cast<const int>(), nullptr);
|
||||
ASSERT_EQ(entt::resolve<clazz>().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>().data("i"_hs).get(std::as_const(instance)).try_cast<const int>(), nullptr);
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("i"_hs).get(instance));
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("i"_hs).set(instance, 3));
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("i"_hs).get(std::as_const(instance)));
|
||||
ASSERT_FALSE(entt::resolve<clazz>().data("i"_hs).set(std::as_const(instance), 3));
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("ci"_hs).get(instance));
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("ci"_hs).set(instance, 3));
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("ci"_hs).get(std::as_const(instance)));
|
||||
ASSERT_FALSE(entt::resolve<clazz>().data("ci"_hs).set(std::as_const(instance), 3));
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("j"_hs).get(instance));
|
||||
ASSERT_FALSE(entt::resolve<clazz>().data("j"_hs).set(instance, 3));
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("j"_hs).get(std::as_const(instance)));
|
||||
ASSERT_FALSE(entt::resolve<clazz>().data("j"_hs).set(std::as_const(instance), 3));
|
||||
}
|
||||
|
||||
TEST_F(MetaData, ArrayStatic) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto data = entt::resolve<array>().data("global"_hs);
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
// NOLINTBEGIN(*-avoid-c-arrays)
|
||||
ASSERT_EQ(data.type(), entt::resolve<int[2]>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int[2]>());
|
||||
// NOLINTEND(*-avoid-c-arrays)
|
||||
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>().data("local"_hs);
|
||||
array instance{};
|
||||
|
||||
ASSERT_TRUE(data);
|
||||
ASSERT_EQ(data.arity(), 1u);
|
||||
// NOLINTBEGIN(*-avoid-c-arrays)
|
||||
ASSERT_EQ(data.type(), entt::resolve<int[4]>());
|
||||
ASSERT_EQ(data.arg(0u), entt::resolve<int[4]>());
|
||||
// NOLINTEND(*-avoid-c-arrays)
|
||||
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>().data("void"_hs);
|
||||
clazz 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, 1));
|
||||
ASSERT_EQ(instance.i, 1);
|
||||
ASSERT_EQ(data.get(instance), entt::meta_any{std::in_place_type<void>});
|
||||
}
|
||||
|
||||
TEST_F(MetaData, AsRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz instance{};
|
||||
auto data = entt::resolve<clazz>().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_EQ(instance.i, 0);
|
||||
|
||||
data.get(instance).cast<int &>() = 3;
|
||||
|
||||
ASSERT_EQ(instance.i, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, AsConstRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz instance{};
|
||||
auto data = entt::resolve<clazz>().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(instance.i, 0);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaDataDeathTest, AsConstRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz instance{};
|
||||
auto data = entt::resolve<clazz>().data("ci"_hs);
|
||||
|
||||
ASSERT_DEATH(data.get(instance).cast<int &>() = 3, "");
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetGetBaseData) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<derived>();
|
||||
derived instance{};
|
||||
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
ASSERT_TRUE(type.data("value"_hs).set(instance, 1));
|
||||
ASSERT_EQ(type.data("value"_hs).get(instance).cast<int>(), 1);
|
||||
ASSERT_EQ(instance.value, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, SetGetFromBase) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<derived>();
|
||||
derived instance{};
|
||||
|
||||
ASSERT_TRUE(type.data("value_from_base"_hs));
|
||||
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
ASSERT_TRUE(type.data("value_from_base"_hs).set(instance, 1));
|
||||
ASSERT_EQ(type.data("value_from_base"_hs).get(instance).cast<int>(), 1);
|
||||
ASSERT_EQ(instance.value, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, ReRegistration) {
|
||||
using namespace entt::literals;
|
||||
|
||||
SetUp();
|
||||
|
||||
auto &&node = entt::internal::resolve<base>(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()));
|
||||
auto type = entt::resolve<base>();
|
||||
|
||||
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_factory<base>{}.data<&base::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));
|
||||
|
||||
entt::meta_factory<base>{}
|
||||
.data<&base::value>("field"_hs)
|
||||
.traits(test::meta_traits::one)
|
||||
.custom<int>(3)
|
||||
// this should not overwrite traits and custom data
|
||||
.data<&base::value>("field"_hs);
|
||||
|
||||
ASSERT_EQ(type.data("field"_hs).traits<test::meta_traits>(), test::meta_traits::one);
|
||||
ASSERT_NE(static_cast<const int *>(type.data("field"_hs).custom()), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(MetaData, CollisionAndReuse) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("j"_hs));
|
||||
ASSERT_FALSE(entt::resolve<clazz>().data("cj"_hs));
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("j"_hs).is_const());
|
||||
|
||||
ASSERT_NO_THROW(entt::meta_factory<clazz>{}.data<&clazz::i>("j"_hs));
|
||||
ASSERT_NO_THROW(entt::meta_factory<clazz>{}.data<&clazz::j>("cj"_hs));
|
||||
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("j"_hs));
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("cj"_hs));
|
||||
ASSERT_FALSE(entt::resolve<clazz>().data("j"_hs).is_const());
|
||||
}
|
||||
115
lib/All/entt/test/entt/meta/meta_dtor.cpp
Normal file
115
lib/All/entt/test/entt/meta/meta_dtor.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/locator/locator.hpp>
|
||||
#include <entt/meta/context.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/node.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
|
||||
struct clazz {
|
||||
clazz(int &cnt)
|
||||
: counter{&cnt} {
|
||||
++(*counter);
|
||||
}
|
||||
|
||||
static void destroy_decr(clazz &instance) {
|
||||
--(*instance.counter);
|
||||
}
|
||||
|
||||
void destroy_incr() const {
|
||||
++(*counter);
|
||||
}
|
||||
|
||||
int *counter;
|
||||
};
|
||||
|
||||
struct MetaDtor: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<clazz>{}
|
||||
.type("clazz"_hs)
|
||||
.ctor<int &>()
|
||||
.dtor<clazz::destroy_decr>();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(MetaDtor, Dtor) {
|
||||
int counter{};
|
||||
|
||||
auto any = entt::resolve<clazz>().construct(entt::forward_as_meta(counter));
|
||||
auto cref = std::as_const(any).as_ref();
|
||||
auto ref = any.as_ref();
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(cref);
|
||||
ASSERT_TRUE(ref);
|
||||
|
||||
ASSERT_EQ(counter, 1);
|
||||
|
||||
cref.reset();
|
||||
ref.reset();
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(cref);
|
||||
ASSERT_FALSE(ref);
|
||||
|
||||
ASSERT_EQ(counter, 1);
|
||||
|
||||
any.reset();
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_FALSE(cref);
|
||||
ASSERT_FALSE(ref);
|
||||
|
||||
ASSERT_EQ(counter, 0);
|
||||
}
|
||||
|
||||
TEST_F(MetaDtor, AsRefConstruction) {
|
||||
int counter{};
|
||||
|
||||
clazz instance{counter};
|
||||
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(counter, 1);
|
||||
|
||||
any.reset();
|
||||
cany.reset();
|
||||
cref.reset();
|
||||
ref.reset();
|
||||
|
||||
ASSERT_FALSE(any);
|
||||
ASSERT_FALSE(cany);
|
||||
ASSERT_FALSE(cref);
|
||||
ASSERT_FALSE(ref);
|
||||
|
||||
ASSERT_EQ(counter, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaDtor, ReRegistration) {
|
||||
SetUp();
|
||||
|
||||
int counter{};
|
||||
auto &&node = entt::internal::resolve<clazz>(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()));
|
||||
|
||||
ASSERT_NE(node.dtor.dtor, nullptr);
|
||||
|
||||
entt::meta_factory<clazz>{}.dtor<&clazz::destroy_incr>();
|
||||
entt::resolve<clazz>().construct(entt::forward_as_meta(counter)).reset();
|
||||
|
||||
ASSERT_EQ(counter, 2);
|
||||
}
|
||||
509
lib/All/entt/test/entt/meta/meta_factory.cpp
Normal file
509
lib/All/entt/test/entt/meta/meta_factory.cpp
Normal file
@@ -0,0 +1,509 @@
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/meta/context.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/range.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include "../../common/boxed_type.h"
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/meta_traits.h"
|
||||
|
||||
struct base {
|
||||
char member{};
|
||||
};
|
||||
|
||||
struct clazz: base {
|
||||
clazz(int val)
|
||||
: value{val} {}
|
||||
|
||||
[[nodiscard]] explicit operator int() const noexcept {
|
||||
return get_int();
|
||||
}
|
||||
|
||||
void set_int(int val) noexcept {
|
||||
value = val;
|
||||
}
|
||||
|
||||
void set_boxed_int(test::boxed_int val) noexcept {
|
||||
value = val.value;
|
||||
}
|
||||
|
||||
[[nodiscard]] int get_int() const noexcept {
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::string to_string(const clazz &instance) {
|
||||
return std::to_string(instance.get_int());
|
||||
}
|
||||
|
||||
[[nodiscard]] static clazz from_string(const std::string &value) {
|
||||
return clazz{std::stoi(value)};
|
||||
}
|
||||
|
||||
private:
|
||||
int value{};
|
||||
};
|
||||
|
||||
struct dtor_callback {
|
||||
dtor_callback(bool &ref)
|
||||
: cb{&ref} {}
|
||||
|
||||
static void on_destroy(dtor_callback &instance) {
|
||||
*instance.cb = !*instance.cb;
|
||||
}
|
||||
|
||||
private:
|
||||
bool *cb;
|
||||
};
|
||||
|
||||
struct MetaFactory: ::testing::Test {
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
using MetaFactoryDeathTest = MetaFactory;
|
||||
|
||||
TEST_F(MetaFactory, Constructors) {
|
||||
entt::meta_ctx ctx{};
|
||||
|
||||
ASSERT_EQ(entt::resolve(entt::type_id<int>()), entt::meta_type{});
|
||||
ASSERT_EQ(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
|
||||
|
||||
entt::meta_factory<int> factory{};
|
||||
|
||||
ASSERT_NE(entt::resolve(entt::type_id<int>()), entt::meta_type{});
|
||||
ASSERT_EQ(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
|
||||
ASSERT_TRUE(entt::resolve(entt::type_id<int>()).is_integral());
|
||||
|
||||
factory = entt::meta_factory<int>{ctx};
|
||||
|
||||
ASSERT_NE(entt::resolve(entt::type_id<int>()), entt::meta_type{});
|
||||
ASSERT_NE(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
|
||||
ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()).is_integral());
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, Type) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<int> factory{};
|
||||
|
||||
ASSERT_EQ(entt::resolve("foo"_hs), entt::meta_type{});
|
||||
|
||||
factory.type("foo"_hs);
|
||||
|
||||
ASSERT_NE(entt::resolve("foo"_hs), entt::meta_type{});
|
||||
ASSERT_EQ(entt::resolve<int>().id(), "foo"_hs);
|
||||
|
||||
factory.type("bar"_hs);
|
||||
|
||||
ASSERT_EQ(entt::resolve("foo"_hs), entt::meta_type{});
|
||||
ASSERT_NE(entt::resolve("bar"_hs), entt::meta_type{});
|
||||
ASSERT_EQ(entt::resolve<int>().id(), "bar"_hs);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaFactoryDeathTest, Type) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<int> factory{};
|
||||
entt::meta_factory<double> other{};
|
||||
|
||||
factory.type("foo"_hs);
|
||||
|
||||
ASSERT_DEATH(other.type("foo"_hs);, "");
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, Base) {
|
||||
entt::meta_factory<clazz> factory{};
|
||||
decltype(std::declval<entt::meta_type>().base()) range{};
|
||||
|
||||
ASSERT_NE(entt::resolve(entt::type_id<clazz>()), entt::meta_type{});
|
||||
ASSERT_EQ(entt::resolve(entt::type_id<base>()), entt::meta_type{});
|
||||
|
||||
range = entt::resolve<clazz>().base();
|
||||
|
||||
ASSERT_EQ(range.begin(), range.end());
|
||||
|
||||
factory.base<base>();
|
||||
range = entt::resolve<clazz>().base();
|
||||
|
||||
ASSERT_EQ(entt::resolve(entt::type_id<base>()), entt::meta_type{});
|
||||
ASSERT_NE(range.begin(), range.end());
|
||||
ASSERT_EQ(std::distance(range.begin(), range.end()), 1);
|
||||
ASSERT_EQ(range.begin()->first, entt::type_id<base>().hash());
|
||||
ASSERT_EQ(range.begin()->second.info(), entt::type_id<base>());
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, Conv) {
|
||||
const clazz instance{3};
|
||||
entt::meta_factory<clazz> factory{};
|
||||
const entt::meta_any any = entt::forward_as_meta(instance);
|
||||
|
||||
ASSERT_FALSE(any.allow_cast<int>());
|
||||
ASSERT_FALSE(any.allow_cast<std::string>());
|
||||
|
||||
factory.conv<int>().conv<&clazz::to_string>();
|
||||
|
||||
ASSERT_TRUE(any.allow_cast<int>());
|
||||
ASSERT_TRUE(any.allow_cast<std::string>());
|
||||
ASSERT_EQ(any.allow_cast<int>().cast<int>(), instance.get_int());
|
||||
ASSERT_EQ(any.allow_cast<std::string>().cast<std::string>(), clazz::to_string(instance));
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, Ctor) {
|
||||
const std::array values{1, 3};
|
||||
entt::meta_factory<clazz> factory{};
|
||||
|
||||
ASSERT_FALSE(entt::resolve<clazz>().construct(values[0u]));
|
||||
ASSERT_FALSE(entt::resolve<clazz>().construct(std::to_string(values[1u])));
|
||||
|
||||
factory.ctor<int>().ctor<&clazz::from_string>();
|
||||
|
||||
const auto instance = entt::resolve<clazz>().construct(values[0u]);
|
||||
const auto other = entt::resolve<clazz>().construct(std::to_string(values[1u]));
|
||||
|
||||
ASSERT_TRUE(instance);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_TRUE(instance.allow_cast<clazz>());
|
||||
ASSERT_TRUE(other.allow_cast<clazz>());
|
||||
ASSERT_EQ(instance.cast<const clazz &>().get_int(), values[0u]);
|
||||
ASSERT_EQ(other.cast<const clazz &>().get_int(), values[1u]);
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, Dtor) {
|
||||
bool check = false;
|
||||
entt::meta_factory<dtor_callback> factory{};
|
||||
entt::meta_any any{std::in_place_type<dtor_callback>, check};
|
||||
|
||||
any.reset();
|
||||
|
||||
ASSERT_FALSE(check);
|
||||
|
||||
factory.dtor<&dtor_callback::on_destroy>();
|
||||
any.emplace<dtor_callback>(check);
|
||||
any.reset();
|
||||
|
||||
ASSERT_TRUE(check);
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, DataMemberObject) {
|
||||
using namespace entt::literals;
|
||||
|
||||
base instance{'c'};
|
||||
entt::meta_factory<base> factory{};
|
||||
entt::meta_type type = entt::resolve<base>();
|
||||
|
||||
ASSERT_FALSE(type.data("member"_hs));
|
||||
|
||||
factory.data<&base::member>("member"_hs);
|
||||
type = entt::resolve<base>();
|
||||
|
||||
ASSERT_TRUE(type.data("member"_hs));
|
||||
ASSERT_EQ(type.get("member"_hs, std::as_const(instance)), instance.member);
|
||||
ASSERT_EQ(type.get("member"_hs, instance), instance.member);
|
||||
ASSERT_FALSE(type.set("member"_hs, std::as_const(instance), instance.member));
|
||||
ASSERT_TRUE(type.set("member"_hs, instance, instance.member));
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, DataPointer) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<int> factory{};
|
||||
entt::meta_type type = entt::resolve<int>();
|
||||
|
||||
ASSERT_FALSE(type.data("value"_hs));
|
||||
|
||||
static int value = 1;
|
||||
factory.data<&value>("value"_hs);
|
||||
type = entt::resolve<int>();
|
||||
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
ASSERT_EQ(type.get("value"_hs, {}), value);
|
||||
ASSERT_TRUE(type.set("value"_hs, {}, value));
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, DataValue) {
|
||||
using namespace entt::literals;
|
||||
|
||||
constexpr int value = 1;
|
||||
entt::meta_factory<int> factory{};
|
||||
entt::meta_type type = entt::resolve<int>();
|
||||
|
||||
ASSERT_FALSE(type.data("value"_hs));
|
||||
|
||||
factory.data<value>("value"_hs);
|
||||
type = entt::resolve<int>();
|
||||
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
ASSERT_EQ(type.get("value"_hs, {}), value);
|
||||
ASSERT_FALSE(type.set("value"_hs, {}, value));
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, DataGetterOnly) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz instance{1};
|
||||
entt::meta_factory<clazz> factory{};
|
||||
entt::meta_type type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_FALSE(type.data("value"_hs));
|
||||
|
||||
factory.data<nullptr, &clazz::get_int>("value"_hs);
|
||||
type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
ASSERT_EQ(type.get("value"_hs, std::as_const(instance)), instance.get_int());
|
||||
ASSERT_EQ(type.get("value"_hs, instance), instance.get_int());
|
||||
ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), instance.get_int()));
|
||||
ASSERT_FALSE(type.set("value"_hs, instance, instance.get_int()));
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, DataSetterGetter) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz instance{1};
|
||||
entt::meta_factory<clazz> factory{};
|
||||
entt::meta_type type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_FALSE(type.data("value"_hs));
|
||||
|
||||
factory.data<&clazz::set_int, &clazz::get_int>("value"_hs);
|
||||
type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
ASSERT_EQ(type.get("value"_hs, std::as_const(instance)), instance.get_int());
|
||||
ASSERT_EQ(type.get("value"_hs, instance), instance.get_int());
|
||||
ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), instance.get_int()));
|
||||
ASSERT_TRUE(type.set("value"_hs, instance, instance.get_int()));
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, DataMultiSetterGetter) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz instance{1};
|
||||
entt::meta_factory<clazz> factory{};
|
||||
entt::meta_type type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_FALSE(type.data("value"_hs));
|
||||
|
||||
factory.data<entt::value_list<&clazz::set_int, &clazz::set_boxed_int>, &clazz::get_int>("value"_hs);
|
||||
type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
ASSERT_EQ(type.get("value"_hs, std::as_const(instance)), instance.get_int());
|
||||
ASSERT_EQ(type.get("value"_hs, instance), instance.get_int());
|
||||
ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), instance.get_int()));
|
||||
ASSERT_TRUE(type.set("value"_hs, instance, instance.get_int()));
|
||||
ASSERT_FALSE(type.set("value"_hs, std::as_const(instance), test::boxed_int{instance.get_int()}));
|
||||
ASSERT_TRUE(type.set("value"_hs, instance, test::boxed_int{instance.get_int()}));
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, DataOverwrite) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<clazz> factory{};
|
||||
entt::meta_type type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_FALSE(type.data("value"_hs));
|
||||
|
||||
factory.data<nullptr, &clazz::get_int>("value"_hs);
|
||||
type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
ASSERT_TRUE(type.data("value"_hs).is_const());
|
||||
|
||||
factory.data<&clazz::set_int, &clazz::get_int>("value"_hs);
|
||||
type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
ASSERT_FALSE(type.data("value"_hs).is_const());
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, Func) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const clazz instance{1};
|
||||
entt::meta_factory<clazz> factory{};
|
||||
entt::meta_type type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_FALSE(type.func("func"_hs));
|
||||
|
||||
factory.func<&clazz::get_int>("func"_hs);
|
||||
type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_TRUE(type.func("func"_hs));
|
||||
ASSERT_TRUE(type.invoke("func"_hs, instance));
|
||||
ASSERT_EQ(type.invoke("func"_hs, instance).cast<int>(), instance.get_int());
|
||||
ASSERT_FALSE(type.invoke("func"_hs, {}));
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, FuncOverload) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz instance{1};
|
||||
entt::meta_factory<clazz> factory{};
|
||||
const entt::meta_type type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_FALSE(type.func("func"_hs));
|
||||
|
||||
factory.func<&clazz::set_int>("func"_hs);
|
||||
|
||||
ASSERT_TRUE(type.func("func"_hs));
|
||||
ASSERT_FALSE(type.func("func"_hs).next());
|
||||
|
||||
factory.func<&clazz::set_boxed_int>("func"_hs);
|
||||
|
||||
ASSERT_TRUE(type.func("func"_hs));
|
||||
ASSERT_TRUE(type.func("func"_hs).next());
|
||||
ASSERT_FALSE(type.func("func"_hs).next().next());
|
||||
|
||||
ASSERT_TRUE(type.invoke("func"_hs, instance, 2));
|
||||
ASSERT_EQ(instance.get_int(), 2);
|
||||
|
||||
ASSERT_TRUE(type.invoke("func"_hs, instance, test::boxed_int{3}));
|
||||
ASSERT_EQ(instance.get_int(), 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, Traits) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<clazz>{}
|
||||
.data<&base::member>("member"_hs)
|
||||
.func<&clazz::set_int>("func"_hs)
|
||||
.func<&clazz::set_boxed_int>("func"_hs);
|
||||
|
||||
entt::meta_type type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_EQ(type.traits<test::meta_traits>(), test::meta_traits::none);
|
||||
ASSERT_EQ(type.data("member"_hs).traits<test::meta_traits>(), test::meta_traits::none);
|
||||
ASSERT_EQ(type.func("func"_hs).traits<test::meta_traits>(), test::meta_traits::none);
|
||||
ASSERT_EQ(type.func("func"_hs).next().traits<test::meta_traits>(), test::meta_traits::none);
|
||||
|
||||
entt::meta_factory<clazz>{}
|
||||
.traits(test::meta_traits::one | test::meta_traits::three)
|
||||
.data<&base::member>("member"_hs)
|
||||
.traits(test::meta_traits::one)
|
||||
.func<&clazz::set_int>("func"_hs)
|
||||
.traits(test::meta_traits::two)
|
||||
.func<&clazz::set_boxed_int>("func"_hs)
|
||||
.traits(test::meta_traits::three);
|
||||
|
||||
// traits are copied and never refreshed
|
||||
type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_EQ(type.traits<test::meta_traits>(), test::meta_traits::one | test::meta_traits::three);
|
||||
ASSERT_EQ(type.data("member"_hs).traits<test::meta_traits>(), test::meta_traits::one);
|
||||
ASSERT_EQ(type.func("func"_hs).traits<test::meta_traits>(), test::meta_traits::two);
|
||||
ASSERT_EQ(type.func("func"_hs).next().traits<test::meta_traits>(), test::meta_traits::three);
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, Custom) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<clazz>{}
|
||||
.data<&base::member>("member"_hs)
|
||||
.func<&clazz::set_int>("func"_hs)
|
||||
.func<&clazz::set_boxed_int>("func"_hs);
|
||||
|
||||
entt::meta_type type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_EQ(static_cast<const int *>(type.custom()), nullptr);
|
||||
ASSERT_EQ(static_cast<const int *>(type.data("member"_hs).custom()), nullptr);
|
||||
ASSERT_EQ(static_cast<const int *>(type.func("func"_hs).custom()), nullptr);
|
||||
ASSERT_EQ(static_cast<const int *>(type.func("func"_hs).next().custom()), nullptr);
|
||||
|
||||
entt::meta_factory<clazz>{}
|
||||
.custom<int>(0)
|
||||
.data<&base::member>("member"_hs)
|
||||
.custom<int>(1)
|
||||
.func<&clazz::set_int>("func"_hs)
|
||||
.custom<int>(2)
|
||||
.func<&clazz::set_boxed_int>("func"_hs)
|
||||
.custom<int>(3);
|
||||
|
||||
// custom data pointers are copied and never refreshed
|
||||
type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_EQ(static_cast<int>(type.custom()), 0);
|
||||
ASSERT_EQ(static_cast<int>(type.data("member"_hs).custom()), 1);
|
||||
ASSERT_EQ(static_cast<int>(type.func("func"_hs).custom()), 2);
|
||||
ASSERT_EQ(static_cast<int>(type.func("func"_hs).next().custom()), 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, Meta) {
|
||||
entt::meta_ctx ctx{};
|
||||
|
||||
ASSERT_EQ(entt::resolve(entt::type_id<int>()), entt::meta_type{});
|
||||
ASSERT_EQ(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
|
||||
|
||||
auto factory = entt::meta<int>();
|
||||
|
||||
ASSERT_NE(entt::resolve(entt::type_id<int>()), entt::meta_type{});
|
||||
ASSERT_EQ(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
|
||||
ASSERT_TRUE(entt::resolve(entt::type_id<int>()).is_integral());
|
||||
|
||||
factory = entt::meta<int>(ctx);
|
||||
|
||||
ASSERT_NE(entt::resolve(entt::type_id<int>()), entt::meta_type{});
|
||||
ASSERT_NE(entt::resolve(ctx, entt::type_id<int>()), entt::meta_type{});
|
||||
ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()).is_integral());
|
||||
}
|
||||
|
||||
TEST_F(MetaFactory, MetaReset) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_ctx ctx{};
|
||||
|
||||
entt::meta_factory<int>{}.type("global"_hs);
|
||||
entt::meta_factory<int>{ctx}.type("local"_hs);
|
||||
|
||||
ASSERT_TRUE(entt::resolve(entt::type_id<int>()));
|
||||
ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()));
|
||||
|
||||
entt::meta_reset();
|
||||
|
||||
ASSERT_FALSE(entt::resolve(entt::type_id<int>()));
|
||||
ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()));
|
||||
|
||||
entt::meta_reset(ctx);
|
||||
|
||||
ASSERT_FALSE(entt::resolve(entt::type_id<int>()));
|
||||
ASSERT_FALSE(entt::resolve(ctx, entt::type_id<int>()));
|
||||
|
||||
entt::meta_factory<int>{}.type("global"_hs);
|
||||
entt::meta_factory<int>{ctx}.type("local"_hs);
|
||||
|
||||
ASSERT_TRUE(entt::resolve(entt::type_id<int>()));
|
||||
ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()));
|
||||
|
||||
entt::meta_reset<int>();
|
||||
|
||||
ASSERT_FALSE(entt::resolve(entt::type_id<int>()));
|
||||
ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()));
|
||||
|
||||
entt::meta_reset<int>(ctx);
|
||||
|
||||
ASSERT_FALSE(entt::resolve(entt::type_id<int>()));
|
||||
ASSERT_FALSE(entt::resolve(ctx, entt::type_id<int>()));
|
||||
|
||||
entt::meta_factory<int>{}.type("global"_hs);
|
||||
entt::meta_factory<int>{ctx}.type("local"_hs);
|
||||
|
||||
ASSERT_TRUE(entt::resolve(entt::type_id<int>()));
|
||||
ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()));
|
||||
|
||||
entt::meta_reset("global"_hs);
|
||||
|
||||
ASSERT_FALSE(entt::resolve(entt::type_id<int>()));
|
||||
ASSERT_TRUE(entt::resolve(ctx, entt::type_id<int>()));
|
||||
|
||||
entt::meta_reset(ctx, "local"_hs);
|
||||
|
||||
ASSERT_FALSE(entt::resolve(entt::type_id<int>()));
|
||||
ASSERT_FALSE(entt::resolve(ctx, entt::type_id<int>()));
|
||||
}
|
||||
701
lib/All/entt/test/entt/meta/meta_func.cpp
Normal file
701
lib/All/entt/test/entt/meta/meta_func.cpp
Normal file
@@ -0,0 +1,701 @@
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#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/policy.hpp>
|
||||
#include <entt/meta/range.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/meta_traits.h"
|
||||
|
||||
struct base {
|
||||
base() = default;
|
||||
virtual ~base() = default;
|
||||
|
||||
void setter(int iv) {
|
||||
value = iv;
|
||||
}
|
||||
|
||||
[[nodiscard]] int getter() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
static void static_setter(base &ref, int iv) {
|
||||
ref.value = iv;
|
||||
}
|
||||
|
||||
int value{3};
|
||||
};
|
||||
|
||||
void fake_member(base &instance, int value) {
|
||||
instance.value = value;
|
||||
}
|
||||
|
||||
[[nodiscard]] int fake_const_member(const base &instance) {
|
||||
return instance.value;
|
||||
}
|
||||
|
||||
struct derived: base {
|
||||
derived() = default;
|
||||
};
|
||||
|
||||
struct function {
|
||||
[[nodiscard]] int f(const base &, int val, int other) {
|
||||
return f(val, other);
|
||||
}
|
||||
|
||||
[[nodiscard]] int f(int val, const int other) {
|
||||
value = val;
|
||||
return other * other;
|
||||
}
|
||||
|
||||
[[nodiscard]] int f(int iv) const {
|
||||
return value * iv;
|
||||
}
|
||||
|
||||
void g(int iv) {
|
||||
value = iv * iv;
|
||||
}
|
||||
|
||||
[[nodiscard]] static int h(int &iv, const function &instance) {
|
||||
return (iv *= instance.value);
|
||||
}
|
||||
|
||||
static void k(int iv, function &instance) {
|
||||
instance.value = iv;
|
||||
}
|
||||
|
||||
[[nodiscard]] int v(int &iv) const {
|
||||
return (iv = value);
|
||||
}
|
||||
|
||||
[[nodiscard]] int &a() {
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] operator int() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
int value{};
|
||||
};
|
||||
|
||||
double double_member(const double &value) {
|
||||
return value * value;
|
||||
}
|
||||
|
||||
struct MetaFunc: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<double>{}
|
||||
.type("double"_hs)
|
||||
.func<&double_member>("member"_hs);
|
||||
|
||||
entt::meta_factory<base>{}
|
||||
.type("base"_hs)
|
||||
.func<&base::setter>("setter"_hs)
|
||||
.func<fake_member>("fake_member"_hs)
|
||||
.func<fake_const_member>("fake_const_member"_hs);
|
||||
|
||||
entt::meta_factory<derived>{}
|
||||
.type("derived"_hs)
|
||||
.base<base>()
|
||||
.func<&base::setter>("setter_from_base"_hs)
|
||||
.func<&base::getter>("getter_from_base"_hs)
|
||||
.func<&base::static_setter>("static_setter_from_base"_hs);
|
||||
|
||||
entt::meta_factory<function>{}
|
||||
.type("func"_hs)
|
||||
.func<&entt::registry::emplace_or_replace<function>, entt::as_ref_t>("emplace"_hs)
|
||||
.traits(test::meta_traits::one | test::meta_traits::two | test::meta_traits::three)
|
||||
.func<entt::overload<int(const base &, int, int)>(&function::f)>("f3"_hs)
|
||||
.traits(test::meta_traits::three)
|
||||
.func<entt::overload<int(int, int)>(&function::f)>("f2"_hs)
|
||||
.traits(test::meta_traits::two)
|
||||
.custom<int>(2)
|
||||
.func<entt::overload<int(int) const>(&function::f)>("f1"_hs)
|
||||
.traits(test::meta_traits::one)
|
||||
.func<&function::g>("g"_hs)
|
||||
.custom<char>('c')
|
||||
.func<function::h>("h"_hs)
|
||||
.func<function::k>("k"_hs)
|
||||
.func<&function::v, entt::as_void_t>("v"_hs)
|
||||
.func<&function::a, entt::as_ref_t>("a"_hs)
|
||||
.func<&function::a, entt::as_cref_t>("ca"_hs)
|
||||
.conv<int>();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
|
||||
std::size_t reset_and_check() {
|
||||
std::size_t count = 0;
|
||||
|
||||
for(const auto &func: entt::resolve<function>().func()) {
|
||||
for(auto curr = func.second; curr; curr = curr.next()) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
SetUp();
|
||||
|
||||
for(const auto &func: entt::resolve<function>().func()) {
|
||||
for(auto curr = func.second; curr; curr = curr.next()) {
|
||||
--count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
};
|
||||
};
|
||||
|
||||
using MetaFuncDeathTest = MetaFunc;
|
||||
|
||||
TEST_F(MetaFunc, SafeWhenEmpty) {
|
||||
const entt::meta_func func{};
|
||||
entt::meta_any *args = nullptr;
|
||||
|
||||
ASSERT_FALSE(func);
|
||||
ASSERT_EQ(func, entt::meta_func{});
|
||||
ASSERT_EQ(func.arity(), 0u);
|
||||
ASSERT_FALSE(func.is_const());
|
||||
ASSERT_FALSE(func.is_static());
|
||||
ASSERT_EQ(func.ret(), entt::meta_type{});
|
||||
ASSERT_EQ(func.arg(0u), entt::meta_type{});
|
||||
ASSERT_EQ(func.arg(1u), entt::meta_type{});
|
||||
ASSERT_FALSE(func.invoke({}, args, 0u));
|
||||
ASSERT_FALSE(func.invoke({}, args, 1u));
|
||||
ASSERT_FALSE(func.invoke({}));
|
||||
ASSERT_FALSE(func.invoke({}, 'c'));
|
||||
ASSERT_EQ(func.traits<test::meta_traits>(), test::meta_traits::none);
|
||||
ASSERT_EQ(static_cast<const char *>(func.custom()), nullptr);
|
||||
ASSERT_EQ(func.next(), func);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, UserTraits) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_EQ(entt::resolve<function>().func("h"_hs).traits<test::meta_traits>(), test::meta_traits::none);
|
||||
ASSERT_EQ(entt::resolve<function>().func("k"_hs).traits<test::meta_traits>(), test::meta_traits::none);
|
||||
|
||||
ASSERT_EQ(entt::resolve<function>().func("emplace"_hs).traits<test::meta_traits>(), test::meta_traits::one | test::meta_traits::two | test::meta_traits::three);
|
||||
ASSERT_EQ(entt::resolve<function>().func("f1"_hs).traits<test::meta_traits>(), test::meta_traits::one);
|
||||
ASSERT_EQ(entt::resolve<function>().func("f2"_hs).traits<test::meta_traits>(), test::meta_traits::two);
|
||||
ASSERT_EQ(entt::resolve<function>().func("f3"_hs).traits<test::meta_traits>(), test::meta_traits::three);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaFuncDeathTest, UserTraits) {
|
||||
using namespace entt::literals;
|
||||
|
||||
using traits_type = entt::internal::meta_traits;
|
||||
constexpr auto value = traits_type{static_cast<std::underlying_type_t<traits_type>>(traits_type::_user_defined_traits) + 1u};
|
||||
ASSERT_DEATH(entt::meta_factory<function>{}.func<&function::g>("g"_hs).traits(value), "");
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, Custom) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_EQ(*static_cast<const char *>(entt::resolve<function>().func("g"_hs).custom()), 'c');
|
||||
ASSERT_EQ(static_cast<const char &>(entt::resolve<function>().func("g"_hs).custom()), 'c');
|
||||
|
||||
ASSERT_EQ(static_cast<const int *>(entt::resolve<function>().func("g"_hs).custom()), nullptr);
|
||||
ASSERT_EQ(static_cast<const int *>(entt::resolve<function>().func("h"_hs).custom()), nullptr);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaFuncDeathTest, Custom) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const int value = entt::resolve<function>().func("g"_hs).custom(), "");
|
||||
ASSERT_DEATH([[maybe_unused]] const char value = entt::resolve<function>().func("h"_hs).custom(), "");
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, Comparison) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<function>().func("f2"_hs);
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func, func);
|
||||
ASSERT_NE(func, entt::meta_func{});
|
||||
ASSERT_FALSE(func != func);
|
||||
ASSERT_TRUE(func == func);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, NonConst) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<function>().func("f2"_hs);
|
||||
function 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(instance.value, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, Const) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<function>().func("f1"_hs);
|
||||
function instance{2};
|
||||
|
||||
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{});
|
||||
|
||||
ASSERT_FALSE(empty);
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 8);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, RetVoid) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<function>().func("g"_hs);
|
||||
function 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, 4);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(instance.value, 16);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, Static) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<function>().func("h"_hs);
|
||||
function instance{2};
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 2u);
|
||||
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_EQ(func.arg(1u), entt::resolve<function>());
|
||||
ASSERT_FALSE(func.arg(2u));
|
||||
|
||||
auto any = func.invoke({}, 3, entt::forward_as_meta(instance));
|
||||
auto empty = func.invoke({}, derived{}, entt::forward_as_meta(instance));
|
||||
|
||||
ASSERT_FALSE(empty);
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 6);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, StaticRetVoid) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<function>().func("k"_hs);
|
||||
function instance{};
|
||||
|
||||
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<int>());
|
||||
ASSERT_EQ(func.arg(1u), entt::resolve<function>());
|
||||
ASSERT_FALSE(func.arg(2u));
|
||||
|
||||
auto any = func.invoke({}, 3, entt::forward_as_meta(instance));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, StaticAsMember) {
|
||||
using namespace entt::literals;
|
||||
|
||||
base instance{};
|
||||
auto func = entt::resolve<base>().func("fake_member"_hs);
|
||||
auto any = func.invoke(instance, 3);
|
||||
|
||||
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_FALSE(func.invoke({}, 3));
|
||||
ASSERT_FALSE(func.invoke(std::as_const(instance), 3));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<void>());
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, StaticAsConstMember) {
|
||||
using namespace entt::literals;
|
||||
|
||||
base instance{};
|
||||
auto func = entt::resolve<base>().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_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, NonClassTypeMember) {
|
||||
using namespace entt::literals;
|
||||
|
||||
double instance = 3.;
|
||||
auto func = entt::resolve<double>().func("member"_hs);
|
||||
auto any = func.invoke(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<double>());
|
||||
ASSERT_FALSE(func.arg(0u));
|
||||
|
||||
ASSERT_FALSE(func.invoke({}));
|
||||
ASSERT_TRUE(func.invoke(instance));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<double>());
|
||||
ASSERT_EQ(any.cast<double>(), instance * instance);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, MetaAnyArgs) {
|
||||
using namespace entt::literals;
|
||||
|
||||
function instance{3};
|
||||
auto any = entt::resolve<function>().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<function>().func("f1"_hs).invoke(value, 'c'));
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, CastAndConvert) {
|
||||
using namespace entt::literals;
|
||||
|
||||
function instance;
|
||||
instance.value = 3;
|
||||
auto any = entt::resolve<function>().func("f3"_hs).invoke(instance, derived{}, 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;
|
||||
|
||||
function instance;
|
||||
auto any = entt::resolve<function>().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<function>().func("h"_hs);
|
||||
|
||||
function instance{2};
|
||||
entt::meta_any any{3};
|
||||
int value = 4;
|
||||
|
||||
ASSERT_EQ(func.invoke({}, entt::forward_as_meta(value), entt::forward_as_meta(instance)).cast<int>(), 8);
|
||||
ASSERT_EQ(func.invoke({}, any.as_ref(), entt::forward_as_meta(instance)).cast<int>(), 6);
|
||||
ASSERT_EQ(any.cast<int>(), 6);
|
||||
ASSERT_EQ(value, 8);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, ArgsByConstRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
function instance{};
|
||||
auto func = entt::resolve<function>().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(instance.value, 9);
|
||||
|
||||
ASSERT_TRUE(func.invoke(instance, std::as_const(any).as_ref()));
|
||||
ASSERT_EQ(instance.value, 4);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, ConstInstance) {
|
||||
using namespace entt::literals;
|
||||
|
||||
function instance{2};
|
||||
auto any = entt::resolve<function>().func("f1"_hs).invoke(std::as_const(instance), 2);
|
||||
|
||||
ASSERT_FALSE(entt::resolve<function>().func("g"_hs).invoke(std::as_const(instance), 1));
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<int>(), 4);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, AsVoid) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<function>().func("v"_hs);
|
||||
function instance{3};
|
||||
int value{2};
|
||||
|
||||
ASSERT_EQ(func.invoke(instance, entt::forward_as_meta(value)), entt::meta_any{std::in_place_type<void>});
|
||||
ASSERT_EQ(func.ret(), entt::resolve<void>());
|
||||
ASSERT_EQ(value, instance.value);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, AsRef) {
|
||||
using namespace entt::literals;
|
||||
|
||||
function instance{};
|
||||
auto func = entt::resolve<function>().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;
|
||||
|
||||
function instance{3};
|
||||
auto func = entt::resolve<function>().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;
|
||||
|
||||
function instance{};
|
||||
auto func = entt::resolve<function>().func("ca"_hs);
|
||||
|
||||
ASSERT_DEATH((func.invoke(instance).cast<int &>() = 3), "");
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, InvokeBaseFunction) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<derived>();
|
||||
derived instance{};
|
||||
|
||||
ASSERT_TRUE(type.func("setter"_hs));
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
|
||||
type.func("setter"_hs).invoke(instance, 1);
|
||||
|
||||
ASSERT_EQ(instance.value, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, InvokeFromBase) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<derived>();
|
||||
derived 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, 1);
|
||||
|
||||
ASSERT_EQ(instance.value, 1);
|
||||
|
||||
auto getter_from_base = type.func("getter_from_base"_hs);
|
||||
|
||||
ASSERT_TRUE(getter_from_base);
|
||||
ASSERT_EQ(getter_from_base.invoke(instance).cast<int>(), 1);
|
||||
|
||||
auto static_setter_from_base = type.func("static_setter_from_base"_hs);
|
||||
|
||||
ASSERT_TRUE(static_setter_from_base);
|
||||
ASSERT_EQ(instance.value, 1);
|
||||
|
||||
static_setter_from_base.invoke(instance, 3);
|
||||
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, ExternalMemberFunction) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto func = entt::resolve<function>().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<function>());
|
||||
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<function>(entity));
|
||||
|
||||
func.invoke({}, entt::forward_as_meta(registry), entity);
|
||||
|
||||
ASSERT_TRUE(registry.all_of<function>(entity));
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, Overloaded) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<function>();
|
||||
|
||||
ASSERT_FALSE(type.func("f2"_hs).next());
|
||||
|
||||
entt::meta_factory<function>{}
|
||||
// this should not overwrite traits and custom data
|
||||
.func<entt::overload<int(int, int)>(&function::f)>("f2"_hs)
|
||||
// this should put traits and custom data on the new overload instead
|
||||
.func<entt::overload<int(int) const>(&function::f)>("f2"_hs)
|
||||
.traits(test::meta_traits::three)
|
||||
.custom<int>(3);
|
||||
|
||||
ASSERT_TRUE(type.func("f2"_hs).next());
|
||||
ASSERT_FALSE(type.func("f2"_hs).next().next());
|
||||
|
||||
ASSERT_EQ(type.func("f2"_hs).traits<test::meta_traits>(), test::meta_traits::two);
|
||||
ASSERT_EQ(type.func("f2"_hs).next().traits<test::meta_traits>(), test::meta_traits::three);
|
||||
|
||||
ASSERT_NE(static_cast<const int *>(type.func("f2"_hs).custom()), nullptr);
|
||||
ASSERT_NE(static_cast<const int *>(type.func("f2"_hs).next().custom()), nullptr);
|
||||
|
||||
ASSERT_EQ(static_cast<const int &>(type.func("f2"_hs).custom()), 2);
|
||||
ASSERT_EQ(static_cast<const int &>(type.func("f2"_hs).next().custom()), 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, OverloadedOrder) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<function>{}
|
||||
.func<entt::overload<int(int, int)>(&function::f)>("f2"_hs)
|
||||
.func<entt::overload<int(int) const>(&function::f)>("f2"_hs);
|
||||
|
||||
auto type = entt::resolve<function>();
|
||||
auto func = type.func("f2"_hs);
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 2u);
|
||||
ASSERT_FALSE(func.is_const());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<int>());
|
||||
|
||||
func = func.next();
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 1u);
|
||||
ASSERT_TRUE(func.is_const());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<int>());
|
||||
|
||||
func = func.next();
|
||||
|
||||
ASSERT_FALSE(func);
|
||||
}
|
||||
|
||||
TEST_F(MetaFunc, ReRegistration) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_EQ(reset_and_check(), 0u);
|
||||
|
||||
function instance{};
|
||||
auto type = entt::resolve<function>();
|
||||
|
||||
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_factory<function>{}
|
||||
.func<entt::overload<int(int, int)>(&function::f)>("f"_hs)
|
||||
.func<entt::overload<int(int) const>(&function::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));
|
||||
|
||||
entt::meta_factory<function>{}
|
||||
.func<entt::overload<int(int, int)>(&function::f)>("f"_hs)
|
||||
.traits(test::meta_traits::one)
|
||||
.custom<int>(3)
|
||||
// this should not overwrite traits and custom data
|
||||
.func<entt::overload<int(int, int)>(&function::f)>("f"_hs);
|
||||
|
||||
ASSERT_EQ(type.func("f"_hs).traits<test::meta_traits>(), test::meta_traits::one);
|
||||
ASSERT_NE(static_cast<const int *>(type.func("f"_hs).custom()), nullptr);
|
||||
|
||||
ASSERT_EQ(reset_and_check(), 0u);
|
||||
}
|
||||
73
lib/All/entt/test/entt/meta/meta_handle.cpp
Normal file
73
lib/All/entt/test/entt/meta/meta_handle.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/meta/factory.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
|
||||
struct clazz {
|
||||
void incr() {
|
||||
++value;
|
||||
}
|
||||
|
||||
void decr() {
|
||||
--value;
|
||||
}
|
||||
|
||||
int value{};
|
||||
};
|
||||
|
||||
struct MetaHandle: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<clazz>{}
|
||||
.type("clazz"_hs)
|
||||
.func<&clazz::incr>("incr"_hs)
|
||||
.func<&clazz::decr>("decr"_hs);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
entt::meta_reset();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(MetaHandle, Handle) {
|
||||
using namespace entt::literals;
|
||||
|
||||
clazz instance{};
|
||||
entt::meta_handle handle{};
|
||||
entt::meta_handle chandle{};
|
||||
|
||||
ASSERT_FALSE(handle);
|
||||
ASSERT_FALSE(chandle);
|
||||
|
||||
ASSERT_EQ(handle, chandle);
|
||||
ASSERT_EQ(handle, entt::meta_handle{});
|
||||
ASSERT_FALSE(handle != handle);
|
||||
ASSERT_TRUE(handle == handle);
|
||||
|
||||
handle = entt::meta_handle{instance};
|
||||
chandle = entt::meta_handle{std::as_const(instance)};
|
||||
|
||||
ASSERT_TRUE(handle);
|
||||
ASSERT_TRUE(chandle);
|
||||
|
||||
ASSERT_EQ(handle, chandle);
|
||||
ASSERT_NE(handle, entt::meta_handle{});
|
||||
ASSERT_FALSE(handle != handle);
|
||||
ASSERT_TRUE(handle == handle);
|
||||
|
||||
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);
|
||||
}
|
||||
462
lib/All/entt/test/entt/meta/meta_pointer.cpp
Normal file
462
lib/All/entt/test/entt/meta/meta_pointer.cpp
Normal file
@@ -0,0 +1,462 @@
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/meta/adl_pointer.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/pointer.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include <entt/meta/type_traits.hpp>
|
||||
#include "../../common/config.h"
|
||||
|
||||
template<typename Type>
|
||||
struct wrapped_shared_ptr {
|
||||
wrapped_shared_ptr(Type init)
|
||||
: ptr{new Type{init}} {}
|
||||
|
||||
[[nodiscard]] Type &deref() const {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Type> ptr;
|
||||
};
|
||||
|
||||
struct self_ptr {
|
||||
using element_type = self_ptr;
|
||||
|
||||
self_ptr(int val)
|
||||
: value{val} {}
|
||||
|
||||
const self_ptr &operator*() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
struct proxy_ptr {
|
||||
using element_type = proxy_ptr;
|
||||
|
||||
proxy_ptr(int &val)
|
||||
: value{&val} {}
|
||||
|
||||
proxy_ptr operator*() const {
|
||||
return *this;
|
||||
}
|
||||
|
||||
int *value;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct adl_wrapped_shared_ptr: wrapped_shared_ptr<Type> {
|
||||
using is_meta_pointer_like = void;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct spec_wrapped_shared_ptr: wrapped_shared_ptr<Type> {
|
||||
using is_meta_pointer_like = void;
|
||||
};
|
||||
|
||||
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 3;
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceOperatorInvalidType) {
|
||||
const int value = 0;
|
||||
const 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 = 3;
|
||||
const 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 &>(), 3);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(MetaPointerLikeDeathTest, DereferenceOperatorConstType) {
|
||||
const int value = 3;
|
||||
const entt::meta_any any{&value};
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_DEATH(deref.cast<int &>() = 0, "");
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceOperatorConstAnyNonConstType) {
|
||||
int value = 3;
|
||||
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 &>(), 3);
|
||||
ASSERT_EQ(deref.cast<const int &>(), 3);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceOperatorConstAnyConstType) {
|
||||
const int value = 3;
|
||||
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 &>(), 3);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(MetaPointerLikeDeathTest, DereferenceOperatorConstAnyConstType) {
|
||||
const int value = 3;
|
||||
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 &>() = 3;
|
||||
|
||||
ASSERT_EQ(*any.cast<int *>(), 3);
|
||||
ASSERT_EQ(value, 3);
|
||||
}
|
||||
|
||||
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 &>() = 3;
|
||||
|
||||
ASSERT_EQ(*any.cast<std::shared_ptr<int>>(), 3);
|
||||
ASSERT_EQ(*value, 3);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, PointerToConstMoveOnlyType) {
|
||||
const std::unique_ptr<int> instance;
|
||||
const entt::meta_any any{&instance};
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(deref);
|
||||
|
||||
ASSERT_EQ(deref.try_cast<std::unique_ptr<int>>(), nullptr);
|
||||
ASSERT_NE(deref.try_cast<const std::unique_ptr<int>>(), nullptr);
|
||||
ASSERT_EQ(&deref.cast<const std::unique_ptr<int> &>(), &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 &>() = 3;
|
||||
|
||||
ASSERT_EQ(*any.cast<int *>(), 3);
|
||||
ASSERT_EQ(value, 3);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, AsConstRef) {
|
||||
int value = 3;
|
||||
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 &>() = 3;
|
||||
|
||||
ASSERT_EQ(*any.cast<int *>(), 3);
|
||||
ASSERT_EQ(value, 3);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceOverloadAdl) {
|
||||
const entt::meta_any any{adl_wrapped_shared_ptr<int>{3}};
|
||||
|
||||
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 &>(), 3);
|
||||
ASSERT_EQ(deref.cast<const int &>(), 3);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceOverloadSpec) {
|
||||
const entt::meta_any any{spec_wrapped_shared_ptr<int>{3}};
|
||||
|
||||
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 &>(), 3);
|
||||
ASSERT_EQ(deref.cast<const int &>(), 3);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferencePointerToConstOverloadAdl) {
|
||||
const entt::meta_any any{adl_wrapped_shared_ptr<const int>{3}};
|
||||
|
||||
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 &>(), 3);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferencePointerToConstOverloadSpec) {
|
||||
const entt::meta_any any{spec_wrapped_shared_ptr<const int>{3}};
|
||||
|
||||
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 &>(), 3);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(MetaPointerLikeDeathTest, DereferencePointerToConstOverloadAdl) {
|
||||
const entt::meta_any any{adl_wrapped_shared_ptr<const int>{3}};
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_DEATH(deref.cast<int &>() = 3, "");
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(MetaPointerLikeDeathTest, DereferencePointerToConstOverloadSpec) {
|
||||
const entt::meta_any any{spec_wrapped_shared_ptr<const int>{3}};
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_TRUE(deref);
|
||||
ASSERT_DEATH(deref.cast<int &>() = 3, "");
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferencePointerToVoid) {
|
||||
const entt::meta_any any{static_cast<void *>(nullptr)};
|
||||
|
||||
ASSERT_TRUE(any.type().is_pointer());
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_FALSE(deref);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferencePointerToConstVoid) {
|
||||
const entt::meta_any any{static_cast<const void *>(nullptr)};
|
||||
|
||||
ASSERT_TRUE(any.type().is_pointer());
|
||||
ASSERT_TRUE(any.type().is_pointer_like());
|
||||
|
||||
auto deref = *any;
|
||||
|
||||
ASSERT_FALSE(deref);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceSharedPointerToVoid) {
|
||||
const entt::meta_any any{std::shared_ptr<void>{}};
|
||||
|
||||
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(MetaPointerLike, DereferenceUniquePointerToVoid) {
|
||||
const entt::meta_any any{std::unique_ptr<void, void (*)(void *)>{nullptr, nullptr}};
|
||||
|
||||
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(MetaPointerLike, DereferencePointerToFunction) {
|
||||
entt::meta_any any{&test_function};
|
||||
|
||||
ASSERT_TRUE(any.type().is_pointer());
|
||||
ASSERT_TRUE((*std::as_const(any)).type().is_pointer_like());
|
||||
ASSERT_NE((**any).try_cast<int (*)()>(), nullptr);
|
||||
ASSERT_EQ((***std::as_const(any)).cast<int (*)()>()(), 3);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceSelfPointer) {
|
||||
self_ptr obj{3};
|
||||
const 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;
|
||||
const proxy_ptr obj{value};
|
||||
const 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 = 3;
|
||||
|
||||
ASSERT_EQ(value, 3);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceArray) {
|
||||
// NOLINTBEGIN(*-avoid-c-arrays)
|
||||
const entt::meta_any array{std::in_place_type<int[3]>};
|
||||
const entt::meta_any array_of_array{std::in_place_type<int[3][3]>};
|
||||
// NOLINTEND(*-avoid-c-arrays)
|
||||
|
||||
// NOLINTBEGIN(*-avoid-c-arrays)
|
||||
ASSERT_EQ(array.type(), entt::resolve<int[3]>());
|
||||
ASSERT_EQ(array_of_array.type(), entt::resolve<int[3][3]>());
|
||||
// NOLINTEND(*-avoid-c-arrays)
|
||||
|
||||
ASSERT_FALSE(*array);
|
||||
ASSERT_FALSE(*array_of_array);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferencePlainNullPointer) {
|
||||
const entt::meta_any any{static_cast<int *>(nullptr)};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(*any);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceSharedNullPointer) {
|
||||
const entt::meta_any any{std::shared_ptr<int>{}};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(*any);
|
||||
}
|
||||
|
||||
TEST(MetaPointerLike, DereferenceUniqueNullPointer) {
|
||||
const entt::meta_any any{std::unique_ptr<int>{}};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(*any);
|
||||
}
|
||||
98
lib/All/entt/test/entt/meta/meta_range.cpp
Normal file
98
lib/All/entt/test/entt/meta/meta_range.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/core/iterator.hpp>
|
||||
#include <entt/core/type_info.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_factory<int>{}
|
||||
.type("int"_hs)
|
||||
.data<2>("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;
|
||||
|
||||
testing::StaticAssertTypeEq<iterator::value_type, std::pair<entt::id_type, entt::meta_type>>();
|
||||
testing::StaticAssertTypeEq<iterator::pointer, entt::input_iterator_pointer<std::pair<entt::id_type, entt::meta_type>>>();
|
||||
testing::StaticAssertTypeEq<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_factory<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>(), 2);
|
||||
}
|
||||
}
|
||||
50
lib/All/entt/test/entt/meta/meta_template.cpp
Normal file
50
lib/All/entt/test/entt/meta/meta_template.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#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>
|
||||
#include <entt/meta/type_traits.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{});
|
||||
}
|
||||
905
lib/All/entt/test/entt/meta/meta_type.cpp
Normal file
905
lib/All/entt/test/entt/meta/meta_type.cpp
Normal file
@@ -0,0 +1,905 @@
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#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/range.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include <entt/meta/template.hpp>
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/meta_traits.h"
|
||||
|
||||
template<typename Type>
|
||||
void set(Type &elem, Type value) {
|
||||
elem = value;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
Type get(Type &elem) {
|
||||
return elem;
|
||||
}
|
||||
|
||||
struct base {
|
||||
char value{'c'};
|
||||
};
|
||||
|
||||
struct derived: base {
|
||||
derived()
|
||||
: base{} {}
|
||||
};
|
||||
|
||||
struct abstract {
|
||||
virtual ~abstract() = default;
|
||||
|
||||
virtual void func(int) {}
|
||||
void base_only(int) {}
|
||||
};
|
||||
|
||||
struct concrete: base, abstract {
|
||||
void func(int val) override {
|
||||
abstract::func(val);
|
||||
value = val;
|
||||
}
|
||||
|
||||
int value{3};
|
||||
};
|
||||
|
||||
struct clazz {
|
||||
clazz() = default;
|
||||
|
||||
clazz(const base &, int val)
|
||||
: value{val} {}
|
||||
|
||||
void member() {}
|
||||
static void func() {}
|
||||
|
||||
[[nodiscard]] operator int() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
int value{};
|
||||
};
|
||||
|
||||
struct overloaded_func {
|
||||
[[nodiscard]] int f(const base &, int first, int second) {
|
||||
return f(first, second);
|
||||
}
|
||||
|
||||
[[nodiscard]] int f(int first, const int second) {
|
||||
value = first;
|
||||
return second * second;
|
||||
}
|
||||
|
||||
[[nodiscard]] int f(int val) {
|
||||
return 2 * std::as_const(*this).f(val);
|
||||
}
|
||||
|
||||
[[nodiscard]] int f(int val) const {
|
||||
return val * value;
|
||||
}
|
||||
|
||||
[[nodiscard]] float f(int first, const float second) {
|
||||
value = first;
|
||||
return second + second;
|
||||
}
|
||||
|
||||
int value{};
|
||||
};
|
||||
|
||||
struct from_void_callback {
|
||||
from_void_callback(bool &ref)
|
||||
: cb{&ref} {}
|
||||
|
||||
from_void_callback(const from_void_callback &) = delete;
|
||||
from_void_callback &operator=(const from_void_callback &) = delete;
|
||||
|
||||
~from_void_callback() {
|
||||
*cb = !*cb;
|
||||
}
|
||||
|
||||
private:
|
||||
bool *cb;
|
||||
};
|
||||
|
||||
enum class property_type : std::uint8_t {
|
||||
value,
|
||||
other
|
||||
};
|
||||
|
||||
struct MetaType: ::testing::Test {
|
||||
void SetUp() override {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_factory<double>{}
|
||||
.type("double"_hs)
|
||||
.traits(test::meta_traits::one)
|
||||
.data<set<double>, get<double>>("var"_hs);
|
||||
|
||||
entt::meta_factory<unsigned int>{}
|
||||
.type("unsigned int"_hs)
|
||||
.traits(test::meta_traits::two)
|
||||
.data<0u>("min"_hs)
|
||||
.data<128u>("max"_hs);
|
||||
|
||||
entt::meta_factory<base>{}
|
||||
.type("base"_hs)
|
||||
.data<&base::value>("value"_hs);
|
||||
|
||||
entt::meta_factory<derived>{}
|
||||
.type("derived"_hs)
|
||||
.traits(test::meta_traits::one | test::meta_traits::three)
|
||||
.base<base>();
|
||||
|
||||
entt::meta_factory<abstract>{}
|
||||
.type("abstract"_hs)
|
||||
.func<&abstract::func>("func"_hs)
|
||||
.func<&abstract::base_only>("base_only"_hs);
|
||||
|
||||
entt::meta_factory<concrete>{}
|
||||
.type("concrete"_hs)
|
||||
.base<base>()
|
||||
.base<abstract>();
|
||||
|
||||
entt::meta_factory<overloaded_func>{}
|
||||
.type("overloaded_func"_hs)
|
||||
.func<entt::overload<int(const base &, int, int)>(&overloaded_func::f)>("f"_hs)
|
||||
.func<entt::overload<int(int, int)>(&overloaded_func::f)>("f"_hs)
|
||||
.func<entt::overload<int(int)>(&overloaded_func::f)>("f"_hs)
|
||||
.func<entt::overload<int(int) const>(&overloaded_func::f)>("f"_hs)
|
||||
.func<entt::overload<float(int, float)>(&overloaded_func::f)>("f"_hs);
|
||||
|
||||
entt::meta_factory<property_type>{}
|
||||
.type("property"_hs)
|
||||
.traits(test::meta_traits::two | test::meta_traits::three)
|
||||
.data<property_type::value>("value"_hs)
|
||||
.data<property_type::other>("other"_hs)
|
||||
.data<set<property_type>, get<property_type>>("var"_hs);
|
||||
|
||||
entt::meta_factory<clazz>{}
|
||||
.type("class"_hs)
|
||||
.custom<char>('c')
|
||||
.ctor<const base &, int>()
|
||||
.data<&clazz::value>("value"_hs)
|
||||
.func<&clazz::member>("member"_hs)
|
||||
.func<clazz::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();
|
||||
const auto it = std::find_if(range.begin(), range.end(), [](auto curr) { return curr.second.id() == "class"_hs; });
|
||||
|
||||
ASSERT_NE(it, range.end());
|
||||
ASSERT_EQ(it->second, entt::resolve<clazz>());
|
||||
|
||||
bool found = false;
|
||||
|
||||
for(auto curr: entt::resolve()) {
|
||||
found = found || curr.second == entt::resolve<double>();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(found);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, SafeWhenEmpty) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::meta_type type{};
|
||||
entt::meta_any *args = nullptr;
|
||||
|
||||
ASSERT_FALSE(type);
|
||||
ASSERT_EQ(type, entt::meta_type{});
|
||||
ASSERT_EQ(type.info(), entt::type_id<void>());
|
||||
ASSERT_EQ(type.id(), entt::id_type{});
|
||||
ASSERT_EQ(type.size_of(), 0u);
|
||||
ASSERT_FALSE(type.is_arithmetic());
|
||||
ASSERT_FALSE(type.is_integral());
|
||||
ASSERT_FALSE(type.is_signed());
|
||||
ASSERT_FALSE(type.is_array());
|
||||
ASSERT_FALSE(type.is_enum());
|
||||
ASSERT_FALSE(type.is_class());
|
||||
ASSERT_FALSE(type.is_pointer());
|
||||
ASSERT_EQ(type.remove_pointer(), type);
|
||||
ASSERT_FALSE(type.is_pointer_like());
|
||||
ASSERT_FALSE(type.is_sequence_container());
|
||||
ASSERT_FALSE(type.is_associative_container());
|
||||
ASSERT_FALSE(type.is_template_specialization());
|
||||
ASSERT_EQ(type.template_arity(), 0u);
|
||||
ASSERT_EQ(type.template_type(), type);
|
||||
ASSERT_EQ(type.template_arg(0u), type);
|
||||
ASSERT_EQ(type.template_arg(1u), type);
|
||||
ASSERT_FALSE(type.can_cast(type));
|
||||
ASSERT_FALSE(type.can_cast(entt::resolve<void>()));
|
||||
ASSERT_FALSE(type.can_convert(type));
|
||||
ASSERT_FALSE(type.can_convert(entt::resolve<void>()));
|
||||
ASSERT_EQ(type.base().begin(), type.base().end());
|
||||
ASSERT_EQ(type.data().begin(), type.data().end());
|
||||
ASSERT_EQ(type.data("data"_hs), entt::meta_data{});
|
||||
ASSERT_EQ(type.func().begin(), type.func().end());
|
||||
ASSERT_EQ(type.func("func"_hs), entt::meta_func{});
|
||||
ASSERT_FALSE(type.construct(args, 0u));
|
||||
ASSERT_FALSE(type.construct(args, 1u));
|
||||
ASSERT_FALSE(type.construct());
|
||||
ASSERT_FALSE(type.construct(0.0));
|
||||
ASSERT_FALSE(type.from_void(static_cast<void *>(nullptr)));
|
||||
ASSERT_FALSE(type.from_void(static_cast<void *>(nullptr), true));
|
||||
ASSERT_FALSE(type.from_void(static_cast<void *>(&type)));
|
||||
ASSERT_FALSE(type.from_void(static_cast<void *>(&type), true));
|
||||
ASSERT_FALSE(type.from_void(static_cast<const void *>(nullptr)));
|
||||
ASSERT_FALSE(type.from_void(static_cast<const void *>(&type)));
|
||||
ASSERT_FALSE(type.invoke("func"_hs, {}, args, 0u));
|
||||
ASSERT_FALSE(type.invoke("func"_hs, {}, args, 1u));
|
||||
ASSERT_FALSE(type.invoke("func"_hs, {}));
|
||||
ASSERT_FALSE(type.invoke("func"_hs, {}, 'c'));
|
||||
ASSERT_FALSE(type.set("data"_hs, {}, 0));
|
||||
ASSERT_FALSE(type.get("data"_hs, {}));
|
||||
ASSERT_EQ(type.traits<test::meta_traits>(), test::meta_traits::none);
|
||||
ASSERT_EQ(static_cast<const char *>(type.custom()), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, UserTraits) {
|
||||
ASSERT_EQ(entt::resolve<bool>().traits<test::meta_traits>(), test::meta_traits::none);
|
||||
ASSERT_EQ(entt::resolve<clazz>().traits<test::meta_traits>(), test::meta_traits::none);
|
||||
|
||||
ASSERT_EQ(entt::resolve<double>().traits<test::meta_traits>(), test::meta_traits::one);
|
||||
ASSERT_EQ(entt::resolve<unsigned int>().traits<test::meta_traits>(), test::meta_traits::two);
|
||||
ASSERT_EQ(entt::resolve<derived>().traits<test::meta_traits>(), test::meta_traits::one | test::meta_traits::three);
|
||||
ASSERT_EQ(entt::resolve<property_type>().traits<test::meta_traits>(), test::meta_traits::two | test::meta_traits::three);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaTypeDeathTest, UserTraits) {
|
||||
using traits_type = entt::internal::meta_traits;
|
||||
constexpr auto value = traits_type{static_cast<std::underlying_type_t<traits_type>>(traits_type::_user_defined_traits) + 1u};
|
||||
ASSERT_DEATH(entt::meta_factory<clazz>{}.traits(value), "");
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Custom) {
|
||||
ASSERT_EQ(*static_cast<const char *>(entt::resolve<clazz>().custom()), 'c');
|
||||
ASSERT_EQ(static_cast<const char &>(entt::resolve<clazz>().custom()), 'c');
|
||||
|
||||
ASSERT_EQ(static_cast<const int *>(entt::resolve<clazz>().custom()), nullptr);
|
||||
ASSERT_EQ(static_cast<const int *>(entt::resolve<base>().custom()), nullptr);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaTypeDeathTest, Custom) {
|
||||
ASSERT_DEATH([[maybe_unused]] const int value = entt::resolve<clazz>().custom(), "");
|
||||
ASSERT_DEATH([[maybe_unused]] const char value = entt::resolve<base>().custom(), "");
|
||||
}
|
||||
|
||||
TEST_F(MetaType, IdAndInfo) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_TRUE(type);
|
||||
ASSERT_NE(type, entt::meta_type{});
|
||||
ASSERT_EQ(type.id(), "class"_hs);
|
||||
ASSERT_EQ(type.info(), entt::type_id<clazz>());
|
||||
}
|
||||
|
||||
TEST_F(MetaType, SizeOf) {
|
||||
ASSERT_EQ(entt::resolve<void>().size_of(), 0u);
|
||||
ASSERT_EQ(entt::resolve<int>().size_of(), sizeof(int));
|
||||
// NOLINTBEGIN(*-avoid-c-arrays)
|
||||
ASSERT_EQ(entt::resolve<int[]>().size_of(), 0u);
|
||||
ASSERT_EQ(entt::resolve<int[3]>().size_of(), sizeof(int[3]));
|
||||
// NOLINTEND(*-avoid-c-arrays)
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Traits) {
|
||||
ASSERT_TRUE(entt::resolve<bool>().is_arithmetic());
|
||||
ASSERT_TRUE(entt::resolve<double>().is_arithmetic());
|
||||
ASSERT_FALSE(entt::resolve<clazz>().is_arithmetic());
|
||||
|
||||
ASSERT_TRUE(entt::resolve<int>().is_integral());
|
||||
ASSERT_FALSE(entt::resolve<double>().is_integral());
|
||||
ASSERT_FALSE(entt::resolve<clazz>().is_integral());
|
||||
|
||||
ASSERT_TRUE(entt::resolve<long>().is_signed());
|
||||
ASSERT_FALSE(entt::resolve<unsigned int>().is_signed());
|
||||
ASSERT_FALSE(entt::resolve<clazz>().is_signed());
|
||||
|
||||
// NOLINTBEGIN(*-avoid-c-arrays)
|
||||
ASSERT_TRUE(entt::resolve<int[5]>().is_array());
|
||||
ASSERT_TRUE(entt::resolve<int[5][3]>().is_array());
|
||||
// NOLINTEND(*-avoid-c-arrays)
|
||||
ASSERT_FALSE(entt::resolve<int>().is_array());
|
||||
|
||||
ASSERT_TRUE(entt::resolve<property_type>().is_enum());
|
||||
ASSERT_FALSE(entt::resolve<char>().is_enum());
|
||||
|
||||
ASSERT_TRUE(entt::resolve<derived>().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>().remove_pointer(), entt::resolve<derived>());
|
||||
}
|
||||
|
||||
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, CanCast) {
|
||||
auto type = entt::resolve<derived>();
|
||||
|
||||
ASSERT_FALSE(type.can_cast(entt::resolve<void>()));
|
||||
ASSERT_TRUE(type.can_cast(entt::resolve<base>()));
|
||||
ASSERT_TRUE(type.can_cast(entt::resolve<derived>()));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, CanConvert) {
|
||||
auto instance = entt::resolve<clazz>();
|
||||
auto other = entt::resolve<derived>();
|
||||
auto arithmetic = entt::resolve<int>();
|
||||
|
||||
ASSERT_TRUE(instance.can_convert(entt::resolve<clazz>()));
|
||||
ASSERT_TRUE(instance.can_convert(entt::resolve<int>()));
|
||||
|
||||
ASSERT_TRUE(other.can_convert(entt::resolve<derived>()));
|
||||
ASSERT_TRUE(other.can_convert(entt::resolve<base>()));
|
||||
ASSERT_FALSE(other.can_convert(entt::resolve<int>()));
|
||||
|
||||
ASSERT_TRUE(arithmetic.can_convert(entt::resolve<int>()));
|
||||
ASSERT_FALSE(arithmetic.can_convert(entt::resolve<clazz>()));
|
||||
ASSERT_TRUE(arithmetic.can_convert(entt::resolve<double>()));
|
||||
ASSERT_TRUE(arithmetic.can_convert(entt::resolve<float>()));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Base) {
|
||||
auto type = entt::resolve<derived>();
|
||||
|
||||
ASSERT_NE(type.base().cbegin(), type.base().cend());
|
||||
|
||||
for(auto curr: type.base()) {
|
||||
ASSERT_EQ(curr.first, entt::type_id<base>().hash());
|
||||
ASSERT_EQ(curr.second, entt::resolve<base>());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Ctor) {
|
||||
derived instance;
|
||||
base &as_base = instance;
|
||||
auto type = entt::resolve<clazz>();
|
||||
|
||||
ASSERT_TRUE((type.construct(entt::forward_as_meta(instance), 3)));
|
||||
ASSERT_TRUE((type.construct(entt::forward_as_meta(as_base), 3)));
|
||||
|
||||
// use the implicitly generated default constructor
|
||||
auto any = type.construct();
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.type(), entt::resolve<clazz>());
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Data) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<clazz>();
|
||||
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>();
|
||||
clazz 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>();
|
||||
clazz instance{};
|
||||
|
||||
ASSERT_TRUE(type.invoke("member"_hs, instance));
|
||||
ASSERT_FALSE(type.invoke("rebmem"_hs, instance));
|
||||
|
||||
ASSERT_TRUE(type.invoke("func"_hs, {}));
|
||||
ASSERT_FALSE(type.invoke("cnuf"_hs, {}));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, InvokeFromBase) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<concrete>();
|
||||
concrete instance{};
|
||||
|
||||
ASSERT_TRUE(type.invoke("base_only"_hs, instance, 3));
|
||||
ASSERT_FALSE(type.invoke("ylno_esab"_hs, {}, 'c'));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, OverloadedFunc) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const auto type = entt::resolve<overloaded_func>();
|
||||
overloaded_func instance{};
|
||||
entt::meta_any res{};
|
||||
|
||||
ASSERT_TRUE(type.func("f"_hs));
|
||||
|
||||
res = type.invoke("f"_hs, instance, base{}, 1, 2);
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_EQ(instance.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(instance.value, 3);
|
||||
ASSERT_NE(res.try_cast<int>(), nullptr);
|
||||
ASSERT_EQ(res.cast<int>(), 16);
|
||||
|
||||
res = type.invoke("f"_hs, instance, 2);
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
ASSERT_NE(res.try_cast<int>(), nullptr);
|
||||
ASSERT_EQ(res.cast<int>(), 12);
|
||||
|
||||
res = type.invoke("f"_hs, std::as_const(instance), 2);
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
ASSERT_NE(res.try_cast<int>(), nullptr);
|
||||
ASSERT_EQ(res.cast<int>(), 6);
|
||||
|
||||
res = type.invoke("f"_hs, instance, 0, 1.f);
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_EQ(instance.value, 0);
|
||||
ASSERT_NE(res.try_cast<float>(), nullptr);
|
||||
ASSERT_EQ(res.cast<float>(), 2.f);
|
||||
|
||||
res = type.invoke("f"_hs, instance, 4, 8.f);
|
||||
|
||||
ASSERT_TRUE(res);
|
||||
ASSERT_EQ(instance.value, 4);
|
||||
ASSERT_NE(res.try_cast<float>(), nullptr);
|
||||
ASSERT_EQ(res.cast<float>(), 16.f);
|
||||
|
||||
// it fails as an ambiguous call
|
||||
ASSERT_FALSE(type.invoke("f"_hs, instance, 4, 8.));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, OverloadedFuncOrder) {
|
||||
using namespace entt::literals;
|
||||
|
||||
const auto type = entt::resolve<overloaded_func>();
|
||||
auto func = type.func("f"_hs);
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 3u);
|
||||
ASSERT_FALSE(func.is_const());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<int>());
|
||||
|
||||
func = func.next();
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 2u);
|
||||
ASSERT_FALSE(func.is_const());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<int>());
|
||||
|
||||
func = func.next();
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 1u);
|
||||
ASSERT_FALSE(func.is_const());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<int>());
|
||||
|
||||
func = func.next();
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 1u);
|
||||
ASSERT_TRUE(func.is_const());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<int>());
|
||||
|
||||
func = func.next();
|
||||
|
||||
ASSERT_TRUE(func);
|
||||
ASSERT_EQ(func.arity(), 2u);
|
||||
ASSERT_FALSE(func.is_const());
|
||||
ASSERT_EQ(func.ret(), entt::resolve<float>());
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Construct) {
|
||||
auto any = entt::resolve<clazz>().construct(base{}, 2);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz>().value, 2);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ConstructNoArgs) {
|
||||
// this should work, no other tests required
|
||||
auto any = entt::resolve<clazz>().construct();
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ConstructMetaAnyArgs) {
|
||||
auto any = entt::resolve<clazz>().construct(entt::meta_any{base{}}, entt::meta_any{3});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz>().value, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ConstructInvalidArgs) {
|
||||
ASSERT_FALSE(entt::resolve<clazz>().construct('c', base{}));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, LessArgs) {
|
||||
ASSERT_FALSE(entt::resolve<clazz>().construct(base{}));
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ConstructCastAndConvert) {
|
||||
auto any = entt::resolve<clazz>().construct(derived{}, clazz{derived{}, 3});
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz>().value, 3);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, ConstructArithmeticConversion) {
|
||||
auto any = entt::resolve<clazz>().construct(derived{}, true);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_EQ(any.cast<clazz>().value, 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, FromVoid) {
|
||||
ASSERT_FALSE(entt::resolve<double>().from_void(static_cast<double *>(nullptr)));
|
||||
ASSERT_FALSE(entt::resolve<double>().from_void(static_cast<const double *>(nullptr)));
|
||||
|
||||
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 type = entt::resolve<double>();
|
||||
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, FromVoidOwnership) {
|
||||
bool check = false;
|
||||
auto type = entt::resolve<from_void_callback>();
|
||||
void *instance = std::make_unique<from_void_callback>(check).release();
|
||||
|
||||
auto any = type.from_void(instance);
|
||||
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
|
||||
auto other = type.from_void(instance, true);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_TRUE(other);
|
||||
|
||||
ASSERT_FALSE(check);
|
||||
|
||||
any.reset();
|
||||
|
||||
ASSERT_FALSE(check);
|
||||
|
||||
other.reset();
|
||||
|
||||
ASSERT_TRUE(check);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Reset) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_TRUE(entt::resolve("class"_hs));
|
||||
ASSERT_EQ(entt::resolve<clazz>().id(), "class"_hs);
|
||||
ASSERT_TRUE(entt::resolve<clazz>().data("value"_hs));
|
||||
ASSERT_TRUE((entt::resolve<clazz>().construct(derived{}, clazz{})));
|
||||
// implicitly generated default constructor
|
||||
ASSERT_TRUE(entt::resolve<clazz>().construct());
|
||||
|
||||
entt::meta_reset("class"_hs);
|
||||
|
||||
ASSERT_FALSE(entt::resolve("class"_hs));
|
||||
ASSERT_NE(entt::resolve<clazz>().id(), "class"_hs);
|
||||
ASSERT_FALSE(entt::resolve<clazz>().data("value"_hs));
|
||||
ASSERT_FALSE((entt::resolve<clazz>().construct(derived{}, clazz{})));
|
||||
// implicitly generated default constructor is not cleared
|
||||
ASSERT_TRUE(entt::resolve<clazz>().construct());
|
||||
|
||||
entt::meta_factory<clazz>{}.type("class"_hs);
|
||||
|
||||
ASSERT_TRUE(entt::resolve("class"_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("class"_hs));
|
||||
ASSERT_TRUE(entt::resolve("overloaded_func"_hs));
|
||||
ASSERT_TRUE(entt::resolve("double"_hs));
|
||||
|
||||
entt::meta_reset();
|
||||
|
||||
ASSERT_FALSE(entt::resolve("class"_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>();
|
||||
concrete instance;
|
||||
|
||||
ASSERT_EQ(type.info(), entt::type_id<abstract>());
|
||||
ASSERT_EQ(instance.base::value, 'c');
|
||||
ASSERT_EQ(instance.value, 3);
|
||||
|
||||
type.func("func"_hs).invoke(instance, 2);
|
||||
|
||||
ASSERT_EQ(instance.base::value, 'c');
|
||||
ASSERT_EQ(instance.value, 2);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, EnumAndNamedConstants) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto type = entt::resolve<property_type>();
|
||||
|
||||
ASSERT_TRUE(type.data("value"_hs));
|
||||
ASSERT_TRUE(type.data("other"_hs));
|
||||
|
||||
ASSERT_EQ(type.data("value"_hs).type(), type);
|
||||
ASSERT_EQ(type.data("other"_hs).type(), type);
|
||||
|
||||
ASSERT_EQ(type.data("value"_hs).get({}).cast<property_type>(), property_type::value);
|
||||
ASSERT_EQ(type.data("other"_hs).get({}).cast<property_type>(), property_type::other);
|
||||
|
||||
ASSERT_FALSE(type.data("value"_hs).set({}, property_type::other));
|
||||
ASSERT_FALSE(type.data("other"_hs).set({}, property_type::value));
|
||||
|
||||
ASSERT_EQ(type.data("value"_hs).get({}).cast<property_type>(), property_type::value);
|
||||
ASSERT_EQ(type.data("other"_hs).get({}).cast<property_type>(), property_type::other);
|
||||
}
|
||||
|
||||
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({}, 128u));
|
||||
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>(), 128u);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, Variables) {
|
||||
using namespace entt::literals;
|
||||
|
||||
auto p_data = entt::resolve<property_type>().data("var"_hs);
|
||||
auto d_data = entt::resolve("double"_hs).data("var"_hs);
|
||||
|
||||
property_type prop{property_type::value};
|
||||
double value = 3.;
|
||||
|
||||
p_data.set(prop, property_type::other);
|
||||
d_data.set(value, 3.);
|
||||
|
||||
ASSERT_EQ(p_data.get(prop).cast<property_type>(), property_type::other);
|
||||
ASSERT_EQ(d_data.get(value).cast<double>(), 3.);
|
||||
ASSERT_EQ(prop, property_type::other);
|
||||
ASSERT_EQ(value, 3.);
|
||||
}
|
||||
|
||||
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>();
|
||||
entt::meta_reset<derived>();
|
||||
entt::meta_reset<abstract>();
|
||||
entt::meta_reset<concrete>();
|
||||
entt::meta_reset<overloaded_func>();
|
||||
entt::meta_reset<property_type>();
|
||||
entt::meta_reset<clazz>();
|
||||
|
||||
ASSERT_FALSE(entt::resolve("double"_hs));
|
||||
ASSERT_FALSE(entt::resolve("base"_hs));
|
||||
ASSERT_FALSE(entt::resolve("derived"_hs));
|
||||
ASSERT_FALSE(entt::resolve("class"_hs));
|
||||
|
||||
ASSERT_TRUE(entt::internal::meta_context::from(entt::locator<entt::meta_ctx>::value_or()).value.empty());
|
||||
|
||||
// implicitly generated default constructor is not cleared
|
||||
ASSERT_TRUE(entt::resolve<clazz>().construct());
|
||||
ASSERT_FALSE(entt::resolve<clazz>().data("value"_hs));
|
||||
ASSERT_FALSE(entt::resolve<clazz>().func("member"_hs));
|
||||
|
||||
entt::meta_factory<double>{}.type("double"_hs);
|
||||
entt::meta_any any{3.};
|
||||
|
||||
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_factory<base>{}
|
||||
.traits(test::meta_traits::one)
|
||||
.custom<int>(3)
|
||||
// this should not overwrite traits and custom data
|
||||
.type("base"_hs);
|
||||
|
||||
// this should not overwrite traits and custom data
|
||||
[[maybe_unused]] const entt::meta_factory<base> factory{};
|
||||
|
||||
ASSERT_EQ(entt::resolve<base>().traits<test::meta_traits>(), test::meta_traits::one);
|
||||
ASSERT_NE(static_cast<const int *>(entt::resolve("base"_hs).custom()), nullptr);
|
||||
}
|
||||
|
||||
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_factory<double>{}
|
||||
.type("real"_hs)
|
||||
.traits(test::meta_traits::one)
|
||||
.custom<int>(3);
|
||||
|
||||
// this should not overwrite traits and custom data
|
||||
entt::meta_factory<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));
|
||||
|
||||
ASSERT_EQ(entt::resolve<double>().traits<test::meta_traits>(), test::meta_traits::one);
|
||||
ASSERT_NE(static_cast<const int *>(entt::resolve<double>().custom()), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(MetaType, NameCollision) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_NO_THROW(entt::meta_factory<clazz>{}.type("class"_hs));
|
||||
ASSERT_TRUE(entt::resolve("class"_hs));
|
||||
|
||||
ASSERT_NO_THROW(entt::meta_factory<clazz>{}.type("quux"_hs));
|
||||
ASSERT_FALSE(entt::resolve("class"_hs));
|
||||
ASSERT_TRUE(entt::resolve("quux"_hs));
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(MetaTypeDeathTest, NameCollision) {
|
||||
using namespace entt::literals;
|
||||
|
||||
ASSERT_DEATH(entt::meta_factory<clazz>{}.type("abstract"_hs), "");
|
||||
}
|
||||
272
lib/All/entt/test/entt/meta/meta_utility.cpp
Normal file
272
lib/All/entt/test/entt/meta/meta_utility.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_traits.hpp>
|
||||
#include <entt/meta/meta.hpp>
|
||||
#include <entt/meta/policy.hpp>
|
||||
#include <entt/meta/resolve.hpp>
|
||||
#include <entt/meta/utility.hpp>
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/empty.h"
|
||||
|
||||
struct clazz {
|
||||
void setter(int iv) {
|
||||
member = iv;
|
||||
}
|
||||
|
||||
[[nodiscard]] int getter() const {
|
||||
return member;
|
||||
}
|
||||
|
||||
static void static_setter(clazz &instance, int iv) {
|
||||
instance.member = iv;
|
||||
}
|
||||
|
||||
[[nodiscard]] static int static_getter(const clazz &instance) {
|
||||
return instance.member;
|
||||
}
|
||||
|
||||
static void reset_value() {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] static int get_value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] static clazz factory(int iv) {
|
||||
clazz instance{};
|
||||
instance.member = iv;
|
||||
return instance;
|
||||
}
|
||||
|
||||
int member{};
|
||||
const int cmember{}; // NOLINT
|
||||
inline static int value{}; // NOLINT
|
||||
inline static const int cvalue{}; // NOLINT
|
||||
inline static int arr[3u]{}; // NOLINT
|
||||
};
|
||||
|
||||
struct MetaUtility: ::testing::Test {
|
||||
void SetUp() override {
|
||||
clazz::value = 0;
|
||||
}
|
||||
};
|
||||
|
||||
using MetaUtilityDeathTest = MetaUtility;
|
||||
|
||||
TEST_F(MetaUtility, MetaDispatch) {
|
||||
int value = 2;
|
||||
|
||||
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>(), 2);
|
||||
ASSERT_EQ(as_ref.cast<int>(), 2);
|
||||
ASSERT_EQ(as_cref.cast<int>(), 2);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaDispatchMetaAny) {
|
||||
entt::meta_any any{2};
|
||||
|
||||
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>(), 2);
|
||||
ASSERT_EQ(from_const_any.cast<int>(), 2);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaDispatchMetaAnyAsRef) {
|
||||
entt::meta_any any{2};
|
||||
|
||||
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>(), 2);
|
||||
ASSERT_EQ(from_const_any.cast<int>(), 2);
|
||||
}
|
||||
|
||||
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), 4)));
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::static_setter>(invalid, 4)));
|
||||
ASSERT_TRUE((entt::meta_setter<clazz, &clazz::static_setter>(instance, 4)));
|
||||
ASSERT_EQ(instance.member, 4);
|
||||
|
||||
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, 8)));
|
||||
ASSERT_TRUE((entt::meta_setter<clazz, &clazz::member>(instance, 8)));
|
||||
ASSERT_EQ(instance.member, 8);
|
||||
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::cmember>(instance, 8)));
|
||||
ASSERT_FALSE((entt::meta_setter<clazz, &clazz::cmember>(invalid, 8)));
|
||||
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>(entt::meta_any{}.context(), instance)).cast<int>(), 0);
|
||||
|
||||
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::getter>(invalid)));
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::getter>(entt::meta_any{}.context(), instance)).cast<int>(), 0);
|
||||
|
||||
ASSERT_FALSE((entt::meta_getter<clazz, &clazz::member>(invalid)));
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::member>(entt::meta_any{}.context(), 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>(entt::meta_any{}.context(), 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>(entt::meta_any{}.context(), instance)));
|
||||
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::value>(invalid)).cast<int>(), 0);
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::value>(entt::meta_any{}.context(), instance)).cast<int>(), 0);
|
||||
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::cvalue>(invalid)).cast<int>(), 0);
|
||||
ASSERT_EQ((entt::meta_getter<clazz, &clazz::cvalue>(entt::meta_any{}.context(), instance)).cast<int>(), 0);
|
||||
|
||||
ASSERT_EQ((entt::meta_getter<clazz, 1>(invalid)).cast<int>(), 1);
|
||||
ASSERT_EQ((entt::meta_getter<clazz, 1>(entt::meta_any{}.context(), instance)).cast<int>(), 1);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaInvokeWithCandidate) {
|
||||
std::array args{entt::meta_any{clazz{}}, entt::meta_any{4}};
|
||||
|
||||
clazz::value = 3;
|
||||
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz>({}, &clazz::setter, std::next(args.data()))));
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz>(entt::meta_any{}.context(), {}, &clazz::getter, nullptr)));
|
||||
|
||||
ASSERT_TRUE((entt::meta_invoke<clazz>(args[0u], &clazz::setter, std::next(args.data()))));
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz>(entt::meta_any{}.context(), args[0u], &clazz::setter, args.data())));
|
||||
ASSERT_EQ((entt::meta_invoke<clazz>(args[0u], &clazz::getter, nullptr)).cast<int>(), 4);
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz>(entt::meta_any{}.context(), args[1u], &clazz::getter, nullptr)));
|
||||
|
||||
ASSERT_EQ((entt::meta_invoke<clazz>({}, &clazz::get_value, nullptr)).cast<int>(), 3);
|
||||
ASSERT_TRUE((entt::meta_invoke<clazz>(entt::meta_any{}.context(), {}, &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<test::empty>({}, setter, std::next(args.data())));
|
||||
ASSERT_EQ(entt::meta_invoke<test::empty>(entt::meta_any{}.context(), {}, getter, std::next(args.data())).cast<int>(), 6);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaInvoke) {
|
||||
std::array args{entt::meta_any{clazz{}}, entt::meta_any{4}};
|
||||
|
||||
clazz::value = 3;
|
||||
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::setter>({}, std::next(args.data()))));
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::getter>(entt::meta_any{}.context(), {}, nullptr)));
|
||||
|
||||
ASSERT_TRUE((entt::meta_invoke<clazz, &clazz::setter>(args[0u], std::next(args.data()))));
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::setter>(entt::meta_any{}.context(), args[0u], args.data())));
|
||||
ASSERT_EQ((entt::meta_invoke<clazz, &clazz::getter>(args[0u], nullptr)).cast<int>(), 4);
|
||||
ASSERT_FALSE((entt::meta_invoke<clazz, &clazz::getter>(entt::meta_any{}.context(), args[1u], nullptr)));
|
||||
|
||||
ASSERT_EQ((entt::meta_invoke<clazz, &clazz::get_value>({}, nullptr)).cast<int>(), 3);
|
||||
ASSERT_TRUE((entt::meta_invoke<clazz, &clazz::reset_value>(entt::meta_any{}.context(), {}, nullptr)));
|
||||
ASSERT_EQ(args[0u].cast<clazz &>().value, 0);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaConstructArgsOnly) {
|
||||
std::array args{entt::meta_any{clazz{}}, entt::meta_any{4}};
|
||||
const auto any = entt::meta_construct<clazz, int>(std::next(args.data()));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE((entt::meta_construct<clazz, int>(args.data())));
|
||||
ASSERT_EQ(any.cast<const clazz &>().member, 4);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaConstructWithCandidate) {
|
||||
std::array args{entt::meta_any{clazz{}}, entt::meta_any{4}};
|
||||
const auto any = entt::meta_construct<clazz>(&clazz::factory, std::next(args.data()));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE((entt::meta_construct<clazz>(&clazz::factory, args.data())));
|
||||
ASSERT_EQ(any.cast<const clazz &>().member, 4);
|
||||
|
||||
ASSERT_EQ(args[0u].cast<const clazz &>().member, 0);
|
||||
ASSERT_TRUE((entt::meta_construct<clazz>(&clazz::static_setter, args.data())));
|
||||
ASSERT_EQ(args[0u].cast<const clazz &>().member, 4);
|
||||
|
||||
const auto setter = [](int &value) { value = 3; };
|
||||
const auto builder = [](int value) { return value * 2; };
|
||||
|
||||
ASSERT_TRUE(entt::meta_construct<test::empty>(setter, std::next(args.data())));
|
||||
ASSERT_EQ(entt::meta_construct<test::empty>(builder, std::next(args.data())).cast<int>(), 6);
|
||||
}
|
||||
|
||||
TEST_F(MetaUtility, MetaConstruct) {
|
||||
std::array args{entt::meta_any{clazz{}}, entt::meta_any{4}};
|
||||
const auto any = entt::meta_construct<clazz, &clazz::factory>(std::next(args.data()));
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE((entt::meta_construct<clazz, &clazz::factory>(args.data())));
|
||||
ASSERT_EQ(any.cast<const clazz &>().member, 4);
|
||||
|
||||
ASSERT_EQ(args[0u].cast<const clazz &>().member, 0);
|
||||
ASSERT_TRUE((entt::meta_construct<clazz, &clazz::static_setter>(args.data())));
|
||||
ASSERT_EQ(args[0u].cast<const clazz &>().member, 4);
|
||||
}
|
||||
498
lib/All/entt/test/entt/poly/poly.cpp
Normal file
498
lib/All/entt/test/entt/poly/poly.cpp
Normal file
@@ -0,0 +1,498 @@
|
||||
#include <array>
|
||||
#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"
|
||||
#include "../../common/linter.hpp"
|
||||
|
||||
template<typename Base>
|
||||
struct common_type: Base {
|
||||
void incr() {
|
||||
constexpr auto member_index = 0u;
|
||||
entt::poly_call<member_index>(*this);
|
||||
}
|
||||
|
||||
void set(int iv) {
|
||||
constexpr auto member_index = 1u;
|
||||
entt::poly_call<member_index>(*this, iv);
|
||||
}
|
||||
|
||||
[[nodiscard]] int get() const {
|
||||
constexpr auto member_index = 2u;
|
||||
return static_cast<int>(entt::poly_call<member_index>(*this));
|
||||
}
|
||||
|
||||
void decr() {
|
||||
constexpr auto member_index = 3u;
|
||||
entt::poly_call<member_index>(*this);
|
||||
}
|
||||
|
||||
[[nodiscard]] int mul(int iv) const {
|
||||
constexpr auto member_index = 4u;
|
||||
return static_cast<int>(entt::poly_call<member_index>(*this, iv));
|
||||
}
|
||||
|
||||
[[nodiscard]] int rand() const {
|
||||
constexpr auto member_index = 5u;
|
||||
return static_cast<int>(entt::poly_call<member_index>(*this));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct common_members {
|
||||
static void decr(Type &self) {
|
||||
self.set(self.get() - 1);
|
||||
}
|
||||
|
||||
[[nodiscard]] static double mul(const Type &self, double dv) {
|
||||
return dv * self.get();
|
||||
}
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename... Type>
|
||||
entt::type_list<Type...> as_type_list(const entt::type_list<Type...> &);
|
||||
|
||||
[[nodiscard]] int absolutely_random() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
[[nodiscard]] int three_is_a_magic_number() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
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 {
|
||||
[[nodiscard]] 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
|
||||
[[nodiscard]] int get() {
|
||||
return entt::poly_call<0>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using impl = entt::value_list<&Type::get>;
|
||||
};
|
||||
|
||||
struct DeducedDerived
|
||||
: entt::type_list<> {
|
||||
template<typename Base>
|
||||
struct type: Deduced::type<Base> {
|
||||
static constexpr auto base = Deduced::impl<Deduced::type<entt::poly_inspector>>::size;
|
||||
|
||||
int three_is_a_magic_number() {
|
||||
return entt::poly_call<base + 0>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using impl = entt::value_list_cat_t<typename Deduced::impl<Type>, entt::value_list<&three_is_a_magic_number>>;
|
||||
};
|
||||
|
||||
struct DefinedDerived
|
||||
: entt::type_list_cat_t<
|
||||
decltype(as_type_list(std::declval<Defined>())),
|
||||
entt::type_list<int()>> {
|
||||
template<typename Base>
|
||||
struct type: Defined::type<Base> {
|
||||
static constexpr auto base = Defined::impl<Defined::type<entt::poly_inspector>>::size;
|
||||
|
||||
int three_is_a_magic_number() {
|
||||
return entt::poly_call<base + 0>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using impl = entt::value_list_cat_t<typename Defined::impl<Type>, entt::value_list<&three_is_a_magic_number>>;
|
||||
};
|
||||
|
||||
struct impl {
|
||||
impl() = default;
|
||||
|
||||
impl(int iv)
|
||||
: value{iv} {}
|
||||
|
||||
void incr() {
|
||||
++value;
|
||||
}
|
||||
|
||||
void set(int iv) {
|
||||
value = iv;
|
||||
}
|
||||
|
||||
[[nodiscard]] 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, );
|
||||
|
||||
template<typename Type>
|
||||
struct PolyDerived: testing::Test {
|
||||
using type = entt::basic_poly<Type>;
|
||||
};
|
||||
|
||||
using PolyDerivedTypes = ::testing::Types<DeducedDerived, DefinedDerived>;
|
||||
|
||||
TYPED_TEST_SUITE(PolyDerived, PolyDerivedTypes, );
|
||||
|
||||
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(), absolutely_random());
|
||||
|
||||
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);
|
||||
test::is_initialized(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(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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_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) {
|
||||
constexpr auto alignment = alignof(over_aligned);
|
||||
using poly_type = typename TestFixture::template type<alignment, alignment>;
|
||||
|
||||
std::array<poly_type, 2u> sbo = {over_aligned{}, over_aligned{}};
|
||||
const auto *data = sbo[0].data();
|
||||
|
||||
// NOLINTBEGIN(*-reinterpret-cast)
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[0u].data()) % alignment) == 0u);
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[1u].data()) % alignment) == 0u);
|
||||
// NOLINTEND(*-reinterpret-cast)
|
||||
|
||||
std::swap(sbo[0], sbo[1]);
|
||||
|
||||
// NOLINTBEGIN(*-reinterpret-cast)
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[0u].data()) % alignment) == 0u);
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(sbo[1u].data()) % alignment) == 0u);
|
||||
// NOLINTEND(*-reinterpret-cast)
|
||||
|
||||
ASSERT_NE(data, sbo[1].data());
|
||||
}
|
||||
|
||||
TYPED_TEST(Poly, NoSboAlignment) {
|
||||
constexpr auto alignment = alignof(over_aligned);
|
||||
using poly_type = typename TestFixture::template type<alignment>;
|
||||
|
||||
std::array<poly_type, 2u> nosbo = {over_aligned{}, over_aligned{}};
|
||||
const auto *data = nosbo[0].data();
|
||||
|
||||
// NOLINTBEGIN(*-reinterpret-cast)
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[0u].data()) % alignment) == 0u);
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[1u].data()) % alignment) == 0u);
|
||||
// NOLINTEND(*-reinterpret-cast)
|
||||
|
||||
std::swap(nosbo[0], nosbo[1]);
|
||||
|
||||
// NOLINTBEGIN(*-reinterpret-cast)
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[0u].data()) % alignment) == 0u);
|
||||
ASSERT_TRUE((reinterpret_cast<std::uintptr_t>(nosbo[1u].data()) % alignment) == 0u);
|
||||
// NOLINTEND(*-reinterpret-cast)
|
||||
|
||||
ASSERT_EQ(data, nosbo[1].data());
|
||||
}
|
||||
|
||||
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(PolyDerived, InheritanceSupport) {
|
||||
using poly_type = typename TestFixture::type;
|
||||
|
||||
poly_type poly{impl{}};
|
||||
|
||||
ASSERT_EQ(poly->three_is_a_magic_number(), three_is_a_magic_number());
|
||||
}
|
||||
261
lib/All/entt/test/entt/process/process.cpp
Normal file
261
lib/All/entt/test/entt/process/process.cpp
Normal file
@@ -0,0 +1,261 @@
|
||||
#include <cstdint>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/process/process.hpp>
|
||||
#include "../../common/empty.h"
|
||||
|
||||
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;
|
||||
|
||||
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 != nullptr) {
|
||||
(*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<test::empty> 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<test::empty> 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<test::empty> 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) = 2;
|
||||
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, 2);
|
||||
}
|
||||
182
lib/All/entt/test/entt/process/scheduler.cpp
Normal file
182
lib/All/entt/test/entt/process/scheduler.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/process/process.hpp>
|
||||
#include <entt/process/scheduler.hpp>
|
||||
|
||||
struct foo_process: entt::process<foo_process, entt::scheduler::delta_type> {
|
||||
foo_process(std::function<void()> upd, std::function<void()> abort)
|
||||
: on_update{std::move(upd)}, on_aborted{std::move(abort)} {}
|
||||
|
||||
void update(delta_type, void *) const {
|
||||
on_update();
|
||||
}
|
||||
|
||||
void aborted() const {
|
||||
on_aborted();
|
||||
}
|
||||
|
||||
std::function<void()> on_update;
|
||||
std::function<void()> on_aborted;
|
||||
};
|
||||
|
||||
struct succeeded_process: entt::process<succeeded_process, entt::scheduler::delta_type> {
|
||||
void update(delta_type, void *data) {
|
||||
++static_cast<std::pair<int, int> *>(data)->first;
|
||||
succeed();
|
||||
}
|
||||
};
|
||||
|
||||
struct failed_process: entt::process<failed_process, entt::scheduler::delta_type> {
|
||||
void update(delta_type, void *data) {
|
||||
++static_cast<std::pair<int, int> *>(data)->second;
|
||||
fail();
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Scheduler, Functionalities) {
|
||||
entt::scheduler scheduler{};
|
||||
entt::scheduler other{std::move(scheduler)};
|
||||
|
||||
scheduler = std::move(other);
|
||||
|
||||
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(Scheduler, Swap) {
|
||||
entt::scheduler scheduler{};
|
||||
entt::scheduler other{};
|
||||
int counter{};
|
||||
|
||||
scheduler.attach([&counter](auto &&...) { ++counter; });
|
||||
|
||||
ASSERT_EQ(scheduler.size(), 1u);
|
||||
ASSERT_EQ(other.size(), 0u);
|
||||
ASSERT_EQ(counter, 0);
|
||||
|
||||
scheduler.update({});
|
||||
|
||||
ASSERT_EQ(counter, 1);
|
||||
|
||||
scheduler.swap(other);
|
||||
scheduler.update({});
|
||||
|
||||
ASSERT_EQ(scheduler.size(), 0u);
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
ASSERT_EQ(counter, 1);
|
||||
|
||||
other.update({});
|
||||
|
||||
ASSERT_EQ(counter, 2);
|
||||
}
|
||||
|
||||
TEST(Scheduler, Then) {
|
||||
entt::scheduler scheduler{};
|
||||
std::pair<int, int> counter{};
|
||||
|
||||
scheduler
|
||||
// failing process with successor
|
||||
.attach<succeeded_process>()
|
||||
.then<succeeded_process>()
|
||||
.then<failed_process>()
|
||||
.then<succeeded_process>()
|
||||
// failing process without successor
|
||||
.attach<succeeded_process>()
|
||||
.then<succeeded_process>()
|
||||
.then<failed_process>()
|
||||
// non-failing process
|
||||
.attach<succeeded_process>()
|
||||
.then<succeeded_process>();
|
||||
|
||||
while(!scheduler.empty()) {
|
||||
scheduler.update(0, &counter);
|
||||
}
|
||||
|
||||
ASSERT_EQ(counter.first, 6u);
|
||||
ASSERT_EQ(counter.second, 2u);
|
||||
}
|
||||
|
||||
TEST(Scheduler, Functor) {
|
||||
entt::scheduler 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(Scheduler, SpawningProcess) {
|
||||
entt::scheduler scheduler{};
|
||||
std::pair<int, int> counter{};
|
||||
|
||||
scheduler.attach([&scheduler](auto, void *, auto resolve, auto) {
|
||||
scheduler.attach<succeeded_process>().then<failed_process>();
|
||||
resolve();
|
||||
});
|
||||
|
||||
while(!scheduler.empty()) {
|
||||
scheduler.update(0, &counter);
|
||||
}
|
||||
|
||||
ASSERT_EQ(counter.first, 1u);
|
||||
ASSERT_EQ(counter.second, 1u);
|
||||
}
|
||||
|
||||
TEST(Scheduler, CustomAllocator) {
|
||||
const std::allocator<void> allocator{};
|
||||
entt::scheduler scheduler{allocator};
|
||||
|
||||
ASSERT_EQ(scheduler.get_allocator(), allocator);
|
||||
ASSERT_FALSE(scheduler.get_allocator() != allocator);
|
||||
|
||||
scheduler.attach([](auto &&...) {});
|
||||
const decltype(scheduler) other{std::move(scheduler), allocator};
|
||||
|
||||
ASSERT_EQ(other.size(), 1u);
|
||||
}
|
||||
187
lib/All/entt/test/entt/resource/resource.cpp
Normal file
187
lib/All/entt/test/entt/resource/resource.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/type_info.hpp>
|
||||
#include <entt/resource/resource.hpp>
|
||||
#include "../../common/linter.hpp"
|
||||
|
||||
struct base {
|
||||
virtual ~base() = default;
|
||||
|
||||
[[nodiscard]] virtual const entt::type_info &type() const noexcept {
|
||||
return entt::type_id<base>();
|
||||
}
|
||||
};
|
||||
|
||||
struct derived: base {
|
||||
[[nodiscard]] 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) {
|
||||
const 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);
|
||||
|
||||
copy.reset(std::make_shared<derived>());
|
||||
|
||||
ASSERT_TRUE(copy);
|
||||
ASSERT_TRUE(move);
|
||||
ASSERT_NE(copy, move);
|
||||
|
||||
move.reset();
|
||||
|
||||
ASSERT_TRUE(copy);
|
||||
ASSERT_FALSE(move);
|
||||
ASSERT_NE(copy, move);
|
||||
}
|
||||
|
||||
TEST(Resource, Swap) {
|
||||
entt::resource<int> resource{};
|
||||
entt::resource<int> other{};
|
||||
|
||||
ASSERT_FALSE(resource);
|
||||
ASSERT_FALSE(other);
|
||||
|
||||
resource.swap(other);
|
||||
|
||||
ASSERT_FALSE(resource);
|
||||
ASSERT_FALSE(other);
|
||||
|
||||
resource.reset(std::make_shared<int>(1));
|
||||
|
||||
ASSERT_TRUE(resource);
|
||||
ASSERT_EQ(*resource, 1);
|
||||
ASSERT_FALSE(other);
|
||||
|
||||
resource.swap(other);
|
||||
|
||||
ASSERT_FALSE(resource);
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_EQ(*other, 1);
|
||||
}
|
||||
|
||||
TEST(Resource, DerivedToBase) {
|
||||
const 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};
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(*resource), derived &>();
|
||||
testing::StaticAssertTypeEq<decltype(*entt::resource<const derived>{other}), const derived &>();
|
||||
testing::StaticAssertTypeEq<decltype(*std::as_const(resource)), derived &>();
|
||||
|
||||
entt::resource<const derived> copy{resource};
|
||||
entt::resource<const derived> move{std::move(other)};
|
||||
|
||||
test::is_initialized(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(), 3);
|
||||
|
||||
ASSERT_TRUE(move);
|
||||
ASSERT_EQ(move, resource);
|
||||
ASSERT_NE(move, entt::resource<derived>{});
|
||||
ASSERT_EQ(move.handle().use_count(), 3);
|
||||
|
||||
copy = resource;
|
||||
move = std::move(resource);
|
||||
test::is_initialized(resource);
|
||||
|
||||
ASSERT_FALSE(resource);
|
||||
ASSERT_FALSE(other);
|
||||
|
||||
ASSERT_TRUE(copy);
|
||||
ASSERT_TRUE(move);
|
||||
ASSERT_EQ(copy.handle().use_count(), 2);
|
||||
}
|
||||
|
||||
TEST(Resource, DynamicResourceHandleCast) {
|
||||
const entt::resource<derived> resource{std::make_shared<derived>()};
|
||||
entt::resource<const base> other = resource;
|
||||
|
||||
ASSERT_TRUE(other);
|
||||
ASSERT_EQ(resource.handle().use_count(), 2);
|
||||
ASSERT_EQ(resource, other);
|
||||
|
||||
entt::resource<const derived> cast = dynamic_resource_cast<const derived>(other);
|
||||
|
||||
ASSERT_TRUE(cast);
|
||||
ASSERT_EQ(resource.handle().use_count(), 3);
|
||||
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(), 1);
|
||||
}
|
||||
|
||||
TEST(Resource, Comparison) {
|
||||
const entt::resource<derived> resource{std::make_shared<derived>()};
|
||||
const 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
lib/All/entt/test/entt/resource/resource_cache.cpp
Normal file
428
lib/All/entt/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/container/dense_map.hpp>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/core/iterator.hpp>
|
||||
#include <entt/resource/cache.hpp>
|
||||
#include <entt/resource/loader.hpp>
|
||||
#include <entt/resource/resource.hpp>
|
||||
#include "../../common/empty.h"
|
||||
#include "../../common/linter.hpp"
|
||||
#include "../../common/throwing_allocator.hpp"
|
||||
|
||||
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()(test::other_empty, Func &&func) const {
|
||||
return std::forward<Func>(func)();
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
result_type operator()(test::empty) const {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
TEST(ResourceCache, Functionalities) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<int> cache;
|
||||
|
||||
ASSERT_NO_THROW([[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, 2);
|
||||
|
||||
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, 2u);
|
||||
|
||||
entt::resource_cache<int> temp{cache, cache.get_allocator()};
|
||||
const 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, 3u);
|
||||
|
||||
entt::resource_cache<std::size_t> other{cache};
|
||||
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
ASSERT_TRUE(other.contains("resource"_hs));
|
||||
|
||||
cache.load("foo"_hs, 2u);
|
||||
cache.load("bar"_hs, 1u);
|
||||
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], 3u);
|
||||
ASSERT_EQ(other["foo"_hs], 2u);
|
||||
ASSERT_EQ(other["bar"_hs], 1u);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, Move) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<std::size_t> cache;
|
||||
cache.load("resource"_hs, 3u);
|
||||
|
||||
entt::resource_cache<std::size_t> other{std::move(cache)};
|
||||
|
||||
test::is_initialized(cache);
|
||||
|
||||
ASSERT_TRUE(cache.empty());
|
||||
ASSERT_TRUE(other.contains("resource"_hs));
|
||||
|
||||
cache = other;
|
||||
cache.load("foo"_hs, 2u);
|
||||
cache.load("bar"_hs, 1u);
|
||||
other.load("quux"_hs, 0u);
|
||||
other = std::move(cache);
|
||||
test::is_initialized(cache);
|
||||
|
||||
ASSERT_TRUE(cache.empty());
|
||||
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], 3u);
|
||||
ASSERT_EQ(other["foo"_hs], 2u);
|
||||
ASSERT_EQ(other["bar"_hs], 1u);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, Iterator) {
|
||||
using namespace entt::literals;
|
||||
|
||||
using iterator = typename entt::resource_cache<int>::iterator;
|
||||
|
||||
testing::StaticAssertTypeEq<iterator::value_type, std::pair<entt::id_type, entt::resource<int>>>();
|
||||
testing::StaticAssertTypeEq<iterator::pointer, entt::input_iterator_pointer<std::pair<entt::id_type, entt::resource<int>>>>();
|
||||
testing::StaticAssertTypeEq<iterator::reference, std::pair<entt::id_type, entt::resource<int>>>();
|
||||
|
||||
entt::resource_cache<int> cache;
|
||||
cache.load("resource"_hs, 2);
|
||||
|
||||
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;
|
||||
|
||||
testing::StaticAssertTypeEq<iterator::value_type, std::pair<entt::id_type, entt::resource<const int>>>();
|
||||
testing::StaticAssertTypeEq<iterator::pointer, entt::input_iterator_pointer<std::pair<entt::id_type, entt::resource<const int>>>>();
|
||||
testing::StaticAssertTypeEq<iterator::reference, std::pair<entt::id_type, entt::resource<const int>>>();
|
||||
|
||||
entt::resource_cache<int> cache;
|
||||
cache.load("resource"_hs, 2);
|
||||
|
||||
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, 2);
|
||||
|
||||
const typename entt::resource_cache<int>::iterator it = cache.begin();
|
||||
typename entt::resource_cache<int>::const_iterator cit = it;
|
||||
|
||||
testing::StaticAssertTypeEq<decltype(*it), std::pair<entt::id_type, entt::resource<int>>>();
|
||||
testing::StaticAssertTypeEq<decltype(*cit), std::pair<entt::id_type, entt::resource<const int>>>();
|
||||
|
||||
ASSERT_EQ(it->first, "resource"_hs);
|
||||
ASSERT_EQ((*it).second, 2);
|
||||
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) {
|
||||
constexpr std::size_t resource_count = 5u;
|
||||
entt::resource_cache<std::size_t> cache;
|
||||
|
||||
for(std::size_t next{}; next < resource_count; ++next) {
|
||||
cache.load(static_cast<entt::id_type>(next), next);
|
||||
}
|
||||
|
||||
ASSERT_EQ(cache.size(), resource_count);
|
||||
|
||||
for(std::size_t next{}; next < resource_count; ++next) {
|
||||
ASSERT_TRUE(cache.contains(static_cast<entt::id_type>(next)));
|
||||
}
|
||||
|
||||
auto it = cache.erase(++cache.begin());
|
||||
it = cache.erase(it, it + 1);
|
||||
|
||||
ASSERT_EQ((--cache.end())->first, 2u);
|
||||
ASSERT_EQ(cache.erase(2u), 1u);
|
||||
ASSERT_EQ(cache.erase(2u), 0u);
|
||||
|
||||
ASSERT_EQ(cache.size(), 2u);
|
||||
|
||||
ASSERT_EQ(it, ++cache.begin());
|
||||
ASSERT_EQ(cache.begin()->first, 0u);
|
||||
ASSERT_EQ((--cache.end())->first, 3u);
|
||||
|
||||
for(std::size_t next{}; next < resource_count; ++next) {
|
||||
if(next == 1u || next == 2u || next == 4u) {
|
||||
ASSERT_FALSE(cache.contains(static_cast<entt::id_type>(next)));
|
||||
} else {
|
||||
ASSERT_TRUE(cache.contains(static_cast<entt::id_type>(next)));
|
||||
}
|
||||
}
|
||||
|
||||
cache.erase(cache.begin(), cache.end());
|
||||
|
||||
for(std::size_t next{}; next < resource_count; ++next) {
|
||||
ASSERT_FALSE(cache.contains(static_cast<entt::id_type>(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, 1);
|
||||
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
ASSERT_EQ(std::as_const(cache)["resource"_hs], 1);
|
||||
ASSERT_EQ(cache["resource"_hs], 1);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, LoaderDispatching) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<int, loader<int>> cache;
|
||||
cache.force_load("resource"_hs, 1);
|
||||
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
ASSERT_EQ(cache["resource"_hs], 1);
|
||||
|
||||
cache.force_load("resource"_hs, test::other_empty{}, []() { return std::make_shared<int>(2); });
|
||||
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
ASSERT_EQ(cache["resource"_hs], 2);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, BrokenLoader) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<int, loader<int>> cache;
|
||||
cache.load("resource"_hs, test::empty{});
|
||||
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
ASSERT_FALSE(cache["resource"_hs]);
|
||||
|
||||
cache.force_load("resource"_hs, 2);
|
||||
|
||||
ASSERT_TRUE(cache.contains("resource"_hs));
|
||||
ASSERT_TRUE(cache["resource"_hs]);
|
||||
}
|
||||
|
||||
TEST(ResourceCache, ThrowingAllocator) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::resource_cache<std::size_t, entt::resource_loader<std::size_t>, test::throwing_allocator<std::size_t>> cache{};
|
||||
cache.get_allocator().throw_counter<entt::internal::dense_map_node<entt::id_type, std::shared_ptr<std::size_t>>>(0u);
|
||||
|
||||
ASSERT_THROW(cache.load("resource"_hs), test::throwing_allocator_exception);
|
||||
ASSERT_FALSE(cache.contains("resource"_hs));
|
||||
|
||||
cache.get_allocator().throw_counter<entt::internal::dense_map_node<entt::id_type, std::shared_ptr<std::size_t>>>(0u);
|
||||
|
||||
ASSERT_THROW(cache.force_load("resource"_hs), test::throwing_allocator_exception);
|
||||
ASSERT_FALSE(cache.contains("resource"_hs));
|
||||
}
|
||||
13
lib/All/entt/test/entt/resource/resource_loader.cpp
Normal file
13
lib/All/entt/test/entt/resource/resource_loader.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <memory>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/resource/loader.hpp>
|
||||
|
||||
TEST(ResourceLoader, Functionalities) {
|
||||
using loader_type = entt::resource_loader<int>;
|
||||
const auto resource = loader_type{}(4);
|
||||
|
||||
testing::StaticAssertTypeEq<typename loader_type::result_type, std::shared_ptr<int>>();
|
||||
|
||||
ASSERT_TRUE(resource);
|
||||
ASSERT_EQ(*resource, 4);
|
||||
}
|
||||
466
lib/All/entt/test/entt/signal/delegate.cpp
Normal file
466
lib/All/entt/test/entt/signal/delegate.cpp
Normal file
@@ -0,0 +1,466 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/signal/delegate.hpp>
|
||||
#include "../../common/config.h"
|
||||
|
||||
int power_of_two(const int &iv) {
|
||||
return iv * iv;
|
||||
}
|
||||
|
||||
int sum_with_ref(const int &iv, int jv) {
|
||||
return iv + jv;
|
||||
}
|
||||
|
||||
int sum_with_ptr(const int *iv, int jv) {
|
||||
return (*iv) + jv;
|
||||
}
|
||||
|
||||
int non_const_reference(int &iv) {
|
||||
return iv *= iv;
|
||||
}
|
||||
|
||||
int move_only_type(std::unique_ptr<int> ptr) {
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
struct delegate_functor {
|
||||
int operator()(int iv) {
|
||||
return iv + iv;
|
||||
}
|
||||
|
||||
[[nodiscard]] int mul(int iv) const {
|
||||
return iv * data_member;
|
||||
}
|
||||
|
||||
static const int static_value = 3;
|
||||
// NOLINTNEXTLINE(*-avoid-const-or-ref-data-members)
|
||||
const int data_member = 4;
|
||||
};
|
||||
|
||||
struct const_nonconst_noexcept {
|
||||
void f() {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void g() noexcept {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void h() const {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void i() const noexcept {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
int u{};
|
||||
// NOLINTNEXTLINE(*-avoid-const-or-ref-data-members)
|
||||
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<&power_of_two>();
|
||||
mf_del.connect<&delegate_functor::operator()>(functor);
|
||||
lf_del.connect([](const void *ptr, int value) { return static_cast<const delegate_functor *>(ptr)->mul(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), 12);
|
||||
|
||||
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(4), "");
|
||||
ASSERT_DEATH(std::as_const(del)(4), "");
|
||||
}
|
||||
|
||||
TEST(Delegate, DataMembers) {
|
||||
entt::delegate<double()> delegate;
|
||||
delegate_functor functor;
|
||||
|
||||
delegate.connect<&delegate_functor::data_member>(functor);
|
||||
|
||||
ASSERT_EQ(delegate(), 4);
|
||||
}
|
||||
|
||||
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<&power_of_two>();
|
||||
|
||||
ASSERT_EQ(lhs, entt::delegate<int(int)>{entt::connect_arg<&power_of_two>});
|
||||
ASSERT_TRUE(lhs != rhs);
|
||||
ASSERT_FALSE(lhs == rhs);
|
||||
ASSERT_NE(lhs, rhs);
|
||||
|
||||
rhs.connect<&power_of_two>();
|
||||
|
||||
ASSERT_EQ(rhs, entt::delegate<int(int)>{entt::connect_arg<&power_of_two>});
|
||||
ASSERT_FALSE(lhs != rhs);
|
||||
ASSERT_TRUE(lhs == rhs);
|
||||
ASSERT_EQ(lhs, rhs);
|
||||
|
||||
lhs.connect<&sum_with_ref>(value);
|
||||
|
||||
ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&sum_with_ref>, value}));
|
||||
ASSERT_TRUE(lhs != rhs);
|
||||
ASSERT_FALSE(lhs == rhs);
|
||||
ASSERT_NE(lhs, rhs);
|
||||
|
||||
rhs.connect<&sum_with_ref>(value);
|
||||
|
||||
ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&sum_with_ref>, value}));
|
||||
ASSERT_FALSE(lhs != rhs);
|
||||
ASSERT_TRUE(lhs == rhs);
|
||||
ASSERT_EQ(lhs, rhs);
|
||||
|
||||
lhs.connect<&sum_with_ptr>(&value);
|
||||
|
||||
ASSERT_EQ(lhs, (entt::delegate<int(int)>{entt::connect_arg<&sum_with_ptr>, &value}));
|
||||
ASSERT_TRUE(lhs != rhs);
|
||||
ASSERT_FALSE(lhs == rhs);
|
||||
ASSERT_NE(lhs, rhs);
|
||||
|
||||
rhs.connect<&sum_with_ptr>(&value);
|
||||
|
||||
ASSERT_EQ(rhs, (entt::delegate<int(int)>{entt::connect_arg<&sum_with_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_EQ(lhs.target(), rhs.target());
|
||||
ASSERT_EQ(lhs.data(), rhs.data());
|
||||
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_EQ(lhs.target(), rhs.target());
|
||||
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)->mul(val) * val; }, &functor);
|
||||
|
||||
ASSERT_NE(lhs, (entt::delegate<int(int)>{[](const void *, int val) { return val + val; }, &functor}));
|
||||
ASSERT_NE(lhs.target(), rhs.target());
|
||||
ASSERT_EQ(lhs.data(), rhs.data());
|
||||
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)->mul(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;
|
||||
|
||||
const entt::delegate plain_func{entt::connect_arg<&power_of_two>};
|
||||
const entt::delegate sum_func_with_ref{entt::connect_arg<&sum_with_ref>, value};
|
||||
const entt::delegate sum_func_with_const_ref{entt::connect_arg<&sum_with_ref>, std::as_const(value)};
|
||||
const entt::delegate sum_func_with_ptr{entt::connect_arg<&sum_with_ptr>, &value};
|
||||
const entt::delegate sum_func_with_const_ptr{entt::connect_arg<&sum_with_ptr>, &std::as_const(value)};
|
||||
const entt::delegate member_func_f{entt::connect_arg<&const_nonconst_noexcept::f>, functor};
|
||||
const entt::delegate member_func_g{entt::connect_arg<&const_nonconst_noexcept::g>, functor};
|
||||
const entt::delegate member_func_h{entt::connect_arg<&const_nonconst_noexcept::h>, &functor};
|
||||
const entt::delegate member_func_h_const{entt::connect_arg<&const_nonconst_noexcept::h>, &std::as_const(functor)};
|
||||
const entt::delegate member_func_i{entt::connect_arg<&const_nonconst_noexcept::i>, functor};
|
||||
const entt::delegate member_func_i_const{entt::connect_arg<&const_nonconst_noexcept::i>, std::as_const(functor)};
|
||||
const entt::delegate data_member_u{entt::connect_arg<&const_nonconst_noexcept::u>, functor};
|
||||
const entt::delegate data_member_v{entt::connect_arg<&const_nonconst_noexcept::v>, &functor};
|
||||
const entt::delegate data_member_v_const{entt::connect_arg<&const_nonconst_noexcept::v>, &std::as_const(functor)};
|
||||
const entt::delegate lambda{+[](const void *, int) { return 0; }};
|
||||
|
||||
testing::StaticAssertTypeEq<typename decltype(plain_func)::type, int(const int &)>();
|
||||
testing::StaticAssertTypeEq<typename decltype(sum_func_with_ref)::type, int(int)>();
|
||||
testing::StaticAssertTypeEq<typename decltype(sum_func_with_const_ref)::type, int(int)>();
|
||||
testing::StaticAssertTypeEq<typename decltype(sum_func_with_ptr)::type, int(int)>();
|
||||
testing::StaticAssertTypeEq<typename decltype(sum_func_with_const_ptr)::type, int(int)>();
|
||||
testing::StaticAssertTypeEq<typename decltype(member_func_f)::type, void()>();
|
||||
testing::StaticAssertTypeEq<typename decltype(member_func_g)::type, void()>();
|
||||
testing::StaticAssertTypeEq<typename decltype(member_func_h)::type, void()>();
|
||||
testing::StaticAssertTypeEq<typename decltype(member_func_h_const)::type, void()>();
|
||||
testing::StaticAssertTypeEq<typename decltype(member_func_i)::type, void()>();
|
||||
testing::StaticAssertTypeEq<typename decltype(member_func_i_const)::type, void()>();
|
||||
testing::StaticAssertTypeEq<typename decltype(data_member_u)::type, int()>();
|
||||
testing::StaticAssertTypeEq<typename decltype(data_member_v)::type, const int()>();
|
||||
testing::StaticAssertTypeEq<typename decltype(data_member_v_const)::type, const int()>();
|
||||
testing::StaticAssertTypeEq<typename decltype(lambda)::type, int(int)>();
|
||||
|
||||
ASSERT_TRUE(plain_func);
|
||||
ASSERT_TRUE(sum_func_with_ref);
|
||||
ASSERT_TRUE(sum_func_with_const_ref);
|
||||
ASSERT_TRUE(sum_func_with_ptr);
|
||||
ASSERT_TRUE(sum_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::mul>(functor);
|
||||
|
||||
ASSERT_TRUE(delegate);
|
||||
ASSERT_EQ(delegate(3), 12);
|
||||
|
||||
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, DiscardLast) {
|
||||
entt::delegate<int(int, const std::unique_ptr<int> &)> delegate;
|
||||
const auto value = 3;
|
||||
const auto other = std::make_unique<int>(4);
|
||||
|
||||
delegate.connect<&power_of_two>();
|
||||
|
||||
ASSERT_TRUE(delegate);
|
||||
ASSERT_EQ(delegate(3, other), 9);
|
||||
|
||||
delegate.connect<&sum_with_ref>(value);
|
||||
|
||||
ASSERT_TRUE(delegate);
|
||||
ASSERT_EQ(delegate(1, other), 4);
|
||||
|
||||
delegate.connect<&sum_with_ptr>(&value);
|
||||
|
||||
ASSERT_TRUE(delegate);
|
||||
ASSERT_EQ(delegate(2, other), 5);
|
||||
}
|
||||
|
||||
TEST(Delegate, SkipFirst) {
|
||||
entt::delegate<int(const std::unique_ptr<int> &, int)> delegate;
|
||||
const auto value = 3;
|
||||
const auto other = std::make_unique<int>(4);
|
||||
|
||||
delegate.connect<&power_of_two>();
|
||||
|
||||
ASSERT_TRUE(delegate);
|
||||
ASSERT_EQ(delegate(other, 3), 9);
|
||||
|
||||
delegate.connect<&sum_with_ref>(value);
|
||||
|
||||
ASSERT_TRUE(delegate);
|
||||
ASSERT_EQ(delegate(other, 1), 4);
|
||||
|
||||
delegate.connect<&sum_with_ptr>(&value);
|
||||
|
||||
ASSERT_TRUE(delegate);
|
||||
ASSERT_EQ(delegate(other, 2), 5);
|
||||
}
|
||||
|
||||
TEST(Delegate, Constructors) {
|
||||
delegate_functor functor;
|
||||
const auto value = 2;
|
||||
|
||||
const entt::delegate<int(int)> empty{};
|
||||
const entt::delegate<int(int)> func{entt::connect_arg<&power_of_two>};
|
||||
const entt::delegate<int(int)> ref{entt::connect_arg<&sum_with_ref>, value};
|
||||
const entt::delegate<int(int)> ptr{entt::connect_arg<&sum_with_ptr>, &value};
|
||||
const 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(5, ptr(3));
|
||||
|
||||
ASSERT_TRUE(member);
|
||||
ASSERT_EQ(6, member(3));
|
||||
}
|
||||
|
||||
TEST(Delegate, VoidVsNonVoidReturnType) {
|
||||
delegate_functor functor;
|
||||
|
||||
const entt::delegate<void(int)> func{entt::connect_arg<&power_of_two>};
|
||||
const entt::delegate<void(int)> member{entt::connect_arg<&delegate_functor::operator()>, &functor};
|
||||
const entt::delegate<void(int)> cmember{entt::connect_arg<&delegate_functor::mul>, &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>();
|
||||
const delegate_functor functor;
|
||||
|
||||
ASSERT_EQ(delegate(functor), 4);
|
||||
}
|
||||
|
||||
TEST(Delegate, UnboundMemberFunction) {
|
||||
entt::delegate<int(delegate_functor *, const int &)> 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 power_of_two(const int &);
|
||||
bound.connect<&power_of_two>();
|
||||
|
||||
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::mul>(&functor);
|
||||
|
||||
ASSERT_EQ(bound(3, 'c'), 12);
|
||||
|
||||
// int delegate_functor::operator()(int);
|
||||
unbound.connect<&delegate_functor::operator()>();
|
||||
|
||||
ASSERT_EQ(unbound(functor, 3, 'c'), 6);
|
||||
}
|
||||
198
lib/All/entt/test/entt/signal/dispatcher.cpp
Normal file
198
lib/All/entt/test/entt/signal/dispatcher.cpp
Normal file
@@ -0,0 +1,198 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/core/hashed_string.hpp>
|
||||
#include <entt/signal/dispatcher.hpp>
|
||||
#include "../../common/empty.h"
|
||||
|
||||
// makes the type non-aggregate
|
||||
struct non_aggregate {
|
||||
non_aggregate(int) {}
|
||||
};
|
||||
|
||||
struct receiver {
|
||||
static void forward(entt::dispatcher &dispatcher, test::empty &event) {
|
||||
dispatcher.enqueue(event);
|
||||
}
|
||||
|
||||
void receive(const test::empty &) {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
int cnt{0};
|
||||
};
|
||||
|
||||
TEST(Dispatcher, Functionalities) {
|
||||
entt::dispatcher dispatcher{};
|
||||
entt::dispatcher other{std::move(dispatcher)};
|
||||
|
||||
dispatcher = std::move(other);
|
||||
|
||||
receiver receiver{};
|
||||
|
||||
ASSERT_EQ(dispatcher.size<test::empty>(), 0u);
|
||||
ASSERT_EQ(dispatcher.size(), 0u);
|
||||
|
||||
dispatcher.trigger(non_aggregate{1});
|
||||
dispatcher.enqueue<non_aggregate>(2);
|
||||
dispatcher.update<non_aggregate>();
|
||||
|
||||
dispatcher.sink<test::empty>().connect<&receiver::receive>(receiver);
|
||||
dispatcher.trigger<test::empty>();
|
||||
dispatcher.enqueue<test::empty>();
|
||||
|
||||
ASSERT_EQ(dispatcher.size<non_aggregate>(), 0u);
|
||||
ASSERT_EQ(dispatcher.size<test::empty>(), 1u);
|
||||
ASSERT_EQ(dispatcher.size(), 1u);
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
|
||||
dispatcher.enqueue(test::other_empty{});
|
||||
dispatcher.update<test::other_empty>();
|
||||
|
||||
ASSERT_EQ(dispatcher.size<test::other_empty>(), 0u);
|
||||
ASSERT_EQ(dispatcher.size<test::empty>(), 1u);
|
||||
ASSERT_EQ(dispatcher.size(), 1u);
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
|
||||
dispatcher.update<test::empty>();
|
||||
dispatcher.trigger<test::empty>();
|
||||
|
||||
ASSERT_EQ(dispatcher.size<test::empty>(), 0u);
|
||||
ASSERT_EQ(dispatcher.size(), 0u);
|
||||
ASSERT_EQ(receiver.cnt, 3);
|
||||
|
||||
dispatcher.enqueue<test::empty>();
|
||||
dispatcher.clear<test::empty>();
|
||||
dispatcher.update();
|
||||
|
||||
dispatcher.enqueue(test::empty{});
|
||||
dispatcher.clear();
|
||||
dispatcher.update();
|
||||
|
||||
ASSERT_EQ(dispatcher.size<test::empty>(), 0u);
|
||||
ASSERT_EQ(dispatcher.size(), 0u);
|
||||
ASSERT_EQ(receiver.cnt, 3);
|
||||
|
||||
receiver.reset();
|
||||
|
||||
test::empty event{};
|
||||
|
||||
dispatcher.sink<test::empty>().disconnect<&receiver::receive>(receiver);
|
||||
dispatcher.trigger<test::empty>();
|
||||
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<test::empty>().connect<&receiver::receive>(receiver);
|
||||
dispatcher.enqueue<test::empty>();
|
||||
|
||||
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<test::empty>().connect<&receiver::forward>(dispatcher);
|
||||
dispatcher.sink<test::empty>().connect<&receiver::receive>(receiver);
|
||||
|
||||
dispatcher.enqueue<test::empty>();
|
||||
dispatcher.update();
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
|
||||
dispatcher.sink<test::empty>().disconnect<&receiver::forward>(dispatcher);
|
||||
dispatcher.update();
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 2);
|
||||
}
|
||||
|
||||
TEST(Dispatcher, OpaqueDisconnect) {
|
||||
entt::dispatcher dispatcher{};
|
||||
receiver receiver{};
|
||||
|
||||
dispatcher.sink<test::empty>().connect<&receiver::receive>(receiver);
|
||||
dispatcher.trigger<test::empty>();
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
|
||||
dispatcher.disconnect(receiver);
|
||||
dispatcher.trigger<test::empty>();
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
}
|
||||
|
||||
TEST(Dispatcher, NamedQueue) {
|
||||
using namespace entt::literals;
|
||||
|
||||
entt::dispatcher dispatcher{};
|
||||
receiver receiver{};
|
||||
|
||||
dispatcher.sink<test::empty>("named"_hs).connect<&receiver::receive>(receiver);
|
||||
dispatcher.trigger<test::empty>();
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 0);
|
||||
|
||||
dispatcher.trigger("named"_hs, test::empty{});
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
|
||||
dispatcher.enqueue<test::empty>();
|
||||
dispatcher.enqueue(test::empty{});
|
||||
dispatcher.enqueue_hint<test::empty>("named"_hs);
|
||||
dispatcher.enqueue_hint("named"_hs, test::empty{});
|
||||
dispatcher.update<test::empty>();
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 1);
|
||||
|
||||
dispatcher.clear<test::empty>();
|
||||
dispatcher.update<test::empty>("named"_hs);
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 3);
|
||||
|
||||
dispatcher.enqueue_hint<test::empty>("named"_hs);
|
||||
dispatcher.clear<test::empty>("named"_hs);
|
||||
dispatcher.update<test::empty>("named"_hs);
|
||||
|
||||
ASSERT_EQ(receiver.cnt, 3);
|
||||
}
|
||||
|
||||
TEST(Dispatcher, CustomAllocator) {
|
||||
const std::allocator<void> allocator{};
|
||||
entt::dispatcher dispatcher{allocator};
|
||||
|
||||
ASSERT_EQ(dispatcher.get_allocator(), allocator);
|
||||
ASSERT_FALSE(dispatcher.get_allocator() != allocator);
|
||||
|
||||
dispatcher.enqueue<test::empty>();
|
||||
const decltype(dispatcher) other{std::move(dispatcher), allocator};
|
||||
|
||||
ASSERT_EQ(other.size<test::empty>(), 1u);
|
||||
}
|
||||
169
lib/All/entt/test/entt/signal/emitter.cpp
Normal file
169
lib/All/entt/test/entt/signal/emitter.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/signal/emitter.hpp>
|
||||
#include "../../common/boxed_type.h"
|
||||
#include "../../common/emitter.h"
|
||||
#include "../../common/empty.h"
|
||||
#include "../../common/linter.hpp"
|
||||
|
||||
TEST(Emitter, Move) {
|
||||
test::emitter emitter{};
|
||||
emitter.on<test::boxed_int>([](auto &, const auto &) {});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<test::boxed_int>());
|
||||
|
||||
test::emitter other{std::move(emitter)};
|
||||
|
||||
test::is_initialized(emitter);
|
||||
|
||||
ASSERT_FALSE(other.empty());
|
||||
ASSERT_TRUE(other.contains<test::boxed_int>());
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
|
||||
emitter = std::move(other);
|
||||
test::is_initialized(other);
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<test::boxed_int>());
|
||||
ASSERT_TRUE(other.empty());
|
||||
}
|
||||
|
||||
TEST(Emitter, Swap) {
|
||||
test::emitter emitter{};
|
||||
test::emitter other{};
|
||||
int value{};
|
||||
|
||||
emitter.on<test::boxed_int>([&value](auto &event, const auto &) {
|
||||
value = event.value;
|
||||
});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(other.empty());
|
||||
|
||||
emitter.swap(other);
|
||||
emitter.publish(test::boxed_int{1});
|
||||
|
||||
ASSERT_EQ(value, 0);
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
|
||||
other.publish(test::boxed_int{1});
|
||||
|
||||
ASSERT_EQ(value, 1);
|
||||
}
|
||||
|
||||
TEST(Emitter, Clear) {
|
||||
test::emitter emitter{};
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
|
||||
emitter.on<test::boxed_int>([](auto &, const auto &) {});
|
||||
emitter.on<test::boxed_char>([](const auto &, const auto &) {});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<test::boxed_int>());
|
||||
ASSERT_TRUE(emitter.contains<test::boxed_char>());
|
||||
ASSERT_FALSE(emitter.contains<test::empty>());
|
||||
|
||||
emitter.erase<test::empty>();
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<test::boxed_int>());
|
||||
ASSERT_TRUE(emitter.contains<test::boxed_char>());
|
||||
ASSERT_FALSE(emitter.contains<test::empty>());
|
||||
|
||||
emitter.erase<test::boxed_int>();
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_FALSE(emitter.contains<test::boxed_int>());
|
||||
ASSERT_TRUE(emitter.contains<test::boxed_char>());
|
||||
ASSERT_FALSE(emitter.contains<test::empty>());
|
||||
|
||||
emitter.on<test::boxed_int>([](auto &, const auto &) {});
|
||||
emitter.on<test::empty>([](const auto &, const auto &) {});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<test::boxed_int>());
|
||||
ASSERT_TRUE(emitter.contains<test::boxed_char>());
|
||||
ASSERT_TRUE(emitter.contains<test::empty>());
|
||||
|
||||
emitter.clear();
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
ASSERT_FALSE(emitter.contains<test::boxed_int>());
|
||||
ASSERT_FALSE(emitter.contains<test::empty>());
|
||||
}
|
||||
|
||||
TEST(Emitter, ClearFromCallback) {
|
||||
test::emitter emitter{};
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
|
||||
emitter.on<test::boxed_int>([](auto &, auto &owner) {
|
||||
owner.template on<test::boxed_int>([](auto &, auto &) {});
|
||||
owner.template erase<test::boxed_int>();
|
||||
});
|
||||
|
||||
emitter.on<test::empty>([](const auto &, auto &owner) {
|
||||
owner.template on<test::empty>([](const auto &, auto &) {});
|
||||
owner.template erase<test::empty>();
|
||||
});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
|
||||
emitter.publish(test::boxed_int{});
|
||||
emitter.publish(test::empty{});
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
}
|
||||
|
||||
TEST(Emitter, On) {
|
||||
test::emitter emitter{};
|
||||
int value{};
|
||||
|
||||
emitter.on<test::boxed_int>([&value](auto &event, const auto &) {
|
||||
value = event.value;
|
||||
});
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<test::boxed_int>());
|
||||
ASSERT_EQ(value, 0);
|
||||
|
||||
emitter.publish(test::boxed_int{1});
|
||||
|
||||
ASSERT_EQ(value, 1);
|
||||
}
|
||||
|
||||
TEST(Emitter, OnAndErase) {
|
||||
test::emitter emitter{};
|
||||
const std::function<void(test::empty &, test::emitter &)> func{};
|
||||
|
||||
emitter.on(func);
|
||||
|
||||
ASSERT_FALSE(emitter.empty());
|
||||
ASSERT_TRUE(emitter.contains<test::empty>());
|
||||
|
||||
emitter.erase<test::empty>();
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
ASSERT_FALSE(emitter.contains<test::empty>());
|
||||
}
|
||||
|
||||
TEST(Emitter, CustomAllocator) {
|
||||
const std::allocator<void> allocator{};
|
||||
test::emitter emitter{allocator};
|
||||
|
||||
ASSERT_EQ(emitter.get_allocator(), allocator);
|
||||
ASSERT_FALSE(emitter.get_allocator() != allocator);
|
||||
|
||||
emitter.on<test::boxed_int>([](auto &, const auto &) {});
|
||||
const decltype(emitter) other{std::move(emitter), allocator};
|
||||
|
||||
test::is_initialized(emitter);
|
||||
|
||||
ASSERT_TRUE(emitter.empty());
|
||||
ASSERT_FALSE(other.empty());
|
||||
}
|
||||
554
lib/All/entt/test/entt/signal/sigh.cpp
Normal file
554
lib/All/entt/test/entt/signal/sigh.cpp
Normal file
@@ -0,0 +1,554 @@
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <gtest/gtest.h>
|
||||
#include <entt/signal/sigh.hpp>
|
||||
#include "../../common/config.h"
|
||||
#include "../../common/linter.hpp"
|
||||
|
||||
struct sigh_listener {
|
||||
static void f(int &iv) {
|
||||
++iv;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool g(int) {
|
||||
val = !val;
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool h(const int &) const {
|
||||
return val;
|
||||
}
|
||||
|
||||
// useless definition just because msvc does weird things if both are empty
|
||||
void i() {
|
||||
val = val && val;
|
||||
}
|
||||
|
||||
bool val{false};
|
||||
};
|
||||
|
||||
struct const_nonconst_noexcept {
|
||||
void f() {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void g() noexcept {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void h() const {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
void i() const noexcept {
|
||||
++cnt;
|
||||
}
|
||||
|
||||
mutable int cnt{0};
|
||||
};
|
||||
|
||||
void connect_and_auto_disconnect(entt::sigh<void(int &)> &sigh, const int &) {
|
||||
entt::sink sink{sigh};
|
||||
sink.connect<sigh_listener::f>();
|
||||
sink.disconnect<&connect_and_auto_disconnect>(sigh);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(SinkDeathTest, Invalid) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<void(int &)> sigh;
|
||||
entt::sink<entt::sigh<void(int &)>> sink{};
|
||||
|
||||
ASSERT_FALSE(sink);
|
||||
|
||||
ASSERT_DEATH([[maybe_unused]] const bool empty = sink.empty(), "");
|
||||
ASSERT_DEATH(sink.connect<&sigh_listener::f>(), "");
|
||||
ASSERT_DEATH(sink.disconnect<&sigh_listener::f>(), "");
|
||||
ASSERT_DEATH(sink.disconnect(&listener), "");
|
||||
ASSERT_DEATH(sink.disconnect(), "");
|
||||
|
||||
sink = entt::sink{sigh};
|
||||
|
||||
ASSERT_TRUE(sink);
|
||||
ASSERT_TRUE(sink.empty());
|
||||
}
|
||||
|
||||
TEST(SigH, Lifetime) {
|
||||
using signal = entt::sigh<void(void)>;
|
||||
|
||||
ASSERT_NO_THROW(signal{});
|
||||
|
||||
signal src{};
|
||||
signal other{};
|
||||
|
||||
ASSERT_NO_THROW(signal{src});
|
||||
ASSERT_NO_THROW(signal{std::move(other)});
|
||||
|
||||
other = {};
|
||||
|
||||
ASSERT_NO_THROW(src = other);
|
||||
ASSERT_NO_THROW(src = std::move(other));
|
||||
|
||||
ASSERT_NO_THROW(delete new signal{});
|
||||
}
|
||||
|
||||
TEST(SigH, Disconnect) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<void(int &)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
sink.connect<&sigh_listener::f>();
|
||||
|
||||
ASSERT_FALSE(sink.empty());
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
|
||||
sink.disconnect<&sigh_listener::f>();
|
||||
|
||||
ASSERT_TRUE(sink.empty());
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
|
||||
sink.connect<&sigh_listener::g>(listener);
|
||||
|
||||
ASSERT_FALSE(sink.empty());
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
|
||||
sink.disconnect<&sigh_listener::g>(listener);
|
||||
|
||||
ASSERT_TRUE(sink.empty());
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
|
||||
sink.connect<&sigh_listener::g>(listener);
|
||||
|
||||
ASSERT_FALSE(sink.empty());
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
|
||||
sink.disconnect(&listener);
|
||||
|
||||
ASSERT_TRUE(sink.empty());
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
|
||||
sink.connect<&sigh_listener::f>();
|
||||
|
||||
ASSERT_FALSE(sink.empty());
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
|
||||
sink.disconnect();
|
||||
|
||||
ASSERT_TRUE(sink.empty());
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
}
|
||||
|
||||
TEST(SigH, Swap) {
|
||||
entt::sigh<void(int &)> sigh1;
|
||||
entt::sigh<void(int &)> sigh2;
|
||||
entt::sink sink1{sigh1};
|
||||
const 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(SigH, Functions) {
|
||||
entt::sigh<void(int &)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
int value = 0;
|
||||
|
||||
sink.connect<&sigh_listener::f>();
|
||||
sigh.publish(value);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(sigh.size(), 1u);
|
||||
ASSERT_EQ(value, 1);
|
||||
|
||||
value = 0;
|
||||
sink.disconnect<&sigh_listener::f>();
|
||||
sigh.publish(value);
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_EQ(sigh.size(), 0u);
|
||||
ASSERT_EQ(value, 0);
|
||||
}
|
||||
|
||||
TEST(SigH, FunctionsWithPayload) {
|
||||
entt::sigh<void()> sigh;
|
||||
entt::sink sink{sigh};
|
||||
int value = 0;
|
||||
|
||||
sink.connect<&sigh_listener::f>(value);
|
||||
sigh.publish();
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(sigh.size(), 1u);
|
||||
ASSERT_EQ(value, 1);
|
||||
|
||||
value = 0;
|
||||
sink.disconnect<&sigh_listener::f>(value);
|
||||
sigh.publish();
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_EQ(sigh.size(), 0u);
|
||||
ASSERT_EQ(value, 0);
|
||||
|
||||
sink.connect<&sigh_listener::f>(value);
|
||||
sink.disconnect(&value);
|
||||
sigh.publish();
|
||||
|
||||
ASSERT_EQ(value, 0);
|
||||
}
|
||||
|
||||
TEST(SigH, Members) {
|
||||
sigh_listener l1;
|
||||
sigh_listener l2;
|
||||
entt::sigh<bool(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
sink.connect<&sigh_listener::g>(l1);
|
||||
sigh.publish(3);
|
||||
|
||||
ASSERT_TRUE(l1.val);
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(sigh.size(), 1u);
|
||||
|
||||
sink.disconnect<&sigh_listener::g>(l1);
|
||||
sigh.publish(3);
|
||||
|
||||
ASSERT_TRUE(l1.val);
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_EQ(sigh.size(), 0u);
|
||||
|
||||
sink.connect<&sigh_listener::g>(&l1);
|
||||
sink.connect<&sigh_listener::h>(l2);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(sigh.size(), 2u);
|
||||
|
||||
sink.disconnect(&l1);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(sigh.size(), 1u);
|
||||
}
|
||||
|
||||
TEST(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.val = true;
|
||||
++cnt;
|
||||
};
|
||||
|
||||
listener.val = true;
|
||||
sigh.collect(std::move(no_return), 3);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(cnt, 2);
|
||||
|
||||
auto bool_return = [&cnt](bool value) {
|
||||
// gtest and its macro hell are sometimes really annoying...
|
||||
[](auto curr) { ASSERT_TRUE(curr); }(value);
|
||||
++cnt;
|
||||
return true;
|
||||
};
|
||||
|
||||
cnt = 0;
|
||||
sigh.collect(std::move(bool_return), 3);
|
||||
|
||||
ASSERT_EQ(cnt, 1);
|
||||
}
|
||||
|
||||
TEST(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; }, 3);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_EQ(cnt, 2);
|
||||
|
||||
cnt = 0;
|
||||
sigh.collect([&cnt]() { ++cnt; return true; }, 3);
|
||||
|
||||
ASSERT_EQ(cnt, 1);
|
||||
}
|
||||
|
||||
TEST(SigH, Connection) {
|
||||
entt::sigh<void(int &)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
int value = 0;
|
||||
|
||||
auto conn = sink.connect<&sigh_listener::f>();
|
||||
sigh.publish(value);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_TRUE(conn);
|
||||
ASSERT_EQ(value, 1);
|
||||
|
||||
value = 0;
|
||||
conn.release();
|
||||
sigh.publish(value);
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_FALSE(conn);
|
||||
ASSERT_EQ(0, value);
|
||||
}
|
||||
|
||||
TEST(SigH, ScopedConnection) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<void(int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
{
|
||||
ASSERT_FALSE(listener.val);
|
||||
|
||||
const entt::scoped_connection conn = sink.connect<&sigh_listener::g>(listener);
|
||||
sigh.publish(1);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_TRUE(listener.val);
|
||||
ASSERT_TRUE(conn);
|
||||
}
|
||||
|
||||
sigh.publish(1);
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_TRUE(listener.val);
|
||||
}
|
||||
|
||||
TEST(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);
|
||||
|
||||
{
|
||||
const entt::scoped_connection inner{std::move(outer)};
|
||||
|
||||
test::is_initialized(outer);
|
||||
|
||||
ASSERT_FALSE(listener.val);
|
||||
ASSERT_FALSE(outer);
|
||||
ASSERT_TRUE(inner);
|
||||
|
||||
sigh.publish(1);
|
||||
|
||||
ASSERT_TRUE(listener.val);
|
||||
}
|
||||
|
||||
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.val);
|
||||
ASSERT_TRUE(outer);
|
||||
ASSERT_FALSE(inner);
|
||||
|
||||
inner = std::move(outer);
|
||||
test::is_initialized(outer);
|
||||
|
||||
ASSERT_FALSE(outer);
|
||||
ASSERT_TRUE(inner);
|
||||
|
||||
sigh.publish(1);
|
||||
|
||||
ASSERT_FALSE(listener.val);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
}
|
||||
|
||||
TEST(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.val);
|
||||
ASSERT_FALSE(inner);
|
||||
|
||||
inner = sink.connect<&sigh_listener::g>(listener);
|
||||
sigh.publish(1);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_TRUE(listener.val);
|
||||
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(1);
|
||||
|
||||
ASSERT_FALSE(sigh.empty());
|
||||
ASSERT_FALSE(listener.val);
|
||||
ASSERT_TRUE(inner);
|
||||
}
|
||||
|
||||
sigh.publish(1);
|
||||
|
||||
ASSERT_TRUE(sigh.empty());
|
||||
ASSERT_FALSE(listener.val);
|
||||
}
|
||||
|
||||
TEST(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(SigH, UnboundDataMember) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<bool &(sigh_listener &)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
ASSERT_FALSE(listener.val);
|
||||
|
||||
sink.connect<&sigh_listener::val>();
|
||||
sigh.collect([](bool &value) { value = !value; }, listener);
|
||||
|
||||
ASSERT_TRUE(listener.val);
|
||||
}
|
||||
|
||||
TEST(SigH, UnboundMemberFunction) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<void(sigh_listener *, int)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
|
||||
ASSERT_FALSE(listener.val);
|
||||
|
||||
sink.connect<&sigh_listener::g>();
|
||||
sigh.publish(&listener, 1);
|
||||
|
||||
ASSERT_TRUE(listener.val);
|
||||
}
|
||||
|
||||
TEST(SigH, ConnectAndAutoDisconnect) {
|
||||
sigh_listener listener;
|
||||
entt::sigh<void(int &)> sigh;
|
||||
entt::sink sink{sigh};
|
||||
int value = 0;
|
||||
|
||||
sink.connect<&sigh_listener::g>(listener);
|
||||
sink.connect<&connect_and_auto_disconnect>(sigh);
|
||||
|
||||
ASSERT_FALSE(listener.val);
|
||||
ASSERT_EQ(sigh.size(), 2u);
|
||||
ASSERT_EQ(value, 0);
|
||||
|
||||
sigh.publish(value);
|
||||
|
||||
ASSERT_TRUE(listener.val);
|
||||
ASSERT_EQ(sigh.size(), 2u);
|
||||
ASSERT_EQ(value, 0);
|
||||
|
||||
sigh.publish(value);
|
||||
|
||||
ASSERT_FALSE(listener.val);
|
||||
ASSERT_EQ(sigh.size(), 2u);
|
||||
ASSERT_EQ(value, 1);
|
||||
}
|
||||
|
||||
TEST(SigH, CustomAllocator) {
|
||||
const std::allocator<void (*)(int)> allocator;
|
||||
entt::sigh<void(int), std::allocator<void (*)(int)>> 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};
|
||||
|
||||
test::is_initialized(copy);
|
||||
|
||||
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