Skip to content

Commit

Permalink
test: write more tests for the core crate (#49)
Browse files Browse the repository at this point in the history
will fix the specific unwated behavior (116fb82, 483d7b6) later
  • Loading branch information
imrn99 authored Apr 22, 2024
1 parent ce3948d commit 97c7091
Show file tree
Hide file tree
Showing 7 changed files with 309 additions and 62 deletions.
113 changes: 70 additions & 43 deletions honeycomb-core/src/attributes/collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ impl<T: AttributeBind + AttributeUpdate> AttrSparseVec<T> {
/// - the index lands out of bounds
/// - the index cannot be converted to `usize`
///
#[deprecated]
pub fn get_mut(&mut self, index: T::IdentifierType) -> &mut Option<T> {
&mut self.data[index.to_usize().unwrap()]
}
Expand Down Expand Up @@ -279,6 +280,11 @@ impl<T: AttributeBind + AttributeUpdate + Clone> AttrCompactVec<T> {
self.data.len()
}

/// Return the number of stored, used attributes in the internal storage.
pub fn n_used_attributes(&self) -> usize {
self.data.len() - self.unused_data_slots.len()
}

/// Getter
///
/// # Arguments
Expand Down Expand Up @@ -317,6 +323,7 @@ impl<T: AttributeBind + AttributeUpdate + Clone> AttrCompactVec<T> {
/// - the index lands out of bounds
/// - the index cannot be converted to `usize`
///
#[deprecated]
pub fn get_mut(&mut self, index: T::IdentifierType) -> Option<&mut T> {
self.index_map[index.to_usize().unwrap()].map(|idx| &mut self.data[idx])
}
Expand Down Expand Up @@ -461,42 +468,8 @@ impl<T: AttributeBind + AttributeUpdate + Clone> AttrCompactVec<T> {

#[cfg(test)]
mod tests {
use super::super::Temperature;
use super::*;
use crate::{FaceIdentifier, OrbitPolicy};

#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Temperature {
pub val: f32,
}

impl AttributeUpdate for Temperature {
fn merge(attr1: Self, attr2: Self) -> Self {
Temperature {
val: (attr1.val + attr2.val) / 2.0,
}
}

fn split(attr: Self) -> (Self, Self) {
(attr, attr)
}

fn merge_undefined(attr: Option<Self>) -> Self {
attr.unwrap_or(Temperature { val: 0.0 })
}
}

impl AttributeBind for Temperature {
type IdentifierType = FaceIdentifier;
fn binds_to<'a>() -> OrbitPolicy<'a> {
OrbitPolicy::Face
}
}

impl From<f32> for Temperature {
fn from(val: f32) -> Self {
Self { val }
}
}

macro_rules! generate_sparse {
($name: ident) => {
Expand All @@ -514,6 +487,18 @@ mod tests {
};
}

#[test]
fn sparse_vec_n_attributes() {
generate_sparse!(storage);
assert_eq!(storage.n_attributes(), 10);
let _ = storage.remove(3);
assert_eq!(storage.n_attributes(), 9);
// extend does not affect the number of attributes
storage.extend(10);
assert!(storage.get(15).is_none());
assert_eq!(storage.n_attributes(), 9);
}

#[test]
fn sparse_vec_get_set_get() {
generate_sparse!(storage);
Expand All @@ -531,8 +516,8 @@ mod tests {
}

#[test]
#[should_panic]
fn sparse_vec_get_insert_get() {
#[should_panic(expected = "assertion failed: tmp.is_none()")]
fn sparse_vec_insert_already_existing() {
generate_sparse!(storage);
assert_eq!(storage.get(3), &Some(Temperature::from(279.0)));
storage.insert(3, Temperature::from(280.0)); // panic
Expand Down Expand Up @@ -575,8 +560,8 @@ mod tests {
}

#[test]
#[should_panic]
fn sparse_vec_remove_replace() {
#[should_panic(expected = "called `Option::unwrap()` on a `None` value")]
fn sparse_vec_replace_already_removed() {
generate_sparse!(storage);
assert_eq!(storage.remove(3), Some(Temperature::from(279.0)));
storage.replace(3, Temperature::from(280.0)).unwrap(); // panic
Expand All @@ -598,6 +583,48 @@ mod tests {
};
}

#[test]
fn compact_vec_n_attributes() {
generate_compact!(storage);
assert_eq!(storage.n_attributes(), 10);
let _ = storage.remove(3);
assert_eq!(storage.n_attributes(), 10);
// extend does not affect the number of attributes
storage.extend(10);
assert!(storage.get(15).is_none());
assert_eq!(storage.n_attributes(), 10);
}

#[test]
fn compact_vec_n_used_attributes() {
generate_compact!(storage);
assert_eq!(storage.n_used_attributes(), 10);
let _ = storage.remove(3);
assert_eq!(storage.n_used_attributes(), 9);
// extend does not affect the number of attributes
storage.extend(10);
assert!(storage.get(15).is_none());
assert_eq!(storage.n_used_attributes(), 9);
}

#[test]
fn compact_vec_extend_through_set() {
generate_compact!(storage);
assert_eq!(storage.n_attributes(), 10);
// extend does not affect the number of attributes
storage.extend(10);
assert_eq!(storage.n_attributes(), 10);
storage.set(10, Temperature::from(293.0));
assert_eq!(storage.n_attributes(), 11);
storage.set(11, Temperature::from(295.0));
assert_eq!(storage.n_attributes(), 12);
storage.set(12, Temperature::from(297.0));
assert_eq!(storage.n_attributes(), 13);
let _ = storage.remove(3);
assert_eq!(storage.n_attributes(), 13);
assert_eq!(storage.n_used_attributes(), 12);
}

#[test]
fn compact_vec_get_set_get() {
generate_compact!(storage);
Expand All @@ -615,8 +642,8 @@ mod tests {
}

#[test]
#[should_panic]
fn compact_vec_get_insert_get() {
#[should_panic(expected = "assertion failed: idx.is_none()")]
fn compact_vec_insert_already_existing() {
generate_compact!(storage);
assert_eq!(storage.get(3), Some(&Temperature::from(279.0)));
storage.insert(3, Temperature::from(280.0)); // panic
Expand Down Expand Up @@ -659,8 +686,8 @@ mod tests {
}

#[test]
#[should_panic]
fn compact_vec_remove_replace() {
#[should_panic(expected = "assertion failed: idx.is_some()")]
fn compact_vec_replace_already_removed() {
generate_compact!(storage);
assert_eq!(storage.remove(3), Some(Temperature::from(279.0)));
storage.replace(3, Temperature::from(280.0)); // panic
Expand Down
40 changes: 40 additions & 0 deletions honeycomb-core/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,43 @@

pub mod collections;
pub mod traits;

// ------ TESTS

#[cfg(test)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
struct Temperature {
pub val: f32,
}

#[cfg(test)]
impl crate::AttributeUpdate for Temperature {
fn merge(attr1: Self, attr2: Self) -> Self {
Temperature {
val: (attr1.val + attr2.val) / 2.0,
}
}

fn split(attr: Self) -> (Self, Self) {
(attr, attr)
}

fn merge_undefined(attr: Option<Self>) -> Self {
attr.unwrap_or(Temperature { val: 0.0 })
}
}

#[cfg(test)]
impl crate::AttributeBind for Temperature {
type IdentifierType = crate::FaceIdentifier;
fn binds_to<'a>() -> crate::OrbitPolicy<'a> {
crate::OrbitPolicy::Face
}
}

#[cfg(test)]
impl From<f32> for Temperature {
fn from(val: f32) -> Self {
Self { val }
}
}
30 changes: 30 additions & 0 deletions honeycomb-core/src/attributes/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,33 @@ pub trait AttributeBind: Sized {
/// which the attribute is associated.
fn binds_to<'a>() -> OrbitPolicy<'a>;
}

#[cfg(test)]
mod tests {
use super::super::Temperature;
use super::*;
use std::any::Any;

#[test]
fn attribute_update() {
let t1 = Temperature { val: 273.0 };
let t2 = Temperature { val: 298.0 };

let t_new = AttributeUpdate::merge(t1, t2); // use AttributeUpdate::_
let t_ref = Temperature { val: 285.5 };

assert_eq!(Temperature::split(t_new), (t_ref, t_ref)); // or Temperature::_
assert_eq!(Temperature::merge_undefined(Some(t_ref)), t_ref);
assert_eq!(Temperature::merge_undefined(None), Temperature::from(0.0))
}

#[test]
fn attribute_bind() {
assert_eq!(Temperature::binds_to(), crate::OrbitPolicy::Face);
let inst: <Temperature as AttributeBind>::IdentifierType = 0;
let ref_inst: crate::FaceIdentifier = 0;
let prim_inst: u32 = 0;
assert_eq!(inst.type_id(), ref_inst.type_id());
assert_eq!(inst.type_id(), prim_inst.type_id());
}
}
5 changes: 3 additions & 2 deletions honeycomb-core/src/cells/orbits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use std::collections::{BTreeSet, VecDeque};
///
/// This is used to define special cases of orbits that are often used in
/// algorithms. These special cases correspond to *i-cells*.
#[derive(Debug, PartialEq)]
pub enum OrbitPolicy<'a> {
/// 0-cell orbit.
Vertex,
Expand Down Expand Up @@ -286,14 +287,14 @@ mod tests {
}

#[test]
#[should_panic]
#[should_panic(expected = "assertion failed: !slice.len().is_zero()")]
fn empty_orbit_policy() {
let map = simple_map();
let _ = Orbit2::new(&map, OrbitPolicy::Custom(&[]), 3);
}

#[test]
#[should_panic]
#[should_panic(expected = "assertion failed: i < 3")]
fn invalid_orbit_policy() {
let map = simple_map();
let orbit = Orbit2::new(&map, OrbitPolicy::Custom(&[6]), 3);
Expand Down
2 changes: 0 additions & 2 deletions honeycomb-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@
#![allow(clippy::semicolon_if_nothing_returned)]
#![allow(clippy::needless_for_each)]
#![allow(clippy::needless_pass_by_value)]
#![allow(clippy::should_panic_without_expect)]
#![allow(clippy::float_cmp)]

// ------ MODULE DECLARATIONS
mod attributes;
Expand Down
60 changes: 47 additions & 13 deletions honeycomb-core/src/spatial_repr/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,35 +292,69 @@ mod tests {
use super::*;
use crate::FloatType;

fn almost_equal(lhs: &Vector2<FloatType>, rhs: &Vector2<FloatType>) -> bool {
const EPS: FloatType = 10.0e-12;
((lhs.x() - rhs.x()).abs() < EPS) & ((lhs.y() - rhs.y()).abs() < EPS)
macro_rules! almost_equal {
($f1: expr, $f2: expr) => {
((($f1 - $f2) as FloatType).abs() < FloatType::EPSILON)
};
}

fn almost_equal_vec(lhs: &Vector2<FloatType>, rhs: &Vector2<FloatType>) -> bool {
almost_equal!(lhs.x(), rhs.x()) & almost_equal!(lhs.y(), rhs.y())
}

#[test]
fn dot_product() {
let along_x = Vector2::unit_x() * 15.0;
let along_y = Vector2::unit_y() * 10.0;
assert_eq!(along_x.dot(&along_y), 0.0);
assert_eq!(along_x.dot(&Vector2::unit_x()), 15.0);
assert_eq!(along_y.dot(&Vector2::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));
}

#[test]
fn unit_dir() {
let along_x = Vector2::unit_x() * 4.0;
let along_y = Vector2::unit_y() * 3.0;
assert_eq!(along_x.unit_dir().unwrap(), Vector2::unit_x());
assert_eq!(
Vector2::<FloatType>::unit_x().unit_dir().unwrap(),
Vector2::unit_x()
);
assert_eq!(along_y.unit_dir().unwrap(), Vector2::unit_y());
assert!(almost_equal(
assert!(almost_equal_vec(
&along_x.unit_dir().unwrap(),
&Vector2::unit_x()
));
assert!(almost_equal_vec(
&Vector2::<FloatType>::unit_x().unit_dir().unwrap(),
&Vector2::unit_x()
));
assert!(almost_equal_vec(
&along_y.unit_dir().unwrap(),
&Vector2::unit_y()
));
assert!(almost_equal_vec(
&(along_x + along_y).unit_dir().unwrap(),
&Vector2::from((4.0 / 5.0, 3.0 / 5.0))
));
let origin: Vector2<FloatType> = Vector2::default();
assert!(origin.unit_dir().is_err());
}

#[test]
fn normal_dir() {
let along_x = Vector2::unit_x() * 4.0;
let along_y = Vector2::unit_y() * 3.0;
assert!(almost_equal_vec(&along_x.normal_dir(), &Vector2::unit_y()));
assert!(almost_equal_vec(
&Vector2::unit_x().normal_dir(),
&Vector2::unit_y()
));
assert!(almost_equal_vec(&along_y.normal_dir(), &-Vector2::unit_x()));
assert!(almost_equal_vec(
&Vector2::unit_y().normal_dir(),
&-Vector2::unit_x()
));
}

#[test]
#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: InvalidUnitDir")]
fn normal_dir_of_null_vel() {
let origin: Vector2<FloatType> = Vector2::default();
let _ = origin.normal_dir(); // panics
}
}
Loading

0 comments on commit 97c7091

Please sign in to comment.