Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/bundle/tests.rs
6849 views
1
use crate::{
2
archetype::ArchetypeCreated, lifecycle::HookContext, prelude::*, world::DeferredWorld,
3
};
4
5
#[derive(Component)]
6
struct A;
7
8
#[derive(Component)]
9
#[component(on_add = a_on_add, on_insert = a_on_insert, on_replace = a_on_replace, on_remove = a_on_remove)]
10
struct AMacroHooks;
11
12
fn a_on_add(mut world: DeferredWorld, _: HookContext) {
13
world.resource_mut::<R>().assert_order(0);
14
}
15
16
fn a_on_insert(mut world: DeferredWorld, _: HookContext) {
17
world.resource_mut::<R>().assert_order(1);
18
}
19
20
fn a_on_replace(mut world: DeferredWorld, _: HookContext) {
21
world.resource_mut::<R>().assert_order(2);
22
}
23
24
fn a_on_remove(mut world: DeferredWorld, _: HookContext) {
25
world.resource_mut::<R>().assert_order(3);
26
}
27
28
#[derive(Component)]
29
struct B;
30
31
#[derive(Component)]
32
struct C;
33
34
#[derive(Component)]
35
struct D;
36
37
#[derive(Component, Eq, PartialEq, Debug)]
38
struct V(&'static str); // component with a value
39
40
#[derive(Resource, Default)]
41
struct R(usize);
42
43
impl R {
44
#[track_caller]
45
fn assert_order(&mut self, count: usize) {
46
assert_eq!(count, self.0);
47
self.0 += 1;
48
}
49
}
50
51
#[derive(Bundle)]
52
#[bundle(ignore_from_components)]
53
struct BundleNoExtract {
54
b: B,
55
no_from_comp: crate::spawn::SpawnRelatedBundle<ChildOf, Spawn<C>>,
56
}
57
58
#[test]
59
fn can_spawn_bundle_without_extract() {
60
let mut world = World::new();
61
let id = world
62
.spawn(BundleNoExtract {
63
b: B,
64
no_from_comp: Children::spawn(Spawn(C)),
65
})
66
.id();
67
68
assert!(world.entity(id).get::<Children>().is_some());
69
}
70
71
#[test]
72
fn component_hook_order_spawn_despawn() {
73
let mut world = World::new();
74
world.init_resource::<R>();
75
world
76
.register_component_hooks::<A>()
77
.on_add(|mut world, _| world.resource_mut::<R>().assert_order(0))
78
.on_insert(|mut world, _| world.resource_mut::<R>().assert_order(1))
79
.on_replace(|mut world, _| world.resource_mut::<R>().assert_order(2))
80
.on_remove(|mut world, _| world.resource_mut::<R>().assert_order(3));
81
82
let entity = world.spawn(A).id();
83
world.despawn(entity);
84
assert_eq!(4, world.resource::<R>().0);
85
}
86
87
#[test]
88
fn component_hook_order_spawn_despawn_with_macro_hooks() {
89
let mut world = World::new();
90
world.init_resource::<R>();
91
92
let entity = world.spawn(AMacroHooks).id();
93
world.despawn(entity);
94
95
assert_eq!(4, world.resource::<R>().0);
96
}
97
98
#[test]
99
fn component_hook_order_insert_remove() {
100
let mut world = World::new();
101
world.init_resource::<R>();
102
world
103
.register_component_hooks::<A>()
104
.on_add(|mut world, _| world.resource_mut::<R>().assert_order(0))
105
.on_insert(|mut world, _| world.resource_mut::<R>().assert_order(1))
106
.on_replace(|mut world, _| world.resource_mut::<R>().assert_order(2))
107
.on_remove(|mut world, _| world.resource_mut::<R>().assert_order(3));
108
109
let mut entity = world.spawn_empty();
110
entity.insert(A);
111
entity.remove::<A>();
112
entity.flush();
113
assert_eq!(4, world.resource::<R>().0);
114
}
115
116
#[test]
117
fn component_hook_order_replace() {
118
let mut world = World::new();
119
world
120
.register_component_hooks::<A>()
121
.on_replace(|mut world, _| world.resource_mut::<R>().assert_order(0))
122
.on_insert(|mut world, _| {
123
if let Some(mut r) = world.get_resource_mut::<R>() {
124
r.assert_order(1);
125
}
126
});
127
128
let entity = world.spawn(A).id();
129
world.init_resource::<R>();
130
let mut entity = world.entity_mut(entity);
131
entity.insert(A);
132
entity.insert_if_new(A); // this will not trigger on_replace or on_insert
133
entity.flush();
134
assert_eq!(2, world.resource::<R>().0);
135
}
136
137
#[test]
138
fn component_hook_order_recursive() {
139
let mut world = World::new();
140
world.init_resource::<R>();
141
world
142
.register_component_hooks::<A>()
143
.on_add(|mut world, context| {
144
world.resource_mut::<R>().assert_order(0);
145
world.commands().entity(context.entity).insert(B);
146
})
147
.on_remove(|mut world, context| {
148
world.resource_mut::<R>().assert_order(2);
149
world.commands().entity(context.entity).remove::<B>();
150
});
151
152
world
153
.register_component_hooks::<B>()
154
.on_add(|mut world, context| {
155
world.resource_mut::<R>().assert_order(1);
156
world.commands().entity(context.entity).remove::<A>();
157
})
158
.on_remove(|mut world, _| {
159
world.resource_mut::<R>().assert_order(3);
160
});
161
162
let entity = world.spawn(A).flush();
163
let entity = world.get_entity(entity).unwrap();
164
assert!(!entity.contains::<A>());
165
assert!(!entity.contains::<B>());
166
assert_eq!(4, world.resource::<R>().0);
167
}
168
169
#[test]
170
fn component_hook_order_recursive_multiple() {
171
let mut world = World::new();
172
world.init_resource::<R>();
173
world
174
.register_component_hooks::<A>()
175
.on_add(|mut world, context| {
176
world.resource_mut::<R>().assert_order(0);
177
world.commands().entity(context.entity).insert(B).insert(C);
178
});
179
180
world
181
.register_component_hooks::<B>()
182
.on_add(|mut world, context| {
183
world.resource_mut::<R>().assert_order(1);
184
world.commands().entity(context.entity).insert(D);
185
});
186
187
world
188
.register_component_hooks::<C>()
189
.on_add(|mut world, _| {
190
world.resource_mut::<R>().assert_order(3);
191
});
192
193
world
194
.register_component_hooks::<D>()
195
.on_add(|mut world, _| {
196
world.resource_mut::<R>().assert_order(2);
197
});
198
199
world.spawn(A).flush();
200
assert_eq!(4, world.resource::<R>().0);
201
}
202
203
#[test]
204
fn insert_if_new() {
205
let mut world = World::new();
206
let id = world.spawn(V("one")).id();
207
let mut entity = world.entity_mut(id);
208
entity.insert_if_new(V("two"));
209
entity.insert_if_new((A, V("three")));
210
entity.flush();
211
// should still contain "one"
212
let entity = world.entity(id);
213
assert!(entity.contains::<A>());
214
assert_eq!(entity.get(), Some(&V("one")));
215
}
216
217
#[derive(Component, Debug, Eq, PartialEq)]
218
#[component(storage = "SparseSet")]
219
pub struct SparseV(&'static str);
220
221
#[derive(Component, Debug, Eq, PartialEq)]
222
#[component(storage = "SparseSet")]
223
pub struct SparseA;
224
225
#[test]
226
fn sparse_set_insert_if_new() {
227
let mut world = World::new();
228
let id = world.spawn(SparseV("one")).id();
229
let mut entity = world.entity_mut(id);
230
entity.insert_if_new(SparseV("two"));
231
entity.insert_if_new((SparseA, SparseV("three")));
232
entity.flush();
233
// should still contain "one"
234
let entity = world.entity(id);
235
assert!(entity.contains::<SparseA>());
236
assert_eq!(entity.get(), Some(&SparseV("one")));
237
}
238
239
#[test]
240
fn new_archetype_created() {
241
let mut world = World::new();
242
#[derive(Resource, Default)]
243
struct Count(u32);
244
world.init_resource::<Count>();
245
world.add_observer(|_t: On<ArchetypeCreated>, mut count: ResMut<Count>| {
246
count.0 += 1;
247
});
248
249
let mut e = world.spawn((A, B));
250
e.insert(C);
251
e.remove::<A>();
252
e.insert(A);
253
e.insert(A);
254
255
assert_eq!(world.resource::<Count>().0, 3);
256
}
257
258
#[derive(Bundle)]
259
#[expect(unused, reason = "tests the output of the derive macro is valid")]
260
struct Ignore {
261
#[bundle(ignore)]
262
foo: i32,
263
#[bundle(ignore)]
264
bar: i32,
265
}
266
267