#[cfg(test)]
mod tests {
use crate::binary_format::{DT_NAVMESH_MAGIC, DT_NAVMESH_VERSION};
use crate::{NavMeshParams, PolyFlags, PolyRef};
use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::Cursor;
#[test]
fn test_little_endian_serialization() -> Result<(), Box<dyn std::error::Error>> {
let mut buffer = Vec::new();
buffer.write_u32::<LittleEndian>(DT_NAVMESH_MAGIC)?;
buffer.write_u32::<LittleEndian>(DT_NAVMESH_VERSION)?;
buffer.write_f32::<LittleEndian>(123.456)?;
buffer.write_i32::<LittleEndian>(-42)?;
let mut cursor = Cursor::new(&buffer);
assert_eq!(cursor.read_u32::<LittleEndian>()?, DT_NAVMESH_MAGIC);
assert_eq!(cursor.read_u32::<LittleEndian>()?, DT_NAVMESH_VERSION);
assert!((cursor.read_f32::<LittleEndian>()? - 123.456).abs() < f32::EPSILON);
assert_eq!(cursor.read_i32::<LittleEndian>()?, -42);
Ok(())
}
#[test]
fn test_big_endian_serialization() -> Result<(), Box<dyn std::error::Error>> {
let mut buffer = Vec::new();
buffer.write_u32::<BigEndian>(DT_NAVMESH_MAGIC)?;
buffer.write_u32::<BigEndian>(DT_NAVMESH_VERSION)?;
buffer.write_f32::<BigEndian>(123.456)?;
buffer.write_i32::<BigEndian>(-42)?;
let mut cursor = Cursor::new(&buffer);
assert_eq!(cursor.read_u32::<BigEndian>()?, DT_NAVMESH_MAGIC);
assert_eq!(cursor.read_u32::<BigEndian>()?, DT_NAVMESH_VERSION);
assert!((cursor.read_f32::<BigEndian>()? - 123.456).abs() < f32::EPSILON);
assert_eq!(cursor.read_i32::<BigEndian>()?, -42);
Ok(())
}
#[test]
fn test_cross_endian_compatibility() -> Result<(), Box<dyn std::error::Error>> {
let mut le_buffer = Vec::new();
le_buffer.write_u32::<LittleEndian>(0x12345678)?;
le_buffer.write_u16::<LittleEndian>(0xABCD)?;
let mut be_buffer = Vec::new();
be_buffer.write_u32::<BigEndian>(0x12345678)?;
be_buffer.write_u16::<BigEndian>(0xABCD)?;
assert_ne!(le_buffer, be_buffer);
let mut le_cursor = Cursor::new(&le_buffer);
let le_u32 = le_cursor.read_u32::<LittleEndian>()?;
let le_u16 = le_cursor.read_u16::<LittleEndian>()?;
let mut be_cursor = Cursor::new(&be_buffer);
let be_u32 = be_cursor.read_u32::<BigEndian>()?;
let be_u16 = be_cursor.read_u16::<BigEndian>()?;
assert_eq!(le_u32, be_u32);
assert_eq!(le_u16, be_u16);
Ok(())
}
#[test]
fn test_polyref_serialization() -> Result<(), Box<dyn std::error::Error>> {
let poly_refs = vec![
PolyRef::new(0),
PolyRef::new(1),
PolyRef::new(0xFFFFFFFF),
PolyRef::new(0x12345678),
];
for poly_ref in poly_refs {
let mut le_buffer = Vec::new();
le_buffer.write_u32::<LittleEndian>(poly_ref.id())?;
let mut le_cursor = Cursor::new(&le_buffer);
let le_read = PolyRef::new(le_cursor.read_u32::<LittleEndian>()?);
assert_eq!(poly_ref, le_read);
let mut be_buffer = Vec::new();
be_buffer.write_u32::<BigEndian>(poly_ref.id())?;
let mut be_cursor = Cursor::new(&be_buffer);
let be_read = PolyRef::new(be_cursor.read_u32::<BigEndian>()?);
assert_eq!(poly_ref, be_read);
}
Ok(())
}
#[test]
fn test_float_array_serialization() -> Result<(), Box<dyn std::error::Error>> {
let positions: Vec<[f32; 3]> = vec![
[1.0, 2.0, 3.0],
[-1.0, -2.0, -3.0],
[1e10, 1e-10, 0.0],
[f32::MIN_POSITIVE, f32::MAX, -f32::MIN_POSITIVE],
];
let mut buffer = Vec::new();
for pos in &positions {
for &val in pos {
buffer.write_f32::<LittleEndian>(val)?;
}
}
let mut cursor = Cursor::new(&buffer);
for original_pos in &positions {
let mut read_pos = [0.0_f32; 3];
for val in &mut read_pos {
*val = cursor.read_f32::<LittleEndian>()?;
}
for i in 0..3 {
let diff = (original_pos[i] - read_pos[i]).abs();
let max_val = original_pos[i].abs().max(read_pos[i].abs());
let relative_error = if max_val > 0.0 { diff / max_val } else { diff };
assert!(
relative_error < 1e-6 || diff < 1e-6,
"Float mismatch at index {}: {} vs {}",
i,
original_pos[i],
read_pos[i]
);
}
}
Ok(())
}
#[test]
fn test_struct_padding() -> Result<(), Box<dyn std::error::Error>> {
#[repr(C)]
struct TestStruct {
a: u8,
b: u32,
c: u16,
d: u8,
}
let size = std::mem::size_of::<TestStruct>();
assert!(size >= 1 + 4 + 2 + 1); assert_eq!(size % 4, 0);
let test = TestStruct {
a: 0x12,
b: 0x34567890,
c: 0xABCD,
d: 0xEF,
};
let mut buffer = Vec::new();
buffer.write_u8(test.a)?;
while buffer.len() % 4 != 0 {
buffer.write_u8(0)?;
}
buffer.write_u32::<LittleEndian>(test.b)?;
buffer.write_u16::<LittleEndian>(test.c)?;
buffer.write_u8(test.d)?;
while buffer.len() % 4 != 0 {
buffer.write_u8(0)?;
}
assert_eq!(buffer.len() % 4, 0);
Ok(())
}
#[test]
fn test_navmesh_params_serialization() -> Result<(), Box<dyn std::error::Error>> {
let params = NavMeshParams {
origin: [100.0, 200.0, 300.0],
tile_width: 32.0,
tile_height: 32.0,
max_tiles: 128,
max_polys_per_tile: 256,
};
let mut buffer = Vec::new();
for &val in ¶ms.origin {
buffer.write_f32::<LittleEndian>(val)?;
}
buffer.write_f32::<LittleEndian>(params.tile_width)?;
buffer.write_f32::<LittleEndian>(params.tile_height)?;
buffer.write_i32::<LittleEndian>(params.max_tiles)?;
buffer.write_i32::<LittleEndian>(params.max_polys_per_tile)?;
let mut cursor = Cursor::new(&buffer);
let mut read_origin = [0.0_f32; 3];
for val in &mut read_origin {
*val = cursor.read_f32::<LittleEndian>()?;
}
let read_params = NavMeshParams {
origin: read_origin,
tile_width: cursor.read_f32::<LittleEndian>()?,
tile_height: cursor.read_f32::<LittleEndian>()?,
max_tiles: cursor.read_i32::<LittleEndian>()?,
max_polys_per_tile: cursor.read_i32::<LittleEndian>()?,
};
assert_eq!(params.origin, read_params.origin);
assert_eq!(params.tile_width, read_params.tile_width);
assert_eq!(params.tile_height, read_params.tile_height);
assert_eq!(params.max_tiles, read_params.max_tiles);
assert_eq!(params.max_polys_per_tile, read_params.max_polys_per_tile);
Ok(())
}
#[test]
fn test_bitflags_serialization() -> Result<(), Box<dyn std::error::Error>> {
let flags_values = vec![
PolyFlags::WALK,
PolyFlags::SWIM,
PolyFlags::DOOR,
PolyFlags::WALK | PolyFlags::SWIM,
PolyFlags::all(),
PolyFlags::empty(),
];
for flags in flags_values {
let mut buffer = Vec::new();
buffer.write_u16::<LittleEndian>(flags.bits())?;
let mut cursor = Cursor::new(&buffer);
let bits = cursor.read_u16::<LittleEndian>()?;
let read_flags = PolyFlags::from_bits(bits).unwrap();
assert_eq!(flags, read_flags);
}
Ok(())
}
#[test]
fn test_magic_number_endianness() {
let magic_bytes = DT_NAVMESH_MAGIC.to_le_bytes();
assert_eq!(magic_bytes, [b'D', b'N', b'A', b'V']);
let be_bytes = DT_NAVMESH_MAGIC.to_be_bytes();
assert_ne!(be_bytes, [b'D', b'N', b'A', b'V']);
}
}