#include #include 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); }