test(walls): 93% coverage

This commit is contained in:
Kristofers Solo 2024-12-25 22:57:13 +02:00
parent 43a669dee8
commit 9740ce1a5a
6 changed files with 325 additions and 159 deletions

71
Cargo.lock generated
View File

@ -1347,18 +1347,18 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]] [[package]]
name = "bytemuck" name = "bytemuck"
version = "1.20.0" version = "1.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
dependencies = [ dependencies = [
"bytemuck_derive", "bytemuck_derive",
] ]
[[package]] [[package]]
name = "bytemuck_derive" name = "bytemuck_derive"
version = "1.8.0" version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1399,9 +1399,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.3" version = "1.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"libc", "libc",
@ -1525,9 +1525,9 @@ dependencies = [
[[package]] [[package]]
name = "const_panic" name = "const_panic"
version = "0.2.10" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "013b6c2c3a14d678f38cd23994b02da3a1a1b6a5d1eedddfe63a5a5f11b13a81" checksum = "53857514f72ee4a2b583de67401e3ff63a5472ca4acf289d09a9ea7636dfec17"
[[package]] [[package]]
name = "const_soft_float" name = "const_soft_float"
@ -1677,18 +1677,18 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-channel" name = "crossbeam-channel"
version = "0.5.13" version = "0.5.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
dependencies = [ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]] [[package]]
name = "crossbeam-deque" name = "crossbeam-deque"
version = "0.8.5" version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [ dependencies = [
"crossbeam-epoch", "crossbeam-epoch",
"crossbeam-utils", "crossbeam-utils",
@ -1705,9 +1705,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.20" version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]] [[package]]
name = "crunchy" name = "crunchy"
@ -1951,9 +1951,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "foldhash" name = "foldhash"
version = "0.1.3" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
[[package]] [[package]]
name = "font-types" name = "font-types"
@ -2297,13 +2297,13 @@ dependencies = [
[[package]] [[package]]
name = "gpu-descriptor" name = "gpu-descriptor"
version = "0.3.0" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c08c1f623a8d0b722b8b99f821eb0ba672a1618f0d3b16ddbee1cedd2dd8557" checksum = "dcf29e94d6d243368b7a56caa16bc213e4f9f8ed38c4d9557069527b5d5281ca"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"gpu-descriptor-types", "gpu-descriptor-types",
"hashbrown 0.14.5", "hashbrown 0.15.1",
] ]
[[package]] [[package]]
@ -2375,10 +2375,13 @@ checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]] [[package]]
name = "hexlab" name = "hexlab"
version = "0.3.1" version = "0.4.0"
dependencies = [ dependencies = [
"bevy", "bevy",
"bevy_reflect",
"bevy_utils",
"claims", "claims",
"glam",
"hexx", "hexx",
"rand", "rand",
"rstest", "rstest",
@ -2698,9 +2701,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.8.0" version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
dependencies = [ dependencies = [
"adler2", "adler2",
"simd-adler32", "simd-adler32",
@ -2708,9 +2711,9 @@ dependencies = [
[[package]] [[package]]
name = "naga" name = "naga"
version = "23.0.0" version = "23.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d5941e45a15b53aad4375eedf02033adb7a28931eedc31117faffa52e6a857e" checksum = "364f94bc34f61332abebe8cad6f6cd82a5b65cff22c828d05d0968911462ca4f"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"bit-set 0.8.0", "bit-set 0.8.0",
@ -3269,9 +3272,9 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]] [[package]]
name = "png" name = "png"
version = "0.17.15" version = "0.17.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67582bd5b65bdff614270e2ea89a1cf15bef71245cc1e5f7ea126977144211d" checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"crc32fast", "crc32fast",
@ -3710,9 +3713,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.133" version = "1.0.134"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
@ -3938,9 +3941,9 @@ dependencies = [
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.8.0" version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8"
dependencies = [ dependencies = [
"tinyvec_macros", "tinyvec_macros",
] ]
@ -4085,9 +4088,9 @@ checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e"
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.17" version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
[[package]] [[package]]
name = "unicode-bidi-mirroring" name = "unicode-bidi-mirroring"
@ -4755,9 +4758,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]] [[package]]
name = "winit" name = "winit"
version = "0.30.5" version = "0.30.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0be9e76a1f1077e04a411f0b989cbd3c93339e1771cb41e71ac4aee95bfd2c67" checksum = "dba50bc8ef4b6f1a75c9274fb95aa9a8f63fbc66c56f391bd85cf68d51e7b1a3"
dependencies = [ dependencies = [
"android-activity", "android-activity",
"atomic-waker", "atomic-waker",

View File

@ -1,7 +1,7 @@
[package] [package]
name = "hexlab" name = "hexlab"
authors = ["Kristofers Solo <dev@kristofers.xyz>"] authors = ["Kristofers Solo <dev@kristofers.xyz>"]
version = "0.3.1" version = "0.4.0"
edition = "2021" edition = "2021"
description = "A hexagonal maze generation and manipulation library" description = "A hexagonal maze generation and manipulation library"
repository = "https://github.com/kristoferssolo/hexlab" repository = "https://github.com/kristoferssolo/hexlab"
@ -19,11 +19,20 @@ exclude = ["/.github", "/.gitignore", "/tests", "*.png", "*.md"]
readme = "README.md" readme = "README.md"
[dependencies] [dependencies]
bevy = { version = "0.15", optional = true }
hexx = { version = "0.19" } hexx = { version = "0.19" }
rand = "0.8" rand = "0.8"
serde = { version = "1.0", features = ["derive"], optional = true } serde = { version = "1.0", features = ["derive"], optional = true }
thiserror = "2.0" thiserror = "2.0"
bevy = { version = "0.15", optional = true }
bevy_utils = { version = "0.15", optional = true }
glam = { version = "0.29", optional = true }
[dependencies.bevy_reflect]
version = "0.15"
optional = true
default-features = false
features = ["glam"]
[dev-dependencies] [dev-dependencies]
claims = "0.8" claims = "0.8"
@ -32,8 +41,13 @@ rstest = "0.23"
[features] [features]
default = [] default = []
serde = ["dep:serde", "hexx/serde"] serde = ["dep:serde", "hexx/serde"]
bevy = ["bevy_reflect"] bevy = ["dep:bevy", "bevy_reflect"]
bevy_reflect = ["dep:bevy", "hexx/bevy_reflect"] bevy_reflect = [
"dep:bevy_reflect",
"dep:bevy_utils",
"hexx/bevy_reflect",
"dep:glam",
]
full = ["serde", "bevy"] full = ["serde", "bevy"]
[profile.dev] [profile.dev]

View File

@ -1,15 +1,13 @@
mod backtrack; mod backtrack;
use crate::HexMaze; use crate::HexMaze;
use backtrack::generate_backtracking; use backtrack::generate_backtracking;
#[cfg(feature = "bevy_reflect")]
use bevy::prelude::*;
use hexx::Hex; use hexx::Hex;
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "bevy", derive(Component))] #[cfg_attr(feature = "bevy", derive(bevy::Component))]
#[cfg_attr(feature = "bevy", reflect(Component))] #[cfg_attr(feature = "bevy", reflect(bevy::Component))]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum GeneratorType { pub enum GeneratorType {
#[default] #[default]

View File

@ -1,8 +1,6 @@
use super::{HexTile, Walls}; use super::{HexTile, Walls};
#[cfg(feature = "bevy_reflect")] #[cfg(feature = "bevy_reflect")]
use bevy::prelude::*; use bevy_utils::HashMap;
#[cfg(feature = "bevy_reflect")]
use bevy::utils::HashMap;
use hexx::{EdgeDirection, Hex}; use hexx::{EdgeDirection, Hex};
#[cfg(not(feature = "bevy_reflect"))] #[cfg(not(feature = "bevy_reflect"))]
use std::collections::HashMap; use std::collections::HashMap;
@ -14,9 +12,9 @@ use std::ops::{Deref, DerefMut};
/// of tiles and their associated walls. /// of tiles and their associated walls.
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "bevy", derive(Component))] #[cfg_attr(feature = "bevy", derive(bevy::Component))]
#[cfg_attr(feature = "bevy", reflect(Component))] #[cfg_attr(feature = "bevy", reflect(bevy::Component))]
#[derive(Debug, Clone, Default, PartialEq, Eq)] #[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct HexMaze(HashMap<Hex, HexTile>); pub struct HexMaze(HashMap<Hex, HexTile>);
@ -56,7 +54,6 @@ impl HexMaze {
/// ///
/// assert_eq!(maze.len(), 1); /// assert_eq!(maze.len(), 1);
/// assert!(!maze.is_empty()); /// assert!(!maze.is_empty());
/// assert!(!maze.get_tile(&coord).is_some());
/// ``` /// ```
pub fn add_tile(&mut self, coords: Hex) { pub fn add_tile(&mut self, coords: Hex) {
let tile = HexTile::new(coords); let tile = HexTile::new(coords);
@ -80,8 +77,9 @@ impl HexMaze {
/// maze.add_tile(coord); /// maze.add_tile(coord);
/// ///
/// maze.add_wall(coord, EdgeDirection::FLAT_NORTH); /// maze.add_wall(coord, EdgeDirection::FLAT_NORTH);
/// let walls = maze.get_walls(&coord).unwrap(); /// let walls = maze.get_walls(&coord);
/// assert!(walls.contains(EdgeDirection::FLAT_NORTH)); /// assert!(walls.is_some());
/// assert!(walls.unwrap().contains(EdgeDirection::FLAT_NORTH));
/// ``` /// ```
pub fn add_wall(&mut self, coord: Hex, direction: EdgeDirection) { pub fn add_wall(&mut self, coord: Hex, direction: EdgeDirection) {
if let Some(tile) = self.0.get_mut(&coord) { if let Some(tile) = self.0.get_mut(&coord) {
@ -104,7 +102,8 @@ impl HexMaze {
/// let coord = Hex::ZERO; /// let coord = Hex::ZERO;
/// maze.add_tile(coord); /// maze.add_tile(coord);
/// ///
/// assert!(!maze.get_tile(&coord).is_some()); /// assert!(maze.get_tile(&coord).is_some());
/// assert!(maze.get_tile(&Hex::new(1, 1)).is_none());
/// ``` /// ```
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
#[must_use] #[must_use]

View File

@ -1,6 +1,4 @@
use super::Walls; use super::Walls;
#[cfg(feature = "bevy_reflect")]
use bevy::prelude::*;
use hexx::Hex; use hexx::Hex;
#[cfg(feature = "bevy_reflect")] #[cfg(feature = "bevy_reflect")]
use hexx::HexLayout; use hexx::HexLayout;
@ -11,7 +9,7 @@ use std::fmt::Display;
/// Each tile has a position and a set of walls defining its boundaries. /// Each tile has a position and a set of walls defining its boundaries.
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "bevy", derive(Component))] #[cfg_attr(feature = "bevy", derive(Component))]
#[cfg_attr(feature = "bevy", reflect(Component))] #[cfg_attr(feature = "bevy", reflect(Component))]
#[derive(Debug, Clone, Default, PartialEq, Eq)] #[derive(Debug, Clone, Default, PartialEq, Eq)]
@ -26,6 +24,16 @@ impl HexTile {
/// # Arguments /// # Arguments
/// ///
/// - `pos` - The hexagonal coordinates of the tile. /// - `pos` - The hexagonal coordinates of the tile.
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// let tile = HexTile::new(Hex::new(1, -1));
/// assert_eq!(tile.pos(), Hex::new(1, -1));
/// assert_eq!(*tile.walls(), Walls::default());
/// ```
#[must_use] #[must_use]
pub fn new(pos: Hex) -> Self { pub fn new(pos: Hex) -> Self {
Self { Self {
@ -35,6 +43,15 @@ impl HexTile {
} }
/// Returns a reference to the tile's walls /// Returns a reference to the tile's walls
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// let tile = HexTile::new(Hex::ZERO);
/// assert_eq!(*tile.walls(), Walls::default());
/// ```
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
#[must_use] #[must_use]
pub const fn walls(&self) -> &Walls { pub const fn walls(&self) -> &Walls {
@ -42,11 +59,21 @@ impl HexTile {
} }
/// Returns position of the tile /// Returns position of the tile
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// let tile = HexTile::new(Hex::new(2, -2));
/// assert_eq!(tile.pos(), Hex::new(2, -2));
/// ```
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
#[must_use] #[must_use]
pub const fn pos(&self) -> Hex { pub const fn pos(&self) -> Hex {
self.pos self.pos
} }
/// Converts the tile's position to a 2D vector based on the given layout. /// Converts the tile's position to a 2D vector based on the given layout.
/// ///
/// # Arguments /// # Arguments
@ -55,7 +82,7 @@ impl HexTile {
#[cfg(feature = "bevy_reflect")] #[cfg(feature = "bevy_reflect")]
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
#[must_use] #[must_use]
pub fn to_vec2(&self, layout: &HexLayout) -> Vec2 { pub fn to_vec2(&self, layout: &HexLayout) -> glam::Vec2 {
layout.hex_to_world_pos(self.pos) layout.hex_to_world_pos(self.pos)
} }
@ -67,7 +94,9 @@ impl HexTile {
#[cfg(feature = "bevy_reflect")] #[cfg(feature = "bevy_reflect")]
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
#[must_use] #[must_use]
pub fn to_vec3(&self, layout: &HexLayout) -> Vec3 { pub fn to_vec3(&self, layout: &HexLayout) -> glam::Vec3 {
use glam::Vec3;
let pos = self.to_vec2(layout); let pos = self.to_vec2(layout);
Vec3::new(pos.x, 0., pos.y) Vec3::new(pos.x, 0., pos.y)
} }
@ -90,76 +119,26 @@ impl Display for HexTile {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use hexx::EdgeDirection;
use super::*; use super::*;
use hexx::EdgeDirection;
use rand::{thread_rng, Rng};
#[test] fn random_hex() -> Hex {
fn new_tile() { let mut rng = thread_rng();
let pos = Hex::ZERO; Hex::new(rng.gen(), rng.gen())
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] #[test]
fn tile_modification() { fn tile_modification() {
let pos = Hex::new(2, 3); let hex = random_hex();
let mut tile = HexTile::new(pos); let mut tile = HexTile::new(hex);
// Modify walls // Modify walls
tile.walls.remove(EdgeDirection::FLAT_TOP); tile.walls.remove(EdgeDirection::FLAT_TOP);
assert!( assert!(!tile.walls.contains(EdgeDirection::FLAT_TOP));
!tile.walls.contains(EdgeDirection::FLAT_TOP),
"Wall should be removed"
);
tile.walls.add(EdgeDirection::FLAT_TOP); tile.walls.add(EdgeDirection::FLAT_TOP);
assert!( assert!(tile.walls.contains(EdgeDirection::FLAT_TOP));
tile.walls.contains(EdgeDirection::FLAT_TOP),
"Wall should be added back"
);
}
#[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] #[test]
@ -174,38 +153,10 @@ mod test {
// Verify each tile has correct position // Verify each tile has correct position
for (tile, &pos) in tiles.iter().zip(positions.iter()) { for (tile, &pos) in tiles.iter().zip(positions.iter()) {
assert_eq!( assert_eq!(tile.pos, pos);
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] #[test]
fn hex_boundaries() { fn hex_boundaries() {
// Test with extreme coordinate values // Test with extreme coordinate values
@ -218,10 +169,77 @@ mod test {
for pos in extreme_positions { for pos in extreme_positions {
let tile = HexTile::new(pos); let tile = HexTile::new(pos);
assert_eq!( assert_eq!(tile.pos, pos);
tile.pos, pos, }
"Tile should handle extreme coordinate values" }
);
#[test]
fn hex_tile_creation_and_properties() {
let hex = random_hex();
let tile = HexTile::new(hex);
assert_eq!(tile.pos(), hex);
assert!(tile.walls().is_enclosed());
}
#[test]
fn hex_tile_from_hex() {
let hex = random_hex();
let tile = HexTile::from(hex);
assert_eq!(tile.pos, hex);
assert_eq!(tile.walls, Walls::default());
}
#[test]
fn hex_hex_into_tile() {
let hex = random_hex();
let tile: HexTile = hex.into();
assert_eq!(tile.pos, hex);
assert_eq!(tile.walls, Walls::default());
}
#[test]
fn hex_tile_display() {
let tile = HexTile::new(Hex::new(3, -3));
assert_eq!(format!("{tile}"), "(3,-3)");
}
#[test]
fn hex_tile_wall_modifications() {
let mut tile = HexTile::new(Hex::ZERO);
for direction in EdgeDirection::ALL_DIRECTIONS {
tile.walls.add(direction);
}
assert_eq!(tile.walls.count(), 6);
for direction in EdgeDirection::ALL_DIRECTIONS {
tile.walls.remove(direction);
}
assert_eq!(tile.walls.count(), 0);
}
#[cfg(feature = "bevy_reflect")]
mod bevy_tests {
use super::*;
use glam::{Vec2, Vec3};
#[test]
fn hex_tile_to_vec2() {
let layout = HexLayout::default();
let tile = HexTile::new(Hex::new(1, 0));
let vec2 = tile.to_vec2(&layout);
assert_eq!(vec2, Vec2::new(1.5, -0.8660254));
}
#[test]
fn hex_tile_to_vec3() {
let layout = HexLayout::default();
let tile = HexTile::new(Hex::new(0, 1));
let vec3 = tile.to_vec3(&layout);
assert_eq!(vec3, Vec3::new(0.0, 0.0, -1.7320508));
} }
} }
} }

View File

@ -1,5 +1,3 @@
#[cfg(feature = "bevy_reflect")]
use bevy::prelude::*;
use hexx::EdgeDirection; use hexx::EdgeDirection;
/// A bit-flag representation of walls in a hexagonal tile. /// A bit-flag representation of walls in a hexagonal tile.
@ -28,7 +26,7 @@ use hexx::EdgeDirection;
/// assert_eq!(walls.count(), 2); /// assert_eq!(walls.count(), 2);
/// ``` /// ```
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "bevy", derive(Component))] #[cfg_attr(feature = "bevy", derive(Component))]
#[cfg_attr(feature = "bevy", reflect(Component))] #[cfg_attr(feature = "bevy", reflect(Component))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -38,6 +36,15 @@ impl Walls {
/// Creates a new set of walls with all edges closed. /// Creates a new set of walls with all edges closed.
/// ///
/// This is the default state where all six edges of the hexagon have walls. /// This is the default state where all six edges of the hexagon have walls.
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// let walls = Walls::new();
/// assert!(walls.is_enclosed());
/// ```
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
@ -45,6 +52,15 @@ impl Walls {
} }
/// Creates a new set of walls with no edges (completely open). /// Creates a new set of walls with no edges (completely open).
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// let walls = Walls::empty();
/// assert!(walls.is_empty());
/// ```
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
#[must_use] #[must_use]
pub const fn empty() -> Self { pub const fn empty() -> Self {
@ -52,6 +68,15 @@ impl Walls {
} }
/// Checks if the walls are currently empty (no walls present). /// Checks if the walls are currently empty (no walls present).
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// let walls = Walls::empty();
/// assert!(walls.is_empty());
/// ```
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
#[must_use] #[must_use]
pub const fn is_empty(&self) -> bool { pub const fn is_empty(&self) -> bool {
@ -62,7 +87,26 @@ impl Walls {
/// ///
/// # Arguments /// # Arguments
/// ///
/// 0 `direction` - The direction in which to add the wall. /// - `direction` - The direction in which to add the wall.
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// let mut walls = Walls::empty();
/// assert_eq!(walls.count(), 0);
///
/// walls.add(1);
/// assert_eq!(walls.count(), 1);
///
/// walls.add(1);
/// assert_eq!(walls.count(), 1);
///
/// walls.add(EdgeDirection::FLAT_NORTH);
/// assert_eq!(walls.count(), 2);
///
/// ```
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
pub fn add<T>(&mut self, direction: T) pub fn add<T>(&mut self, direction: T)
where where
@ -76,6 +120,23 @@ impl Walls {
/// # Arguments /// # Arguments
/// ///
/// - `direction` - The direction from which to remove the wall. /// - `direction` - The direction from which to remove the wall.
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// let mut walls = Walls::new();
///
/// assert!(walls.remove(1));
/// assert_eq!(walls.count(), 5);
///
/// assert!(!walls.remove(1));
/// assert_eq!(walls.count(), 5);
///
/// assert!(walls.remove(EdgeDirection::FLAT_NORTH));
/// assert_eq!(walls.count(), 4);
/// ```
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
pub fn remove<T>(&mut self, direction: T) -> bool pub fn remove<T>(&mut self, direction: T) -> bool
where where
@ -93,6 +154,18 @@ impl Walls {
/// # Arguments /// # Arguments
/// ///
/// - `other` - The direction to check for a wall. /// - `other` - The direction to check for a wall.
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// let mut walls = Walls::empty();
/// walls.add(EdgeDirection::FLAT_NORTH);
///
/// assert!(walls.contains(EdgeDirection::FLAT_NORTH));
/// assert!(!walls.contains(EdgeDirection::FLAT_SOUTH));
/// ```
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
pub fn contains<T>(&self, other: T) -> bool pub fn contains<T>(&self, other: T) -> bool
where where
@ -102,6 +175,18 @@ impl Walls {
} }
/// Returns the raw bit representation of the walls /// Returns the raw bit representation of the walls
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// let walls = Walls::new();
/// assert_eq!(walls.as_bits(), 0b11_1111);
///
/// let walls = Walls::empty();
/// assert_eq!(walls.as_bits(), 0);
/// ```
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
#[must_use] #[must_use]
pub const fn as_bits(&self) -> u8 { pub const fn as_bits(&self) -> u8 {
@ -109,6 +194,21 @@ impl Walls {
} }
/// Returns the total number of walls present /// Returns the total number of walls present
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// let mut walls = Walls::empty();
/// assert!(walls.is_empty());
///
/// walls.add(0);
/// assert_eq!(walls.count(), 1);
///
/// walls.add(1);
/// assert_eq!(walls.count(), 2);
/// ```
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
#[must_use] #[must_use]
pub fn count(&self) -> u8 { pub fn count(&self) -> u8 {
@ -116,6 +216,14 @@ impl Walls {
} }
/// Returns a `Walls` value representing all possible directions. /// Returns a `Walls` value representing all possible directions.
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// assert_eq!(Walls::all_directions().as_bits(), 0b11_1111);
/// ```
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
#[must_use] #[must_use]
pub const fn all_directions() -> Self { pub const fn all_directions() -> Self {
@ -134,6 +242,20 @@ impl Walls {
/// # Returns /// # Returns
/// ///
/// The previous state (`true` if a wall was present before toggling, `false` otherwise). /// The previous state (`true` if a wall was present before toggling, `false` otherwise).
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// let mut walls = Walls::empty();
///
/// assert!(!walls.toggle(0));
/// assert_eq!(walls.count(), 1);
///
/// assert!(walls.toggle(0));
/// assert_eq!(walls.count(), 0);
/// ```
pub fn toggle<T>(&mut self, direction: T) -> bool pub fn toggle<T>(&mut self, direction: T) -> bool
where where
T: Into<Self> + Copy, T: Into<Self> + Copy,
@ -155,10 +277,10 @@ impl Walls {
/// ///
/// # Deprecated /// # Deprecated
/// ///
/// This method is deprecated since version 0.3.1. Use `is_enclosed()` instead. /// This method is deprecated since version 0.4.0. Use `is_enclosed()` instead.
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
#[must_use] #[must_use]
#[deprecated(since = "0.3.1", note = "use `walls::Walls::is_enclosed()`")] #[deprecated(since = "0.4.0", note = "use `walls::Walls::is_enclosed()`")]
pub fn is_closed(&self) -> bool { pub fn is_closed(&self) -> bool {
self.is_enclosed() self.is_enclosed()
} }
@ -168,6 +290,18 @@ impl Walls {
/// # Returns /// # Returns
/// ///
/// `true` if the hexagon has all possible walls, making it completely enclosed. /// `true` if the hexagon has all possible walls, making it completely enclosed.
///
/// # Examples
///
/// ```
/// use hexlab::prelude::*;
///
/// let mut walls = Walls::new();
/// assert!(walls.is_enclosed());
///
/// walls.remove(0);
/// assert!(!walls.is_enclosed());
/// ```
#[cfg_attr(not(debug_assertions), inline)] #[cfg_attr(not(debug_assertions), inline)]
#[must_use] #[must_use]
pub fn is_enclosed(&self) -> bool { pub fn is_enclosed(&self) -> bool {
@ -247,7 +381,7 @@ mod test {
#[test] #[test]
fn all_directions_creates_closed_walls() { fn all_directions_creates_closed_walls() {
let walls = Walls::all_directions(); let walls = Walls::all_directions();
assert!(walls.is_closed()); assert!(walls.is_enclosed());
assert!(!walls.is_empty()); assert!(!walls.is_empty());
assert_eq!(walls.as_bits(), 0b111111); assert_eq!(walls.as_bits(), 0b111111);
} }
@ -284,7 +418,7 @@ mod test {
#[test] #[test]
fn new_created_closed_walls() { fn new_created_closed_walls() {
let walls = Walls::new(); let walls = Walls::new();
assert!(walls.is_closed()); assert!(walls.is_enclosed());
assert_eq!(walls.as_bits(), 0b111111); assert_eq!(walls.as_bits(), 0b111111);
} }
@ -393,7 +527,7 @@ mod test {
#[test] #[test]
fn default_creates_closed_walls() { fn default_creates_closed_walls() {
let walls = Walls::default(); let walls = Walls::default();
assert!(walls.is_closed()); assert!(walls.is_enclosed());
assert_eq!(walls.as_bits(), 0b111111); assert_eq!(walls.as_bits(), 0b111111);
} }