test: Add interaction tests
This commit is contained in:
170
tests/interaction.rs
Normal file
170
tests/interaction.rs
Normal file
@@ -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::<Grid>().get_tile((x, y)) {
|
||||||
|
*app.world_mut().get_mut::<TileState>(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<Grid>,
|
||||||
|
mut tile_query: Query<&mut TileState>,
|
||||||
|
mut inventory: ResMut<Inventory>,
|
||||||
|
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::<Grid>();
|
||||||
|
let tile_entity = grid.get_tile((1, 1)).unwrap();
|
||||||
|
let tile_state = app.world().entity(tile_entity).get::<TileState>().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::<Inventory>();
|
||||||
|
// 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::<ItemStack>() {
|
||||||
|
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<Grid>,
|
||||||
|
mut tile_query: Query<&mut TileState>,
|
||||||
|
mut inventory: ResMut<Inventory>,
|
||||||
|
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::<Grid>();
|
||||||
|
let tile_entity = grid.get_tile((1, 1)).unwrap();
|
||||||
|
let tile_state = app.world().entity(tile_entity).get::<TileState>().unwrap();
|
||||||
|
|
||||||
|
if let TileState::Empty = tile_state {
|
||||||
|
// Correct
|
||||||
|
} else {
|
||||||
|
panic!("Tile should remain Empty, found {:?}", tile_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user