#[cfg(test)]
mod tests {
use crate::nav_mesh_query::NavMeshQuery;
use crate::{NavMesh, NavMeshParams, PolyRef, QueryFilter};
use glam::Vec3;
#[test]
fn test_navmesh_invalid_params() {
let invalid_params1 = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: 0.0, tile_height: 10.0,
max_tiles: 1,
max_polys_per_tile: 1,
};
assert!(NavMesh::new(invalid_params1).is_err());
let invalid_params2 = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: -10.0, tile_height: 10.0,
max_tiles: 1,
max_polys_per_tile: 1,
};
assert!(NavMesh::new(invalid_params2).is_err());
let invalid_params3 = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: 10.0,
tile_height: 10.0,
max_tiles: 0, max_polys_per_tile: 1,
};
assert!(NavMesh::new(invalid_params3).is_err());
let invalid_params4 = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: 10.0,
tile_height: 10.0,
max_tiles: 1,
max_polys_per_tile: 0, };
assert!(NavMesh::new(invalid_params4).is_err());
}
#[test]
fn test_query_invalid_polygon_refs() -> Result<(), Box<dyn std::error::Error>> {
let params = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: 10.0,
tile_height: 10.0,
max_tiles: 1,
max_polys_per_tile: 1,
};
let nav_mesh = NavMesh::new(params)?;
let query = NavMeshQuery::new(&nav_mesh);
let filter = QueryFilter::default();
let invalid_ref = PolyRef::new(0);
let pos = Vec3::new(5.0, 0.0, 5.0);
let dir = Vec3::new(1.0, 0.0, 0.0);
assert!(query.raycast(invalid_ref, pos, dir, 10.0, &filter).is_err());
assert!(query.closest_point_on_poly(invalid_ref, pos).is_err());
let huge_ref = PolyRef::new(0xFFFFFFFF);
assert!(query.raycast(huge_ref, pos, dir, 10.0, &filter).is_err());
assert!(
query
.closest_point_on_poly(huge_ref, Vec3::from(pos))
.is_err()
);
Ok(())
}
#[test]
fn test_query_invalid_positions() -> Result<(), Box<dyn std::error::Error>> {
let params = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: 10.0,
tile_height: 10.0,
max_tiles: 1,
max_polys_per_tile: 1,
};
let nav_mesh = NavMesh::new(params)?;
let query = NavMeshQuery::new(&nav_mesh);
let filter = QueryFilter::default();
let nan_pos = [f32::NAN, 0.0, 0.0];
let valid_pos = [5.0, 0.0, 5.0];
let half_extents = [1.0, 1.0, 1.0];
let result =
query.find_nearest_poly(Vec3::from(nan_pos), Vec3::from(half_extents), &filter);
assert!(result.is_err() || result.unwrap().0 == PolyRef::new(0));
let inf_pos = [f32::INFINITY, 0.0, 0.0];
let result2 =
query.find_nearest_poly(Vec3::from(inf_pos), Vec3::from(half_extents), &filter);
assert!(result2.is_err() || result2.unwrap().0 == PolyRef::new(0));
let huge_pos = [1e30, 0.0, 1e30];
let result3 =
query.find_nearest_poly(Vec3::from(huge_pos), Vec3::from(half_extents), &filter);
assert!(result3.is_ok() || result3.is_err());
Ok(())
}
#[test]
fn test_query_invalid_extents() -> Result<(), Box<dyn std::error::Error>> {
let params = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: 10.0,
tile_height: 10.0,
max_tiles: 1,
max_polys_per_tile: 1,
};
let nav_mesh = NavMesh::new(params)?;
let query = NavMeshQuery::new(&nav_mesh);
let filter = QueryFilter::default();
let pos = [5.0, 0.0, 5.0];
let zero_extents = [0.0, 0.0, 0.0];
let result = query.find_nearest_poly(Vec3::from(pos), Vec3::from(zero_extents), &filter);
assert!(result.is_ok() || result.is_err());
let neg_extents = [-1.0, -1.0, -1.0];
let result2 = query.find_nearest_poly(Vec3::from(pos), Vec3::from(neg_extents), &filter);
assert!(result2.is_ok() || result2.is_err());
let nan_extents = [f32::NAN, 1.0, 1.0];
let result3 = query.find_nearest_poly(Vec3::from(pos), Vec3::from(nan_extents), &filter);
assert!(result3.is_err() || result3.unwrap().0 == PolyRef::new(0));
Ok(())
}
#[test]
fn test_raycast_invalid_directions() -> Result<(), Box<dyn std::error::Error>> {
let params = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: 10.0,
tile_height: 10.0,
max_tiles: 1,
max_polys_per_tile: 1,
};
let nav_mesh = NavMesh::new(params)?;
let query = NavMeshQuery::new(&nav_mesh);
let filter = QueryFilter::default();
let dummy_ref = PolyRef::new(1);
let pos = Vec3::new(5.0, 0.0, 5.0);
let zero_dir = Vec3::new(0.0, 0.0, 0.0);
let result = query.raycast(dummy_ref, pos, zero_dir, 10.0, &filter);
assert!(result.is_err() || result.unwrap().2 == 0.0);
let nan_dir = Vec3::new(f32::NAN, 0.0, 0.0);
let result2 = query.raycast(dummy_ref, pos, nan_dir, 10.0, &filter);
assert!(result2.is_err());
let inf_dir = Vec3::new(f32::INFINITY, 0.0, 0.0);
let result3 = query.raycast(dummy_ref, pos, inf_dir, 10.0, &filter);
assert!(result3.is_err());
Ok(())
}
#[test]
fn test_raycast_invalid_distances() -> Result<(), Box<dyn std::error::Error>> {
let params = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: 10.0,
tile_height: 10.0,
max_tiles: 1,
max_polys_per_tile: 1,
};
let nav_mesh = NavMesh::new(params)?;
let query = NavMeshQuery::new(&nav_mesh);
let filter = QueryFilter::default();
let dummy_ref = PolyRef::new(1);
let pos = Vec3::new(5.0, 0.0, 5.0);
let dir = Vec3::new(1.0, 0.0, 0.0);
let result = query.raycast(dummy_ref, pos, dir, -10.0, &filter);
assert!(result.is_err() || result.unwrap().2 == 0.0);
let result2 = query.raycast(dummy_ref, pos, dir, f32::NAN, &filter);
assert!(result2.is_err());
let result3 = query.raycast(dummy_ref, pos, dir, f32::INFINITY, &filter);
assert!(result3.is_ok() || result3.is_err());
Ok(())
}
#[test]
fn test_pathfinding_invalid_params() -> Result<(), Box<dyn std::error::Error>> {
let params = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: 10.0,
tile_height: 10.0,
max_tiles: 1,
max_polys_per_tile: 1,
};
let nav_mesh = NavMesh::new(params)?;
let mut query = NavMeshQuery::new(&nav_mesh);
let filter = QueryFilter::default();
let invalid_ref = PolyRef::new(0);
let valid_ref = PolyRef::new(1); let pos = [5.0, 0.0, 5.0];
let result = query.find_path(
invalid_ref,
valid_ref,
Vec3::from(pos),
Vec3::from(pos),
&filter,
);
assert!(result.is_err());
let result2 = query.find_path(
valid_ref,
invalid_ref,
Vec3::from(pos),
Vec3::from(pos),
&filter,
);
assert!(result2.is_err());
let result3 = query.find_path(
valid_ref,
valid_ref,
Vec3::from(pos),
Vec3::from(pos),
&filter,
);
assert!(result3.is_ok() || result3.is_err());
Ok(())
}
#[test]
fn test_sliced_pathfinding_invalid_params() -> Result<(), Box<dyn std::error::Error>> {
let params = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: 10.0,
tile_height: 10.0,
max_tiles: 1,
max_polys_per_tile: 1,
};
let nav_mesh = NavMesh::new(params)?;
let mut query = NavMeshQuery::new(&nav_mesh);
let filter = QueryFilter::default();
let invalid_ref = PolyRef::new(0);
let valid_ref = PolyRef::new(1);
let pos = [5.0, 0.0, 5.0];
let result = query.init_sliced_find_path(
invalid_ref,
valid_ref,
Vec3::from(pos),
Vec3::from(pos),
&filter,
0,
);
assert!(result.is_err());
let result2 = query.update_sliced_find_path(10);
assert!(result2.is_err());
let result3 = query.finalize_sliced_find_path(100);
assert!(result3.is_err());
Ok(())
}
#[test]
fn test_query_filter_edge_cases() -> Result<(), Box<dyn std::error::Error>> {
let params = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: 10.0,
tile_height: 10.0,
max_tiles: 1,
max_polys_per_tile: 1,
};
let nav_mesh = NavMesh::new(params)?;
let query = NavMeshQuery::new(&nav_mesh);
let mut exclude_all_filter = QueryFilter::default();
exclude_all_filter.include_flags = crate::PolyFlags::empty();
let pos = [5.0, 0.0, 5.0];
let half_extents = [1.0, 1.0, 1.0];
let result = query.find_nearest_poly(
Vec3::from(pos),
Vec3::from(half_extents),
&exclude_all_filter,
);
assert!(result.is_err() || result.unwrap().0 == PolyRef::new(0));
let mut extreme_cost_filter = QueryFilter::default();
extreme_cost_filter.area_cost[0] = f32::INFINITY;
let result2 = query.find_nearest_poly(
Vec3::from(pos),
Vec3::from(half_extents),
&extreme_cost_filter,
);
assert!(result2.is_ok() || result2.is_err());
Ok(())
}
#[test]
fn test_mesh_memory_safety() {
let huge_params = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: 10.0,
tile_height: 10.0,
max_tiles: i32::MAX, max_polys_per_tile: i32::MAX, };
let result = NavMesh::new(huge_params);
assert!(result.is_err());
}
#[test]
fn test_concurrent_access_safety() -> Result<(), Box<dyn std::error::Error>> {
let params = NavMeshParams {
origin: [0.0, 0.0, 0.0],
tile_width: 10.0,
tile_height: 10.0,
max_tiles: 1,
max_polys_per_tile: 1,
};
let nav_mesh = NavMesh::new(params)?;
let query = NavMeshQuery::new(&nav_mesh);
let filter = QueryFilter::default();
let pos = [5.0, 0.0, 5.0];
let half_extents = [1.0, 1.0, 1.0];
for _ in 0..10 {
let _result =
query.find_nearest_poly(Vec3::from(pos), Vec3::from(half_extents), &filter);
}
Ok(())
}
#[test]
fn test_rust_specific_safety() {
let mut test_vec = vec![1, 2, 3];
let _last = test_vec.pop();
let maybe_value: Option<i32> = None;
assert!(maybe_value.is_none());
use crate::Status;
let status = Status::InvalidParam;
assert!(!status.to_string().is_empty());
}
}