From b308bc0ef7c36cdbedc4db4199747663f973d534 Mon Sep 17 00:00:00 2001 From: Xevion Date: Fri, 8 Aug 2025 08:50:52 -0500 Subject: [PATCH] refactor: move all tests out of src/ into tests/, remove unnecessary tests --- src/audio.rs | 153 ---------------- src/constants.rs | 176 ------------------ src/entity/direction.rs | 64 ------- src/entity/graph.rs | 363 ------------------------------------- src/entity/pacman.rs | 216 ---------------------- src/game.rs | 230 ----------------------- src/helpers.rs | 40 ---- src/map/builder.rs | 159 ---------------- src/map/parser.rs | 53 ------ src/map/render.rs | 77 -------- src/texture/animated.rs | 124 ------------- src/texture/blinking.rs | 132 -------------- src/texture/directional.rs | 109 ----------- src/texture/sprite.rs | 233 ------------------------ src/texture/text.rs | 225 ----------------------- tests/animated.rs | 67 +++++++ tests/blinking.rs | 52 ++++++ tests/constants.rs | 173 ++++++++++++++++++ tests/direction.rs | 61 +++++++ tests/directional.rs | 50 +++++ tests/graph.rs | 152 ++++++++++++++++ tests/helpers.rs | 37 ++++ tests/map_builder.rs | 114 ++++++++++++ tests/pacman.rs | 152 ++++++++++++++++ tests/parser.rs | 70 +++++++ tests/sprite.rs | 90 +++++++++ 26 files changed, 1018 insertions(+), 2354 deletions(-) create mode 100644 tests/animated.rs create mode 100644 tests/blinking.rs create mode 100644 tests/constants.rs create mode 100644 tests/direction.rs create mode 100644 tests/directional.rs create mode 100644 tests/graph.rs create mode 100644 tests/helpers.rs create mode 100644 tests/map_builder.rs create mode 100644 tests/pacman.rs create mode 100644 tests/parser.rs create mode 100644 tests/sprite.rs diff --git a/src/audio.rs b/src/audio.rs index e827efc..18d75dc 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -162,156 +162,3 @@ impl Audio { self.disabled } } - -#[cfg(test)] -mod tests { - use super::*; - use std::sync::Once; - - static INIT: Once = Once::new(); - - fn init_sdl() -> Result<(), String> { - INIT.call_once(|| { - if let Err(e) = sdl2::init() { - eprintln!("Failed to initialize SDL2: {}", e); - } - }); - Ok(()) - } - - #[test] - fn test_sound_assets_array() { - assert_eq!(SOUND_ASSETS.len(), 4); - assert_eq!(SOUND_ASSETS[0], Asset::Wav1); - assert_eq!(SOUND_ASSETS[1], Asset::Wav2); - assert_eq!(SOUND_ASSETS[2], Asset::Wav3); - assert_eq!(SOUND_ASSETS[3], Asset::Wav4); - } - - #[test] - fn test_audio_asset_paths() { - // Test that all sound assets have valid paths - for asset in SOUND_ASSETS.iter() { - let path = asset.path(); - assert!(!path.is_empty()); - assert!(path.contains("sound/waka/")); - assert!(path.ends_with(".ogg")); - } - } - - // Only run SDL2-dependent tests if SDL2 initialization succeeds - #[test] - fn test_audio_basic_functionality() { - if let Err(_) = init_sdl() { - eprintln!("Skipping SDL2-dependent tests due to initialization failure"); - return; - } - - // Test basic audio creation - let audio = Audio::new(); - assert_eq!(audio.is_muted(), false); - assert_eq!(audio.next_sound_index, 0); - - // Audio might be disabled if initialization failed - if !audio.is_disabled() { - assert_eq!(audio.sounds.len(), 4); - } - } - - #[test] - fn test_audio_mute_functionality() { - if let Err(_) = init_sdl() { - eprintln!("Skipping SDL2-dependent tests due to initialization failure"); - return; - } - - let mut audio = Audio::new(); - - // Test mute/unmute - assert_eq!(audio.is_muted(), false); - audio.set_mute(true); - assert_eq!(audio.is_muted(), true); - audio.set_mute(false); - assert_eq!(audio.is_muted(), false); - } - - #[test] - fn test_audio_sound_rotation() { - if let Err(_) = init_sdl() { - eprintln!("Skipping SDL2-dependent tests due to initialization failure"); - return; - } - - let mut audio = Audio::new(); - - // Skip test if audio is disabled - if audio.is_disabled() { - eprintln!("Skipping sound rotation test due to disabled audio"); - return; - } - - let initial_index = audio.next_sound_index; - - // Test sound rotation - for i in 0..4 { - audio.eat(); - assert_eq!(audio.next_sound_index, (initial_index + i + 1) % 4); - } - - assert_eq!(audio.next_sound_index, initial_index); - } - - #[test] - fn test_audio_sound_index_bounds() { - if let Err(_) = init_sdl() { - eprintln!("Skipping SDL2-dependent tests due to initialization failure"); - return; - } - - let audio = Audio::new(); - - // Skip test if audio is disabled - if audio.is_disabled() { - eprintln!("Skipping sound index bounds test due to disabled audio"); - return; - } - - assert!(audio.next_sound_index < audio.sounds.len()); - } - - #[test] - fn test_audio_default_impl() { - if let Err(_) = init_sdl() { - eprintln!("Skipping SDL2-dependent tests due to initialization failure"); - return; - } - - let audio = Audio::default(); - assert_eq!(audio.is_muted(), false); - assert_eq!(audio.next_sound_index, 0); - - // Audio might be disabled if initialization failed - if !audio.is_disabled() { - assert_eq!(audio.sounds.len(), 4); - } - } - - #[test] - fn test_audio_disabled_state() { - if let Err(_) = init_sdl() { - eprintln!("Skipping SDL2-dependent tests due to initialization failure"); - return; - } - - // Test that disabled audio doesn't crash when calling functions - let mut audio = Audio::new(); - - // These should not panic even if audio is disabled - audio.eat(); - audio.set_mute(true); - audio.set_mute(false); - - // Test that we can check the disabled state - let _is_disabled = audio.is_disabled(); - } -} diff --git a/src/constants.rs b/src/constants.rs index bd4ca91..7b4eb72 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -75,179 +75,3 @@ pub const RAW_BOARD: [&str; BOARD_CELL_SIZE.y as usize] = [ "#..........................#", "############################", ]; - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_loop_time() { - // 60 FPS = 16.67ms per frame - let expected_nanos = (1_000_000_000.0 / 60.0) as u64; - assert_eq!(LOOP_TIME.as_nanos() as u64, expected_nanos); - } - - #[test] - fn test_cell_size() { - assert_eq!(CELL_SIZE, 8); - } - - #[test] - fn test_board_cell_size() { - assert_eq!(BOARD_CELL_SIZE.x, 28); - assert_eq!(BOARD_CELL_SIZE.y, 31); - } - - #[test] - fn test_scale() { - assert_eq!(SCALE, 2.6); - } - - #[test] - fn test_board_cell_offset() { - assert_eq!(BOARD_CELL_OFFSET.x, 0); - assert_eq!(BOARD_CELL_OFFSET.y, 3); - } - - #[test] - fn test_board_pixel_offset() { - let expected = UVec2::new(0 * CELL_SIZE, 3 * CELL_SIZE); - assert_eq!(BOARD_PIXEL_OFFSET, expected); - assert_eq!(BOARD_PIXEL_OFFSET.x, 0); - assert_eq!(BOARD_PIXEL_OFFSET.y, 24); // 3 * 8 - } - - #[test] - fn test_board_pixel_size() { - let expected = UVec2::new(28 * CELL_SIZE, 31 * CELL_SIZE); - assert_eq!(BOARD_PIXEL_SIZE, expected); - assert_eq!(BOARD_PIXEL_SIZE.x, 224); // 28 * 8 - assert_eq!(BOARD_PIXEL_SIZE.y, 248); // 31 * 8 - } - - #[test] - fn test_canvas_size() { - let expected = UVec2::new((28 + 0) * CELL_SIZE, (31 + 3) * CELL_SIZE); - assert_eq!(CANVAS_SIZE, expected); - assert_eq!(CANVAS_SIZE.x, 224); // (28 + 0) * 8 - assert_eq!(CANVAS_SIZE.y, 272); // (31 + 3) * 8 - } - - #[test] - fn test_map_tile_variants() { - assert_ne!(MapTile::Empty, MapTile::Wall); - assert_ne!(MapTile::Pellet, MapTile::PowerPellet); - assert_ne!(MapTile::Tunnel, MapTile::Empty); - } - - #[test] - fn test_map_tile_clone() { - let original = MapTile::Wall; - let cloned = original; - assert_eq!(original, cloned); - } - - #[test] - fn test_raw_board_dimensions() { - assert_eq!(RAW_BOARD.len(), BOARD_CELL_SIZE.y as usize); - assert_eq!(RAW_BOARD.len(), 31); - - for row in RAW_BOARD.iter() { - assert_eq!(row.len(), BOARD_CELL_SIZE.x as usize); - assert_eq!(row.len(), 28); - } - } - - #[test] - fn test_raw_board_boundaries() { - // First row should be all walls - assert!(RAW_BOARD[0].chars().all(|c| c == '#')); - - // Last row should be all walls - let last_row = RAW_BOARD[RAW_BOARD.len() - 1]; - assert!(last_row.chars().all(|c| c == '#')); - - // First and last character of each row should be walls (except tunnel rows and rows with spaces) - for (i, row) in RAW_BOARD.iter().enumerate() { - if i != 14 && !row.starts_with(' ') { - // Skip tunnel row and rows that start with spaces - assert_eq!(row.chars().next().unwrap(), '#'); - assert_eq!(row.chars().last().unwrap(), '#'); - } - } - } - - #[test] - fn test_raw_board_tunnel_row() { - // Row 14 should have tunnel characters 'T' at the edges - let tunnel_row = RAW_BOARD[14]; - assert_eq!(tunnel_row.chars().next().unwrap(), 'T'); - assert_eq!(tunnel_row.chars().last().unwrap(), 'T'); - } - - #[test] - fn test_raw_board_power_pellets() { - // Power pellets are represented by 'o' - let mut power_pellet_count = 0; - for row in RAW_BOARD.iter() { - power_pellet_count += row.chars().filter(|&c| c == 'o').count(); - } - assert_eq!(power_pellet_count, 4); // Should have exactly 4 power pellets - } - - #[test] - fn test_raw_board_starting_position() { - // Should have a starting position 'X' for Pac-Man - let mut found_starting_position = false; - for row in RAW_BOARD.iter() { - if row.contains('X') { - found_starting_position = true; - break; - } - } - assert!(found_starting_position); - } - - #[test] - fn test_raw_board_ghost_house() { - // The ghost house area should be present (the == characters) - let mut found_ghost_house = false; - for row in RAW_BOARD.iter() { - if row.contains("==") { - found_ghost_house = true; - break; - } - } - assert!(found_ghost_house); - } - - #[test] - fn test_raw_board_symmetry() { - // The board should be roughly symmetrical - let mid_point = RAW_BOARD[0].len() / 2; - - for row in RAW_BOARD.iter() { - let left_half = &row[..mid_point]; - let right_half = &row[mid_point..]; - - // Check that the halves are symmetrical (accounting for the center column) - assert_eq!(left_half.len(), right_half.len()); - } - } - - #[test] - fn test_constants_consistency() { - // Verify that derived constants are calculated correctly - let calculated_pixel_offset = UVec2::new(BOARD_CELL_OFFSET.x * CELL_SIZE, BOARD_CELL_OFFSET.y * CELL_SIZE); - assert_eq!(BOARD_PIXEL_OFFSET, calculated_pixel_offset); - - let calculated_pixel_size = UVec2::new(BOARD_CELL_SIZE.x * CELL_SIZE, BOARD_CELL_SIZE.y * CELL_SIZE); - assert_eq!(BOARD_PIXEL_SIZE, calculated_pixel_size); - - let calculated_canvas_size = UVec2::new( - (BOARD_CELL_SIZE.x + BOARD_CELL_OFFSET.x) * CELL_SIZE, - (BOARD_CELL_SIZE.y + BOARD_CELL_OFFSET.y) * CELL_SIZE, - ); - assert_eq!(CANVAS_SIZE, calculated_canvas_size); - } -} diff --git a/src/entity/direction.rs b/src/entity/direction.rs index ce35507..3c2b233 100644 --- a/src/entity/direction.rs +++ b/src/entity/direction.rs @@ -35,67 +35,3 @@ impl From for IVec2 { } pub const DIRECTIONS: [Direction; 4] = [Direction::Up, Direction::Down, Direction::Left, Direction::Right]; - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_direction_opposite() { - assert_eq!(Direction::Up.opposite(), Direction::Down); - assert_eq!(Direction::Down.opposite(), Direction::Up); - assert_eq!(Direction::Left.opposite(), Direction::Right); - assert_eq!(Direction::Right.opposite(), Direction::Left); - } - - #[test] - fn test_direction_as_ivec2() { - assert_eq!(Direction::Up.as_ivec2(), -IVec2::Y); - assert_eq!(Direction::Down.as_ivec2(), IVec2::Y); - assert_eq!(Direction::Left.as_ivec2(), -IVec2::X); - assert_eq!(Direction::Right.as_ivec2(), IVec2::X); - } - - #[test] - fn test_direction_from_ivec2() { - assert_eq!(IVec2::from(Direction::Up), -IVec2::Y); - assert_eq!(IVec2::from(Direction::Down), IVec2::Y); - assert_eq!(IVec2::from(Direction::Left), -IVec2::X); - assert_eq!(IVec2::from(Direction::Right), IVec2::X); - } - - #[test] - fn test_directions_constant() { - assert_eq!(DIRECTIONS.len(), 4); - assert!(DIRECTIONS.contains(&Direction::Up)); - assert!(DIRECTIONS.contains(&Direction::Down)); - assert!(DIRECTIONS.contains(&Direction::Left)); - assert!(DIRECTIONS.contains(&Direction::Right)); - } - - #[test] - fn test_direction_equality() { - assert_eq!(Direction::Up, Direction::Up); - assert_ne!(Direction::Up, Direction::Down); - assert_ne!(Direction::Left, Direction::Right); - } - - #[test] - fn test_direction_clone() { - let dir = Direction::Up; - let cloned = dir; - assert_eq!(dir, cloned); - } - - #[test] - fn test_direction_hash() { - use std::collections::HashMap; - let mut map = HashMap::new(); - map.insert(Direction::Up, "up"); - map.insert(Direction::Down, "down"); - - assert_eq!(map.get(&Direction::Up), Some(&"up")); - assert_eq!(map.get(&Direction::Down), Some(&"down")); - assert_eq!(map.get(&Direction::Left), None); - } -} diff --git a/src/entity/graph.rs b/src/entity/graph.rs index 3aa52bf..0ab3f0a 100644 --- a/src/entity/graph.rs +++ b/src/entity/graph.rs @@ -441,366 +441,3 @@ impl Traverser { } } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::entity::direction::Direction; - - 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 - } - - #[test] - fn test_graph_new() { - let graph = Graph::new(); - assert_eq!(graph.node_count(), 0); - assert!(graph.adjacency_list.is_empty()); - } - - #[test] - fn test_graph_add_node() { - let mut graph = Graph::new(); - let node = Node { - position: glam::Vec2::new(10.0, 20.0), - }; - let id = graph.add_node(node); - - assert_eq!(id, 0); - assert_eq!(graph.node_count(), 1); - assert_eq!(graph.adjacency_list.len(), 1); - - let retrieved_node = graph.get_node(id).unwrap(); - assert_eq!(retrieved_node.position, glam::Vec2::new(10.0, 20.0)); - } - - #[test] - fn test_graph_node_count() { - let mut graph = Graph::new(); - assert_eq!(graph.node_count(), 0); - - graph.add_node(Node { - position: glam::Vec2::new(0.0, 0.0), - }); - assert_eq!(graph.node_count(), 1); - - graph.add_node(Node { - position: glam::Vec2::new(1.0, 1.0), - }); - assert_eq!(graph.node_count(), 2); - } - - #[test] - fn test_graph_get_node() { - let mut graph = Graph::new(); - let node = Node { - position: glam::Vec2::new(5.0, 10.0), - }; - let id = graph.add_node(node); - - let retrieved = graph.get_node(id).unwrap(); - assert_eq!(retrieved.position, glam::Vec2::new(5.0, 10.0)); - - assert!(graph.get_node(999).is_none()); - } - - #[test] - fn test_graph_connect() { - 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 result = graph.connect(node1, node2, false, None, Direction::Right); - assert!(result.is_ok()); - - // Check that edges were added in both directions - let edge1 = graph.find_edge_in_direction(node1, Direction::Right); - let edge2 = graph.find_edge_in_direction(node2, Direction::Left); - - assert!(edge1.is_some()); - assert!(edge2.is_some()); - assert_eq!(edge1.unwrap().target, node2); - assert_eq!(edge2.unwrap().target, node1); - } - - #[test] - fn test_graph_connect_invalid_nodes() { - let mut graph = Graph::new(); - let node1 = graph.add_node(Node { - position: glam::Vec2::new(0.0, 0.0), - }); - - // Try to connect to non-existent node - let result = graph.connect(node1, 999, false, None, Direction::Right); - assert!(result.is_err()); - - // Try to connect from non-existent node - let result = graph.connect(999, node1, false, None, Direction::Right); - assert!(result.is_err()); - } - - #[test] - fn test_graph_find_edge() { - 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), - }); - - graph.connect(node1, node2, false, None, Direction::Right).unwrap(); - - let edge = graph.find_edge(node1, node2); - assert!(edge.is_some()); - assert_eq!(edge.unwrap().target, node2); - - // Test non-existent edge - assert!(graph.find_edge(node1, 999).is_none()); - } - - #[test] - fn test_graph_find_edge_in_direction() { - 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), - }); - - graph.connect(node1, node2, false, None, Direction::Right).unwrap(); - - let edge = graph.find_edge_in_direction(node1, Direction::Right); - assert!(edge.is_some()); - assert_eq!(edge.unwrap().target, node2); - - // Test non-existent direction - assert!(graph.find_edge_in_direction(node1, Direction::Up).is_none()); - } - - #[test] - fn test_intersection_edges() { - let mut intersection = Intersection::default(); - intersection.set( - Direction::Up, - Edge { - target: 1, - distance: 10.0, - direction: Direction::Up, - permissions: EdgePermissions::All, - }, - ); - intersection.set( - Direction::Right, - Edge { - target: 2, - distance: 15.0, - direction: Direction::Right, - permissions: EdgePermissions::All, - }, - ); - - let edges: Vec<_> = intersection.edges().collect(); - assert_eq!(edges.len(), 2); - - let up_edge = edges.iter().find(|e| e.direction == Direction::Up).unwrap(); - let right_edge = edges.iter().find(|e| e.direction == Direction::Right).unwrap(); - - assert_eq!(up_edge.target, 1); - assert_eq!(up_edge.distance, 10.0); - assert_eq!(right_edge.target, 2); - assert_eq!(right_edge.distance, 15.0); - } - - #[test] - fn test_intersection_get() { - let mut intersection = Intersection::default(); - let edge = Edge { - target: 1, - distance: 10.0, - direction: Direction::Up, - permissions: EdgePermissions::All, - }; - intersection.set(Direction::Up, edge); - - let retrieved = intersection.get(Direction::Up); - assert!(retrieved.is_some()); - assert_eq!(retrieved.unwrap().target, 1); - - assert!(intersection.get(Direction::Down).is_none()); - } - - #[test] - fn test_intersection_set() { - let mut intersection = Intersection::default(); - let edge = Edge { - target: 1, - distance: 10.0, - direction: Direction::Left, - permissions: EdgePermissions::All, - }; - - intersection.set(Direction::Left, edge); - let retrieved = intersection.get(Direction::Left); - assert!(retrieved.is_some()); - assert_eq!(retrieved.unwrap().target, 1); - } - - #[test] - fn test_position_is_at_node() { - let pos = Position::AtNode(5); - assert!(pos.is_at_node()); - - let pos = Position::BetweenNodes { - from: 1, - to: 2, - traversed: 5.0, - }; - assert!(!pos.is_at_node()); - } - - #[test] - fn test_position_from_node_id() { - let pos = Position::AtNode(5); - assert_eq!(pos.from_node_id(), 5); - - let pos = Position::BetweenNodes { - from: 1, - to: 2, - traversed: 5.0, - }; - assert_eq!(pos.from_node_id(), 1); - } - - #[test] - fn test_position_to_node_id() { - let pos = Position::AtNode(5); - assert_eq!(pos.to_node_id(), None); - - let pos = Position::BetweenNodes { - from: 1, - to: 2, - traversed: 5.0, - }; - assert_eq!(pos.to_node_id(), Some(2)); - } - - #[test] - fn test_position_is_stopped() { - let pos = Position::AtNode(5); - assert!(pos.is_stopped()); - - let pos = Position::BetweenNodes { - from: 1, - to: 2, - traversed: 5.0, - }; - assert!(!pos.is_stopped()); - } - - #[test] - fn test_traverser_new() { - let graph = create_test_graph(); - let traverser = Traverser::new(&graph, 0, Direction::Left, &|_| true); - - assert_eq!(traverser.direction, Direction::Left); - // The next_direction might be consumed immediately when the traverser starts moving - // So we just check that the direction is set correctly - assert_eq!(traverser.direction, Direction::Left); - } - - #[test] - fn test_traverser_set_next_direction() { - let graph = create_test_graph(); - let mut traverser = Traverser::new(&graph, 0, Direction::Left, &|_| true); - - traverser.set_next_direction(Direction::Up); - assert!(traverser.next_direction.is_some()); - assert_eq!(traverser.next_direction.unwrap().0, Direction::Up); - - // Setting same direction should not change anything - traverser.set_next_direction(Direction::Up); - assert_eq!(traverser.next_direction.unwrap().0, Direction::Up); - } - - #[test] - fn test_traverser_advance_at_node() { - let graph = create_test_graph(); - let mut traverser = Traverser::new(&graph, 0, Direction::Right, &|_| true); - - // Should start moving in the initial direction - traverser.advance(&graph, 5.0, &|_| true); - - match traverser.position { - Position::BetweenNodes { from, to, traversed } => { - assert_eq!(from, 0); - assert_eq!(to, 1); - assert_eq!(traversed, 5.0); - } - _ => panic!("Expected to be between nodes"), - } - } - - #[test] - fn test_traverser_advance_between_nodes() { - let graph = create_test_graph(); - let mut traverser = Traverser::new(&graph, 0, Direction::Right, &|_| true); - - // Move to between nodes - traverser.advance(&graph, 5.0, &|_| true); - - // Advance further - traverser.advance(&graph, 3.0, &|_| true); - - match traverser.position { - Position::BetweenNodes { from, to, traversed } => { - assert_eq!(from, 0); - assert_eq!(to, 1); - assert_eq!(traversed, 8.0); - } - _ => panic!("Expected to be between nodes"), - } - } - - #[test] - fn test_edge_structure() { - let edge = Edge { - target: 5, - distance: 10.5, - direction: Direction::Up, - permissions: EdgePermissions::All, - }; - - assert_eq!(edge.target, 5); - assert_eq!(edge.distance, 10.5); - assert_eq!(edge.direction, Direction::Up); - } - - #[test] - fn test_node_structure() { - let node = Node { - position: glam::Vec2::new(10.0, 20.0), - }; - - assert_eq!(node.position, glam::Vec2::new(10.0, 20.0)); - } -} diff --git a/src/entity/pacman.rs b/src/entity/pacman.rs index 118fade..570bde3 100644 --- a/src/entity/pacman.rs +++ b/src/entity/pacman.rs @@ -100,219 +100,3 @@ impl Pacman { } } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::entity::graph::{Graph, Node}; - use crate::texture::sprite::{AtlasMapper, MapperFrame, SpriteAtlas}; - use sdl2::keyboard::Keycode; - use std::collections::HashMap; - - 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 - } - - fn create_test_atlas() -> SpriteAtlas { - // Create a minimal test atlas with required tiles - let mut frames = HashMap::new(); - frames.insert( - "pacman/up_a.png".to_string(), - MapperFrame { - x: 0, - y: 0, - width: 16, - height: 16, - }, - ); - frames.insert( - "pacman/up_b.png".to_string(), - MapperFrame { - x: 16, - y: 0, - width: 16, - height: 16, - }, - ); - frames.insert( - "pacman/down_a.png".to_string(), - MapperFrame { - x: 32, - y: 0, - width: 16, - height: 16, - }, - ); - frames.insert( - "pacman/down_b.png".to_string(), - MapperFrame { - x: 48, - y: 0, - width: 16, - height: 16, - }, - ); - frames.insert( - "pacman/left_a.png".to_string(), - MapperFrame { - x: 64, - y: 0, - width: 16, - height: 16, - }, - ); - frames.insert( - "pacman/left_b.png".to_string(), - MapperFrame { - x: 80, - y: 0, - width: 16, - height: 16, - }, - ); - frames.insert( - "pacman/right_a.png".to_string(), - MapperFrame { - x: 96, - y: 0, - width: 16, - height: 16, - }, - ); - frames.insert( - "pacman/right_b.png".to_string(), - MapperFrame { - x: 112, - y: 0, - width: 16, - height: 16, - }, - ); - frames.insert( - "pacman/full.png".to_string(), - MapperFrame { - x: 128, - y: 0, - width: 16, - height: 16, - }, - ); - - let mapper = AtlasMapper { frames }; - // Create a dummy texture (we won't actually render, just test the logic) - let dummy_texture = unsafe { std::mem::zeroed() }; - SpriteAtlas::new(dummy_texture, mapper) - } - - #[test] - fn test_pacman_new() { - let graph = create_test_graph(); - let atlas = create_test_atlas(); - - let pacman = Pacman::new(&graph, 0, &atlas); - - assert_eq!(pacman.traverser.direction, Direction::Left); - assert!(matches!(pacman.traverser.position, crate::entity::graph::Position::AtNode(0))); - } - - #[test] - fn test_handle_key_valid_directions() { - let graph = create_test_graph(); - let atlas = create_test_atlas(); - let mut pacman = Pacman::new(&graph, 0, &atlas); - - // Test that direction keys are handled correctly - // The traverser might consume next_direction immediately, so we check the actual direction - pacman.handle_key(Keycode::Up); - // Check that the direction was set (either in next_direction or current direction) - assert!(pacman.traverser.next_direction.is_some() || pacman.traverser.direction == Direction::Up); - - pacman.handle_key(Keycode::Down); - assert!(pacman.traverser.next_direction.is_some() || pacman.traverser.direction == Direction::Down); - - pacman.handle_key(Keycode::Left); - assert!(pacman.traverser.next_direction.is_some() || pacman.traverser.direction == Direction::Left); - - pacman.handle_key(Keycode::Right); - assert!(pacman.traverser.next_direction.is_some() || pacman.traverser.direction == Direction::Right); - } - - #[test] - fn test_handle_key_invalid_direction() { - let graph = create_test_graph(); - let atlas = create_test_atlas(); - let mut pacman = Pacman::new(&graph, 0, &atlas); - - let original_direction = pacman.traverser.direction; - let original_next_direction = pacman.traverser.next_direction; - - // Test invalid key - pacman.handle_key(Keycode::Space); - - // Should not change direction - assert_eq!(pacman.traverser.direction, original_direction); - assert_eq!(pacman.traverser.next_direction, original_next_direction); - } - - #[test] - fn test_get_pixel_pos_at_node() { - let graph = create_test_graph(); - let atlas = create_test_atlas(); - let pacman = Pacman::new(&graph, 0, &atlas); - - let pos = pacman.get_pixel_pos(&graph); - assert_eq!(pos, glam::Vec2::new(0.0, 0.0)); - } - - #[test] - fn test_get_pixel_pos_between_nodes() { - let graph = create_test_graph(); - let atlas = create_test_atlas(); - let mut pacman = Pacman::new(&graph, 0, &atlas); - - // Move pacman between nodes - need to advance with a larger distance to ensure movement - pacman.traverser.advance(&graph, 5.0, &can_pacman_traverse); // Larger advance to ensure movement - - let pos = pacman.get_pixel_pos(&graph); - // Should be between (0,0) and (16,0), but not exactly at (8,0) due to advance distance - assert!(pos.x >= 0.0 && pos.x <= 16.0); - assert_eq!(pos.y, 0.0); - } - - #[test] - fn test_tick_updates_texture() { - let graph = create_test_graph(); - let atlas = create_test_atlas(); - let mut pacman = Pacman::new(&graph, 0, &atlas); - - // Test that tick doesn't panic - pacman.tick(0.016, &graph); // 60 FPS frame time - } - - #[test] - fn test_pacman_initial_direction() { - let graph = create_test_graph(); - let atlas = create_test_atlas(); - let pacman = Pacman::new(&graph, 0, &atlas); - - // Pacman should start with the initial direction (Left) - assert_eq!(pacman.traverser.direction, Direction::Left); - // The next_direction might be consumed immediately when the traverser starts moving - // So we just check that the direction is set correctly - assert_eq!(pacman.traverser.direction, Direction::Left); - } -} diff --git a/src/game.rs b/src/game.rs index 2452467..35cbfd7 100644 --- a/src/game.rs +++ b/src/game.rs @@ -152,233 +152,3 @@ impl Game { Ok(()) } } - -#[cfg(test)] -mod tests { - use super::*; - use sdl2::keyboard::Keycode; - use sdl2::pixels::Color; - - fn create_test_game() -> Game { - // Create a minimal test game without SDL dependencies - // This is a simplified version for testing basic logic - let map = Map::new(RAW_BOARD); - let pacman_start_pos = map.find_starting_position(0).unwrap(); - let pacman_start_node = *map - .grid_to_node - .get(&glam::IVec2::new(pacman_start_pos.x as i32, pacman_start_pos.y as i32)) - .expect("Pac-Man starting position not found in graph"); - - // Create a dummy atlas for testing - let mut mapper = std::collections::HashMap::new(); - mapper.insert( - "pacman/up_a.png".to_string(), - crate::texture::sprite::MapperFrame { - x: 0, - y: 0, - width: 16, - height: 16, - }, - ); - mapper.insert( - "pacman/up_b.png".to_string(), - crate::texture::sprite::MapperFrame { - x: 16, - y: 0, - width: 16, - height: 16, - }, - ); - mapper.insert( - "pacman/down_a.png".to_string(), - crate::texture::sprite::MapperFrame { - x: 32, - y: 0, - width: 16, - height: 16, - }, - ); - mapper.insert( - "pacman/down_b.png".to_string(), - crate::texture::sprite::MapperFrame { - x: 48, - y: 0, - width: 16, - height: 16, - }, - ); - mapper.insert( - "pacman/left_a.png".to_string(), - crate::texture::sprite::MapperFrame { - x: 64, - y: 0, - width: 16, - height: 16, - }, - ); - mapper.insert( - "pacman/left_b.png".to_string(), - crate::texture::sprite::MapperFrame { - x: 80, - y: 0, - width: 16, - height: 16, - }, - ); - mapper.insert( - "pacman/right_a.png".to_string(), - crate::texture::sprite::MapperFrame { - x: 96, - y: 0, - width: 16, - height: 16, - }, - ); - mapper.insert( - "pacman/right_b.png".to_string(), - crate::texture::sprite::MapperFrame { - x: 112, - y: 0, - width: 16, - height: 16, - }, - ); - mapper.insert( - "pacman/full.png".to_string(), - crate::texture::sprite::MapperFrame { - x: 128, - y: 0, - width: 16, - height: 16, - }, - ); - mapper.insert( - "maze/full.png".to_string(), - crate::texture::sprite::MapperFrame { - x: 0, - y: 0, - width: 224, - height: 248, - }, - ); - - let atlas_mapper = crate::texture::sprite::AtlasMapper { frames: mapper }; - let dummy_texture = unsafe { std::mem::zeroed() }; - let atlas = crate::texture::sprite::SpriteAtlas::new(dummy_texture, atlas_mapper); - - let mut map_texture = crate::texture::sprite::SpriteAtlas::get_tile(&atlas, "maze/full.png").unwrap(); - map_texture.color = Some(Color::RGB(0x20, 0x20, 0xf9)); - - let text_texture = TextTexture::new(1.0); - let audio = Audio::new(); - let pacman = Pacman::new(&map.graph, pacman_start_node, &atlas); - - Game { - score: 0, - map, - pacman, - debug_mode: false, - map_texture, - text_texture, - audio, - atlas, - } - } - - #[test] - fn test_game_keyboard_event_direction_keys() { - let mut game = create_test_game(); - - // Test that direction keys are handled - game.keyboard_event(Keycode::Up); - game.keyboard_event(Keycode::Down); - game.keyboard_event(Keycode::Left); - game.keyboard_event(Keycode::Right); - - // Should not panic - assert!(true); - } - - #[test] - fn test_game_keyboard_event_mute_toggle() { - let mut game = create_test_game(); - - let initial_mute_state = game.audio.is_muted(); - - // Toggle mute - game.keyboard_event(Keycode::M); - - // Mute state should have changed - assert_eq!(game.audio.is_muted(), !initial_mute_state); - - // Toggle again - game.keyboard_event(Keycode::M); - - // Should be back to original state - assert_eq!(game.audio.is_muted(), initial_mute_state); - } - - #[test] - fn test_game_tick() { - let mut game = create_test_game(); - - // Test that tick doesn't panic - game.tick(0.016); // 60 FPS frame time - - assert!(true); - } - - #[test] - fn test_game_initial_state() { - let game = create_test_game(); - - assert_eq!(game.score, 0); - assert!(!game.debug_mode); - assert!(game.map.graph.node_count() > 0); - } - - #[test] - fn test_game_debug_mode_toggle() { - let mut game = create_test_game(); - - assert!(!game.debug_mode); - - // Toggle debug mode (this would normally be done via Space key in the app) - game.debug_mode = !game.debug_mode; - - assert!(game.debug_mode); - } - - #[test] - fn test_game_score_increment() { - let mut game = create_test_game(); - - let initial_score = game.score; - game.score += 10; - - assert_eq!(game.score, initial_score + 10); - } - - #[test] - fn test_game_pacman_initialization() { - let game = create_test_game(); - - // Check that Pac-Man was initialized - assert_eq!(game.pacman.traverser.direction, crate::entity::direction::Direction::Left); - // The traverser might start moving immediately, so we just check the direction - assert_eq!(game.pacman.traverser.direction, crate::entity::direction::Direction::Left); - } - - #[test] - fn test_game_map_initialization() { - let game = create_test_game(); - - // Check that map was initialized - assert!(game.map.graph.node_count() > 0); - assert!(!game.map.grid_to_node.is_empty()); - - // Check that Pac-Man's starting position exists - let pacman_pos = game.map.find_starting_position(0); - assert!(pacman_pos.is_some()); - } -} diff --git a/src/helpers.rs b/src/helpers.rs index 425b1e0..92a19c6 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -9,43 +9,3 @@ pub fn centered_with_size(pixel_pos: IVec2, size: UVec2) -> Rect { size.y, ) } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_centered_with_size_basic() { - let rect = centered_with_size(IVec2::new(100, 100), UVec2::new(50, 30)); - assert_eq!(rect.origin(), (75, 85)); - assert_eq!(rect.size(), (50, 30)); - } - - #[test] - fn test_centered_with_size_odd_dimensions() { - let rect = centered_with_size(IVec2::new(50, 50), UVec2::new(51, 31)); - assert_eq!(rect.origin(), (25, 35)); - assert_eq!(rect.size(), (51, 31)); - } - - #[test] - fn test_centered_with_size_zero_position() { - let rect = centered_with_size(IVec2::new(0, 0), UVec2::new(100, 100)); - assert_eq!(rect.origin(), (-50, -50)); - assert_eq!(rect.size(), (100, 100)); - } - - #[test] - fn test_centered_with_size_negative_position() { - let rect = centered_with_size(IVec2::new(-100, -50), UVec2::new(80, 40)); - assert_eq!(rect.origin(), (-140, -70)); - assert_eq!(rect.size(), (80, 40)); - } - - #[test] - fn test_centered_with_size_large_dimensions() { - let rect = centered_with_size(IVec2::new(1000, 1000), UVec2::new(1000, 1000)); - assert_eq!(rect.origin(), (500, 500)); - assert_eq!(rect.size(), (1000, 1000)); - } -} diff --git a/src/map/builder.rs b/src/map/builder.rs index 601de39..9d27b83 100644 --- a/src/map/builder.rs +++ b/src/map/builder.rs @@ -368,162 +368,3 @@ impl Map { .expect("Failed to connect left tunnel hidden node to right tunnel hidden node"); } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::constants::{BOARD_CELL_SIZE, CELL_SIZE}; - use glam::{IVec2, Vec2}; - - fn create_minimal_test_board() -> [&'static str; BOARD_CELL_SIZE.y as usize] { - let mut board = [""; BOARD_CELL_SIZE.y as usize]; - // Create a minimal valid board with house doors - board[0] = "############################"; - board[1] = "#............##............#"; - board[2] = "#.####.#####.##.#####.####.#"; - board[3] = "#o####.#####.##.#####.####o#"; - board[4] = "#.####.#####.##.#####.####.#"; - board[5] = "#..........................#"; - board[6] = "#.####.##.########.##.####.#"; - board[7] = "#.####.##.########.##.####.#"; - board[8] = "#......##....##....##......#"; - board[9] = "######.##### ## #####.######"; - board[10] = " #.##### ## #####.# "; - board[11] = " #.## == ##.# "; - board[12] = " #.## ######## ##.# "; - board[13] = "######.## ######## ##.######"; - board[14] = "T . ######## . T"; - board[15] = "######.## ######## ##.######"; - board[16] = " #.## ######## ##.# "; - board[17] = " #.## ##.# "; - board[18] = " #.## ######## ##.# "; - board[19] = "######.## ######## ##.######"; - board[20] = "#............##............#"; - board[21] = "#.####.#####.##.#####.####.#"; - board[22] = "#.####.#####.##.#####.####.#"; - board[23] = "#o..##.......X .......##..o#"; - board[24] = "###.##.##.########.##.##.###"; - board[25] = "###.##.##.########.##.##.###"; - board[26] = "#......##....##....##......#"; - board[27] = "#.##########.##.##########.#"; - board[28] = "#.##########.##.##########.#"; - board[29] = "#..........................#"; - board[30] = "############################"; - board - } - - #[test] - fn test_map_new() { - let board = create_minimal_test_board(); - let map = Map::new(board); - - assert!(map.graph.node_count() > 0); - assert!(!map.grid_to_node.is_empty()); - } - - #[test] - fn test_find_starting_position_pacman() { - let board = create_minimal_test_board(); - let map = Map::new(board); - - let pacman_pos = map.find_starting_position(0); - assert!(pacman_pos.is_some()); - - let pos = pacman_pos.unwrap(); - // Pacman should be found somewhere in the board - assert!(pos.x < BOARD_CELL_SIZE.x); - assert!(pos.y < BOARD_CELL_SIZE.y); - } - - #[test] - fn test_find_starting_position_ghost() { - let board = create_minimal_test_board(); - let map = Map::new(board); - - // Test for ghost 1 (might not exist in this board) - let ghost_pos = map.find_starting_position(1); - // Ghost 1 might not exist, so this could be None - if let Some(pos) = ghost_pos { - assert!(pos.x < BOARD_CELL_SIZE.x); - assert!(pos.y < BOARD_CELL_SIZE.y); - } - } - - #[test] - fn test_find_starting_position_nonexistent() { - let board = create_minimal_test_board(); - let map = Map::new(board); - - let pos = map.find_starting_position(99); // Non-existent entity - assert!(pos.is_none()); - } - - #[test] - fn test_map_graph_construction() { - let board = create_minimal_test_board(); - let map = Map::new(board); - - // Check that nodes were created - assert!(map.graph.node_count() > 0); - - // Check that grid_to_node mapping was created - assert!(!map.grid_to_node.is_empty()); - - // Check that some connections were made - let mut has_connections = false; - for intersection in &map.graph.adjacency_list { - if intersection.edges().next().is_some() { - has_connections = true; - break; - } - } - assert!(has_connections); - } - - #[test] - fn test_map_grid_to_node_mapping() { - let board = create_minimal_test_board(); - let map = Map::new(board); - - // Check that Pac-Man's position is mapped - let pacman_pos = map.find_starting_position(0).unwrap(); - let grid_pos = IVec2::new(pacman_pos.x as i32, pacman_pos.y as i32); - - assert!(map.grid_to_node.contains_key(&grid_pos)); - let node_id = map.grid_to_node[&grid_pos]; - assert!(map.graph.get_node(node_id).is_some()); - } - - #[test] - fn test_map_node_positions() { - let board = create_minimal_test_board(); - let map = Map::new(board); - - // Check that node positions are correctly calculated - for (grid_pos, &node_id) in &map.grid_to_node { - let node = map.graph.get_node(node_id).unwrap(); - let expected_pos = Vec2::new((grid_pos.x * CELL_SIZE as i32) as f32, (grid_pos.y * CELL_SIZE as i32) as f32) - + Vec2::splat(CELL_SIZE as f32 / 2.0); - - assert_eq!(node.position, expected_pos); - } - } - - #[test] - fn test_map_adjacent_connections() { - let board = create_minimal_test_board(); - let map = Map::new(board); - - // Check that adjacent walkable tiles are connected - // Find any node that has connections - let mut found_connected_node = false; - for &node_id in map.grid_to_node.values() { - let intersection = &map.graph.adjacency_list[node_id]; - if intersection.edges().next().is_some() { - found_connected_node = true; - break; - } - } - assert!(found_connected_node); - } -} diff --git a/src/map/parser.rs b/src/map/parser.rs index fcde796..0242027 100644 --- a/src/map/parser.rs +++ b/src/map/parser.rs @@ -118,56 +118,3 @@ impl MapTileParser { }) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::constants::RAW_BOARD; - - #[test] - fn test_parse_character() { - assert!(matches!(MapTileParser::parse_character('#').unwrap(), MapTile::Wall)); - assert!(matches!(MapTileParser::parse_character('.').unwrap(), MapTile::Pellet)); - assert!(matches!(MapTileParser::parse_character('o').unwrap(), MapTile::PowerPellet)); - assert!(matches!(MapTileParser::parse_character(' ').unwrap(), MapTile::Empty)); - assert!(matches!(MapTileParser::parse_character('T').unwrap(), MapTile::Tunnel)); - assert!(matches!(MapTileParser::parse_character('X').unwrap(), MapTile::Empty)); - assert!(matches!(MapTileParser::parse_character('=').unwrap(), MapTile::Wall)); - - // Test invalid character - assert!(MapTileParser::parse_character('Z').is_err()); - } - - #[test] - fn test_parse_board() { - let result = MapTileParser::parse_board(RAW_BOARD); - assert!(result.is_ok()); - - let parsed = result.unwrap(); - - // Verify we have tiles - assert_eq!(parsed.tiles.len(), BOARD_CELL_SIZE.x as usize); - assert_eq!(parsed.tiles[0].len(), BOARD_CELL_SIZE.y as usize); - - // Verify we found house door positions - assert!(parsed.house_door[0].is_some()); - assert!(parsed.house_door[1].is_some()); - - // Verify we found tunnel ends - assert!(parsed.tunnel_ends[0].is_some()); - assert!(parsed.tunnel_ends[1].is_some()); - - // Verify we found Pac-Man's starting position - assert!(parsed.pacman_start.is_some()); - } - - #[test] - fn test_parse_board_invalid_character() { - let mut invalid_board = RAW_BOARD.clone(); - invalid_board[0] = "###########################Z"; - - let result = MapTileParser::parse_board(invalid_board); - assert!(result.is_err()); - assert!(matches!(result.unwrap_err(), ParseError::UnknownCharacter('Z'))); - } -} diff --git a/src/map/render.rs b/src/map/render.rs index c531e6b..efb7895 100644 --- a/src/map/render.rs +++ b/src/map/render.rs @@ -65,80 +65,3 @@ impl MapRenderer { } } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::entity::graph::{Graph, Node}; - use crate::texture::sprite::{AtlasMapper, MapperFrame}; - use std::collections::HashMap; - - 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, crate::entity::direction::Direction::Right) - .unwrap(); - graph - .connect(node1, node3, false, None, crate::entity::direction::Direction::Down) - .unwrap(); - - graph - } - - fn create_test_atlas() -> SpriteAtlas { - let mut frames = HashMap::new(); - frames.insert( - "maze/full.png".to_string(), - MapperFrame { - x: 0, - y: 0, - width: 224, - height: 248, - }, - ); - let mapper = AtlasMapper { frames }; - let dummy_texture = unsafe { std::mem::zeroed() }; - SpriteAtlas::new(dummy_texture, mapper) - } - - #[test] - fn test_render_map_does_not_panic() { - // This test just ensures the function doesn't panic - // We can't easily test the actual rendering without SDL context - let atlas = create_test_atlas(); - let _map_texture = SpriteAtlas::get_tile(&atlas, "maze/full.png").unwrap(); - - // The function should not panic even with dummy data - // Note: We can't actually call render_map without a canvas, but we can test the logic - assert!(true); // Placeholder test - } - - #[test] - fn test_debug_render_nodes_does_not_panic() { - // This test just ensures the function doesn't panic - // We can't easily test the actual rendering without SDL context - let _graph = create_test_graph(); - - // The function should not panic even with dummy data - // Note: We can't actually call debug_render_nodes without a canvas, but we can test the logic - assert!(true); // Placeholder test - } - - #[test] - fn test_map_renderer_structure() { - // Test that MapRenderer is a unit struct - let _renderer = MapRenderer; - // This should compile and not panic - assert!(true); - } -} diff --git a/src/texture/animated.rs b/src/texture/animated.rs index 85f5843..fcf50cb 100644 --- a/src/texture/animated.rs +++ b/src/texture/animated.rs @@ -74,127 +74,3 @@ impl AnimatedTexture { self.tiles.len() } } - -#[cfg(test)] -mod tests { - use super::*; - use glam::U16Vec2; - use sdl2::pixels::Color; - - impl AtlasTile { - fn mock(id: u32) -> Self { - AtlasTile { - pos: U16Vec2::new(0, 0), - size: U16Vec2::new(16, 16), - color: Some(Color::RGB(id as u8, 0, 0)), - } - } - } - - #[test] - fn test_new_animated_texture() { - let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2), AtlasTile::mock(3)]; - let texture = AnimatedTexture::new(tiles.clone(), 0.1).unwrap(); - - assert_eq!(texture.current_frame(), 0); - assert_eq!(texture.time_bank(), 0.0); - assert_eq!(texture.frame_duration(), 0.1); - assert_eq!(texture.tiles_len(), 3); - } - - #[test] - fn test_new_animated_texture_zero_duration() { - let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)]; - let result = AnimatedTexture::new(tiles, 0.0); - assert!(result.is_err()); - assert!(matches!(result.unwrap_err(), AnimatedTextureError::InvalidFrameDuration(0.0))); - } - - #[test] - fn test_new_animated_texture_negative_duration() { - let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)]; - let result = AnimatedTexture::new(tiles, -0.1); - assert!(result.is_err()); - assert!(matches!( - result.unwrap_err(), - AnimatedTextureError::InvalidFrameDuration(-0.1) - )); - } - - #[test] - fn test_tick_no_frame_change() { - let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)]; - let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap(); - - // Tick with less than frame duration - texture.tick(0.05); - assert_eq!(texture.current_frame(), 0); - assert_eq!(texture.time_bank(), 0.05); - } - - #[test] - fn test_tick_single_frame_change() { - let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)]; - let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap(); - - // Tick with exactly frame duration - texture.tick(0.1); - assert_eq!(texture.current_frame(), 1); - assert_eq!(texture.time_bank(), 0.0); - } - - #[test] - fn test_tick_multiple_frame_changes() { - let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2), AtlasTile::mock(3)]; - let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap(); - - // Tick with 2.5 frame durations - texture.tick(0.25); - assert_eq!(texture.current_frame(), 2); - assert!((texture.time_bank() - 0.05).abs() < 0.001); - } - - #[test] - fn test_tick_wrap_around() { - let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)]; - let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap(); - - // Advance to last frame - texture.tick(0.1); - assert_eq!(texture.current_frame(), 1); - - // Advance again to wrap around - texture.tick(0.1); - assert_eq!(texture.current_frame(), 0); - } - - #[test] - fn test_current_tile() { - let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)]; - let texture = AnimatedTexture::new(tiles, 0.1).unwrap(); - - // Should return first tile initially - assert_eq!(texture.current_tile().color.unwrap().r, 1); - } - - #[test] - fn test_current_tile_after_frame_change() { - let tiles = vec![AtlasTile::mock(1), AtlasTile::mock(2)]; - let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap(); - - // Advance one frame - texture.tick(0.1); - assert_eq!(texture.current_tile().color.unwrap().r, 2); - } - - #[test] - fn test_single_tile_animation() { - let tiles = vec![AtlasTile::mock(1)]; - let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap(); - - // Should stay on same frame - texture.tick(0.1); - assert_eq!(texture.current_frame(), 0); - assert_eq!(texture.current_tile().color.unwrap().r, 1); - } -} diff --git a/src/texture/blinking.rs b/src/texture/blinking.rs index a79705e..3ed8f2a 100644 --- a/src/texture/blinking.rs +++ b/src/texture/blinking.rs @@ -44,135 +44,3 @@ impl BlinkingTexture { self.blink_duration } } - -#[cfg(test)] -mod tests { - use super::*; - use glam::U16Vec2; - 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)), - } - } - - #[test] - fn test_new_blinking_texture() { - let tile = mock_atlas_tile(1); - let texture = BlinkingTexture::new(tile, 0.5); - - assert_eq!(texture.is_on(), true); - assert_eq!(texture.time_bank(), 0.0); - assert_eq!(texture.blink_duration(), 0.5); - assert_eq!(texture.tile().color.unwrap().r, 1); - } - - #[test] - fn test_tick_no_blink_change() { - let tile = mock_atlas_tile(1); - let mut texture = BlinkingTexture::new(tile, 0.5); - - // Tick with less than blink duration - texture.tick(0.25); - assert_eq!(texture.is_on(), true); - assert_eq!(texture.time_bank(), 0.25); - } - - #[test] - fn test_tick_single_blink_change() { - let tile = mock_atlas_tile(1); - let mut texture = BlinkingTexture::new(tile, 0.5); - - // Tick with exactly blink duration - texture.tick(0.5); - assert_eq!(texture.is_on(), false); - assert_eq!(texture.time_bank(), 0.0); - } - - #[test] - fn test_tick_multiple_blink_changes() { - let tile = mock_atlas_tile(1); - let mut texture = BlinkingTexture::new(tile, 0.5); - - // First blink - texture.tick(0.5); - assert_eq!(texture.is_on(), false); - - // Second blink (back to on) - texture.tick(0.5); - assert_eq!(texture.is_on(), true); - - // Third blink (back to off) - texture.tick(0.5); - assert_eq!(texture.is_on(), false); - } - - #[test] - fn test_tick_partial_blink_duration() { - let tile = mock_atlas_tile(1); - let mut texture = BlinkingTexture::new(tile, 0.5); - - // Tick with 1.25 blink durations - texture.tick(0.625); - assert_eq!(texture.is_on(), false); - assert_eq!(texture.time_bank(), 0.125); - } - - #[test] - fn test_tick_with_zero_duration() { - let tile = mock_atlas_tile(1); - let mut texture = BlinkingTexture::new(tile, 0.0); - - // Should not cause issues - skip the test if blink_duration is 0 - if texture.blink_duration() > 0.0 { - texture.tick(0.1); - assert_eq!(texture.is_on(), true); - } - } - - #[test] - fn test_tick_with_negative_duration() { - let tile = mock_atlas_tile(1); - let mut texture = BlinkingTexture::new(tile, -0.5); - - // Should not cause issues - skip the test if blink_duration is negative - if texture.blink_duration() > 0.0 { - texture.tick(0.1); - assert_eq!(texture.is_on(), true); - } - } - - #[test] - fn test_tick_with_negative_delta_time() { - let tile = mock_atlas_tile(1); - let mut texture = BlinkingTexture::new(tile, 0.5); - - // Should not cause issues - texture.tick(-0.1); - assert_eq!(texture.is_on(), true); - assert_eq!(texture.time_bank(), -0.1); - } - - #[test] - fn test_tile_access() { - let tile = mock_atlas_tile(42); - let texture = BlinkingTexture::new(tile, 0.5); - - assert_eq!(texture.tile().color.unwrap().r, 42); - } - - #[test] - fn test_clone() { - let tile = mock_atlas_tile(1); - let texture = BlinkingTexture::new(tile, 0.5); - let cloned = texture.clone(); - - assert_eq!(texture.is_on(), cloned.is_on()); - assert_eq!(texture.time_bank(), cloned.time_bank()); - assert_eq!(texture.blink_duration(), cloned.blink_duration()); - assert_eq!(texture.tile().color.unwrap().r, cloned.tile().color.unwrap().r); - } -} diff --git a/src/texture/directional.rs b/src/texture/directional.rs index dc155e0..2f4ff8e 100644 --- a/src/texture/directional.rs +++ b/src/texture/directional.rs @@ -79,112 +79,3 @@ impl DirectionalAnimatedTexture { self.stopped_textures.len() } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::texture::sprite::AtlasTile; - use glam::U16Vec2; - 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)), - } - } - - fn mock_animated_texture(id: u32) -> AnimatedTexture { - AnimatedTexture::new(vec![mock_atlas_tile(id)], 0.1).expect("Invalid frame duration") - } - - #[test] - fn test_new_directional_animated_texture() { - let mut textures = HashMap::new(); - let mut stopped_textures = HashMap::new(); - - textures.insert(Direction::Up, mock_animated_texture(1)); - textures.insert(Direction::Down, mock_animated_texture(2)); - stopped_textures.insert(Direction::Up, mock_animated_texture(3)); - stopped_textures.insert(Direction::Down, mock_animated_texture(4)); - - let texture = DirectionalAnimatedTexture::new(textures, stopped_textures); - - assert_eq!(texture.texture_count(), 2); - assert_eq!(texture.stopped_texture_count(), 2); - assert!(texture.has_direction(Direction::Up)); - assert!(texture.has_direction(Direction::Down)); - assert!(!texture.has_direction(Direction::Left)); - assert!(texture.has_stopped_direction(Direction::Up)); - assert!(texture.has_stopped_direction(Direction::Down)); - assert!(!texture.has_stopped_direction(Direction::Left)); - } - - #[test] - fn test_tick() { - let mut textures = HashMap::new(); - textures.insert(Direction::Up, mock_animated_texture(1)); - textures.insert(Direction::Down, mock_animated_texture(2)); - - let mut texture = DirectionalAnimatedTexture::new(textures, HashMap::new()); - - // Should not panic - texture.tick(0.1); - assert_eq!(texture.texture_count(), 2); - } - - #[test] - fn test_empty_texture() { - let texture = DirectionalAnimatedTexture::new(HashMap::new(), HashMap::new()); - - assert_eq!(texture.texture_count(), 0); - assert_eq!(texture.stopped_texture_count(), 0); - assert!(!texture.has_direction(Direction::Up)); - assert!(!texture.has_stopped_direction(Direction::Up)); - } - - #[test] - fn test_partial_directions() { - let mut textures = HashMap::new(); - textures.insert(Direction::Up, mock_animated_texture(1)); - - let texture = DirectionalAnimatedTexture::new(textures, HashMap::new()); - - assert_eq!(texture.texture_count(), 1); - assert!(texture.has_direction(Direction::Up)); - assert!(!texture.has_direction(Direction::Down)); - assert!(!texture.has_direction(Direction::Left)); - assert!(!texture.has_direction(Direction::Right)); - } - - #[test] - fn test_clone() { - let mut textures = HashMap::new(); - textures.insert(Direction::Up, mock_animated_texture(1)); - - let texture = DirectionalAnimatedTexture::new(textures, HashMap::new()); - let cloned = texture.clone(); - - assert_eq!(texture.texture_count(), cloned.texture_count()); - assert_eq!(texture.stopped_texture_count(), cloned.stopped_texture_count()); - assert_eq!(texture.has_direction(Direction::Up), cloned.has_direction(Direction::Up)); - } - - #[test] - fn test_all_directions() { - let mut textures = HashMap::new(); - textures.insert(Direction::Up, mock_animated_texture(1)); - textures.insert(Direction::Down, mock_animated_texture(2)); - textures.insert(Direction::Left, mock_animated_texture(3)); - textures.insert(Direction::Right, mock_animated_texture(4)); - - let texture = DirectionalAnimatedTexture::new(textures, HashMap::new()); - - assert_eq!(texture.texture_count(), 4); - assert!(texture.has_direction(Direction::Up)); - assert!(texture.has_direction(Direction::Down)); - assert!(texture.has_direction(Direction::Left)); - assert!(texture.has_direction(Direction::Right)); - } -} diff --git a/src/texture/sprite.rs b/src/texture/sprite.rs index 85533a9..19941d4 100644 --- a/src/texture/sprite.rs +++ b/src/texture/sprite.rs @@ -134,236 +134,3 @@ impl SpriteAtlas { pub unsafe fn texture_to_static(texture: Texture) -> Texture<'static> { std::mem::transmute(texture) } - -#[cfg(test)] -mod tests { - use super::*; - use sdl2::pixels::Color; - - // Mock texture for testing - we'll use a dummy approach since we can't create real SDL2 textures - fn mock_texture() -> Texture<'static> { - // This is unsafe and only for testing - in real usage this would be a proper texture - unsafe { std::mem::transmute(0usize) } - } - - #[test] - fn test_atlas_tile_new() { - let pos = U16Vec2::new(10, 20); - let size = U16Vec2::new(32, 32); - let tile = AtlasTile::new(pos, size, None); - - assert_eq!(tile.pos, pos); - assert_eq!(tile.size, size); - assert_eq!(tile.color, None); - } - - #[test] - fn test_atlas_tile_with_color() { - let pos = U16Vec2::new(10, 20); - let size = U16Vec2::new(32, 32); - let color = Color::RGB(255, 0, 0); - let tile = AtlasTile::new(pos, size, None).with_color(color); - - assert_eq!(tile.pos, pos); - assert_eq!(tile.size, size); - assert_eq!(tile.color, Some(color)); - } - - #[test] - fn test_mapper_frame() { - let frame = MapperFrame { - x: 10, - y: 20, - width: 32, - height: 32, - }; - - assert_eq!(frame.x, 10); - assert_eq!(frame.y, 20); - assert_eq!(frame.width, 32); - assert_eq!(frame.height, 32); - } - - #[test] - fn test_atlas_mapper_new() { - let mut frames = HashMap::new(); - frames.insert( - "test".to_string(), - MapperFrame { - x: 0, - y: 0, - width: 32, - height: 32, - }, - ); - - let mapper = AtlasMapper { frames }; - - assert_eq!(mapper.frames.len(), 1); - assert!(mapper.frames.contains_key("test")); - } - - #[test] - fn test_sprite_atlas_new() { - let mut frames = HashMap::new(); - frames.insert( - "test".to_string(), - MapperFrame { - x: 0, - y: 0, - width: 32, - height: 32, - }, - ); - - let mapper = AtlasMapper { frames }; - let texture = mock_texture(); - let atlas = SpriteAtlas::new(texture, mapper); - - assert_eq!(atlas.tiles_count(), 1); - assert!(atlas.has_tile("test")); - assert_eq!(atlas.default_color(), None); - } - - #[test] - fn test_sprite_atlas_get_tile() { - let mut frames = HashMap::new(); - frames.insert( - "test".to_string(), - MapperFrame { - x: 10, - y: 20, - width: 32, - height: 64, - }, - ); - - 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, U16Vec2::new(10, 20)); - assert_eq!(tile.size, U16Vec2::new(32, 64)); - assert_eq!(tile.color, None); - } - - #[test] - fn test_sprite_atlas_get_tile_nonexistent() { - let mapper = AtlasMapper { frames: HashMap::new() }; - let texture = mock_texture(); - let atlas = SpriteAtlas::new(texture, mapper); - - let tile = atlas.get_tile("nonexistent"); - assert!(tile.is_none()); - } - - #[test] - fn test_sprite_atlas_set_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)); - } - - #[test] - fn test_sprite_atlas_empty() { - let mapper = AtlasMapper { frames: HashMap::new() }; - let texture = mock_texture(); - let atlas = SpriteAtlas::new(texture, mapper); - - assert_eq!(atlas.tiles_count(), 0); - assert!(!atlas.has_tile("any")); - } - - #[test] - fn test_sprite_atlas_multiple_tiles() { - let mut frames = HashMap::new(); - frames.insert( - "tile1".to_string(), - MapperFrame { - x: 0, - y: 0, - width: 32, - height: 32, - }, - ); - frames.insert( - "tile2".to_string(), - MapperFrame { - x: 32, - y: 0, - width: 64, - height: 64, - }, - ); - - 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")); - } - - #[test] - fn test_atlas_tile_clone() { - let pos = U16Vec2::new(10, 20); - let size = U16Vec2::new(32, 32); - let color = Color::RGB(255, 0, 0); - let tile = AtlasTile::new(pos, size, Some(color)); - let cloned = tile; - - assert_eq!(tile.pos, cloned.pos); - assert_eq!(tile.size, cloned.size); - assert_eq!(tile.color, cloned.color); - } - - #[test] - fn test_mapper_frame_clone() { - let frame = MapperFrame { - x: 10, - y: 20, - width: 32, - height: 64, - }; - let cloned = frame; - - assert_eq!(frame.x, cloned.x); - assert_eq!(frame.y, cloned.y); - assert_eq!(frame.width, cloned.width); - assert_eq!(frame.height, cloned.height); - } - - #[test] - fn test_atlas_mapper_clone() { - let mut frames = HashMap::new(); - frames.insert( - "test".to_string(), - MapperFrame { - x: 0, - y: 0, - width: 32, - height: 32, - }, - ); - - let mapper = AtlasMapper { frames }; - let cloned = mapper.clone(); - - assert_eq!(mapper.frames.len(), cloned.frames.len()); - assert!(mapper.frames.contains_key("test")); - assert!(cloned.frames.contains_key("test")); - } -} diff --git a/src/texture/text.rs b/src/texture/text.rs index 0fde8f5..e568237 100644 --- a/src/texture/text.rs +++ b/src/texture/text.rs @@ -151,228 +151,3 @@ impl TextTexture { (8.0 * self.scale) as u32 } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::texture::sprite::{AtlasMapper, MapperFrame, SpriteAtlas}; - use std::collections::HashMap; - - fn create_mock_atlas() -> SpriteAtlas { - let mut frames = HashMap::new(); - frames.insert( - "text/A.png".to_string(), - MapperFrame { - x: 0, - y: 0, - width: 8, - height: 8, - }, - ); - frames.insert( - "text/1.png".to_string(), - MapperFrame { - x: 8, - y: 0, - width: 8, - height: 8, - }, - ); - frames.insert( - "text/!.png".to_string(), - MapperFrame { - x: 16, - y: 0, - width: 8, - height: 8, - }, - ); - frames.insert( - "text/-.png".to_string(), - MapperFrame { - x: 24, - y: 0, - width: 8, - height: 8, - }, - ); - frames.insert( - "text/_double_quote.png".to_string(), - MapperFrame { - x: 32, - y: 0, - width: 8, - height: 8, - }, - ); - frames.insert( - "text/_forward_slash.png".to_string(), - MapperFrame { - x: 40, - y: 0, - width: 8, - height: 8, - }, - ); - - let mapper = AtlasMapper { frames }; - // Note: In real tests, we'd need a proper texture, but for unit tests we can work around this - unsafe { SpriteAtlas::new(std::mem::zeroed(), mapper) } - } - - #[test] - fn test_text_texture_new() { - let text_texture = TextTexture::new(1.0); - assert_eq!(text_texture.scale(), 1.0); - assert!(text_texture.char_map.is_empty()); - } - - #[test] - fn test_text_texture_new_with_scale() { - let text_texture = TextTexture::new(2.5); - assert_eq!(text_texture.scale(), 2.5); - } - - #[test] - fn test_char_to_tile_name_letters() { - let text_texture = TextTexture::new(1.0); - - assert_eq!(text_texture.char_to_tile_name('A'), Some("text/A.png".to_string())); - assert_eq!(text_texture.char_to_tile_name('Z'), Some("text/Z.png".to_string())); - assert_eq!(text_texture.char_to_tile_name('a'), None); // lowercase not supported - } - - #[test] - fn test_char_to_tile_name_numbers() { - let text_texture = TextTexture::new(1.0); - - assert_eq!(text_texture.char_to_tile_name('0'), Some("text/0.png".to_string())); - assert_eq!(text_texture.char_to_tile_name('9'), Some("text/9.png".to_string())); - } - - #[test] - fn test_char_to_tile_name_special_characters() { - let text_texture = TextTexture::new(1.0); - - assert_eq!(text_texture.char_to_tile_name('!'), Some("text/!.png".to_string())); - assert_eq!(text_texture.char_to_tile_name('-'), Some("text/-.png".to_string())); - assert_eq!( - text_texture.char_to_tile_name('"'), - Some("text/_double_quote.png".to_string()) - ); - assert_eq!( - text_texture.char_to_tile_name('/'), - Some("text/_forward_slash.png".to_string()) - ); - } - - #[test] - fn test_char_to_tile_name_unsupported() { - let text_texture = TextTexture::new(1.0); - - assert_eq!(text_texture.char_to_tile_name(' '), None); - assert_eq!(text_texture.char_to_tile_name('@'), None); - assert_eq!(text_texture.char_to_tile_name('a'), None); - assert_eq!(text_texture.char_to_tile_name('z'), None); - } - - #[test] - fn test_set_scale() { - let mut text_texture = TextTexture::new(1.0); - assert_eq!(text_texture.scale(), 1.0); - - text_texture.set_scale(3.0); - assert_eq!(text_texture.scale(), 3.0); - - text_texture.set_scale(0.5); - assert_eq!(text_texture.scale(), 0.5); - } - - #[test] - fn test_text_width_empty_string() { - let text_texture = TextTexture::new(1.0); - assert_eq!(text_texture.text_width(""), 0); - } - - #[test] - fn test_text_width_single_character() { - let text_texture = TextTexture::new(1.0); - assert_eq!(text_texture.text_width("A"), 8); // 8 pixels per character at scale 1.0 - } - - #[test] - fn test_text_width_multiple_characters() { - let text_texture = TextTexture::new(1.0); - assert_eq!(text_texture.text_width("ABC"), 24); // 3 * 8 = 24 pixels - } - - #[test] - fn test_text_width_with_scale() { - let text_texture = TextTexture::new(2.0); - assert_eq!(text_texture.text_width("A"), 16); // 8 * 2 = 16 pixels - assert_eq!(text_texture.text_width("ABC"), 48); // 3 * 16 = 48 pixels - } - - #[test] - fn test_text_width_with_unsupported_characters() { - let text_texture = TextTexture::new(1.0); - // Only supported characters should be counted - assert_eq!(text_texture.text_width("A B"), 16); // A and B only, space ignored - assert_eq!(text_texture.text_width("A@B"), 16); // A and B only, @ ignored - } - - #[test] - fn test_text_height() { - let text_texture = TextTexture::new(1.0); - assert_eq!(text_texture.text_height(), 8); // 8 pixels per character at scale 1.0 - } - - #[test] - fn test_text_height_with_scale() { - let text_texture = TextTexture::new(2.0); - assert_eq!(text_texture.text_height(), 16); // 8 * 2 = 16 pixels - } - - #[test] - fn test_text_height_with_fractional_scale() { - let text_texture = TextTexture::new(1.5); - assert_eq!(text_texture.text_height(), 12); // 8 * 1.5 = 12 pixels - } - - #[test] - fn test_get_char_tile_caching() { - let mut text_texture = TextTexture::new(1.0); - let atlas = create_mock_atlas(); - - // First call should cache the tile - let tile1 = text_texture.get_char_tile(&atlas, 'A'); - assert!(tile1.is_some()); - - // Second call should use cached tile - let tile2 = text_texture.get_char_tile(&atlas, 'A'); - assert!(tile2.is_some()); - - // Both should be the same tile - assert_eq!(tile1.unwrap().pos, tile2.unwrap().pos); - assert_eq!(tile1.unwrap().size, tile2.unwrap().size); - } - - #[test] - fn test_get_char_tile_unsupported_character() { - let mut text_texture = TextTexture::new(1.0); - let atlas = create_mock_atlas(); - - let tile = text_texture.get_char_tile(&atlas, ' '); - assert!(tile.is_none()); - } - - #[test] - fn test_get_char_tile_missing_from_atlas() { - let mut text_texture = TextTexture::new(1.0); - let atlas = create_mock_atlas(); - - // 'B' is not in our mock atlas - let tile = text_texture.get_char_tile(&atlas, 'B'); - assert!(tile.is_none()); - } -} diff --git a/tests/animated.rs b/tests/animated.rs new file mode 100644 index 0000000..18d3189 --- /dev/null +++ b/tests/animated.rs @@ -0,0 +1,67 @@ +use glam::U16Vec2; +use pacman::texture::animated::{AnimatedTexture, AnimatedTextureError}; +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)), + } +} + +#[test] +fn test_new_animated_texture_zero_duration() { + let tiles = vec![mock_atlas_tile(1), mock_atlas_tile(2)]; + let result = AnimatedTexture::new(tiles, 0.0); + assert!(result.is_err()); + assert!(matches!(result.unwrap_err(), AnimatedTextureError::InvalidFrameDuration(0.0))); +} + +#[test] +fn test_new_animated_texture_negative_duration() { + let tiles = vec![mock_atlas_tile(1), mock_atlas_tile(2)]; + let result = AnimatedTexture::new(tiles, -0.1); + assert!(result.is_err()); + assert!(matches!( + result.unwrap_err(), + AnimatedTextureError::InvalidFrameDuration(-0.1) + )); +} + +#[test] +fn test_tick_multiple_frame_changes() { + let tiles = vec![mock_atlas_tile(1), mock_atlas_tile(2), mock_atlas_tile(3)]; + let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap(); + + // Tick with 2.5 frame durations + texture.tick(0.25); + assert_eq!(texture.current_frame(), 2); + assert!((texture.time_bank() - 0.05).abs() < 0.001); +} + +#[test] +fn test_tick_wrap_around() { + let tiles = vec![mock_atlas_tile(1), mock_atlas_tile(2)]; + let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap(); + + // Advance to last frame + texture.tick(0.1); + assert_eq!(texture.current_frame(), 1); + + // Advance again to wrap around + texture.tick(0.1); + assert_eq!(texture.current_frame(), 0); +} + +#[test] +fn test_single_tile_animation() { + let tiles = vec![mock_atlas_tile(1)]; + let mut texture = AnimatedTexture::new(tiles, 0.1).unwrap(); + + // Should stay on same frame + texture.tick(0.1); + 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 new file mode 100644 index 0000000..9039b08 --- /dev/null +++ b/tests/blinking.rs @@ -0,0 +1,52 @@ +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)), + } +} + +#[test] +fn test_tick_multiple_blink_changes() { + let tile = mock_atlas_tile(1); + let mut texture = BlinkingTexture::new(tile, 0.5); + + // First blink + texture.tick(0.5); + assert_eq!(texture.is_on(), false); + + // Second blink (back to on) + texture.tick(0.5); + assert_eq!(texture.is_on(), true); + + // Third blink (back to off) + texture.tick(0.5); + assert_eq!(texture.is_on(), false); +} + +#[test] +fn test_tick_partial_blink_duration() { + let tile = mock_atlas_tile(1); + let mut texture = BlinkingTexture::new(tile, 0.5); + + // Tick with 1.25 blink durations + texture.tick(0.625); + assert_eq!(texture.is_on(), false); + assert_eq!(texture.time_bank(), 0.125); +} + +#[test] +fn test_tick_with_negative_delta_time() { + let tile = mock_atlas_tile(1); + let mut texture = BlinkingTexture::new(tile, 0.5); + + // Should not cause issues + texture.tick(-0.1); + assert_eq!(texture.is_on(), true); + assert_eq!(texture.time_bank(), -0.1); +} diff --git a/tests/constants.rs b/tests/constants.rs new file mode 100644 index 0000000..a849191 --- /dev/null +++ b/tests/constants.rs @@ -0,0 +1,173 @@ +use glam::UVec2; +use pacman::constants::*; + +#[test] +fn test_loop_time() { + // 60 FPS = 16.67ms per frame + let expected_nanos = (1_000_000_000.0 / 60.0) as u64; + assert_eq!(LOOP_TIME.as_nanos() as u64, expected_nanos); +} + +#[test] +fn test_cell_size() { + assert_eq!(CELL_SIZE, 8); +} + +#[test] +fn test_board_cell_size() { + assert_eq!(BOARD_CELL_SIZE.x, 28); + assert_eq!(BOARD_CELL_SIZE.y, 31); +} + +#[test] +fn test_scale() { + assert_eq!(SCALE, 2.6); +} + +#[test] +fn test_board_cell_offset() { + assert_eq!(BOARD_CELL_OFFSET.x, 0); + assert_eq!(BOARD_CELL_OFFSET.y, 3); +} + +#[test] +fn test_board_pixel_offset() { + let expected = UVec2::new(0 * CELL_SIZE, 3 * CELL_SIZE); + assert_eq!(BOARD_PIXEL_OFFSET, expected); + assert_eq!(BOARD_PIXEL_OFFSET.x, 0); + assert_eq!(BOARD_PIXEL_OFFSET.y, 24); // 3 * 8 +} + +#[test] +fn test_board_pixel_size() { + let expected = UVec2::new(28 * CELL_SIZE, 31 * CELL_SIZE); + assert_eq!(BOARD_PIXEL_SIZE, expected); + assert_eq!(BOARD_PIXEL_SIZE.x, 224); // 28 * 8 + assert_eq!(BOARD_PIXEL_SIZE.y, 248); // 31 * 8 +} + +#[test] +fn test_canvas_size() { + let expected = UVec2::new((28 + 0) * CELL_SIZE, (31 + 3) * CELL_SIZE); + assert_eq!(CANVAS_SIZE, expected); + assert_eq!(CANVAS_SIZE.x, 224); // (28 + 0) * 8 + assert_eq!(CANVAS_SIZE.y, 272); // (31 + 3) * 8 +} + +#[test] +fn test_map_tile_variants() { + assert_ne!(MapTile::Empty, MapTile::Wall); + assert_ne!(MapTile::Pellet, MapTile::PowerPellet); + assert_ne!(MapTile::Tunnel, MapTile::Empty); +} + +#[test] +fn test_map_tile_clone() { + let original = MapTile::Wall; + let cloned = original; + assert_eq!(original, cloned); +} + +#[test] +fn test_raw_board_dimensions() { + assert_eq!(RAW_BOARD.len(), BOARD_CELL_SIZE.y as usize); + assert_eq!(RAW_BOARD.len(), 31); + + for row in RAW_BOARD.iter() { + assert_eq!(row.len(), BOARD_CELL_SIZE.x as usize); + assert_eq!(row.len(), 28); + } +} + +#[test] +fn test_raw_board_boundaries() { + // First row should be all walls + assert!(RAW_BOARD[0].chars().all(|c| c == '#')); + + // Last row should be all walls + let last_row = RAW_BOARD[RAW_BOARD.len() - 1]; + assert!(last_row.chars().all(|c| c == '#')); + + // First and last character of each row should be walls (except tunnel rows and rows with spaces) + for (i, row) in RAW_BOARD.iter().enumerate() { + if i != 14 && !row.starts_with(' ') { + // Skip tunnel row and rows that start with spaces + assert_eq!(row.chars().next().unwrap(), '#'); + assert_eq!(row.chars().last().unwrap(), '#'); + } + } +} + +#[test] +fn test_raw_board_tunnel_row() { + // Row 14 should have tunnel characters 'T' at the edges + let tunnel_row = RAW_BOARD[14]; + assert_eq!(tunnel_row.chars().next().unwrap(), 'T'); + assert_eq!(tunnel_row.chars().last().unwrap(), 'T'); +} + +#[test] +fn test_raw_board_power_pellets() { + // Power pellets are represented by 'o' + let mut power_pellet_count = 0; + for row in RAW_BOARD.iter() { + power_pellet_count += row.chars().filter(|&c| c == 'o').count(); + } + assert_eq!(power_pellet_count, 4); // Should have exactly 4 power pellets +} + +#[test] +fn test_raw_board_starting_position() { + // Should have a starting position 'X' for Pac-Man + let mut found_starting_position = false; + for row in RAW_BOARD.iter() { + if row.contains('X') { + found_starting_position = true; + break; + } + } + assert!(found_starting_position); +} + +#[test] +fn test_raw_board_ghost_house() { + // The ghost house area should be present (the == characters) + let mut found_ghost_house = false; + for row in RAW_BOARD.iter() { + if row.contains("==") { + found_ghost_house = true; + break; + } + } + assert!(found_ghost_house); +} + +#[test] +fn test_raw_board_symmetry() { + // The board should be roughly symmetrical + let mid_point = RAW_BOARD[0].len() / 2; + + for row in RAW_BOARD.iter() { + let left_half = &row[..mid_point]; + let right_half = &row[mid_point..]; + + // Check that the halves are symmetrical (accounting for the center column) + assert_eq!(left_half.len(), right_half.len()); + } +} + +#[test] +fn test_constants_consistency() { + // Verify that derived constants are calculated correctly + let calculated_pixel_offset = UVec2::new(BOARD_CELL_OFFSET.x * CELL_SIZE, BOARD_CELL_OFFSET.y * CELL_SIZE); + assert_eq!(BOARD_PIXEL_OFFSET, calculated_pixel_offset); + + let calculated_pixel_size = UVec2::new(BOARD_CELL_SIZE.x * CELL_SIZE, BOARD_CELL_SIZE.y * CELL_SIZE); + assert_eq!(BOARD_PIXEL_SIZE, calculated_pixel_size); + + let calculated_canvas_size = UVec2::new( + (BOARD_CELL_SIZE.x + BOARD_CELL_OFFSET.x) * CELL_SIZE, + (BOARD_CELL_SIZE.y + BOARD_CELL_OFFSET.y) * CELL_SIZE, + ); + assert_eq!(CANVAS_SIZE, calculated_canvas_size); +} diff --git a/tests/direction.rs b/tests/direction.rs new file mode 100644 index 0000000..fb30e00 --- /dev/null +++ b/tests/direction.rs @@ -0,0 +1,61 @@ +use glam::IVec2; +use pacman::entity::direction::*; + +#[test] +fn test_direction_opposite() { + assert_eq!(Direction::Up.opposite(), Direction::Down); + assert_eq!(Direction::Down.opposite(), Direction::Up); + assert_eq!(Direction::Left.opposite(), Direction::Right); + assert_eq!(Direction::Right.opposite(), Direction::Left); +} + +#[test] +fn test_direction_as_ivec2() { + assert_eq!(Direction::Up.as_ivec2(), -IVec2::Y); + assert_eq!(Direction::Down.as_ivec2(), IVec2::Y); + assert_eq!(Direction::Left.as_ivec2(), -IVec2::X); + assert_eq!(Direction::Right.as_ivec2(), IVec2::X); +} + +#[test] +fn test_direction_from_ivec2() { + assert_eq!(IVec2::from(Direction::Up), -IVec2::Y); + assert_eq!(IVec2::from(Direction::Down), IVec2::Y); + assert_eq!(IVec2::from(Direction::Left), -IVec2::X); + assert_eq!(IVec2::from(Direction::Right), IVec2::X); +} + +#[test] +fn test_directions_constant() { + assert_eq!(DIRECTIONS.len(), 4); + assert!(DIRECTIONS.contains(&Direction::Up)); + assert!(DIRECTIONS.contains(&Direction::Down)); + assert!(DIRECTIONS.contains(&Direction::Left)); + assert!(DIRECTIONS.contains(&Direction::Right)); +} + +#[test] +fn test_direction_equality() { + assert_eq!(Direction::Up, Direction::Up); + assert_ne!(Direction::Up, Direction::Down); + assert_ne!(Direction::Left, Direction::Right); +} + +#[test] +fn test_direction_clone() { + let dir = Direction::Up; + let cloned = dir; + assert_eq!(dir, cloned); +} + +#[test] +fn test_direction_hash() { + use std::collections::HashMap; + let mut map = HashMap::new(); + map.insert(Direction::Up, "up"); + map.insert(Direction::Down, "down"); + + assert_eq!(map.get(&Direction::Up), Some(&"up")); + assert_eq!(map.get(&Direction::Down), Some(&"down")); + assert_eq!(map.get(&Direction::Left), None); +} diff --git a/tests/directional.rs b/tests/directional.rs new file mode 100644 index 0000000..ad42ea6 --- /dev/null +++ b/tests/directional.rs @@ -0,0 +1,50 @@ +use glam::U16Vec2; +use pacman::entity::direction::Direction; +use pacman::texture::animated::AnimatedTexture; +use pacman::texture::directional::DirectionalAnimatedTexture; +use pacman::texture::sprite::AtlasTile; +use sdl2::pixels::Color; +use std::collections::HashMap; + +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)), + } +} + +fn mock_animated_texture(id: u32) -> AnimatedTexture { + AnimatedTexture::new(vec![mock_atlas_tile(id)], 0.1).expect("Invalid frame duration") +} + +#[test] +fn test_partial_directions() { + let mut textures = HashMap::new(); + textures.insert(Direction::Up, mock_animated_texture(1)); + + let texture = DirectionalAnimatedTexture::new(textures, HashMap::new()); + + assert_eq!(texture.texture_count(), 1); + assert!(texture.has_direction(Direction::Up)); + assert!(!texture.has_direction(Direction::Down)); + assert!(!texture.has_direction(Direction::Left)); + assert!(!texture.has_direction(Direction::Right)); +} + +#[test] +fn test_all_directions() { + let mut textures = HashMap::new(); + textures.insert(Direction::Up, mock_animated_texture(1)); + textures.insert(Direction::Down, mock_animated_texture(2)); + textures.insert(Direction::Left, mock_animated_texture(3)); + textures.insert(Direction::Right, mock_animated_texture(4)); + + let texture = DirectionalAnimatedTexture::new(textures, HashMap::new()); + + assert_eq!(texture.texture_count(), 4); + assert!(texture.has_direction(Direction::Up)); + assert!(texture.has_direction(Direction::Down)); + assert!(texture.has_direction(Direction::Left)); + assert!(texture.has_direction(Direction::Right)); +} diff --git a/tests/graph.rs b/tests/graph.rs new file mode 100644 index 0000000..1c3e247 --- /dev/null +++ b/tests/graph.rs @@ -0,0 +1,152 @@ +use pacman::entity::direction::Direction; +use pacman::entity::graph::{Graph, Node, Position, Traverser}; + +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 +} + +#[test] +fn test_graph_connect() { + 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 result = graph.connect(node1, node2, false, None, Direction::Right); + assert!(result.is_ok()); + + // Check that edges were added in both directions + let edge1 = graph.find_edge_in_direction(node1, Direction::Right); + let edge2 = graph.find_edge_in_direction(node2, Direction::Left); + + assert!(edge1.is_some()); + assert!(edge2.is_some()); + assert_eq!(edge1.unwrap().target, node2); + assert_eq!(edge2.unwrap().target, node1); +} + +#[test] +fn test_graph_connect_invalid_nodes() { + let mut graph = Graph::new(); + let node1 = graph.add_node(Node { + position: glam::Vec2::new(0.0, 0.0), + }); + + // Try to connect to non-existent node + let result = graph.connect(node1, 999, false, None, Direction::Right); + assert!(result.is_err()); + + // Try to connect from non-existent node + let result = graph.connect(999, node1, false, None, Direction::Right); + assert!(result.is_err()); +} + +#[test] +fn test_graph_find_edge() { + 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), + }); + + graph.connect(node1, node2, false, None, Direction::Right).unwrap(); + + let edge = graph.find_edge(node1, node2); + assert!(edge.is_some()); + assert_eq!(edge.unwrap().target, node2); + + // Test non-existent edge + assert!(graph.find_edge(node1, 999).is_none()); +} + +#[test] +fn test_graph_find_edge_in_direction() { + 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), + }); + + graph.connect(node1, node2, false, None, Direction::Right).unwrap(); + + let edge = graph.find_edge_in_direction(node1, Direction::Right); + assert!(edge.is_some()); + assert_eq!(edge.unwrap().target, node2); + + // Test non-existent direction + assert!(graph.find_edge_in_direction(node1, Direction::Up).is_none()); +} + +#[test] +fn test_traverser_set_next_direction() { + let graph = create_test_graph(); + let mut traverser = Traverser::new(&graph, 0, Direction::Left, &|_| true); + + traverser.set_next_direction(Direction::Up); + assert!(traverser.next_direction.is_some()); + assert_eq!(traverser.next_direction.unwrap().0, Direction::Up); + + // Setting same direction should not change anything + traverser.set_next_direction(Direction::Up); + assert_eq!(traverser.next_direction.unwrap().0, Direction::Up); +} + +#[test] +fn test_traverser_advance_at_node() { + let graph = create_test_graph(); + let mut traverser = Traverser::new(&graph, 0, Direction::Right, &|_| true); + + // Should start moving in the initial direction + traverser.advance(&graph, 5.0, &|_| true); + + match traverser.position { + Position::BetweenNodes { from, to, traversed } => { + assert_eq!(from, 0); + assert_eq!(to, 1); + assert_eq!(traversed, 5.0); + } + _ => panic!("Expected to be between nodes"), + } +} + +#[test] +fn test_traverser_advance_between_nodes() { + let graph = create_test_graph(); + let mut traverser = Traverser::new(&graph, 0, Direction::Right, &|_| true); + + // Move to between nodes + traverser.advance(&graph, 5.0, &|_| true); + + // Advance further + traverser.advance(&graph, 3.0, &|_| true); + + match traverser.position { + Position::BetweenNodes { from, to, traversed } => { + assert_eq!(from, 0); + assert_eq!(to, 1); + assert_eq!(traversed, 8.0); + } + _ => panic!("Expected to be between nodes"), + } +} diff --git a/tests/helpers.rs b/tests/helpers.rs new file mode 100644 index 0000000..8b0dab6 --- /dev/null +++ b/tests/helpers.rs @@ -0,0 +1,37 @@ +use glam::{IVec2, UVec2}; +use pacman::helpers::centered_with_size; + +#[test] +fn test_centered_with_size_basic() { + let rect = centered_with_size(IVec2::new(100, 100), UVec2::new(50, 30)); + assert_eq!(rect.origin(), (75, 85)); + assert_eq!(rect.size(), (50, 30)); +} + +#[test] +fn test_centered_with_size_odd_dimensions() { + let rect = centered_with_size(IVec2::new(50, 50), UVec2::new(51, 31)); + assert_eq!(rect.origin(), (25, 35)); + assert_eq!(rect.size(), (51, 31)); +} + +#[test] +fn test_centered_with_size_zero_position() { + let rect = centered_with_size(IVec2::new(0, 0), UVec2::new(100, 100)); + assert_eq!(rect.origin(), (-50, -50)); + assert_eq!(rect.size(), (100, 100)); +} + +#[test] +fn test_centered_with_size_negative_position() { + let rect = centered_with_size(IVec2::new(-100, -50), UVec2::new(80, 40)); + assert_eq!(rect.origin(), (-140, -70)); + assert_eq!(rect.size(), (80, 40)); +} + +#[test] +fn test_centered_with_size_large_dimensions() { + let rect = centered_with_size(IVec2::new(1000, 1000), UVec2::new(1000, 1000)); + assert_eq!(rect.origin(), (500, 500)); + assert_eq!(rect.size(), (1000, 1000)); +} diff --git a/tests/map_builder.rs b/tests/map_builder.rs new file mode 100644 index 0000000..cfc0f3e --- /dev/null +++ b/tests/map_builder.rs @@ -0,0 +1,114 @@ +use glam::{IVec2, Vec2}; +use pacman::constants::{BOARD_CELL_SIZE, CELL_SIZE}; +use pacman::map::Map; + +fn create_minimal_test_board() -> [&'static str; BOARD_CELL_SIZE.y as usize] { + let mut board = [""; BOARD_CELL_SIZE.y as usize]; + // Create a minimal valid board with house doors + board[0] = "############################"; + board[1] = "#............##............#"; + board[2] = "#.####.#####.##.#####.####.#"; + board[3] = "#o####.#####.##.#####.####o#"; + board[4] = "#.####.#####.##.#####.####.#"; + board[5] = "#..........................#"; + board[6] = "#.####.##.########.##.####.#"; + board[7] = "#.####.##.########.##.####.#"; + board[8] = "#......##....##....##......#"; + board[9] = "######.##### ## #####.######"; + board[10] = " #.##### ## #####.# "; + board[11] = " #.## == ##.# "; + board[12] = " #.## ######## ##.# "; + board[13] = "######.## ######## ##.######"; + board[14] = "T . ######## . T"; + board[15] = "######.## ######## ##.######"; + board[16] = " #.## ######## ##.# "; + board[17] = " #.## ##.# "; + board[18] = " #.## ######## ##.# "; + board[19] = "######.## ######## ##.######"; + board[20] = "#............##............#"; + board[21] = "#.####.#####.##.#####.####.#"; + board[22] = "#.####.#####.##.#####.####.#"; + board[23] = "#o..##.......X .......##..o#"; + board[24] = "###.##.##.########.##.##.###"; + board[25] = "###.##.##.########.##.##.###"; + board[26] = "#......##....##....##......#"; + board[27] = "#.##########.##.##########.#"; + board[28] = "#.##########.##.##########.#"; + board[29] = "#..........................#"; + board[30] = "############################"; + board +} + +#[test] +fn test_find_starting_position_pacman() { + let board = create_minimal_test_board(); + let map = Map::new(board); + + let pacman_pos = map.find_starting_position(0); + assert!(pacman_pos.is_some()); + + let pos = pacman_pos.unwrap(); + // Pacman should be found somewhere in the board + assert!(pos.x < BOARD_CELL_SIZE.x); + assert!(pos.y < BOARD_CELL_SIZE.y); +} + +#[test] +fn test_find_starting_position_nonexistent() { + let board = create_minimal_test_board(); + let map = Map::new(board); + + let pos = map.find_starting_position(99); // Non-existent entity + assert!(pos.is_none()); +} + +#[test] +fn test_map_graph_construction() { + let board = create_minimal_test_board(); + let map = Map::new(board); + + // Check that nodes were created + assert!(map.graph.node_count() > 0); + + // Check that grid_to_node mapping was created + assert!(!map.grid_to_node.is_empty()); + + // Check that some connections were made + let mut has_connections = false; + for intersection in &map.graph.adjacency_list { + if intersection.edges().next().is_some() { + has_connections = true; + break; + } + } + assert!(has_connections); +} + +#[test] +fn test_map_grid_to_node_mapping() { + let board = create_minimal_test_board(); + let map = Map::new(board); + + // Check that Pac-Man's position is mapped + let pacman_pos = map.find_starting_position(0).unwrap(); + let grid_pos = IVec2::new(pacman_pos.x as i32, pacman_pos.y as i32); + + assert!(map.grid_to_node.contains_key(&grid_pos)); + let node_id = map.grid_to_node[&grid_pos]; + assert!(map.graph.get_node(node_id).is_some()); +} + +#[test] +fn test_map_node_positions() { + let board = create_minimal_test_board(); + let map = Map::new(board); + + // Check that node positions are correctly calculated + for (grid_pos, &node_id) in &map.grid_to_node { + let node = map.graph.get_node(node_id).unwrap(); + let expected_pos = Vec2::new((grid_pos.x * CELL_SIZE as i32) as f32, (grid_pos.y * CELL_SIZE as i32) as f32) + + Vec2::splat(CELL_SIZE as f32 / 2.0); + + assert_eq!(node.position, expected_pos); + } +} diff --git a/tests/pacman.rs b/tests/pacman.rs new file mode 100644 index 0000000..e893a8b --- /dev/null +++ b/tests/pacman.rs @@ -0,0 +1,152 @@ +use pacman::entity::direction::Direction; +use pacman::entity::graph::{Graph, Node}; +use pacman::entity::pacman::Pacman; +use pacman::texture::sprite::{AtlasMapper, MapperFrame, SpriteAtlas}; +use sdl2::keyboard::Keycode; +use std::collections::HashMap; + +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 +} + +fn create_test_atlas() -> SpriteAtlas { + // Create a minimal test atlas with required tiles + let mut frames = HashMap::new(); + frames.insert( + "pacman/up_a.png".to_string(), + MapperFrame { + x: 0, + y: 0, + width: 16, + height: 16, + }, + ); + frames.insert( + "pacman/up_b.png".to_string(), + MapperFrame { + x: 16, + y: 0, + width: 16, + height: 16, + }, + ); + frames.insert( + "pacman/down_a.png".to_string(), + MapperFrame { + x: 32, + y: 0, + width: 16, + height: 16, + }, + ); + frames.insert( + "pacman/down_b.png".to_string(), + MapperFrame { + x: 48, + y: 0, + width: 16, + height: 16, + }, + ); + frames.insert( + "pacman/left_a.png".to_string(), + MapperFrame { + x: 64, + y: 0, + width: 16, + height: 16, + }, + ); + frames.insert( + "pacman/left_b.png".to_string(), + MapperFrame { + x: 80, + y: 0, + width: 16, + height: 16, + }, + ); + frames.insert( + "pacman/right_a.png".to_string(), + MapperFrame { + x: 96, + y: 0, + width: 16, + height: 16, + }, + ); + frames.insert( + "pacman/right_b.png".to_string(), + MapperFrame { + x: 112, + y: 0, + width: 16, + height: 16, + }, + ); + frames.insert( + "pacman/full.png".to_string(), + MapperFrame { + x: 128, + y: 0, + width: 16, + height: 16, + }, + ); + + let mapper = AtlasMapper { frames }; + // Create a dummy texture (we won't actually render, just test the logic) + let dummy_texture = unsafe { std::mem::zeroed() }; + SpriteAtlas::new(dummy_texture, mapper) +} + +#[test] +fn test_handle_key_valid_directions() { + let graph = create_test_graph(); + let atlas = create_test_atlas(); + let mut pacman = Pacman::new(&graph, 0, &atlas); + + // Test that direction keys are handled correctly + pacman.handle_key(Keycode::Up); + assert!(pacman.traverser.next_direction.is_some() || pacman.traverser.direction == Direction::Up); + + pacman.handle_key(Keycode::Down); + assert!(pacman.traverser.next_direction.is_some() || pacman.traverser.direction == Direction::Down); + + pacman.handle_key(Keycode::Left); + assert!(pacman.traverser.next_direction.is_some() || pacman.traverser.direction == Direction::Left); + + pacman.handle_key(Keycode::Right); + assert!(pacman.traverser.next_direction.is_some() || pacman.traverser.direction == Direction::Right); +} + +#[test] +fn test_handle_key_invalid_direction() { + let graph = create_test_graph(); + let atlas = create_test_atlas(); + let mut pacman = Pacman::new(&graph, 0, &atlas); + + let original_direction = pacman.traverser.direction; + let original_next_direction = pacman.traverser.next_direction; + + // Test invalid key + pacman.handle_key(Keycode::Space); + + // Should not change direction + assert_eq!(pacman.traverser.direction, original_direction); + assert_eq!(pacman.traverser.next_direction, original_next_direction); +} diff --git a/tests/parser.rs b/tests/parser.rs new file mode 100644 index 0000000..ebbb030 --- /dev/null +++ b/tests/parser.rs @@ -0,0 +1,70 @@ +use pacman::constants::{BOARD_CELL_SIZE, RAW_BOARD}; +use pacman::map::parser::{MapTileParser, ParseError}; + +#[test] +fn test_parse_character() { + assert!(matches!( + MapTileParser::parse_character('#').unwrap(), + pacman::constants::MapTile::Wall + )); + assert!(matches!( + MapTileParser::parse_character('.').unwrap(), + pacman::constants::MapTile::Pellet + )); + assert!(matches!( + MapTileParser::parse_character('o').unwrap(), + pacman::constants::MapTile::PowerPellet + )); + assert!(matches!( + MapTileParser::parse_character(' ').unwrap(), + pacman::constants::MapTile::Empty + )); + assert!(matches!( + MapTileParser::parse_character('T').unwrap(), + pacman::constants::MapTile::Tunnel + )); + assert!(matches!( + MapTileParser::parse_character('X').unwrap(), + pacman::constants::MapTile::Empty + )); + assert!(matches!( + MapTileParser::parse_character('=').unwrap(), + pacman::constants::MapTile::Wall + )); + + // Test invalid character + assert!(MapTileParser::parse_character('Z').is_err()); +} + +#[test] +fn test_parse_board() { + let result = MapTileParser::parse_board(RAW_BOARD); + assert!(result.is_ok()); + + let parsed = result.unwrap(); + + // Verify we have tiles + assert_eq!(parsed.tiles.len(), BOARD_CELL_SIZE.x as usize); + assert_eq!(parsed.tiles[0].len(), BOARD_CELL_SIZE.y as usize); + + // Verify we found house door positions + assert!(parsed.house_door[0].is_some()); + assert!(parsed.house_door[1].is_some()); + + // Verify we found tunnel ends + assert!(parsed.tunnel_ends[0].is_some()); + assert!(parsed.tunnel_ends[1].is_some()); + + // Verify we found Pac-Man's starting position + assert!(parsed.pacman_start.is_some()); +} + +#[test] +fn test_parse_board_invalid_character() { + let mut invalid_board = RAW_BOARD.clone(); + invalid_board[0] = "###########################Z"; + + let result = MapTileParser::parse_board(invalid_board); + assert!(result.is_err()); + assert!(matches!(result.unwrap_err(), ParseError::UnknownCharacter('Z'))); +} diff --git a/tests/sprite.rs b/tests/sprite.rs new file mode 100644 index 0000000..9a77687 --- /dev/null +++ b/tests/sprite.rs @@ -0,0 +1,90 @@ +use pacman::texture::sprite::{AtlasMapper, MapperFrame, SpriteAtlas}; +use sdl2::pixels::Color; +use std::collections::HashMap; + +// Mock texture for testing +fn mock_texture() -> sdl2::render::Texture<'static> { + unsafe { std::mem::transmute(0usize) } +} + +#[test] +fn test_sprite_atlas_get_tile() { + let mut frames = HashMap::new(); + frames.insert( + "test".to_string(), + MapperFrame { + x: 10, + y: 20, + width: 32, + height: 64, + }, + ); + + 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] +fn test_sprite_atlas_get_tile_nonexistent() { + let mapper = AtlasMapper { frames: HashMap::new() }; + let texture = mock_texture(); + let atlas = SpriteAtlas::new(texture, mapper); + + let tile = atlas.get_tile("nonexistent"); + assert!(tile.is_none()); +} + +#[test] +fn test_sprite_atlas_set_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)); +} + +#[test] +fn test_sprite_atlas_multiple_tiles() { + let mut frames = HashMap::new(); + frames.insert( + "tile1".to_string(), + MapperFrame { + x: 0, + y: 0, + width: 32, + height: 32, + }, + ); + frames.insert( + "tile2".to_string(), + MapperFrame { + x: 32, + y: 0, + width: 64, + height: 64, + }, + ); + + 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")); +}