Files
PixelDefense/engine/libs/flecs/test/api/src/Query.c

9841 lines
268 KiB
C

#include <api.h>
#include <stdlib.h>
static
int order_by_entity(
ecs_entity_t e1,
const void *ptr1,
ecs_entity_t e2,
const void *ptr2)
{
return (e1 > e2) - (e1 < e2);
}
static
uint64_t group_by_first_id(
ecs_world_t *world,
ecs_table_t *table,
ecs_id_t id,
void *ctx)
{
const ecs_type_t *type = ecs_table_get_type(table);
ecs_id_t *first = type->array;
if (!first) {
return 0;
}
return first[0];
}
static
uint64_t group_by_rel(ecs_world_t *world, ecs_table_t *table, ecs_id_t id, void *ctx) {
ecs_id_t match;
if (ecs_search(world, table, ecs_pair(id, EcsWildcard), &match) != -1) {
return ecs_pair_second(world, match);
}
return 0;
}
void Query_simple_query_existing_table(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ecs_entity_t e = ecs_new(world, TagA);
ecs_query_t *q = ecs_query_new(world, "TagA");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_simple_query_2_existing_tables(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_add(world, e2, TagB);
ecs_query_t *q = ecs_query_new(world, "TagA");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_simple_query_new_table(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ecs_query_t *q = ecs_query_new(world, "TagA");
test_assert(q != NULL);
ecs_entity_t e = ecs_new(world, TagA);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_simple_query_2_new_tables(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_query_t *q = ecs_query_new(world, "TagA");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_add(world, e2, TagB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_simple_query_existing_and_new_table(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_query_t *q = ecs_query_new(world, "TagA");
test_assert(q != NULL);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_add(world, e2, TagB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_wildcard_query_existing_table(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, ObjA);
ECS_TAG(world, ObjB);
ecs_entity_t e1 = ecs_new_w_pair(world, Rel, ObjA);
ecs_entity_t e2 = ecs_new_w_pair(world, Rel, ObjB);
ecs_query_t *q = ecs_query_new(world, "(Rel, *)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(ecs_pair(Rel, ObjA), ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(ecs_pair(Rel, ObjB), ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_wildcard_query_new_table(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, ObjA);
ECS_TAG(world, ObjB);
ecs_query_t *q = ecs_query_new(world, "(Rel, *)");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new_w_pair(world, Rel, ObjA);
ecs_entity_t e2 = ecs_new_w_pair(world, Rel, ObjB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(ecs_pair(Rel, ObjA), ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(ecs_pair(Rel, ObjB), ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_wildcard_query_existing_table_2_results_p_table(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, ObjA);
ECS_TAG(world, ObjB);
ECS_TAG(world, ObjC);
ecs_entity_t e1 = ecs_new_w_pair(world, Rel, ObjA);
ecs_entity_t e2 = ecs_new_w_pair(world, Rel, ObjB);
ecs_add_pair(world, e1, Rel, ObjC);
ecs_add_pair(world, e2, Rel, ObjC);
ecs_query_t *q = ecs_query_new(world, "(Rel, *)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(ecs_pair(Rel, ObjA), ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(ecs_pair(Rel, ObjC), ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(ecs_pair(Rel, ObjB), ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(ecs_pair(Rel, ObjC), ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_wildcard_query_new_table_2_results_p_table(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, ObjA);
ECS_TAG(world, ObjB);
ECS_TAG(world, ObjC);
ecs_query_t *q = ecs_query_new(world, "(Rel, *)");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new_w_pair(world, Rel, ObjA);
ecs_entity_t e2 = ecs_new_w_pair(world, Rel, ObjB);
ecs_add_pair(world, e1, Rel, ObjC);
ecs_add_pair(world, e2, Rel, ObjC);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(ecs_pair(Rel, ObjA), ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(ecs_pair(Rel, ObjC), ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(ecs_pair(Rel, ObjB), ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(ecs_pair(Rel, ObjC), ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_wildcard_query_2nd_term(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, TgtA);
ECS_TAG(world, TgtB);
ECS_TAG(world, TgtC);
ECS_TAG(world, Tag);
ecs_entity_t e1 = ecs_new(world, Tag);
ecs_add_pair(world, e1, Rel, TgtA);
ecs_add_pair(world, e1, Rel, TgtB);
ecs_entity_t e2 = ecs_new(world, Tag);
ecs_add_pair(world, e2, Rel, TgtA);
ecs_entity_t e3 = ecs_new(world, Tag);
ecs_add_pair(world, e3, Rel, TgtA);
ecs_add_pair(world, e3, Rel, TgtC);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {{ Tag }, { ecs_pair(Rel, EcsWildcard) }}
});
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(Tag, it.ids[0]);
test_uint(ecs_pair(Rel, TgtA), it.ids[1]);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(Tag, it.ids[0]);
test_uint(ecs_pair(Rel, TgtA), it.ids[1]);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(Tag, it.ids[0]);
test_uint(ecs_pair(Rel, TgtB), it.ids[1]);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e3, it.entities[0]);
test_uint(Tag, it.ids[0]);
test_uint(ecs_pair(Rel, TgtA), it.ids[1]);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e3, it.entities[0]);
test_uint(Tag, it.ids[0]);
test_uint(ecs_pair(Rel, TgtC), it.ids[1]);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_wildcard_query_2nd_term_self(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, TgtA);
ECS_TAG(world, TgtB);
ECS_TAG(world, TgtC);
ECS_TAG(world, Tag);
ecs_entity_t e1 = ecs_new(world, Tag);
ecs_add_pair(world, e1, Rel, TgtA);
ecs_add_pair(world, e1, Rel, TgtB);
ecs_entity_t e2 = ecs_new(world, Tag);
ecs_add_pair(world, e2, Rel, TgtA);
ecs_entity_t e3 = ecs_new(world, Tag);
ecs_add_pair(world, e3, Rel, TgtA);
ecs_add_pair(world, e3, Rel, TgtC);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {{ Tag }, { ecs_pair(Rel, EcsWildcard), .src.flags = EcsSelf }}
});
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(Tag, it.ids[0]);
test_uint(ecs_pair(Rel, TgtA), it.ids[1]);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(Tag, it.ids[0]);
test_uint(ecs_pair(Rel, TgtA), it.ids[1]);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(Tag, it.ids[0]);
test_uint(ecs_pair(Rel, TgtB), it.ids[1]);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e3, it.entities[0]);
test_uint(Tag, it.ids[0]);
test_uint(ecs_pair(Rel, TgtA), it.ids[1]);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e3, it.entities[0]);
test_uint(Tag, it.ids[0]);
test_uint(ecs_pair(Rel, TgtC), it.ids[1]);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_simple_query_existing_empty_table(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_add(world, e1, TagB);
ecs_query_t *q = ecs_query_new(world, "TagA");
test_assert(q != NULL);
ecs_remove(world, e1, TagB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_simple_query_existing_empty_type(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_PREFAB(world, TypeX, TagA, TagB);
ecs_query_t *q = ecs_query_new(world, "TagA");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_add(world, e1, TagB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_simple_query_new_empty_table(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_query_t *q = ecs_query_new(world, "TagA");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_add(world, e1, TagB);
ecs_remove(world, e1, TagB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_component_query_existing_table(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t e = ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e, it.entities[0]);
test_uint(ecs_id(Position), ecs_field_id(&it, 1));
test_assert(ecs_field_size(&it, 1) == sizeof(Position));
test_assert(ecs_field(&it, Position, 1) != NULL);
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_component_query_new_table(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
ecs_entity_t e = ecs_new(world, Position);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e, it.entities[0]);
test_uint(ecs_id(Position), ecs_field_id(&it, 1));
test_uint(ecs_field_size(&it, 1), sizeof(Position));
test_assert(ecs_field(&it, Position, 1) != NULL);
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_component_query_existing_empty_table(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_TAG(world, TagA);
ecs_entity_t e = ecs_new(world, Position);
ecs_add(world, e, TagA);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
ecs_remove(world, e, TagA);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e, it.entities[0]);
test_uint(ecs_id(Position), ecs_field_id(&it, 1));
test_uint(ecs_field_size(&it, 1), sizeof(Position));
test_assert(ecs_field(&it, Position, 1) != NULL);
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_2_component_query_existing_empty_table(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_TAG(world, Tag);
ECS_PREFAB(world, MyType, Position, Velocity);
ecs_entity_t e = ecs_new(world, Position);
ecs_add(world, e, Velocity);
ecs_add(world, e, Tag);
ecs_query_t *q = ecs_query_new(world, "Position, Velocity");
test_assert(q != NULL);
ecs_remove(world, e, Tag);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e, it.entities[0]);
test_uint(ecs_id(Position), ecs_field_id(&it, 1));
test_uint(ecs_id(Velocity), ecs_field_id(&it, 2));
test_uint(ecs_field_size(&it, 1), sizeof(Position));
test_assert(ecs_field(&it, Position, 1) != NULL);
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_2_component_query_existing_empty_type(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_PREFAB(world, MyType, Position, Velocity);
ecs_query_t *q = ecs_query_new(world, "Position, Velocity");
test_assert(q != NULL);
ecs_entity_t e = ecs_new(world, Position);
ecs_add(world, e, Velocity);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e, it.entities[0]);
test_uint(ecs_id(Position), ecs_field_id(&it, 1));
test_uint(ecs_id(Velocity), ecs_field_id(&it, 2));
test_uint(ecs_field_size(&it, 1), sizeof(Position));
test_assert(ecs_field(&it, Position, 1) != NULL);
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_only_optional(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ecs_query_t *q = ecs_query_new(world, "?TagA");
test_assert(q != NULL);
ecs_entity_t e = ecs_new(world, TagA);
int32_t count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
if (ecs_field_is_set(&it, 1)) {
test_assert(count == 0);
test_int(it.count, 1);
test_uint(it.entities[0], e);
count ++;
}
}
test_int(count, 1);
ecs_query_fini(q);
ecs_fini(world);
}
void Query_only_optional_new_empty_table(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ecs_entity_t e = ecs_new(world, TagA);
ecs_query_t *q = ecs_query_new(world, "?TagA");
test_assert(q != NULL);
int32_t count = 0, total_count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
if (ecs_field_is_set(&it, 1)) {
test_assert(count == 0);
test_int(it.count, 1);
test_uint(it.entities[0], e);
count ++;
}
total_count ++;
}
test_int(count, 1);
test_assert(total_count >= count);
int32_t prev_total_count = total_count;
total_count = 0;
ecs_remove(world, e, TagA);
it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
test_assert(!ecs_field_is_set(&it, 1));
test_assert(it.count > 0);
total_count ++;
}
test_assert(total_count == (prev_total_count - 1));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_only_optional_new_empty_non_empty_table(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e = ecs_new(world, TagA);
ecs_add(world, e, TagB);
ecs_query_t *q = ecs_query_new(world, "?TagA");
test_assert(q != NULL);
int32_t count = 0, total_count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
if (ecs_field_is_set(&it, 1)) {
test_assert(count == 0);
test_int(it.count, 1);
test_uint(it.entities[0], e);
count ++;
}
total_count ++;
}
test_int(count, 1);
test_assert(total_count >= count);
int32_t prev_total_count = total_count;
count = 0; total_count = 0;
ecs_remove(world, e, TagA);
ecs_table_t *table = ecs_get_table(world, e);
it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
test_assert(!ecs_field_is_set(&it, 1));
test_assert(it.count > 0);
total_count ++;
if (it.entities[0] == e) {
test_assert(table == it.table);
count ++;
}
}
test_int(count, 1);
test_assert(total_count == prev_total_count);
ecs_query_fini(q);
ecs_fini(world);
}
void Query_only_optional_new_unset_tables(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_TAG(world, TagC);
ecs_entity_t e = ecs_new(world, TagA);
ecs_add(world, e, TagB);
ecs_table_t *table = ecs_get_table(world, e);
ecs_query_t *q = ecs_query_new(world, "?TagC");
test_assert(q != NULL);
int32_t count = 0, total_count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
test_assert(!ecs_field_is_set(&it, 1));
test_assert(it.count > 0);
if (it.entities[0] == e) {
test_assert(table == it.table);
count ++;
}
total_count ++;
}
test_int(count, 1);
test_assert(total_count >= count);
int32_t prev_total_count = total_count;
count = 0; total_count = 0;
ecs_remove(world, e, TagA);
table = ecs_get_table(world, e);
it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
test_assert(!ecs_field_is_set(&it, 1));
test_assert(it.count > 0);
total_count ++;
if (it.entities[0] == e) {
test_assert(table == it.table);
count ++;
}
}
test_int(count, 1);
test_assert(total_count == prev_total_count);
ecs_query_fini(q);
ecs_fini(world);
}
void Query_singleton_w_optional_new_empty_table(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Singleton);
ECS_TAG(world, TagA);
ecs_singleton_add(world, Singleton);
ecs_entity_t e = ecs_new(world, TagA);
ecs_set_name(world, e, "e");
ecs_query_t *q = ecs_query_new(world, "Singleton($), ?TagA");
test_assert(q != NULL);
int32_t count = 0, total_count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
if (ecs_field_is_set(&it, 2)) {
test_assert(count == 0);
test_int(it.count, 1);
test_uint(it.entities[0], e);
count ++;
}
total_count ++;
}
test_int(count, 1);
test_assert(total_count >= count);
int32_t prev_total_count = total_count;
total_count = 0;
ecs_remove(world, e, TagA);
it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
test_assert(!ecs_field_is_set(&it, 2));
test_assert(it.count > 0);
total_count ++;
}
test_assert(total_count == (prev_total_count - 1));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_singleton_w_optional_new_empty_non_empty_table(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Singleton);
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_singleton_add(world, Singleton);
ecs_entity_t e = ecs_new(world, TagA);
ecs_add(world, e, TagB);
ecs_query_t *q = ecs_query_new(world, "Singleton($), ?TagA");
test_assert(q != NULL);
int32_t count = 0, total_count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
if (ecs_field_is_set(&it, 2)) {
test_assert(count == 0);
test_int(it.count, 1);
test_uint(it.entities[0], e);
count ++;
}
total_count ++;
}
test_int(count, 1);
test_assert(total_count >= count);
int32_t prev_total_count = total_count;
count = 0; total_count = 0;
ecs_remove(world, e, TagA);
ecs_table_t *table = ecs_get_table(world, e);
it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
test_assert(!ecs_field_is_set(&it, 2));
test_assert(it.count > 0);
total_count ++;
if (it.entities[0] == e) {
test_assert(table == it.table);
count ++;
}
}
test_int(count, 1);
test_assert(total_count == prev_total_count);
ecs_query_fini(q);
ecs_fini(world);
}
void Query_singleton_w_optional_new_unset_tables(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Singleton);
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_TAG(world, TagC);
ecs_singleton_add(world, Singleton);
ecs_entity_t e = ecs_new(world, TagA);
ecs_add(world, e, TagB);
ecs_table_t *table = ecs_get_table(world, e);
ecs_query_t *q = ecs_query_new(world, "Singleton($), ?TagC");
test_assert(q != NULL);
int32_t count = 0, total_count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
test_assert(!ecs_field_is_set(&it, 2));
test_assert(it.count > 0);
if (it.entities[0] == e) {
test_assert(table == it.table);
count ++;
}
total_count ++;
}
test_int(count, 1);
test_assert(total_count >= count);
int32_t prev_total_count = total_count;
count = 0; total_count = 0;
ecs_remove(world, e, TagA);
table = ecs_get_table(world, e);
it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
test_assert(!ecs_field_is_set(&it, 2));
test_assert(it.count > 0);
total_count ++;
if (it.entities[0] == e) {
test_assert(table == it.table);
count ++;
}
}
test_int(count, 1);
test_assert(total_count == prev_total_count);
ecs_query_fini(q);
ecs_fini(world);
}
void Query_query_only_from_entity(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_entity_t e = ecs_new_entity(world, "e");
ecs_add(world, e, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag(e)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 0);
test_uint(ecs_field_src(&it, 1), e);
test_uint(ecs_field_id(&it, 1), Tag);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_from_entity_no_match(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_entity_t e = ecs_new_entity(world, "e");
ecs_query_t *q = ecs_query_new(world, "Tag(e)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(false, ecs_query_next(&it));
ecs_add(world, e, Tag);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 0);
test_uint(ecs_field_src(&it, 1), e);
test_uint(ecs_field_id(&it, 1), Tag);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_from_entity_no_match_iter_alloc(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, A);
ECS_TAG(world, B);
ECS_TAG(world, C);
ECS_TAG(world, D);
ECS_TAG(world, E);
ecs_new_entity(world, "e");
ecs_query_t *q = ecs_query_new(world, "A(e), B(e), C(e), D(e), E(e)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_from_singleton(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_singleton_add(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag($)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 0);
test_uint(ecs_field_src(&it, 1), Tag);
test_uint(ecs_field_id(&it, 1), Tag);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_from_entity_match_after(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_entity_t e = ecs_new_entity(world, "e");
ecs_query_t *q = ecs_query_new(world, "Tag(e)");
test_assert(q != NULL);
ecs_add(world, e, Tag);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 0);
test_uint(ecs_field_src(&it, 1), e);
test_uint(ecs_field_id(&it, 1), Tag);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_from_singleton_match_after(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag($)");
test_assert(q != NULL);
ecs_singleton_add(world, Tag);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 0);
test_uint(ecs_field_src(&it, 1), Tag);
test_uint(ecs_field_id(&it, 1), Tag);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_from_singleton_component_match_after(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position($)");
test_assert(q != NULL);
ecs_singleton_add(world, Position);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 0);
test_uint(ecs_field_src(&it, 1), ecs_id(Position));
test_uint(ecs_field_id(&it, 1), ecs_id(Position));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_from_nothing(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag()");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 0);
test_uint(ecs_field_id(&it, 1), Tag);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_from_entity_optional(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_ENTITY(world, Ent, Position);
ecs_set(world, Ent, Position, {10, 20});
ecs_query_t *q = ecs_query_new(world, "?Position(Ent)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(it.count, 0);
test_bool(ecs_field_is_set(&it, 1), true);
Position *ptr = ecs_field(&it, Position, 1);
test_assert(ptr != NULL);
test_int(ptr->x, 10);
test_int(ptr->y, 20);
test_assert(!ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_from_entity_no_match_optional(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_new_entity(world, "Ent");
ecs_query_t *q = ecs_query_new(world, "?Position(Ent)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(it.count, 0);
test_bool(ecs_field_is_set(&it, 1), false);
test_assert(!ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_from_entity_or(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t Ent = ecs_new_entity(world, "Ent");
ecs_set(world, Ent, Position, {10, 20});
ecs_query_t *q = ecs_query_new(world, "Position(Ent) || Velocity(Ent)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(it.count, 0);
test_bool(ecs_field_is_set(&it, 1), true);
test_assert(!ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_from_entity_no_match_or(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Mass);
ECS_ENTITY(world, Ent, Mass);
ecs_query_t *q = ecs_query_new(world, "Position(Ent) || Velocity(Ent)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_from_entity_or_change(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t Ent = ecs_new_entity(world, "Ent");
ecs_set(world, Ent, Position, {10, 20});
ecs_query_t *q = ecs_query_new(world, "Position(Ent) || Velocity(Ent)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(it.count, 0);
test_bool(ecs_field_is_set(&it, 1), true);
test_uint(ecs_id(Position), ecs_field_id(&it, 1));
test_uint(Ent, it.sources[0]);
test_assert(!ecs_query_next(&it));
ecs_remove(world, Ent, Position);
ecs_set(world, Ent, Velocity, {1, 2});
it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(it.count, 0);
test_bool(ecs_field_is_set(&it, 1), true);
test_uint(ecs_id(Velocity), ecs_field_id(&it, 1));
test_uint(Ent, it.sources[0]);
test_assert(!ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_from_entity_or_change(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_TAG(world, Tag);
ecs_entity_t Ent = ecs_new_entity(world, "Ent");
ecs_set(world, Ent, Position, {10, 20});
ecs_entity_t e = ecs_new(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Position(Ent) || Velocity(Ent), Tag");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(it.count, 1);
test_bool(ecs_field_is_set(&it, 1), true);
test_uint(ecs_id(Position), ecs_field_id(&it, 1));
test_uint(Tag, ecs_field_id(&it, 2));
test_uint(e, it.entities[0]);
test_uint(Ent, it.sources[0]);
test_uint(0, it.sources[1]);
test_assert(!ecs_query_next(&it));
ecs_remove(world, Ent, Position);
ecs_set(world, Ent, Velocity, {1, 2});
it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(it.count, 1);
test_bool(ecs_field_is_set(&it, 1), true);
test_uint(ecs_id(Velocity), ecs_field_id(&it, 1));
test_uint(Tag, ecs_field_id(&it, 2));
test_uint(e, it.entities[0]);
test_uint(Ent, it.sources[0]);
test_uint(0, it.sources[1]);
test_assert(!ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_from_entity_w_superset(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Mass);
ecs_entity_t g = ecs_new_entity(world, "Game");
ecs_set(world, g, Position, {10, 20});
ecs_set(world, g, Velocity, {1, 2});
ecs_entity_t p = ecs_new_w_id(world, EcsPrefab);
ecs_set(world, p, Mass, {30});
ecs_entity_t e = ecs_new_w_pair(world, EcsIsA, p);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {
{ .id = ecs_id(Velocity), .src.name = "Game" },
{ .id = ecs_id(Mass), .src.flags = EcsUp }
}
});
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e, it.entities[0]);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_singleton_tag_non_instanced(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Singleton);
ECS_COMPONENT(world, Position);
ecs_singleton_add(world, Singleton);
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_entity_t e3 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t e4 = ecs_set(world, 0, Position, {40, 50});
ecs_query_t *q = ecs_query_new(world, "Position, Singleton($)");
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(4, it.count);
test_uint(e1, it.entities[0]);
test_uint(e2, it.entities[1]);
test_uint(e3, it.entities[2]);
test_uint(e4, it.entities[3]);
test_uint(0, it.sources[0]);
test_uint(Singleton, it.sources[1]);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_int(p[1].x, 20);
test_int(p[1].y, 30);
test_int(p[2].x, 30);
test_int(p[2].y, 40);
test_int(p[3].x, 40);
test_int(p[3].y, 50);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_singleton_tag_instanced(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Singleton);
ECS_COMPONENT(world, Position);
ecs_singleton_add(world, Singleton);
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_entity_t e3 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t e4 = ecs_set(world, 0, Position, {40, 50});
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){ .filter = {
.expr = "Position, Singleton($)",
.instanced = true
}});
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(4, it.count);
test_uint(e1, it.entities[0]);
test_uint(e2, it.entities[1]);
test_uint(e3, it.entities[2]);
test_uint(e4, it.entities[3]);
test_uint(0, it.sources[0]);
test_uint(Singleton, it.sources[1]);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_int(p[1].x, 20);
test_int(p[1].y, 30);
test_int(p[2].x, 30);
test_int(p[2].y, 40);
test_int(p[3].x, 40);
test_int(p[3].y, 50);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_singleton_component_non_instanced(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_singleton_set(world, Velocity, {1, 2});
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_entity_t e3 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t e4 = ecs_set(world, 0, Position, {40, 50});
ecs_query_t *q = ecs_query_new(world, "Position, Velocity($)");
ecs_iter_t it = ecs_query_iter(world, q);
Position *p;
Velocity *v;
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(0, it.sources[0]);
test_uint(ecs_id(Velocity), it.sources[1]);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
v = ecs_field(&it, Velocity, 2);
test_int(v[0].x, 1);
test_int(v[0].y, 2);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(0, it.sources[0]);
test_uint(ecs_id(Velocity), it.sources[1]);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 20);
test_int(p[0].y, 30);
v = ecs_field(&it, Velocity, 2);
test_int(v[0].x, 1);
test_int(v[0].y, 2);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e3, it.entities[0]);
test_uint(0, it.sources[0]);
test_uint(ecs_id(Velocity), it.sources[1]);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
v = ecs_field(&it, Velocity, 2);
test_int(v[0].x, 1);
test_int(v[0].y, 2);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e4, it.entities[0]);
test_uint(0, it.sources[0]);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 40);
test_int(p[0].y, 50);
v = ecs_field(&it, Velocity, 2);
test_int(v[0].x, 1);
test_int(v[0].y, 2);
test_uint(ecs_id(Velocity), it.sources[1]);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_singleton_component_instanced(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_singleton_set(world, Velocity, {1, 2});
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_entity_t e3 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t e4 = ecs_set(world, 0, Position, {40, 50});
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){ .filter = {
.expr = "Position, Velocity($)",
.instanced = true
}});
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(4, it.count);
test_uint(e1, it.entities[0]);
test_uint(e2, it.entities[1]);
test_uint(e3, it.entities[2]);
test_uint(e4, it.entities[3]);
test_uint(0, it.sources[0]);
test_uint(ecs_id(Velocity), it.sources[1]);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_int(p[1].x, 20);
test_int(p[1].y, 30);
test_int(p[2].x, 30);
test_int(p[2].y, 40);
test_int(p[3].x, 40);
test_int(p[3].y, 50);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(v[0].x, 1);
test_int(v[0].y, 2);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_from_entity(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e1 = ecs_new_entity(world, "e");
ecs_add(world, e1, TagB);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_query_t *q = ecs_query_new(world, "TagA, TagB(e)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(ecs_field_src(&it, 1), 0);
test_uint(ecs_field_id(&it, 1), TagA);
test_uint(ecs_field_src(&it, 2), e1);
test_uint(ecs_field_id(&it, 2), TagB);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_from_singleton(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_singleton_add(world, TagB);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_query_t *q = ecs_query_new(world, "TagA, TagB($)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(ecs_field_src(&it, 1), 0);
test_uint(ecs_field_id(&it, 1), TagA);
test_uint(ecs_field_src(&it, 2), TagB);
test_uint(ecs_field_id(&it, 2), TagB);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_from_entity_match_after(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e1 = ecs_new_entity(world, "e");
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_query_t *q = ecs_query_new(world, "TagA, TagB(e)");
test_assert(q != NULL);
ecs_add(world, e1, TagB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(ecs_field_src(&it, 1), 0);
test_uint(ecs_field_id(&it, 1), TagA);
test_uint(ecs_field_src(&it, 2), e1);
test_uint(ecs_field_id(&it, 2), TagB);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_from_singleton_match_after(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_query_t *q = ecs_query_new(world, "TagA, TagB($)");
test_assert(q != NULL);
ecs_singleton_add(world, TagB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(ecs_field_src(&it, 1), 0);
test_uint(ecs_field_id(&it, 1), TagA);
test_uint(ecs_field_src(&it, 2), TagB);
test_uint(ecs_field_id(&it, 2), TagB);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_from_nothing(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_query_t *q = ecs_query_new(world, "TagA, TagB()");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(ecs_field_src(&it, 1), 0);
test_uint(ecs_field_id(&it, 1), TagA);
test_uint(ecs_field_src(&it, 2), 0);
test_uint(ecs_field_id(&it, 2), TagB);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_existing_switch_and_case(void) {
ecs_world_t *world = ecs_mini();
ECS_ENTITY(world, Movement, Union);
ECS_TAG(world, Walking);
ECS_TAG(world, Running);
ecs_entity_t e1 = ecs_new_w_pair(world, Movement, Walking);
ecs_query_t *q = ecs_query_new(world, "(Movement, *)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(ecs_field_id(&it, 1), ecs_pair(Movement, EcsWildcard));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_new_switch_and_case(void) {
ecs_world_t *world = ecs_mini();
ECS_ENTITY(world, Movement, Union);
ECS_TAG(world, Walking);
ECS_TAG(world, Running);
ecs_query_t *q = ecs_query_new(world, "(Movement, *)");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new_w_pair(world, Movement, Walking);
ecs_entity_t e2 = ecs_new_w_pair(world, Movement, Running);
ecs_entity_t e3 = ecs_new_w_pair(world, Movement, Walking);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 3);
test_uint(it.entities[0], e1);
test_uint(it.entities[1], e2);
test_uint(it.entities[2], e3);
test_uint(ecs_field_id(&it, 1), ecs_pair(Movement, EcsWildcard));
test_assert(it.sizes != NULL);
test_int(it.sizes[0], ECS_SIZEOF(ecs_entity_t));
test_assert(it.ptrs != NULL);
ecs_entity_t *cases = ecs_field(&it, ecs_entity_t, 1);
test_uint(cases[0], Walking);
test_uint(cases[1], Running);
test_uint(cases[2], Walking);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_for_case_existing(void) {
ecs_world_t *world = ecs_mini();
ECS_ENTITY(world, Movement, Union);
ECS_TAG(world, Walking);
ECS_TAG(world, Running);
ecs_entity_t e1 = ecs_new_w_pair(world, Movement, Walking);
ecs_new_w_pair(world, Movement, Running);
ecs_entity_t e3 = ecs_new_w_pair(world, Movement, Walking);
ecs_query_t *q = ecs_query_new(world, "(Movement, Walking)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(ecs_field_id(&it, 1), ecs_pair(Movement, Walking));
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(ecs_field_id(&it, 1), ecs_pair(Movement, Walking));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_for_case_new(void) {
ecs_world_t *world = ecs_mini();
ECS_ENTITY(world, Movement, Union);
ECS_TAG(world, Walking);
ECS_TAG(world, Running);
ecs_query_t *q = ecs_query_new(world, "(Movement, Walking)");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new_w_pair(world, Movement, Walking);
ecs_new_w_pair(world, Movement, Running);
ecs_entity_t e3 = ecs_new_w_pair(world, Movement, Walking);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(ecs_field_id(&it, 1), ecs_pair(Movement, Walking));
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(ecs_field_id(&it, 1), ecs_pair(Movement, Walking));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_case_w_generation(void) {
ecs_world_t *world = ecs_mini();
ECS_ENTITY(world, Rel, Union);
ecs_entity_t tgt_1 = ecs_new_id(world);
ecs_delete(world, tgt_1);
tgt_1 = ecs_new_id(world);
test_assert(tgt_1 != (uint32_t)tgt_1);
ecs_entity_t tgt_2 = ecs_new_id(world);
ecs_delete(world, tgt_2);
tgt_2 = ecs_new_id(world);
test_assert(tgt_2 != (uint32_t)tgt_2);
ecs_query_t *q = ecs_query_new(world, "(Rel, *)");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new_w_pair(world, Rel, tgt_1);
ecs_entity_t e2 = ecs_new_w_pair(world, Rel, tgt_2);
ecs_iter_t it = ecs_query_iter(world, q);
{
test_bool(true, ecs_query_next(&it));
test_int(it.count, 2);
test_uint(it.entities[0], e1);
test_uint(it.entities[1], e2);
test_uint(ecs_field_id(&it, 1), ecs_pair(Rel, EcsWildcard));
ecs_entity_t *cases = ecs_field(&it, ecs_entity_t, 1);
test_assert(cases != NULL);
test_uint(cases[0], tgt_1);
test_uint(cases[1], tgt_2);
}
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_case_w_not_alive(void) {
ecs_world_t *world = ecs_mini();
ECS_ENTITY(world, Rel, Union);
ecs_entity_t tgt_1 = ecs_new_id(world);
ecs_delete(world, tgt_1);
tgt_1 = ecs_new_id(world);
test_assert(tgt_1 != (uint32_t)tgt_1);
ecs_entity_t tgt_2 = ecs_new_id(world);
ecs_delete(world, tgt_2);
tgt_2 = ecs_new_id(world);
test_assert(tgt_2 != (uint32_t)tgt_2);
ecs_query_t *q = ecs_query_new(world, "(Rel, *)");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new_w_pair(world, Rel, tgt_1);
ecs_entity_t e2 = ecs_new_w_pair(world, Rel, tgt_2);
ecs_delete(world, tgt_1);
ecs_delete(world, tgt_2);
ecs_iter_t it = ecs_query_iter(world, q);
{
test_bool(true, ecs_query_next(&it));
test_int(it.count, 2);
test_uint(it.entities[0], e1);
test_uint(it.entities[1], e2);
test_uint(ecs_field_id(&it, 1), ecs_pair(Rel, EcsWildcard));
ecs_entity_t *cases = ecs_field(&it, ecs_entity_t, 1);
test_assert(cases != NULL);
test_uint(cases[0], tgt_1);
test_uint(cases[1], tgt_2);
}
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_for_switch_filter_term(void) {
ecs_world_t *world = ecs_mini();
ECS_ENTITY(world, Movement, Union);
ECS_TAG(world, Walking);
ECS_TAG(world, Running);
ecs_query_t *q = ecs_query_new(world, "[none] (Movement, *)");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new_w_pair(world, Movement, Walking);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(ecs_field_id(&it, 1), ecs_pair(Movement, EcsWildcard));
test_int(it.sizes[0], ECS_SIZEOF(ecs_entity_t));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_switch_from_nothing(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_ENTITY(world, Movement, Union);
ECS_TAG(world, Walking);
ECS_TAG(world, Running);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){ .filter = {
.terms = {
{Tag},
{ ecs_pair(Movement, EcsWildcard), .src.flags = EcsIsEntity }
}
}});
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new_w_id(world, Tag);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(ecs_field_id(&it, 1), Tag);
test_uint(ecs_field_id(&it, 2), ecs_pair(Movement, EcsWildcard));
test_bool(true, ecs_field_is_set(&it, 1));
test_bool(false, ecs_field_is_set(&it, 2));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_case_from_nothing(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_ENTITY(world, Movement, Union);
ECS_TAG(world, Walking);
ECS_TAG(world, Running);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){ .filter = {
.terms = {
{Tag},
{ecs_pair(Movement, Walking), .src.flags = EcsIsEntity }
}
}});
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new_w_id(world, Tag);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(ecs_field_id(&it, 1), Tag);
test_uint(ecs_field_id(&it, 2), ecs_pair(Movement, Walking));
test_bool(true, ecs_field_is_set(&it, 1));
test_bool(false, ecs_field_is_set(&it, 2));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_case_inherited(void) {
test_quarantine("Aug 1st 2022");
ecs_world_t *world = ecs_mini();
ECS_ENTITY(world, Movement, Union);
ECS_TAG(world, Walking);
ECS_TAG(world, Running);
ecs_entity_t base_1 = ecs_new_w_pair(world, Movement, Walking);
ecs_entity_t inst_1 = ecs_new_w_pair(world, EcsIsA, base_1);
ecs_entity_t base_2 = ecs_new_w_pair(world, Movement, Running);
ecs_new_w_pair(world, EcsIsA, base_2);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){ .filter = {
.terms = {
{ ecs_pair(Movement, Walking) }
}
}});
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], base_1);
test_uint(ecs_field_id(&it, 1), ecs_pair(Movement, Walking));
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst_1);
test_uint(ecs_field_id(&it, 1), ecs_pair(Movement, Walking));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_disabled_from_nothing(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){ .filter = {
.terms = {
{TagA},
{TagB, .src.flags = EcsIsEntity}
}
}});
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new_w_id(world, TagA);
ecs_add(world, e1, TagB);
ecs_add_id(world, e1, ECS_TOGGLE | TagB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(ecs_field_id(&it, 1), TagA);
test_uint(ecs_field_id(&it, 2), TagB);
test_bool(true, ecs_field_is_set(&it, 1));
test_bool(false, ecs_field_is_set(&it, 2));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_2_or(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_TAG(world, TagC);
ecs_query_t *q = ecs_query_new(world, "TagA || TagB");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_add(world, e2, TagB);
ecs_entity_t e3 = ecs_new(world, TagB);
ecs_new(world, TagC);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e3, it.entities[0]);
test_uint(TagB, ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_only_3_or(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_TAG(world, TagC);
ECS_TAG(world, TagD);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){ .filter = {
.expr = "TagA || TagB || TagC"
}});
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_add(world, e2, TagB);
ecs_entity_t e3 = ecs_new(world, TagB);
ecs_entity_t e4 = ecs_new(world, TagC);
ecs_new(world, TagD);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e3, it.entities[0]);
test_uint(TagB, ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e4, it.entities[0]);
test_uint(TagC, ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_query_2_or(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_TAG(world, TagC);
ECS_TAG(world, Foo);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){ .filter = {
.expr = "TagA || TagB, Foo"
}});
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_add(world, e2, TagB);
ecs_entity_t e3 = ecs_new(world, TagB);
ecs_add(world, e1, Foo);
ecs_add(world, e2, Foo);
ecs_add(world, e3, Foo);
ecs_new(world, TagB);
ecs_new(world, TagC);
ecs_new(world, Foo);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_uint(Foo, ecs_field_id(&it, 2));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_uint(Foo, ecs_field_id(&it, 2));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e3, it.entities[0]);
test_uint(TagB, ecs_field_id(&it, 1));
test_uint(Foo, ecs_field_id(&it, 2));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_query_3_or(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_TAG(world, TagC);
ECS_TAG(world, Foo);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){ .filter = {
.expr = "TagA || TagB || TagC, Foo"
}});
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_add(world, e2, TagB);
ecs_entity_t e3 = ecs_new(world, TagB);
ecs_add(world, e3, TagC);
ecs_entity_t e4 = ecs_new(world, TagC);
ecs_add(world, e1, Foo);
ecs_add(world, e2, Foo);
ecs_add(world, e3, Foo);
ecs_add(world, e4, Foo);
ecs_new(world, TagB);
ecs_new(world, TagC);
ecs_new(world, Foo);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_uint(Foo, ecs_field_id(&it, 2));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_uint(Foo, ecs_field_id(&it, 2));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e3, it.entities[0]);
test_uint(TagB, ecs_field_id(&it, 1));
test_uint(Foo, ecs_field_id(&it, 2));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e4, it.entities[0]);
test_uint(TagC, ecs_field_id(&it, 1));
test_uint(Foo, ecs_field_id(&it, 2));
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_query_and_type(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Foo);
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_PREFAB(world, TypeX, TagA, TagB);
ecs_entity_t e1 = ecs_new_w_id(world, TagA);
ecs_add(world, e1, TagB);
ecs_table_t *table1 = ecs_get_table(world, e1);
ecs_entity_t e2 = ecs_new_w_id(world, TagA);
ecs_add(world, e2, TagB);
ecs_add(world, e2, Foo);
ecs_table_t *table2 = ecs_get_table(world, e2);
/* Not matched */
ecs_new(world, TagA);
ecs_new(world, TagB);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){ .filter = {
.expr = "AND | TypeX"
}});
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.ids[0], TypeX);
test_assert(it.table == table1);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.ids[0], TypeX);
test_assert(it.table == table2);
test_bool(ecs_query_next(&it), false);
ecs_fini(world);
}
void Query_query_or_type(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_PREFAB(world, TypeX, TagA, TagB);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_table_t *table1 = ecs_get_table(world, e1);
ecs_entity_t e2 = ecs_new(world, TagB);
ecs_table_t *table2 = ecs_get_table(world, e2);
ecs_entity_t e3 = ecs_new(world, TagA);
ecs_add(world, e3, TagB);
ecs_table_t *table3 = ecs_get_table(world, e3);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){ .filter = {
.expr = "OR | TypeX"
}});
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.ids[0], TagA);
test_assert(it.table == table1);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.ids[0], TagB);
test_assert(it.table == table2);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.ids[0], TagA);
test_assert(it.table == table3);
test_bool(ecs_query_next(&it), false);
ecs_query_fini(q);
ecs_fini(world);
}
void Query_query_and_type_match_after(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Foo);
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_PREFAB(world, TypeX, TagA, TagB);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){ .filter = {
.expr = "AND | TypeX"
}});
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new_w_id(world, TagA);
ecs_add(world, e1, TagB);
ecs_table_t *table1 = ecs_get_table(world, e1);
ecs_entity_t e2 = ecs_new_w_id(world, TagA);
ecs_add(world, e2, TagB);
ecs_add(world, e2, Foo);
ecs_table_t *table2 = ecs_get_table(world, e2);
/* Not matched */
ecs_new(world, TagA);
ecs_new(world, TagB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.ids[0], TypeX);
test_assert(it.table == table1);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.ids[0], TypeX);
test_assert(it.table == table2);
test_bool(ecs_query_next(&it), false);
ecs_fini(world);
}
void Query_query_or_type_match_after(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_PREFAB(world, TypeX, TagA, TagB);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){ .filter = {
.expr = "OR | TypeX"
}});
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_table_t *table1 = ecs_get_table(world, e1);
ecs_entity_t e2 = ecs_new(world, TagB);
ecs_table_t *table2 = ecs_get_table(world, e2);
ecs_entity_t e3 = ecs_new(world, TagA);
ecs_add(world, e3, TagB);
ecs_table_t *table3 = ecs_get_table(world, e3);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.ids[0], TagA);
test_assert(it.table == table1);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.ids[0], TagB);
test_assert(it.table == table2);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.ids[0], TagA);
test_assert(it.table == table3);
test_bool(ecs_query_next(&it), false);
ecs_query_fini(q);
ecs_fini(world);
}
void Query_query_changed_after_new(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "[in] Position");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_new(world, Position);
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Query_query_changed_after_delete(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t e1 = ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "[in] Position");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_delete(world, e1);
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Query_query_changed_after_add(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t e1 = ecs_new(world, 0);
ecs_query_t *q = ecs_query_new(world, "[in] Position");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_add(world, e1, Position);
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Query_query_changed_after_remove(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t e1 = ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "[in] Position");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_remove(world, e1, Position);
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Query_query_changed_after_set(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t e1 = ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "[in] Position");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_set(world, e1, Position, {10, 20});
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Query_query_change_after_modified(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t e1 = ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "[in] Position");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_modified(world, e1, Position);
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Sys(ecs_iter_t *it) { }
void Query_query_change_after_out_system(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, Sys, EcsOnUpdate, [out] Position);
ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "[in] Position");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_progress(world, 0);
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Query_query_change_after_in_system(void) {
ecs_world_t *world = ecs_init();
ECS_COMPONENT(world, Position);
ECS_SYSTEM(world, Sys, EcsOnUpdate, [in] Position);
ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "[in] Position");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_progress(world, 0);
test_assert(ecs_query_changed(q, 0) == false);
it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == false);
ecs_iter_fini(&it);
ecs_fini(world);
}
void Query_query_change_after_modified_out_term(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e = ecs_new(world, Position);
ecs_add(world, e, Velocity);
ecs_query_t *q = ecs_query_new(world, "[in] Position, [out] Velocity");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_set(world, e, Position, {10, 20});
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_set(world, e, Velocity, {1, 2});
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Query_query_change_check_iter(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_TAG(world, TagC);
ecs_entity_t e1 = ecs_new(world, Position);
ecs_entity_t e2 = ecs_new(world, Position);
ecs_entity_t e3 = ecs_new(world, Position);
ecs_add(world, e1, TagA);
ecs_add(world, e2, TagB);
ecs_add(world, e3, TagC);
ecs_query_t *q = ecs_query_new(world, "[in] Position");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) {
test_bool(ecs_query_changed(q, &it), true);
}
test_assert(ecs_query_changed(q, 0) == false);
ecs_modified(world, e1, Position);
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e1);
test_bool(ecs_query_changed(q, &it), true);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e2);
test_bool(ecs_query_changed(q, &it), false);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e3);
test_bool(ecs_query_changed(q, &it), false);
test_bool(ecs_query_changed(q, NULL), false);
test_bool(ecs_query_next(&it), false);
it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == false);
while (ecs_query_next(&it)) {
test_bool(ecs_query_changed(q, &it), false);
}
test_assert(ecs_query_changed(q, 0) == false);
ecs_modified(world, e2, Position);
it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e1);
test_bool(ecs_query_changed(q, &it), false);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e2);
test_bool(ecs_query_changed(q, &it), true);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e3);
test_bool(ecs_query_changed(q, &it), false);
test_bool(ecs_query_changed(q, NULL), false);
test_bool(ecs_query_next(&it), false);
ecs_fini(world);
}
void Query_query_change_check_iter_after_skip_read(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t e = ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "[in] Position");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_set(world, e, Position, {10, 20});
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_assert(ecs_query_changed(q, &it) == true);
ecs_query_skip(&it);
test_bool(ecs_query_next(&it), false);
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_assert(ecs_query_changed(q, &it) == true);
test_bool(ecs_query_next(&it), false);
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Query_query_change_check_iter_after_skip_write(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_new(world, Position);
ecs_query_t *qw = ecs_query_new(world, "[out] Position");
ecs_query_t *q = ecs_query_new(world, "[in] Position");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
it = ecs_query_iter(world, qw);
test_assert(ecs_query_changed(q, 0) == false);
test_bool(ecs_query_next(&it), true);
test_assert(ecs_query_changed(q, 0) == false);
ecs_query_skip(&it);
test_bool(ecs_query_next(&it), false);
test_assert(ecs_query_changed(q, 0) == false);
test_assert(ecs_query_changed(q, 0) == false);
it = ecs_query_iter(world, qw);
test_assert(ecs_query_changed(q, 0) == false);
test_bool(ecs_query_next(&it), true);
test_assert(ecs_query_changed(q, 0) == false);
test_bool(ecs_query_next(&it), false);
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_assert(ecs_query_changed(q, &it) == true);
test_bool(ecs_query_next(&it), false);
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Query_query_change_parent_term(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t parent = ecs_new(world, Position);
ecs_new_w_pair(world, EcsChildOf, parent);
ecs_query_t *q = ecs_query_new(world, "[in] Position(parent)");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_set(world, parent, Position, {10, 20});
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_assert(ecs_query_changed(q, &it) == true);
test_bool(ecs_query_next(&it), false);
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Query_query_change_prefab_term(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t base = ecs_new(world, Position);
ecs_new_w_pair(world, EcsIsA, base);
ecs_query_t *q = ecs_query_new(world, "[in] Position(up)");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_set(world, base, Position, {10, 20});
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_assert(ecs_query_changed(q, &it) == true);
test_bool(ecs_query_next(&it), false);
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Query_query_change_parent_term_w_tag(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t parent = ecs_new(world, Position);
ecs_add_id(world, parent, EcsPrefab);
ecs_new_w_pair(world, EcsChildOf, parent);
ecs_query_t *q = ecs_query_new(world, "[in] Position(parent), ?Prefab");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_set(world, parent, Position, {10, 20});
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_assert(ecs_query_changed(q, &it) == true);
test_bool(ecs_query_next(&it), false);
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Query_query_change_prefab_term_w_tag(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t base = ecs_new(world, Position);
ecs_add_id(world, base, EcsPrefab);
ecs_new_w_pair(world, EcsIsA, base);
ecs_query_t *q = ecs_query_new(world, "[in] Position(up)");
test_assert(q != NULL);
test_assert(ecs_query_changed(q, 0) == true);
test_assert(ecs_query_changed(q, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_changed(q, 0) == true);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q, 0) == false);
ecs_set(world, base, Position, {10, 20});
test_assert(ecs_query_changed(q, 0) == true);
it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_assert(ecs_query_changed(q, &it) == true);
test_bool(ecs_query_next(&it), false);
test_assert(ecs_query_changed(q, 0) == false);
ecs_fini(world);
}
void Query_query_change_skip_non_instanced(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_TAG(world, Tag);
ecs_entity_t base = ecs_new(world, Position);
ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, base);
ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, base);
ecs_entity_t e3 = ecs_new_w_pair(world, EcsIsA, base);
ecs_entity_t e4 = ecs_new_w_pair(world, EcsIsA, base);
ecs_add(world, e1, Velocity);
ecs_add(world, e2, Velocity);
ecs_add(world, e3, Velocity);
ecs_add(world, e4, Velocity);
ecs_add(world, e3, Tag);
ecs_add(world, e4, Tag);
ecs_query_t *q = ecs_query_new(world, "Position(up), [out] Velocity");
test_assert(q != NULL);
ecs_query_t *q_r = ecs_query_new(world, "Position(up), [in] Velocity");
test_assert(q_r != NULL);
test_assert(ecs_query_changed(q_r, 0) == true);
ecs_iter_t it = ecs_query_iter(world, q_r);
while (ecs_query_next(&it)) { }
test_assert(ecs_query_changed(q_r, 0) == false);
it = ecs_query_iter(world, q);
int32_t count = 0;
while (ecs_query_next(&it)) {
test_int(it.count, 1);
if (it.entities[0] == e1) {
ecs_query_skip(&it); /* Skip one entity in table 1 */
}
if (it.entities[0] == e3 || it.entities[0] == e4) {
ecs_query_skip(&it); /* Skip both entities in table 1 */
}
count ++;
}
test_int(count, 4);
test_bool(ecs_query_changed(q_r, NULL), true);
it = ecs_query_iter(world, q_r);
count = 0;
while (ecs_query_next(&it)) {
test_int(it.count, 1);
if (it.entities[0] == e1 || it.entities[0] == e2) {
/* Table changed, not all entities were skipped */
test_bool( ecs_query_changed(0, &it), true );
}
if (it.entities[0] == e3 || it.entities[0] == e4) {
/* Table did not change, all entities were skipped */
test_bool( ecs_query_changed(0, &it), false );
}
count ++;
}
test_int(count, 4);
test_bool(ecs_query_changed(q_r, NULL), false);
ecs_fini(world);
}
void Query_query_changed_w_or(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e = ecs_new_id(world);
ecs_add(world, e, Position);
ecs_add(world, e, Velocity);
ecs_add(world, e, TagA);
ecs_add(world, e, TagB);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ ecs_id(Position), .inout = EcsIn },
{ TagA, .oper = EcsOr },
{ TagB },
{ ecs_id(Velocity), .inout = EcsIn }
}
});
test_assert(q != NULL);
test_bool(true, ecs_query_changed(q, NULL));
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_next(&it));
test_bool(false, ecs_query_changed(q, NULL));
ecs_set(world, e, Position, {10, 20});
test_bool(true, ecs_query_changed(q, NULL));
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_next(&it));
test_bool(false, ecs_query_changed(q, NULL));
ecs_set(world, e, Velocity, {10, 20});
test_bool(true, ecs_query_changed(q, NULL));
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_next(&it));
test_bool(false, ecs_query_changed(q, NULL));
ecs_fini(world);
}
void Query_query_changed_or(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e1 = ecs_new_id(world);
ecs_add(world, e1, Position);
ecs_add(world, e1, TagA);
ecs_add(world, e1, TagB);
ecs_entity_t e2 = ecs_new_id(world);
ecs_add(world, e2, Velocity);
ecs_add(world, e2, TagA);
ecs_add(world, e2, TagB);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ TagA },
{ ecs_id(Position), .inout = EcsIn, .oper = EcsOr },
{ ecs_id(Velocity), .inout = EcsIn },
{ TagB }
}
});
test_assert(q != NULL);
test_bool(true, ecs_query_changed(q, NULL));
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_next(&it));
test_bool(false, ecs_query_changed(q, NULL));
ecs_set(world, e1, Position, {10, 20});
test_bool(true, ecs_query_changed(q, NULL));
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_next(&it));
test_bool(false, ecs_query_changed(q, NULL));
ecs_set(world, e2, Velocity, {10, 20});
test_bool(true, ecs_query_changed(q, NULL));
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_next(&it));
test_bool(false, ecs_query_changed(q, NULL));
ecs_fini(world);
}
void Query_query_changed_tag(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ecs_entity_t e1 = ecs_new_id(world);
ecs_add(world, e1, TagA);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ TagA }
}
});
test_assert(q != NULL);
test_bool(true, ecs_query_changed(q, NULL));
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_next(&it));
test_bool(false, ecs_query_changed(q, NULL));
ecs_fini(world);
}
void Query_query_changed_no_source(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e1 = ecs_new_id(world);
ecs_add(world, e1, TagA);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ TagA },
{ TagB, .src.flags = EcsIsEntity, .inout = EcsOut }
}
});
test_assert(q != NULL);
test_bool(true, ecs_query_changed(q, NULL));
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_next(&it));
test_bool(false, ecs_query_changed(q, NULL));
ecs_fini(world);
}
void Query_query_changed_no_source_component(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e1 = ecs_new_id(world);
ecs_add(world, e1, Position);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ ecs_id(Position), .inout = EcsIn },
{ ecs_id(Velocity), .src.flags = EcsIsEntity, .inout = EcsOut }
}
});
test_assert(q != NULL);
test_bool(true, ecs_query_changed(q, NULL));
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_next(&it));
test_bool(false, ecs_query_changed(q, NULL));
ecs_fini(world);
}
void Query_query_changed_w_not_out(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t e1 = ecs_new_id(world);
ecs_add(world, e1, Position);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ ecs_id(Position), .inout = EcsIn },
{ ecs_id(Velocity), .inout = EcsOut, .oper = EcsNot }
}
});
test_assert(q != NULL);
test_bool(true, ecs_query_changed(q, NULL));
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_next(&it));
test_bool(false, ecs_query_changed(q, NULL));
ecs_fini(world);
}
void Query_query_changed_w_singleton(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_singleton_set(world, Velocity, {1, 2});
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position)
}, {
.id = ecs_id(Velocity),
.src.id = ecs_id(Velocity)
}}
});
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_uint(e, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(p->x, 10);
test_int(p->y, 20);
test_int(v->x, 1);
test_int(v->y, 2);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_changed_w_only_singleton(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_singleton_set(world, Position, {1, 2});
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position),
.src.id = ecs_id(Position)
}}
});
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
ecs_fini(world);
}
void Query_query_changed_w_only_singleton_after_set(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_singleton_set(world, Position, {1, 2});
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position), .src.id = ecs_id(Position)
}}
});
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
ecs_singleton_set(world, Position, {3, 4});
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 3);
test_int(p->y, 4);
test_bool(false, ecs_query_next(&it));
}
ecs_fini(world);
}
void Query_query_changed_w_only_singleton_after_out_term(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_singleton_set(world, Position, {1, 2});
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position), .src.id = ecs_id(Position)
}}
});
ecs_query_t *q_write = ecs_query(world, {
.filter.terms = {
{ ecs_id(Position), .inout = EcsOut }
}
});
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q_write);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
Position *p = ecs_field(&it, Position, 1);
p->x = 3;
p->y = 4;
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 3);
test_int(p->y, 4);
test_bool(false, ecs_query_next(&it));
}
ecs_fini(world);
}
void Query_query_changed_w_only_singleton_after_singleton_out_term(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_singleton_set(world, Position, {1, 2});
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position), .src.id = ecs_id(Position)
}}
});
ecs_query_t *q_write = ecs_query(world, {
.filter.terms = {
{ ecs_id(Position), .src.id = ecs_id(Position), .inout = EcsOut }
}
});
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q_write);
test_bool(true, ecs_query_next(&it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
p->x = 3;
p->y = 4;
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(0, it.count);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 3);
test_int(p->y, 4);
test_bool(false, ecs_query_next(&it));
}
ecs_fini(world);
}
void Query_query_changed_w_only_parent(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t parent = ecs_set(world, 0, Position, {1, 2});
ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, parent);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position),
.src.flags = EcsParent
}}
});
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
ecs_fini(world);
}
void Query_query_changed_w_only_parent_after_set(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t parent = ecs_set(world, 0, Position, {1, 2});
ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, parent);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position),
.src.flags = EcsParent
}}
});
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
ecs_set(world, parent, Position, {3, 4});
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 3);
test_int(p->y, 4);
test_bool(false, ecs_query_next(&it));
}
ecs_fini(world);
}
void Query_query_changed_w_only_parent_after_out_term(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t parent = ecs_set(world, 0, Position, {1, 2});
ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, parent);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position),
.src.flags = EcsParent
}}
});
ecs_query_t *q_write = ecs_query(world, {
.filter.terms = {
{ ecs_id(Position), .inout = EcsOut }
}
});
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q_write);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(parent, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
p->x = 3;
p->y = 4;
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 3);
test_int(p->y, 4);
test_bool(false, ecs_query_next(&it));
}
ecs_fini(world);
}
void Query_query_changed_w_only_parent_after_parent_out_term(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t parent = ecs_set(world, 0, Position, {1, 2});
ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, parent);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position),
.src.flags = EcsParent
}}
});
ecs_query_t *q_write = ecs_query(world, {
.filter.terms = {
{ ecs_id(Position), .src.flags = EcsParent, .inout = EcsOut }
}
});
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 1);
test_int(p->y, 2);
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q_write);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
p->x = 3;
p->y = 4;
test_bool(false, ecs_query_next(&it));
}
{
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
Position *p = ecs_field(&it, Position, 1);
test_int(p->x, 3);
test_int(p->y, 4);
test_bool(false, ecs_query_next(&it));
}
ecs_fini(world);
}
void Query_subquery_match_existing(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_PREFAB(world, Type, Position, Velocity);
ecs_bulk_new(world, Position, 3);
ecs_bulk_new(world, Velocity, 3);
const ecs_id_t *ids = ecs_bulk_new(world, Position, 3);
ecs_add(world, ids[0], Velocity);
ecs_add(world, ids[1], Velocity);
ecs_add(world, ids[2], Velocity);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
ecs_query_t *sq = ecs_query_init(world, &(ecs_query_desc_t){
.filter.expr = "Velocity",
.parent = q
});
test_assert(sq != NULL);
int32_t table_count = 0, entity_count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
table_count ++;
entity_count += it.count;
int32_t i;
for (i = 0; i < it.count; i ++) {
test_assert(ecs_has(world, it.entities[i], Position));
}
}
test_int(table_count, 2);
test_int(entity_count, 6);
table_count = 0, entity_count = 0;
it = ecs_query_iter(world, sq);
while (ecs_query_next(&it)) {
table_count ++;
entity_count += it.count;
int32_t i;
for (i = 0; i < it.count; i ++) {
test_assert(ecs_has(world, it.entities[i], Position));
test_assert(ecs_has(world, it.entities[i], Velocity));
}
}
test_int(table_count, 1);
test_int(entity_count, 3);
ecs_query_fini(sq);
ecs_fini(world);
}
void Query_subquery_match_new(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
ecs_query_t *sq = ecs_query_init(world, &(ecs_query_desc_t){
.filter.expr = "Velocity",
.parent = q
});
test_assert(sq != NULL);
ecs_bulk_new(world, Position, 3);
ecs_bulk_new(world, Velocity, 3);
const ecs_id_t *ids = ecs_bulk_new(world, Position, 3);
ecs_add(world, ids[0], Velocity);
ecs_add(world, ids[1], Velocity);
ecs_add(world, ids[2], Velocity);
int32_t table_count = 0, entity_count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
table_count ++;
entity_count += it.count;
int32_t i;
for (i = 0; i < it.count; i ++) {
test_assert(ecs_has(world, it.entities[i], Position));
}
}
test_int(table_count, 2);
test_int(entity_count, 6);
table_count = 0, entity_count = 0;
it = ecs_query_iter(world, sq);
while (ecs_query_next(&it)) {
table_count ++;
entity_count += it.count;
int32_t i;
for (i = 0; i < it.count; i ++) {
test_assert(ecs_has(world, it.entities[i], Position));
test_assert(ecs_has(world, it.entities[i], Velocity));
}
}
test_int(table_count, 1);
test_int(entity_count, 3);
ecs_query_fini(sq);
ecs_fini(world);
}
void Query_subquery_inactive(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_bulk_new(world, Position, 3);
ecs_bulk_new(world, Velocity, 3);
ECS_ENTITY(world, e, Position, Velocity);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
ecs_query_t *sq = ecs_query_init(world, &(ecs_query_desc_t){
.filter.expr = "Velocity",
.parent = q
});
test_assert(sq != NULL);
/* Create an empty table which should deactivate it for both queries */
ecs_delete(world, e);
int32_t table_count = 0, entity_count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
table_count ++;
entity_count += it.count;
int32_t i;
for (i = 0; i < it.count; i ++) {
test_assert(ecs_has(world, it.entities[i], Position));
}
}
test_int(table_count, 1);
test_int(entity_count, 3);
table_count = 0, entity_count = 0;
it = ecs_query_iter(world, sq);
test_int(it.table_count, 0);
ecs_iter_fini(&it);
table_count = 0, entity_count = 0;
it = ecs_query_iter(world, sq);
while (ecs_query_next(&it)) {
table_count ++;
}
test_int(table_count, 0);
ecs_query_fini(sq);
ecs_fini(world);
}
void Query_subquery_unmatch(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t parent = ecs_new(world, 0);
ecs_add(world, parent, Position);
ecs_entity_t e1 = ecs_new(world, 0);
ecs_add(world, e1, Position);
ecs_add(world, e1, Velocity);
ecs_add_pair(world, e1, EcsChildOf, parent);
ecs_entity_t e2 = ecs_new(world, 0);
ecs_add(world, e2, Position);
ecs_add_pair(world, e2, EcsChildOf, parent);
ecs_query_t *q = ecs_query_new(world, "Position, Position(parent)");
test_assert(q != NULL);
ecs_query_t *sq = ecs_query_init(world, &(ecs_query_desc_t){
.filter.expr = "Velocity",
.parent = q
});
test_assert(sq != NULL);
int32_t table_count = 0, entity_count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
table_count ++;
entity_count += it.count;
int32_t i;
for (i = 0; i < it.count; i ++) {
test_assert(ecs_has(world, it.entities[i], Position));
}
}
test_int(table_count, 2);
test_int(entity_count, 2);
table_count = 0, entity_count = 0;
it = ecs_query_iter(world, sq);
while (ecs_query_next(&it)) {
table_count ++;
entity_count += it.count;
int32_t i;
for (i = 0; i < it.count; i ++) {
test_assert(ecs_has(world, it.entities[i], Position));
test_assert(ecs_has(world, it.entities[i], Velocity));
}
}
test_int(table_count, 1);
test_int(entity_count, 1);
/* Query now no longer match */
ecs_remove(world, parent, Position);
/* Force rematching */
ecs_run_aperiodic(world, 0);
/* Test if tables have been unmatched */
it = ecs_query_iter(world, q);
test_int(it.table_count, 0);
ecs_iter_fini(&it);
it = ecs_query_iter(world, sq);
test_int(it.table_count, 0);
ecs_iter_fini(&it);
ecs_query_fini(sq);
ecs_fini(world);
}
void Query_subquery_rematch(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t parent = ecs_new(world, 0);
ecs_add(world, parent, Position);
ecs_entity_t e1 = ecs_new(world, 0);
ecs_add(world, e1, Position);
ecs_add(world, e1, Velocity);
ecs_add_pair(world, e1, EcsChildOf, parent);
ecs_entity_t e2 = ecs_new(world, 0);
ecs_add(world, e2, Position);
ecs_add_pair(world, e2, EcsChildOf, parent);
ecs_query_t *q = ecs_query_new(world, "Position, Position(parent)");
test_assert(q != NULL);
ecs_query_t *sq = ecs_query_init(world, &(ecs_query_desc_t){
.filter.expr = "Velocity",
.parent = q
});
test_assert(sq != NULL);
int32_t table_count = 0, entity_count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
table_count ++;
entity_count += it.count;
int32_t i;
for (i = 0; i < it.count; i ++) {
test_assert(ecs_has(world, it.entities[i], Position));
}
}
test_int(table_count, 2);
test_int(entity_count, 2);
table_count = 0, entity_count = 0;
it = ecs_query_iter(world, sq);
while (ecs_query_next(&it)) {
table_count ++;
entity_count += it.count;
int32_t i;
for (i = 0; i < it.count; i ++) {
test_assert(ecs_has(world, it.entities[i], Position));
test_assert(ecs_has(world, it.entities[i], Velocity));
}
}
test_int(table_count, 1);
test_int(entity_count, 1);
/* Query now no longer match */
ecs_remove(world, parent, Position);
/* Force unmatching */
ecs_run_aperiodic(world, 0);
/* Test if tables have been unmatched */
it = ecs_query_iter(world, q);
test_int(it.table_count, 0);
ecs_iter_fini(&it);
it = ecs_query_iter(world, sq);
test_int(it.table_count, 0);
ecs_iter_fini(&it);
/* Rematch queries */
ecs_add(world, parent, Position);
/* Force rematching */
ecs_run_aperiodic(world, 0);
/* Test if tables have been rematched */
it = ecs_query_iter(world, q);
test_int(it.table_count, 2);
ecs_iter_fini(&it);
it = ecs_query_iter(world, sq);
test_int(it.table_count, 1);
ecs_iter_fini(&it);
ecs_query_fini(sq);
ecs_fini(world);
}
void Query_subquery_rematch_w_parent_optional(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Mass);
ecs_entity_t parent = ecs_new(world, 0);
ecs_entity_t e1 = ecs_new(world, 0);
ecs_add(world, e1, Position);
ecs_add(world, e1, Velocity);
ecs_add_pair(world, e1, EcsChildOf, parent);
ecs_entity_t e2 = ecs_new(world, 0);
ecs_add(world, e2, Position);
ecs_add_pair(world, e2, EcsChildOf, parent);
ecs_query_t *q = ecs_query_new(world, "Position, ?Position(parent)");
test_assert(q != NULL);
ecs_query_t *sq = ecs_query_init(world, &(ecs_query_desc_t){
.filter.expr = "Velocity",
.parent = q
});
test_assert(sq != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_int(it.table_count, 2);
ecs_iter_fini(&it);
it = ecs_query_iter(world, sq);
test_int(it.table_count, 1);
ecs_iter_fini(&it);
/* Trigger rematch */
ecs_add(world, parent, Position);
ecs_run_aperiodic(world, 0);
/* Tables should be matched */
it = ecs_query_iter(world, q);
test_int(it.table_count, 3);
ecs_iter_fini(&it);
it = ecs_query_iter(world, sq);
test_int(it.table_count, 1);
ecs_iter_fini(&it);
ecs_query_fini(sq);
ecs_fini(world);
}
void Query_subquery_rematch_w_sub_optional(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Mass);
ecs_entity_t parent = ecs_new(world, 0);
ecs_entity_t e1 = ecs_new(world, 0);
ecs_add(world, e1, Position);
ecs_add(world, e1, Velocity);
ecs_add_pair(world, e1, EcsChildOf, parent);
ecs_entity_t e2 = ecs_new(world, 0);
ecs_add(world, e2, Position);
ecs_add_pair(world, e2, EcsChildOf, parent);
ecs_query_t *q = ecs_query_new(world, "Position, ?Position(parent)");
test_assert(q != NULL);
ecs_query_t *sq = ecs_query_init(world, &(ecs_query_desc_t){
.filter.expr = "Velocity",
.parent = q
});
test_assert(sq != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_int(it.table_count, 2);
ecs_iter_fini(&it);
it = ecs_query_iter(world, sq);
test_int(it.table_count, 1);
ecs_iter_fini(&it);
/* Trigger rematch */
ecs_add(world, parent, Position);
ecs_run_aperiodic(world, 0);
/* Tables should be matched */
it = ecs_query_iter(world, q);
test_int(it.table_count, 3);
ecs_iter_fini(&it);
it = ecs_query_iter(world, sq);
test_int(it.table_count, 1);
ecs_iter_fini(&it);
ecs_query_fini(sq);
ecs_fini(world);
}
void Query_query_single_pairs(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_TAG(world, Rel);
ECS_ENTITY(world, e1, (Rel, Position));
ECS_ENTITY(world, e2, (Rel, Velocity));
ECS_ENTITY(world, e3, Position);
ECS_ENTITY(world, e4, Velocity);
int32_t table_count = 0, entity_count = 0;
ecs_query_t *q = ecs_query_new(world, "(Rel, Velocity)");
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
table_count ++;
int32_t i;
for (i = 0; i < it.count; i ++) {
test_assert(it.entities[i] == e2);
entity_count ++;
}
}
test_int(table_count, 1);
test_int(entity_count, 1);
ecs_fini(world);
}
void Query_query_single_instanceof(void) {
ecs_world_t *world = ecs_mini();
ECS_ENTITY(world, BaseA, 0);
ECS_ENTITY(world, BaseB, 0);
ECS_ENTITY(world, e1, (IsA, BaseB));
ECS_ENTITY(world, e2, (IsA, BaseA));
int32_t table_count = 0, entity_count = 0;
ecs_query_t *q = ecs_query_new(world, "(IsA, BaseA)");
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
table_count ++;
int32_t i;
for (i = 0; i < it.count; i ++) {
test_assert(it.entities[i] == e2);
entity_count ++;
}
}
test_int(table_count, 1);
test_int(entity_count, 1);
ecs_fini(world);
}
void Query_query_single_childof(void) {
ecs_world_t *world = ecs_mini();
ECS_ENTITY(world, BaseA, 0);
ECS_ENTITY(world, BaseB, 0);
ECS_ENTITY(world, e1, (ChildOf, BaseB));
ECS_ENTITY(world, e2, (ChildOf, BaseA));
int32_t table_count = 0, entity_count = 0;
ecs_query_t *q = ecs_query_new(world, "(ChildOf, BaseA)");
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
table_count ++;
int32_t i;
for (i = 0; i < it.count; i ++) {
test_assert(it.entities[i] == e2);
entity_count ++;
}
}
test_int(table_count, 1);
test_int(entity_count, 1);
ecs_fini(world);
}
void Query_query_optional_owned(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t base = ecs_new(world, Velocity);
ecs_entity_t e1 = ecs_new(world, Position);
ecs_add_pair(world, e1, EcsIsA, base);
ecs_entity_t e2 = ecs_new(world, Position);
ecs_add(world, e2, Velocity);
ecs_entity_t e3 = ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position, ?Velocity(self)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
int32_t count = 0;
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_assert(p != NULL);
if (it.entities[0] == e1) {
test_assert(v == NULL);
test_bool(ecs_field_is_set(&it, 1), true);
test_bool(ecs_field_is_set(&it, 2), false);
} else if (it.entities[0] == e2) {
test_assert(v != NULL);
test_bool(ecs_field_is_set(&it, 1), true);
test_bool(ecs_field_is_set(&it, 2), true);
} else if (it.entities[0] == e3) {
test_assert(v == NULL);
test_bool(ecs_field_is_set(&it, 1), true);
test_bool(ecs_field_is_set(&it, 2), false);
}
count ++;
}
test_int(count, 3);
ecs_fini(world);
}
void Query_query_optional_shared(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t base = ecs_new(world, Velocity);
ecs_entity_t e1 = ecs_new(world, Position);
ecs_add_pair(world, e1, EcsIsA, base);
ecs_entity_t e2 = ecs_new(world, Position);
ecs_add(world, e2, Velocity);
ecs_entity_t e3 = ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position, ?Velocity(up)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
int32_t count = 0;
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_assert(p != NULL);
if (it.entities[0] == e1) {
test_assert(v != NULL);
test_bool(ecs_field_is_set(&it, 1), true);
test_bool(ecs_field_is_set(&it, 2), true);
} else if (it.entities[0] == e2) {
test_assert(v == NULL);
test_bool(ecs_field_is_set(&it, 1), true);
test_bool(ecs_field_is_set(&it, 2), false);
} else if (it.entities[0] == e3) {
test_assert(v == NULL);
test_bool(ecs_field_is_set(&it, 1), true);
test_bool(ecs_field_is_set(&it, 2), false);
}
count ++;
}
test_int(count, 3);
ecs_fini(world);
}
void Query_query_optional_shared_nested(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t base_base = ecs_new(world, Velocity);
ecs_entity_t base = ecs_new(world, 0);
ecs_add_pair(world, base, EcsIsA, base_base);
ecs_entity_t e1 = ecs_new(world, Position);
ecs_add_pair(world, e1, EcsIsA, base);
ecs_entity_t e2 = ecs_new(world, Position);
ecs_add(world, e2, Velocity);
ecs_entity_t e3 = ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position, ?Velocity(up)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
int32_t count = 0;
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_assert(p != NULL);
if (it.entities[0] == e1) {
test_assert(v != NULL);
} else if (it.entities[0] == e2) {
test_assert(v == NULL);
} else if (it.entities[0] == e3) {
test_assert(v == NULL);
}
count ++;
}
test_int(count, 3);
ecs_fini(world);
}
void Query_query_optional_any(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t base = ecs_new(world, Velocity);
ecs_entity_t e1 = ecs_new(world, Position);
ecs_add_pair(world, e1, EcsIsA, base);
ecs_entity_t e2 = ecs_new(world, Position);
ecs_add(world, e2, Velocity);
ecs_entity_t e3 = ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position, ?Velocity(self|up)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
int32_t count = 0;
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_assert(p != NULL);
if (it.entities[0] == e1) {
test_assert(v != NULL);
test_assert(!ecs_field_is_self(&it, 2));
} else if (it.entities[0] == e2) {
test_assert(v != NULL);
test_assert(ecs_field_is_self(&it, 2));
} else if (it.entities[0] == e3) {
test_assert(v == NULL);
}
count ++;
}
test_int(count, 3);
ecs_fini(world);
}
void Query_query_rematch_optional_after_add(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t base = ecs_new(world, 0);
ecs_entity_t e1 = ecs_new(world, Position);
ecs_add_pair(world, e1, EcsIsA, base);
ecs_entity_t e2 = ecs_new(world, Position);
ecs_add(world, e2, Velocity);
ecs_entity_t e3 = ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position, ?Velocity(up)");
test_assert(q != NULL);
/* First iteration, base doesn't have Velocity but query should match with
* entity anyway since the component is optional */
ecs_iter_t it = ecs_query_iter(world, q);
int32_t count = 0;
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_assert(p != NULL);
if (it.entities[0] == e1) {
test_assert(v == NULL);
} else if (it.entities[0] == e2) {
test_assert(v == NULL);
} else if (it.entities[0] == e3) {
test_assert(v == NULL);
}
count ++;
}
test_int(count, 3);
/* Add Velocity to base, should trigger rematch */
ecs_add(world, base, Velocity);
/* Trigger a merge, which triggers the rematch */
ecs_readonly_begin(world);
ecs_readonly_end(world);
/* Second iteration, base has Velocity and entity should be able to access
* the shared component. */
it = ecs_query_iter(world, q);
count = 0;
while (ecs_query_next(&it)) {
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_assert(p != NULL);
if (it.entities[0] == e1) {
test_assert(v != NULL);
} else if (it.entities[0] == e2) {
test_assert(v == NULL);
} else if (it.entities[0] == e3) {
test_assert(v == NULL);
}
count ++;
}
test_int(count, 3);
ecs_fini(world);
}
void Query_get_owned_tag(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_entity_t e = ecs_new(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag");
int count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
test_assert(ecs_field_w_size(&it, 0, 1) == NULL);
test_int(it.count, 1);
test_int(it.entities[0], e);
count += it.count;
}
test_int(count, 1);
ecs_fini(world);
}
void Query_get_shared_tag(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_entity_t base = ecs_new(world, Tag);
ecs_entity_t instance = ecs_new_w_pair(world, EcsIsA, base);
ecs_query_t *q = ecs_query_new(world, "Tag(up)");
int count = 0;
ecs_iter_t it = ecs_query_iter(world, q);
while (ecs_query_next(&it)) {
test_assert(ecs_field_w_size(&it, 0, 1) == NULL);
test_int(it.count, 1);
test_int(it.entities[0], instance);
count += it.count;
}
test_int(count, 1);
ecs_fini(world);
}
void Query_explicit_delete(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
/* Ensure query isn't deleted twice when deleting world */
ecs_query_fini(q);
ecs_fini(world);
}
void Query_get_column_size(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(ecs_field_size(&it, 1), sizeof(Position));
test_assert(!ecs_query_next(&it));
ecs_fini(world);
}
void Query_orphaned_query(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
/* Nonsense subquery, doesn't matter, this is just for orphan testing */
ecs_query_t *sq = ecs_query_init(world, &(ecs_query_desc_t){
.filter.expr = "Position",
.parent = q
});
test_assert(sq != NULL);
test_assert(!ecs_query_orphaned(sq));
ecs_query_fini(q);
test_assert(ecs_query_orphaned(sq));
ecs_query_fini(sq);
ecs_fini(world);
}
void Query_nested_orphaned_query(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
/* Nonsense subquery, doesn't matter, this is just for orphan testing */
ecs_query_t *sq = ecs_query_init(world, &(ecs_query_desc_t){
.filter.expr = "Position",
.parent = q
});
test_assert(sq != NULL);
ecs_query_t *nsq = ecs_query_init(world, &(ecs_query_desc_t){
.filter.expr = "Position",
.parent = sq
});
test_assert(nsq != NULL);
test_assert(!ecs_query_orphaned(sq));
test_assert(!ecs_query_orphaned(nsq));
ecs_query_fini(q);
test_assert(ecs_query_orphaned(sq));
test_assert(ecs_query_orphaned(nsq));
ecs_query_fini(sq);
ecs_query_fini(nsq);
ecs_fini(world);
}
void Query_invalid_access_orphaned_query(void) {
install_test_abort();
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
/* Nonsense subquery, doesn't matter, this is just for orphan testing */
ecs_query_t *sq = ecs_query_init(world, &(ecs_query_desc_t){
.filter.expr = "Position",
.parent = q
});
test_assert(sq != NULL);
test_assert(!ecs_query_orphaned(sq));
ecs_query_fini(q);
test_expect_abort();
ecs_query_iter(world, sq);
}
void Query_stresstest_query_free(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Foo);
ECS_TAG(world, Bar);
ECS_TAG(world, Hello);
ecs_entity_t e = ecs_new_id(world);
ecs_add(world, e, Foo);
ecs_add(world, e, Bar);
ecs_add(world, e, Hello);
/* Create & delete query to test if query is properly unregistered with
* the table */
for (int i = 0; i < 10000; i ++) {
ecs_query_t *q = ecs_query_new(world, "Foo");
ecs_query_fini(q);
}
/* If code did not crash, test passes */
test_assert(true);
ecs_fini(world);
}
void Query_only_from_entity(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_entity_t e = ecs_set_name(world, 0, "e");
ecs_query_t *q = ecs_query_new(world, "Tag(e)");
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(!ecs_query_next(&it));
ecs_add(world, e, Tag);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_assert(ecs_field_src(&it, 1) == e);
test_assert(ecs_field_id(&it, 1) == Tag);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_only_from_singleton(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_entity_t e = ecs_set_name(world, 0, "e");
ecs_query_t *q = ecs_query_new(world, "e($)");
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(!ecs_query_next(&it));
ecs_add_id(world, e, e);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_assert(ecs_field_src(&it, 1) == e);
test_assert(ecs_field_id(&it, 1) == e);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_only_not_from_entity(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_entity_t e = ecs_set_name(world, 0, "e");
ecs_query_t *q = ecs_query_new(world, "!Tag(e)");
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_assert(ecs_field_src(&it, 1) == e);
test_assert(ecs_field_id(&it, 1) == Tag);
test_assert(!ecs_query_next(&it));
ecs_add(world, e, Tag);
it = ecs_query_iter(world, q);
test_assert(!ecs_query_next(&it));
test_assert(ECS_BIT_IS_SET(it.flags, EcsIterIsValid) == false);
ecs_fini(world);
}
void Query_only_not_from_singleton(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_entity_t e = ecs_set_name(world, 0, "e");
ecs_query_t *q = ecs_query_new(world, "!e($)");
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_assert(ecs_field_src(&it, 1) == e);
test_assert(ecs_field_id(&it, 1) == e);
test_assert(!ecs_query_next(&it));
ecs_add_id(world, e, e);
it = ecs_query_iter(world, q);
test_assert(!ecs_query_next(&it));
ecs_fini(world);
}
void Query_get_filter(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_query_t *q = ecs_query_new(world, "Position, Velocity");
test_assert(q != NULL);
const ecs_filter_t *f = ecs_query_get_filter(q);
test_assert(f != NULL);
test_int(f->term_count, 2);
test_int(f->terms[0].id, ecs_id(Position));
test_int(f->terms[1].id, ecs_id(Velocity));
ecs_fini(world);
}
void Query_group_by(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_TAG(world, TagC);
ECS_TAG(world, TagX);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {{TagX}},
.group_by = group_by_first_id
});
ecs_entity_t e1 = ecs_new(world, TagX);
ecs_entity_t e2 = ecs_new(world, TagX);
ecs_entity_t e3 = ecs_new(world, TagX);
ecs_add_id(world, e1, TagC);
ecs_add_id(world, e2, TagB);
ecs_add_id(world, e3, TagA);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e3);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e2);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e1);
test_bool(ecs_query_next(&it), false);
ecs_fini(world);
}
static int ctx_value;
static int ctx_value_free_invoked = 0;
static
void ctx_value_free(void *ctx) {
test_assert(ctx == &ctx_value);
ctx_value_free_invoked ++;
}
void Query_group_by_w_ctx(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_TAG(world, TagC);
ECS_TAG(world, TagX);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {{TagX}},
.group_by = group_by_first_id,
.group_by_ctx = &ctx_value,
.group_by_ctx_free = ctx_value_free
});
ecs_entity_t e1 = ecs_new(world, TagX);
ecs_entity_t e2 = ecs_new(world, TagX);
ecs_entity_t e3 = ecs_new(world, TagX);
ecs_add_id(world, e1, TagC);
ecs_add_id(world, e2, TagB);
ecs_add_id(world, e3, TagA);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e3);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e2);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e1);
test_bool(ecs_query_next(&it), false);
ecs_query_fini(q);
test_int(ctx_value_free_invoked, 1);
ecs_fini(world);
}
void Query_group_by_w_sort_reverse_group_creation(void) {
ecs_world_t *world = ecs_mini();
ecs_entity_t TagA = ecs_new_id(world);
ecs_entity_t TagB = ecs_new_id(world);
ecs_entity_t TagC = ecs_new_id(world);
ecs_entity_t TagX = ecs_new_id(world);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {{TagX}},
.order_by = order_by_entity,
.group_by = group_by_first_id
});
ecs_entity_t e1 = ecs_new_w_id(world, TagX);
ecs_entity_t e2 = ecs_new_w_id(world, TagX);
ecs_entity_t e3 = ecs_new_w_id(world, TagX);
ecs_add_id(world, e1, TagC);
ecs_add_id(world, e2, TagB);
ecs_add_id(world, e3, TagA);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e3);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e2);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e1);
test_bool(ecs_query_next(&it), false);
ecs_fini(world);
}
void Query_group_by_iter_one(void) {
ecs_world_t* world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, TgtA);
ECS_TAG(world, TgtB);
ECS_TAG(world, TgtC);
ECS_TAG(world, Tag);
ecs_new_w_pair(world, Rel, TgtA);
ecs_entity_t e2 = ecs_new_w_pair(world, Rel, TgtB);
ecs_new_w_pair(world, Rel, TgtC);
ecs_entity_t e4 = ecs_new_w_pair(world, Rel, TgtA);
ecs_entity_t e5 = ecs_new_w_pair(world, Rel, TgtB);
ecs_entity_t e6 = ecs_new_w_pair(world, Rel, TgtC);
ecs_add(world, e4, Tag);
ecs_add(world, e5, Tag);
ecs_add(world, e6, Tag);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ ecs_pair(Rel, EcsWildcard) }
},
.group_by = group_by_rel,
.group_by_id = Rel
});
ecs_iter_t it = ecs_query_iter(world, q);
ecs_query_set_group(&it, TgtB);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(ecs_pair(Rel, TgtB), ecs_field_id(&it, 1));
test_uint(TgtB, it.group_id);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e5, it.entities[0]);
test_uint(ecs_pair(Rel, TgtB), ecs_field_id(&it, 1));
test_uint(TgtB, it.group_id);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_group_by_iter_one_all_groups(void) {
ecs_world_t* world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, TgtA);
ECS_TAG(world, TgtB);
ECS_TAG(world, TgtC);
ECS_TAG(world, Tag);
ecs_entity_t e1 = ecs_new_w_pair(world, Rel, TgtA);
ecs_entity_t e2 = ecs_new_w_pair(world, Rel, TgtB);
ecs_entity_t e3 = ecs_new_w_pair(world, Rel, TgtC);
ecs_entity_t e4 = ecs_new_w_pair(world, Rel, TgtA);
ecs_entity_t e5 = ecs_new_w_pair(world, Rel, TgtB);
ecs_entity_t e6 = ecs_new_w_pair(world, Rel, TgtC);
ecs_add(world, e4, Tag);
ecs_add(world, e5, Tag);
ecs_add(world, e6, Tag);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ ecs_pair(Rel, EcsWildcard) }
},
.group_by = group_by_rel,
.group_by_id = Rel
});
ecs_iter_t it = ecs_query_iter(world, q);
ecs_query_set_group(&it, TgtB);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(ecs_pair(Rel, TgtB), ecs_field_id(&it, 1));
test_uint(TgtB, it.group_id);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e5, it.entities[0]);
test_uint(ecs_pair(Rel, TgtB), ecs_field_id(&it, 1));
test_uint(TgtB, it.group_id);
test_bool(false, ecs_query_next(&it));
it = ecs_query_iter(world, q);
ecs_query_set_group(&it, TgtA);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(ecs_pair(Rel, TgtA), ecs_field_id(&it, 1));
test_uint(TgtA, it.group_id);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e4, it.entities[0]);
test_uint(ecs_pair(Rel, TgtA), ecs_field_id(&it, 1));
test_uint(TgtA, it.group_id);
test_bool(false, ecs_query_next(&it));
it = ecs_query_iter(world, q);
ecs_query_set_group(&it, TgtC);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e3, it.entities[0]);
test_uint(ecs_pair(Rel, TgtC), ecs_field_id(&it, 1));
test_uint(TgtC, it.group_id);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e6, it.entities[0]);
test_uint(ecs_pair(Rel, TgtC), ecs_field_id(&it, 1));
test_uint(TgtC, it.group_id);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_group_by_iter_one_empty(void) {
ecs_world_t* world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, TgtA);
ECS_TAG(world, TgtB);
ECS_TAG(world, TgtC);
ECS_TAG(world, TgtD);
ECS_TAG(world, Tag);
ecs_new_w_pair(world, Rel, TgtA);
ecs_new_w_pair(world, Rel, TgtB);
ecs_new_w_pair(world, Rel, TgtC);
ecs_entity_t e4 = ecs_new_w_pair(world, Rel, TgtA);
ecs_entity_t e5 = ecs_new_w_pair(world, Rel, TgtB);
ecs_entity_t e6 = ecs_new_w_pair(world, Rel, TgtC);
ecs_add(world, e4, Tag);
ecs_add(world, e5, Tag);
ecs_add(world, e6, Tag);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ ecs_pair(Rel, EcsWildcard) }
},
.group_by = group_by_rel,
.group_by_id = Rel
});
ecs_iter_t it = ecs_query_iter(world, q);
ecs_query_set_group(&it, TgtD);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_group_by_iter_one_empty_query(void) {
ecs_world_t* world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, TgtA);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ ecs_pair(Rel, EcsWildcard) }
},
.group_by = group_by_rel,
.group_by_id = Rel
});
ecs_iter_t it = ecs_query_iter(world, q);
ecs_query_set_group(&it, TgtA);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_group_by_iter_one_empty_table(void) {
ecs_world_t* world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, TgtA);
ECS_TAG(world, TgtB);
ECS_TAG(world, TgtC);
ECS_TAG(world, Tag);
ecs_new_w_pair(world, Rel, TgtA);
ecs_new_w_pair(world, Rel, TgtB);
ecs_entity_t e3 = ecs_new_w_pair(world, Rel, TgtC);
ecs_entity_t e4 = ecs_new_w_pair(world, Rel, TgtA);
ecs_entity_t e5 = ecs_new_w_pair(world, Rel, TgtB);
ecs_entity_t e6 = ecs_new_w_pair(world, Rel, TgtC);
ecs_add(world, e4, Tag);
ecs_add(world, e5, Tag);
ecs_add(world, e6, Tag);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ ecs_pair(Rel, EcsWildcard) }
},
.group_by = group_by_rel,
.group_by_id = Rel
});
ecs_delete(world, e3);
ecs_delete(world, e6);
ecs_iter_t it = ecs_query_iter(world, q);
ecs_query_set_group(&it, TgtC);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_group_by_w_deleted_group_id(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Rel);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ ecs_pair(Rel, EcsWildcard) }
},
.group_by = group_by_rel,
.group_by_id = Rel
});
ecs_entity_t tgt = ecs_new_id(world);
ecs_entity_t e = ecs_new_w_pair(world, Rel, tgt);
ecs_iter_t it = ecs_query_iter(world, q);
ecs_query_set_group(&it, tgt);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e, it.entities[0]);
test_bool(false, ecs_query_next(&it));
ecs_delete(world, tgt);
ecs_delete(world, e);
it = ecs_query_iter(world, q);
test_bool(false, ecs_query_next(&it));
tgt = ecs_new_id(world);
e = ecs_new_w_pair(world, Rel, tgt);
it = ecs_query_iter(world, q);
ecs_query_set_group(&it, tgt);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e, it.entities[0]);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
static int group_by_ctx;
static int on_group_create_invoked;
static int on_group_delete_invoked;
static
void* on_group_create(ecs_world_t *world, uint64_t group_id, void *group_by_arg) {
test_assert(world != NULL);
test_assert(group_id != 0);
test_assert(group_by_arg != NULL);
test_assert(group_by_arg == &group_by_ctx);
uint64_t *group_ctx = ecs_os_malloc_t(uint64_t);
*group_ctx = group_id;
on_group_create_invoked ++;
return group_ctx;
}
static
void on_group_delete(ecs_world_t *world, uint64_t group_id, void *group_ctx, void *group_by_arg) {
test_assert(world != NULL);
test_assert(group_id != 0);
test_assert(group_ctx != NULL);
test_assert(group_by_arg != NULL);
test_assert(group_by_arg == &group_by_ctx);
test_assert(*(uint64_t*)group_ctx == group_id);
ecs_os_free(group_ctx);
on_group_delete_invoked ++;
}
void Query_group_by_callbacks(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Rel);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ ecs_pair(Rel, EcsWildcard) }
},
.group_by = group_by_rel,
.group_by_id = Rel,
.on_group_create = on_group_create,
.on_group_delete = on_group_delete,
.group_by_ctx = &group_by_ctx
});
ecs_entity_t tgt_a = ecs_new_id(world);
ecs_entity_t tgt_b = ecs_new_id(world);
test_int(on_group_create_invoked, 0);
test_int(on_group_delete_invoked, 0);
ecs_entity_t e1 = ecs_new_w_pair(world, Rel, tgt_a);
ecs_run_aperiodic(world, 0);
test_int(on_group_create_invoked, 1);
test_int(on_group_delete_invoked, 0);
ecs_entity_t e2 = ecs_new_w_pair(world, Rel, tgt_a);
ecs_run_aperiodic(world, 0);
test_int(on_group_create_invoked, 1);
test_int(on_group_delete_invoked, 0);
ecs_entity_t e3 = ecs_new_w_pair(world, Rel, tgt_b);
ecs_run_aperiodic(world, 0);
test_int(on_group_create_invoked, 2);
test_int(on_group_delete_invoked, 0);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(2, it.count);
test_uint(e1, it.entities[0]);
test_uint(e2, it.entities[1]);
test_uint(tgt_a, it.group_id);
const ecs_query_group_info_t *gi = ecs_query_get_group_info(q, it.group_id);
test_assert(gi != NULL);
test_assert(gi->ctx != NULL);
test_uint(tgt_a, *(uint64_t*)gi->ctx);
test_assert(ecs_query_next(&it));
test_int(1, it.count);
test_uint(e3, it.entities[0]);
test_uint(tgt_b, it.group_id);
gi = ecs_query_get_group_info(q, it.group_id);
test_assert(gi != NULL);
test_assert(gi->ctx != NULL);
test_uint(tgt_b, *(uint64_t*)gi->ctx);
test_assert(!ecs_query_next(&it));
ecs_delete_with(world, ecs_pair(Rel, tgt_a));
ecs_run_aperiodic(world, 0);
test_int(on_group_create_invoked, 2);
test_int(on_group_delete_invoked, 1);
ecs_query_fini(q);
test_int(on_group_create_invoked, 2);
test_int(on_group_delete_invoked, 2);
ecs_fini(world);
}
void Query_group_by_default_action(void) {
ecs_world_t* world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, TgtA);
ECS_TAG(world, TgtB);
ECS_TAG(world, TgtC);
ecs_entity_t e1 = ecs_new_w_pair(world, Rel, TgtC);
ecs_entity_t e2 = ecs_new_w_pair(world, Rel, TgtB);
ecs_entity_t e3 = ecs_new_w_pair(world, Rel, TgtA);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ ecs_pair(Rel, EcsWildcard) }
},
// .group_by = group_by_rel, default action groups by relationship
.group_by_id = Rel
});
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e3, it.entities[0]);
test_uint(ecs_pair(Rel, TgtA), ecs_field_id(&it, 1));
test_uint(TgtA, it.group_id);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(ecs_pair(Rel, TgtB), ecs_field_id(&it, 1));
test_uint(TgtB, it.group_id);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(ecs_pair(Rel, TgtC), ecs_field_id(&it, 1));
test_uint(TgtC, it.group_id);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_group_table_count(void) {
ecs_world_t* world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, TgtA);
ECS_TAG(world, TgtB);
ECS_TAG(world, Foo);
ecs_new_w_pair(world, Rel, TgtA);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ ecs_pair(Rel, EcsWildcard) }
},
.group_by_id = Rel
});
ecs_run_aperiodic(world, 0);
const ecs_query_group_info_t *gi_a;
const ecs_query_group_info_t *gi_b;
gi_a = ecs_query_get_group_info(q, TgtA);
gi_b = ecs_query_get_group_info(q, TgtB);
test_assert(gi_a != NULL);
test_assert(gi_b == NULL);
test_int(gi_a->table_count, 1);
test_int(gi_a->match_count, 1);
ecs_new_w_pair(world, Rel, TgtB);
ecs_run_aperiodic(world, 0);
gi_a = ecs_query_get_group_info(q, TgtA);
gi_b = ecs_query_get_group_info(q, TgtB);
test_assert(gi_a != NULL);
test_assert(gi_b != NULL);
test_int(gi_a->table_count, 1);
test_int(gi_a->match_count, 1);
test_int(gi_b->table_count, 1);
test_int(gi_b->match_count, 1);
ecs_entity_t e3 = ecs_new_w_pair(world, Rel, TgtA);
ecs_run_aperiodic(world, 0);
gi_a = ecs_query_get_group_info(q, TgtA);
gi_b = ecs_query_get_group_info(q, TgtB);
test_assert(gi_a != NULL);
test_assert(gi_b != NULL);
test_int(gi_a->table_count, 1);
test_int(gi_a->match_count, 1);
test_int(gi_b->table_count, 1);
test_int(gi_b->match_count, 1);
ecs_add(world, e3, Foo);
ecs_run_aperiodic(world, 0);
gi_a = ecs_query_get_group_info(q, TgtA);
gi_b = ecs_query_get_group_info(q, TgtB);
test_assert(gi_a != NULL);
test_assert(gi_b != NULL);
test_int(gi_a->table_count, 2);
test_int(gi_a->match_count, 2);
test_int(gi_b->table_count, 1);
test_int(gi_b->match_count, 1);
ecs_delete_with(world, Foo);
ecs_run_aperiodic(world, 0);
gi_a = ecs_query_get_group_info(q, TgtA);
gi_b = ecs_query_get_group_info(q, TgtB);
test_assert(gi_a != NULL);
test_assert(gi_b != NULL);
test_int(gi_a->table_count, 1);
test_int(gi_a->match_count, 3);
test_int(gi_b->table_count, 1);
test_int(gi_b->match_count, 1);
ecs_delete_with(world, ecs_pair(Rel, TgtA));
ecs_run_aperiodic(world, 0);
gi_a = ecs_query_get_group_info(q, TgtA);
gi_b = ecs_query_get_group_info(q, TgtB);
test_assert(gi_a == NULL);
test_assert(gi_b != NULL);
test_int(gi_b->table_count, 1);
test_int(gi_b->match_count, 1);
ecs_delete_with(world, ecs_pair(Rel, TgtB));
ecs_run_aperiodic(world, 0);
gi_a = ecs_query_get_group_info(q, TgtA);
gi_b = ecs_query_get_group_info(q, TgtB);
test_assert(gi_a == NULL);
test_assert(gi_b == NULL);
ecs_fini(world);
}
void Query_iter_valid(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(it.flags & EcsIterIsValid, false);
test_bool(ecs_query_next(&it), true);
test_bool(it.flags & EcsIterIsValid, true);
test_bool(ecs_query_next(&it), false);
test_bool(it.flags & EcsIterIsValid, false);
ecs_fini(world);
}
void Query_query_optional_tag(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_add_id(world, e2, TagB);
ecs_query_t *q = ecs_query_new(world, "TagA, ?TagB");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
int32_t count = 0;
while (ecs_query_next(&it)) {
test_uint(ecs_field_id(&it, 1), TagA);
test_assert(ecs_field_id(&it, 2) == TagB);
test_int(it.count, 1);
if (it.entities[0] == e1) {
test_bool(ecs_field_is_set(&it, 1), true);
test_bool(ecs_field_is_set(&it, 2), false);
} else if (it.entities[0] == e2) {
test_bool(ecs_field_is_set(&it, 1), true);
test_bool(ecs_field_is_set(&it, 2), true);
}
count ++;
}
test_int(count, 2);
ecs_fini(world);
}
void Query_query_optional_shared_tag(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_add_id(world, e2, TagB);
ecs_entity_t e3 = ecs_new(world, TagA);
ecs_add_pair(world, e3, EcsIsA, e2);
ecs_query_t *q = ecs_query_new(world, "TagA, ?TagB(self|up)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
int32_t count = 0;
while (ecs_query_next(&it)) {
test_uint(ecs_field_id(&it, 1), TagA);
test_assert(ecs_field_id(&it, 2) == TagB);
test_int(it.count, 1);
if (it.entities[0] == e1) {
test_bool(ecs_field_is_set(&it, 1), true);
test_bool(ecs_field_is_set(&it, 2), false);
} else if (it.entities[0] == e2) {
test_bool(ecs_field_is_set(&it, 1), true);
test_bool(ecs_field_is_set(&it, 2), true);
} else if (it.entities[0] == e3) {
test_bool(ecs_field_is_set(&it, 1), true);
test_bool(ecs_field_is_set(&it, 2), true);
}
count ++;
}
test_int(count, 3);
ecs_fini(world);
}
void Query_query_iter_10_tags(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_TAG(world, TagC);
ECS_TAG(world, TagD);
ECS_TAG(world, TagE);
ECS_TAG(world, TagF);
ECS_TAG(world, TagG);
ECS_TAG(world, TagH);
ECS_TAG(world, TagI);
ECS_TAG(world, TagJ);
ECS_TAG(world, TagK);
ecs_entity_t e_1 = ecs_new(world, TagA);
ecs_add_id(world, e_1, TagB);
ecs_add_id(world, e_1, TagC);
ecs_add_id(world, e_1, TagD);
ecs_add_id(world, e_1, TagE);
ecs_add_id(world, e_1, TagF);
ecs_add_id(world, e_1, TagG);
ecs_add_id(world, e_1, TagH);
ecs_add_id(world, e_1, TagI);
ecs_add_id(world, e_1, TagJ);
ecs_entity_t e_2 = ecs_new(world, TagA);
ecs_add_id(world, e_2, TagB);
ecs_add_id(world, e_2, TagC);
ecs_add_id(world, e_2, TagD);
ecs_add_id(world, e_2, TagE);
ecs_add_id(world, e_2, TagF);
ecs_add_id(world, e_2, TagG);
ecs_add_id(world, e_2, TagH);
ecs_add_id(world, e_2, TagI);
ecs_add_id(world, e_2, TagJ);
ecs_add_id(world, e_2, TagK); /* 2nd match in different table */
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {
{TagA}, {TagB}, {TagC}, {TagD}, {TagE}, {TagF}, {TagG}, {TagH},
{TagI}, {TagJ}
}
});
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(it.count, 1);
test_int(it.entities[0], e_1);
test_int(ecs_field_id(&it, 1), TagA);
test_int(ecs_field_id(&it, 2), TagB);
test_int(ecs_field_id(&it, 3), TagC);
test_int(ecs_field_id(&it, 4), TagD);
test_int(ecs_field_id(&it, 5), TagE);
test_int(ecs_field_id(&it, 6), TagF);
test_int(ecs_field_id(&it, 7), TagG);
test_int(ecs_field_id(&it, 8), TagH);
test_int(ecs_field_id(&it, 9), TagI);
test_int(ecs_field_id(&it, 10), TagJ);
test_assert(ecs_query_next(&it));
test_int(it.count, 1);
test_int(it.entities[0], e_2);
test_int(ecs_field_id(&it, 1), TagA);
test_int(ecs_field_id(&it, 2), TagB);
test_int(ecs_field_id(&it, 3), TagC);
test_int(ecs_field_id(&it, 4), TagD);
test_int(ecs_field_id(&it, 5), TagE);
test_int(ecs_field_id(&it, 6), TagF);
test_int(ecs_field_id(&it, 7), TagG);
test_int(ecs_field_id(&it, 8), TagH);
test_int(ecs_field_id(&it, 9), TagI);
test_int(ecs_field_id(&it, 10), TagJ);
test_assert(!ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_query_iter_20_tags(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_TAG(world, TagC);
ECS_TAG(world, TagD);
ECS_TAG(world, TagE);
ECS_TAG(world, TagF);
ECS_TAG(world, TagG);
ECS_TAG(world, TagH);
ECS_TAG(world, TagI);
ECS_TAG(world, TagJ);
ECS_TAG(world, TagK);
ECS_TAG(world, TagL);
ECS_TAG(world, TagM);
ECS_TAG(world, TagN);
ECS_TAG(world, TagO);
ECS_TAG(world, TagP);
ECS_TAG(world, TagQ);
ECS_TAG(world, TagR);
ECS_TAG(world, TagS);
ECS_TAG(world, TagT);
ECS_TAG(world, TagU);
ecs_entity_t e_1 = ecs_new(world, TagA);
ecs_add_id(world, e_1, TagB);
ecs_add_id(world, e_1, TagC);
ecs_add_id(world, e_1, TagD);
ecs_add_id(world, e_1, TagE);
ecs_add_id(world, e_1, TagF);
ecs_add_id(world, e_1, TagG);
ecs_add_id(world, e_1, TagH);
ecs_add_id(world, e_1, TagI);
ecs_add_id(world, e_1, TagJ);
ecs_add_id(world, e_1, TagK);
ecs_add_id(world, e_1, TagL);
ecs_add_id(world, e_1, TagM);
ecs_add_id(world, e_1, TagN);
ecs_add_id(world, e_1, TagO);
ecs_add_id(world, e_1, TagP);
ecs_add_id(world, e_1, TagQ);
ecs_add_id(world, e_1, TagR);
ecs_add_id(world, e_1, TagS);
ecs_add_id(world, e_1, TagT);
ecs_entity_t e_2 = ecs_new(world, TagA);
ecs_add_id(world, e_2, TagB);
ecs_add_id(world, e_2, TagC);
ecs_add_id(world, e_2, TagD);
ecs_add_id(world, e_2, TagE);
ecs_add_id(world, e_2, TagF);
ecs_add_id(world, e_2, TagG);
ecs_add_id(world, e_2, TagH);
ecs_add_id(world, e_2, TagI);
ecs_add_id(world, e_2, TagJ);
ecs_add_id(world, e_2, TagK);
ecs_add_id(world, e_2, TagL);
ecs_add_id(world, e_2, TagM);
ecs_add_id(world, e_2, TagN);
ecs_add_id(world, e_2, TagO);
ecs_add_id(world, e_2, TagP);
ecs_add_id(world, e_2, TagQ);
ecs_add_id(world, e_2, TagR);
ecs_add_id(world, e_2, TagS);
ecs_add_id(world, e_2, TagT);
ecs_add_id(world, e_2, TagU); /* 2nd match in different table */
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter = {
.terms_buffer = (ecs_term_t[]){
{TagA}, {TagB}, {TagC}, {TagD}, {TagE}, {TagF}, {TagG}, {TagH},
{TagI}, {TagJ}, {TagK}, {TagL}, {TagM}, {TagN}, {TagO}, {TagP},
{TagQ}, {TagR}, {TagS}, {TagT}
},
.terms_buffer_count = 20
},
});
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(it.count, 1);
test_int(it.entities[0], e_1);
test_int(ecs_field_id(&it, 1), TagA);
test_int(ecs_field_id(&it, 2), TagB);
test_int(ecs_field_id(&it, 3), TagC);
test_int(ecs_field_id(&it, 4), TagD);
test_int(ecs_field_id(&it, 5), TagE);
test_int(ecs_field_id(&it, 6), TagF);
test_int(ecs_field_id(&it, 7), TagG);
test_int(ecs_field_id(&it, 8), TagH);
test_int(ecs_field_id(&it, 9), TagI);
test_int(ecs_field_id(&it, 10), TagJ);
test_int(ecs_field_id(&it, 11), TagK);
test_int(ecs_field_id(&it, 12), TagL);
test_int(ecs_field_id(&it, 13), TagM);
test_int(ecs_field_id(&it, 14), TagN);
test_int(ecs_field_id(&it, 15), TagO);
test_int(ecs_field_id(&it, 16), TagP);
test_int(ecs_field_id(&it, 17), TagQ);
test_int(ecs_field_id(&it, 18), TagR);
test_int(ecs_field_id(&it, 19), TagS);
test_int(ecs_field_id(&it, 20), TagT);
test_assert(ecs_query_next(&it));
test_int(it.count, 1);
test_int(it.entities[0], e_2);
test_int(ecs_field_id(&it, 1), TagA);
test_int(ecs_field_id(&it, 2), TagB);
test_int(ecs_field_id(&it, 3), TagC);
test_int(ecs_field_id(&it, 4), TagD);
test_int(ecs_field_id(&it, 5), TagE);
test_int(ecs_field_id(&it, 6), TagF);
test_int(ecs_field_id(&it, 7), TagG);
test_int(ecs_field_id(&it, 8), TagH);
test_int(ecs_field_id(&it, 9), TagI);
test_int(ecs_field_id(&it, 10), TagJ);
test_int(ecs_field_id(&it, 11), TagK);
test_int(ecs_field_id(&it, 12), TagL);
test_int(ecs_field_id(&it, 13), TagM);
test_int(ecs_field_id(&it, 14), TagN);
test_int(ecs_field_id(&it, 15), TagO);
test_int(ecs_field_id(&it, 16), TagP);
test_int(ecs_field_id(&it, 17), TagQ);
test_int(ecs_field_id(&it, 18), TagR);
test_int(ecs_field_id(&it, 19), TagS);
test_int(ecs_field_id(&it, 20), TagT);
test_assert(!ecs_query_next(&it));
ecs_fini(world);
}
typedef struct {
float v;
} CompA, CompB, CompC, CompD, CompE, CompF, CompG, CompH, CompI, CompJ, CompK,
CompL, CompM, CompN, CompO, CompP, CompQ, CompR, CompS, CompT, CompU;
void Query_query_iter_10_components(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, CompA);
ECS_COMPONENT(world, CompB);
ECS_COMPONENT(world, CompC);
ECS_COMPONENT(world, CompD);
ECS_COMPONENT(world, CompE);
ECS_COMPONENT(world, CompF);
ECS_COMPONENT(world, CompG);
ECS_COMPONENT(world, CompH);
ECS_COMPONENT(world, CompI);
ECS_COMPONENT(world, CompJ);
ECS_COMPONENT(world, CompK);
ecs_entity_t e_1 = ecs_set(world, 0, CompA, {10});
ecs_set(world, e_1, CompB, {10});
ecs_set(world, e_1, CompC, {10});
ecs_set(world, e_1, CompD, {10});
ecs_set(world, e_1, CompE, {10});
ecs_set(world, e_1, CompF, {10});
ecs_set(world, e_1, CompG, {10});
ecs_set(world, e_1, CompH, {10});
ecs_set(world, e_1, CompI, {10});
ecs_set(world, e_1, CompJ, {10});
ecs_entity_t e_2 = ecs_set(world, 0, CompA, {10});
ecs_set(world, e_2, CompB, {10});
ecs_set(world, e_2, CompC, {10});
ecs_set(world, e_2, CompD, {10});
ecs_set(world, e_2, CompE, {10});
ecs_set(world, e_2, CompF, {10});
ecs_set(world, e_2, CompG, {10});
ecs_set(world, e_2, CompH, {10});
ecs_set(world, e_2, CompI, {10});
ecs_set(world, e_2, CompJ, {10});
ecs_set(world, e_2, CompK, {10});
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {
{ecs_id(CompA)}, {ecs_id(CompB)}, {ecs_id(CompC)}, {ecs_id(CompD)},
{ecs_id(CompE)}, {ecs_id(CompF)}, {ecs_id(CompG)}, {ecs_id(CompH)},
{ecs_id(CompI)}, {ecs_id(CompJ)}
}
});
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(it.count, 1);
test_int(it.entities[0], e_1);
test_int(ecs_field_id(&it, 1), ecs_id(CompA));
test_int(ecs_field_id(&it, 2), ecs_id(CompB));
test_int(ecs_field_id(&it, 3), ecs_id(CompC));
test_int(ecs_field_id(&it, 4), ecs_id(CompD));
test_int(ecs_field_id(&it, 5), ecs_id(CompE));
test_int(ecs_field_id(&it, 6), ecs_id(CompF));
test_int(ecs_field_id(&it, 7), ecs_id(CompG));
test_int(ecs_field_id(&it, 8), ecs_id(CompH));
test_int(ecs_field_id(&it, 9), ecs_id(CompI));
test_int(ecs_field_id(&it, 10), ecs_id(CompJ));
int i;
for (i = 0; i < 10; i ++) {
CompA *ptr = ecs_field_w_size(&it, 0, i + 1);
test_assert(ptr != NULL);
test_int(ptr[0].v, 10);
}
test_assert(ecs_query_next(&it));
test_int(it.count, 1);
test_int(it.entities[0], e_2);
test_int(ecs_field_id(&it, 1), ecs_id(CompA));
test_int(ecs_field_id(&it, 2), ecs_id(CompB));
test_int(ecs_field_id(&it, 3), ecs_id(CompC));
test_int(ecs_field_id(&it, 4), ecs_id(CompD));
test_int(ecs_field_id(&it, 5), ecs_id(CompE));
test_int(ecs_field_id(&it, 6), ecs_id(CompF));
test_int(ecs_field_id(&it, 7), ecs_id(CompG));
test_int(ecs_field_id(&it, 8), ecs_id(CompH));
test_int(ecs_field_id(&it, 9), ecs_id(CompI));
test_int(ecs_field_id(&it, 10), ecs_id(CompJ));
for (i = 0; i < 10; i ++) {
CompA *ptr = ecs_field_w_size(&it, 0, i + 1);
test_assert(ptr != NULL);
test_int(ptr[0].v, 10);
}
test_assert(!ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_iter_20_components(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, CompA);
ECS_COMPONENT(world, CompB);
ECS_COMPONENT(world, CompC);
ECS_COMPONENT(world, CompD);
ECS_COMPONENT(world, CompE);
ECS_COMPONENT(world, CompF);
ECS_COMPONENT(world, CompG);
ECS_COMPONENT(world, CompH);
ECS_COMPONENT(world, CompI);
ECS_COMPONENT(world, CompJ);
ECS_COMPONENT(world, CompK);
ECS_COMPONENT(world, CompL);
ECS_COMPONENT(world, CompM);
ECS_COMPONENT(world, CompN);
ECS_COMPONENT(world, CompO);
ECS_COMPONENT(world, CompP);
ECS_COMPONENT(world, CompQ);
ECS_COMPONENT(world, CompR);
ECS_COMPONENT(world, CompS);
ECS_COMPONENT(world, CompT);
ECS_COMPONENT(world, CompU);
ecs_entity_t e_1 = ecs_set(world, 0, CompA, {10});
ecs_set(world, e_1, CompB, {10});
ecs_set(world, e_1, CompC, {10});
ecs_set(world, e_1, CompD, {10});
ecs_set(world, e_1, CompE, {10});
ecs_set(world, e_1, CompF, {10});
ecs_set(world, e_1, CompG, {10});
ecs_set(world, e_1, CompH, {10});
ecs_set(world, e_1, CompI, {10});
ecs_set(world, e_1, CompJ, {10});
ecs_set(world, e_1, CompK, {10});
ecs_set(world, e_1, CompL, {10});
ecs_set(world, e_1, CompM, {10});
ecs_set(world, e_1, CompN, {10});
ecs_set(world, e_1, CompO, {10});
ecs_set(world, e_1, CompP, {10});
ecs_set(world, e_1, CompQ, {10});
ecs_set(world, e_1, CompR, {10});
ecs_set(world, e_1, CompS, {10});
ecs_set(world, e_1, CompT, {10});
ecs_entity_t e_2 = ecs_set(world, 0, CompA, {10});
ecs_set(world, e_2, CompB, {10});
ecs_set(world, e_2, CompC, {10});
ecs_set(world, e_2, CompD, {10});
ecs_set(world, e_2, CompE, {10});
ecs_set(world, e_2, CompF, {10});
ecs_set(world, e_2, CompG, {10});
ecs_set(world, e_2, CompH, {10});
ecs_set(world, e_2, CompI, {10});
ecs_set(world, e_2, CompJ, {10});
ecs_set(world, e_2, CompK, {10});
ecs_set(world, e_2, CompL, {10});
ecs_set(world, e_2, CompM, {10});
ecs_set(world, e_2, CompN, {10});
ecs_set(world, e_2, CompO, {10});
ecs_set(world, e_2, CompP, {10});
ecs_set(world, e_2, CompQ, {10});
ecs_set(world, e_2, CompR, {10});
ecs_set(world, e_2, CompS, {10});
ecs_set(world, e_2, CompT, {10});
ecs_set(world, e_2, CompU, {10});
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter = {
.terms_buffer = (ecs_term_t[]){
{ecs_id(CompA)}, {ecs_id(CompB)}, {ecs_id(CompC)}, {ecs_id(CompD)},
{ecs_id(CompE)}, {ecs_id(CompF)}, {ecs_id(CompG)}, {ecs_id(CompH)},
{ecs_id(CompI)}, {ecs_id(CompJ)}, {ecs_id(CompK)}, {ecs_id(CompL)},
{ecs_id(CompM)}, {ecs_id(CompN)}, {ecs_id(CompO)}, {ecs_id(CompP)},
{ecs_id(CompQ)}, {ecs_id(CompR)}, {ecs_id(CompS)}, {ecs_id(CompT)}
},
.terms_buffer_count = 20
}
});
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(it.count, 1);
test_int(it.entities[0], e_1);
test_int(ecs_field_id(&it, 1), ecs_id(CompA));
test_int(ecs_field_id(&it, 2), ecs_id(CompB));
test_int(ecs_field_id(&it, 3), ecs_id(CompC));
test_int(ecs_field_id(&it, 4), ecs_id(CompD));
test_int(ecs_field_id(&it, 5), ecs_id(CompE));
test_int(ecs_field_id(&it, 6), ecs_id(CompF));
test_int(ecs_field_id(&it, 7), ecs_id(CompG));
test_int(ecs_field_id(&it, 8), ecs_id(CompH));
test_int(ecs_field_id(&it, 9), ecs_id(CompI));
test_int(ecs_field_id(&it, 10), ecs_id(CompJ));
test_int(ecs_field_id(&it, 11), ecs_id(CompK));
test_int(ecs_field_id(&it, 12), ecs_id(CompL));
test_int(ecs_field_id(&it, 13), ecs_id(CompM));
test_int(ecs_field_id(&it, 14), ecs_id(CompN));
test_int(ecs_field_id(&it, 15), ecs_id(CompO));
test_int(ecs_field_id(&it, 16), ecs_id(CompP));
test_int(ecs_field_id(&it, 17), ecs_id(CompQ));
test_int(ecs_field_id(&it, 18), ecs_id(CompR));
test_int(ecs_field_id(&it, 19), ecs_id(CompS));
test_int(ecs_field_id(&it, 20), ecs_id(CompT));
int i;
for (i = 0; i < 20; i ++) {
CompA *ptr = ecs_field_w_size(&it, 0, i + 1);
test_assert(ptr != NULL);
test_int(ptr[0].v, 10);
}
test_assert(ecs_query_next(&it));
test_int(it.count, 1);
test_int(it.entities[0], e_2);
test_int(ecs_field_id(&it, 1), ecs_id(CompA));
test_int(ecs_field_id(&it, 2), ecs_id(CompB));
test_int(ecs_field_id(&it, 3), ecs_id(CompC));
test_int(ecs_field_id(&it, 4), ecs_id(CompD));
test_int(ecs_field_id(&it, 5), ecs_id(CompE));
test_int(ecs_field_id(&it, 6), ecs_id(CompF));
test_int(ecs_field_id(&it, 7), ecs_id(CompG));
test_int(ecs_field_id(&it, 8), ecs_id(CompH));
test_int(ecs_field_id(&it, 9), ecs_id(CompI));
test_int(ecs_field_id(&it, 10), ecs_id(CompJ));
test_int(ecs_field_id(&it, 11), ecs_id(CompK));
test_int(ecs_field_id(&it, 12), ecs_id(CompL));
test_int(ecs_field_id(&it, 13), ecs_id(CompM));
test_int(ecs_field_id(&it, 14), ecs_id(CompN));
test_int(ecs_field_id(&it, 15), ecs_id(CompO));
test_int(ecs_field_id(&it, 16), ecs_id(CompP));
test_int(ecs_field_id(&it, 17), ecs_id(CompQ));
test_int(ecs_field_id(&it, 18), ecs_id(CompR));
test_int(ecs_field_id(&it, 19), ecs_id(CompS));
test_int(ecs_field_id(&it, 20), ecs_id(CompT));
for (i = 0; i < 20; i ++) {
CompA *ptr = ecs_field_w_size(&it, 0, i + 1);
test_assert(ptr != NULL);
test_int(ptr[0].v, 10);
}
test_assert(!ecs_query_next(&it));
ecs_fini(world);
}
void Query_iter_type_set(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t e = ecs_new(world, Position);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(it.count, 1);
test_int(it.entities[0], e);
test_assert(it.table != NULL);
const ecs_type_t *type = ecs_table_get_type(it.table);
test_int(type->count, 1);
test_int(type->array[0], ecs_id(Position));
test_assert(!ecs_query_next(&it));
ecs_fini(world);
}
void Query_filter_term(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {{ .id = ecs_id(Position), .inout = EcsInOutNone }}
});
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_assert(it.ids != NULL);
test_assert(it.ids[0] == ecs_id(Position));
test_int(it.count, 1);
test_assert(it.entities != NULL);
test_assert(it.entities[0] == e);
test_assert(it.ptrs != NULL);
test_assert(it.columns != NULL);
test_bool(ecs_query_next(&it), false);
ecs_fini(world);
}
void Query_2_terms_1_filter(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {
{ .id = ecs_id(Position), .inout = EcsInOutNone },
{ .id = ecs_id(Velocity) }
}
});
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
ecs_set(world, e, Velocity, {1, 1});
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_assert(it.ids != NULL);
test_assert(it.ids[0] == ecs_id(Position));
test_assert(it.ids[1] == ecs_id(Velocity));
test_int(it.count, 1);
test_assert(it.entities != NULL);
test_assert(it.entities[0] == e);
test_assert(it.ptrs != NULL);
test_assert(it.sizes != NULL);
test_assert(it.columns != NULL);
test_assert(it.ptrs[0] == NULL);
test_assert(it.ptrs[1] != NULL);
test_bool(ecs_query_next(&it), false);
ecs_fini(world);
}
void Query_3_terms_2_filter(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ECS_COMPONENT(world, Mass);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {
{ .id = ecs_id(Position), .inout = EcsInOutNone },
{ .id = ecs_id(Velocity), .inout = EcsInOutNone },
{ .id = ecs_id(Mass) }
}
});
ecs_entity_t e = ecs_set(world, 0, Position, {10, 20});
ecs_set(world, e, Velocity, {1, 1});
ecs_set(world, e, Mass, {1});
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_assert(it.ids != NULL);
test_assert(it.ids[0] == ecs_id(Position));
test_assert(it.ids[1] == ecs_id(Velocity));
test_assert(it.ids[2] == ecs_id(Mass));
test_int(it.count, 1);
test_assert(it.entities != NULL);
test_assert(it.entities[0] == e);
test_assert(it.ptrs != NULL);
test_assert(it.sizes != NULL);
test_assert(it.columns != NULL);
test_assert(it.ptrs[0] == NULL);
test_assert(it.ptrs[1] == NULL);
test_assert(it.ptrs[2] != NULL);
test_bool(ecs_query_next(&it), false);
ecs_fini(world);
}
void Query_no_instancing_w_singleton(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_singleton_set(world, Velocity, {1, 2});
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_entity_t e3 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t e4 = ecs_set(world, 0, Position, {40, 50});
ecs_entity_t e5 = ecs_set(world, 0, Position, {50, 60});
ecs_add(world, e4, Tag);
ecs_add(world, e5, Tag);
ecs_query_t *q = ecs_query_new(world, "Position, Velocity($)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
{
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_int(it.entities[0], e1);
test_int(p->x, 10);
test_int(p->y, 20);
test_int(v->x, 1);
test_int(v->y, 2);
}
test_assert(ecs_query_next(&it));
{
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_int(it.entities[0], e2);
test_int(p->x, 20);
test_int(p->y, 30);
test_int(v->x, 1);
test_int(v->y, 2);
}
test_assert(ecs_query_next(&it));
{
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_int(it.entities[0], e3);
test_int(p->x, 30);
test_int(p->y, 40);
test_int(v->x, 1);
test_int(v->y, 2);
}
test_assert(ecs_query_next(&it));
{
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_int(it.entities[0], e4);
test_int(p->x, 40);
test_int(p->y, 50);
test_int(v->x, 1);
test_int(v->y, 2);
}
test_assert(ecs_query_next(&it));
{
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_int(it.entities[0], e5);
test_int(p->x, 50);
test_int(p->y, 60);
test_int(v->x, 1);
test_int(v->y, 2);
}
test_assert(!ecs_query_next(&it));
ecs_fini(world);
}
void Query_no_instancing_w_shared(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_entity_t base = ecs_set(world, 0, Velocity, {1, 2});
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_entity_t e3 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t e4 = ecs_set(world, 0, Position, {40, 50});
ecs_entity_t e5 = ecs_set(world, 0, Position, {50, 60});
ecs_add(world, e4, Tag);
ecs_add(world, e5, Tag);
ecs_add_pair(world, e1, EcsIsA, base);
ecs_add_pair(world, e2, EcsIsA, base);
ecs_add_pair(world, e3, EcsIsA, base);
ecs_add_pair(world, e4, EcsIsA, base);
ecs_add_pair(world, e5, EcsIsA, base);
ecs_entity_t e6 = ecs_set(world, 0, Position, {60, 70});
ecs_entity_t e7 = ecs_set(world, 0, Position, {70, 80});
ecs_set(world, e6, Velocity, {2, 3});
ecs_set(world, e7, Velocity, {4, 5});
ecs_query_t *q = ecs_query_new(world, "Position, Velocity");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
{
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 2);
test_int(it.entities[0], e6);
test_int(p[0].x, 60);
test_int(p[0].y, 70);
test_int(v[0].x, 2);
test_int(v[0].y, 3);
test_int(it.entities[1], e7);
test_int(p[1].x, 70);
test_int(p[1].y, 80);
test_int(v[1].x, 4);
test_int(v[1].y, 5);
}
test_assert(ecs_query_next(&it));
{
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_int(it.entities[0], e1);
test_int(p->x, 10);
test_int(p->y, 20);
test_int(v->x, 1);
test_int(v->y, 2);
}
test_assert(ecs_query_next(&it));
{
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_int(it.entities[0], e2);
test_int(p->x, 20);
test_int(p->y, 30);
test_int(v->x, 1);
test_int(v->y, 2);
}
test_assert(ecs_query_next(&it));
{
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_int(it.entities[0], e3);
test_int(p->x, 30);
test_int(p->y, 40);
test_int(v->x, 1);
test_int(v->y, 2);
}
test_assert(ecs_query_next(&it));
{
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_int(it.entities[0], e4);
test_int(p->x, 40);
test_int(p->y, 50);
test_int(v->x, 1);
test_int(v->y, 2);
}
test_assert(ecs_query_next(&it));
{
Position *p = ecs_field(&it, Position, 1);
Velocity *v = ecs_field(&it, Velocity, 2);
test_int(it.count, 1);
test_int(it.entities[0], e5);
test_int(p->x, 50);
test_int(p->y, 60);
test_int(v->x, 1);
test_int(v->y, 2);
}
test_assert(!ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_iter_frame_offset(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ECS_TAG(world, TagC);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {
{ .id = TagA, }
},
});
ecs_entity_t e1 = ecs_new(world, TagA);
ecs_entity_t e2 = ecs_new(world, TagA);
ecs_entity_t e3 = ecs_new(world, TagA);
ecs_entity_t e4 = ecs_new(world, TagA);
ecs_entity_t e5 = ecs_new(world, TagA);
ecs_add(world, e3, TagB);
ecs_add(world, e4, TagB);
ecs_add(world, e5, TagC);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 2);
test_int(it.frame_offset, 0);
test_assert(it.entities != NULL);
test_assert(it.entities[0] == e1);
test_assert(it.entities[1] == e2);
test_assert(it.ids[0] == TagA);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 2);
test_int(it.frame_offset, 2);
test_assert(it.entities != NULL);
test_assert(it.entities[0] == e3);
test_assert(it.entities[1] == e4);
test_assert(it.ids[0] == TagA);
test_bool(ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.frame_offset, 4);
test_assert(it.entities != NULL);
test_assert(it.entities[0] == e5);
test_assert(it.ids[0] == TagA);
test_bool(ecs_query_next(&it), false);
ecs_fini(world);
}
void Query_add_singleton_after_query(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {
{ TagA },
{ TagB, .src.id = TagB }
}
});
test_assert(q != NULL);
ecs_entity_t e = ecs_new_id(world);
ecs_add(world, e, TagA);
ecs_singleton_add(world, TagB);
test_assert(ecs_has(world, TagB, TagB));
ecs_iter_t it = ecs_query_iter(world, q);
test_bool (ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e);
test_bool (ecs_query_next(&it), false);
ecs_singleton_remove(world, TagB);
test_assert(!ecs_has(world, TagB, TagB));
it = ecs_query_iter(world, q);
test_bool (ecs_query_next(&it), false);
ecs_fini(world);
}
void Query_query_w_component_from_parent_from_non_this(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t parent = ecs_new(world, TagB);
ecs_entity_t child = ecs_new_w_pair(world, EcsChildOf, parent);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {
{ TagA },
{ TagB, .src.id = child, .src.trav = EcsChildOf, .src.flags = EcsUp }
}
});
test_assert(q != NULL);
ecs_entity_t e = ecs_new_id(world);
ecs_add(world, e, TagA);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool (ecs_query_next(&it), true);
test_int(it.count, 1);
test_int(it.entities[0], e);
test_int(it.sources[0], 0);
test_int(it.sources[1], parent);
test_bool (ecs_query_next(&it), false);
ecs_remove_pair(world, child, EcsChildOf, parent);
it = ecs_query_iter(world, q);
test_bool (ecs_query_next(&it), false);
ecs_fini(world);
}
void Query_create_query_while_pending(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_entity_t e = ecs_new(world, TagA);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {{ TagA }}
});
test_assert(q != NULL);
ecs_add(world, e, TagB);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert( ecs_query_next(&it));
test_int(it.count, 1);
test_int(it.entities[0], e);
test_assert( !ecs_query_next(&it));
ecs_fini(world);
}
void Query_empty_query(void) {
ecs_world_t *world = ecs_mini();
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {{ 0 }}
});
test_assert(q != NULL);
ecs_query_fini(q);
ecs_fini(world);
}
void Query_implicit_existing_isa_superset(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_entity_t base = ecs_new(world, Tag);
ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base);
ecs_query_t *q = ecs_query_new(world, "Tag");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], base);
test_uint(it.sources[0], 0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
test_uint(it.sources[0], base);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_implicit_new_isa_superset(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag");
test_assert(q != NULL);
ecs_entity_t base = ecs_new(world, Tag);
ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], base);
test_uint(it.sources[0], 0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
test_uint(it.sources[0], base);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_isa_superset(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag(up)");
test_assert(q != NULL);
ecs_entity_t base = ecs_new(world, Tag);
ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
test_uint(it.sources[0], base);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_isa_superset_2_lvls(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag(up)");
test_assert(q != NULL);
ecs_entity_t base = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, base);
ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, e1);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], base);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], base);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_isa_superset_3_lvls(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag(up)");
test_assert(q != NULL);
ecs_entity_t base = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, base);
ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, e1);
ecs_entity_t e3 = ecs_new_w_pair(world, EcsIsA, e2);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], base);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], base);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.sources[0], base);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_isa_superset_2_lvls_owned(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag(up)");
test_assert(q != NULL);
ecs_entity_t base = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, base);
ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, e1);
ecs_add(world, e1, Tag);
ecs_add(world, e2, Tag);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], base);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e1);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_isa_superset_3_lvls_owned(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag(up)");
test_assert(q != NULL);
ecs_entity_t base = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, base);
ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, e1);
ecs_entity_t e3 = ecs_new_w_pair(world, EcsIsA, e2);
ecs_add(world, e1, Tag);
ecs_add(world, e2, Tag);
ecs_add(world, e3, Tag);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], base);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e1);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.sources[0], e2);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_isa_superset_owned_empty_table_after_match(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag(up)");
test_assert(q != NULL);
ecs_entity_t base = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, base);
ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, e1);
ecs_entity_t e3 = ecs_new_w_pair(world, EcsIsA, e2);
ecs_add(world, e1, Tag);
ecs_add(world, e2, Tag);
ecs_add(world, e3, Tag);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], base);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e1);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.sources[0], e2);
test_bool(false, ecs_query_next(&it));
ecs_remove_pair(world, e3, EcsIsA, e2);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], base);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e1);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_isa_self_superset(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag(self|up)");
test_assert(q != NULL);
ecs_entity_t base = ecs_new(world, Tag);
ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], base);
test_uint(it.sources[0], 0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
test_uint(it.sources[0], base);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_childof_superset(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag(up(ChildOf))");
test_assert(q != NULL);
ecs_entity_t base = ecs_new(world, Tag);
ecs_entity_t inst = ecs_new_w_pair(world, EcsChildOf, base);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
test_uint(it.sources[0], base);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_superset_2_targets(void) {
ecs_world_t *world = ecs_mini();
ECS_ENTITY(world, R, EcsTraversable);
ECS_COMPONENT(world, Position);
ecs_entity_t e_0 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e_1 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t e_2 = ecs_set(world, 0, Position, {50, 60});
ecs_entity_t e_3 = ecs_set(world, 0, Position, {70, 80});
ecs_add_pair(world, e_3, R, e_2);
ecs_add_pair(world, e_2, R, e_1);
ecs_add_pair(world, e_1, R, e_0);
ecs_entity_t t = ecs_new_id(world);
ecs_add(world, t, Position);
ecs_add_pair(world, t, R, e_2);
ecs_add_pair(world, t, R, e_1);
ecs_delete(world, t);
ecs_query_t *q = ecs_query_new(world, "Position(up(R))");
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_3);
test_uint(it.sources[0], e_2);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 50);
test_int(p[0].y, 60);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_2);
test_uint(it.sources[0], e_1);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_1);
test_uint(it.sources[0], e_0);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_superset_2_relations(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ .id = TagA, .src.trav = EcsChildOf, .src.flags = EcsUp },
{ .id = TagA, .src.trav = EcsIsA, .src.flags = EcsUp },
}
});
ecs_entity_t base = ecs_new(world, TagA);
ecs_entity_t parent = ecs_new(world, TagA);
ecs_entity_t e1 = ecs_new_id(world);
ecs_add_pair(world, e1, EcsIsA, base);
ecs_add_pair(world, e1, EcsChildOf, parent);
ecs_entity_t e2 = ecs_new_id(world);
ecs_add_pair(world, e2, EcsIsA, base);
ecs_add_pair(world, e2, EcsChildOf, parent);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(2, it.count);
test_uint(e1, it.entities[0]);
test_uint(e2, it.entities[1]);
test_uint(parent, it.sources[0]);
test_uint(base, it.sources[1]);
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_superset_2_relations_instanced(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ .id = TagA, .src.trav = EcsChildOf, .src.flags = EcsUp },
{ .id = TagA, .src.trav = EcsIsA, .src.flags = EcsUp },
},
.filter.instanced = true
});
ecs_entity_t base = ecs_new(world, TagA);
ecs_entity_t parent = ecs_new(world, TagA);
ecs_entity_t e1 = ecs_new_id(world);
ecs_add_pair(world, e1, EcsIsA, base);
ecs_add_pair(world, e1, EcsChildOf, parent);
ecs_entity_t e2 = ecs_new_id(world);
ecs_add_pair(world, e2, EcsIsA, base);
ecs_add_pair(world, e2, EcsChildOf, parent);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(2, it.count);
test_uint(e1, it.entities[0]);
test_uint(e2, it.entities[1]);
test_uint(parent, it.sources[0]);
test_uint(base, it.sources[1]);
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_superset_2_relations_w_component(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ .id = ecs_id(Position), .src.trav = EcsChildOf, .src.flags = EcsUp },
{ .id = ecs_id(Position), .src.trav = EcsIsA, .src.flags = EcsUp },
}
});
ecs_entity_t base = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t parent = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t e1 = ecs_new_id(world);
ecs_add_pair(world, e1, EcsIsA, base);
ecs_add_pair(world, e1, EcsChildOf, parent);
ecs_entity_t e2 = ecs_new_id(world);
ecs_add_pair(world, e2, EcsIsA, base);
ecs_add_pair(world, e2, EcsChildOf, parent);
ecs_iter_t it = ecs_query_iter(world, q);
{
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e1, it.entities[0]);
test_uint(parent, it.sources[0]);
test_uint(base, it.sources[1]);
Position *p1 = ecs_field(&it, Position, 1);
Position *p2 = ecs_field(&it, Position, 2);
test_assert(p1 != NULL);
test_assert(p2 != NULL);
test_int(p1->x, 30);
test_int(p1->y, 40);
test_int(p2->x, 10);
test_int(p2->y, 20);
}
{
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e2, it.entities[0]);
test_uint(parent, it.sources[0]);
test_uint(base, it.sources[1]);
Position *p1 = ecs_field(&it, Position, 1);
Position *p2 = ecs_field(&it, Position, 2);
test_assert(p1 != NULL);
test_assert(p2 != NULL);
test_int(p1->x, 30);
test_int(p1->y, 40);
test_int(p2->x, 10);
test_int(p2->y, 20);
}
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_superset_2_relations_instanced_w_component(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {
{ .id = ecs_id(Position), .src.trav = EcsChildOf, .src.flags = EcsUp },
{ .id = ecs_id(Position), .src.trav = EcsIsA, .src.flags = EcsUp },
},
.filter.instanced = true
});
ecs_entity_t base = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t parent = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t e1 = ecs_new_id(world);
ecs_add_pair(world, e1, EcsIsA, base);
ecs_add_pair(world, e1, EcsChildOf, parent);
ecs_entity_t e2 = ecs_new_id(world);
ecs_add_pair(world, e2, EcsIsA, base);
ecs_add_pair(world, e2, EcsChildOf, parent);
ecs_iter_t it = ecs_query_iter(world, q);
{
test_bool(true, ecs_query_next(&it));
test_int(2, it.count);
test_uint(e1, it.entities[0]);
test_uint(e2, it.entities[1]);
test_uint(parent, it.sources[0]);
test_uint(base, it.sources[1]);
Position *p1 = ecs_field(&it, Position, 1);
Position *p2 = ecs_field(&it, Position, 2);
test_assert(p1 != NULL);
test_assert(p2 != NULL);
test_int(p1->x, 30);
test_int(p1->y, 40);
test_int(p2->x, 10);
test_int(p2->y, 20);
}
test_bool(false, ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_parent(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query_new(world, "Tag(parent)");
test_assert(q != NULL);
ecs_entity_t base = ecs_new(world, Tag);
ecs_entity_t inst = ecs_new_w_pair(world, EcsChildOf, base);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
test_uint(it.sources[0], base);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_existing_isa_cascade(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_TAG(world, Foo);
ECS_TAG(world, Bar);
ecs_entity_t e0 = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, e0);
ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, e1);
ecs_entity_t e3 = ecs_new_w_pair(world, EcsIsA, e2);
ecs_query_t *q = ecs_query_new(world, "Tag(cascade)");
test_assert(q != NULL);
ecs_add_id(world, e1, Bar); /* mix up order */
ecs_add_id(world, e2, Foo);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.sources[0], e0);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_new_isa_cascade(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_TAG(world, Foo);
ECS_TAG(world, Bar);
ecs_query_t *q = ecs_query_new(world, "Tag(cascade)");
test_assert(q != NULL);
ecs_entity_t e0 = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new_w_pair(world, EcsIsA, e0);
ecs_entity_t e2 = ecs_new_w_pair(world, EcsIsA, e1);
ecs_entity_t e3 = ecs_new_w_pair(world, EcsIsA, e2);
ecs_add_id(world, e2, Foo); /* mix up order */
ecs_add_id(world, e1, Bar);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.sources[0], e0);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_childof_cascade(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_TAG(world, Foo);
ECS_TAG(world, Bar);
ecs_query_t *q = ecs_query_new(world, "Tag(cascade(ChildOf))");
test_assert(q != NULL);
ecs_entity_t e0 = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new_w_pair(world, EcsChildOf, e0);
ecs_entity_t e2 = ecs_new_w_pair(world, EcsChildOf, e1);
ecs_entity_t e3 = ecs_new_w_pair(world, EcsChildOf, e2);
ecs_add_id(world, e2, Foo); /* mix up order */
ecs_add_id(world, e1, Bar);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.sources[0], e0);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_parent_cascade(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_TAG(world, Foo);
ECS_TAG(world, Bar);
ecs_query_t *q = ecs_query_new(world, "Tag(parent|cascade)");
test_assert(q != NULL);
ecs_entity_t e0 = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new_w_pair(world, EcsChildOf, e0);
ecs_entity_t e2 = ecs_new_w_pair(world, EcsChildOf, e1);
ecs_entity_t e3 = ecs_new_w_pair(world, EcsChildOf, e2);
ecs_add_id(world, e2, Foo); /* mix up order */
ecs_add_id(world, e1, Bar);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.sources[0], e0);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_existing_custom_rel_cascade(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_ENTITY(world, Rel, EcsTraversable);
ECS_TAG(world, Foo);
ECS_TAG(world, Bar);
ecs_entity_t e0 = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new_w_pair(world, Rel, e0);
ecs_entity_t e2 = ecs_new_w_pair(world, Rel, e1);
ecs_entity_t e3 = ecs_new_w_pair(world, Rel, e2);
ecs_query_t *q = ecs_query_new(world, "Tag(cascade(Rel))");
test_assert(q != NULL);
ecs_add_id(world, e2, Foo); /* mix up order */
ecs_add_id(world, e1, Bar);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.sources[0], e0);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_new_custom_rel_cascade(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_ENTITY(world, Rel, EcsTraversable);
ECS_TAG(world, Foo);
ECS_TAG(world, Bar);
ecs_query_t *q = ecs_query_new(world, "Tag(cascade(Rel))");
test_assert(q != NULL);
ecs_entity_t e0 = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new_w_pair(world, Rel, e0);
ecs_entity_t e2 = ecs_new_w_pair(world, Rel, e1);
ecs_entity_t e3 = ecs_new_w_pair(world, Rel, e2);
ecs_add_id(world, e2, Foo); /* mix up order */
ecs_add_id(world, e1, Bar);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.sources[0], e0);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_cascade_w_2_depths(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_ENTITY(world, Rel, EcsTraversable);
ECS_TAG(world, Foo);
ECS_TAG(world, Bar);
ecs_query_t *q = ecs_query_new(world, "Tag(cascade(Rel))");
test_assert(q != NULL);
ecs_entity_t e0 = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new(world, Tag);
ecs_entity_t e2 = ecs_new_id(world);
ecs_entity_t e3 = ecs_new_id(world);
ecs_add_pair(world, e1, Rel, e0);
ecs_add_pair(world, e2, Rel, e1);
ecs_add_pair(world, e3, Rel, e2);
ecs_add_id(world, e2, Foo); /* mix up order */
ecs_add_id(world, e1, Bar);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e1);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.sources[0], e1);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_cascade_w_3_depths(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_ENTITY(world, Rel, EcsTraversable);
ECS_TAG(world, Foo);
ECS_TAG(world, Bar);
ecs_query_t *q = ecs_query_new(world, "Tag(cascade(Rel))");
test_assert(q != NULL);
ecs_entity_t e0 = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new(world, Tag);
ecs_entity_t e2 = ecs_new(world, Tag);
ecs_entity_t e3 = ecs_new_id(world);
ecs_add_pair(world, e1, Rel, e0);
ecs_add_pair(world, e2, Rel, e1);
ecs_add_pair(world, e3, Rel, e2);
ecs_add_id(world, e2, Foo); /* mix up order */
ecs_add_id(world, e1, Bar);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], e0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e1);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.sources[0], e2);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_cascade_w_2_depths_desc(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_ENTITY(world, Rel, EcsTraversable);
ECS_TAG(world, Foo);
ECS_TAG(world, Bar);
ecs_query_t *q = ecs_query_new(world, "Tag(cascade|desc(Rel))");
test_assert(q != NULL);
ecs_entity_t e0 = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new(world, Tag);
ecs_entity_t e2 = ecs_new_id(world);
ecs_entity_t e3 = ecs_new_id(world);
ecs_add_pair(world, e1, Rel, e0);
ecs_add_pair(world, e2, Rel, e1);
ecs_add_pair(world, e3, Rel, e2);
ecs_add_id(world, e2, Foo); /* mix up order */
ecs_add_id(world, e1, Bar);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.sources[0], e1);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e1);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], e0);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_cascade_w_3_depths_desc(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_ENTITY(world, Rel, EcsTraversable);
ECS_TAG(world, Foo);
ECS_TAG(world, Bar);
ecs_query_t *q = ecs_query_new(world, "Tag(cascade|desc(Rel))");
test_assert(q != NULL);
ecs_entity_t e0 = ecs_new(world, Tag);
ecs_entity_t e1 = ecs_new(world, Tag);
ecs_entity_t e2 = ecs_new(world, Tag);
ecs_entity_t e3 = ecs_new_id(world);
ecs_add_pair(world, e1, Rel, e0);
ecs_add_pair(world, e2, Rel, e1);
ecs_add_pair(world, e3, Rel, e2);
ecs_add_id(world, e2, Foo); /* mix up order */
ecs_add_id(world, e1, Bar);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(it.sources[0], e2);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(it.sources[0], e1);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e1);
test_uint(it.sources[0], e0);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_not_pair_relation_wildcard(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Foo);
ECS_TAG(world, RelA);
ECS_TAG(world, RelB);
ECS_TAG(world, ObjA);
ECS_TAG(world, ObjB);
ecs_query_t *q = ecs_query_new(world, "Foo, !(*, ObjA)");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new(world, Foo);
ecs_entity_t e2 = ecs_new(world, Foo);
ecs_entity_t e3 = ecs_new(world, Foo);
ecs_entity_t e4 = ecs_new(world, Foo);
ecs_add_pair(world, e1, RelA, ObjA);
ecs_add_pair(world, e2, RelA, ObjB);
ecs_add_pair(world, e3, RelB, ObjA);
ecs_add_pair(world, e4, RelB, ObjB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(ecs_field_id(&it, 2), ecs_pair(EcsWildcard, ObjA));
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e4);
test_uint(ecs_field_id(&it, 2), ecs_pair(EcsWildcard, ObjA));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_not_pair_object_wildcard(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Foo);
ECS_TAG(world, RelA);
ECS_TAG(world, RelB);
ECS_TAG(world, ObjA);
ECS_TAG(world, ObjB);
ecs_query_t *q = ecs_query_new(world, "Foo, !(RelA, *)");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new(world, Foo);
ecs_entity_t e2 = ecs_new(world, Foo);
ecs_entity_t e3 = ecs_new(world, Foo);
ecs_entity_t e4 = ecs_new(world, Foo);
ecs_add_pair(world, e1, RelA, ObjA);
ecs_add_pair(world, e2, RelA, ObjB);
ecs_add_pair(world, e3, RelB, ObjA);
ecs_add_pair(world, e4, RelB, ObjB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e3);
test_uint(ecs_field_id(&it, 2), ecs_pair(RelA, EcsWildcard));
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e4);
test_uint(ecs_field_id(&it, 2), ecs_pair(RelA, EcsWildcard));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_two_pair_wildcards_one_not(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Foo);
ECS_TAG(world, RelA);
ECS_TAG(world, RelB);
ECS_TAG(world, ObjA);
ECS_TAG(world, ObjB);
ecs_query_t *q = ecs_query_new(world, "Foo, (RelA, *), !(RelB, *)");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new(world, Foo);
ecs_entity_t e2 = ecs_new(world, Foo);
ecs_entity_t e3 = ecs_new(world, Foo);
ecs_entity_t e4 = ecs_new(world, Foo);
ecs_add_pair(world, e1, RelA, ObjA);
ecs_add_pair(world, e1, RelB, ObjA);
ecs_add_pair(world, e2, RelA, ObjA);
ecs_add_pair(world, e3, RelA, ObjB);
ecs_add_pair(world, e3, RelB, ObjB);
ecs_add_pair(world, e4, RelA, ObjB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(ecs_field_id(&it, 1), Foo);
test_uint(ecs_field_id(&it, 2), ecs_pair(RelA, ObjA));
test_uint(ecs_field_id(&it, 3), ecs_pair(RelB, EcsWildcard));
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e4);
test_uint(ecs_field_id(&it, 1), Foo);
test_uint(ecs_field_id(&it, 2), ecs_pair(RelA, ObjB));
test_uint(ecs_field_id(&it, 3), ecs_pair(RelB, EcsWildcard));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_two_pair_wildcards_one_not_any(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Foo);
ECS_TAG(world, RelA);
ECS_TAG(world, RelB);
ECS_TAG(world, ObjA);
ECS_TAG(world, ObjB);
ecs_query_t *q = ecs_query_new(world, "Foo, (RelA, *), !(RelB, _)");
test_assert(q != NULL);
ecs_entity_t e1 = ecs_new(world, Foo);
ecs_entity_t e2 = ecs_new(world, Foo);
ecs_entity_t e3 = ecs_new(world, Foo);
ecs_entity_t e4 = ecs_new(world, Foo);
ecs_add_pair(world, e1, RelA, ObjA);
ecs_add_pair(world, e1, RelB, ObjA);
ecs_add_pair(world, e2, RelA, ObjA);
ecs_add_pair(world, e3, RelA, ObjB);
ecs_add_pair(world, e3, RelB, ObjB);
ecs_add_pair(world, e4, RelA, ObjB);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
test_uint(ecs_field_id(&it, 1), Foo);
test_uint(ecs_field_id(&it, 2), ecs_pair(RelA, ObjA));
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e4);
test_uint(ecs_field_id(&it, 1), Foo);
test_uint(ecs_field_id(&it, 2), ecs_pair(RelA, ObjB));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_isa_rematch(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t base_1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t base_2 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base_1);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 2);
test_uint(it.entities[0], base_1);
test_uint(it.entities[1], base_2);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_int(p[1].x, 30);
test_int(p[1].y, 40);
test_uint(it.sources[0], 0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_uint(it.sources[0], base_1);
test_bool(false, ecs_query_next(&it));
ecs_remove_pair(world, inst, EcsIsA, base_1);
ecs_add_pair(world, inst, EcsIsA, base_2);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 2);
test_uint(it.entities[0], base_1);
test_uint(it.entities[1], base_2);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_int(p[1].x, 30);
test_int(p[1].y, 40);
test_uint(it.sources[0], 0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_uint(it.sources[0], base_2);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_childof_rematch(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t base_1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t base_2 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t inst = ecs_new_w_pair(world, EcsChildOf, base_1);
ecs_query_t *q = ecs_query_new(world, "Position(parent)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_uint(it.sources[0], base_1);
test_bool(false, ecs_query_next(&it));
ecs_add_pair(world, inst, EcsChildOf, base_2);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_uint(it.sources[0], base_2);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_isa_unmatch(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t base_1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t base_2 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base_1);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 2);
test_uint(it.entities[0], base_1);
test_uint(it.entities[1], base_2);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_int(p[1].x, 30);
test_int(p[1].y, 40);
test_uint(it.sources[0], 0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_uint(it.sources[0], base_1);
test_bool(false, ecs_query_next(&it));
ecs_remove(world, base_1, Position);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], base_2);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_uint(it.sources[0], 0);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_childof_unmatch(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t base_1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t inst = ecs_new_w_pair(world, EcsChildOf, base_1);
ecs_query_t *q = ecs_query_new(world, "Position(parent)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_uint(it.sources[0], base_1);
test_bool(false, ecs_query_next(&it));
ecs_remove(world, base_1, Position);
it = ecs_query_iter(world, q);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_isa_rematch_2_lvls(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t base_1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t base_2 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t base = ecs_new_w_pair(world, EcsIsA, base_1);
ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base);
ecs_query_t *q = ecs_query_new(world, "Position");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 2);
test_uint(it.entities[0], base_1);
test_uint(it.entities[1], base_2);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_int(p[1].x, 30);
test_int(p[1].y, 40);
test_uint(it.sources[0], 0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], base);
test_uint(it.sources[0], base_1);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
test_uint(it.sources[0], base_1);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_bool(false, ecs_query_next(&it));
ecs_remove_pair(world, base, EcsIsA, base_1);
ecs_add_pair(world, base, EcsIsA, base_2);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 2);
test_uint(it.entities[0], base_1);
test_uint(it.entities[1], base_2);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_int(p[1].x, 30);
test_int(p[1].y, 40);
test_uint(it.sources[0], 0);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
test_uint(it.sources[0], base_2);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], base);
test_uint(it.sources[0], base_2);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_childof_rematch_2_lvls(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t base_1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t base_2 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t base = ecs_new_w_pair(world, EcsChildOf, base_1);
ecs_entity_t inst = ecs_new_w_pair(world, EcsChildOf, base);
ecs_query_t *q = ecs_query_new(world, "Position(parent)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], base);
test_uint(it.sources[0], base_1);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
test_uint(it.sources[0], base_1);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_bool(false, ecs_query_next(&it));
ecs_add_pair(world, base, EcsChildOf, base_2);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
test_uint(it.sources[0], base_2);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], base);
test_uint(it.sources[0], base_2);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_cascade_rematch_2_lvls(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t e_0 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e_1 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t e_2 = ecs_set(world, 0, Position, {50, 60});
ecs_entity_t e_3 = ecs_set(world, 0, Position, {70, 80});
ecs_add_pair(world, e_3, EcsChildOf, e_2);
ecs_add_pair(world, e_2, EcsChildOf, e_1);
ecs_add_pair(world, e_1, EcsChildOf, e_0);
ecs_query_t *q = ecs_query_new(world, "Position(cascade(ChildOf))");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_1);
test_uint(it.sources[0], e_0);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_2);
test_uint(it.sources[0], e_1);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_3);
test_uint(it.sources[0], e_2);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 50);
test_int(p[0].y, 60);
test_bool(false, ecs_query_next(&it));
ecs_remove_pair(world, e_1, EcsChildOf, EcsWildcard);
ecs_remove_pair(world, e_2, EcsChildOf, EcsWildcard);
ecs_remove_pair(world, e_3, EcsChildOf, EcsWildcard);
ecs_add_pair(world, e_0, EcsChildOf, e_1);
ecs_add_pair(world, e_1, EcsChildOf, e_2);
ecs_add_pair(world, e_2, EcsChildOf, e_3);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_2);
test_uint(it.sources[0], e_3);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 70);
test_int(p[0].y, 80);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_1);
test_uint(it.sources[0], e_2);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 50);
test_int(p[0].y, 60);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_0);
test_uint(it.sources[0], e_1);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_cascade_rematch_2_lvls_2_relations(void) {
ecs_world_t *world = ecs_mini();
ECS_ENTITY(world, R, EcsTraversable);
ECS_COMPONENT(world, Position);
ecs_entity_t e_0 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e_1 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t e_2 = ecs_set(world, 0, Position, {50, 60});
ecs_entity_t e_3 = ecs_set(world, 0, Position, {70, 80});
ecs_add_pair(world, e_3, R, e_2);
ecs_add_pair(world, e_2, R, e_1);
ecs_add_pair(world, e_1, R, e_0);
ecs_entity_t t = ecs_new_id(world);
ecs_add(world, t, Position);
ecs_add_pair(world, t, R, e_2);
ecs_add_pair(world, t, R, e_1);
ecs_delete(world, t);
ecs_query_t *q = ecs_query_new(world, "Position(cascade(R))");
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_1);
test_uint(it.sources[0], e_0);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_2);
test_uint(it.sources[0], e_1);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_3);
test_uint(it.sources[0], e_2);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 50);
test_int(p[0].y, 60);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_cascade_topological(void) {
ecs_world_t *world = ecs_init();
ECS_ENTITY(world, R, Traversable);
ECS_TAG(world, Tag);
ecs_entity_t e1 = ecs_new(world, Tag);
ecs_entity_t e2 = ecs_new(world, Tag);
ecs_entity_t e3 = ecs_new(world, Tag);
ecs_entity_t e4 = ecs_new(world, Tag);
ecs_entity_t e5 = ecs_new(world, Tag);
ecs_entity_t e6 = ecs_new(world, Tag);
ecs_add_pair(world, e3, R, e1);
ecs_add_pair(world, e3, R, e2);
ecs_add_pair(world, e3, R, e4);
ecs_add_pair(world, e1, R, e5);
ecs_add_pair(world, e2, R, e6);
ecs_add_pair(world, e4, R, e1);
ecs_add_pair(world, e4, R, e2);
ecs_query_t *q = ecs_query_new(world, "Tag, ?Tag(cascade(R))");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(2, it.count);
test_uint(it.entities[0], e5);
test_uint(it.entities[1], e6);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(it.entities[0], e1);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(it.entities[0], e2);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(it.entities[0], e4);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(it.entities[0], e3);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_cascade_desc_rematch_2_lvls(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t e_0 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e_1 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t e_2 = ecs_set(world, 0, Position, {50, 60});
ecs_entity_t e_3 = ecs_set(world, 0, Position, {70, 80});
ecs_add_pair(world, e_3, EcsChildOf, e_2);
ecs_add_pair(world, e_2, EcsChildOf, e_1);
ecs_add_pair(world, e_1, EcsChildOf, e_0);
ecs_query_t *q = ecs_query_new(world, "Position(cascade|desc(ChildOf))");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_3);
test_uint(it.sources[0], e_2);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 50);
test_int(p[0].y, 60);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_2);
test_uint(it.sources[0], e_1);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_1);
test_uint(it.sources[0], e_0);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_bool(false, ecs_query_next(&it));
ecs_remove_pair(world, e_1, EcsChildOf, EcsWildcard);
ecs_remove_pair(world, e_2, EcsChildOf, EcsWildcard);
ecs_remove_pair(world, e_3, EcsChildOf, EcsWildcard);
ecs_add_pair(world, e_0, EcsChildOf, e_1);
ecs_add_pair(world, e_1, EcsChildOf, e_2);
ecs_add_pair(world, e_2, EcsChildOf, e_3);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_0);
test_uint(it.sources[0], e_1);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_1);
test_uint(it.sources[0], e_2);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 50);
test_int(p[0].y, 60);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_2);
test_uint(it.sources[0], e_3);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 70);
test_int(p[0].y, 80);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_cascade_desc_rematch_2_lvls_2_relations(void) {
ecs_world_t *world = ecs_mini();
ECS_ENTITY(world, R, EcsTraversable);
ECS_COMPONENT(world, Position);
ecs_entity_t e_0 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e_1 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t e_2 = ecs_set(world, 0, Position, {50, 60});
ecs_entity_t e_3 = ecs_set(world, 0, Position, {70, 80});
ecs_add_pair(world, e_3, R, e_2);
ecs_add_pair(world, e_2, R, e_1);
ecs_add_pair(world, e_1, R, e_0);
ecs_entity_t t = ecs_new_id(world);
ecs_add(world, t, Position);
ecs_add_pair(world, t, R, e_2);
ecs_add_pair(world, t, R, e_1);
ecs_delete(world, t);
ecs_query_t *q = ecs_query_new(world, "Position(cascade|desc(R))");
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_3);
test_uint(it.sources[0], e_2);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 50);
test_int(p[0].y, 60);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_2);
test_uint(it.sources[0], e_1);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e_1);
test_uint(it.sources[0], e_0);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_cascade_desc_topological(void) {
ecs_world_t *world = ecs_init();
ECS_ENTITY(world, R, Traversable);
ECS_TAG(world, Tag);
ecs_entity_t e1 = ecs_new(world, Tag);
ecs_entity_t e2 = ecs_new(world, Tag);
ecs_entity_t e3 = ecs_new(world, Tag);
ecs_entity_t e4 = ecs_new(world, Tag);
ecs_entity_t e5 = ecs_new(world, Tag);
ecs_entity_t e6 = ecs_new(world, Tag);
ecs_add_pair(world, e3, R, e1);
ecs_add_pair(world, e3, R, e2);
ecs_add_pair(world, e3, R, e4);
ecs_add_pair(world, e1, R, e5);
ecs_add_pair(world, e2, R, e6);
ecs_add_pair(world, e4, R, e1);
ecs_add_pair(world, e4, R, e2);
ecs_query_t *q = ecs_query_new(world, "Tag, ?Tag(cascade|desc(R))");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(it.entities[0], e3);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(it.entities[0], e4);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(it.entities[0], e1);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(it.entities[0], e2);
test_bool(true, ecs_query_next(&it));
test_int(2, it.count);
test_uint(it.entities[0], e5);
test_uint(it.entities[1], e6);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_childof_rematch_from_isa(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ecs_entity_t base_1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t base_2 = ecs_set(world, 0, Position, {30, 40});
ecs_entity_t base = ecs_new_w_pair(world, EcsIsA, base_1);
ecs_entity_t inst = ecs_new_w_pair(world, EcsChildOf, base);
ecs_query_t *q = ecs_query_new(world, "Position(parent)");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
test_uint(it.sources[0], base_1);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_bool(false, ecs_query_next(&it));
ecs_remove_pair(world, base, EcsIsA, base_1);
ecs_add_pair(world, base, EcsIsA, base_2);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
test_uint(it.sources[0], base_2);
p = ecs_field(&it, Position, 1);
test_int(p[0].x, 30);
test_int(p[0].y, 40);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_rematch_optional_ref(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_COMPONENT(world, Position);
ecs_query_t *q = ecs_query_new(world, "Tag, ?Position(parent)");
test_assert(q != NULL);
ecs_entity_t parent = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t child = ecs_new(world, Tag);
ecs_add_pair(world, child, EcsChildOf, parent);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
test_uint(Tag, ecs_field_id(&it, 1));
test_uint(ecs_id(Position), ecs_field_id(&it, 2));
test_bool(true, ecs_field_is_set(&it, 1));
test_bool(true, ecs_field_is_set(&it, 2));
test_uint(0, it.sources[0]);
test_uint(parent, it.sources[1]);
Position *p = ecs_field(&it, Position, 2);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
test_bool(false, ecs_query_next(&it));
ecs_remove(world, parent, Position);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
test_uint(Tag, ecs_field_id(&it, 1));
test_uint(ecs_id(Position), ecs_field_id(&it, 2));
test_bool(true, ecs_field_is_set(&it, 1));
test_bool(false, ecs_field_is_set(&it, 2));
test_uint(0, it.sources[0]);
test_uint(0, it.sources[1]);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_rematch_optional_ref_w_2_refs(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Tag);
ECS_COMPONENT(world, Position);
ECS_COMPONENT(world, Velocity);
ecs_query_t *q = ecs_query_new(world, "Tag, Velocity(parent), ?Position(parent)");
test_assert(q != NULL);
ecs_entity_t parent = ecs_set(world, 0, Position, {10, 20});
ecs_set(world, parent, Velocity, {1, 2});
ecs_entity_t child = ecs_new(world, Tag);
ecs_add_pair(world, child, EcsChildOf, parent);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
test_uint(Tag, ecs_field_id(&it, 1));
test_uint(ecs_id(Velocity), ecs_field_id(&it, 2));
test_uint(ecs_id(Position), ecs_field_id(&it, 3));
test_bool(true, ecs_field_is_set(&it, 1));
test_bool(true, ecs_field_is_set(&it, 2));
test_bool(true, ecs_field_is_set(&it, 3));
test_uint(0, it.sources[0]);
test_uint(parent, it.sources[1]);
Velocity *v = ecs_field(&it, Velocity, 2);
test_assert(v != NULL);
test_int(v->x, 1);
test_int(v->y, 2);
Position *p = ecs_field(&it, Position, 3);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
test_bool(false, ecs_query_next(&it));
ecs_remove(world, parent, Position);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
test_uint(Tag, ecs_field_id(&it, 1));
test_uint(ecs_id(Velocity), ecs_field_id(&it, 2));
test_uint(ecs_id(Position), ecs_field_id(&it, 3));
test_bool(true, ecs_field_is_set(&it, 1));
test_bool(true, ecs_field_is_set(&it, 2));
test_bool(false, ecs_field_is_set(&it, 3));
test_uint(0, it.sources[0]);
test_uint(parent, it.sources[1]);
test_uint(0, it.sources[2]);
v = ecs_field(&it, Velocity, 2);
test_assert(v != NULL);
test_int(v->x, 1);
test_int(v->y, 2);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_rematch_optional_ref_tag_w_ref_component(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_query_t *q = ecs_query_new(world, "TagA, ?Position(parent), TagB(parent)");
test_assert(q != NULL);
ecs_entity_t parent = ecs_set(world, 0, Position, {10, 20});
ecs_add(world, parent, TagB);
ecs_entity_t child = ecs_new(world, TagA);
ecs_add_pair(world, child, EcsChildOf, parent);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_uint(ecs_id(Position), ecs_field_id(&it, 2));
test_bool(true, ecs_field_is_set(&it, 1));
test_bool(true, ecs_field_is_set(&it, 2));
test_bool(true, ecs_field_is_set(&it, 3));
test_uint(0, it.sources[0]);
test_uint(parent, it.sources[1]);
test_uint(parent, it.sources[2]);
Position *p = ecs_field(&it, Position, 2);
test_assert(p != NULL);
test_int(p->x, 10);
test_int(p->y, 20);
test_bool(false, ecs_query_next(&it));
ecs_remove(world, parent, Position);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(child, it.entities[0]);
test_uint(TagA, ecs_field_id(&it, 1));
test_uint(ecs_id(Position), ecs_field_id(&it, 2));
test_bool(true, ecs_field_is_set(&it, 1));
test_bool(false, ecs_field_is_set(&it, 2));
test_bool(true, ecs_field_is_set(&it, 3));
test_uint(0, it.sources[0]);
test_uint(0, it.sources[1]);
test_uint(parent, it.sources[2]);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_match_query_expr_from_scope(void) {
ecs_world_t *world = ecs_mini();
ecs_entity_t foo = ecs_entity_init(world, &(ecs_entity_desc_t){
.name = "Foo"
});
ecs_entity_t bar = ecs_entity_init(world, &(ecs_entity_desc_t){
.name = "Foo.Bar"
});
ecs_set_scope(world, foo);
ecs_query_t *q = ecs_query_new(world, "Bar");
test_assert(q != NULL);
ecs_set_scope(world, 0);
ecs_entity_t e = ecs_new_w_id(world, bar);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(e, it.entities[0]);
test_uint(bar, ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_long_or_w_ref(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_TAG(world, A);
ECS_TAG(world, B);
ECS_TAG(world, C);
ECS_TAG(world, D);
ECS_TAG(world, E);
ECS_TAG(world, F);
ECS_TAG(world, G);
ECS_TAG(world, H);
ECS_TAG(world, I);
ECS_TAG(world, J);
ECS_TAG(world, K);
ECS_TAG(world, L);
ECS_TAG(world, M);
ECS_TAG(world, N);
ECS_TAG(world, O);
ECS_TAG(world, P);
ECS_TAG(world, Q);
ECS_TAG(world, R);
ecs_entity_t e = ecs_new_entity(world, "e");
ecs_set(world, e, Position, {10, 20});
ecs_entity_t e2 = ecs_new(world, A);
ecs_query_t *q = ecs_query_new(world,
"Position(e), A || B || C || D || E || F || G || H || I || J || K || L ||"
"M || N || O || P || Q || R");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_uint(ecs_id(Position), ecs_field_id(&it, 1));
test_uint(A, ecs_field_id(&it, 2));
test_uint(e2, it.entities[0]);
test_uint(e, it.sources[0]);
test_uint(0, it.sources[1]);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_0_query(void) {
ecs_world_t *world = ecs_mini();
ecs_query_t *q = ecs_query_new(world, "0");
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_pair_id_and_subj(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Rel);
ECS_TAG(world, Obj);
ECS_TAG(world, Subj);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {{
.id = ecs_pair(Rel, Obj), .src.id = Subj
}}
});
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(false, ecs_query_next(&it));
ecs_add_pair(world, Subj, Rel, Obj);
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 0);
test_uint(it.sources[0], Subj);
test_uint(it.ids[0], ecs_pair(Rel, Obj));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_table_count(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {{
.id = TagA
}}
});
test_assert(q != NULL);
test_int(0, ecs_query_table_count(q));
ecs_new(world, TagA);
test_int(1, ecs_query_table_count(q));
ecs_entity_t e = ecs_new(world, TagA);
test_int(1, ecs_query_table_count(q));
ecs_add(world, e, TagB);
test_int(2, ecs_query_table_count(q));
ecs_delete_with(world, TagB);
test_int(1, ecs_query_table_count(q));
ecs_delete_with(world, TagA);
test_int(0, ecs_query_table_count(q));
ecs_fini(world);
}
void Query_empty_table_count(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {{
.id = TagA
}}
});
test_assert(q != NULL);
test_int(0, ecs_query_empty_table_count(q));
ecs_entity_t e = ecs_new(world, TagA);
test_int(0, ecs_query_empty_table_count(q));
ecs_delete(world, e);
test_int(1, ecs_query_empty_table_count(q));
ecs_fini(world);
}
void Query_entity_count(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, TagA);
ECS_TAG(world, TagB);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {{
.id = TagA
}}
});
test_assert(q != NULL);
test_int(0, ecs_query_entity_count(q));
ecs_entity_t e1 = ecs_new(world, TagA);
test_int(1, ecs_query_entity_count(q));
ecs_entity_t e2 = ecs_new(world, TagA);
test_int(2, ecs_query_entity_count(q));
ecs_add(world, e2, TagB);
test_int(2, ecs_query_entity_count(q));
ecs_delete(world, e1);
test_int(1, ecs_query_entity_count(q));
ecs_delete(world, e2);
test_int(0, ecs_query_entity_count(q));
ecs_fini(world);
}
void Query_rematch_after_delete_inherited_tag(void) {
ecs_world_t *world = ecs_mini();
ecs_entity_t tag = ecs_new_id(world);
ecs_entity_t base = ecs_new_w_id(world, tag);
ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {
{ .id = tag }
}
});
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(base, it.entities[0]);
test_uint(tag, ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(inst, it.entities[0]);
test_uint(tag, ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_delete_with(world, tag);
it = ecs_query_iter(world, q);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_rematch_after_delete_rel_of_inherited_pair(void) {
ecs_world_t *world = ecs_mini();
ecs_entity_t rel = ecs_new_id(world);
ecs_entity_t obj = ecs_new_id(world);
ecs_entity_t base = ecs_new_w_pair(world, rel, obj);
ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {
{ .id = ecs_pair(rel, obj) }
}
});
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(base, it.entities[0]);
test_uint(ecs_pair(rel, obj), ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(inst, it.entities[0]);
test_uint(ecs_pair(rel, obj), ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_delete_with(world, ecs_pair(rel, EcsWildcard));
it = ecs_query_iter(world, q);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_rematch_after_delete_obj_of_inherited_pair(void) {
ecs_world_t *world = ecs_mini();
ecs_entity_t rel = ecs_new_id(world);
ecs_entity_t obj = ecs_new_id(world);
ecs_entity_t base = ecs_new_w_pair(world, rel, obj);
ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {
{ .id = ecs_pair(rel, obj) }
}
});
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(base, it.entities[0]);
test_uint(ecs_pair(rel, obj), ecs_field_id(&it, 1));
test_bool(true, ecs_query_next(&it));
test_int(1, it.count);
test_uint(inst, it.entities[0]);
test_uint(ecs_pair(rel, obj), ecs_field_id(&it, 1));
test_bool(false, ecs_query_next(&it));
ecs_delete_with(world, ecs_pair(EcsWildcard, obj));
it = ecs_query_iter(world, q);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_rematch_empty_table_w_superset(void) {
ecs_world_t *world = ecs_init();
ECS_TAG(world, Foo);
ECS_TAG(world, Bar);
ecs_query_t *q = ecs_query_init(world, &(ecs_query_desc_t){
.filter.terms = {{ Foo }, { Bar, .oper = EcsNot }}
});
ecs_entity_t base = ecs_new_w_id(world, EcsPrefab);
ecs_add(world, base, Foo);
test_assert( ecs_is_alive(world, base));
ecs_delete_with(world, Foo);
test_assert( !ecs_is_alive(world, base));
base = ecs_new_w_id(world, EcsPrefab);
ecs_add(world, base, Foo);
ecs_entity_t inst = ecs_new_w_pair(world, EcsIsA, base);
ecs_add(world, inst, Bar);
ecs_run_aperiodic(world, 0); // force table (IsA, base) to empty list
ecs_remove(world, inst, Bar);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], inst);
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_short_notation(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Foo);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = Foo
}}
});
test_assert(q != NULL);
ecs_entity_t e = ecs_new(world, Foo);
ecs_iter_t it = ecs_query_iter(world, q);
test_assert(ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e);
test_uint(it.ids[0], ecs_field_id(&it, 1));
test_assert(!ecs_query_next(&it));
ecs_query_fini(q);
ecs_fini(world);
}
void Query_query_w_invalid_filter_flag(void) {
install_test_abort();
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
test_expect_abort();
ecs_query(world, {
.filter.terms = {
{ .id = ecs_id(Position), .src.flags = EcsFilter }
}
});
}
void Query_query_next_table(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position)
}}
});
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_add(world, e2, Tag);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e1));
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e2));
test_bool(false, ecs_query_next_table(&it));
ecs_fini(world);
}
void Query_query_next_table_w_populate(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position)
}}
});
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_add(world, e2, Tag);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e1));
ecs_query_populate(&it, false);
test_int(1, it.count);
test_assert(it.table == ecs_get_table(world, e1));
test_uint(it.entities[0], e1);
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e2));
ecs_query_populate(&it, false);
test_int(1, it.count);
test_assert(it.table == ecs_get_table(world, e2));
test_uint(it.entities[0], e2);
test_bool(false, ecs_query_next_table(&it));
ecs_fini(world);
}
void Query_query_next_table_w_changed(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position)
}}
});
ecs_query_t *qr = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position),
.inout = EcsIn
}}
});
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_add(world, e2, Tag);
test_bool(true, ecs_query_changed(qr, NULL));
ecs_iter_t it = ecs_query_iter(world, qr);
while (ecs_query_next_table(&it)) { }
test_bool(false, ecs_query_changed(qr, NULL));
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e1));
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e2));
test_bool(false, ecs_query_next_table(&it));
test_bool(false, ecs_query_changed(qr, NULL));
it = ecs_query_iter(world, qr);
test_bool(true, ecs_query_next_table(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_bool(true, ecs_query_next_table(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_bool(false, ecs_query_next_table(&it));
ecs_fini(world);
}
void Query_query_next_table_w_skip(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position)
}}
});
ecs_query_t *qr = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position),
.inout = EcsIn
}}
});
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_add(world, e2, Tag);
test_bool(true, ecs_query_changed(qr, NULL));
ecs_iter_t it = ecs_query_iter(world, qr);
while (ecs_query_next(&it)) { }
test_bool(false, ecs_query_changed(qr, NULL));
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e1));
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e2));
ecs_query_skip(&it);
test_bool(false, ecs_query_next_table(&it));
test_bool(false, ecs_query_changed(qr, NULL));
it = ecs_query_iter(world, qr);
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_bool(true, ecs_query_next(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_next_table_w_populate_first_changed(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position)
}}
});
ecs_query_t *qr = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position),
.inout = EcsIn
}}
});
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_add(world, e2, Tag);
test_bool(true, ecs_query_changed(qr, NULL));
ecs_iter_t it = ecs_query_iter(world, qr);
while (ecs_query_next(&it)) { }
test_bool(false, ecs_query_changed(qr, NULL));
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e1));
ecs_query_populate(&it, false);
test_int(1, it.count);
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e2));
test_bool(false, ecs_query_next_table(&it));
test_bool(true, ecs_query_changed(qr, NULL));
it = ecs_query_iter(world, qr);
test_bool(true, ecs_query_next_table(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_bool(true, ecs_query_next_table(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_bool(false, ecs_query_next_table(&it));
ecs_fini(world);
}
void Query_query_next_table_w_populate_last_changed(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position)
}}
});
ecs_query_t *qr = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position),
.inout = EcsIn
}}
});
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_add(world, e2, Tag);
test_bool(true, ecs_query_changed(qr, NULL));
ecs_iter_t it = ecs_query_iter(world, qr);
while (ecs_query_next(&it)) { }
test_bool(false, ecs_query_changed(qr, NULL));
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e1));
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e2));
ecs_query_populate(&it, false);
test_int(1, it.count);
test_bool(false, ecs_query_next_table(&it));
test_bool(true, ecs_query_changed(qr, NULL));
it = ecs_query_iter(world, qr);
test_bool(true, ecs_query_next_table(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_bool(true, ecs_query_next_table(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_bool(false, ecs_query_next_table(&it));
ecs_fini(world);
}
void Query_query_next_table_w_populate_skip_first(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position)
}}
});
ecs_query_t *qr = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position),
.inout = EcsIn
}}
});
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_add(world, e2, Tag);
test_bool(true, ecs_query_changed(qr, NULL));
ecs_iter_t it = ecs_query_iter(world, qr);
while (ecs_query_next(&it)) { }
test_bool(false, ecs_query_changed(qr, NULL));
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e1));
ecs_query_populate(&it, false);
ecs_query_skip(&it);
test_int(1, it.count);
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e2));
ecs_query_populate(&it, false);
test_int(1, it.count);
test_bool(false, ecs_query_next_table(&it));
test_bool(true, ecs_query_changed(qr, NULL));
it = ecs_query_iter(world, qr);
test_bool(true, ecs_query_next_table(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_bool(true, ecs_query_next_table(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_bool(false, ecs_query_next_table(&it));
ecs_fini(world);
}
void Query_query_next_table_w_populate_skip_last(void) {
ecs_world_t *world = ecs_mini();
ECS_COMPONENT(world, Position);
ECS_TAG(world, Tag);
ecs_query_t *q = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position)
}}
});
ecs_query_t *qr = ecs_query(world, {
.filter.terms = {{
.id = ecs_id(Position),
.inout = EcsIn
}}
});
ecs_entity_t e1 = ecs_set(world, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(world, 0, Position, {20, 30});
ecs_add(world, e2, Tag);
test_bool(true, ecs_query_changed(qr, NULL));
ecs_iter_t it = ecs_query_iter(world, qr);
while (ecs_query_next(&it)) { }
test_bool(false, ecs_query_changed(qr, NULL));
it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e1));
ecs_query_populate(&it, false);
test_int(1, it.count);
test_bool(true, ecs_query_next_table(&it));
test_int(0, it.count);
test_assert(it.table == ecs_get_table(world, e2));
ecs_query_populate(&it, false);
test_int(1, it.count);
ecs_query_skip(&it);
test_bool(false, ecs_query_next_table(&it));
test_bool(true, ecs_query_changed(qr, NULL));
it = ecs_query_iter(world, qr);
test_bool(true, ecs_query_next_table(&it));
test_bool(true, ecs_query_changed(NULL, &it));
test_bool(true, ecs_query_next_table(&it));
test_bool(false, ecs_query_changed(NULL, &it));
test_bool(false, ecs_query_next_table(&it));
ecs_fini(world);
}
void Query_create_query_existing_query_entity(void) {
ecs_world_t *world = ecs_mini();
ECS_TAG(world, Foo);
ECS_TAG(world, Bar);
ecs_query_t *q_1 = ecs_query_init(world, &(ecs_query_desc_t){
.filter.entity = ecs_entity(world, { .name = "q" }),
.filter.terms = {
{ .id = Foo },
{ .id = Bar }
},
});
test_assert(q_1 != NULL);
ecs_query_t *q_2 = ecs_query_init(world, &(ecs_query_desc_t){
.filter.entity = ecs_entity(world, { .name = "q" }),
.filter.terms = {
{ .id = Foo },
{ .id = Bar }
},
});
test_assert(q_2 != NULL);
ecs_fini(world);
}
void Query_query_for_recycled_pair(void) {
ecs_world_t *world = ecs_init();
ecs_entity_t rel = ecs_new_entity(world, "Rel");
ecs_entity_t tgt = ecs_new_entity(world, "Tgt");
ecs_delete(world, rel);
ecs_delete(world, tgt);
rel = ecs_new_entity(world, "Rel");
tgt = ecs_new_entity(world, "Tgt");
ecs_entity_t e = ecs_new_w_pair(world, rel, tgt);
ecs_query_t *q = ecs_query(world, {
.filter.terms[0] = {
.first.id = rel,
.second.id = tgt
}
});
test_assert(q != NULL);
ecs_iter_t it = ecs_query_iter(world, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e);
test_uint(ecs_field_id(&it, 1), ecs_pair(rel, tgt));
test_bool(false, ecs_query_next(&it));
ecs_fini(world);
}
void Query_query_w_singleton_w_rule_iter(void) {
ecs_world_t* ecs = ecs_init();
ECS_TAG(ecs, Tag);
ECS_TAG(ecs, Singleton);
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{Singleton, .src.id = Singleton}, {Tag}
}
});
ecs_rule_t *r = ecs_rule(ecs, {
.terms = {{Tag}}
});
ecs_singleton_add(ecs, Singleton);
ecs_entity_t e = ecs_new(ecs, Tag);
ecs_iter_t qit = ecs_query_iter(ecs, q);
test_bool(true, ecs_query_next(&qit));
test_int(1, qit.count);
test_uint(e, qit.entities[0]);
ecs_id_t id = qit.ids[0];
ecs_iter_t rit = ecs_rule_iter(ecs, r);
test_bool(true, ecs_rule_next(&rit));
test_int(1, rit.count);
test_uint(e, rit.entities[0]);
test_bool(false, ecs_rule_next(&rit));
test_assert(id == qit.ids[0]);
test_bool(false, ecs_query_next(&qit));
ecs_rule_fini(r);
ecs_fini(ecs);
}
void Query_query_w_singleton_nested_iter(void) {
ecs_world_t* ecs = ecs_init();
ECS_TAG(ecs, TagA);
ECS_TAG(ecs, TagB);
ECS_TAG(ecs, Singleton);
ecs_query_t *qa = ecs_query(ecs, {
.filter.terms = {
{TagA}, {Singleton, .src.id = Singleton}
}
});
ecs_query_t *qb = ecs_query(ecs, {
.filter.terms = {
{TagB}, {Singleton, .src.id = Singleton}
}
});
ecs_singleton_add(ecs, Singleton);
ecs_entity_t ea = ecs_new(ecs, TagA);
ecs_entity_t eb = ecs_new(ecs, TagB);
ecs_iter_t qita = ecs_query_iter(ecs, qa);
ecs_iter_t qitb = ecs_query_iter(ecs, qb);
test_bool(ecs_query_next(&qita), true);
test_int(1, qita.count);
test_uint(ea, qita.entities[0]);
test_bool(ecs_query_next(&qitb), true);
test_int(1, qitb.count);
test_uint(eb, qitb.entities[0]);
test_uint(TagA, qita.ids[0]);
test_uint(TagB, qitb.ids[0]);
test_bool(ecs_query_next(&qita), false);
test_bool(ecs_query_next(&qitb), false);
ecs_fini(ecs);
}
void Query_query_w_singleton_interleaved_iter(void) {
ecs_world_t* ecs = ecs_init();
ECS_TAG(ecs, TagA);
ECS_TAG(ecs, TagB);
ECS_TAG(ecs, TagC);
ECS_TAG(ecs, Singleton);
ecs_query_t *qa = ecs_query(ecs, {
.filter.terms = {
{TagA}, {Singleton, .src.id = Singleton}
}
});
ecs_query_t *qb = ecs_query(ecs, {
.filter.terms = {
{TagB}, {Singleton, .src.id = Singleton}
}
});
ecs_query_t *qc = ecs_query(ecs, {
.filter.terms = {
{TagC}, {Singleton, .src.id = Singleton}
}
});
ecs_singleton_add(ecs, Singleton);
ecs_entity_t ea = ecs_new(ecs, TagA);
ecs_entity_t eb = ecs_new(ecs, TagB);
ecs_entity_t ec = ecs_new(ecs, TagC);
ecs_iter_t qita = ecs_query_iter(ecs, qa);
ecs_iter_t qitb = ecs_query_iter(ecs, qb);
test_bool(ecs_query_next(&qita), true);
test_int(1, qita.count);
test_uint(ea, qita.entities[0]);
test_bool(ecs_query_next(&qitb), true);
test_int(1, qitb.count);
test_uint(eb, qitb.entities[0]);
test_uint(TagA, qita.ids[0]);
test_uint(TagB, qitb.ids[0]);
test_bool(ecs_query_next(&qita), false);
ecs_iter_t qitc = ecs_query_iter(ecs, qc);
test_bool(ecs_query_next(&qitc), true);
test_int(1, qitc.count);
test_uint(ec, qitc.entities[0]);
test_uint(TagB, qitb.ids[0]);
test_uint(TagC, qitc.ids[0]);
test_bool(ecs_query_next(&qitb), false);
test_bool(ecs_query_next(&qitc), false);
ecs_fini(ecs);
}
void Query_recycled_component_id(void) {
ecs_world_t* ecs = ecs_init();
for (int i = 0; i < FLECS_HI_COMPONENT_ID; i ++) {
ecs_new_low_id(ecs);
}
ecs_entity_t e = ecs_new_id(ecs);
ecs_delete(ecs, e);
ECS_COMPONENT(ecs, Position);
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Position) }
}
});
test_assert(q != NULL);
ecs_entity_t e1 = ecs_set(ecs, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(ecs, 0, Position, {20, 30});
ecs_iter_t it = ecs_query_iter(ecs, q);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 2);
test_uint(it.entities[0], e1);
test_uint(it.entities[1], e2);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 10);
test_int(p[0].y, 20);
test_int(p[1].x, 20);
test_int(p[1].y, 30);
test_bool(false, ecs_query_next(&it));
ecs_fini(ecs);
}
void Query_set_get_context(void) {
ecs_world_t* ecs = ecs_init();
ECS_COMPONENT(ecs, Position);
int ctx = 0;
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Position) }
},
.ctx = &ctx
});
test_assert(q != NULL);
test_assert(ecs_query_get_ctx(q) == &ctx);
test_assert(ecs_query_get_binding_ctx(q) == NULL);
ecs_fini(ecs);
}
void Query_set_get_binding_context(void) {
ecs_world_t* ecs = ecs_init();
ECS_COMPONENT(ecs, Position);
int ctx = 0;
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Position) }
},
.binding_ctx = &ctx
});
test_assert(q != NULL);
test_assert(ecs_query_get_binding_ctx(q) == &ctx);
test_assert(ecs_query_get_ctx(q) == NULL);
ecs_fini(ecs);
}
static void ctx_free(void *ptr) {
*(int*)ptr = 10;
}
void Query_set_get_context_w_free(void) {
ecs_world_t* ecs = ecs_init();
ECS_COMPONENT(ecs, Position);
int ctx = 0;
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Position) }
},
.ctx = &ctx,
.ctx_free = ctx_free
});
test_assert(q != NULL);
test_assert(ecs_query_get_ctx(q) == &ctx);
test_assert(ecs_query_get_binding_ctx(q) == NULL);
test_int(ctx, 0);
ecs_query_fini(q);
test_int(ctx, 10);
ecs_fini(ecs);
}
void Query_set_get_binding_context_w_free(void) {
ecs_world_t* ecs = ecs_init();
ECS_COMPONENT(ecs, Position);
int ctx = 0;
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Position) }
},
.binding_ctx = &ctx,
.binding_ctx_free = ctx_free
});
test_assert(q != NULL);
test_assert(ecs_query_get_binding_ctx(q) == &ctx);
test_assert(ecs_query_get_ctx(q) == NULL);
test_int(ctx, 0);
ecs_query_fini(q);
test_int(ctx, 10);
ecs_fini(ecs);
}
void Query_set_this(void) {
ecs_world_t* ecs = ecs_init();
ECS_COMPONENT(ecs, Position);
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Position) }
}
});
test_assert(q != NULL);
/* ecs_entity_t e1 = */ ecs_set(ecs, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(ecs, 0, Position, {20, 30});
/* ecs_entity_t e3 = */ ecs_set(ecs, 0, Position, {30, 40});
ecs_iter_t it = ecs_query_iter(ecs, q);
ecs_iter_set_var(&it, 0, e2);
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 20);
test_int(p[0].y, 30);
test_bool(false, ecs_query_next(&it));
ecs_fini(ecs);
}
void Query_set_this_no_match(void) {
ecs_world_t* ecs = ecs_init();
ECS_COMPONENT(ecs, Position);
ECS_COMPONENT(ecs, Velocity);
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Position) }
}
});
test_assert(q != NULL);
/* ecs_entity_t e1 = */ ecs_set(ecs, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(ecs, 0, Velocity, {20, 30});
/* ecs_entity_t e3 = */ ecs_set(ecs, 0, Position, {30, 40});
ecs_iter_t it = ecs_query_iter(ecs, q);
ecs_iter_set_var(&it, 0, e2);
test_bool(false, ecs_query_next(&it));
ecs_fini(ecs);
}
void Query_set_this_is_true(void) {
ecs_world_t* ecs = ecs_init();
ECS_COMPONENT(ecs, Position);
ECS_COMPONENT(ecs, Velocity);
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Position) }
}
});
test_assert(q != NULL);
/* ecs_entity_t e1 = */ ecs_set(ecs, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(ecs, 0, Position, {20, 30});
/* ecs_entity_t e3 = */ ecs_set(ecs, 0, Position, {30, 40});
ecs_entity_t e4 = ecs_set(ecs, 0, Velocity, {20, 30});
ecs_iter_t it = ecs_query_iter(ecs, q);
ecs_iter_set_var(&it, 0, e2);
test_bool(true, ecs_iter_is_true(&it));
it = ecs_query_iter(ecs, q);
ecs_iter_set_var(&it, 0, e4);
test_bool(false, ecs_iter_is_true(&it));
ecs_fini(ecs);
}
void Query_set_this_w_wildcard(void) {
ecs_world_t* ecs = ecs_init();
ECS_COMPONENT(ecs, Position);
ECS_TAG(ecs, Likes);
ECS_TAG(ecs, Apples);
ECS_TAG(ecs, Pears);
ecs_query_t *q = ecs_query(ecs, {
.filter.terms = {
{ .id = ecs_id(Position) },
{ .id = ecs_pair(Likes, EcsWildcard) }
}
});
test_assert(q != NULL);
ecs_entity_t e1 = ecs_set(ecs, 0, Position, {10, 20});
ecs_entity_t e2 = ecs_set(ecs, 0, Position, {20, 30});
ecs_entity_t e3 = ecs_set(ecs, 0, Position, {30, 40});
ecs_add_pair(ecs, e1, Likes, Apples);
ecs_add_pair(ecs, e2, Likes, Apples);
ecs_add_pair(ecs, e3, Likes, Apples);
ecs_add_pair(ecs, e1, Likes, Pears);
ecs_add_pair(ecs, e2, Likes, Pears);
ecs_add_pair(ecs, e3, Likes, Pears);
ecs_iter_t it = ecs_query_iter(ecs, q);
ecs_iter_set_var(&it, 0, e2);
{
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 20);
test_int(p[0].y, 30);
test_uint(ecs_pair(Likes, Apples), ecs_field_id(&it, 2));
}
{
test_bool(true, ecs_query_next(&it));
test_int(it.count, 1);
test_uint(it.entities[0], e2);
Position *p = ecs_field(&it, Position, 1);
test_int(p[0].x, 20);
test_int(p[0].y, 30);
test_uint(ecs_pair(Likes, Pears), ecs_field_id(&it, 2));
}
test_bool(false, ecs_query_next(&it));
ecs_fini(ecs);
}