bevy/crates/bevy_ecs/hecs/tests/tests.rs
Lukas Wirth fb7c651ab9
Port hecs derive macro improvements (#761)
* Port derive macro changes from hecs

* Emit more info on duplicate components in archetype creation
2020-11-06 13:20:53 -08:00

392 lines
11 KiB
Rust

// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// modified by Bevy contributors
use bevy_hecs::*;
#[test]
fn random_access() {
let mut world = World::new();
let e = world.spawn(("abc", 123));
let f = world.spawn(("def", 456, true));
assert_eq!(*world.get::<&str>(e).unwrap(), "abc");
assert_eq!(*world.get::<i32>(e).unwrap(), 123);
assert_eq!(*world.get::<&str>(f).unwrap(), "def");
assert_eq!(*world.get::<i32>(f).unwrap(), 456);
*world.get_mut::<i32>(f).unwrap() = 42;
assert_eq!(*world.get::<i32>(f).unwrap(), 42);
}
#[test]
fn despawn() {
let mut world = World::new();
let e = world.spawn(("abc", 123));
let f = world.spawn(("def", 456));
assert_eq!(world.query::<()>().count(), 2);
world.despawn(e).unwrap();
assert_eq!(world.query::<()>().count(), 1);
assert!(world.get::<&str>(e).is_err());
assert!(world.get::<i32>(e).is_err());
assert_eq!(*world.get::<&str>(f).unwrap(), "def");
assert_eq!(*world.get::<i32>(f).unwrap(), 456);
}
#[test]
fn query_all() {
let mut world = World::new();
let e = world.spawn(("abc", 123));
let f = world.spawn(("def", 456));
let ents = world
.query::<(Entity, &i32, &&str)>()
.map(|(e, &i, &s)| (e, i, s))
.collect::<Vec<_>>();
assert_eq!(ents.len(), 2);
assert!(ents.contains(&(e, 123, "abc")));
assert!(ents.contains(&(f, 456, "def")));
let ents = world.query::<Entity>().collect::<Vec<_>>();
assert_eq!(ents.len(), 2);
assert!(ents.contains(&e));
assert!(ents.contains(&f));
}
#[test]
fn query_single_component() {
let mut world = World::new();
let e = world.spawn(("abc", 123));
let f = world.spawn(("def", 456, true));
let ents = world
.query::<(Entity, &i32)>()
.map(|(e, &i)| (e, i))
.collect::<Vec<_>>();
assert_eq!(ents.len(), 2);
assert!(ents.contains(&(e, 123)));
assert!(ents.contains(&(f, 456)));
}
#[test]
fn query_missing_component() {
let mut world = World::new();
world.spawn(("abc", 123));
world.spawn(("def", 456));
assert!(world.query::<(&bool, &i32)>().next().is_none());
}
#[test]
fn query_sparse_component() {
let mut world = World::new();
world.spawn(("abc", 123));
let f = world.spawn(("def", 456, true));
let ents = world
.query::<(Entity, &bool)>()
.map(|(e, &b)| (e, b))
.collect::<Vec<_>>();
assert_eq!(ents, &[(f, true)]);
}
#[test]
fn query_optional_component() {
let mut world = World::new();
let e = world.spawn(("abc", 123));
let f = world.spawn(("def", 456, true));
let ents = world
.query::<(Entity, Option<&bool>, &i32)>()
.map(|(e, b, &i)| (e, b.copied(), i))
.collect::<Vec<_>>();
assert_eq!(ents.len(), 2);
assert!(ents.contains(&(e, None, 123)));
assert!(ents.contains(&(f, Some(true), 456)));
}
#[test]
fn build_entity() {
let mut world = World::new();
let mut entity = EntityBuilder::new();
entity.add("abc");
entity.add(123);
let e = world.spawn(entity.build());
entity.add("def");
entity.add([0u8; 1024]);
entity.add(456);
let f = world.spawn(entity.build());
assert_eq!(*world.get::<&str>(e).unwrap(), "abc");
assert_eq!(*world.get::<i32>(e).unwrap(), 123);
assert_eq!(*world.get::<&str>(f).unwrap(), "def");
assert_eq!(*world.get::<i32>(f).unwrap(), 456);
}
#[test]
fn dynamic_components() {
let mut world = World::new();
let e = world.spawn((42,));
world.insert(e, (true, "abc")).unwrap();
assert_eq!(
world
.query::<(Entity, &i32, &bool)>()
.map(|(e, &i, &b)| (e, i, b))
.collect::<Vec<_>>(),
&[(e, 42, true)]
);
assert_eq!(world.remove_one::<i32>(e), Ok(42));
assert_eq!(
world
.query::<(Entity, &i32, &bool)>()
.map(|(e, &i, &b)| (e, i, b))
.collect::<Vec<_>>(),
&[]
);
assert_eq!(
world
.query::<(Entity, &bool, &&str)>()
.map(|(e, &b, &s)| (e, b, s))
.collect::<Vec<_>>(),
&[(e, true, "abc")]
);
}
#[test]
fn shared_borrow() {
let mut world = World::new();
world.spawn(("abc", 123));
world.spawn(("def", 456));
world.query::<(&i32, &i32)>();
}
#[test]
#[cfg(feature = "macros")]
fn derived_bundle() {
#[derive(Bundle)]
struct Foo {
x: i32,
y: f64,
}
let mut world = World::new();
let e = world.spawn(Foo { x: 42, y: 1.0 });
assert_eq!(*world.get::<i32>(e).unwrap(), 42);
assert_eq!(*world.get::<f64>(e).unwrap(), 1.0);
}
#[test]
#[cfg(feature = "macros")]
#[cfg_attr(
debug_assertions,
should_panic(
expected = "attempted to allocate entity with duplicate i32 components; each type must occur at most once!"
)
)]
#[cfg_attr(
not(debug_assertions),
should_panic(
expected = "attempted to allocate entity with duplicate components; each type must occur at most once!"
)
)]
fn bad_bundle_derive() {
#[derive(Bundle)]
struct Foo {
x: i32,
y: i32,
}
let mut world = World::new();
world.spawn(Foo { x: 42, y: 42 });
}
#[test]
#[cfg_attr(miri, ignore)]
fn spawn_many() {
let mut world = World::new();
const N: usize = 100_000;
for _ in 0..N {
world.spawn((42u128,));
}
assert_eq!(world.iter().count(), N);
}
#[test]
fn clear() {
let mut world = World::new();
world.spawn(("abc", 123));
world.spawn(("def", 456, true));
world.clear();
assert_eq!(world.iter().count(), 0);
}
#[test]
fn remove_missing() {
let mut world = World::new();
let e = world.spawn(("abc", 123));
assert!(world.remove_one::<bool>(e).is_err());
}
#[test]
fn query_batched() {
let mut world = World::new();
let a = world.spawn(());
let b = world.spawn(());
let c = world.spawn((42,));
assert_eq!(world.query_batched::<()>(1).count(), 3);
assert_eq!(world.query_batched::<()>(2).count(), 2);
assert_eq!(world.query_batched::<()>(2).flat_map(|x| x).count(), 3);
// different archetypes are always in different batches
assert_eq!(world.query_batched::<()>(3).count(), 2);
assert_eq!(world.query_batched::<()>(3).flat_map(|x| x).count(), 3);
assert_eq!(world.query_batched::<()>(4).count(), 2);
let entities = world
.query_batched::<Entity>(1)
.flat_map(|x| x)
.map(|e| e)
.collect::<Vec<_>>();
dbg!(&entities);
assert_eq!(entities.len(), 3);
assert!(entities.contains(&a));
assert!(entities.contains(&b));
assert!(entities.contains(&c));
}
#[test]
fn spawn_batch() {
let mut world = World::new();
world.spawn_batch((0..100).map(|x| (x, "abc")));
let entities = world.query::<&i32>().map(|&x| x).collect::<Vec<_>>();
assert_eq!(entities.len(), 100);
}
#[test]
fn query_one() {
let mut world = World::new();
let a = world.spawn(("abc", 123));
let b = world.spawn(("def", 456));
let c = world.spawn(("ghi", 789, true));
assert_eq!(world.query_one::<&i32>(a), Ok(&123));
assert_eq!(world.query_one::<&i32>(b), Ok(&456));
assert!(world.query_one::<(&i32, &bool)>(a).is_err());
assert_eq!(world.query_one::<(&i32, &bool)>(c), Ok((&789, &true)));
world.despawn(a).unwrap();
assert!(world.query_one::<&i32>(a).is_err());
}
#[test]
fn remove_tracking() {
let mut world = World::new();
let a = world.spawn(("abc", 123));
let b = world.spawn(("abc", 123));
world.despawn(a).unwrap();
assert_eq!(
world.removed::<i32>(),
&[a],
"despawning results in 'removed component' state"
);
assert_eq!(
world.removed::<&'static str>(),
&[a],
"despawning results in 'removed component' state"
);
world.insert_one(b, 10.0).unwrap();
assert_eq!(
world.removed::<i32>(),
&[a],
"archetype moves does not result in 'removed component' state"
);
world.remove_one::<i32>(b).unwrap();
assert_eq!(
world.removed::<i32>(),
&[a, b],
"removing a component results in a 'removed component' state"
);
world.clear_trackers();
assert_eq!(
world.removed::<i32>(),
&[],
"clearning trackers clears removals"
);
assert_eq!(
world.removed::<&'static str>(),
&[],
"clearning trackers clears removals"
);
assert_eq!(
world.removed::<f64>(),
&[],
"clearning trackers clears removals"
);
let c = world.spawn(("abc", 123));
let d = world.spawn(("abc", 123));
world.clear();
assert_eq!(
world.removed::<i32>(),
&[c, d],
"world clears result in 'removed component' states"
);
assert_eq!(
world.removed::<&'static str>(),
&[c, d, b],
"world clears result in 'removed component' states"
);
assert_eq!(
world.removed::<f64>(),
&[b],
"world clears result in 'removed component' states"
);
}
#[test]
fn added_tracking() {
let mut world = World::new();
let a = world.spawn((123,));
assert_eq!(world.query::<&i32>().count(), 1);
assert_eq!(world.query::<Added<i32>>().count(), 1);
assert_eq!(world.query_mut::<&i32>().count(), 1);
assert_eq!(world.query_mut::<Added<i32>>().count(), 1);
assert!(world.query_one::<&i32>(a).is_ok());
assert!(world.query_one::<Added<i32>>(a).is_ok());
assert!(world.query_one_mut::<&i32>(a).is_ok());
assert!(world.query_one_mut::<Added<i32>>(a).is_ok());
world.clear_trackers();
assert_eq!(world.query::<&i32>().count(), 1);
assert_eq!(world.query::<Added<i32>>().count(), 0);
assert_eq!(world.query_mut::<&i32>().count(), 1);
assert_eq!(world.query_mut::<Added<i32>>().count(), 0);
assert!(world.query_one_mut::<&i32>(a).is_ok());
assert!(world.query_one_mut::<Added<i32>>(a).is_err());
}
#[test]
#[cfg_attr(
debug_assertions,
should_panic(
expected = "attempted to allocate entity with duplicate f32 components; each type must occur at most once!"
)
)]
#[cfg_attr(
not(debug_assertions),
should_panic(
expected = "attempted to allocate entity with duplicate components; each type must occur at most once!"
)
)]
fn duplicate_components_panic() {
let mut world = World::new();
world.reserve::<(f32, i64, f32)>(1);
}