1824 lines
48 KiB
C++
1824 lines
48 KiB
C++
// Catch static asserts
|
|
#define flecs_static_assert(cond, str)\
|
|
ecs_assert(cond, ECS_INVALID_OPERATION, str)
|
|
|
|
#include <cpp_api.h>
|
|
|
|
int Pod::ctor_invoked = 0;
|
|
int Pod::dtor_invoked = 0;
|
|
int Pod::copy_invoked = 0;
|
|
int Pod::move_invoked = 0;
|
|
int Pod::copy_ctor_invoked = 0;
|
|
int Pod::move_ctor_invoked = 0;
|
|
|
|
int CountNoDefaultCtor::ctor_invoked = 0;
|
|
int CountNoDefaultCtor::dtor_invoked = 0;
|
|
int CountNoDefaultCtor::copy_invoked = 0;
|
|
int CountNoDefaultCtor::move_invoked = 0;
|
|
int CountNoDefaultCtor::copy_ctor_invoked = 0;
|
|
int CountNoDefaultCtor::move_ctor_invoked = 0;
|
|
|
|
void ComponentLifecycle_ctor_on_add(void) {
|
|
flecs::world world;
|
|
|
|
world.component<Pod>();
|
|
|
|
auto e = world.entity().add<Pod>();
|
|
test_assert(e.id() != 0);
|
|
test_assert(e.has<Pod>());
|
|
|
|
const Pod *pod = e.get<Pod>();
|
|
test_assert(pod != NULL);
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 0);
|
|
test_int(Pod::copy_invoked, 0);
|
|
test_int(Pod::move_invoked, 0);
|
|
|
|
test_int(pod->value, 10);
|
|
}
|
|
|
|
void ComponentLifecycle_dtor_on_remove(void) {
|
|
flecs::world world;
|
|
|
|
world.component<Pod>();
|
|
|
|
auto e = world.entity().add<Pod>();
|
|
test_assert(e.id() != 0);
|
|
test_assert(e.has<Pod>());
|
|
test_int(Pod::ctor_invoked, 1);
|
|
|
|
e.remove<Pod>();
|
|
test_assert(!e.has<Pod>());
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 1);
|
|
test_int(Pod::copy_invoked, 0);
|
|
test_int(Pod::move_invoked, 0);
|
|
}
|
|
|
|
void ComponentLifecycle_move_on_add(void) {
|
|
flecs::world world;
|
|
|
|
world.component<Pod>();
|
|
|
|
auto e = world.entity().add<Pod>();
|
|
test_assert(e.id() != 0);
|
|
test_assert(e.has<Pod>());
|
|
|
|
const Pod *pod = e.get<Pod>();
|
|
test_assert(pod != NULL);
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 0);
|
|
test_int(Pod::copy_invoked, 0);
|
|
test_int(Pod::move_invoked, 0);
|
|
test_int(Pod::copy_ctor_invoked, 0);
|
|
test_int(Pod::move_ctor_invoked, 0);
|
|
|
|
e.add<Position>();
|
|
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 1);
|
|
test_int(Pod::copy_invoked, 0);
|
|
test_int(Pod::move_invoked, 0);
|
|
test_int(Pod::copy_ctor_invoked, 0);
|
|
test_int(Pod::move_ctor_invoked, 1);
|
|
|
|
test_int(pod->value, 10);
|
|
}
|
|
|
|
void ComponentLifecycle_move_on_remove(void) {
|
|
flecs::world world;
|
|
|
|
world.component<Pod>();
|
|
|
|
auto e = world.entity().add<Position>().add<Pod>();
|
|
test_assert(e.id() != 0);
|
|
test_assert(e.has<Pod>());
|
|
|
|
const Pod *pod = e.get<Pod>();
|
|
test_assert(pod != NULL);
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 0);
|
|
test_int(Pod::copy_invoked, 0);
|
|
test_int(Pod::move_invoked, 0);
|
|
test_int(Pod::copy_ctor_invoked, 0);
|
|
test_int(Pod::move_ctor_invoked, 0);
|
|
|
|
e.remove<Position>();
|
|
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 1);
|
|
test_int(Pod::copy_invoked, 0);
|
|
test_int(Pod::move_invoked, 0);
|
|
test_int(Pod::copy_ctor_invoked, 0);
|
|
test_int(Pod::move_ctor_invoked, 1);
|
|
|
|
test_int(pod->value, 10);
|
|
}
|
|
|
|
void ComponentLifecycle_copy_on_set(void) {
|
|
flecs::world world;
|
|
|
|
world.component<Pod>();
|
|
|
|
auto e = world.entity();
|
|
test_assert(e.id() != 0);
|
|
|
|
e.set<Pod>({20});
|
|
test_assert(e.has<Pod>());
|
|
test_int(Pod::ctor_invoked, 2);
|
|
test_int(Pod::dtor_invoked, 1);
|
|
test_int(Pod::copy_invoked, 0);
|
|
test_int(Pod::move_invoked, 1);
|
|
}
|
|
|
|
void ComponentLifecycle_copy_on_override(void) {
|
|
flecs::world world;
|
|
|
|
world.component<Pod>();
|
|
|
|
auto base = world.entity();
|
|
test_assert(base.id() != 0);
|
|
|
|
base.set<Pod>({10});
|
|
test_int(Pod::ctor_invoked, 2);
|
|
test_int(Pod::dtor_invoked, 1);
|
|
test_int(Pod::copy_invoked, 0);
|
|
Pod::ctor_invoked = 0;
|
|
Pod::dtor_invoked = 0;
|
|
Pod::copy_invoked = 0;
|
|
Pod::move_invoked = 0;
|
|
|
|
auto e = world.entity();
|
|
test_assert(e.id() != 0);
|
|
|
|
e.add(flecs::IsA, base);
|
|
test_int(Pod::ctor_invoked, 0);
|
|
|
|
e.add<Pod>();
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 0);
|
|
test_int(Pod::copy_invoked, 1);
|
|
test_int(Pod::move_invoked, 0);
|
|
|
|
const Pod *pod = e.get<Pod>();
|
|
test_assert(pod != NULL);
|
|
test_int(pod->value, 10);
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_string_add(void) {
|
|
flecs::world world;
|
|
|
|
auto e = world.entity().add<Struct_w_string>();
|
|
test_assert(e.id() != 0);
|
|
test_assert(e.has<Struct_w_string>());
|
|
|
|
const Struct_w_string *str = e.get<Struct_w_string>();
|
|
test_assert(str != NULL);
|
|
test_assert(str->value == "");
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_string_remove(void) {
|
|
flecs::world world;
|
|
|
|
auto e = world.entity().add<Struct_w_string>();
|
|
test_assert(e.id() != 0);
|
|
test_assert(e.has<Struct_w_string>());
|
|
|
|
e.remove<Struct_w_string>();
|
|
test_assert(!e.has<Struct_w_string>());
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_string_set(void) {
|
|
flecs::world world;
|
|
|
|
auto e = world.entity()
|
|
.set<Struct_w_string>({"Hello World"});
|
|
test_assert(e.id() != 0);
|
|
test_assert(e.has<Struct_w_string>());
|
|
|
|
const Struct_w_string *str = e.get<Struct_w_string>();
|
|
test_assert(str != NULL);
|
|
test_assert(str->value == "Hello World");
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_string_override(void) {
|
|
flecs::world world;
|
|
|
|
auto base = world.entity();
|
|
test_assert(base.id() != 0);
|
|
|
|
base.set<Struct_w_string>({"Hello World"});
|
|
|
|
auto e = world.entity();
|
|
test_assert(e.id() != 0);
|
|
|
|
e.add(flecs::IsA, base);
|
|
|
|
e.add<Struct_w_string>();
|
|
|
|
const Struct_w_string *str = e.get<Struct_w_string>();
|
|
test_assert(str != NULL);
|
|
test_assert(str->value == "Hello World");
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_string_add_2_remove(void) {
|
|
flecs::world world;
|
|
|
|
auto e1 = world.entity().add<Struct_w_string>();
|
|
auto e2 = world.entity().add<Struct_w_string>();
|
|
|
|
const Struct_w_string *str1 = e1.get<Struct_w_string>();
|
|
test_assert(str1 != NULL);
|
|
test_assert(str1->value == "");
|
|
const Struct_w_string *str2 = e2.get<Struct_w_string>();
|
|
test_assert(str2 != NULL);
|
|
test_assert(str2->value == "");
|
|
|
|
e1.remove<Struct_w_string>();
|
|
str1 = e1.get<Struct_w_string>();
|
|
test_assert(str1 == NULL);
|
|
|
|
str2 = e2.get<Struct_w_string>();
|
|
test_assert(str2 != NULL);
|
|
test_assert(str2->value == "");
|
|
|
|
e2.remove<Struct_w_string>();
|
|
str2 = e2.get<Struct_w_string>();
|
|
test_assert(str2 == NULL);
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_string_set_2_remove(void) {
|
|
flecs::world world;
|
|
|
|
auto e1 = world.entity().set<Struct_w_string>({"hello"});
|
|
auto e2 = world.entity().set<Struct_w_string>({"world"});
|
|
|
|
const Struct_w_string *str1 = e1.get<Struct_w_string>();
|
|
test_assert(str1 != NULL);
|
|
test_assert(str1->value == "hello");
|
|
const Struct_w_string *str2 = e2.get<Struct_w_string>();
|
|
test_assert(str2 != NULL);
|
|
test_assert(str2->value == "world");
|
|
|
|
e1.remove<Struct_w_string>();
|
|
str1 = e1.get<Struct_w_string>();
|
|
test_assert(str1 == NULL);
|
|
|
|
str2 = e2.get<Struct_w_string>();
|
|
test_assert(str2 != NULL);
|
|
test_assert(str2->value == "world");
|
|
|
|
e2.remove<Struct_w_string>();
|
|
str2 = e2.get<Struct_w_string>();
|
|
test_assert(str2 == NULL);
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_string_add_2_remove_w_tag(void) {
|
|
flecs::world world;
|
|
|
|
auto e1 = world.entity().add<Tag>().add<Struct_w_string>();
|
|
auto e2 = world.entity().add<Tag>().add<Struct_w_string>();
|
|
|
|
const Struct_w_string *str1 = e1.get<Struct_w_string>();
|
|
test_assert(str1 != NULL);
|
|
test_assert(str1->value == "");
|
|
const Struct_w_string *str2 = e2.get<Struct_w_string>();
|
|
test_assert(str2 != NULL);
|
|
test_assert(str2->value == "");
|
|
|
|
e1.remove<Struct_w_string>();
|
|
str1 = e1.get<Struct_w_string>();
|
|
test_assert(str1 == NULL);
|
|
|
|
str2 = e2.get<Struct_w_string>();
|
|
test_assert(str2 != NULL);
|
|
test_assert(str2->value == "");
|
|
|
|
e2.remove<Struct_w_string>();
|
|
str2 = e2.get<Struct_w_string>();
|
|
test_assert(str2 == NULL);
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_string_set_2_remove_w_tag(void) {
|
|
flecs::world world;
|
|
|
|
auto e1 = world.entity().add<Tag>().set<Struct_w_string>({"hello"});
|
|
auto e2 = world.entity().add<Tag>().set<Struct_w_string>({"world"});
|
|
|
|
const Struct_w_string *str1 = e1.get<Struct_w_string>();
|
|
test_assert(str1 != NULL);
|
|
test_assert(str1->value == "hello");
|
|
const Struct_w_string *str2 = e2.get<Struct_w_string>();
|
|
test_assert(str2 != NULL);
|
|
test_assert(str2->value == "world");
|
|
|
|
e1.remove<Struct_w_string>();
|
|
str1 = e1.get<Struct_w_string>();
|
|
test_assert(str1 == NULL);
|
|
|
|
str2 = e2.get<Struct_w_string>();
|
|
test_assert(str2 != NULL);
|
|
test_assert(str2->value == "world");
|
|
|
|
e2.remove<Struct_w_string>();
|
|
str2 = e2.get<Struct_w_string>();
|
|
test_assert(str2 == NULL);
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_vector_add(void) {
|
|
flecs::world world;
|
|
|
|
auto e = world.entity().add<Struct_w_vector>();
|
|
test_assert(e.has<Struct_w_vector>());
|
|
|
|
const Struct_w_vector *ptr = e.get<Struct_w_vector>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->value.size(), 0);
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_vector_remove(void) {
|
|
flecs::world world;
|
|
|
|
auto e = world.entity().add<Struct_w_vector>();
|
|
test_assert(e.has<Struct_w_vector>());
|
|
|
|
e.remove<Struct_w_vector>();
|
|
test_assert(!e.has<Struct_w_vector>());
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_vector_set(void) {
|
|
flecs::world world;
|
|
|
|
auto e = world.entity().set<Struct_w_vector>({std::vector<int>{1, 2}});
|
|
test_assert(e.has<Struct_w_vector>());
|
|
|
|
const Struct_w_vector *ptr = e.get<Struct_w_vector>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->value.size(), 2);
|
|
test_int(ptr->value.at(0), 1);
|
|
test_int(ptr->value.at(1), 2);
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_vector_override(void) {
|
|
flecs::world world;
|
|
|
|
auto base = world.entity().set<Struct_w_vector>({std::vector<int>{1, 2}});
|
|
test_assert(base.has<Struct_w_vector>());
|
|
|
|
auto e = world.entity().is_a(base).add<Struct_w_vector>();
|
|
test_assert(e.has<Struct_w_vector>());
|
|
|
|
const Struct_w_vector *ptr = base.get<Struct_w_vector>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->value.size(), 2);
|
|
test_int(ptr->value.at(0), 1);
|
|
test_int(ptr->value.at(1), 2);
|
|
|
|
ptr = e.get<Struct_w_vector>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->value.size(), 2);
|
|
test_int(ptr->value.at(0), 1);
|
|
test_int(ptr->value.at(1), 2);
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_vector_add_2_remove(void) {
|
|
flecs::world world;
|
|
|
|
auto e1 = world.entity().add<Struct_w_vector>();
|
|
auto e2 = world.entity().add<Struct_w_vector>();
|
|
|
|
const Struct_w_vector *ptr1 = e1.get<Struct_w_vector>();
|
|
test_assert(ptr1 != NULL);
|
|
test_int(ptr1->value.size(), 0);
|
|
const Struct_w_vector *ptr2 = e2.get<Struct_w_vector>();
|
|
test_assert(ptr2 != NULL);
|
|
test_int(ptr2->value.size(), 0);
|
|
|
|
e1.remove<Struct_w_vector>();
|
|
ptr1 = e1.get<Struct_w_vector>();
|
|
test_assert(ptr1 == NULL);
|
|
|
|
ptr2 = e2.get<Struct_w_vector>();
|
|
test_assert(ptr2 != NULL);
|
|
test_int(ptr2->value.size(), 0);
|
|
|
|
e2.remove<Struct_w_vector>();
|
|
ptr2 = e2.get<Struct_w_vector>();
|
|
test_assert(ptr2 == NULL);
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_vector_set_2_remove(void) {
|
|
flecs::world world;
|
|
|
|
auto e1 = world.entity().set<Struct_w_vector>({std::vector<int>{1, 2}});
|
|
auto e2 = world.entity().set<Struct_w_vector>({std::vector<int>{3, 4}});
|
|
|
|
const Struct_w_vector *ptr1 = e1.get<Struct_w_vector>();
|
|
test_assert(ptr1 != NULL);
|
|
test_int(ptr1->value.size(), 2);
|
|
test_int(ptr1->value.at(0), 1);
|
|
test_int(ptr1->value.at(1), 2);
|
|
const Struct_w_vector *ptr2 = e2.get<Struct_w_vector>();
|
|
test_assert(ptr2 != NULL);
|
|
test_int(ptr2->value.size(), 2);
|
|
test_int(ptr2->value.at(0), 3);
|
|
test_int(ptr2->value.at(1), 4);
|
|
|
|
e1.remove<Struct_w_vector>();
|
|
ptr1 = e1.get<Struct_w_vector>();
|
|
test_assert(ptr1 == NULL);
|
|
|
|
ptr2 = e2.get<Struct_w_vector>();
|
|
test_assert(ptr2 != NULL);
|
|
test_int(ptr2->value.size(), 2);
|
|
test_int(ptr2->value.at(0), 3);
|
|
test_int(ptr2->value.at(1), 4);
|
|
|
|
e2.remove<Struct_w_vector>();
|
|
ptr2 = e2.get<Struct_w_vector>();
|
|
test_assert(ptr2 == NULL);
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_vector_add_2_remove_w_tag(void) {
|
|
flecs::world world;
|
|
|
|
auto e1 = world.entity().add<Tag>().add<Struct_w_vector>();
|
|
auto e2 = world.entity().add<Tag>().add<Struct_w_vector>();
|
|
|
|
const Struct_w_vector *ptr1 = e1.get<Struct_w_vector>();
|
|
test_assert(ptr1 != NULL);
|
|
test_int(ptr1->value.size(), 0);
|
|
const Struct_w_vector *ptr2 = e2.get<Struct_w_vector>();
|
|
test_assert(ptr2 != NULL);
|
|
test_int(ptr2->value.size(), 0);
|
|
|
|
e1.remove<Struct_w_vector>();
|
|
ptr1 = e1.get<Struct_w_vector>();
|
|
test_assert(ptr1 == NULL);
|
|
|
|
ptr2 = e2.get<Struct_w_vector>();
|
|
test_assert(ptr2 != NULL);
|
|
test_int(ptr2->value.size(), 0);
|
|
|
|
e2.remove<Struct_w_vector>();
|
|
ptr2 = e2.get<Struct_w_vector>();
|
|
test_assert(ptr2 == NULL);
|
|
}
|
|
|
|
void ComponentLifecycle_struct_w_vector_set_2_remove_w_tag(void) {
|
|
flecs::world world;
|
|
|
|
auto e1 = world.entity().add<Tag>().set<Struct_w_vector>({std::vector<int>{1, 2}});
|
|
auto e2 = world.entity().add<Tag>().set<Struct_w_vector>({std::vector<int>{3, 4}});
|
|
|
|
const Struct_w_vector *ptr1 = e1.get<Struct_w_vector>();
|
|
test_assert(ptr1 != NULL);
|
|
test_int(ptr1->value.size(), 2);
|
|
test_int(ptr1->value.at(0), 1);
|
|
test_int(ptr1->value.at(1), 2);
|
|
const Struct_w_vector *ptr2 = e2.get<Struct_w_vector>();
|
|
test_assert(ptr2 != NULL);
|
|
test_int(ptr2->value.size(), 2);
|
|
test_int(ptr2->value.at(0), 3);
|
|
test_int(ptr2->value.at(1), 4);
|
|
|
|
e1.remove<Struct_w_vector>();
|
|
ptr1 = e1.get<Struct_w_vector>();
|
|
test_assert(ptr1 == NULL);
|
|
|
|
ptr2 = e2.get<Struct_w_vector>();
|
|
test_assert(ptr2 != NULL);
|
|
test_int(ptr2->value.size(), 2);
|
|
test_int(ptr2->value.at(0), 3);
|
|
test_int(ptr2->value.at(1), 4);
|
|
|
|
e2.remove<Struct_w_vector>();
|
|
ptr2 = e2.get<Struct_w_vector>();
|
|
test_assert(ptr2 == NULL);
|
|
}
|
|
|
|
void ComponentLifecycle_get_mut_new(void) {
|
|
flecs::world world;
|
|
|
|
world.component<Pod>();
|
|
|
|
auto e = world.entity();
|
|
test_assert(e.id() != 0);
|
|
|
|
Pod* value = e.get_mut<Pod>();
|
|
test_assert(value != NULL);
|
|
|
|
Pod::ctor_invoked = 1;
|
|
Pod::dtor_invoked = 0;
|
|
Pod::copy_invoked = 0;
|
|
Pod::move_invoked = 0;
|
|
|
|
e.modified<Pod>();
|
|
|
|
Pod::ctor_invoked = 1;
|
|
Pod::dtor_invoked = 0;
|
|
Pod::copy_invoked = 0;
|
|
Pod::move_invoked = 0;
|
|
}
|
|
|
|
void ComponentLifecycle_get_mut_existing(void) {
|
|
flecs::world world;
|
|
|
|
world.component<Pod>();
|
|
|
|
auto e = world.entity();
|
|
test_assert(e.id() != 0);
|
|
|
|
Pod* value = e.get_mut<Pod>();
|
|
test_assert(value != NULL);
|
|
|
|
Pod::ctor_invoked = 1;
|
|
Pod::dtor_invoked = 0;
|
|
Pod::copy_invoked = 0;
|
|
Pod::move_invoked = 0;
|
|
|
|
value = e.get_mut<Pod>();
|
|
test_assert(value != NULL);
|
|
|
|
/* Repeated calls to get_mut should not invoke constructor */
|
|
Pod::ctor_invoked = 1;
|
|
Pod::dtor_invoked = 0;
|
|
Pod::copy_invoked = 0;
|
|
Pod::move_invoked = 0;
|
|
}
|
|
|
|
void ComponentLifecycle_implicit_component(void) {
|
|
flecs::world world;
|
|
|
|
auto e = world.entity().add<Pod>();
|
|
test_assert(e.id() != 0);
|
|
test_assert(e.has<Pod>());
|
|
test_int(Pod::ctor_invoked, 1);
|
|
|
|
const Pod *pod = e.get<Pod>();
|
|
test_assert(pod != NULL);
|
|
|
|
test_int(pod->value, 10);
|
|
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 0);
|
|
test_int(Pod::copy_invoked, 0);
|
|
test_int(Pod::move_invoked, 0);
|
|
|
|
world.entity().add<Pod>();
|
|
|
|
test_int(Pod::ctor_invoked, 2);
|
|
test_int(Pod::move_ctor_invoked, 0);
|
|
test_int(Pod::move_invoked, 0);
|
|
|
|
world.entity().add<Pod>();
|
|
|
|
test_int(Pod::ctor_invoked, 3);
|
|
test_int(Pod::move_ctor_invoked, 2);
|
|
test_int(Pod::move_invoked, 0);
|
|
}
|
|
|
|
void ComponentLifecycle_implicit_after_query(void) {
|
|
flecs::world world;
|
|
|
|
world.query<Pod>();
|
|
|
|
auto e = world.entity().add<Pod>();
|
|
test_assert(e.id() != 0);
|
|
test_assert(e.has<Pod>());
|
|
test_int(Pod::ctor_invoked, 1);
|
|
|
|
const Pod *pod = e.get<Pod>();
|
|
test_assert(pod != NULL);
|
|
|
|
test_int(pod->value, 10);
|
|
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 0);
|
|
test_int(Pod::copy_invoked, 0);
|
|
test_int(Pod::move_invoked, 0);
|
|
|
|
world.entity().add<Pod>();
|
|
|
|
test_int(Pod::ctor_invoked, 2);
|
|
test_int(Pod::move_ctor_invoked, 0);
|
|
test_int(Pod::move_invoked, 0);
|
|
|
|
world.entity().add<Pod>();
|
|
|
|
test_int(Pod::ctor_invoked, 3);
|
|
test_int(Pod::move_ctor_invoked, 2);
|
|
test_int(Pod::move_invoked, 0);
|
|
}
|
|
|
|
template <typename T>
|
|
static void try_add(flecs::world& ecs) {
|
|
flecs::entity e = ecs.entity().add<T>();
|
|
|
|
test_assert(e.has<T>());
|
|
|
|
const T *ptr = e.get<T>();
|
|
test_int(ptr->x_, 99);
|
|
|
|
e.remove<T>();
|
|
test_assert(!e.has<T>());
|
|
}
|
|
|
|
template <typename T>
|
|
static void try_add_relation(flecs::world& ecs) {
|
|
flecs::entity obj = ecs.entity();
|
|
|
|
flecs::entity e = ecs.entity().add<T>(obj);
|
|
test_assert(e.has<T>());
|
|
|
|
const T *ptr = e.get<T>();
|
|
test_int(ptr->x_, 89);
|
|
|
|
e.remove<T>();
|
|
test_assert(!e.has<T>());
|
|
}
|
|
|
|
template <typename T>
|
|
static void try_add_second(flecs::world& ecs) {
|
|
flecs::entity rel = ecs.entity();
|
|
|
|
flecs::entity e = ecs.entity().add_second<T>(rel);
|
|
test_assert(e.has<T>());
|
|
|
|
const T *ptr = e.get<T>();
|
|
test_int(ptr->x_, 89);
|
|
|
|
e.remove<T>();
|
|
test_assert(!e.has<T>());
|
|
}
|
|
|
|
template <typename T>
|
|
static void try_set(flecs::world& ecs) {
|
|
flecs::entity e = ecs.entity().set<T>({10});
|
|
|
|
const T *ptr = e.get<T>();
|
|
test_int(ptr->x_, 10);
|
|
}
|
|
|
|
template <typename T>
|
|
static void try_emplace(flecs::world& ecs) {
|
|
flecs::entity e = ecs.entity().emplace<T>(10);
|
|
|
|
const T *ptr = e.get<T>();
|
|
test_int(ptr->x_, 10);
|
|
}
|
|
|
|
template <typename T>
|
|
static void try_set_default(flecs::world& ecs) {
|
|
flecs::entity e = ecs.entity().set(T());
|
|
|
|
const T *ptr = e.get<T>();
|
|
test_int(ptr->x_, 99);
|
|
|
|
e.remove<T>();
|
|
}
|
|
|
|
void ComponentLifecycle_deleted_copy(void) {
|
|
flecs::world ecs;
|
|
|
|
ecs.component<NoCopy>();
|
|
|
|
try_add<NoCopy>(ecs);
|
|
|
|
try_set<NoCopy>(ecs);
|
|
}
|
|
|
|
void ComponentLifecycle_no_default_ctor_emplace(void) {
|
|
flecs::world ecs;
|
|
|
|
ecs.component<NoDefaultCtor>();
|
|
|
|
try_emplace<NoDefaultCtor>(ecs);
|
|
}
|
|
|
|
void ComponentLifecycle_default_init(void) {
|
|
flecs::world ecs;
|
|
|
|
ecs.component<DefaultInit>();
|
|
|
|
try_add<DefaultInit>(ecs);
|
|
|
|
try_set<DefaultInit>(ecs);
|
|
}
|
|
|
|
void ComponentLifecycle_no_default_ctor_add(void) {
|
|
install_test_abort();
|
|
|
|
flecs::world ecs;
|
|
|
|
ecs.component<NoDefaultCtor>();
|
|
|
|
test_expect_abort();
|
|
|
|
try_add<NoDefaultCtor>(ecs);
|
|
}
|
|
|
|
void ComponentLifecycle_no_default_ctor_add_relation(void) {
|
|
install_test_abort();
|
|
|
|
flecs::world ecs;
|
|
|
|
ecs.component<NoDefaultCtor>();
|
|
|
|
test_expect_abort();
|
|
|
|
try_add_relation<NoDefaultCtor>(ecs);
|
|
}
|
|
|
|
void ComponentLifecycle_no_default_ctor_add_second(void) {
|
|
install_test_abort();
|
|
|
|
flecs::world ecs;
|
|
|
|
ecs.component<NoDefaultCtor>();
|
|
|
|
test_expect_abort();
|
|
|
|
try_add_second<NoDefaultCtor>(ecs);
|
|
}
|
|
|
|
void ComponentLifecycle_no_default_ctor_set(void) {
|
|
install_test_abort();
|
|
|
|
flecs::world ecs;
|
|
|
|
ecs.component<NoDefaultCtor>();
|
|
|
|
test_expect_abort();
|
|
|
|
try_set<NoDefaultCtor>(ecs);
|
|
}
|
|
|
|
void ComponentLifecycle_no_copy_ctor(void) {
|
|
flecs::world ecs;
|
|
|
|
ecs.component<NoCopyCtor>();
|
|
|
|
try_add<NoCopyCtor>(ecs);
|
|
|
|
try_set<NoCopyCtor>(ecs);
|
|
}
|
|
|
|
void ComponentLifecycle_no_move_ctor(void) {
|
|
install_test_abort();
|
|
|
|
flecs::world ecs;
|
|
|
|
test_expect_abort();
|
|
|
|
ecs.component<NoMoveCtor>();
|
|
}
|
|
|
|
void ComponentLifecycle_no_copy_assign(void) {
|
|
flecs::world ecs;
|
|
|
|
ecs.component<NoCopyAssign>();
|
|
|
|
try_add<NoCopyAssign>(ecs);
|
|
|
|
try_set<NoCopyAssign>(ecs);
|
|
}
|
|
|
|
void ComponentLifecycle_no_move_assign(void) {
|
|
install_test_abort();
|
|
|
|
flecs::world ecs;
|
|
|
|
test_expect_abort();
|
|
|
|
ecs.component<NoMoveAssign>();
|
|
}
|
|
|
|
void ComponentLifecycle_no_copy(void) {
|
|
flecs::world ecs;
|
|
|
|
ecs.component<NoCopy>();
|
|
|
|
try_add<NoCopy>(ecs);
|
|
|
|
try_set<NoCopy>(ecs);
|
|
}
|
|
|
|
void ComponentLifecycle_no_move(void) {
|
|
install_test_abort();
|
|
|
|
flecs::world ecs;
|
|
|
|
test_expect_abort();
|
|
|
|
ecs.component<NoMove>();
|
|
}
|
|
|
|
void ComponentLifecycle_no_dtor(void) {
|
|
install_test_abort();
|
|
|
|
flecs::world ecs;
|
|
|
|
test_expect_abort();
|
|
|
|
ecs.component<NoDtor>();
|
|
}
|
|
|
|
void ComponentLifecycle_default_ctor_w_value_ctor(void) {
|
|
flecs::world ecs;
|
|
|
|
ecs.component<DefaultCtorValueCtor>();
|
|
|
|
try_add<DefaultCtorValueCtor>(ecs);
|
|
|
|
try_set<DefaultCtorValueCtor>(ecs);
|
|
|
|
try_set_default<FlecsCtorDefaultCtor>(ecs);
|
|
}
|
|
|
|
void ComponentLifecycle_no_default_ctor_move_ctor_on_set(void) {
|
|
flecs::world ecs;
|
|
|
|
ecs.component<CountNoDefaultCtor>();
|
|
|
|
// Emplace, construct
|
|
auto e = ecs.entity().emplace<CountNoDefaultCtor>(10);
|
|
test_assert(e.has<CountNoDefaultCtor>());
|
|
|
|
const CountNoDefaultCtor* ptr = e.get<CountNoDefaultCtor>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->value, 10);
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 0);
|
|
|
|
// Set, move assign
|
|
e.set<CountNoDefaultCtor>({10});
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 2);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 1);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 0);
|
|
}
|
|
|
|
void ComponentLifecycle_emplace_w_ctor(void) {
|
|
flecs::world ecs;
|
|
|
|
auto e = ecs.entity()
|
|
.emplace<Pod>(10);
|
|
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 0);
|
|
|
|
const Pod *ptr = e.get<Pod>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->value, 10);
|
|
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 0);
|
|
}
|
|
|
|
void ComponentLifecycle_emplace_no_default_ctor(void) {
|
|
flecs::world ecs;
|
|
|
|
auto e = ecs.entity()
|
|
.emplace<CountNoDefaultCtor>(10);
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 0);
|
|
|
|
const CountNoDefaultCtor *ptr = e.get<CountNoDefaultCtor>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->value, 10);
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 0);
|
|
}
|
|
|
|
void ComponentLifecycle_emplace_defer_use_move_ctor(void) {
|
|
{
|
|
flecs::world ecs;
|
|
|
|
auto e = ecs.entity();
|
|
|
|
ecs.defer_begin();
|
|
e.emplace<CountNoDefaultCtor>(10);
|
|
test_assert(!e.has<CountNoDefaultCtor>());
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 0);
|
|
ecs.defer_end();
|
|
|
|
test_assert(e.has<CountNoDefaultCtor>());
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 1);
|
|
|
|
const CountNoDefaultCtor *ptr = e.get<CountNoDefaultCtor>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->value, 10);
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 1);
|
|
}
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 2);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 1);
|
|
}
|
|
|
|
void ComponentLifecycle_emplace_existing(void) {
|
|
install_test_abort();
|
|
|
|
flecs::world ecs;
|
|
|
|
auto e = ecs.entity()
|
|
.emplace<Pod>(10);
|
|
|
|
const Pod *ptr = e.get<Pod>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->value, 10);
|
|
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 0);
|
|
|
|
test_expect_abort();
|
|
e.emplace<Pod>(20);
|
|
}
|
|
|
|
void ComponentLifecycle_emplace_singleton(void) {
|
|
flecs::world ecs;
|
|
|
|
ecs.emplace<Pod>(10);
|
|
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 0);
|
|
|
|
const Pod *ptr = ecs.get<Pod>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->value, 10);
|
|
|
|
test_int(Pod::ctor_invoked, 1);
|
|
test_int(Pod::dtor_invoked, 0);
|
|
}
|
|
|
|
class CtorDtorNonTrivial {
|
|
public:
|
|
CtorDtorNonTrivial(int x) : x_(x) {
|
|
ctor_invoked ++;
|
|
}
|
|
|
|
~CtorDtorNonTrivial() {
|
|
dtor_invoked ++;
|
|
dtor_value = x_;
|
|
}
|
|
|
|
int x_;
|
|
std::string str_;
|
|
|
|
static int ctor_invoked;
|
|
static int dtor_invoked;
|
|
static int dtor_value;
|
|
};
|
|
|
|
int CtorDtorNonTrivial::ctor_invoked;
|
|
int CtorDtorNonTrivial::dtor_invoked;
|
|
int CtorDtorNonTrivial::dtor_value;
|
|
|
|
void ComponentLifecycle_dtor_w_non_trivial_implicit_move(void) {
|
|
flecs::world ecs;
|
|
|
|
test_bool(std::is_trivially_move_assignable<CtorDtorNonTrivial>::value, false);
|
|
test_bool(std::is_move_assignable<CtorDtorNonTrivial>::value, true);
|
|
|
|
auto e_1 = ecs.entity().emplace<CtorDtorNonTrivial>(10);
|
|
auto e_2 = ecs.entity().emplace<CtorDtorNonTrivial>(20);
|
|
|
|
const CtorDtorNonTrivial *ptr = e_1.get<CtorDtorNonTrivial>();
|
|
test_assert(ptr != nullptr);
|
|
test_int(ptr->x_, 10);
|
|
|
|
ptr = e_2.get<CtorDtorNonTrivial>();
|
|
test_assert(ptr != nullptr);
|
|
test_int(ptr->x_, 20);
|
|
|
|
test_int(CtorDtorNonTrivial::ctor_invoked, 2);
|
|
|
|
// Moves e_2 to e_1
|
|
e_1.destruct();
|
|
|
|
test_int(CtorDtorNonTrivial::ctor_invoked, 2);
|
|
test_int(CtorDtorNonTrivial::dtor_invoked, 1);
|
|
|
|
// Counter intuitive but correct. The class is not trivially movable, so
|
|
// the move assignment should take care of cleaning up e_1 (10). That still
|
|
// leaves the original e_2 which was moved from, but not destructed.
|
|
//
|
|
// In a real application the class should probably implement its own move
|
|
// assignment to ensure correct destructor behavior.
|
|
test_int(CtorDtorNonTrivial::dtor_value, 20);
|
|
}
|
|
|
|
class CtorDtor_w_MoveAssign {
|
|
public:
|
|
CtorDtor_w_MoveAssign(int x) : x_(x) {
|
|
ctor_invoked ++;
|
|
}
|
|
|
|
~CtorDtor_w_MoveAssign() {
|
|
dtor_invoked ++;
|
|
dtor_value = x_;
|
|
}
|
|
|
|
CtorDtor_w_MoveAssign(const CtorDtor_w_MoveAssign& obj) = default;
|
|
CtorDtor_w_MoveAssign(CtorDtor_w_MoveAssign&& obj) = default;
|
|
CtorDtor_w_MoveAssign& operator=(const CtorDtor_w_MoveAssign& obj) = default;
|
|
|
|
CtorDtor_w_MoveAssign& operator=(CtorDtor_w_MoveAssign&& obj) {
|
|
move_value = this->x_;
|
|
|
|
this->x_ = obj.x_;
|
|
obj.x_ = 0;
|
|
return *this;
|
|
}
|
|
|
|
int x_;
|
|
std::string str_;
|
|
|
|
static int ctor_invoked;
|
|
static int dtor_invoked;
|
|
static int dtor_value;
|
|
static int move_value;
|
|
};
|
|
|
|
int CtorDtor_w_MoveAssign::ctor_invoked;
|
|
int CtorDtor_w_MoveAssign::dtor_invoked;
|
|
int CtorDtor_w_MoveAssign::dtor_value;
|
|
int CtorDtor_w_MoveAssign::move_value;
|
|
|
|
void ComponentLifecycle_dtor_w_non_trivial_explicit_move(void) {
|
|
flecs::world ecs;
|
|
|
|
test_bool(std::is_trivially_move_assignable<CtorDtor_w_MoveAssign>::value, false);
|
|
test_bool(std::is_move_assignable<CtorDtor_w_MoveAssign>::value, true);
|
|
|
|
auto e_1 = ecs.entity().emplace<CtorDtor_w_MoveAssign>(10);
|
|
auto e_2 = ecs.entity().emplace<CtorDtor_w_MoveAssign>(20);
|
|
|
|
const CtorDtor_w_MoveAssign *ptr = e_1.get<CtorDtor_w_MoveAssign>();
|
|
test_assert(ptr != nullptr);
|
|
test_int(ptr->x_, 10);
|
|
|
|
ptr = e_2.get<CtorDtor_w_MoveAssign>();
|
|
test_assert(ptr != nullptr);
|
|
test_int(ptr->x_, 20);
|
|
|
|
test_int(CtorDtor_w_MoveAssign::ctor_invoked, 2);
|
|
|
|
// Moves e_2 to e_1
|
|
e_1.destruct();
|
|
|
|
test_int(CtorDtor_w_MoveAssign::ctor_invoked, 2);
|
|
test_int(CtorDtor_w_MoveAssign::dtor_invoked, 1);
|
|
|
|
test_int(CtorDtor_w_MoveAssign::move_value, 10);
|
|
test_int(CtorDtor_w_MoveAssign::dtor_value, 0);
|
|
}
|
|
|
|
void ComponentLifecycle_grow_no_default_ctor(void) {
|
|
{
|
|
flecs::world world;
|
|
|
|
world.component<CountNoDefaultCtor>();
|
|
|
|
auto e1 = world.entity().emplace<CountNoDefaultCtor>(1);
|
|
auto e2 = world.entity().emplace<CountNoDefaultCtor>(2);
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 2);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 0);
|
|
|
|
auto e3 = world.entity().emplace<CountNoDefaultCtor>(3);
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 3);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 2);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 2);
|
|
|
|
test_assert(e1.has<CountNoDefaultCtor>());
|
|
test_assert(e2.has<CountNoDefaultCtor>());
|
|
test_assert(e3.has<CountNoDefaultCtor>());
|
|
|
|
test_int(e1.get<CountNoDefaultCtor>()->value, 1);
|
|
test_int(e2.get<CountNoDefaultCtor>()->value, 2);
|
|
test_int(e3.get<CountNoDefaultCtor>()->value, 3);
|
|
}
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 3);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 5);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 2);
|
|
}
|
|
|
|
void ComponentLifecycle_grow_no_default_ctor_move(void) {
|
|
{
|
|
flecs::world world;
|
|
|
|
world.component<CountNoDefaultCtor>();
|
|
world.component<Tag>();
|
|
|
|
auto e1 = world.entity().emplace<CountNoDefaultCtor>(1);
|
|
auto e2 = world.entity().emplace<CountNoDefaultCtor>(2);
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 2);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 0);
|
|
|
|
CountNoDefaultCtor::reset();
|
|
auto e3 = world.entity().emplace<CountNoDefaultCtor>(3);
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 2);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 2);
|
|
|
|
test_assert(e1.has<CountNoDefaultCtor>());
|
|
test_assert(e2.has<CountNoDefaultCtor>());
|
|
test_assert(e3.has<CountNoDefaultCtor>());
|
|
|
|
test_int(e1.get<CountNoDefaultCtor>()->value, 1);
|
|
test_int(e2.get<CountNoDefaultCtor>()->value, 2);
|
|
test_int(e3.get<CountNoDefaultCtor>()->value, 3);
|
|
|
|
CountNoDefaultCtor::reset();
|
|
e1.add<Tag>();
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 1);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 1);
|
|
|
|
CountNoDefaultCtor::reset();
|
|
e2.add<Tag>();
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 1);
|
|
|
|
CountNoDefaultCtor::reset();
|
|
e3.add<Tag>();
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 3);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 3);
|
|
|
|
CountNoDefaultCtor::reset();
|
|
}
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 3);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 0);
|
|
}
|
|
|
|
void ComponentLifecycle_grow_no_default_ctor_move_w_component(void) {
|
|
{
|
|
flecs::world world;
|
|
|
|
world.component<CountNoDefaultCtor>();
|
|
world.component<Position>();
|
|
|
|
auto e1 = world.entity().emplace<CountNoDefaultCtor>(1);
|
|
auto e2 = world.entity().emplace<CountNoDefaultCtor>(2);
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 2);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 0);
|
|
|
|
CountNoDefaultCtor::reset();
|
|
auto e3 = world.entity().emplace<CountNoDefaultCtor>(3);
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 2);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 2);
|
|
|
|
test_assert(e1.has<CountNoDefaultCtor>());
|
|
test_assert(e2.has<CountNoDefaultCtor>());
|
|
test_assert(e3.has<CountNoDefaultCtor>());
|
|
|
|
test_int(e1.get<CountNoDefaultCtor>()->value, 1);
|
|
test_int(e2.get<CountNoDefaultCtor>()->value, 2);
|
|
test_int(e3.get<CountNoDefaultCtor>()->value, 3);
|
|
|
|
CountNoDefaultCtor::reset();
|
|
e1.add<Position>();
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 1);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 1);
|
|
|
|
CountNoDefaultCtor::reset();
|
|
e2.add<Position>(); // e2 is last element, e3 got moved to e1's location
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 1);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 1);
|
|
|
|
CountNoDefaultCtor::reset();
|
|
e3.add<Position>();
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 3); /* 2 (e1,e2) for resize, 1 (e3) for moved away storage */
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 3); /* resize */
|
|
|
|
CountNoDefaultCtor::reset();
|
|
}
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 3);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 0);
|
|
}
|
|
|
|
void ComponentLifecycle_delete_no_default_ctor(void) {
|
|
{
|
|
flecs::world world;
|
|
|
|
world.component<CountNoDefaultCtor>();
|
|
|
|
auto e1 = world.entity().emplace<CountNoDefaultCtor>(1);
|
|
auto e2 = world.entity().emplace<CountNoDefaultCtor>(2);
|
|
auto e3 = world.entity().emplace<CountNoDefaultCtor>(3);
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 3);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 2);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 0);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 2);
|
|
|
|
test_assert(e1.has<CountNoDefaultCtor>());
|
|
test_assert(e2.has<CountNoDefaultCtor>());
|
|
test_assert(e3.has<CountNoDefaultCtor>());
|
|
|
|
test_int(e1.get<CountNoDefaultCtor>()->value, 1);
|
|
test_int(e2.get<CountNoDefaultCtor>()->value, 2);
|
|
test_int(e3.get<CountNoDefaultCtor>()->value, 3);
|
|
|
|
e2.destruct();
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 3);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 3);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 1);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 2);
|
|
}
|
|
|
|
test_int(CountNoDefaultCtor::ctor_invoked, 3);
|
|
test_int(CountNoDefaultCtor::dtor_invoked, 5);
|
|
test_int(CountNoDefaultCtor::copy_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_invoked, 1);
|
|
test_int(CountNoDefaultCtor::copy_ctor_invoked, 0);
|
|
test_int(CountNoDefaultCtor::move_ctor_invoked, 2);
|
|
}
|
|
|
|
void ComponentLifecycle_on_add_hook(void) {
|
|
int count = 0;
|
|
|
|
{
|
|
flecs::world ecs;
|
|
|
|
ecs.component<Position>().on_add([&](Position& p) {
|
|
count ++;
|
|
});
|
|
|
|
test_int(0, count);
|
|
|
|
auto e = ecs.entity().add<Position>();
|
|
test_int(1, count);
|
|
|
|
e.add<Position>();
|
|
test_int(1, count);
|
|
}
|
|
|
|
test_int(1, count);
|
|
}
|
|
|
|
void ComponentLifecycle_on_remove_hook(void) {
|
|
int count = 0;
|
|
|
|
{
|
|
flecs::world ecs;
|
|
|
|
ecs.component<Position>().on_remove([&](Position& p) {
|
|
count ++;
|
|
});
|
|
|
|
test_int(0, count);
|
|
|
|
auto e1 = ecs.entity().add<Position>();
|
|
ecs.entity().add<Position>();
|
|
test_int(0, count);
|
|
|
|
e1.remove<Position>();
|
|
test_int(1, count);
|
|
}
|
|
|
|
test_int(2, count);
|
|
}
|
|
|
|
void ComponentLifecycle_on_set_hook(void) {
|
|
int count = 0;
|
|
Position v = {0};
|
|
|
|
{
|
|
flecs::world ecs;
|
|
|
|
ecs.component<Position>().on_set([&](Position& p) {
|
|
count ++;
|
|
v = p;
|
|
});
|
|
|
|
test_int(0, count);
|
|
|
|
auto e1 = ecs.entity().add<Position>();
|
|
test_int(0, count);
|
|
|
|
e1.set<Position>({10, 20});
|
|
test_int(1, count);
|
|
test_int(10, v.x);
|
|
test_int(20, v.y);
|
|
|
|
ecs.entity().set<Position>({30, 40});
|
|
test_int(2, count);
|
|
test_int(30, v.x);
|
|
test_int(40, v.y);
|
|
}
|
|
|
|
test_int(2, count);
|
|
}
|
|
|
|
void ComponentLifecycle_on_add_hook_w_entity(void) {
|
|
int count = 0;
|
|
flecs::entity e_arg;
|
|
|
|
{
|
|
flecs::world ecs;
|
|
|
|
ecs.component<Position>().on_add([&](flecs::entity arg, Position& p) {
|
|
e_arg = arg;
|
|
count ++;
|
|
});
|
|
|
|
test_int(0, count);
|
|
test_assert(e_arg == 0);
|
|
|
|
auto e = ecs.entity().add<Position>();
|
|
test_int(1, count);
|
|
test_assert(e_arg == e);
|
|
|
|
e.add<Position>();
|
|
test_int(1, count);
|
|
}
|
|
|
|
test_int(1, count);
|
|
}
|
|
|
|
void ComponentLifecycle_on_remove_hook_w_entity(void) {
|
|
int count = 0;
|
|
flecs::entity e_arg;
|
|
flecs::entity e2;
|
|
|
|
{
|
|
flecs::world ecs;
|
|
|
|
ecs.component<Position>().on_remove([&](flecs::entity arg, Position& p){
|
|
e_arg = arg;
|
|
count ++;
|
|
});
|
|
|
|
test_int(0, count);
|
|
test_assert(e_arg == 0);
|
|
|
|
auto e1 = ecs.entity().add<Position>();
|
|
e2 = ecs.entity().add<Position>();
|
|
test_int(0, count);
|
|
|
|
e1.remove<Position>();
|
|
test_int(1, count);
|
|
test_assert(e_arg == e1);
|
|
}
|
|
|
|
test_int(2, count);
|
|
test_assert(e_arg == e2);
|
|
}
|
|
|
|
void ComponentLifecycle_on_set_hook_w_entity(void) {
|
|
int count = 0;
|
|
Position v = {0};
|
|
flecs::entity e_arg;
|
|
|
|
{
|
|
flecs::world ecs;
|
|
|
|
ecs.component<Position>().on_set([&](flecs::entity arg, Position& p) {
|
|
count ++;
|
|
v = p;
|
|
e_arg = arg;
|
|
});
|
|
|
|
test_int(0, count);
|
|
|
|
auto e1 = ecs.entity().add<Position>();
|
|
test_int(0, count);
|
|
|
|
e1.set<Position>({10, 20});
|
|
test_int(1, count);
|
|
test_assert(e_arg == e1);
|
|
test_int(10, v.x);
|
|
test_int(20, v.y);
|
|
|
|
auto e2 = ecs.entity().set<Position>({30, 40});
|
|
test_int(2, count);
|
|
test_assert(e_arg == e2);
|
|
test_int(30, v.x);
|
|
test_int(40, v.y);
|
|
}
|
|
|
|
test_int(2, count);
|
|
}
|
|
|
|
void ComponentLifecycle_chained_hooks(void) {
|
|
flecs::world ecs;
|
|
|
|
int32_t add_count = 0;
|
|
int32_t remove_count = 0;
|
|
int32_t set_count = 0;
|
|
|
|
ecs.component<Position>()
|
|
.on_add([&](Position& p){
|
|
add_count ++;
|
|
})
|
|
.on_set([&](Position& p){
|
|
set_count ++;
|
|
})
|
|
.on_remove([&](Position& p){
|
|
remove_count ++;
|
|
});
|
|
|
|
auto e = ecs.entity();
|
|
test_int(0, add_count);
|
|
test_int(0, set_count);
|
|
test_int(0, remove_count);
|
|
|
|
e.add<Position>();
|
|
test_int(1, add_count);
|
|
test_int(0, set_count);
|
|
test_int(0, remove_count);
|
|
|
|
e.set<Position>({10, 20});
|
|
test_int(1, add_count);
|
|
test_int(1, set_count);
|
|
test_int(0, remove_count);
|
|
|
|
e.remove<Position>();
|
|
test_int(1, add_count);
|
|
test_int(1, set_count);
|
|
test_int(1, remove_count);
|
|
}
|
|
|
|
void ComponentLifecycle_ctor_w_2_worlds(void) {
|
|
{
|
|
flecs::world ecs;
|
|
|
|
test_int(Pod::ctor_invoked, 0);
|
|
|
|
ecs.entity().add<Pod>();
|
|
test_int(Pod::ctor_invoked, 1);
|
|
}
|
|
|
|
Pod::ctor_invoked = 0;
|
|
|
|
{
|
|
flecs::world ecs;
|
|
|
|
test_int(Pod::ctor_invoked, 0);
|
|
|
|
ecs.entity().add<Pod>();
|
|
test_int(Pod::ctor_invoked, 1);
|
|
}
|
|
}
|
|
|
|
void ComponentLifecycle_ctor_w_2_worlds_explicit_registration(void) {
|
|
{
|
|
flecs::world ecs;
|
|
|
|
ecs.component<Pod>();
|
|
test_int(Pod::ctor_invoked, 0);
|
|
|
|
ecs.entity().add<Pod>();
|
|
test_int(Pod::ctor_invoked, 1);
|
|
}
|
|
|
|
Pod::ctor_invoked = 0;
|
|
|
|
{
|
|
flecs::world ecs;
|
|
|
|
ecs.component<Pod>();
|
|
test_int(Pod::ctor_invoked, 0);
|
|
|
|
ecs.entity().add<Pod>();
|
|
test_int(Pod::ctor_invoked, 1);
|
|
}
|
|
}
|
|
|
|
struct DeferEmplaceTest {
|
|
double x, y;
|
|
|
|
DeferEmplaceTest(double x_, double y_) {
|
|
x = x_;
|
|
y = y_;
|
|
}
|
|
};
|
|
|
|
void ComponentLifecycle_defer_emplace(void) {
|
|
flecs::world ecs;
|
|
|
|
flecs::entity e = ecs.entity();
|
|
|
|
ecs.defer_begin();
|
|
e.emplace<DeferEmplaceTest>(10.0, 20.0);
|
|
test_assert(!e.has<DeferEmplaceTest>());
|
|
ecs.defer_end();
|
|
test_assert(e.has<DeferEmplaceTest>());
|
|
|
|
const DeferEmplaceTest *p = e.get<DeferEmplaceTest>();
|
|
test_assert(p != NULL);
|
|
test_int(p->x, 10);
|
|
test_int(p->y, 20);
|
|
}
|
|
|
|
void ComponentLifecycle_emplace_w_on_add(void) {
|
|
flecs::world ecs;
|
|
|
|
flecs::entity e1 = ecs.entity();
|
|
|
|
int on_add = 0;
|
|
ecs.component<Position>()
|
|
.on_add([&](flecs::entity e, Position&) {
|
|
on_add = true;
|
|
test_assert(e == e1);
|
|
});
|
|
|
|
e1.emplace<Position>();
|
|
test_int(on_add, 1);
|
|
}
|
|
|
|
void ComponentLifecycle_emplace_w_on_add_existing(void) {
|
|
flecs::world ecs;
|
|
|
|
flecs::entity e1 = ecs.entity().add<Velocity>();
|
|
|
|
int on_add = 0;
|
|
ecs.component<Position>()
|
|
.on_add([&](flecs::entity e, Position&) {
|
|
on_add = true;
|
|
test_assert(e == e1);
|
|
});
|
|
|
|
e1.emplace<Position>();
|
|
test_int(on_add, 1);
|
|
}
|
|
|
|
void ComponentLifecycle_set_pair_no_copy(void) {
|
|
flecs::world ecs;
|
|
|
|
struct Tag { };
|
|
|
|
flecs::entity e = ecs.entity()
|
|
.set<NoCopy, Tag>({ 10 });
|
|
|
|
const NoCopy *ptr = e.get<NoCopy, Tag>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->x_, 10);
|
|
}
|
|
|
|
void ComponentLifecycle_set_pair_w_entity_no_copy(void) {
|
|
flecs::world ecs;
|
|
|
|
flecs::entity tag = ecs.entity();
|
|
|
|
flecs::entity e = ecs.entity()
|
|
.set<NoCopy>(tag, { 10 });
|
|
|
|
const NoCopy *ptr = e.get<NoCopy>(tag);
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->x_, 10);
|
|
}
|
|
|
|
void ComponentLifecycle_set_pair_second_no_copy(void) {
|
|
flecs::world ecs;
|
|
|
|
flecs::entity tag = ecs.entity();
|
|
|
|
flecs::entity e = ecs.entity()
|
|
.set_second<NoCopy>(tag, { 10 });
|
|
|
|
const NoCopy *ptr = e.get_second<NoCopy>(tag);
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->x_, 10);
|
|
}
|
|
|
|
void ComponentLifecycle_set_override_no_copy(void) {
|
|
flecs::world ecs;
|
|
|
|
flecs::entity e = ecs.entity()
|
|
.set_override<NoCopy>({ 10 });
|
|
|
|
const NoCopy *ptr = e.get<NoCopy>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->x_, 10);
|
|
|
|
test_assert(e.has(flecs::Override | ecs.id<NoCopy>()));
|
|
}
|
|
|
|
void ComponentLifecycle_set_override_pair_no_copy(void) {
|
|
flecs::world ecs;
|
|
|
|
flecs::entity e = ecs.entity()
|
|
.set_override<NoCopy, Tag>({ 10 });
|
|
|
|
const NoCopy *ptr = e.get<NoCopy, Tag>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->x_, 10);
|
|
|
|
test_assert(e.has(flecs::Override | ecs.pair<NoCopy, Tag>()));
|
|
}
|
|
|
|
void ComponentLifecycle_set_override_pair_w_entity_no_copy(void) {
|
|
flecs::world ecs;
|
|
|
|
flecs::entity tag = ecs.entity();
|
|
|
|
flecs::entity e = ecs.entity()
|
|
.set_override<NoCopy>(tag, { 10 });
|
|
|
|
const NoCopy *ptr = e.get<NoCopy>(tag);
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->x_, 10);
|
|
|
|
test_assert(e.has(flecs::Override | ecs.pair<NoCopy>(tag)));
|
|
}
|
|
|
|
void ComponentLifecycle_dtor_after_defer_set(void) {
|
|
{
|
|
flecs::world ecs;
|
|
|
|
auto e = ecs.entity();
|
|
|
|
ecs.defer_begin();
|
|
e.set<Pod>({10});
|
|
test_assert(!e.has<Pod>());
|
|
test_int(Pod::ctor_invoked, 2);
|
|
test_int(Pod::dtor_invoked, 1);
|
|
test_int(Pod::move_invoked, 1);
|
|
test_int(Pod::move_ctor_invoked, 0);
|
|
ecs.defer_end();
|
|
|
|
test_assert(e.has<Pod>());
|
|
test_int(Pod::ctor_invoked, 3);
|
|
test_int(Pod::dtor_invoked, 2);
|
|
test_int(Pod::move_invoked, 2);
|
|
test_int(Pod::move_ctor_invoked, 0);
|
|
|
|
const Pod *ptr = e.get<Pod>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->value, 10);
|
|
|
|
test_int(Pod::ctor_invoked, 3);
|
|
test_int(Pod::dtor_invoked, 2);
|
|
test_int(Pod::move_invoked, 2);
|
|
test_int(Pod::move_ctor_invoked, 0);
|
|
}
|
|
|
|
test_int(Pod::ctor_invoked, 3);
|
|
test_int(Pod::dtor_invoked, 3);
|
|
test_int(Pod::move_invoked, 2);
|
|
test_int(Pod::move_ctor_invoked, 0);
|
|
}
|
|
|
|
void ComponentLifecycle_dtor_with_relation(void) {
|
|
{
|
|
flecs::world ecs;
|
|
|
|
auto e = ecs.entity();
|
|
auto e2 = ecs.entity().set<Pod>({5});
|
|
|
|
e.set<Pod>({10}).add<Tag>(e2);
|
|
|
|
test_int(Pod::ctor_invoked, 4);
|
|
test_int(Pod::dtor_invoked, 3);
|
|
test_int(Pod::move_invoked, 2);
|
|
test_int(Pod::move_ctor_invoked, 1);
|
|
|
|
const Pod *ptr = e.get<Pod>();
|
|
test_assert(ptr != NULL);
|
|
test_int(ptr->value, 10);
|
|
|
|
test_int(Pod::ctor_invoked, 4);
|
|
test_int(Pod::dtor_invoked, 3);
|
|
test_int(Pod::move_invoked, 2);
|
|
test_int(Pod::move_ctor_invoked, 1);
|
|
}
|
|
|
|
test_int(Pod::ctor_invoked, 5);
|
|
test_int(Pod::dtor_invoked, 6);
|
|
test_int(Pod::move_invoked, 4);
|
|
test_int(Pod::move_ctor_invoked, 1);
|
|
}
|
|
|
|
void ComponentLifecycle_register_parent_after_child_w_hooks(void) {
|
|
{
|
|
flecs::world ecs;
|
|
|
|
ecs.component<Pod::Child>();
|
|
ecs.component<Pod>();
|
|
|
|
ecs.entity().set<Pod>({});
|
|
}
|
|
|
|
test_int(Pod::ctor_invoked, 2);
|
|
test_int(Pod::dtor_invoked, 2);
|
|
test_int(Pod::move_invoked, 1);
|
|
test_int(Pod::move_ctor_invoked, 0);
|
|
test_int(Pod::copy_invoked, 0);
|
|
test_int(Pod::copy_ctor_invoked, 0);
|
|
}
|
|
|
|
void ComponentLifecycle_register_parent_after_child_w_hooks_implicit(void) {
|
|
{
|
|
flecs::world ecs;
|
|
|
|
ecs.entity().add<Pod::Child>().set<Pod>({});
|
|
}
|
|
|
|
test_int(Pod::ctor_invoked, 2);
|
|
test_int(Pod::dtor_invoked, 2);
|
|
test_int(Pod::move_invoked, 1);
|
|
test_int(Pod::move_ctor_invoked, 0);
|
|
test_int(Pod::copy_invoked, 0);
|
|
test_int(Pod::copy_ctor_invoked, 0);
|
|
}
|