diff options
Diffstat (limited to 'ecs/tests')
| -rw-r--r-- | ecs/tests/phase.rs | 36 | ||||
| -rw-r--r-- | ecs/tests/query.rs | 413 |
2 files changed, 449 insertions, 0 deletions
diff --git a/ecs/tests/phase.rs b/ecs/tests/phase.rs new file mode 100644 index 0000000..af2646b --- /dev/null +++ b/ecs/tests/phase.rs @@ -0,0 +1,36 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; + +use ecs::component::local::Local; +use ecs::phase::UPDATE; +use ecs::system::Into; +use ecs::system::initializable::Initializable; +use ecs::{Component, World}; + +#[derive(Component)] +struct Thing; + +#[test] +fn system_run_order_correct_when_one_has_local_comp() +{ + static COUNTER: AtomicUsize = AtomicUsize::new(0); + + fn first_system(_thing: Local<Thing>) + { + assert_eq!(COUNTER.fetch_add(1, Ordering::Relaxed), 0); + } + + fn second_system() + { + assert_eq!(COUNTER.fetch_add(1, Ordering::Relaxed), 1); + } + + let mut world = World::new(); + + world.register_system(*UPDATE, first_system.into_system().initialize((Thing,))); + + world.register_system(*UPDATE, second_system); + + world.step(); + + assert_eq!(COUNTER.load(Ordering::Relaxed), 2); +} diff --git a/ecs/tests/query.rs b/ecs/tests/query.rs new file mode 100644 index 0000000..7b218e3 --- /dev/null +++ b/ecs/tests/query.rs @@ -0,0 +1,413 @@ +use ecs::component::Component; +use ecs::pair::{Pair, Wildcard}; +use ecs::query::term::Without; +use ecs::query::{ + TermWithFieldTuple as QueryTermWithFieldTuple, + TermWithoutFieldTuple as QueryTermWithoutFieldTuple, +}; +use ecs::uid::Uid; +use ecs::{Component, Query, World}; +use parking_lot::{Mutex, Once}; + +pub static SETUP: Once = Once::new(); + +pub static TEST_LOCK: Mutex<()> = Mutex::new(()); + +#[derive(Component)] +struct A; + +#[derive(Component)] +struct B; + +#[derive(Component)] +struct C; + +#[derive(Component)] +struct D; + +#[derive(Component)] +struct E; + +#[derive(Component)] +struct F; + +#[derive(Component)] +struct G; + +fn setup() +{ + SETUP.call_once_force(|_| { + assert_eq!(A::id().id(), Uid::FIRST_UNIQUE_ID); + assert_eq!(B::id().id(), Uid::FIRST_UNIQUE_ID + 1); + assert_eq!(C::id().id(), Uid::FIRST_UNIQUE_ID + 2); + assert_eq!(D::id().id(), Uid::FIRST_UNIQUE_ID + 3); + assert_eq!(E::id().id(), Uid::FIRST_UNIQUE_ID + 4); + assert_eq!(F::id().id(), Uid::FIRST_UNIQUE_ID + 5); + assert_eq!(G::id().id(), Uid::FIRST_UNIQUE_ID + 6); + }); +} + +fn assert_query_finds_ents<QueryFieldTerms, QueryFieldlessTerms>( + query: Query<'_, QueryFieldTerms, QueryFieldlessTerms>, + mut expected_ent_ids: Vec<Uid>, +) where + QueryFieldTerms: QueryTermWithFieldTuple, + QueryFieldlessTerms: QueryTermWithoutFieldTuple, +{ + assert!( + query.iter_with_euids().all(|(ent_id, _)| { + let Some(index) = expected_ent_ids + .iter() + .position(|expected_id| *expected_id == ent_id) + else { + return false; + }; + + expected_ent_ids.remove(index); + + true + }), + "Unexpected entity was found. Expected entities left: {expected_ent_ids:?}" + ); + + assert_eq!( + expected_ent_ids.len(), + 0, + concat!( + "Not all entities expected to be found was found. ", + "Expected entities left: {:?}" + ), + expected_ent_ids + ); +} + +#[test] +fn query_archetype_exists_with_edges_to_next_archetypes() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + let ent_1_id = world.create_entity((A, B, C)); + let ent_2_id = world.create_entity((A, B, C, D, E)); + let ent_3_id = world.create_entity((A, B, C, E)); + let ent_4_id = world.create_entity((A, B, C, G, F)); + + assert_query_finds_ents( + world.query::<(&A, &B, &C), ()>(), + vec![ent_1_id, ent_2_id, ent_3_id, ent_4_id], + ); +} + +#[test] +fn query_archetype_exists_with_2_comps_diff_to_next_archetype() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + let ent_1_id = world.create_entity((A, B, C, D, F)); + + let ent_2_id = world.create_entity((A, B, F)); + + assert_query_finds_ents(world.query::<(&A, &B, &F), ()>(), vec![ent_1_id, ent_2_id]); +} + +#[test] +fn query_archetype_exists_with_2_comps_diff_to_next_archetype_rev() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + let ent_1_id = world.create_entity((A, B, F)); + + let ent_2_id = world.create_entity((A, B, C, D, F)); + + assert_query_finds_ents(world.query::<(&A, &B, &F), ()>(), vec![ent_1_id, ent_2_id]); +} + +#[test] +fn query_archetype_exists_with_3_comps_diff_to_next_archetype() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + let ent_1_id = world.create_entity((A, B, C, D, E, F)); + + let ent_2_id = world.create_entity((A, B, F)); + + assert_query_finds_ents(world.query::<(&A, &B, &F), ()>(), vec![ent_1_id, ent_2_id]); +} + +#[test] +fn query_archetype_exists_with_3_comps_diff_to_next_archetype_rev() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + let ent_1_id = world.create_entity((A, B, F)); + + let ent_2_id = world.create_entity((A, B, C, D, E, F)); + + assert_query_finds_ents(world.query::<(&A, &B, &F), ()>(), vec![ent_1_id, ent_2_id]); +} + +#[test] +fn query_archetype_exists_with_4_comps_diff_to_next_archetype() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + let ent_1_id = world.create_entity((A, B, C, D, E, F, G)); + + let ent_2_id = world.create_entity((A, B, G)); + + assert_query_finds_ents(world.query::<(&A, &B, &G), ()>(), vec![ent_1_id, ent_2_id]); +} + +#[test] +fn query_archetype_exists_with_4_comps_diff_to_next_archetype_rev() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + let ent_1_id = world.create_entity((A, B, G)); + + let ent_2_id = world.create_entity((A, B, C, D, E, F, G)); + + assert_query_finds_ents(world.query::<(&A, &B, &G), ()>(), vec![ent_1_id, ent_2_id]); +} + +#[test] +fn query_archetype_exists_with_4_comps_diff_to_next_archetype_and_opt_comp() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + let ent_1_id = world.create_entity((A, B, C, D, E, F, G)); + + let ent_2_id = world.create_entity((A, B, G)); + + assert_query_finds_ents( + world.query::<(&A, Option<&E>, &G), ()>(), + vec![ent_1_id, ent_2_id], + ); +} + +#[test] +fn query_archetype_nonexistant() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + world.create_entity((A, B, C)); + + let ent_2_id = world.create_entity((A, B, C, D, E)); + let ent_3_id = world.create_entity((A, B, C, E)); + + world.create_entity((A, B, C, G, F)); + + assert_query_finds_ents(world.query::<(&A, &E), ()>(), vec![ent_2_id, ent_3_id]); +} + +#[test] +fn query_archetype_nonexistant_and_opt_comp() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + world.create_entity((A, B, C)); + let ent_2_id = world.create_entity((A, B, C, D, E)); + let ent_3_id = world.create_entity((A, B, C, E)); + world.create_entity((A, B, C, G, F)); + + assert_query_finds_ents( + world.query::<(&A, &E, Option<&D>), ()>(), + vec![ent_2_id, ent_3_id], + ); +} + +#[test] +fn query_without_comp_and_archetype_exists() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + let ent_1_id = world.create_entity((A, B, C)); + + world.create_entity((A, B, C, E)); + world.create_entity((A, B, C, F, E)); + + let ent_2_id = world.create_entity((A, B, C, G)); + let ent_3_id = world.create_entity((A, B, C, G, F)); + + assert_query_finds_ents( + world.query::<(&A, &B, &C), (Without<E>,)>(), + vec![ent_1_id, ent_2_id, ent_3_id], + ); +} + +#[test] +fn query_without_required_comp_and_archetype_exists() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + world.create_entity((A, B, C)); + + world.create_entity((A, B, C, E)); + world.create_entity((A, B, C, F, E)); + + world.create_entity((A, B, C, G)); + world.create_entity((A, B, C, G, F)); + + assert_query_finds_ents(world.query::<(&A, &B), (Without<B>,)>(), vec![]); +} + +#[test] +fn query_without_comp_and_archetype_nonexistant() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + world.create_entity((A, B, C)); + + let ent_1_id = world.create_entity((A, B, C, E)); + + world.create_entity((A, B, C, F, E)); + + let ent_2_id = world.create_entity((A, B, C, G, E)); + world.create_entity((A, B, C, G, F, E)); + + assert_query_finds_ents( + world.query::<(&A, &E), (Without<F>,)>(), + vec![ent_1_id, ent_2_id], + ); +} + +#[test] +fn query_with_wildcard_target_pair() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + let ent_1_id = world.create_entity((A, C)); + + world.create_entity((B,)); + + let ent_2_id = world.create_entity(( + B, + Pair::builder().relation::<G>().target_id(ent_1_id).build(), + )); + + world.create_entity(( + B, + Pair::builder().relation::<F>().target_id(ent_1_id).build(), + )); + world.create_entity(( + B, + A, + C, + Pair::builder().relation::<F>().target_id(ent_1_id).build(), + )); + + let ent_3_id = world.create_entity(( + B, + Pair::builder().relation::<G>().target_id(ent_2_id).build(), + )); + + let ent_4_id = world.create_entity(( + B, + E, + Pair::builder().relation::<G>().target_as_data(D).build(), + )); + + assert_query_finds_ents( + world.query::<(&B, Pair<G, Wildcard>), ()>(), + vec![ent_2_id, ent_3_id, ent_4_id], + ); +} + +#[test] +fn query_with_component_target_pair() +{ + setup(); + + let _test_lock = TEST_LOCK.lock(); + + let mut world = World::new(); + + let ent_1_id = world.create_entity((A, C)); + + world.create_entity((B,)); + + world.create_entity(( + B, + Pair::builder().relation::<G>().target_id(ent_1_id).build(), + )); + + world.create_entity(( + B, + Pair::builder().relation::<F>().target_id(ent_1_id).build(), + )); + world.create_entity(( + B, + A, + C, + Pair::builder().relation::<F>().target_id(ent_1_id).build(), + )); + + let ent_2_id = world + .create_entity((B, Pair::builder().relation::<G>().target_as_data(F).build())); + + let ent_3_id = world.create_entity(( + B, + E, + Pair::builder().relation::<G>().target_as_data(F).build(), + )); + + assert_query_finds_ents( + world.query::<(&B, Pair<G, &F>), ()>(), + vec![ent_2_id, ent_3_id], + ); +} |
