diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/maze.rs b/src/maze.rs index 59e5667..8d3ab03 100644 --- a/src/maze.rs +++ b/src/maze.rs @@ -6,7 +6,7 @@ use super::{HexTile, Walls}; /// Represents a hexagonal maze with tiles and walls #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct HexMaze { tiles: HashMap, layout: HexLayout, @@ -77,19 +77,181 @@ impl HexMaze { #[cfg(test)] mod tests { use super::*; + #[test] - fn maze() { - let layout = HexLayout::default(); - let mut maze = HexMaze::new(layout); + fn new_maze() { + let maze = HexMaze::default(); + assert!(maze.is_empty(), "New maze should be empty"); + assert_eq!(maze.len(), 0, "New maze should have zero tiles"); + } + + #[test] + fn add_tile() { + let mut maze = HexMaze::default(); + let coords = [Hex::ZERO, Hex::new(1, -1), Hex::new(-1, 1)]; + + // Add tiles + for &coord in &coords { + maze.add_tile(coord); + assert!( + maze.get_tile(&coord).is_some(), + "Tile should exist after adding" + ); + } + + assert_eq!( + maze.len(), + coords.len(), + "Maze should contain all added tiles" + ); + } + + #[test] + fn wall_operations() { + let mut maze = HexMaze::default(); + let coord = Hex::ZERO; + maze.add_tile(coord); + + // Test adding walls + let directions = [ + EdgeDirection::FLAT_TOP, + EdgeDirection::FLAT_BOTTOM, + EdgeDirection::POINTY_TOP_RIGHT, + ]; + + for &direction in &directions { + maze.add_wall(coord, direction); + assert!( + maze.get_walls(&coord).unwrap().has(direction), + "Wall should exist after adding" + ); + } + } + + #[test] + fn tile_iteration() { + let mut maze = HexMaze::default(); + let coords = [Hex::ZERO, Hex::new(1, 0), Hex::new(0, 1)]; + + // Add tiles + for &coord in &coords { + maze.add_tile(coord); + } + + // Test iterator + let collected = maze.tiles().map(|(_, tile)| tile).collect::>(); + assert_eq!( + collected.len(), + coords.len(), + "Iterator should yield all tiles" + ); + } + + #[test] + fn maze_clone() { + let mut maze = HexMaze::default(); + let coord = Hex::ZERO; + maze.add_tile(coord); + maze.add_wall(coord, EdgeDirection::FLAT_TOP); + + // Test cloning + let cloned_maze = maze.clone(); + assert_eq!( + maze.len(), + cloned_maze.len(), + "Cloned maze should have same size" + ); + assert!( + cloned_maze + .get_walls(&coord) + .unwrap() + .has(EdgeDirection::FLAT_TOP), + "Cloned maze should preserve wall state" + ); + } + + #[test] + fn empty_tile_operations() { + let mut maze = HexMaze::default(); let coord = Hex::ZERO; - maze.add_tile(coord); - assert!(maze.get_tile(&coord).is_some()); + // Operations on non-existent tile + assert!( + maze.get_tile(&coord).is_none(), + "Should return None for non-existent tile" + ); + assert!( + maze.get_walls(&coord).is_none(), + "Should return None for non-existent walls" + ); - maze.add_wall(coord, EdgeDirection::FLAT_TOP_LEFT); - assert!(maze - .get_walls(&coord) - .unwrap() - .has(EdgeDirection::FLAT_TOP_LEFT)); + // Adding wall to non-existent tile should not panic + maze.add_wall(coord, EdgeDirection::FLAT_TOP); + } + + /* #[test] + fn multiple_tile_operations() { + let mut maze = HexMaze::default(); + let coord = Hex::ZERO; + + // Add same tile multiple times + maze.add_tile(coord); + let first_tile = maze.get_tile(&coord).unwrap(); + maze.add_tile(coord); + let second_tile = maze.get_tile(&coord).unwrap(); + + assert_eq!( + first_tile, second_tile, + "Repeated add_tile should update existing tile" + ); + assert_eq!(maze.len(), 1, "Repeated add_tile should not increase size"); + } */ + + #[test] + fn maze_boundaries() { + let mut maze = HexMaze::default(); + let extreme_coords = [ + Hex::new(i32::MAX, i32::MIN), + Hex::new(i32::MIN, i32::MAX), + Hex::new(0, i32::MAX), + Hex::new(0, i32::MIN), + Hex::new(i32::MAX, 0), + Hex::new(i32::MIN, 0), + ]; + + // Test with extreme coordinates + for &coord in &extreme_coords { + maze.add_tile(coord); + assert!( + maze.get_tile(&coord).is_some(), + "Should handle extreme coordinates" + ); + } + } + + #[test] + fn iterator_consistency() { + let mut maze = HexMaze::default(); + let coords = [Hex::ZERO, Hex::new(1, -1), Hex::new(-1, 1)]; + + // Add tiles + for &coord in &coords { + maze.add_tile(coord); + } + + // Verify iterator + let iter_coords = maze.tiles().map(|(coord, _)| *coord).collect::>(); + assert_eq!( + iter_coords.len(), + coords.len(), + "Iterator should yield all coordinates" + ); + + for coord in coords { + assert!( + iter_coords.contains(&coord), + "Iterator should contain all added coordinates" + ); + } } } diff --git a/src/tile.rs b/src/tile.rs index 0dfaf28..7b35c34 100644 --- a/src/tile.rs +++ b/src/tile.rs @@ -26,3 +26,161 @@ impl HexTile { &self.walls } } + +#[cfg(test)] +mod tests { + use hexx::EdgeDirection; + + use super::*; + + #[test] + fn new_tile() { + let pos = Hex::ZERO; + let tile = HexTile::new(pos); + + assert_eq!(tile.pos, pos, "Position should match constructor argument"); + assert_eq!( + tile.walls, + Walls::default(), + "Walls should be initialized to default" + ); + } + + #[test] + fn tile_walls_accessor() { + let pos = Hex::new(1, -1); + let tile = HexTile::new(pos); + + // Test walls accessor method + let walls_ref = tile.walls(); + assert_eq!( + walls_ref, &tile.walls, + "Walls accessor should return reference to walls" + ); + } + + #[test] + fn tile_modification() { + let pos = Hex::new(2, 3); + let mut tile = HexTile::new(pos); + + // Modify walls + tile.walls.remove(EdgeDirection::FLAT_TOP); + assert!( + !tile.walls.has(EdgeDirection::FLAT_TOP), + "Wall should be removed" + ); + + tile.walls.add(EdgeDirection::FLAT_TOP); + assert!( + tile.walls.has(EdgeDirection::FLAT_TOP), + "Wall should be added back" + ); + } + + #[test] + fn tile_copy() { + let pos = Hex::new(-1, 2); + let tile = HexTile::new(pos); + + // Test Copy trait + let copied_tile = tile; + assert_eq!(tile, copied_tile, "Copied tile should equal original"); + + // Verify both tiles are still usable + assert_eq!( + tile.pos, copied_tile.pos, + "Positions should match after copy" + ); + assert_eq!( + tile.walls, copied_tile.walls, + "Walls should match after copy" + ); + } + + #[test] + fn tile_clone() { + let pos = Hex::new(0, -2); + let tile = HexTile::new(pos); + + // Test Clone trait + let cloned_tile = tile.clone(); + assert_eq!(tile, cloned_tile, "Cloned tile should equal original"); + } + + #[test] + fn tile_debug() { + let pos = Hex::ZERO; + let tile = HexTile::new(pos); + + // Test Debug trait + let debug_string = format!("{:?}", tile); + assert!( + debug_string.contains("HexTile"), + "Debug output should contain struct name" + ); + } + + #[test] + fn different_positions() { + let positions = [Hex::ZERO, Hex::new(1, 0), Hex::new(-1, 1), Hex::new(2, -2)]; + + // Create tiles at different positions + let tiles = positions + .iter() + .map(|&pos| HexTile::new(pos)) + .collect::>(); + + // Verify each tile has correct position + for (tile, &pos) in tiles.iter().zip(positions.iter()) { + assert_eq!( + tile.pos, pos, + "Tile position should match constructor argument" + ); + } + } + + #[test] + fn tile_equality() { + let pos1 = Hex::new(1, 1); + let pos2 = Hex::new(1, 1); + let pos3 = Hex::new(2, 1); + + let tile1 = HexTile::new(pos1); + let tile2 = HexTile::new(pos2); + let tile3 = HexTile::new(pos3); + + assert_eq!(tile1, tile2, "Tiles with same position should be equal"); + assert_ne!( + tile1, tile3, + "Tiles with different positions should not be equal" + ); + + // Test with modified walls + let mut tile4 = HexTile::new(pos1); + tile4.walls.remove(EdgeDirection::FLAT_TOP); + assert_ne!( + tile1, tile4, + "Tiles with different walls should not be equal" + ); + } + + #[test] + fn hex_boundaries() { + // Test with extreme coordinate values + let extreme_positions = [ + Hex::new(i32::MAX, i32::MIN), + Hex::new(i32::MIN, i32::MAX), + Hex::new(0, i32::MAX), + Hex::new(i32::MIN, 0), + ]; + + for pos in extreme_positions { + let tile = HexTile::new(pos); + assert_eq!( + tile.pos, pos, + "Tile should handle extreme coordinate values" + ); + } + } +} diff --git a/src/walls.rs b/src/walls.rs index 887b19b..9e81004 100644 --- a/src/walls.rs +++ b/src/walls.rs @@ -69,15 +69,120 @@ impl Default for Walls { #[cfg(test)] mod tests { use super::*; - #[test] - fn walls() { - let mut walls = Walls::new(); - assert!(walls.has(EdgeDirection::FLAT_TOP)); + #[test] + fn new_walls() { + let walls = Walls::new(); + // All walls should be present by default + for direction in EdgeDirection::iter() { + assert!( + walls.has(direction), + "Wall should exist in direction {:?}", + direction + ); + } + } + + #[test] + fn add_remove_single_wall() { + let mut walls = Walls::new(); + + // Remove and verify each wall walls.remove(EdgeDirection::FLAT_TOP); assert!(!walls.has(EdgeDirection::FLAT_TOP)); + // Add back and verify walls.add(EdgeDirection::FLAT_TOP); assert!(walls.has(EdgeDirection::FLAT_TOP)); } + + #[test] + fn multiple_operations() { + let mut walls = Walls::new(); + + // Remove multiple walls + walls.remove(EdgeDirection::FLAT_TOP); + walls.remove(EdgeDirection::FLAT_BOTTOM); + + // Verify removed walls + assert!(!walls.has(EdgeDirection::FLAT_TOP)); + assert!(!walls.has(EdgeDirection::FLAT_BOTTOM)); + + // Verify other walls still exist + assert!(walls.has(EdgeDirection::FLAT_TOP_RIGHT)); + assert!(walls.has(EdgeDirection::FLAT_TOP_LEFT)); + + // Add back one wall + walls.add(EdgeDirection::FLAT_TOP); + assert!(walls.has(EdgeDirection::FLAT_TOP)); + assert!(!walls.has(EdgeDirection::FLAT_BOTTOM)); + } + + #[test] + fn bit_patterns() { + let mut walls = Walls::new(); + assert_eq!( + walls.as_bits(), + 0b111111, + "Initial state should have all walls" + ); + + walls.remove(EdgeDirection::FLAT_BOTTOM_RIGHT); + assert_eq!(walls.as_bits() & 0b000001, 0, "First bit should be cleared"); + + walls.add(EdgeDirection::FLAT_BOTTOM_RIGHT); + assert_eq!(walls.as_bits() & 0b000001, 1, "First bit should be set"); + } + + #[test] + fn remove_all_walls() { + let mut walls = Walls::new(); + + // Remove all walls + for direction in EdgeDirection::iter() { + walls.remove(direction); + } + + // Verify all walls are removed + assert_eq!(walls.as_bits(), 0, "All walls should be removed"); + + // Verify each direction + for direction in EdgeDirection::iter() { + assert!( + !walls.has(direction), + "No wall should exist in direction {:?}", + direction + ); + } + } + + #[test] + fn deref_operations() { + let mut walls = Walls::new(); + + // Test Deref + let bits: &u8 = walls.deref(); + assert_eq!(*bits, 0b111111); + + // Test DerefMut + *walls.deref_mut() = 0; + assert_eq!(walls.as_bits(), 0); + } + + #[test] + fn idempotent_operations() { + let mut walls = Walls::new(); + + // Adding twice shouldn't change the result + walls.add(EdgeDirection::FLAT_TOP); + let first_add = walls.as_bits(); + walls.add(EdgeDirection::FLAT_TOP); + assert_eq!(walls.as_bits(), first_add); + + // Removing twice shouldn't change the result + walls.remove(EdgeDirection::FLAT_TOP); + let first_remove = walls.as_bits(); + walls.remove(EdgeDirection::FLAT_TOP); + assert_eq!(walls.as_bits(), first_remove); + } }