/// Basic tests for the #[synced] attribute macro use bevy::prelude::*; // Test 1: Basic struct with synced attribute compiles #[macros::synced] struct Health { current: f32, } #[test] fn test_health_compiles() { let health = Health { current: 100.0 }; assert_eq!(health.current, 100.0); } #[test] fn test_health_has_component_trait() { // The synced macro should automatically derive Component let health = Health { current: 100.0 }; // Can insert into Bevy world let mut world = World::new(); let entity = world.spawn(health).id(); // Can query it back let health_ref = world.get::(entity).unwrap(); assert_eq!(health_ref.current, 100.0); } #[test] fn test_health_rkyv_serialization() { let health = Health { current: 100.0 }; // Test rkyv serialization (which the synced macro adds) let bytes = rkyv::to_bytes::(&health) .expect("Should serialize with rkyv"); let deserialized: Health = rkyv::from_bytes::(&bytes) .expect("Should deserialize with rkyv"); assert_eq!(deserialized.current, health.current); } #[test] fn test_health_is_clone_and_copy() { let health = Health { current: 100.0 }; // Test Clone let cloned = health.clone(); assert_eq!(cloned.current, health.current); // Test Copy (implicit through assignment) let copied = health; assert_eq!(copied.current, health.current); // Original still valid after copy assert_eq!(health.current, 100.0); } // Test 2: Struct with multiple fields #[macros::synced] struct Position { x: f32, y: f32, } #[test] fn test_position_compiles() { let pos = Position { x: 10.0, y: 20.0 }; assert_eq!(pos.x, 10.0); assert_eq!(pos.y, 20.0); } #[test] fn test_position_rkyv_serialization() { let pos = Position { x: 10.0, y: 20.0 }; let bytes = rkyv::to_bytes::(&pos) .expect("Should serialize with rkyv"); let deserialized: Position = rkyv::from_bytes::(&bytes) .expect("Should deserialize with rkyv"); assert_eq!(deserialized.x, pos.x); assert_eq!(deserialized.y, pos.y); } #[test] fn test_position_in_bevy_world() { let pos = Position { x: 10.0, y: 20.0 }; let mut world = World::new(); let entity = world.spawn(pos).id(); let pos_ref = world.get::(entity).unwrap(); assert_eq!(pos_ref.x, 10.0); assert_eq!(pos_ref.y, 20.0); } // Test 3: Component registration in type registry // This test verifies that the inventory::submit! generated by the macro works #[test] fn test_component_registry_has_health() { use libmarathon::persistence::ComponentTypeRegistry; let registry = ComponentTypeRegistry::init(); // The macro should have registered Health let type_id = std::any::TypeId::of::(); let discriminant = registry.get_discriminant(type_id); assert!(discriminant.is_some(), "Health should be registered in ComponentTypeRegistry"); // Check the type name let type_name = registry.get_type_name(discriminant.unwrap()); assert_eq!(type_name, Some("Health")); } #[test] fn test_component_registry_has_position() { use libmarathon::persistence::ComponentTypeRegistry; let registry = ComponentTypeRegistry::init(); let type_id = std::any::TypeId::of::(); let discriminant = registry.get_discriminant(type_id); assert!(discriminant.is_some(), "Position should be registered in ComponentTypeRegistry"); // Check the type name let type_name = registry.get_type_name(discriminant.unwrap()); assert_eq!(type_name, Some("Position")); } // Test 4: End-to-end serialization via ComponentTypeRegistry #[test] fn test_registry_serialization_roundtrip() { use libmarathon::persistence::ComponentTypeRegistry; let mut world = World::new(); let entity = world.spawn(Health { current: 75.0 }).id(); let registry = ComponentTypeRegistry::init(); let type_id = std::any::TypeId::of::(); let discriminant = registry.get_discriminant(type_id).unwrap(); // Serialize using the registry let serialize_fn = registry.get_discriminant(type_id) .and_then(|disc| { // Get serializer from the registry internals // We'll use the serialization method from the registry let serializer = world.get::(entity).map(|component| { rkyv::to_bytes::(component) .expect("Should serialize") .to_vec() }); serializer }) .expect("Should serialize Health component"); // Deserialize using the registry let deserialize_fn = registry.get_deserialize_fn(discriminant) .expect("Should have deserialize function"); let boxed = deserialize_fn(&serialize_fn) .expect("Should deserialize Health component"); let health = boxed.downcast::() .expect("Should downcast to Health"); assert_eq!(health.current, 75.0); }