From 16118a19706ce57624132d1d389c0af34bc3c5b2 Mon Sep 17 00:00:00 2001 From: demenik Date: Tue, 2 Dec 2025 12:54:42 +0100 Subject: [PATCH] test: Add interaction tests --- tests/interaction.rs | 170 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 tests/interaction.rs diff --git a/tests/interaction.rs b/tests/interaction.rs new file mode 100644 index 0000000..39a383e --- /dev/null +++ b/tests/interaction.rs @@ -0,0 +1,170 @@ +use bevy::ecs::system::RunSystemOnce; +use pomomon_garden::features::grid::components::{Grid, Tile, TileState}; +use pomomon_garden::features::inventory::components::{Inventory, ItemStack, ItemType}; +use pomomon_garden::features::pom::actions::InteractionAction; +use pomomon_garden::prelude::*; + +fn setup_interaction_app( + grid_width: u32, + grid_height: u32, + initial_tile_states: &[(u32, u32, TileState)], + initial_inventory: Vec<(ItemType, u32)>, +) -> App { + let mut app = App::new(); + app.add_plugins(MinimalPlugins); + app.add_plugins(AssetPlugin::default()); // Needed for asset server if used, though we mock or avoid visuals here + + // Grid Setup + let mut grid_tiles = Vec::with_capacity(grid_width as usize); + for x in 0..grid_width { + let mut column = Vec::with_capacity(grid_height as usize); + for y in 0..grid_height { + let entity = app + .world_mut() + .spawn((Tile { x, y }, TileState::Unclaimed)) + .id(); + column.push(entity); + } + grid_tiles.push(column); + } + app.world_mut().insert_resource(Grid { + width: grid_width, + height: grid_height, + tiles: grid_tiles, + }); + + for &(x, y, ref state) in initial_tile_states { + if let Ok(entity) = app.world().resource::().get_tile((x, y)) { + *app.world_mut().get_mut::(entity).unwrap() = state.clone(); + } + } + + // Inventory Setup + let mut inventory_items = Vec::new(); + for (item_type, amount) in initial_inventory { + let id = app.world_mut().spawn(ItemStack { item_type, amount }).id(); + inventory_items.push(id); + } + app.world_mut().insert_resource(Inventory { + items: inventory_items, + }); + + app +} + +#[test] +fn test_plant_seed_interaction() { + let seed_type = ItemType::BerrySeed { + name: "TestSeed".into(), + }; + let mut app = setup_interaction_app( + 3, + 3, + &[(1, 1, TileState::Empty)], + vec![(seed_type.clone(), 1)], + ); + + // Run the interaction logic as a system or closure + app.world_mut().run_system_once( + move |grid: Res, + mut tile_query: Query<&mut TileState>, + mut inventory: ResMut, + mut item_stack_query: Query<&mut ItemStack>, + mut commands: Commands| { + let action = InteractionAction::Plant(seed_type.clone()); + action.execute( + (1, 1), + &grid, + &mut tile_query, + &mut inventory, + &mut item_stack_query, + &mut commands, + ); + }, + ); + + // Apply commands (despawns etc.) + app.update(); + + // Assert Tile State + let grid = app.world().resource::(); + let tile_entity = grid.get_tile((1, 1)).unwrap(); + let tile_state = app.world().entity(tile_entity).get::().unwrap(); + + if let TileState::Occupied { seed } = tile_state { + assert_eq!( + *seed, + ItemType::BerrySeed { + name: "TestSeed".into() + } + ); + } else { + panic!("Tile should be Occupied with seed, found {:?}", tile_state); + } + + // Assert Inventory Empty + let inventory = app.world().resource::(); + // Item stack entity should be despawned or amount 0 + if !inventory.items.is_empty() { + // If the entity still exists, check amount + if let Some(entity) = inventory.items.first() { + if let Some(stack) = app.world().entity(*entity).get::() { + assert_eq!(stack.amount, 0, "Item amount should be 0"); + } else { + // Entity might be despawned but still in inventory list until cleanup? + // Inventory struct implementation removes it from vector if using update_item_stack properly? + // update_item_stack does `self.items.remove(index);` + // So the list should be empty. + panic!( + "Inventory items list should be empty or point to valid 0 amount entities. Found phantom entity." + ); + } + } + } else { + assert!(inventory.items.is_empty()); + } +} + +#[test] +fn test_plant_seed_no_inventory() { + let seed_type = ItemType::BerrySeed { + name: "TestSeed".into(), + }; + let mut app = setup_interaction_app( + 3, + 3, + &[(1, 1, TileState::Empty)], + vec![], // Empty inventory + ); + + app.world_mut().run_system_once( + move |grid: Res, + mut tile_query: Query<&mut TileState>, + mut inventory: ResMut, + mut item_stack_query: Query<&mut ItemStack>, + mut commands: Commands| { + let action = InteractionAction::Plant(seed_type.clone()); + action.execute( + (1, 1), + &grid, + &mut tile_query, + &mut inventory, + &mut item_stack_query, + &mut commands, + ); + }, + ); + + app.update(); + + // Assert Tile State Unchanged + let grid = app.world().resource::(); + let tile_entity = grid.get_tile((1, 1)).unwrap(); + let tile_state = app.world().entity(tile_entity).get::().unwrap(); + + if let TileState::Empty = tile_state { + // Correct + } else { + panic!("Tile should remain Empty, found {:?}", tile_state); + } +}