Skip to content

Commit

Permalink
test: update honeycomb-core::spatial_repr tests (#79)
Browse files Browse the repository at this point in the history
* add dedicated test module in spatial_repr

* add a correct almsot_equal function for fp scalars

* move Coords2 tests to dedicated module

* move Vector2 tests to dedicated file

* move Vertex2 tests to dedicated file

* extract common macro for Coords2 & Vector2

it's dirty but it works
  • Loading branch information
imrn99 authored May 22, 2024
1 parent ed13719 commit 45f89af
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 218 deletions.
43 changes: 0 additions & 43 deletions honeycomb-core/src/spatial_repr/coords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,46 +209,3 @@ impl<T: CoordsFloat> IndexMut<usize> for Coords2<T> {
}
}
}

// ------ TESTS

#[cfg(test)]
mod tests {
use super::*;

macro_rules! almost_equal {
($f1: expr, $f2: expr, $t: ty) => {
($f1 - $f2).abs() < <$t>::EPSILON
};
}
macro_rules! almost_equal_vec {
($lhs: expr, $rhs: expr, $t: ty) => {
almost_equal!($lhs.x, $rhs.x, $t) & almost_equal!($lhs.y, $rhs.y, $t)
};
}

macro_rules! generate_sum_test {
($id: ident, $t: ty) => {
#[test]
fn $id() {
let collection = [
Coords2::unit_x(),
Coords2::unit_x(),
Coords2::unit_x(),
Coords2::unit_y(),
Coords2::unit_y(),
Coords2::unit_y(),
];

let owned_sum: Coords2<$t> = collection.into_iter().sum();
let borrowed_sum: Coords2<$t> = collection.iter().sum();
let ref_value: Coords2<$t> = Coords2::from((3.0, 3.0));
assert!(almost_equal_vec!(owned_sum, ref_value, $t));
assert!(almost_equal_vec!(borrowed_sum, ref_value, $t));
}
};
}

generate_sum_test!(sum_simple, f32);
generate_sum_test!(sum_double, f64);
}
4 changes: 4 additions & 0 deletions honeycomb-core/src/spatial_repr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@
pub mod coords;
pub mod vector;
pub mod vertex;

// ------ TESTS
#[cfg(test)]
mod tests;
220 changes: 220 additions & 0 deletions honeycomb-core/src/spatial_repr/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
// ------ IMPORTS

// ------ CONTENT

use crate::CoordsFloat;

// --- common

// scalar equality function
// ref: https://floating-point-gui.de/errors/comparison/
fn almost_equal<T: CoordsFloat>(a: T, b: T) -> bool {
let abs_diff = (a - b).abs();
let abs_sum = a.abs() + b.abs();
if a == b {
// early return
true
} else if a.is_zero() | b.is_zero() | (abs_sum < T::min_positive_value()) {
// close to zero
abs_diff < (T::epsilon() * T::min_positive_value())
} else {
// regular case
abs_diff / abs_sum.min(T::max_value()) < T::epsilon()
}
}

macro_rules! almost_equals {
// Coords
($lhs: expr, $rhs: expr) => {
almost_equal($lhs.x, $rhs.x) & almost_equal($lhs.x, $rhs.x)
};
// Vector / Vertex
(($lhs: expr, $rhs: expr)) => {
almost_equal($lhs.x(), $rhs.x()) & almost_equal($lhs.y(), $rhs.y())
};
}

// --- coords

mod coords {
use super::almost_equal;
use crate::Coords2;
// tests
macro_rules! generate_sum_test {
($id: ident, $t: ty) => {
#[test]
fn $id() {
let collection = [
Coords2::unit_x(),
Coords2::unit_x(),
Coords2::unit_x(),
Coords2::unit_y(),
Coords2::unit_y(),
Coords2::unit_y(),
];

let owned_sum: Coords2<$t> = collection.into_iter().sum();
let borrowed_sum: Coords2<$t> = collection.iter().sum();
let ref_value: Coords2<$t> = Coords2::from((3.0, 3.0));
assert!(almost_equals!(owned_sum, ref_value));
assert!(almost_equals!(borrowed_sum, ref_value));
}
};
}
// generation
generate_sum_test!(sum_simple, f32);
generate_sum_test!(sum_double, f64);
}

// --- vector

mod vector {
use super::almost_equal;
use crate::{CoordsError, Vector2};
// tests
macro_rules! generate_dot_prod_test {
($id: ident, $t: ty) => {
#[test]
fn $id() {
let along_x = Vector2::<$t>::unit_x() * 15.0;
let along_y = Vector2::<$t>::unit_y() * 10.0;
assert!(almost_equal(along_x.dot(&along_y), 0.0));
assert!(almost_equal(along_x.dot(&Vector2::unit_x()), 15.0));
assert!(almost_equal(along_y.dot(&Vector2::unit_y()), 10.0));
}
};
}
macro_rules! generate_unit_dir_test {
($id: ident, $t: ty) => {
#[test]
fn $id() {
let along_x = Vector2::<$t>::unit_x() * 4.0;
let along_y = Vector2::<$t>::unit_y() * 3.0;
assert!(almost_equals!((
along_x.unit_dir().unwrap(),
Vector2::<$t>::unit_x()
)));
assert!(almost_equals!((
Vector2::<$t>::unit_x().unit_dir().unwrap(),
Vector2::<$t>::unit_x()
)));
assert!(almost_equals!((
along_y.unit_dir().unwrap(),
Vector2::<$t>::unit_y()
)));
assert!(almost_equals!((
(along_x + along_y).unit_dir().unwrap(),
Vector2::<$t>::from((4.0 / 5.0, 3.0 / 5.0))
)));
let origin: Vector2<$t> = Vector2::default();
assert_eq!(origin.unit_dir(), Err(CoordsError::InvalidUnitDir));
}
};
}
macro_rules! generate_normal_dir_test {
($id: ident, $t: ty) => {
#[test]
fn $id() {
let along_x = Vector2::<$t>::unit_x() * 4.0;
let along_y = Vector2::<$t>::unit_y() * 3.0;
assert!(almost_equals!((
along_x.normal_dir().unwrap(),
Vector2::<$t>::unit_y()
)));
assert!(almost_equals!((
Vector2::<$t>::unit_x().normal_dir().unwrap(),
Vector2::<$t>::unit_y()
)));
assert!(almost_equals!((
along_y.normal_dir().unwrap(),
-Vector2::<$t>::unit_x()
)));
assert!(almost_equals!((
Vector2::<$t>::unit_y().normal_dir().unwrap(),
-Vector2::<$t>::unit_x()
)));
let origin: Vector2<$t> = Vector2::default();
assert_eq!(origin.normal_dir(), Err(CoordsError::InvalidUnitDir));
}
};
}
// generation
generate_dot_prod_test!(dot_product_simple, f32);
generate_dot_prod_test!(dot_product_double, f64);

generate_unit_dir_test!(unit_dir_simple, f32);
generate_unit_dir_test!(unit_dir_double, f64);

generate_normal_dir_test!(normal_dir_simple, f32);
generate_normal_dir_test!(normal_dir_double, f64);
}

// --- vertex

mod vertex {
use crate::{Vector2, Vertex2};
// tests
#[test]
fn add_vertex_vector() {
{
let mut a: Vertex2<f64> = Vertex2::from((1.0, 1.0));
let b: Vector2<f64> = Vector2::from((1.0, 0.0));
let a_moved = a + b;
assert_eq!(a_moved, Vertex2::from((2.0, 1.0)));
a += &b;
assert_eq!(a, a_moved);
a += b;
assert_eq!(a, Vertex2::from((3.0, 1.0)));
}
{
let mut a: Vertex2<f32> = Vertex2::from((1.0, 1.0));
let b: Vector2<f32> = Vector2::from((1.0, 0.0));
let a_moved = a + b;
assert_eq!(a_moved, Vertex2::from((2.0, 1.0)));
a += &b;
assert_eq!(a, a_moved);
a += b;
assert_eq!(a, Vertex2::from((3.0, 1.0)));
}
}

#[test]
fn sub_vertex_vector() {
{
let mut a: Vertex2<f64> = Vertex2::from((1.0, 1.0));
let b: Vector2<f64> = Vector2::from((1.0, 0.0));
let a_moved = a - b;
assert_eq!(a_moved, Vertex2::from((0.0, 1.0)));
a -= &b;
assert_eq!(a, a_moved);
a -= b;
assert_eq!(a, Vertex2::from((-1.0, 1.0)));
}
{
let mut a: Vertex2<f32> = Vertex2::from((1.0, 1.0));
let b: Vector2<f32> = Vector2::from((1.0, 0.0));
let a_moved = a - b;
assert_eq!(a_moved, Vertex2::from((0.0, 1.0)));
a -= &b;
assert_eq!(a, a_moved);
a -= b;
assert_eq!(a, Vertex2::from((-1.0, 1.0)));
}
}

#[test]
fn sub_vertex_vertex() {
{
let a: Vertex2<f64> = Vertex2::from((1.0, 1.0));
let b: Vertex2<f64> = Vertex2::from((1.0, 0.0));
let ab = b - a;
assert_eq!(ab, Vector2::from((0.0, -1.0)));
}
{
let a: Vertex2<f32> = Vertex2::from((1.0, 1.0));
let b: Vertex2<f32> = Vertex2::from((1.0, 0.0));
let ab = b - a;
assert_eq!(ab, Vector2::from((0.0, -1.0)));
}
}
}
104 changes: 0 additions & 104 deletions honeycomb-core/src/spatial_repr/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,107 +285,3 @@ impl<T: CoordsFloat> std::ops::Neg for Vector2<T> {
Self { inner: -self.inner }
}
}

// ------ TESTS

#[cfg(test)]
mod tests {
use super::*;

// utils
macro_rules! almost_equal {
($f1: expr, $f2: expr, $t: ty) => {
($f1 - $f2).abs() < <$t>::EPSILON
};
}
macro_rules! almost_equal_vec {
($lhs: expr, $rhs: expr, $t: ty) => {
almost_equal!($lhs.x(), $rhs.x(), $t) & almost_equal!($lhs.y(), $rhs.y(), $t)
};
}

// tests
macro_rules! generate_dot_prod_test {
($id: ident, $t: ty) => {
#[test]
fn $id() {
let along_x = Vector2::<$t>::unit_x() * 15.0;
let along_y = Vector2::<$t>::unit_y() * 10.0;
assert!(almost_equal!(along_x.dot(&along_y), 0.0, $t));
assert!(almost_equal!(along_x.dot(&Vector2::unit_x()), 15.0, $t));
assert!(almost_equal!(along_y.dot(&Vector2::unit_y()), 10.0, $t));
}
};
}
macro_rules! generate_unit_dir_test {
($id: ident, $t: ty) => {
#[test]
fn $id() {
let along_x = Vector2::<$t>::unit_x() * 4.0;
let along_y = Vector2::<$t>::unit_y() * 3.0;
assert!(almost_equal_vec!(
along_x.unit_dir().unwrap(),
Vector2::<$t>::unit_x(),
$t
));
assert!(almost_equal_vec!(
Vector2::<$t>::unit_x().unit_dir().unwrap(),
Vector2::<$t>::unit_x(),
$t
));
assert!(almost_equal_vec!(
along_y.unit_dir().unwrap(),
Vector2::<$t>::unit_y(),
$t
));
assert!(almost_equal_vec!(
(along_x + along_y).unit_dir().unwrap(),
Vector2::<$t>::from((4.0 / 5.0, 3.0 / 5.0)),
$t
));
let origin: Vector2<$t> = Vector2::default();
assert_eq!(origin.unit_dir(), Err(CoordsError::InvalidUnitDir));
}
};
}
macro_rules! generate_normal_dir_test {
($id: ident, $t: ty) => {
#[test]
fn $id() {
let along_x = Vector2::<$t>::unit_x() * 4.0;
let along_y = Vector2::<$t>::unit_y() * 3.0;
assert!(almost_equal_vec!(
along_x.normal_dir().unwrap(),
Vector2::<$t>::unit_y(),
$t
));
assert!(almost_equal_vec!(
Vector2::<$t>::unit_x().normal_dir().unwrap(),
Vector2::<$t>::unit_y(),
$t
));
assert!(almost_equal_vec!(
along_y.normal_dir().unwrap(),
-Vector2::<$t>::unit_x(),
$t
));
assert!(almost_equal_vec!(
Vector2::<$t>::unit_y().normal_dir().unwrap(),
-Vector2::<$t>::unit_x(),
$t
));
let origin: Vector2<$t> = Vector2::default();
assert_eq!(origin.normal_dir(), Err(CoordsError::InvalidUnitDir));
}
};
}

generate_dot_prod_test!(dot_product_simple, f32);
generate_dot_prod_test!(dot_product_double, f64);

generate_unit_dir_test!(unit_dir_simple, f32);
generate_unit_dir_test!(unit_dir_double, f64);

generate_normal_dir_test!(normal_dir_simple, f32);
generate_normal_dir_test!(normal_dir_double, f64);
}
Loading

0 comments on commit 45f89af

Please sign in to comment.