From 5e3441584aa30a6438d964388d73de328e3dbe37 Mon Sep 17 00:00:00 2001 From: randogoth Date: Thu, 11 Jun 2026 11:37:45 +0300 Subject: [PATCH] added tests --- src/lib.rs | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 3af0075..d9b71a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -454,4 +454,142 @@ impl Xenobalanus { clusters } +} + +#[cfg(test)] +mod tests { + use super::*; + + // --- Point --- + + #[test] + fn point_distance_3_4_5() { + let a = Point::new(0.0, 0.0); + let b = Point::new(3.0, 4.0); + assert!((a.distance(b) - 5.0).abs() < 1e-5); + } + + #[test] + fn point_bearing_east_is_zero() { + let origin = Point::new(0.0, 0.0); + let east = Point::new(1.0, 0.0); + // delta_y=0, delta_x=1 → atan2(0,1)=0° → bearing=0° + assert!((origin.bearing(east) - 0.0).abs() < 1e-4); + } + + // --- random_points --- + + #[test] + fn random_points_count_and_bounds() { + let mut xb = Xenobalanus::new(); + xb.random_points((0.0, 0.0), 10.0, 100); + let pts = xb.points(); + assert_eq!(pts.len(), 100); + for (x, y) in pts { + assert!(x >= -5.0 && x <= 5.0, "x={x} out of [-5, 5]"); + assert!(y >= -5.0 && y <= 5.0, "y={y} out of [-5, 5]"); + } + } + + // --- delaunay --- + + fn unit_square() -> Vec { + vec![ + Point::new(0.0, 0.0), + Point::new(1.0, 0.0), + Point::new(1.0, 1.0), + Point::new(0.0, 1.0), + ] + } + + #[test] + fn delaunay_four_points_two_triangles() { + let mut xb = Xenobalanus::new(); + xb.set_points(unit_square()); + xb.delaunay(); + // 4 convex points → 2 triangles → 6 indices + assert_eq!(xb.triangles_flat().len(), 6); + } + + // --- preprocess --- + + #[test] + fn preprocess_sequential_builds_edges() { + let mut xb = Xenobalanus::new(); + xb.set_points(unit_square()); + xb.delaunay(); + xb.preprocess(0, false); + // unit square Delaunay: 4 boundary edges + 1 diagonal = 5 + assert_eq!(xb.edge_lengths().len(), 5); + } + + #[test] + fn preprocess_parallel_matches_sequential() { + let mut xb_seq = Xenobalanus::new(); + xb_seq.set_points(unit_square()); + xb_seq.delaunay(); + xb_seq.preprocess(0, false); + + let mut xb_par = Xenobalanus::new(); + xb_par.set_points(unit_square()); + xb_par.delaunay(); + xb_par.preprocess(0, true); + + assert_eq!(xb_seq.edge_lengths().len(), xb_par.edge_lengths().len()); + } + + // --- dtscan --- + + #[test] + fn dtscan_finds_cluster_in_grid() { + let mut xb = Xenobalanus::new(); + // 3×3 grid with spacing 1.0; diagonal ≈ 1.414 + let pts: Vec = (0..3) + .flat_map(|i| (0..3).map(move |j| Point::new(i as f32, j as f32))) + .collect(); + xb.set_points(pts); + xb.delaunay(); + xb.preprocess(0, false); + // max_closeness=1.5 covers all edges (max diagonal ≈ 1.414) + let clusters = xb.dtscan(2, 1.5); + assert!(!clusters.is_empty()); + } + + // --- delfin --- + + #[test] + fn delfin_smoke_test() { + let mut xb = Xenobalanus::new(); + xb.random_points((0.0, 0.0), 100.0, 200); + xb.delaunay(); + xb.preprocess(2, false); + // just verify it runs without panic + let _voids = xb.delfin(0.0, 0.0); + } + + // --- readme example --- + + #[test] + fn readme_example_pipeline() { + // Mirrors the workflow shown in the README exactly. + let dots: u32 = 10000; + let side_length: f32 = 10000.0; + let mut xeno = Xenobalanus::new(); + xeno.random_points((0.0, 0.0), side_length, dots); + + xeno.delaunay(); + xeno.preprocess(0, false); + + let min_area: f32 = 1000.0; + let min_distance: f32 = 200.0; + let void_polygons: Vec> = xeno.delfin(min_area, min_distance); + + let min_pts: usize = 5; + let max_closeness: f32 = 100.5; + let clusters: Vec> = xeno.dtscan(min_pts, max_closeness); + + // With 10 000 uniform random points both algorithms should find results. + assert!(!void_polygons.is_empty(), "delfin found no voids"); + assert!(!clusters.is_empty(), "dtscan found no clusters"); + } } \ No newline at end of file