Files
PixelDefense/engine/libs/flecs/test/cpp_api/src/World.cpp

1844 lines
42 KiB
C++

#include <cpp_api.h>
void World_multi_world_empty(void) {
flecs::world *w1 = new flecs::world();
delete w1;
flecs::world *w2 = new flecs::world();
delete w2;
test_assert(true);
}
class FooModule {
public:
FooModule(flecs::world& world) {
world.module<FooModule>();
}
};
typedef struct TestInteropModule {
int dummy;
} TestInteropModule;
static
void TestInteropModuleImport(ecs_world_t *world) {
ECS_MODULE(world, TestInteropModule);
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
}
namespace test {
namespace interop {
class module : TestInteropModule {
public:
struct Velocity : ::Velocity { };
module(flecs::world& ecs) {
TestInteropModuleImport(ecs);
ecs.module<test::interop::module>();
ecs.component<Position>("::test::interop::module::Position");
ecs.component<Velocity>("::test::interop::module::Velocity");
}
};
}
}
namespace ns {
struct FooComp {
int value;
};
struct namespace_module {
namespace_module(flecs::world& ecs) {
ecs.module<namespace_module>();
ecs.component<FooComp>();
import_count ++;
ecs.system<FooComp>()
.kind(flecs::OnUpdate)
.each([](flecs::entity entity, FooComp &sc) {
namespace_module::system_invoke_count ++;
});
}
static int import_count;
static int system_invoke_count;
};
int namespace_module::import_count = 0;
int namespace_module::system_invoke_count = 0;
}
void World_builtin_components(void) {
flecs::world ecs;
test_assert(ecs.component<flecs::Component>() == ecs_id(EcsComponent));
test_assert(ecs.component<flecs::Identifier>() == ecs_id(EcsIdentifier));
test_assert(ecs.component<flecs::Poly>() == ecs_id(EcsPoly));
test_assert(ecs.component<flecs::Target>() == ecs_id(EcsTarget));
test_assert(ecs.component<flecs::RateFilter>() == ecs_id(EcsRateFilter));
test_assert(ecs.component<flecs::TickSource>() == ecs_id(EcsTickSource));
test_assert(flecs::Name == EcsName);
test_assert(flecs::Symbol == EcsSymbol);
test_assert(flecs::System == EcsSystem);
test_assert(flecs::Observer == EcsObserver);
test_assert(flecs::Query == EcsQuery);
}
void World_multi_world_component(void) {
flecs::world w1;
flecs::world w2;
auto p_1 = w1.component<Position>();
auto v_1 = w1.component<Velocity>();
auto v_2 = w2.component<Velocity>();
auto m_2 = w2.component<Mass>();
test_assert(v_1.id() == v_2.id());
test_assert(p_1.id() != m_2.id());
test_assert(m_2.id() > v_2.id());
auto m_1 = w2.component<Mass>();
test_assert(m_1.id() == m_2.id());
}
namespace A {
struct Comp {
float x;
float y;
};
}
void World_multi_world_component_namespace(void) {
flecs::world *w = new flecs::world();
auto c = w->component<A::Comp>();
auto id_1 = c.id();
delete w;
w = new flecs::world();
c = w->component<A::Comp>();
auto id_2 = c.id();
test_assert(id_1 == id_2);
delete w;
}
void World_multi_world_module(void) {
flecs::world world1;
world1.import<ns::namespace_module>();
flecs::world world2;
world2.import<ns::namespace_module>();
world1.entity().add<ns::FooComp>();
world2.entity().add<ns::FooComp>();
world1.progress();
test_int(ns::namespace_module::system_invoke_count, 1);
world2.progress();
test_int(ns::namespace_module::system_invoke_count, 2);
}
void World_multi_world_recycled_component(void) {
flecs::entity c;
{
flecs::world ecs;
for (int i = 0; i < FLECS_HI_COMPONENT_ID; i ++) {
ecs_new_low_id(ecs);
}
ecs.entity().destruct();
c = ecs.component<Position>();
}
{
flecs::world ecs;
test_assert((c == ecs.component<Position>()));
}
}
void World_multi_world_recycled_component_different_generation(void) {
flecs::entity c;
{
flecs::world ecs;
for (int i = 0; i < FLECS_HI_COMPONENT_ID; i ++) {
ecs_new_low_id(ecs);
}
ecs.entity().destruct();
c = ecs.component<Position>();
}
{
flecs::world ecs;
for (int i = 0; i < FLECS_HI_COMPONENT_ID; i ++) {
ecs_new_low_id(ecs);
}
ecs.entity().destruct();
test_assert((c == ecs.component<Position>()));
}
}
void World_type_id(void) {
flecs::world ecs;
auto p = ecs.component<Position>();
test_assert(p.id() == flecs::type_id<Position>());
}
void World_different_comp_same_name(void) {
install_test_abort();
flecs::world ecs;
test_expect_abort();
ecs.component<Position>("Position");
ecs.component<Velocity>("Position");
}
void World_reregister_after_reset(void) {
flecs::world ecs;
auto p1 = ecs.component<Position>("Position");
// Simulate different binary
flecs::_::cpp_type<Position>::reset();
auto p2 = ecs.component<Position>("Position");
test_assert(p1.id() == p2.id());
}
void World_implicit_reregister_after_reset(void) {
flecs::world ecs;
ecs.entity().add<Position>();
flecs::entity_t p_id_1 = flecs::type_id<Position>();
// Simulate different binary
flecs::_::cpp_type<Position>::reset();
ecs.entity().add<Position>();
flecs::entity_t p_id_2 = flecs::type_id<Position>();
test_assert(p_id_1 == p_id_2);
}
void World_reregister_after_reset_w_namespace(void) {
flecs::world ecs;
ecs.component<ns::FooComp>();
flecs::entity_t p_id_1 = flecs::type_id<ns::FooComp>();
// Simulate different binary
flecs::_::cpp_type<ns::FooComp>::reset();
ecs.component<ns::FooComp>();
flecs::entity_t p_id_2 = flecs::type_id<ns::FooComp>();
test_assert(p_id_1 == p_id_2);
}
void World_reregister_namespace(void) {
flecs::world ecs;
ecs.component<ns::FooComp>();
flecs::entity_t p_id_1 = flecs::type_id<ns::FooComp>();
ecs.component<ns::FooComp>();
flecs::entity_t p_id_2 = flecs::type_id<ns::FooComp>();
test_assert(p_id_1 == p_id_2);
}
void World_reregister_after_reset_different_name(void) {
install_test_abort();
flecs::world ecs;
test_expect_abort();
ecs.component<Position>("Position");
// Simulate different binary
flecs::_::cpp_type<Position>::reset();
ecs.component<Position>("Velocity");
}
void World_register_component_w_reset_in_multithreaded(void) {
flecs::world ecs;
ecs.set_threads(2);
flecs::entity pos = ecs.component<Position>();
flecs::entity e = ecs.entity();
flecs::_::cpp_type<Position>::reset();
ecs.readonly_begin();
e.set<Position>({10, 20});
ecs.readonly_end();
test_assert(e.has<Position>());
test_assert(e.has(pos));
const Position *p = e.get<Position>();
test_assert(p != nullptr);
test_int(p->x, 10);
test_int(p->y, 20);
}
struct Module { };
void World_register_component_w_core_name(void) {
flecs::world ecs;
flecs::entity c = ecs.component<Module>();
test_assert(c != 0);
test_str(c.path().c_str(), "::Module");
}
template <typename T>
struct Tmp { int32_t v; };
struct Test { };
void World_register_short_template(void) {
flecs::world ecs;
auto c = ecs.component<Tmp<Test>>();
test_assert(c != 0);
test_str(c.name(), "Tmp<Test>");
const EcsComponent *ptr = c.get<flecs::Component>();
test_assert(ptr != NULL);
test_int(ptr->size, 4);
test_int(ptr->alignment, 4);
}
void World_reimport(void) {
flecs::world ecs;
auto m1 = ecs.import<FooModule>();
auto m2 = ecs.import<FooModule>();
test_assert(m1.id() == m2.id());
}
void World_reimport_module_after_reset(void) {
flecs::world ecs;
auto m1 = ecs.import<FooModule>();
// Simulate different binary
flecs::_::cpp_type<FooModule>::reset();
auto m2 = ecs.import<FooModule>();
test_assert(m1.id() == m2.id());
}
void World_reimport_module_new_world(void) {
flecs::entity e1;
{
flecs::world ecs;
e1 = ecs.import<FooModule>();
}
{
flecs::world ecs;
auto e2 = ecs.import<FooModule>();
test_assert(e1.id() == e2.id());
}
}
void World_reimport_namespaced_module(void) {
flecs::world ecs;
test_int(ns::namespace_module::import_count, 0);
// Import first time, should call module constructor.
ecs.import<ns::namespace_module>();
test_int(ns::namespace_module::import_count, 1);
// Import second time, should not call constructor.
ecs.import<ns::namespace_module>();
test_int(ns::namespace_module::import_count, 1);
}
void World_c_interop_module(void) {
flecs::world ecs;
ecs.import<test::interop::module>();
auto e_pos = ecs.lookup("test::interop::module::Position");
test_assert(e_pos.id() != 0);
}
void World_c_interop_after_reset(void) {
flecs::world ecs;
ecs.import<test::interop::module>();
auto e_pos = ecs.lookup("test::interop::module::Position");
test_assert(e_pos.id() != 0);
flecs::_::cpp_type<test::interop::module>::reset();
ecs.import<test::interop::module>();
}
void World_implicit_register_w_new_world(void) {
{
flecs::world ecs;
auto e = ecs.entity().set<Position>({10, 20});
test_assert(e.has<Position>());
auto *p = e.get<Position>();
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
}
{
/* Recreate world, does not reset static state */
flecs::world ecs;
auto e = ecs.entity().set<Position>({10, 20});
test_assert(e.has<Position>());
auto *p = e.get<Position>();
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
}
}
void World_implicit_register_after_reset_register_w_custom_name(void) {
flecs::world ecs;
flecs::entity c = ecs.component<Position>("MyPosition");
test_str(c.name(), "MyPosition");
flecs::reset(); // Simulate working across boundary
auto e = ecs.entity().add<Position>();
test_assert(e.has<Position>());
test_assert(e.has(c));
}
void World_register_after_reset_register_w_custom_name(void) {
flecs::world ecs;
flecs::entity c1 = ecs.component<Position>("MyPosition");
test_str(c1.name(), "MyPosition");
flecs::reset(); // Simulate working across boundary
flecs::entity c2 = ecs.component<Position>();
test_str(c2.name(), "MyPosition");
}
void World_register_builtin_after_reset(void) {
flecs::world ecs;
auto c1 = ecs.component<flecs::Component>();
test_assert(c1 == ecs_id(EcsComponent));
flecs::reset(); // Simulate working across boundary
auto c2 = ecs.component<flecs::Component>();
test_assert(c2 == ecs_id(EcsComponent));
test_assert(c1 == c2);
}
void World_register_meta_after_reset(void) {
flecs::world ecs;
auto c1 = ecs.component<Position>();
flecs::reset(); // Simulate working across boundary
auto c2 = ecs.component<Position>()
.member<float>("x")
.member<float>("y");
test_assert(c1 == c2);
}
void World_count(void) {
flecs::world ecs;
test_int(ecs.count<Position>(), 0);
ecs.entity().add<Position>();
ecs.entity().add<Position>();
ecs.entity().add<Position>();
ecs.entity().add<Position>().add<Mass>();
ecs.entity().add<Position>().add<Mass>();
ecs.entity().add<Position>().add<Velocity>();
test_int(ecs.count<Position>(), 6);
}
void World_count_id(void) {
flecs::world ecs;
auto ent = ecs.entity();
test_int(ecs.count(ent), 0);
ecs.entity().add(ent);
ecs.entity().add(ent);
ecs.entity().add(ent);
ecs.entity().add(ent).add<Mass>();
ecs.entity().add(ent).add<Mass>();
ecs.entity().add(ent).add<Velocity>();
test_int(ecs.count(ent), 6);
}
void World_count_pair(void) {
flecs::world ecs;
auto parent = ecs.entity();
test_int(ecs.count(flecs::ChildOf, parent), 0);
ecs.entity().add(flecs::ChildOf, parent);
ecs.entity().add(flecs::ChildOf, parent);
ecs.entity().add(flecs::ChildOf, parent);
ecs.entity().add(flecs::ChildOf, parent).add<Mass>();
ecs.entity().add(flecs::ChildOf, parent).add<Mass>();
ecs.entity().add(flecs::ChildOf, parent).add<Velocity>();
test_int(ecs.count(flecs::ChildOf, parent), 6);
}
void World_count_pair_type_id(void) {
flecs::world ecs;
struct Rel { };
auto parent = ecs.entity();
test_int(ecs.count<Rel>(parent), 0);
ecs.entity().add<Rel>(parent);
ecs.entity().add<Rel>(parent);
ecs.entity().add<Rel>(parent);
ecs.entity().add<Rel>(parent).add<Mass>();
ecs.entity().add<Rel>(parent).add<Mass>();
ecs.entity().add<Rel>(parent).add<Velocity>();
test_int(ecs.count<Rel>(parent), 6);
}
void World_count_pair_id(void) {
flecs::world ecs;
struct Rel { };
auto rel = ecs.entity();
auto parent = ecs.entity();
test_int(ecs.count(rel, parent), 0);
ecs.entity().add(rel, parent);
ecs.entity().add(rel, parent);
ecs.entity().add(rel, parent);
ecs.entity().add(rel, parent).add<Mass>();
ecs.entity().add(rel, parent).add<Mass>();
ecs.entity().add(rel, parent).add<Velocity>();
test_int(ecs.count(rel, parent), 6);
}
void World_staged_count(void) {
flecs::world ecs;
flecs::world stage = ecs.get_stage(0);
ecs.readonly_begin();
test_int(stage.count<Position>(), 0);
ecs.readonly_end();
ecs.readonly_begin();
stage.entity().add<Position>();
stage.entity().add<Position>();
stage.entity().add<Position>();
stage.entity().add<Position>().add<Mass>();
stage.entity().add<Position>().add<Mass>();
stage.entity().add<Position>().add<Velocity>();
test_int(stage.count<Position>(), 0);
ecs.readonly_end();
test_int(stage.count<Position>(), 6);
}
void World_async_stage_add(void) {
flecs::world ecs;
ecs.component<Position>();
auto e = ecs.entity();
flecs::world async = ecs.async_stage();
e.mut(async).add<Position>();
test_assert(!e.has<Position>());
async.merge();
test_assert(e.has<Position>());
}
void World_with_tag(void) {
flecs::world ecs;
auto Tag = ecs.entity();
ecs.with(Tag, [&]{
auto e1 = ecs.entity(); e1.set<Self>({e1});
auto e2 = ecs.entity(); e2.set<Self>({e2});
auto e3 = ecs.entity(); e3.set<Self>({e3});
});
// Ensures that while Self is (implicitly) registered within the with, it
// does not get any contents from the with.
auto self = ecs.component<Self>();
test_assert(!self.has(Tag));
auto q = ecs.query_builder<>().term(Tag).build();
int32_t count = 0;
q.each([&](flecs::entity e) {
test_assert(e.has(Tag));
test_bool(e.get([&](const Self& s) {
test_assert(s.value == e);
}), true);
count ++;
});
count ++;
}
void World_with_tag_type(void) {
flecs::world ecs;
struct Tag { };
ecs.with<Tag>([&]{
auto e1 = ecs.entity(); e1.set<Self>({e1});
auto e2 = ecs.entity(); e2.set<Self>({e2});
auto e3 = ecs.entity(); e3.set<Self>({e3});
});
// Ensures that while Self is (implicitly) registered within the with, it
// does not get any contents from the with.
auto self = ecs.component<Self>();
test_assert(!self.has<Tag>());
auto q = ecs.query_builder<>().term<Tag>().build();
int32_t count = 0;
q.each([&](flecs::entity e) {
test_assert(e.has<Tag>());
test_bool(e.get([&](const Self& s) {
test_assert(s.value == e);
}), true);
count ++;
});
count ++;
}
void World_with_relation(void) {
flecs::world ecs;
auto Likes = ecs.entity();
auto Bob = ecs.entity();
ecs.with(Likes, Bob, [&]{
auto e1 = ecs.entity(); e1.set<Self>({e1});
auto e2 = ecs.entity(); e2.set<Self>({e2});
auto e3 = ecs.entity(); e3.set<Self>({e3});
});
// Ensures that while Self is (implicitly) registered within the with, it
// does not get any contents from the with.
auto self = ecs.component<Self>();
test_assert(!self.has(Likes, Bob));
auto q = ecs.query_builder<>().term(Likes, Bob).build();
int32_t count = 0;
q.each([&](flecs::entity e) {
test_assert(e.has(Likes, Bob));
test_bool(e.get([&](const Self& s) {
test_assert(s.value == e);
}), true);
count ++;
});
count ++;
}
void World_with_relation_type(void) {
flecs::world ecs;
struct Likes { };
auto Bob = ecs.entity();
ecs.with<Likes>(Bob, [&]{
auto e1 = ecs.entity(); e1.set<Self>({e1});
auto e2 = ecs.entity(); e2.set<Self>({e2});
auto e3 = ecs.entity(); e3.set<Self>({e3});
});
// Ensures that while Self is (implicitly) registered within the with, it
// does not get any contents from the with.
auto self = ecs.component<Self>();
test_assert(!self.has<Likes>(Bob));
auto q = ecs.query_builder<>().term<Likes>(Bob).build();
int32_t count = 0;
q.each([&](flecs::entity e) {
test_assert(e.has<Likes>(Bob));
test_bool(e.get([&](const Self& s) {
test_assert(s.value == e);
}), true);
count ++;
});
count ++;
}
void World_with_relation_object_type(void) {
flecs::world ecs;
struct Likes { };
struct Bob { };
ecs.with<Likes, Bob>([&]{
auto e1 = ecs.entity(); e1.set<Self>({e1});
auto e2 = ecs.entity(); e2.set<Self>({e2});
auto e3 = ecs.entity(); e3.set<Self>({e3});
});
// Ensures that while Self is (implicitly) registered within the with, it
// does not get any contents from the with.
auto self = ecs.component<Self>();
test_assert(!(self.has<Likes, Bob>()));
auto q = ecs.query_builder<>().term<Likes, Bob>().build();
int32_t count = 0;
q.each([&](flecs::entity e) {
test_assert((e.has<Likes, Bob>()));
test_bool(e.get([&](const Self& s) {
test_assert(s.value == e);
}), true);
count ++;
});
count ++;
}
void World_with_scope(void) {
flecs::world ecs;
auto parent = ecs.entity("P");
ecs.scope(parent, [&]{
auto e1 = ecs.entity("C1"); e1.set<Self>({e1});
auto e2 = ecs.entity("C2"); e2.set<Self>({e2});
auto e3 = ecs.entity("C3"); e3.set<Self>({e3});
// Ensure relative lookups work
test_assert(ecs.lookup("C1") == e1);
test_assert(ecs.lookup("C2") == e2);
test_assert(ecs.lookup("C3") == e3);
test_assert(parent.lookup("C1") == e1);
test_assert(parent.lookup("C2") == e2);
test_assert(parent.lookup("C3") == e3);
test_assert(ecs.lookup("::P::C1") == e1);
test_assert(ecs.lookup("::P::C2") == e2);
test_assert(ecs.lookup("::P::C3") == e3);
});
test_assert(parent.lookup("C1") != 0);
test_assert(parent.lookup("C2") != 0);
test_assert(parent.lookup("C3") != 0);
test_assert(ecs.lookup("P::C1") == parent.lookup("C1"));
test_assert(ecs.lookup("P::C2") == parent.lookup("C2"));
test_assert(ecs.lookup("P::C3") == parent.lookup("C3"));
// Ensures that while Self is (implicitly) registered within the with, it
// does not become a child of the parent.
auto self = ecs.component<Self>();
test_assert(!self.has(flecs::ChildOf, parent));
int count = 0;
auto q = ecs.query_builder<>().term(flecs::ChildOf, parent).build();
q.each([&](flecs::entity e) {
test_assert(e.has(flecs::ChildOf, parent));
test_bool(e.get([&](const Self& s){
test_assert(s.value == e);
}), true);
count ++;
});
test_int(count, 3);
}
struct ParentScope { };
void World_with_scope_type(void) {
flecs::world ecs;
ecs.scope<ParentScope>([&]{
ecs.entity("Child");
});
auto parent = ecs.lookup("ParentScope");
test_assert(parent != 0);
auto child = ecs.lookup("ParentScope::Child");
test_assert(child != 0);
test_assert(child == parent.lookup("Child"));
}
void World_with_scope_type_staged(void) {
flecs::world ecs;
flecs::entity e;
flecs::world stage = ecs.get_stage(0);
ecs.readonly_begin();
stage.scope<ParentScope>([&]{
e = stage.entity("Child");
});
ecs.readonly_end();
test_assert( e.has(flecs::ChildOf, ecs.id<ParentScope>()) );
auto parent = ecs.lookup("ParentScope");
test_assert(parent != 0);
auto child = ecs.lookup("ParentScope::Child");
test_assert(child != 0);
test_assert(child == parent.lookup("Child"));
}
void World_with_scope_no_lambda(void) {
flecs::world ecs;
auto parent = ecs.entity("Parent");
auto child = ecs.scope(parent).entity("Child");
test_assert(child.has(flecs::ChildOf, parent));
test_assert(ecs.get_scope() == 0);
}
void World_with_scope_type_no_lambda(void) {
flecs::world ecs;
auto child = ecs.scope<ParentScope>().entity("Child");
test_assert(child.has(flecs::ChildOf, ecs.id<ParentScope>()));
test_assert(ecs.get_scope() == 0);
}
void World_with_tag_nested(void) {
flecs::world ecs;
auto Tier1 = ecs.entity();
ecs.with(Tier1, [&]{
ecs.entity("Tier2").with([&]{
ecs.entity("Tier3");
});
});
auto Tier2 = ecs.lookup("Tier2");
test_assert(Tier2 != 0);
auto Tier3 = ecs.lookup("Tier3");
test_assert(Tier3 != 0);
test_assert(Tier2.has(Tier1));
test_assert(Tier3.has(Tier2));
}
void World_with_scope_nested(void) {
flecs::world ecs;
auto parent = ecs.entity("P");
ecs.scope(parent, [&]{
auto child = ecs.entity("C").scope([&]{
auto gchild = ecs.entity("GC");
test_assert(gchild == ecs.lookup("GC"));
test_assert(gchild == ecs.lookup("::P::C::GC"));
});
// Ensure relative lookups work
test_assert(ecs.lookup("C") == child);
test_assert(ecs.lookup("::P::C") == child);
test_assert(ecs.lookup("::P::C::GC") != 0);
});
test_assert(0 == ecs.lookup("C"));
test_assert(0 == ecs.lookup("GC"));
test_assert(0 == ecs.lookup("C::GC"));
auto child = ecs.lookup("P::C");
test_assert(0 != child);
test_assert(child.has(flecs::ChildOf, parent));
auto gchild = ecs.lookup("P::C::GC");
test_assert(0 != gchild);
test_assert(gchild.has(flecs::ChildOf, child));
}
void World_recursive_lookup(void) {
flecs::world ecs;
auto A = ecs.entity("A");
auto B = ecs.entity("B");
auto P = ecs.entity("P");
P.scope([&]{
auto CA = ecs.entity("A");
test_assert(CA != A);
test_assert(CA == ecs.lookup("A"));
test_assert(CA == ecs.lookup("P::A"));
test_assert(CA == ecs.lookup("::P::A"));
test_assert(A == ecs.lookup("::A"));
test_assert(B == ecs.lookup("B"));
test_assert(B == ecs.lookup("::B"));
});
}
void World_type_w_tag_name(void) {
flecs::world ecs;
auto c = ecs.component<Tag>();
test_assert(c != flecs::entity());
test_str(c.path().c_str(), "::Tag");
test_assert(c != flecs::Tag);
}
void World_entity_w_tag_name(void) {
flecs::world ecs;
auto c = ecs.entity("Tag");
test_assert(c != flecs::entity());
test_str(c.path().c_str(), "::Tag");
test_assert(c != flecs::Tag);
}
template <typename T>
struct TemplateType { };
void World_template_component_name(void) {
flecs::world ecs;
auto c = ecs.component<TemplateType<Position>>();
test_str(c.name().c_str(), "TemplateType<Position>");
test_str(c.path().c_str(), "::TemplateType<Position>");
}
namespace ns {
template <typename T>
struct TemplateType { };
struct foo { };
}
void World_template_component_w_namespace_name(void) {
flecs::world ecs;
auto c = ecs.component<ns::TemplateType<Position>>();
test_str(c.name().c_str(), "TemplateType<Position>");
test_str(c.path().c_str(), "::ns::TemplateType<Position>");
}
void World_template_component_w_namespace_name_and_namespaced_arg(void) {
flecs::world ecs;
auto c = ecs.component<ns::TemplateType<ns::foo>>();
test_str(c.name().c_str(), "TemplateType<ns::foo>");
test_str(c.path().c_str(), "::ns::TemplateType<ns::foo>");
}
namespace foo {
template <typename T>
struct foo { };
struct bar { };
}
void World_template_component_w_same_namespace_name(void) {
flecs::world ecs;
auto c = ecs.component<foo::foo<Position>>();
test_str(c.name().c_str(), "foo<Position>");
test_str(c.path().c_str(), "::foo::foo<Position>");
}
void World_template_component_w_same_namespace_name_and_namespaced_arg(void) {
flecs::world ecs;
auto c = ecs.component<foo::foo<foo::bar>>();
test_str(c.name().c_str(), "foo<foo::bar>");
test_str(c.path().c_str(), "::foo::foo<foo::bar>");
}
struct module_w_template_component {
struct Foo { };
struct Bar { };
template <typename T, typename U>
struct TypeWithArgs { };
module_w_template_component(flecs::world &world) {
world.module<module_w_template_component>();
world.component<TypeWithArgs<Foo, Bar>>();
};
};
void World_template_component_from_module_2_args(void) {
flecs::world ecs;
auto m = ecs.import<module_w_template_component>();
test_assert(m == ecs.lookup("module_w_template_component"));
auto tid = ecs.id<module_w_template_component::TypeWithArgs<
module_w_template_component::Foo,
module_w_template_component::Bar>>();
test_assert(tid != 0);
auto mid = m.lookup("TypeWithArgs<module_w_template_component::Foo, module_w_template_component::Bar>");
if (mid == 0) {
mid = m.lookup("TypeWithArgs<module_w_template_component::Foo,module_w_template_component::Bar>");
}
test_assert(mid != 0);
test_assert(tid == mid);
}
void World_entity_as_tag(void) {
flecs::world ecs;
auto e = ecs.entity<Tag>();
test_assert(e.id() != 0);
auto t = ecs.component<Tag>();
test_assert(t.id() != 0);
test_assert(e == t);
auto e2 = ecs.entity()
.add<Tag>();
test_bool(e2.has<Tag>(), true);
test_bool(e2.has(e), true);
test_str(e.name(), "Tag");
}
void World_entity_w_name_as_tag(void) {
flecs::world ecs;
auto e = ecs.entity<Tag>("Foo");
test_assert(e.id() != 0);
auto t = ecs.component<Tag>();
test_assert(t.id() != 0);
test_assert(e == t);
auto e2 = ecs.entity()
.add<Tag>();
test_bool(e2.has<Tag>(), true);
test_bool(e2.has(e), true);
test_str(e.name(), "Foo");
}
void World_entity_as_component(void) {
flecs::world ecs;
auto e = ecs.entity<Position>();
test_assert(e.id() != 0);
auto t = ecs.component<Position>();
test_assert(t.id() != 0);
test_assert(e == t);
auto e2 = ecs.entity()
.set<Position>({10, 20});
test_bool(e2.has<Position>(), true);
test_bool(e2.has(e), true);
test_str(e.name(), "Position");
}
void World_entity_w_name_as_component(void) {
flecs::world ecs;
auto e = ecs.entity<Position>("Foo");
test_assert(e.id() != 0);
auto t = ecs.component<Position>();
test_assert(t.id() != 0);
test_assert(e == t);
auto e2 = ecs.entity()
.set<Position>({10, 20});
test_bool(e2.has<Position>(), true);
test_bool(e2.has(e), true);
test_str(e.name(), "Foo");
}
void World_entity_as_component_2_worlds(void) {
flecs::world ecs_1;
auto e_1 = ecs_1.entity<Position>();
test_assert(e_1.id() != 0);
flecs::world ecs_2;
auto e_2 = ecs_2.entity<Position>();
test_assert(e_2.id() != 0);
test_assert(e_1 == e_2);
test_assert(e_1 == ecs_1.component<Position>());
test_assert(e_2 == ecs_2.component<Position>());
}
struct Parent {
struct Child { };
};
void World_entity_as_namespaced_component_2_worlds(void) {
flecs::world ecs_1;
auto e_1 = ecs_1.entity<Parent>();
test_assert(e_1.id() != 0);
auto e_1_1 = ecs_1.entity<Parent::Child>();
test_assert(e_1_1.id() != 0);
flecs::world ecs_2;
auto e_2 = ecs_2.entity<Parent>();
test_assert(e_2.id() != 0);
auto e_2_1 = ecs_2.entity<Parent::Child>();
test_assert(e_2_1.id() != 0);
test_assert(e_1 == e_2);
test_assert(e_1 == ecs_1.component<Parent>());
test_assert(e_2 == ecs_2.component<Parent>());
test_assert(e_1_1 == e_2_1);
test_assert(e_1_1 == ecs_1.component<Parent::Child>());
test_assert(e_2_1 == ecs_2.component<Parent::Child>());
}
void World_entity_as_component_2_worlds_implicit_namespaced(void) {
flecs::world ecs_1;
auto e_1 = ecs_1.entity<Parent>();
test_assert(e_1.id() != 0);
ecs_1.entity().add<Parent::Child>();
flecs::world ecs_2;
auto e_2 = ecs_2.entity<Parent>();
test_assert(e_2.id() != 0);
ecs_2.entity().add<Parent::Child>();
test_assert(e_1 == e_2);
test_assert(e_1 == ecs_1.component<Parent>());
test_assert(e_2 == ecs_2.component<Parent>());
test_assert(ecs_1.component<Parent::Child>() ==
ecs_2.component<Parent::Child>());
}
struct PositionDerived : Position {
PositionDerived() { }
PositionDerived(float x, float y) : Position{x, y} { }
};
void World_delete_with_id(void) {
flecs::world ecs;
flecs::id tag = ecs.entity();
auto e_1 = ecs.entity().add(tag);
auto e_2 = ecs.entity().add(tag);
auto e_3 = ecs.entity().add(tag);
ecs.delete_with(tag);
test_assert(!e_1.is_alive());
test_assert(!e_2.is_alive());
test_assert(!e_3.is_alive());
}
void World_delete_with_type(void) {
flecs::world ecs;
auto e_1 = ecs.entity().add<Tag>();
auto e_2 = ecs.entity().add<Tag>();
auto e_3 = ecs.entity().add<Tag>();
ecs.delete_with<Tag>();
test_assert(!e_1.is_alive());
test_assert(!e_2.is_alive());
test_assert(!e_3.is_alive());
}
void World_delete_with_pair(void) {
flecs::world ecs;
flecs::id rel = ecs.entity();
flecs::id obj = ecs.entity();
auto e_1 = ecs.entity().add(rel, obj);
auto e_2 = ecs.entity().add(rel, obj);
auto e_3 = ecs.entity().add(rel, obj);
ecs.delete_with(rel, obj);
test_assert(!e_1.is_alive());
test_assert(!e_2.is_alive());
test_assert(!e_3.is_alive());
}
void World_delete_with_pair_type(void) {
flecs::world ecs;
struct Rel { };
struct Obj { };
auto e_1 = ecs.entity().add<Rel, Obj>();
auto e_2 = ecs.entity().add<Rel, Obj>();
auto e_3 = ecs.entity().add<Rel, Obj>();
ecs.delete_with<Rel, Obj>();
test_assert(!e_1.is_alive());
test_assert(!e_2.is_alive());
test_assert(!e_3.is_alive());
}
void World_delete_with_implicit(void) {
flecs::world ecs;
ecs.delete_with<Tag>();
test_assert(true);
}
void World_delete_with_pair_implicit(void) {
flecs::world ecs;
struct Rel { };
struct Obj { };
ecs.delete_with<Rel, Obj>();
test_assert(true);
}
void World_remove_all_id(void) {
flecs::world ecs;
flecs::id tag_a = ecs.entity();
flecs::id tag_b = ecs.entity();
auto e_1 = ecs.entity().add(tag_a);
auto e_2 = ecs.entity().add(tag_a);
auto e_3 = ecs.entity().add(tag_a).add(tag_b);
ecs.remove_all(tag_a);
test_assert(e_1.is_alive());
test_assert(e_2.is_alive());
test_assert(e_3.is_alive());
test_assert(!e_1.has(tag_a));
test_assert(!e_2.has(tag_a));
test_assert(!e_3.has(tag_a));
test_assert(e_3.has(tag_b));
}
void World_remove_all_type(void) {
flecs::world ecs;
auto e_1 = ecs.entity().add<Position>();
auto e_2 = ecs.entity().add<Position>();
auto e_3 = ecs.entity().add<Position>().add<Velocity>();
ecs.remove_all<Position>();
test_assert(e_1.is_alive());
test_assert(e_2.is_alive());
test_assert(e_3.is_alive());
test_assert(!e_1.has<Position>());
test_assert(!e_2.has<Position>());
test_assert(!e_3.has<Position>());
test_assert(e_3.has<Velocity>());
}
void World_remove_all_pair(void) {
flecs::world ecs;
flecs::id rel = ecs.entity();
flecs::id obj_a = ecs.entity();
flecs::id obj_b = ecs.entity();
auto e_1 = ecs.entity().add(rel, obj_a);
auto e_2 = ecs.entity().add(rel, obj_a);
auto e_3 = ecs.entity().add(rel, obj_a).add(rel, obj_b);
ecs.remove_all(rel, obj_a);
test_assert(e_1.is_alive());
test_assert(e_2.is_alive());
test_assert(e_3.is_alive());
test_assert(!e_1.has(rel, obj_a));
test_assert(!e_2.has(rel, obj_a));
test_assert(!e_3.has(rel, obj_a));
test_assert(e_3.has(rel, obj_b));
}
void World_remove_all_pair_type(void) {
flecs::world ecs;
struct Rel { };
struct ObjA { };
struct ObjB { };
auto e_1 = ecs.entity().add<Rel, ObjA>();
auto e_2 = ecs.entity().add<Rel, ObjA>();
auto e_3 = ecs.entity().add<Rel, ObjA>().add<Rel, ObjB>();
ecs.remove_all<Rel, ObjA>();
test_assert(e_1.is_alive());
test_assert(e_2.is_alive());
test_assert(e_3.is_alive());
test_assert((!e_1.has<Rel, ObjA>()));
test_assert((!e_2.has<Rel, ObjA>()));
test_assert((!e_3.has<Rel, ObjA>()));
test_assert((!e_1.has<Rel, ObjB>()));
test_assert((!e_2.has<Rel, ObjB>()));
test_assert((e_3.has<Rel, ObjB>()));
}
void World_remove_all_implicit(void) {
flecs::world ecs;
ecs.remove_all<Tag>();
test_assert(true);
}
void World_remove_all_pair_implicit(void) {
flecs::world ecs;
struct Rel { };
struct Obj { };
ecs.remove_all<Rel, Obj>();
test_assert(true);
}
void World_get_scope(void) {
flecs::world ecs;
auto e = ecs.entity("scope");
ecs.set_scope(e);
auto s = ecs.get_scope();
test_assert(s == e);
test_str(s.name(), "scope");
}
void World_get_scope_type(void) {
flecs::world ecs;
ecs.set_scope<ParentScope>();
auto s = ecs.get_scope();
test_assert(s == ecs.id<ParentScope>());
test_str(s.name(), "ParentScope");
}
struct Outer
{
struct Inner { };
};
void World_register_namespace_after_component(void) {
flecs::world ecs;
auto inn = ecs.component<Outer::Inner>();
auto out = ecs.component<Outer>();
test_str(inn.path().c_str(), "::Outer::Inner");
test_str(out.path().c_str(), "::Outer");
const char *inn_sym = ecs_get_symbol(ecs, inn);
const char *out_sym = ecs_get_symbol(ecs, out);
test_str(inn_sym, "Outer.Inner");
test_str(out_sym, "Outer");
}
void World_is_alive(void) {
flecs::world ecs;
auto e = ecs.entity();
test_bool(ecs.is_alive(e), true);
test_bool(ecs.is_alive(1000), false);
e.destruct();
test_bool(ecs.is_alive(e), false);
}
void World_is_valid(void) {
flecs::world ecs;
auto e = ecs.entity();
test_bool(ecs.is_valid(e), true);
test_bool(ecs.is_valid(1000), true);
test_bool(ecs.is_valid(0), false);
e.destruct();
test_bool(ecs.is_valid(e), false);
}
void World_exists(void) {
flecs::world ecs;
auto e = ecs.entity();
test_bool(ecs.exists(e), true);
test_bool(ecs.exists(1000), false);
}
void World_get_alive(void) {
flecs::world ecs;
auto e_1 = ecs.entity();
auto e_no_gen = flecs::strip_generation(e_1);
test_assert(e_1 == e_no_gen);
e_1.destruct();
auto e_2 = ecs.entity();
test_assert(e_1 != e_2);
test_assert(e_no_gen == flecs::strip_generation(e_2));
test_assert(ecs.get_alive(e_no_gen) == e_2);
}
void World_ensure(void) {
flecs::world ecs;
auto e_1 = ecs.entity();
e_1.destruct();
test_assert(!e_1.is_alive());
auto e_2 = ecs.entity();
test_assert(e_1 != e_2);
test_assert(e_1 == flecs::strip_generation(e_2));
e_2.destruct();
test_assert(!e_2.is_alive());
auto e_3 = ecs.ensure(e_2);
test_assert(e_2 == e_3);
test_assert(e_3.is_alive());
}
void World_reset_all(void) {
flecs::entity pos, vel;
{
flecs::world ecs;
pos = ecs.component<Position>();
vel = ecs.component<Velocity>();
}
test_assert(flecs::type_id<Position>() == pos);
test_assert(flecs::type_id<Velocity>() == vel);
flecs::reset();
test_assert(flecs::type_id<Position>() == 0);
/* Register components in opposite order, should result in different ids */
{
flecs::world ecs;
test_assert(ecs.component<Position>() != 0);
test_assert(ecs.component<Velocity>() != 0);
}
}
void World_get_tick(void) {
flecs::world ecs;
test_int(ecs.get_info()->frame_count_total, 0);
ecs.progress();
test_int(ecs.get_info()->frame_count_total, 1);
ecs.progress();
test_int(ecs.get_info()->frame_count_total, 2);
}
struct Scope { };
struct FromScope { };
namespace Nested {
struct FromScope { };
}
void World_register_from_scope(void) {
flecs::world ecs;
ecs.set_scope<Scope>();
auto c = ecs.component<FromScope>();
ecs.set_scope(0);
test_assert(c.has(flecs::ChildOf, ecs.id<Scope>()));
}
void World_register_nested_from_scope(void) {
flecs::world ecs;
ecs.set_scope<Scope>();
auto c = ecs.component<Nested::FromScope>();
ecs.set_scope(0);
test_assert(c.has(flecs::ChildOf, ecs.id<Scope>()));
}
void World_register_w_root_name(void) {
flecs::world ecs;
auto c = ecs.component<Scope>("::Root");
test_assert(!c.has(flecs::ChildOf, flecs::Wildcard));
test_str(c.path().c_str(), "::Root");
}
void World_register_nested_w_root_name(void) {
flecs::world ecs;
auto c = ecs.component<Nested::FromScope>("::Root");
test_assert(!c.has(flecs::ChildOf, flecs::Wildcard));
test_str(c.path().c_str(), "::Root");
}
void World_set_lookup_path(void) {
flecs::world ecs;
auto parent = ecs.entity("Parent");
auto child = ecs.scope(parent).entity("Child");
test_assert(ecs.lookup("Parent") == parent);
test_assert(ecs.lookup("Child") == 0);
test_assert(ecs.lookup("Parent::Child") == child);
flecs::entity_t lookup_path[] = { parent, 0 };
flecs::entity_t *old_path = ecs.set_lookup_path(lookup_path);
test_assert(ecs.lookup("Parent") == parent);
test_assert(ecs.lookup("Child") == child);
test_assert(ecs.lookup("Parent::Child") == child);
ecs.set_lookup_path(old_path);
}
void World_run_post_frame(void) {
flecs::world ecs;
int ctx = 10;
ecs.system()
.iter([&](flecs::iter& it) {
it.world().run_post_frame([](flecs::world_t *w, void *ctx) {
int *i = static_cast<int*>(ctx);
test_int(*i, 10);
i[0] ++;
}, &ctx);
});
test_int(ctx, 10);
ecs.progress();
test_int(ctx, 11);
}
void World_component_w_low_id(void) {
flecs::world ecs;
flecs::entity p = ecs.component<Position>();
test_assert(p.id() < FLECS_HI_COMPONENT_ID);
}
void World_reregister_after_reset_w_hooks_and_in_use(void) {
flecs::world ecs;
ecs.component<Pod>();
ecs.entity().add<Pod>();
test_int(1, Pod::ctor_invoked);
flecs::reset();
ecs.component<Pod>();
ecs.entity().add<Pod>();
test_int(2, Pod::ctor_invoked);
}
void World_reregister_after_reset_w_hooks_and_in_use_implicit(void) {
flecs::world ecs;
ecs.component<Pod>();
ecs.entity().add<Pod>();
test_int(1, Pod::ctor_invoked);
flecs::reset();
ecs.entity().add<Pod>();
test_int(2, Pod::ctor_invoked);
}
void World_get_ref() {
flecs::world ecs;
struct Space { int v; };
ecs.set<Space>({12});
auto space = ecs.get_ref<Space>();
test_int(12, space->v);
}
void World_get_set_log_level(void) {
test_int(flecs::log::get_level(), -1);
flecs::log::set_level(4);
test_int(flecs::log::get_level(), 4);
}
void World_reset_world(void) {
flecs::world ecs;
flecs::entity e = ecs.entity();
test_assert(ecs.exists(e));
ecs.reset();
test_assert(!ecs.exists(e));
}
void World_id_from_pair_type(void) {
flecs::world ecs;
flecs::id id = ecs.id<flecs::pair<Position, Velocity>>();
test_assert(id.is_pair());
test_assert(id.first() == ecs.id<Position>());
test_assert(id.second() == ecs.id<Velocity>());
}
void World_scope_w_name(void) {
flecs::world ecs;
flecs::entity parent = ecs.entity("parent");
flecs::entity child = ecs.scope("parent").entity();
test_assert(child.has(flecs::ChildOf, parent));
}
void World_set_get_context(void) {
flecs::world ecs;
int ctx;
ecs.set_ctx(&ctx);
test_assert(ecs.get_ctx() == &ctx);
test_assert(ecs.get_binding_ctx() == nullptr);
}
void World_set_get_binding_context(void) {
flecs::world ecs;
int ctx;
ecs.set_binding_ctx(&ctx);
test_assert(ecs.get_binding_ctx() == &ctx);
test_assert(ecs.get_ctx() == nullptr);
}
static void ctx_free(void *ctx) {
static_cast<int*>(ctx)[0] = 10;
}
void World_set_get_context_w_free(void) {
int ctx = 0;
{
flecs::world ecs;
ecs.set_ctx(&ctx, ctx_free);
test_assert(ecs.get_ctx() == &ctx);
test_assert(ecs.get_binding_ctx() == nullptr);
test_int(ctx, 0);
}
test_int(ctx, 10);
}
void World_set_get_binding_context_w_free(void) {
int ctx = 0;
{
flecs::world ecs;
ecs.set_binding_ctx(&ctx, ctx_free);
test_assert(ecs.get_binding_ctx() == &ctx);
test_assert(ecs.get_ctx() == nullptr);
test_int(ctx, 0);
}
test_int(ctx, 10);
}
void World_make_pair(void) {
flecs::world ecs;
flecs::entity r = ecs.entity();
flecs::entity t = ecs.entity();
flecs::id id = ecs.pair(r, t);
test_assert(id.is_pair());
test_assert(id.first() == r);
test_assert(id.second() == t);
}
void World_make_pair_of_pair_id(void) {
install_test_abort();
flecs::world ecs;
flecs::entity r = ecs.entity();
flecs::entity t = ecs.entity();
flecs::id id = ecs.pair(r, t);
test_expect_abort();
ecs.pair(id, t);
}
void World_make_pair_of_pair_id_tgt(void) {
install_test_abort();
flecs::world ecs;
flecs::entity r = ecs.entity();
flecs::entity t = ecs.entity();
flecs::id id = ecs.pair(r, t);
test_expect_abort();
ecs.pair(r, id);
}
void World_make_pair_of_pair_type(void) {
install_test_abort();
flecs::world ecs;
flecs::entity t = ecs.entity();
flecs::id id = ecs.pair<Position>(t);
test_assert(id.is_pair());
test_assert(id.first() == ecs.id<Position>());
test_assert(id.second() == t);
}
void World_delta_time(void) {
flecs::world ecs;
float dt = 0;
ecs.entity().add<Tag>();
ecs.system<Tag>()
.each([&](flecs::entity e, Tag) {
dt = e.world().delta_time();
});
ecs.progress(2);
test_int(dt, 2);
}