Introduce tests for derive(WorldQuery) (#4625)

The only tests we had for `derive(WorldQuery)` checked that the derive doesnt panic/emit a `compiler_error!`. This PR adds tests that actually assert the returned values of a query using the derived `WorldQuery` impl. Also adds a compile fail test to check that we correctly error on read only world queries containing mutable world queries.
This commit is contained in:
Boxy 2022-04-28 21:06:20 +00:00
parent 990d5c0879
commit b9102b8836
3 changed files with 232 additions and 5 deletions

View File

@ -19,18 +19,19 @@ unsafe fn debug_checked_unreachable() -> ! {
#[cfg(test)]
mod tests {
use super::AnyOf;
use super::WorldQuery;
use crate::prelude::{AnyOf, Entity, Or, With, Without};
use crate::{self as bevy_ecs, component::Component, world::World};
use std::collections::HashSet;
#[derive(Component, Debug, Hash, Eq, PartialEq)]
#[derive(Component, Debug, Hash, Eq, PartialEq, Clone, Copy)]
struct A(usize);
#[derive(Component, Debug, Eq, PartialEq)]
#[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
struct B(usize);
#[derive(Component, Debug, Eq, PartialEq)]
#[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
struct C(usize);
#[derive(Component, Debug, Eq, PartialEq)]
#[derive(Component, Debug, Eq, PartialEq, Clone, Copy)]
#[component(storage = "SparseSet")]
struct Sparse(usize);
@ -337,4 +338,182 @@ mod tests {
vec![(Some(&A(1)), Some(&B(2))), (Some(&A(2)), None),]
);
}
#[test]
#[should_panic = "&mut bevy_ecs::query::tests::A conflicts with a previous access in this query."]
fn self_conflicting_worldquery() {
#[derive(WorldQuery)]
#[world_query(mutable)]
struct SelfConflicting {
a: &'static mut A,
b: &'static mut A,
}
let mut world = World::new();
world.query::<SelfConflicting>();
}
#[test]
fn derived_worldqueries() {
let mut world = World::new();
world.spawn().insert_bundle((A(10), B(18), C(3), Sparse(4)));
world.spawn().insert_bundle((A(101), B(148), C(13)));
world.spawn().insert_bundle((A(51), B(46), Sparse(72)));
world.spawn().insert_bundle((A(398), C(6), Sparse(9)));
world.spawn().insert_bundle((B(11), C(28), Sparse(92)));
world.spawn().insert_bundle((C(18348), Sparse(101)));
world.spawn().insert_bundle((B(839), Sparse(5)));
world.spawn().insert_bundle((B(6721), C(122)));
world.spawn().insert_bundle((A(220), Sparse(63)));
world.spawn().insert_bundle((A(1092), C(382)));
world.spawn().insert_bundle((A(2058), B(3019)));
world.spawn().insert_bundle((B(38), C(8), Sparse(100)));
world.spawn().insert_bundle((A(111), C(52), Sparse(1)));
world.spawn().insert_bundle((A(599), B(39), Sparse(13)));
world.spawn().insert_bundle((A(55), B(66), C(77)));
world.spawn();
{
#[derive(WorldQuery)]
struct CustomAB {
a: &'static A,
b: &'static B,
}
let custom_param_data = world
.query::<CustomAB>()
.iter(&world)
.map(|item| (*item.a, *item.b))
.collect::<Vec<_>>();
let normal_data = world
.query::<(&A, &B)>()
.iter(&world)
.map(|(a, b)| (*a, *b))
.collect::<Vec<_>>();
assert_eq!(custom_param_data, normal_data);
}
{
#[derive(WorldQuery)]
struct FancyParam {
e: Entity,
b: &'static B,
opt: Option<&'static Sparse>,
}
let custom_param_data = world
.query::<FancyParam>()
.iter(&world)
.map(|fancy| (fancy.e, *fancy.b, fancy.opt.copied()))
.collect::<Vec<_>>();
let normal_data = world
.query::<(Entity, &B, Option<&Sparse>)>()
.iter(&world)
.map(|(e, b, opt)| (e, *b, opt.copied()))
.collect::<Vec<_>>();
assert_eq!(custom_param_data, normal_data);
}
{
#[derive(WorldQuery)]
struct MaybeBSparse {
blah: Option<(&'static B, &'static Sparse)>,
}
#[derive(WorldQuery)]
struct MatchEverything {
abcs: AnyOf<(&'static A, &'static B, &'static C)>,
opt_bsparse: MaybeBSparse,
}
let custom_param_data = world
.query::<MatchEverything>()
.iter(&world)
.map(
|MatchEverythingItem {
abcs: (a, b, c),
opt_bsparse: MaybeBSparseItem { blah: bsparse },
}| {
(
(a.copied(), b.copied(), c.copied()),
bsparse.map(|(b, sparse)| (*b, *sparse)),
)
},
)
.collect::<Vec<_>>();
let normal_data = world
.query::<(AnyOf<(&A, &B, &C)>, Option<(&B, &Sparse)>)>()
.iter(&world)
.map(|((a, b, c), bsparse)| {
(
(a.copied(), b.copied(), c.copied()),
bsparse.map(|(b, sparse)| (*b, *sparse)),
)
})
.collect::<Vec<_>>();
assert_eq!(custom_param_data, normal_data)
}
{
#[derive(WorldQuery)]
struct AOrBFilter {
a: Or<(With<A>, With<B>)>,
}
#[derive(WorldQuery)]
struct NoSparseThatsSlow {
no: Without<Sparse>,
}
let custom_param_entities = world
.query_filtered::<Entity, (AOrBFilter, NoSparseThatsSlow)>()
.iter(&world)
.collect::<Vec<_>>();
let normal_entities = world
.query_filtered::<Entity, (Or<(With<A>, With<B>)>, Without<Sparse>)>()
.iter(&world)
.collect::<Vec<_>>();
assert_eq!(custom_param_entities, normal_entities);
}
{
#[derive(WorldQuery)]
struct CSparseFilter {
tuple_structs_pls: With<C>,
ugh: With<Sparse>,
}
let custom_param_entities = world
.query_filtered::<Entity, CSparseFilter>()
.iter(&world)
.collect::<Vec<_>>();
let normal_entities = world
.query_filtered::<Entity, (With<C>, With<Sparse>)>()
.iter(&world)
.collect::<Vec<_>>();
assert_eq!(custom_param_entities, normal_entities);
}
{
#[derive(WorldQuery)]
struct WithoutComps {
_1: Without<A>,
_2: Without<B>,
_3: Without<C>,
}
let custom_param_entities = world
.query_filtered::<Entity, WithoutComps>()
.iter(&world)
.collect::<Vec<_>>();
let normal_entities = world
.query_filtered::<Entity, (Without<A>, Without<B>, Without<C>)>()
.iter(&world)
.collect::<Vec<_>>();
assert_eq!(custom_param_entities, normal_entities);
}
}
}

View File

@ -0,0 +1,23 @@
use bevy_ecs::prelude::*;
use bevy_ecs::query::WorldQuery;
#[derive(Component)]
struct Foo;
#[derive(WorldQuery)]
struct MutableUnmarked {
a: &'static mut Foo,
}
#[derive(WorldQuery)]
#[world_query(mutable)]
struct MutableMarked {
a: &'static mut Foo,
}
#[derive(WorldQuery)]
struct NestedMutableUnmarked {
a: MutableMarked,
}
fn main() {}

View File

@ -0,0 +1,25 @@
error[E0277]: the trait bound `WriteFetch<'_, Foo>: ReadOnlyFetch` is not satisfied
--> tests/ui/world_query_derive.rs:7:10
|
7 | #[derive(WorldQuery)]
| ^^^^^^^^^^ the trait `ReadOnlyFetch` is not implemented for `WriteFetch<'_, Foo>`
|
note: required by a bound in `_::assert_readonly`
--> tests/ui/world_query_derive.rs:7:10
|
7 | #[derive(WorldQuery)]
| ^^^^^^^^^^ required by this bound in `_::assert_readonly`
= note: this error originates in the derive macro `WorldQuery` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `MutableMarkedFetch<'_>: ReadOnlyFetch` is not satisfied
--> tests/ui/world_query_derive.rs:18:10
|
18 | #[derive(WorldQuery)]
| ^^^^^^^^^^ the trait `ReadOnlyFetch` is not implemented for `MutableMarkedFetch<'_>`
|
note: required by a bound in `_::assert_readonly`
--> tests/ui/world_query_derive.rs:18:10
|
18 | #[derive(WorldQuery)]
| ^^^^^^^^^^ required by this bound in `_::assert_readonly`
= note: this error originates in the derive macro `WorldQuery` (in Nightly builds, run with -Z macro-backtrace for more info)