From e7e875a30dd03feeda95c3a8dc5202fed1b47ad9 Mon Sep 17 00:00:00 2001 From: Walter Pearce Date: Thu, 20 Feb 2020 14:13:47 -0800 Subject: [PATCH] Add wasm-pack wasm-bindgen test cases for wasm --- Cargo.toml | 3 + legion_core/src/command.rs | 2 +- legion_core/src/cons.rs | 2 +- legion_core/src/entity.rs | 2 +- legion_core/src/world.rs | 2 +- legion_systems/src/resource.rs | 2 +- legion_systems/src/schedule.rs | 2 +- legion_systems/src/system.rs | 16 +- tests/query_api.rs | 55 +++++ tests/wasm.rs | 392 +++++++++++++++++++++++++++++++++ tests/world_api.rs | 53 +++++ 11 files changed, 524 insertions(+), 7 deletions(-) create mode 100644 tests/wasm.rs diff --git a/Cargo.toml b/Cargo.toml index a00c0ed3..844d153e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,9 @@ tracing = "0.1" itertools = "0.8" rayon = "1.2" +[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +wasm-bindgen-test = { version = "0.3" } + [[bench]] name = "benchmarks" harness = false diff --git a/legion_core/src/command.rs b/legion_core/src/command.rs index 32fef2e6..f0b20fc5 100644 --- a/legion_core/src/command.rs +++ b/legion_core/src/command.rs @@ -548,7 +548,7 @@ impl Drop for CommandBuffer { } #[cfg(test)] -mod tests { +pub mod tests { use super::*; use crate::prelude::*; diff --git a/legion_core/src/cons.rs b/legion_core/src/cons.rs index 43bc60f8..3378b324 100644 --- a/legion_core/src/cons.rs +++ b/legion_core/src/cons.rs @@ -116,7 +116,7 @@ impl_flatten!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, fn test_api() {} #[cfg(test)] -mod tests { +pub mod tests { use super::*; #[test] diff --git a/legion_core/src/entity.rs b/legion_core/src/entity.rs index 54ee30a2..7b2ccbb1 100644 --- a/legion_core/src/entity.rs +++ b/legion_core/src/entity.rs @@ -361,7 +361,7 @@ impl<'a> Iterator for CreateEntityIter<'a> { } #[cfg(test)] -mod tests { +pub mod tests { use crate::entity::*; use std::collections::HashSet; diff --git a/legion_core/src/world.rs b/legion_core/src/world.rs index 62597ce8..93b724e1 100644 --- a/legion_core/src/world.rs +++ b/legion_core/src/world.rs @@ -1458,7 +1458,7 @@ impl<'a, 'b> Filter> for DynamicTagLayout<'a> { } #[cfg(test)] -mod tests { +pub mod tests { use super::*; #[derive(Clone, Copy, Debug, PartialEq)] diff --git a/legion_systems/src/resource.rs b/legion_systems/src/resource.rs index 4bbc6942..1b8969df 100644 --- a/legion_systems/src/resource.rs +++ b/legion_systems/src/resource.rs @@ -402,7 +402,7 @@ impl_resource_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, impl_resource_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z); #[cfg(test)] -mod tests { +pub mod tests { use super::*; #[test] diff --git a/legion_systems/src/schedule.rs b/legion_systems/src/schedule.rs index 45bb7cf3..9f7d6359 100644 --- a/legion_systems/src/schedule.rs +++ b/legion_systems/src/schedule.rs @@ -550,7 +550,7 @@ impl From> for Schedule { } #[cfg(test)] -mod tests { +pub mod tests { use super::*; use crate::prelude::*; use itertools::sorted; diff --git a/legion_systems/src/system.rs b/legion_systems/src/system.rs index 80e721ab..b087c2d6 100644 --- a/legion_systems/src/system.rs +++ b/legion_systems/src/system.rs @@ -1176,7 +1176,7 @@ where } #[cfg(test)] -mod tests { +pub mod tests { use super::*; use crate::schedule::*; use legion_core::prelude::*; @@ -1744,4 +1744,18 @@ mod tests { } }); } + + #[cfg(all(target_arch = "wasm32", not(features = "par-schedule")))] + mod wasm { + #[wasm_bindgen_test] + fn system_mutate_archetype_buffer() { super::system_mutate_archetype_buffer() } + #[wasm_bindgen_test] + fn system_mutate_archetype() { super::system_mutate_archetype() } + #[wasm_bindgen_test] + fn fnmut_stateful_system_test() { super::fnmut_stateful_system_test() } + #[wasm_bindgen_test] + fn builder_create_and_execute() { super::builder_create_and_execute() } + #[wasm_bindgen_test] + fn builder_schedule_execute() { super::builder_schedule_execute() } + } } diff --git a/tests/query_api.rs b/tests/query_api.rs index 4725b746..ac30915d 100644 --- a/tests/query_api.rs +++ b/tests/query_api.rs @@ -587,3 +587,58 @@ fn query_iter_chunks_tag() { } } } + +#[cfg(all(target_arch = "wasm32", not(features = "par-iter")))] +mod wasm { + use wasm_bindgen_test::*; + + #[wasm_bindgen_test] + fn uery_iter_chunks_tag() { super::query_iter_chunks_tag() } + + #[wasm_bindgen_test] + fn query_read_entity_data() { super::query_read_entity_data() } + + #[wasm_bindgen_test] + fn query_try_read_entity_data() { super::query_try_read_entity_data() } + + #[wasm_bindgen_test] + fn query_try_write_entity_data() { super::query_try_write_entity_data() } + + #[wasm_bindgen_test] + fn query_cached_read_entity_data() { super::query_cached_read_entity_data() } + + #[cfg(feature = "par-iter")] + #[wasm_bindgen_test] + fn query_read_entity_data_par() { super::query_read_entity_data_par() } + + #[wasm_bindgen_test] + fn query_read_entity_data_tuple() { super::query_read_entity_data_tuple() } + + #[wasm_bindgen_test] + fn query_write_entity_data() { super::query_write_entity_data() } + + #[wasm_bindgen_test] + fn query_write_entity_data_tuple() { super::query_write_entity_data_tuple() } + + #[wasm_bindgen_test] + fn query_mixed_entity_data_tuple() { super::query_mixed_entity_data_tuple() } + + #[cfg(feature = "par-iter")] + #[wasm_bindgen_test] + fn query_partial_match() { super::query_partial_match() } + + #[wasm_bindgen_test] + fn query_read_shared_data() { super::query_read_shared_data() } + + #[wasm_bindgen_test] + fn query_on_changed_first() { super::query_on_changed_first() } + + #[wasm_bindgen_test] + fn query_on_changed_no_changes() { super::query_on_changed_no_changes() } + + #[wasm_bindgen_test] + fn query_on_changed_self_changes() { super::query_on_changed_self_changes() } + + #[wasm_bindgen_test] + fn query_try_with_changed_filter() { super::query_try_with_changed_filter() } +} diff --git a/tests/wasm.rs b/tests/wasm.rs new file mode 100644 index 00000000..57d6b283 --- /dev/null +++ b/tests/wasm.rs @@ -0,0 +1,392 @@ +#![cfg(all(test, target_arch = "wasm32"))] + +use wasm_bindgen_test::*; + +mod systems { + use super::*; + #[cfg(all(target_arch = "wasm32", not(features = "par-schedule")))] + mod system { + use super::*; + use legion::prelude::*; + + use std::collections::HashMap; + use std::sync::{Arc, Mutex}; + + #[derive(Clone, Copy, Debug, PartialEq)] + struct Pos(f32, f32, f32); + #[derive(Clone, Copy, Debug, PartialEq)] + struct Vel(f32, f32, f32); + + #[derive(Default)] + struct TestResource(pub i32); + #[derive(Default)] + struct TestResourceTwo(pub i32); + #[derive(Default)] + struct TestResourceThree(pub i32); + #[derive(Default)] + struct TestResourceFour(pub i32); + + #[derive(Clone, Copy, Debug, PartialEq)] + struct TestComp(f32, f32, f32); + #[derive(Clone, Copy, Debug, PartialEq)] + struct TestCompTwo(f32, f32, f32); + #[derive(Clone, Copy, Debug, PartialEq)] + struct TestCompThree(f32, f32, f32); + + #[wasm_bindgen_test] + fn builder_schedule_execute() { + let _ = tracing_subscriber::fmt::try_init(); + + let universe = Universe::new(); + let mut world = universe.create_world(); + + let mut resources = Resources::default(); + resources.insert(TestResource(123)); + resources.insert(TestResourceTwo(123)); + + let components = vec![ + (Pos(1., 2., 3.), Vel(0.1, 0.2, 0.3)), + (Pos(4., 5., 6.), Vel(0.4, 0.5, 0.6)), + ]; + + let mut expected = HashMap::::new(); + + for (i, e) in world.insert((), components.clone()).iter().enumerate() { + if let Some((pos, rot)) = components.get(i) { + expected.insert(*e, (*pos, *rot)); + } + } + + #[derive(Debug, Eq, PartialEq)] + pub enum TestSystems { + TestSystemOne, + TestSystemTwo, + TestSystemThree, + TestSystemFour, + } + + let runs = Arc::new(Mutex::new(Vec::new())); + + let system_one_runs = runs.clone(); + let system_one = SystemBuilder::<()>::new("TestSystem1") + .read_resource::() + .with_query(Read::::query()) + .with_query(Write::::query()) + .build(move |_commands, _world, _resource, _queries| { + tracing::trace!("system_one"); + system_one_runs + .lock() + .unwrap() + .push(TestSystems::TestSystemOne); + }); + + let system_two_runs = runs.clone(); + let system_two = SystemBuilder::<()>::new("TestSystem2") + .write_resource::() + .with_query(Read::::query()) + .build(move |_commands, _world, _resource, _queries| { + tracing::trace!("system_two"); + system_two_runs + .lock() + .unwrap() + .push(TestSystems::TestSystemTwo); + }); + + let system_three_runs = runs.clone(); + let system_three = SystemBuilder::<()>::new("TestSystem3") + .read_resource::() + .with_query(Read::::query()) + .build(move |_commands, _world, _resource, _queries| { + tracing::trace!("system_three"); + system_three_runs + .lock() + .unwrap() + .push(TestSystems::TestSystemThree); + }); + let system_four_runs = runs.clone(); + let system_four = SystemBuilder::<()>::new("TestSystem4") + .write_resource::() + .with_query(Read::::query()) + .build(move |_commands, _world, _resource, _queries| { + tracing::trace!("system_four"); + system_four_runs + .lock() + .unwrap() + .push(TestSystems::TestSystemFour); + }); + + let order = vec![ + TestSystems::TestSystemOne, + TestSystems::TestSystemTwo, + TestSystems::TestSystemThree, + TestSystems::TestSystemFour, + ]; + + let systems = vec![system_one, system_two, system_three, system_four]; + + let mut executor = Executor::new(systems); + executor.execute(&mut world, &mut resources); + + assert_eq!(*(runs.lock().unwrap()), order); + } + + #[wasm_bindgen_test] + fn builder_create_and_execute() { + let _ = tracing_subscriber::fmt::try_init(); + + let universe = Universe::new(); + let mut world = universe.create_world(); + + let mut resources = Resources::default(); + resources.insert(TestResource(123)); + + let components = vec![ + (Pos(1., 2., 3.), Vel(0.1, 0.2, 0.3)), + (Pos(4., 5., 6.), Vel(0.4, 0.5, 0.6)), + ]; + + let mut expected = HashMap::::new(); + + for (i, e) in world.insert((), components.clone()).iter().enumerate() { + if let Some((pos, rot)) = components.get(i) { + expected.insert(*e, (*pos, *rot)); + } + } + + let mut system = SystemBuilder::<()>::new("TestSystem") + .read_resource::() + .with_query(Read::::query()) + .with_query(Read::::query()) + .build(move |_commands, world, resource, queries| { + assert_eq!(resource.0, 123); + let mut count = 0; + { + for (entity, pos) in queries.0.iter_entities(world) { + assert_eq!(expected.get(&entity).unwrap().0, *pos); + count += 1; + } + } + + assert_eq!(components.len(), count); + }); + system.prepare(&world); + system.run(&mut world, &mut resources); + } + + #[wasm_bindgen_test] + fn fnmut_stateful_system_test() { + let _ = tracing_subscriber::fmt::try_init(); + + let universe = Universe::new(); + let mut world = universe.create_world(); + + let mut resources = Resources::default(); + resources.insert(TestResource(123)); + + let components = vec![ + (Pos(1., 2., 3.), Vel(0.1, 0.2, 0.3)), + (Pos(4., 5., 6.), Vel(0.4, 0.5, 0.6)), + ]; + + let mut expected = HashMap::::new(); + + for (i, e) in world.insert((), components.clone()).iter().enumerate() { + if let Some((pos, rot)) = components.get(i) { + expected.insert(*e, (*pos, *rot)); + } + } + + let mut state = 0; + let mut system = SystemBuilder::<()>::new("TestSystem") + .read_resource::() + .with_query(Read::::query()) + .with_query(Read::::query()) + .build(move |_, _, _, _| { + state += 1; + }); + + system.prepare(&world); + system.run(&mut world, &mut resources); + } + + #[wasm_bindgen_test] + fn system_mutate_archetype() { + let _ = tracing_subscriber::fmt::try_init(); + + let universe = Universe::new(); + let mut world = universe.create_world(); + let mut resources = Resources::default(); + + #[derive(Default, Clone, Copy)] + pub struct Balls(u32); + + let components = vec![ + (Pos(1., 2., 3.), Vel(0.1, 0.2, 0.3)), + (Pos(4., 5., 6.), Vel(0.4, 0.5, 0.6)), + ]; + + let mut expected = HashMap::::new(); + + for (i, e) in world.insert((), components.clone()).iter().enumerate() { + if let Some((pos, rot)) = components.get(i) { + expected.insert(*e, (*pos, *rot)); + } + } + + let expected_copy = expected.clone(); + let mut system = SystemBuilder::<()>::new("TestSystem") + .with_query(<(Read, Read)>::query()) + .build(move |_, world, _, query| { + let mut count = 0; + { + for (entity, (pos, vel)) in query.iter_entities(world) { + assert_eq!(expected_copy.get(&entity).unwrap().0, *pos); + assert_eq!(expected_copy.get(&entity).unwrap().1, *vel); + count += 1; + } + } + + assert_eq!(components.len(), count); + }); + + system.prepare(&world); + system.run(&mut world, &mut resources); + + world + .add_component(*(expected.keys().nth(0).unwrap()), Balls::default()) + .unwrap(); + + system.prepare(&world); + system.run(&mut world, &mut resources); + } + + #[wasm_bindgen_test] + fn system_mutate_archetype_buffer() { + let _ = tracing_subscriber::fmt::try_init(); + + let universe = Universe::new(); + let mut world = universe.create_world(); + let mut resources = Resources::default(); + + #[derive(Default, Clone, Copy)] + pub struct Balls(u32); + + let components = (0..30000) + .map(|_| (Pos(1., 2., 3.), Vel(0.1, 0.2, 0.3))) + .collect::>(); + + let mut expected = HashMap::::new(); + + for (i, e) in world.insert((), components.clone()).iter().enumerate() { + if let Some((pos, rot)) = components.get(i) { + expected.insert(*e, (*pos, *rot)); + } + } + + let expected_copy = expected.clone(); + let mut system = SystemBuilder::<()>::new("TestSystem") + .with_query(<(Read, Read)>::query()) + .build(move |command_buffer, world, _, query| { + let mut count = 0; + { + for (entity, (pos, vel)) in query.iter_entities(world) { + assert_eq!(expected_copy.get(&entity).unwrap().0, *pos); + assert_eq!(expected_copy.get(&entity).unwrap().1, *vel); + count += 1; + + command_buffer.add_component(entity, Balls::default()); + } + } + + assert_eq!(components.len(), count); + }); + + system.prepare(&world); + system.run(&mut world, &mut resources); + + system + .command_buffer_mut(world.id()) + .unwrap() + .write(&mut world); + + system.prepare(&world); + system.run(&mut world, &mut resources); + } + } + + #[cfg(all(target_arch = "wasm32", not(features = "par-schedule")))] + mod schedule { + use super::*; + use itertools::sorted; + use legion::prelude::*; + use std::sync::{Arc, Mutex}; + + #[wasm_bindgen_test] + fn execute_in_order() { + let universe = Universe::new(); + let mut world = universe.create_world(); + + #[derive(Default)] + struct Resource; + + let mut resources = Resources::default(); + resources.insert(Resource); + + let order = Arc::new(Mutex::new(Vec::new())); + + let order_clone = order.clone(); + let system_one = SystemBuilder::new("one") + .write_resource::() + .build(move |_, _, _, _| order_clone.lock().unwrap().push(1usize)); + let order_clone = order.clone(); + let system_two = SystemBuilder::new("two") + .write_resource::() + .build(move |_, _, _, _| order_clone.lock().unwrap().push(2usize)); + let order_clone = order.clone(); + let system_three = SystemBuilder::new("three") + .write_resource::() + .build(move |_, _, _, _| order_clone.lock().unwrap().push(3usize)); + + let mut schedule = Schedule::builder() + .add_system(system_one) + .add_system(system_two) + .add_system(system_three) + .build(); + + schedule.execute(&mut world, &mut resources); + + let order = order.lock().unwrap(); + let sorted: Vec = sorted(order.clone()).collect(); + assert_eq!(*order, sorted); + } + + #[wasm_bindgen_test] + fn flush() { + let universe = Universe::new(); + let mut world = universe.create_world(); + let mut resources = Resources::default(); + + #[derive(Clone, Copy, Debug, PartialEq)] + struct TestComp(f32, f32, f32); + + let system_one = SystemBuilder::new("one").build(move |cmd, _, _, _| { + cmd.insert((), vec![(TestComp(0., 0., 0.),)]); + }); + let system_two = SystemBuilder::new("two") + .with_query(Write::::query()) + .build(move |_, world, _, query| assert_eq!(0, query.iter_mut(world).count())); + let system_three = SystemBuilder::new("three") + .with_query(Write::::query()) + .build(move |_, world, _, query| assert_eq!(1, query.iter_mut(world).count())); + + let mut schedule = Schedule::builder() + .add_system(system_one) + .add_system(system_two) + .flush() + .add_system(system_three) + .build(); + + schedule.execute(&mut world, &mut resources); + } + } +} diff --git a/tests/world_api.rs b/tests/world_api.rs index 9b98939c..daadbf8a 100644 --- a/tests/world_api.rs +++ b/tests/world_api.rs @@ -443,3 +443,56 @@ fn lots_of_deletes() { world.insert(shared, components).to_vec(); } } + +#[cfg(all(target_arch = "wasm32", not(features = "par-iter")))] +mod wasm { + use wasm_bindgen_test::*; + + #[wasm_bindgen_test] + fn insert() { super::insert() } + + #[wasm_bindgen_test] + fn get_component() { super::get_component() } + + #[wasm_bindgen_test] + fn get_component_wrong_type() { super::get_component_wrong_type() } + + #[wasm_bindgen_test] + fn get_shared() { super::get_shared() } + + #[wasm_bindgen_test] + fn get_shared_wrong_type() { super::get_shared_wrong_type() } + + #[wasm_bindgen_test] + fn delete() { super::delete() } + + #[wasm_bindgen_test] + fn delete_last() { super::delete_last() } + + #[wasm_bindgen_test] + fn delete_first() { super::delete_first() } + + #[wasm_bindgen_test] + fn merge() { super::merge() } + + #[wasm_bindgen_test] + fn mutate_add_component() { super::mutate_add_component() } + + #[wasm_bindgen_test] + fn mutate_remove_component() { super::mutate_remove_component() } + + #[wasm_bindgen_test] + fn mutate_add_tag() { super::mutate_add_tag() } + + #[wasm_bindgen_test] + fn mutate_remove_tag() { super::mutate_remove_tag() } + + #[wasm_bindgen_test] + fn mutate_change_tag_minimum_test() { super::mutate_change_tag_minimum_test() } + + #[wasm_bindgen_test] + fn mutate_change_tag() { super::mutate_change_tag() } + + #[wasm_bindgen_test] + fn lots_of_deletes() { super::lots_of_deletes() } +}