diff --git a/Justfile b/Justfile index 112c74f..743b4c5 100644 --- a/Justfile +++ b/Justfile @@ -3,7 +3,7 @@ set windows-shell := ["powershell.exe", "-NoLogo", "-Command"] # Regex to exclude files from coverage report, double escapes for Justfile + CLI # You can use src\\\\..., but the filename alone is acceptable too -coverage_exclude_pattern := "src\\\\app.rs|audio.rs|src\\\\error.rs|platform\\\\emscripten.rs" +coverage_exclude_pattern := "src\\\\app\\.rs|audio\\.rs|src\\\\error\\.rs|platform\\\\emscripten\\.rs|bin\\\\.+\\.rs|main\\.rs|platform\\\\desktop\\.rs|platform\\\\tracing_buffer\\.rs|platform\\\\buffered_writer\\.rs|systems\\\\debug\\.rs|systems\\\\profiling\\.rs" binary_extension := if os() == "windows" { ".exe" } else { "" } diff --git a/tests/animated.rs b/tests/animated.rs deleted file mode 100644 index fa0f649..0000000 --- a/tests/animated.rs +++ /dev/null @@ -1,57 +0,0 @@ -// use glam::U16Vec2; -// use pacman::error::{AnimatedTextureError, GameError, TextureError}; -// use pacman::texture::sprite::AtlasTile; -// use sdl2::pixels::Color; -// use smallvec::smallvec; - -// fn mock_atlas_tile(id: u32) -> AtlasTile { -// AtlasTile { -// pos: U16Vec2::new(0, 0), -// size: U16Vec2::new(16, 16), -// color: Some(Color::RGB(id as u8, 0, 0)), -// } -// } - -// #[test] -// fn test_animated_texture_creation_errors() { -// let tiles = smallvec![mock_atlas_tile(1), mock_atlas_tile(2)]; - -// assert!(matches!( -// AnimatedTexture::new(tiles.clone(), 0).unwrap_err(), -// GameError::Texture(TextureError::Animated(AnimatedTextureError::InvalidFrameDuration(0))) -// )); -// } - -// #[test] -// fn test_animated_texture_advancement() { -// let tiles = smallvec![mock_atlas_tile(1), mock_atlas_tile(2), mock_atlas_tile(3)]; -// let mut texture = AnimatedTexture::new(tiles, 10).unwrap(); - -// assert_eq!(texture.current_frame(), 0); - -// texture.tick(25); -// assert_eq!(texture.current_frame(), 2); -// assert_eq!(texture.time_bank(), 5); -// } - -// #[test] -// fn test_animated_texture_wrap_around() { -// let tiles = smallvec![mock_atlas_tile(1), mock_atlas_tile(2)]; -// let mut texture = AnimatedTexture::new(tiles, 10).unwrap(); - -// texture.tick(10); -// assert_eq!(texture.current_frame(), 1); - -// texture.tick(10); -// assert_eq!(texture.current_frame(), 0); -// } - -// #[test] -// fn test_animated_texture_single_frame() { -// let tiles = smallvec![mock_atlas_tile(1)]; -// let mut texture = AnimatedTexture::new(tiles, 10).unwrap(); - -// texture.tick(10); -// assert_eq!(texture.current_frame(), 0); -// assert_eq!(texture.current_tile().color.unwrap().r, 1); -// } diff --git a/tests/blinking.rs b/tests/blinking.rs index 36a41a5..0f91891 100644 --- a/tests/blinking.rs +++ b/tests/blinking.rs @@ -1,19 +1,10 @@ -use glam::U16Vec2; use pacman::texture::blinking::BlinkingTexture; -use pacman::texture::sprite::AtlasTile; -use sdl2::pixels::Color; -fn mock_atlas_tile(id: u32) -> AtlasTile { - AtlasTile { - pos: U16Vec2::new(0, 0), - size: U16Vec2::new(16, 16), - color: Some(Color::RGB(id as u8, 0, 0)), - } -} +mod common; #[test] fn test_blinking_texture() { - let tile = mock_atlas_tile(1); + let tile = common::mock_atlas_tile(1); let mut texture = BlinkingTexture::new(tile, 0.5); assert!(texture.is_on()); @@ -30,7 +21,7 @@ fn test_blinking_texture() { #[test] fn test_blinking_texture_partial_duration() { - let tile = mock_atlas_tile(1); + let tile = common::mock_atlas_tile(1); let mut texture = BlinkingTexture::new(tile, 0.5); texture.tick(0.625); @@ -40,7 +31,7 @@ fn test_blinking_texture_partial_duration() { #[test] fn test_blinking_texture_negative_time() { - let tile = mock_atlas_tile(1); + let tile = common::mock_atlas_tile(1); let mut texture = BlinkingTexture::new(tile, 0.5); texture.tick(-0.1); diff --git a/tests/collision.rs b/tests/collision.rs index 3531f17..25979a2 100644 --- a/tests/collision.rs +++ b/tests/collision.rs @@ -1,73 +1,7 @@ -use bevy_ecs::{entity::Entity, event::Events, system::RunSystemOnce, world::World}; +use bevy_ecs::system::RunSystemOnce; +use pacman::systems::{check_collision, collision_system, Collider, EntityType, GhostState, Position}; -use pacman::{ - error::GameError, - events::GameEvent, - map::builder::Map, - systems::{ - check_collision, collision_system, Collider, EntityType, Ghost, GhostCollider, ItemCollider, NodeId, PacmanCollider, - Position, - }, -}; - -fn create_test_world() -> World { - let mut world = World::new(); - - // Add required resources - world.insert_resource(Events::::default()); - world.insert_resource(Events::::default()); - - // Add a minimal test map - world.insert_resource(create_test_map()); - - world -} - -fn create_test_map() -> Map { - use pacman::constants::RAW_BOARD; - Map::new(RAW_BOARD).expect("Failed to create test map") -} - -fn spawn_test_pacman(world: &mut World) -> Entity { - world - .spawn((Position::Stopped { node: 0 }, Collider { size: 10.0 }, PacmanCollider)) - .id() -} - -fn spawn_test_item(world: &mut World) -> Entity { - world - .spawn(( - Position::Stopped { node: 0 }, - Collider { size: 8.0 }, - ItemCollider, - EntityType::Pellet, - )) - .id() -} - -fn spawn_test_ghost(world: &mut World) -> Entity { - world - .spawn(( - Position::Stopped { node: 0 }, - Collider { size: 12.0 }, - GhostCollider, - Ghost::Blinky, - EntityType::Ghost, - )) - .id() -} - -fn spawn_test_ghost_at_node(world: &mut World, node: usize) -> Entity { - world - .spawn(( - Position::Stopped { node: node as NodeId }, - Collider { size: 12.0 }, - GhostCollider, - Ghost::Blinky, - EntityType::Ghost, - )) - .id() -} +mod common; #[test] fn test_collider_collision_detection() { @@ -81,7 +15,7 @@ fn test_collider_collision_detection() { #[test] fn test_check_collision_helper() { - let map = create_test_map(); + let map = common::create_test_map(); let pos1 = Position::Stopped { node: 0 }; let pos2 = Position::Stopped { node: 0 }; // Same position let collider1 = Collider { size: 10.0 }; @@ -101,9 +35,9 @@ fn test_check_collision_helper() { #[test] fn test_collision_system_pacman_item() { - let mut world = create_test_world(); - let _pacman = spawn_test_pacman(&mut world); - let _item = spawn_test_item(&mut world); + let mut world = common::create_test_world(); + let _pacman = common::spawn_test_pacman(&mut world, 0); + let _item = common::spawn_test_item(&mut world, 0, EntityType::Pellet); // Run collision system - should not panic world @@ -113,9 +47,9 @@ fn test_collision_system_pacman_item() { #[test] fn test_collision_system_pacman_ghost() { - let mut world = create_test_world(); - let _pacman = spawn_test_pacman(&mut world); - let _ghost = spawn_test_ghost(&mut world); + let mut world = common::create_test_world(); + let _pacman = common::spawn_test_pacman(&mut world, 0); + let _ghost = common::spawn_test_ghost(&mut world, 0, GhostState::Normal); // Run collision system - should not panic world @@ -125,9 +59,9 @@ fn test_collision_system_pacman_ghost() { #[test] fn test_collision_system_no_collision() { - let mut world = create_test_world(); - let _pacman = spawn_test_pacman(&mut world); - let _ghost = spawn_test_ghost_at_node(&mut world, 1); // Different node + let mut world = common::create_test_world(); + let _pacman = common::spawn_test_pacman(&mut world, 0); + let _ghost = common::spawn_test_ghost(&mut world, 1, GhostState::Normal); // Different node // Run collision system - should not panic world @@ -137,10 +71,10 @@ fn test_collision_system_no_collision() { #[test] fn test_collision_system_multiple_entities() { - let mut world = create_test_world(); - let _pacman = spawn_test_pacman(&mut world); - let _item = spawn_test_item(&mut world); - let _ghost = spawn_test_ghost(&mut world); + let mut world = common::create_test_world(); + let _pacman = common::spawn_test_pacman(&mut world, 0); + let _item = common::spawn_test_item(&mut world, 0, EntityType::Pellet); + let _ghost = common::spawn_test_ghost(&mut world, 0, GhostState::Normal); // Run collision system - should not panic world diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 98e211a..18dd82b 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,12 +1,26 @@ #![allow(dead_code)] +use bevy_ecs::{entity::Entity, event::Events, world::World}; +use glam::{U16Vec2, Vec2}; use pacman::{ asset::{get_asset_bytes, Asset}, + constants::RAW_BOARD, + events::GameEvent, game::ATLAS_FRAMES, - texture::sprite::{AtlasMapper, SpriteAtlas}, + map::{ + builder::Map, + direction::Direction, + graph::{Graph, Node}, + }, + systems::{ + AudioEvent, AudioState, BufferedDirection, Collider, DebugState, DeltaTime, EntityType, Ghost, GhostCollider, GhostState, + GlobalState, ItemCollider, MovementModifiers, PacmanCollider, PlayerControlled, Position, ScoreResource, Velocity, + }, + texture::sprite::{AtlasMapper, AtlasTile, SpriteAtlas}, }; use sdl2::{ image::LoadTexture, + pixels::Color, render::{Canvas, TextureCreator}, video::{Window, WindowContext}, Sdl, @@ -38,3 +52,122 @@ pub fn create_atlas(canvas: &mut sdl2::render::Canvas) -> S SpriteAtlas::new(texture, atlas_mapper) } + +/// Creates a simple test graph with 3 connected nodes for testing +pub fn create_test_graph() -> Graph { + let mut graph = Graph::new(); + + let node0 = graph.add_node(Node { + position: Vec2::new(0.0, 0.0), + }); + let node1 = graph.add_node(Node { + position: Vec2::new(16.0, 0.0), + }); + let node2 = graph.add_node(Node { + position: Vec2::new(0.0, 16.0), + }); + + graph.connect(node0, node1, false, None, Direction::Right).unwrap(); + graph.connect(node0, node2, false, None, Direction::Down).unwrap(); + + graph +} + +/// Creates a basic test world with required resources for ECS systems +pub fn create_test_world() -> World { + let mut world = World::new(); + + // Add required resources + world.insert_resource(Events::::default()); + world.insert_resource(Events::::default()); + world.insert_resource(Events::::default()); + world.insert_resource(ScoreResource(0)); + world.insert_resource(AudioState::default()); + world.insert_resource(GlobalState { exit: false }); + world.insert_resource(DebugState::default()); + world.insert_resource(DeltaTime(1.0 / 60.0)); // 60 FPS + world.insert_resource(create_test_map()); + + world +} + +/// Creates a test map using the default RAW_BOARD +pub fn create_test_map() -> Map { + Map::new(RAW_BOARD).expect("Failed to create test map") +} + +/// Spawns a test Pac-Man entity at the specified node +pub fn spawn_test_pacman(world: &mut World, node: usize) -> Entity { + world + .spawn(( + Position::Stopped { node: node as u16 }, + Collider { size: 10.0 }, + PacmanCollider, + EntityType::Player, + )) + .id() +} + +/// Spawns a controllable test player entity +pub fn spawn_test_player(world: &mut World, node: usize) -> Entity { + world + .spawn(( + PlayerControlled, + Position::Stopped { node: node as u16 }, + Velocity { + speed: 1.0, + direction: Direction::Right, + }, + BufferedDirection::None, + EntityType::Player, + MovementModifiers::default(), + )) + .id() +} + +/// Spawns a test item entity at the specified node +pub fn spawn_test_item(world: &mut World, node: usize, item_type: EntityType) -> Entity { + world + .spawn(( + Position::Stopped { node: node as u16 }, + Collider { size: 8.0 }, + ItemCollider, + item_type, + )) + .id() +} + +/// Spawns a test ghost entity at the specified node +pub fn spawn_test_ghost(world: &mut World, node: usize, ghost_state: GhostState) -> Entity { + world + .spawn(( + Position::Stopped { node: node as u16 }, + Collider { size: 12.0 }, + GhostCollider, + Ghost::Blinky, + EntityType::Ghost, + ghost_state, + )) + .id() +} + +/// Sends a game event to the world +pub fn send_game_event(world: &mut World, event: GameEvent) { + let mut events = world.resource_mut::>(); + events.send(event); +} + +/// Sends a collision event between two entities +pub fn send_collision_event(world: &mut World, entity1: Entity, entity2: Entity) { + let mut events = world.resource_mut::>(); + events.send(GameEvent::Collision(entity1, entity2)); +} + +/// Creates a mock atlas tile for testing +pub fn mock_atlas_tile(id: u32) -> AtlasTile { + AtlasTile { + pos: U16Vec2::new(0, 0), + size: U16Vec2::new(16, 16), + color: Some(Color::RGB(id as u8, 0, 0)), + } +} diff --git a/tests/events.rs b/tests/events.rs deleted file mode 100644 index 1af42ad..0000000 --- a/tests/events.rs +++ /dev/null @@ -1,19 +0,0 @@ -use pacman::events::{GameCommand, GameEvent}; -use pacman::map::direction::Direction; - -#[test] -fn test_game_command_to_game_event_conversion_all_variants() { - let commands = vec![ - GameCommand::Exit, - GameCommand::MovePlayer(Direction::Up), - GameCommand::ToggleDebug, - GameCommand::MuteAudio, - GameCommand::ResetLevel, - GameCommand::TogglePause, - ]; - - for command in commands { - let event: GameEvent = command.into(); - assert_eq!(event, GameEvent::Command(command)); - } -} diff --git a/tests/graph.rs b/tests/graph.rs index 04e78d6..0212430 100644 --- a/tests/graph.rs +++ b/tests/graph.rs @@ -1,23 +1,7 @@ use pacman::map::direction::Direction; use pacman::map::graph::{Graph, Node, TraversalFlags}; -fn create_test_graph() -> Graph { - let mut graph = Graph::new(); - let node1 = graph.add_node(Node { - position: glam::Vec2::new(0.0, 0.0), - }); - let node2 = graph.add_node(Node { - position: glam::Vec2::new(16.0, 0.0), - }); - let node3 = graph.add_node(Node { - position: glam::Vec2::new(0.0, 16.0), - }); - - graph.connect(node1, node2, false, None, Direction::Right).unwrap(); - graph.connect(node1, node3, false, None, Direction::Down).unwrap(); - - graph -} +mod common; #[test] fn test_graph_basic_operations() { @@ -124,14 +108,14 @@ fn should_error_on_negative_edge_distance() { #[test] fn should_error_on_duplicate_edge_without_replace() { - let mut graph = create_test_graph(); + let mut graph = common::create_test_graph(); let result = graph.add_edge(0, 1, false, None, Direction::Right, TraversalFlags::ALL); assert!(result.is_err()); } #[test] fn should_allow_replacing_an_edge() { - let mut graph = create_test_graph(); + let mut graph = common::create_test_graph(); let result = graph.add_edge(0, 1, true, Some(42.0), Direction::Right, TraversalFlags::ALL); assert!(result.is_ok()); @@ -141,7 +125,7 @@ fn should_allow_replacing_an_edge() { #[test] fn should_find_edge_between_nodes() { - let graph = create_test_graph(); + let graph = common::create_test_graph(); let edge = graph.find_edge(0, 1); assert!(edge.is_some()); assert_eq!(edge.unwrap().target, 1); diff --git a/tests/hud.rs b/tests/hud.rs deleted file mode 100644 index 9b046fc..0000000 --- a/tests/hud.rs +++ /dev/null @@ -1,26 +0,0 @@ -use bevy_ecs::{event::Events, world::World}; - -use pacman::{error::GameError, systems::components::ScoreResource}; - -fn create_test_world() -> World { - let mut world = World::new(); - - // Add required resources - world.insert_resource(Events::::default()); - world.insert_resource(ScoreResource(1230)); // Test score - - world -} - -#[test] -fn test_hud_render_system_runs_without_error() { - let world = create_test_world(); - - // The HUD render system requires SDL2 resources that aren't available in tests, - // but we can at least verify it doesn't panic when called - // In a real test environment, we'd need to mock the SDL2 canvas and atlas - - // For now, just verify the score resource is accessible - let score = world.resource::(); - assert_eq!(score.0, 1230); -} diff --git a/tests/item.rs b/tests/item.rs index f1b229f..e0dc19f 100644 --- a/tests/item.rs +++ b/tests/item.rs @@ -1,13 +1,7 @@ -use bevy_ecs::{entity::Entity, event::Events, system::RunSystemOnce, world::World}; +use bevy_ecs::{entity::Entity, system::RunSystemOnce}; +use pacman::systems::{is_valid_item_collision, item_system, EntityType, GhostState, Position, ScoreResource}; -use pacman::{ - events::GameEvent, - map::builder::Map, - systems::{ - is_valid_item_collision, item_system, AudioEvent, AudioState, EntityType, Ghost, GhostCollider, GhostState, ItemCollider, - PacmanCollider, Position, ScoreResource, - }, -}; +mod common; #[test] fn test_calculate_score_for_item() { @@ -44,62 +38,14 @@ fn test_is_valid_item_collision() { assert!(!is_valid_item_collision(EntityType::Player, EntityType::Player)); } -fn create_test_world() -> World { - let mut world = World::new(); - - // Add required resources - world.insert_resource(ScoreResource(0)); - world.insert_resource(AudioState::default()); - world.insert_resource(Events::::default()); - world.insert_resource(Events::::default()); - world.insert_resource(Events::::default()); - - // Add a minimal test map - world.insert_resource(create_test_map()); - - world -} - -fn create_test_map() -> Map { - use pacman::constants::RAW_BOARD; - Map::new(RAW_BOARD).expect("Failed to create test map") -} - -fn spawn_test_pacman(world: &mut World) -> Entity { - world - .spawn((Position::Stopped { node: 0 }, EntityType::Player, PacmanCollider)) - .id() -} - -fn spawn_test_item(world: &mut World, item_type: EntityType) -> Entity { - world.spawn((Position::Stopped { node: 1 }, item_type, ItemCollider)).id() -} - -fn spawn_test_ghost(world: &mut World, ghost_state: GhostState) -> Entity { - world - .spawn(( - Position::Stopped { node: 2 }, - Ghost::Blinky, - EntityType::Ghost, - GhostCollider, - ghost_state, - )) - .id() -} - -fn send_collision_event(world: &mut World, entity1: Entity, entity2: Entity) { - let mut events = world.resource_mut::>(); - events.send(GameEvent::Collision(entity1, entity2)); -} - #[test] fn test_item_system_pellet_collection() { - let mut world = create_test_world(); - let pacman = spawn_test_pacman(&mut world); - let pellet = spawn_test_item(&mut world, EntityType::Pellet); + let mut world = common::create_test_world(); + let pacman = common::spawn_test_pacman(&mut world, 0); + let pellet = common::spawn_test_item(&mut world, 1, EntityType::Pellet); // Send collision event - send_collision_event(&mut world, pacman, pellet); + common::send_collision_event(&mut world, pacman, pellet); // Run the item system world.run_system_once(item_system).expect("System should run successfully"); @@ -119,11 +65,11 @@ fn test_item_system_pellet_collection() { #[test] fn test_item_system_power_pellet_collection() { - let mut world = create_test_world(); - let pacman = spawn_test_pacman(&mut world); - let power_pellet = spawn_test_item(&mut world, EntityType::PowerPellet); + let mut world = common::create_test_world(); + let pacman = common::spawn_test_pacman(&mut world, 0); + let power_pellet = common::spawn_test_item(&mut world, 1, EntityType::PowerPellet); - send_collision_event(&mut world, pacman, power_pellet); + common::send_collision_event(&mut world, pacman, power_pellet); world.run_system_once(item_system).expect("System should run successfully"); @@ -142,16 +88,16 @@ fn test_item_system_power_pellet_collection() { #[test] fn test_item_system_multiple_collections() { - let mut world = create_test_world(); - let pacman = spawn_test_pacman(&mut world); - let pellet1 = spawn_test_item(&mut world, EntityType::Pellet); - let pellet2 = spawn_test_item(&mut world, EntityType::Pellet); - let power_pellet = spawn_test_item(&mut world, EntityType::PowerPellet); + let mut world = common::create_test_world(); + let pacman = common::spawn_test_pacman(&mut world, 0); + let pellet1 = common::spawn_test_item(&mut world, 1, EntityType::Pellet); + let pellet2 = common::spawn_test_item(&mut world, 2, EntityType::Pellet); + let power_pellet = common::spawn_test_item(&mut world, 3, EntityType::PowerPellet); // Send multiple collision events - send_collision_event(&mut world, pacman, pellet1); - send_collision_event(&mut world, pacman, pellet2); - send_collision_event(&mut world, pacman, power_pellet); + common::send_collision_event(&mut world, pacman, pellet1); + common::send_collision_event(&mut world, pacman, pellet2); + common::send_collision_event(&mut world, pacman, power_pellet); world.run_system_once(item_system).expect("System should run successfully"); @@ -176,8 +122,8 @@ fn test_item_system_multiple_collections() { #[test] fn test_item_system_ignores_non_item_collisions() { - let mut world = create_test_world(); - let pacman = spawn_test_pacman(&mut world); + let mut world = common::create_test_world(); + let pacman = common::spawn_test_pacman(&mut world, 0); // Create a ghost entity (not an item) let ghost = world.spawn((Position::Stopped { node: 2 }, EntityType::Ghost)).id(); @@ -186,7 +132,7 @@ fn test_item_system_ignores_non_item_collisions() { let initial_score = world.resource::().0; // Send collision event between pacman and ghost - send_collision_event(&mut world, pacman, ghost); + common::send_collision_event(&mut world, pacman, ghost); world.run_system_once(item_system).expect("System should run successfully"); @@ -205,9 +151,9 @@ fn test_item_system_ignores_non_item_collisions() { #[test] fn test_item_system_no_collision_events() { - let mut world = create_test_world(); - let _pacman = spawn_test_pacman(&mut world); - let _pellet = spawn_test_item(&mut world, EntityType::Pellet); + let mut world = common::create_test_world(); + let _pacman = common::spawn_test_pacman(&mut world, 0); + let _pellet = common::spawn_test_item(&mut world, 1, EntityType::Pellet); let initial_score = world.resource::().0; @@ -227,13 +173,13 @@ fn test_item_system_no_collision_events() { #[test] fn test_item_system_collision_with_missing_entity() { - let mut world = create_test_world(); - let pacman = spawn_test_pacman(&mut world); + let mut world = common::create_test_world(); + let pacman = common::spawn_test_pacman(&mut world, 0); // Create a fake entity ID that doesn't exist let fake_entity = Entity::from_raw(999); - send_collision_event(&mut world, pacman, fake_entity); + common::send_collision_event(&mut world, pacman, fake_entity); // System should handle gracefully and not crash world @@ -247,15 +193,15 @@ fn test_item_system_collision_with_missing_entity() { #[test] fn test_item_system_preserves_existing_score() { - let mut world = create_test_world(); + let mut world = common::create_test_world(); // Set initial score world.insert_resource(ScoreResource(100)); - let pacman = spawn_test_pacman(&mut world); - let pellet = spawn_test_item(&mut world, EntityType::Pellet); + let pacman = common::spawn_test_pacman(&mut world, 0); + let pellet = common::spawn_test_item(&mut world, 1, EntityType::Pellet); - send_collision_event(&mut world, pacman, pellet); + common::send_collision_event(&mut world, pacman, pellet); world.run_system_once(item_system).expect("System should run successfully"); @@ -266,17 +212,17 @@ fn test_item_system_preserves_existing_score() { #[test] fn test_power_pellet_does_not_affect_ghosts_in_eyes_state() { - let mut world = create_test_world(); - let pacman = spawn_test_pacman(&mut world); - let power_pellet = spawn_test_item(&mut world, EntityType::PowerPellet); + let mut world = common::create_test_world(); + let pacman = common::spawn_test_pacman(&mut world, 0); + let power_pellet = common::spawn_test_item(&mut world, 1, EntityType::PowerPellet); // Spawn a ghost in Eyes state (returning to ghost house) - let eyes_ghost = spawn_test_ghost(&mut world, GhostState::Eyes); + let eyes_ghost = common::spawn_test_ghost(&mut world, 2, GhostState::Eyes); // Spawn a ghost in Normal state - let normal_ghost = spawn_test_ghost(&mut world, GhostState::Normal); + let normal_ghost = common::spawn_test_ghost(&mut world, 3, GhostState::Normal); - send_collision_event(&mut world, pacman, power_pellet); + common::send_collision_event(&mut world, pacman, power_pellet); world.run_system_once(item_system).expect("System should run successfully"); diff --git a/tests/map_builder.rs b/tests/map_builder.rs index dcacbf5..4b68c52 100644 --- a/tests/map_builder.rs +++ b/tests/map_builder.rs @@ -34,61 +34,3 @@ fn test_map_node_positions() { assert_eq!(node.position, expected_pos); } } - -// #[test] -// fn test_generate_items() { -// use pacman::texture::sprite::{AtlasMapper, MapperFrame, SpriteAtlas}; -// use std::collections::HashMap; - -// let map = Map::new(RAW_BOARD).unwrap(); - -// // Create a minimal atlas for testing -// let mut frames = HashMap::new(); -// frames.insert( -// "maze/pellet.png".to_string(), -// MapperFrame { -// x: 0, -// y: 0, -// width: 8, -// height: 8, -// }, -// ); -// frames.insert( -// "maze/energizer.png".to_string(), -// MapperFrame { -// x: 8, -// y: 0, -// width: 8, -// height: 8, -// }, -// ); - -// let mapper = AtlasMapper { frames }; -// let texture = unsafe { std::mem::transmute::>(0usize) }; -// let atlas = SpriteAtlas::new(texture, mapper); - -// let items = map.generate_items(&atlas).unwrap(); - -// // Verify we have items -// assert!(!items.is_empty()); - -// // Count different types -// let pellet_count = items -// .iter() -// .filter(|item| matches!(item.item_type, pacman::entity::item::ItemType::Pellet)) -// .count(); -// let energizer_count = items -// .iter() -// .filter(|item| matches!(item.item_type, pacman::entity::item::ItemType::Energizer)) -// .count(); - -// // Should have both types -// assert_eq!(pellet_count, 240); -// assert_eq!(energizer_count, 4); - -// // All items should be uncollected initially -// assert!(items.iter().all(|item| !item.is_collected())); - -// // All items should have valid node indices -// assert!(items.iter().all(|item| item.node_index < map.graph.node_count())); -// } diff --git a/tests/movement.rs b/tests/movement.rs index 8ad531e..1b9b098 100644 --- a/tests/movement.rs +++ b/tests/movement.rs @@ -1,28 +1,8 @@ use glam::Vec2; use pacman::map::direction::Direction; -use pacman::map::graph::{Graph, Node}; use pacman::systems::movement::{BufferedDirection, Position, Velocity}; -fn create_test_graph() -> Graph { - let mut graph = Graph::new(); - - // Add a few test nodes - let node0 = graph.add_node(Node { - position: Vec2::new(0.0, 0.0), - }); - let node1 = graph.add_node(Node { - position: Vec2::new(16.0, 0.0), - }); - let node2 = graph.add_node(Node { - position: Vec2::new(0.0, 16.0), - }); - - // Connect them - graph.connect(node0, node1, false, None, Direction::Right).unwrap(); - graph.connect(node0, node2, false, None, Direction::Down).unwrap(); - - graph -} +mod common; #[test] fn test_position_is_at_node() { @@ -127,7 +107,7 @@ fn test_position_tick_overshoot_with_overflow() { #[test] fn test_position_get_pixel_position_stopped() { - let graph = create_test_graph(); + let graph = common::create_test_graph(); let pos = Position::Stopped { node: 0 }; let pixel_pos = pos.get_pixel_position(&graph).unwrap(); @@ -141,7 +121,7 @@ fn test_position_get_pixel_position_stopped() { #[test] fn test_position_get_pixel_position_moving() { - let graph = create_test_graph(); + let graph = common::create_test_graph(); let pos = Position::Moving { from: 0, to: 1, diff --git a/tests/player.rs b/tests/player.rs index 210b0db..5ab5ede 100644 --- a/tests/player.rs +++ b/tests/player.rs @@ -1,63 +1,17 @@ -use bevy_ecs::{entity::Entity, event::Events, system::RunSystemOnce, world::World}; - +use bevy_ecs::{event::Events, system::RunSystemOnce}; use pacman::{ events::{GameCommand, GameEvent}, map::{ - builder::Map, direction::Direction, graph::{Edge, TraversalFlags}, }, systems::{ can_traverse, player_control_system, player_movement_system, AudioState, BufferedDirection, DebugState, DeltaTime, - EntityType, GlobalState, MovementModifiers, PlayerControlled, Position, Velocity, + EntityType, GlobalState, Position, Velocity, }, }; -// Test helper functions for ECS setup -fn create_test_world() -> World { - let mut world = World::new(); - - // Add resources - world.insert_resource(GlobalState { exit: false }); - world.insert_resource(DebugState::default()); - world.insert_resource(AudioState::default()); - world.insert_resource(DeltaTime(1.0 / 60.0)); // 60 FPS - world.insert_resource(Events::::default()); - world.insert_resource(Events::::default()); - - // Create a simple test map with nodes and edges - let test_map = create_test_map(); - world.insert_resource(test_map); - - world -} - -fn create_test_map() -> Map { - // Use the actual RAW_BOARD from constants.rs - use pacman::constants::RAW_BOARD; - Map::new(RAW_BOARD).expect("Failed to create test map") -} - -fn spawn_test_player(world: &mut World) -> Entity { - world - .spawn(( - PlayerControlled, - Position::Stopped { node: 0 }, - Velocity { - speed: 1.0, - direction: Direction::Right, - }, - BufferedDirection::None, - EntityType::Player, - MovementModifiers::default(), - )) - .id() -} - -fn send_game_event(world: &mut World, command: GameCommand) { - let mut events = world.resource_mut::>(); - events.send(GameEvent::Command(command)); -} +mod common; #[test] fn test_can_traverse_player_on_all_edges() { @@ -155,17 +109,13 @@ fn test_entity_type_traversal_flags() { assert_eq!(EntityType::PowerPellet.traversal_flags(), TraversalFlags::empty()); } -// ============================================================================ -// ECS System Tests -// ============================================================================ - #[test] fn test_player_control_system_move_command() { - let mut world = create_test_world(); - let _player = spawn_test_player(&mut world); + let mut world = common::create_test_world(); + let _player = common::spawn_test_player(&mut world, 0); // Send move command - send_game_event(&mut world, GameCommand::MovePlayer(Direction::Up)); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::MovePlayer(Direction::Up))); // Run the system world @@ -190,11 +140,11 @@ fn test_player_control_system_move_command() { #[test] fn test_player_control_system_exit_command() { - let mut world = create_test_world(); - let _player = spawn_test_player(&mut world); + let mut world = common::create_test_world(); + let _player = common::spawn_test_player(&mut world, 0); // Send exit command - send_game_event(&mut world, GameCommand::Exit); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::Exit)); // Run the system world @@ -208,11 +158,11 @@ fn test_player_control_system_exit_command() { #[test] fn test_player_control_system_toggle_debug() { - let mut world = create_test_world(); - let _player = spawn_test_player(&mut world); + let mut world = common::create_test_world(); + let _player = common::spawn_test_player(&mut world, 0); // Send toggle debug command - send_game_event(&mut world, GameCommand::ToggleDebug); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::ToggleDebug)); // Run the system world @@ -226,11 +176,11 @@ fn test_player_control_system_toggle_debug() { #[test] fn test_player_control_system_mute_audio() { - let mut world = create_test_world(); - let _player = spawn_test_player(&mut world); + let mut world = common::create_test_world(); + let _player = common::spawn_test_player(&mut world, 0); // Send mute audio command - send_game_event(&mut world, GameCommand::MuteAudio); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::MuteAudio)); // Run the system world @@ -243,7 +193,7 @@ fn test_player_control_system_mute_audio() { // Send mute audio command again to unmute - need fresh events world.resource_mut::>().clear(); // Clear previous events - send_game_event(&mut world, GameCommand::MuteAudio); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::MuteAudio)); world .run_system_once(player_control_system) .expect("System should run successfully"); @@ -255,10 +205,10 @@ fn test_player_control_system_mute_audio() { #[test] fn test_player_control_system_no_player_entity() { - let mut world = create_test_world(); + let mut world = common::create_test_world(); // Don't spawn a player entity - send_game_event(&mut world, GameCommand::MovePlayer(Direction::Up)); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::MovePlayer(Direction::Up))); // Run the system - should write an error world @@ -272,8 +222,8 @@ fn test_player_control_system_no_player_entity() { #[test] fn test_player_movement_system_buffered_direction_expires() { - let mut world = create_test_world(); - let player = spawn_test_player(&mut world); + let mut world = common::create_test_world(); + let player = common::spawn_test_player(&mut world, 0); // Set a buffered direction with short time world.entity_mut(player).insert(BufferedDirection::Some { @@ -305,8 +255,8 @@ fn test_player_movement_system_buffered_direction_expires() { #[test] fn test_player_movement_system_start_moving_from_stopped() { - let mut world = create_test_world(); - let _player = spawn_test_player(&mut world); + let mut world = common::create_test_world(); + let _player = common::spawn_test_player(&mut world, 0); // Player starts at node 0, facing right (towards node 1) // Should start moving when system runs @@ -330,8 +280,8 @@ fn test_player_movement_system_start_moving_from_stopped() { #[test] fn test_player_movement_system_buffered_direction_change() { - let mut world = create_test_world(); - let player = spawn_test_player(&mut world); + let mut world = common::create_test_world(); + let player = common::spawn_test_player(&mut world, 0); // Set a buffered direction to go down (towards node 2) world.entity_mut(player).insert(BufferedDirection::Some { @@ -361,8 +311,8 @@ fn test_player_movement_system_buffered_direction_change() { #[test] fn test_player_movement_system_no_valid_edge() { - let mut world = create_test_world(); - let player = spawn_test_player(&mut world); + let mut world = common::create_test_world(); + let player = common::spawn_test_player(&mut world, 0); // Set velocity to direction with no edge world.entity_mut(player).insert(Velocity { @@ -386,8 +336,8 @@ fn test_player_movement_system_no_valid_edge() { #[test] fn test_player_movement_system_continue_moving() { - let mut world = create_test_world(); - let player = spawn_test_player(&mut world); + let mut world = common::create_test_world(); + let player = common::spawn_test_player(&mut world, 0); // Set player to already be moving world.entity_mut(player).insert(Position::Moving { @@ -414,17 +364,13 @@ fn test_player_movement_system_continue_moving() { } } -// ============================================================================ -// Integration Tests -// ============================================================================ - #[test] fn test_full_player_input_to_movement_flow() { - let mut world = create_test_world(); - let _player = spawn_test_player(&mut world); + let mut world = common::create_test_world(); + let _player = common::spawn_test_player(&mut world, 0); // Send move command - send_game_event(&mut world, GameCommand::MovePlayer(Direction::Down)); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::MovePlayer(Direction::Down))); // Run control system to process input world @@ -454,11 +400,11 @@ fn test_full_player_input_to_movement_flow() { #[test] fn test_buffered_direction_timing() { - let mut world = create_test_world(); - let _player = spawn_test_player(&mut world); + let mut world = common::create_test_world(); + let _player = common::spawn_test_player(&mut world, 0); // Send move command - send_game_event(&mut world, GameCommand::MovePlayer(Direction::Up)); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::MovePlayer(Direction::Up))); world .run_system_once(player_control_system) .expect("System should run successfully"); @@ -493,21 +439,21 @@ fn test_buffered_direction_timing() { #[test] fn test_multiple_rapid_direction_changes() { - let mut world = create_test_world(); - let _player = spawn_test_player(&mut world); + let mut world = common::create_test_world(); + let _player = common::spawn_test_player(&mut world, 0); // Send multiple rapid direction changes - send_game_event(&mut world, GameCommand::MovePlayer(Direction::Up)); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::MovePlayer(Direction::Up))); world .run_system_once(player_control_system) .expect("System should run successfully"); - send_game_event(&mut world, GameCommand::MovePlayer(Direction::Down)); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::MovePlayer(Direction::Down))); world .run_system_once(player_control_system) .expect("System should run successfully"); - send_game_event(&mut world, GameCommand::MovePlayer(Direction::Left)); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::MovePlayer(Direction::Left))); world .run_system_once(player_control_system) .expect("System should run successfully"); @@ -526,15 +472,15 @@ fn test_multiple_rapid_direction_changes() { #[test] fn test_player_state_persistence_across_systems() { - let mut world = create_test_world(); - let _player = spawn_test_player(&mut world); + let mut world = common::create_test_world(); + let _player = common::spawn_test_player(&mut world, 0); // Test that multiple commands can be processed - but need to handle events properly // Clear any existing events first world.resource_mut::>().clear(); // Toggle debug mode - send_game_event(&mut world, GameCommand::ToggleDebug); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::ToggleDebug)); world .run_system_once(player_control_system) .expect("System should run successfully"); @@ -542,7 +488,7 @@ fn test_player_state_persistence_across_systems() { // Clear events and mute audio world.resource_mut::>().clear(); - send_game_event(&mut world, GameCommand::MuteAudio); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::MuteAudio)); world .run_system_once(player_control_system) .expect("System should run successfully"); @@ -550,7 +496,7 @@ fn test_player_state_persistence_across_systems() { // Clear events and move player world.resource_mut::>().clear(); - send_game_event(&mut world, GameCommand::MovePlayer(Direction::Down)); + common::send_game_event(&mut world, GameEvent::Command(GameCommand::MovePlayer(Direction::Down))); world .run_system_once(player_control_system) .expect("System should run successfully"); diff --git a/tests/sprite.rs b/tests/sprite.rs index 8662dda..b6aa90f 100644 --- a/tests/sprite.rs +++ b/tests/sprite.rs @@ -1,14 +1,12 @@ use glam::U16Vec2; -use pacman::texture::sprite::{AtlasMapper, AtlasTile, MapperFrame, SpriteAtlas}; +use pacman::texture::sprite::{AtlasMapper, AtlasTile, MapperFrame}; use sdl2::pixels::Color; use std::collections::HashMap; -fn mock_texture() -> sdl2::render::Texture { - unsafe { std::mem::transmute(0usize) } -} +mod common; #[test] -fn test_sprite_atlas_basic() { +fn test_atlas_mapper_frame_lookup() { let mut frames = HashMap::new(); frames.insert( "test".to_string(), @@ -19,19 +17,17 @@ fn test_sprite_atlas_basic() { ); let mapper = AtlasMapper { frames }; - let texture = mock_texture(); - let atlas = SpriteAtlas::new(texture, mapper); - let tile = atlas.get_tile("test"); - assert!(tile.is_some()); - let tile = tile.unwrap(); - assert_eq!(tile.pos, glam::U16Vec2::new(10, 20)); - assert_eq!(tile.size, glam::U16Vec2::new(32, 64)); - assert_eq!(tile.color, None); + // Test direct frame lookup + let frame = mapper.frames.get("test"); + assert!(frame.is_some()); + let frame = frame.unwrap(); + assert_eq!(frame.pos, U16Vec2::new(10, 20)); + assert_eq!(frame.size, U16Vec2::new(32, 64)); } #[test] -fn test_sprite_atlas_multiple_tiles() { +fn test_atlas_mapper_multiple_frames() { let mut frames = HashMap::new(); frames.insert( "tile1".to_string(), @@ -49,27 +45,12 @@ fn test_sprite_atlas_multiple_tiles() { ); let mapper = AtlasMapper { frames }; - let texture = mock_texture(); - let atlas = SpriteAtlas::new(texture, mapper); - assert_eq!(atlas.tiles_count(), 2); - assert!(atlas.has_tile("tile1")); - assert!(atlas.has_tile("tile2")); - assert!(!atlas.has_tile("tile3")); - assert!(atlas.get_tile("nonexistent").is_none()); -} - -#[test] -fn test_sprite_atlas_color() { - let mapper = AtlasMapper { frames: HashMap::new() }; - let texture = mock_texture(); - let mut atlas = SpriteAtlas::new(texture, mapper); - - assert_eq!(atlas.default_color(), None); - - let color = Color::RGB(255, 0, 0); - atlas.set_color(color); - assert_eq!(atlas.default_color(), Some(color)); + assert_eq!(mapper.frames.len(), 2); + assert!(mapper.frames.contains_key("tile1")); + assert!(mapper.frames.contains_key("tile2")); + assert!(!mapper.frames.contains_key("tile3")); + assert!(mapper.frames.get("nonexistent").is_none()); } #[test] diff --git a/tests/text.rs b/tests/text.rs index 30e4284..66aa38d 100644 --- a/tests/text.rs +++ b/tests/text.rs @@ -1,9 +1,9 @@ use pacman::texture::{sprite::SpriteAtlas, text::TextTexture}; -use crate::common::create_atlas; - mod common; +use common::create_atlas; + /// Helper function to get all characters that should be in the atlas fn get_all_chars() -> String { let mut chars = Vec::new(); diff --git a/tests/tracing_buffer.rs b/tests/tracing_buffer.rs deleted file mode 100644 index f0a589d..0000000 --- a/tests/tracing_buffer.rs +++ /dev/null @@ -1,19 +0,0 @@ -use pacman::platform::tracing_buffer::SwitchableWriter; -use std::io::Write; - -#[test] -fn test_switchable_writer_buffering() { - let mut writer = SwitchableWriter::default(); - - // Write some data while in buffered mode - writer.write_all(b"Hello, ").unwrap(); - writer.write_all(b"world!").unwrap(); - writer.write_all(b"This is buffered content.\n").unwrap(); - - // Switch to direct mode (this should flush to stdout and show buffer size) - // In a real test we can't easily capture stdout, so we'll just verify it doesn't panic - writer.switch_to_direct_mode().unwrap(); - - // Write more data in direct mode - writer.write_all(b"Direct output after flush\n").unwrap(); -}