@@ -6482,3 +6482,307 @@ void Sparse_children_for_sparse_after_delete_children(void) {
64826482
64836483 ecs_fini (world );
64846484}
6485+
6486+ static ecs_id_t dummy_component_id = 0 ;
6487+ static int dummy_dtor_invoked = 0 ;
6488+ static int dummy_hook_invoked = 0 ;
6489+ static int dummy_observer_invoked = 0 ;
6490+ static int check_observer_invoked = 0 ;
6491+
6492+ static void DummyDtor (void * ptr , ecs_size_t count , const ecs_type_info_t * ti ) {
6493+ test_assert (!dummy_dtor_invoked );
6494+ dummy_dtor_invoked ++ ;
6495+ test_assert (dummy_observer_invoked );
6496+ test_assert (dummy_hook_invoked );
6497+ }
6498+
6499+ static void DummyHook (ecs_iter_t * it ) {
6500+ test_assert (!dummy_hook_invoked );
6501+ dummy_hook_invoked ++ ;
6502+ test_assert (dummy_observer_invoked );
6503+ test_assert (!dummy_dtor_invoked );
6504+
6505+ test_int (it -> count , 1 );
6506+
6507+ Position * p = ecs_field_at (it , Position , 0 , 0 );
6508+ test_assert (p != NULL );
6509+
6510+ test_assert (ecs_has_id (it -> world , it -> entities [0 ], dummy_component_id ));
6511+ }
6512+
6513+ static void DummyObserver (ecs_iter_t * it ) {
6514+ test_assert (!dummy_observer_invoked );
6515+ dummy_observer_invoked ++ ;
6516+ test_assert (!dummy_hook_invoked );
6517+ test_assert (!dummy_dtor_invoked );
6518+
6519+ test_int (it -> count , 1 );
6520+
6521+ Position * p = ecs_field_at (it , Position , 0 , 0 );
6522+ test_assert (p != NULL );
6523+
6524+ ecs_world_t * world = it -> world ;
6525+ ecs_entity_t e = it -> entities [0 ];
6526+
6527+ test_assert (ecs_has_id (world , e , dummy_component_id ));
6528+
6529+ if (ecs_id_is_pair (dummy_component_id )) {
6530+ ecs_entity_t rel = ecs_pair_first (world , dummy_component_id );
6531+ ecs_entity_t tgt = ecs_pair_second (world , dummy_component_id );
6532+ test_assert (ecs_get_target (world , e , rel , 0 ) == tgt );
6533+ }
6534+ }
6535+
6536+ static void CheckObserver (ecs_iter_t * it ) {
6537+ check_observer_invoked ++ ;
6538+ test_assert (ecs_has_id (it -> world , it -> entities [0 ], dummy_component_id ));
6539+ }
6540+
6541+ static void CheckTargetObserver (ecs_iter_t * it ) {
6542+ check_observer_invoked ++ ;
6543+ test_assert (ecs_has_id (it -> world , it -> entities [0 ], dummy_component_id ));
6544+
6545+ ecs_entity_t rel = ecs_pair_first (it -> world , dummy_component_id );
6546+ ecs_entity_t tgt = ecs_pair_second (it -> world , dummy_component_id );
6547+ test_assert (tgt != 0 );
6548+
6549+ test_assert (ecs_get_target (it -> world , it -> entities [0 ], rel , 0 ) == tgt );
6550+ }
6551+
6552+ void Sparse_on_remove_before_hook_before_dtor (void ) {
6553+ ecs_world_t * world = ecs_mini ();
6554+
6555+ ECS_COMPONENT (world , Position );
6556+
6557+ ecs_add_id (world , ecs_id (Position ), EcsSparse );
6558+ if (!fragment ) ecs_add_id (world , ecs_id (Position ), EcsDontFragment );
6559+
6560+ ecs_set_hooks (world , Position , {
6561+ .dtor = DummyDtor ,
6562+ .on_remove = DummyHook
6563+ });
6564+
6565+ ecs_observer (world , {
6566+ .query .terms = {{ ecs_id (Position ) }},
6567+ .events = { EcsOnRemove },
6568+ .callback = DummyObserver
6569+ });
6570+
6571+ dummy_component_id = ecs_id (Position );
6572+
6573+ ecs_entity_t e = ecs_insert (world , ecs_value (Position , {10 , 20 }));
6574+ test_int (dummy_observer_invoked , 0 );
6575+ test_int (dummy_hook_invoked , 0 );
6576+ test_int (dummy_dtor_invoked , 0 );
6577+
6578+ ecs_delete (world , e );
6579+ test_int (dummy_observer_invoked , 1 );
6580+ test_int (dummy_hook_invoked , 1 );
6581+ test_int (dummy_dtor_invoked , 1 );
6582+
6583+ ecs_fini (world );
6584+ }
6585+
6586+ void Sparse_on_remove_before_hook_before_dtor_pair (void ) {
6587+ ecs_world_t * world = ecs_mini ();
6588+
6589+ ECS_COMPONENT (world , Position );
6590+ ECS_TAG (world , Tgt );
6591+
6592+ ecs_add_id (world , ecs_id (Position ), EcsSparse );
6593+ if (!fragment ) ecs_add_id (world , ecs_id (Position ), EcsDontFragment );
6594+
6595+ ecs_set_hooks (world , Position , {
6596+ .dtor = DummyDtor ,
6597+ .on_remove = DummyHook
6598+ });
6599+
6600+ ecs_observer (world , {
6601+ .query .terms = {{ ecs_pair_t (Position , Tgt ) }},
6602+ .events = { EcsOnRemove },
6603+ .callback = DummyObserver
6604+ });
6605+
6606+ dummy_component_id = ecs_pair_t (Position , Tgt );
6607+
6608+ ecs_entity_t e = ecs_new (world );
6609+ ecs_set_pair (world , e , Position , Tgt , {10 , 20 });
6610+ test_int (dummy_observer_invoked , 0 );
6611+ test_int (dummy_hook_invoked , 0 );
6612+ test_int (dummy_dtor_invoked , 0 );
6613+
6614+ ecs_delete (world , e );
6615+ test_int (dummy_observer_invoked , 1 );
6616+ test_int (dummy_hook_invoked , 1 );
6617+ test_int (dummy_dtor_invoked , 1 );
6618+
6619+ ecs_fini (world );
6620+ }
6621+
6622+ void Sparse_check_sparse_in_regular_observer (void ) {
6623+ ecs_world_t * world = ecs_mini ();
6624+
6625+ ECS_COMPONENT (world , Position );
6626+ ECS_COMPONENT (world , Velocity );
6627+
6628+ ecs_add_id (world , ecs_id (Position ), EcsSparse );
6629+ if (!fragment ) ecs_add_id (world , ecs_id (Position ), EcsDontFragment );
6630+
6631+ ecs_observer (world , {
6632+ .query .terms = {{ ecs_id (Velocity ) }},
6633+ .events = { EcsOnRemove },
6634+ .callback = CheckObserver
6635+ });
6636+
6637+ dummy_component_id = ecs_id (Position );
6638+
6639+ ecs_entity_t e = ecs_insert (world , ecs_value (Position , {10 , 20 }));
6640+ ecs_set (world , e , Velocity , {10 , 20 });
6641+ test_int (check_observer_invoked , 0 );
6642+
6643+ ecs_delete (world , e );
6644+ test_int (check_observer_invoked , 1 );
6645+
6646+ ecs_fini (world );
6647+ }
6648+
6649+ void Sparse_check_sparse_target_in_regular_observer (void ) {
6650+ ecs_world_t * world = ecs_mini ();
6651+
6652+ ECS_TAG (world , Rel );
6653+ ECS_TAG (world , Tgt );
6654+ ECS_COMPONENT (world , Velocity );
6655+
6656+ ecs_add_id (world , Rel , EcsSparse );
6657+ if (!fragment ) ecs_add_id (world , Rel , EcsDontFragment );
6658+
6659+ ecs_observer (world , {
6660+ .query .terms = {{ ecs_id (Velocity ) }},
6661+ .events = { EcsOnRemove },
6662+ .callback = CheckTargetObserver
6663+ });
6664+
6665+ dummy_component_id = ecs_pair (Rel , Tgt );
6666+
6667+ ecs_entity_t e = ecs_new_w_pair (world , Rel , Tgt );
6668+ ecs_set (world , e , Velocity , {10 , 20 });
6669+ test_int (check_observer_invoked , 0 );
6670+
6671+ ecs_delete (world , e );
6672+ test_int (check_observer_invoked , 1 );
6673+
6674+ ecs_fini (world );
6675+ }
6676+
6677+ void Sparse_check_sparse_exclusive_target_in_regular_observer (void ) {
6678+ ecs_world_t * world = ecs_mini ();
6679+
6680+ ECS_TAG (world , Rel );
6681+ ECS_TAG (world , Tgt );
6682+ ECS_COMPONENT (world , Velocity );
6683+
6684+ ecs_add_id (world , Rel , EcsSparse );
6685+ if (!fragment ) ecs_add_id (world , Rel , EcsDontFragment );
6686+ ecs_add_id (world , Rel , EcsExclusive );
6687+
6688+ ecs_observer (world , {
6689+ .query .terms = {{ ecs_id (Velocity ) }},
6690+ .events = { EcsOnRemove },
6691+ .callback = CheckTargetObserver
6692+ });
6693+
6694+ dummy_component_id = ecs_pair (Rel , Tgt );
6695+
6696+ ecs_entity_t e = ecs_new_w_pair (world , Rel , Tgt );
6697+ ecs_set (world , e , Velocity , {10 , 20 });
6698+ test_int (check_observer_invoked , 0 );
6699+
6700+ ecs_delete (world , e );
6701+ test_int (check_observer_invoked , 1 );
6702+
6703+ ecs_fini (world );
6704+ }
6705+
6706+ void Sparse_check_regular_in_sparse_observer (void ) {
6707+ ecs_world_t * world = ecs_mini ();
6708+
6709+ ECS_COMPONENT (world , Position );
6710+ ECS_COMPONENT (world , Velocity );
6711+
6712+ ecs_add_id (world , ecs_id (Position ), EcsSparse );
6713+ if (!fragment ) ecs_add_id (world , ecs_id (Position ), EcsDontFragment );
6714+
6715+ ecs_observer (world , {
6716+ .query .terms = {{ ecs_id (Position ) }},
6717+ .events = { EcsOnRemove },
6718+ .callback = CheckObserver
6719+ });
6720+
6721+ dummy_component_id = ecs_id (Velocity );
6722+
6723+ ecs_entity_t e = ecs_insert (world , ecs_value (Position , {10 , 20 }));
6724+ ecs_set (world , e , Velocity , {10 , 20 });
6725+ test_int (check_observer_invoked , 0 );
6726+
6727+ ecs_delete (world , e );
6728+ test_int (check_observer_invoked , 1 );
6729+
6730+ ecs_fini (world );
6731+ }
6732+
6733+ void Sparse_check_regular_target_in_sparse_observer (void ) {
6734+ ecs_world_t * world = ecs_mini ();
6735+
6736+ ECS_TAG (world , Rel );
6737+ ECS_TAG (world , Tgt );
6738+ ECS_COMPONENT (world , Velocity );
6739+
6740+ ecs_add_id (world , ecs_id (Velocity ), EcsSparse );
6741+ if (!fragment ) ecs_add_id (world , ecs_id (Velocity ), EcsDontFragment );
6742+
6743+ ecs_observer (world , {
6744+ .query .terms = {{ ecs_id (Velocity ) }},
6745+ .events = { EcsOnRemove },
6746+ .callback = CheckTargetObserver
6747+ });
6748+
6749+ dummy_component_id = ecs_pair (Rel , Tgt );
6750+
6751+ ecs_entity_t e = ecs_new_w_pair (world , Rel , Tgt );
6752+ ecs_set (world , e , Velocity , {10 , 20 });
6753+ test_int (check_observer_invoked , 0 );
6754+
6755+ ecs_delete (world , e );
6756+ test_int (check_observer_invoked , 1 );
6757+
6758+ ecs_fini (world );
6759+ }
6760+
6761+ void Sparse_check_regular_exclusive_target_in_sparse_observer (void ) {
6762+ ecs_world_t * world = ecs_mini ();
6763+
6764+ ECS_TAG (world , Rel );
6765+ ECS_TAG (world , Tgt );
6766+ ECS_COMPONENT (world , Velocity );
6767+
6768+ ecs_add_id (world , ecs_id (Velocity ), EcsSparse );
6769+ if (!fragment ) ecs_add_id (world , ecs_id (Velocity ), EcsDontFragment );
6770+ ecs_add_id (world , ecs_id (Velocity ), EcsExclusive );
6771+
6772+ ecs_observer (world , {
6773+ .query .terms = {{ ecs_id (Velocity ) }},
6774+ .events = { EcsOnRemove },
6775+ .callback = CheckTargetObserver
6776+ });
6777+
6778+ dummy_component_id = ecs_pair (Rel , Tgt );
6779+
6780+ ecs_entity_t e = ecs_new_w_pair (world , Rel , Tgt );
6781+ ecs_set (world , e , Velocity , {10 , 20 });
6782+ test_int (check_observer_invoked , 0 );
6783+
6784+ ecs_delete (world , e );
6785+ test_int (check_observer_invoked , 1 );
6786+
6787+ ecs_fini (world );
6788+ }
0 commit comments