summaryrefslogtreecommitdiff
path: root/ecs/tests
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/tests')
-rw-r--r--ecs/tests/phase.rs36
-rw-r--r--ecs/tests/query.rs413
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],
+ );
+}