Skip to content

Commit 0883a36

Browse files
committed
Add beginning of complex serialization / deserialization tests (#6834)
1 parent 7a176ae commit 0883a36

File tree

3 files changed

+201
-0
lines changed

3 files changed

+201
-0
lines changed

Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ bytemuck = "1.7"
137137
# Needed to poll Task examples
138138
futures-lite = "1.11.3"
139139
crossbeam-channel = "0.5.0"
140+
postcard = { version = "1.0", features = ["alloc"] }
141+
bincode = "1.3"
142+
rmp-serde = "1.1"
140143

141144
[[example]]
142145
name = "hello_world"

tests/scenes/components.rs

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
//! Testing of serialization and deserialization of diverse scene components.
2+
3+
use bevy::prelude::*;
4+
use bevy_internal::ecs::entity::EntityMap;
5+
use bevy_internal::scene::serde::{SceneDeserializer, SceneSerializer};
6+
use bevy_internal::scene::ScenePlugin;
7+
use bincode::Options;
8+
use serde::de::DeserializeSeed;
9+
use serde::Serialize;
10+
use std::io::BufReader;
11+
12+
#[test]
13+
fn ron_roundtrip_equality() {
14+
assert_round_trip_equality(serialize_world_ron, deserialize_world_ron);
15+
}
16+
17+
#[test]
18+
fn postcard_roundtrip_equality() {
19+
assert_round_trip_equality(serialize_world_postcard, deserialize_world_postcard);
20+
}
21+
22+
#[test]
23+
fn bincode_roundtrip_equality() {
24+
assert_round_trip_equality(serialize_world_bincode, deserialize_world_bincode);
25+
}
26+
27+
#[test]
28+
fn messagepack_roundtrip_equality() {
29+
assert_round_trip_equality(serialize_world_messagepack, deserialize_world_messagepack);
30+
}
31+
32+
/// Convenience function for testing the roundtrip equality of different serialization methods.
33+
fn assert_round_trip_equality(
34+
serialize: fn(DynamicScene, &AppTypeRegistry) -> Vec<u8>,
35+
deserialize: fn(SceneDeserializer, &[u8]) -> DynamicScene,
36+
) {
37+
let mut input_app = create_test_app();
38+
spawn_test_entities(&mut input_app);
39+
40+
let type_registry = input_app.world.resource::<AppTypeRegistry>();
41+
let scene = DynamicScene::from_world(&input_app.world, type_registry);
42+
let serialized = serialize(scene, type_registry);
43+
44+
// We use a clean app to deserialize into, so nothing of the input app can interfere.
45+
let mut output_app = create_test_app();
46+
let scene = {
47+
let scene_deserializer = SceneDeserializer {
48+
type_registry: &output_app.world.resource::<AppTypeRegistry>().read(),
49+
};
50+
deserialize(scene_deserializer, &serialized)
51+
};
52+
53+
let mut entity_map = EntityMap::default();
54+
scene
55+
.write_to_world(&mut output_app.world, &mut entity_map)
56+
.unwrap_or_else(|error| panic!("Could not add deserialized scene to world: {error}"));
57+
58+
// TODO (Wybe 2023-01-22): Ideally we'd check whether the input and output world are exactly equal. But the world does not implement Eq.
59+
// so instead we check the serialized outputs against each other. However, this will miss anything that fails to serialize in the first place.
60+
61+
let type_registry = input_app.world.resource::<AppTypeRegistry>();
62+
let scene = DynamicScene::from_world(&input_app.world, type_registry);
63+
let serialized_again = serialize(scene, type_registry);
64+
65+
assert_eq!(serialized, serialized_again);
66+
}
67+
68+
fn serialize_world_ron(scene: DynamicScene, type_registry: &AppTypeRegistry) -> Vec<u8> {
69+
scene
70+
.serialize_ron(type_registry)
71+
.map(|output| output.as_bytes().to_vec())
72+
.unwrap_or_else(|error| panic!("Scene failed to serialize: {error}"))
73+
}
74+
75+
fn deserialize_world_ron(scene_deserializer: SceneDeserializer, input: &[u8]) -> DynamicScene {
76+
let mut deserializer = ron::de::Deserializer::from_bytes(input)
77+
.unwrap_or_else(|error| panic!("Scene failed to deserialize: {error}"));
78+
scene_deserializer
79+
.deserialize(&mut deserializer)
80+
.unwrap_or_else(|error| panic!("Scene failed to deserialize: {error}"))
81+
}
82+
83+
fn serialize_world_postcard(scene: DynamicScene, type_registry: &AppTypeRegistry) -> Vec<u8> {
84+
let scene_serializer = SceneSerializer::new(&scene, &type_registry.0);
85+
postcard::to_allocvec(&scene_serializer)
86+
.unwrap_or_else(|error| panic!("Scene failed to serialize: {error}"))
87+
}
88+
89+
fn deserialize_world_postcard(scene_deserializer: SceneDeserializer, input: &[u8]) -> DynamicScene {
90+
let mut deserializer = postcard::Deserializer::from_bytes(input);
91+
scene_deserializer
92+
.deserialize(&mut deserializer)
93+
.unwrap_or_else(|error| panic!("Scene failed to deserialize: {error}"))
94+
}
95+
96+
fn serialize_world_bincode(scene: DynamicScene, type_registry: &AppTypeRegistry) -> Vec<u8> {
97+
let scene_serializer = SceneSerializer::new(&scene, &type_registry.0);
98+
bincode::serialize(&scene_serializer)
99+
.unwrap_or_else(|error| panic!("Scene failed to serialize: {error}"))
100+
}
101+
102+
fn deserialize_world_bincode(scene_deserializer: SceneDeserializer, input: &[u8]) -> DynamicScene {
103+
bincode::DefaultOptions::new()
104+
.with_fixint_encoding()
105+
.deserialize_seed(scene_deserializer, input)
106+
.unwrap_or_else(|error| panic!("Scene failed to deserialize: {error}"))
107+
}
108+
109+
fn serialize_world_messagepack(scene: DynamicScene, type_registry: &AppTypeRegistry) -> Vec<u8> {
110+
let scene_serializer = SceneSerializer::new(&scene, &type_registry.0);
111+
let mut buf = Vec::new();
112+
let mut ser = rmp_serde::Serializer::new(&mut buf);
113+
scene_serializer
114+
.serialize(&mut ser)
115+
.unwrap_or_else(|error| panic!("Scene failed to serialize: {error}"));
116+
buf
117+
}
118+
119+
fn deserialize_world_messagepack(
120+
scene_deserializer: SceneDeserializer,
121+
input: &[u8],
122+
) -> DynamicScene {
123+
let mut reader = BufReader::new(input);
124+
125+
scene_deserializer
126+
.deserialize(&mut rmp_serde::Deserializer::new(&mut reader))
127+
.unwrap_or_else(|error| panic!("Scene failed to deserialize: {error}"))
128+
}
129+
130+
fn create_test_app() -> App {
131+
let mut app = App::new();
132+
app.add_plugins(MinimalPlugins)
133+
.add_plugin(AssetPlugin::default())
134+
.add_plugin(ScenePlugin::default())
135+
.add_plugin(TransformPlugin::default())
136+
.register_type::<ReferenceComponent>()
137+
.register_type::<Option<Entity>>()
138+
.register_type::<VectorComponent>()
139+
.register_type::<TupleComponent>()
140+
// TODO (Wcubed 2023-01-22): Without the `Vec` registrations, the serialization
141+
// works. But the de-serialization fails. This does not sound correct.
142+
// Either both should fail, or both should work.
143+
.register_type::<Vec<u32>>()
144+
.register_type::<Vec<String>>()
145+
// TODO (Wcubed 2023-01-22): Without these tuple registrations, the serialization
146+
// works. But the de-serialization fails. This does not sound correct.
147+
// Either both should fail, or both should work.
148+
.register_type::<(i32, String, f32)>()
149+
.register_type::<(bool, bool, u32)>();
150+
151+
app
152+
}
153+
154+
fn spawn_test_entities(app: &mut App) {
155+
let entity_1 = app.world.spawn(TransformBundle::default()).id();
156+
app.world.spawn(ReferenceComponent(Some(entity_1)));
157+
158+
app.world
159+
.spawn(VectorComponent {
160+
integer_vector: vec![1, 2, 3, 4, 5, 123456789],
161+
// Testing different characters in strings
162+
string_vector: vec![
163+
// Basic string
164+
"Hello World!".to_string(),
165+
// Common special characters
166+
"!@#$%^&*(){}[]-=_+\\|,.<>/?;:'\"`~".to_string(),
167+
// Emoji
168+
"😄🌲🕊️🐧🏁".to_string(),
169+
// Chinese characters
170+
"月亮太阳".to_string(),
171+
// Non-breaking space.
172+
" ".to_string(),
173+
],
174+
})
175+
.insert(TupleComponent(
176+
(-12, "A tuple".to_string(), 2.345),
177+
(true, false, 0),
178+
));
179+
}
180+
181+
/// Tests if Entity ids survive serialization.
182+
#[derive(Component, Reflect, Default)]
183+
#[reflect(Component)]
184+
struct ReferenceComponent(Option<Entity>);
185+
186+
/// Tests if vectors survive serialization.
187+
#[derive(Component, Reflect, Default)]
188+
#[reflect(Component)]
189+
struct VectorComponent {
190+
integer_vector: Vec<u32>,
191+
string_vector: Vec<String>,
192+
}
193+
194+
/// Tests if tuples survive serialization.
195+
#[derive(Component, Reflect, Default)]
196+
#[reflect(Component)]
197+
struct TupleComponent((i32, String, f32), (bool, bool, u32));

tests/scenes/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mod components;

0 commit comments

Comments
 (0)