#![cfg(test)]
mod tests {
use crate::*;
use num_traits::Zero;
#[test]
fn test_new() {
let input = 1000;
let output = Distance::new(input.into(), DistanceUnit::mm);
assert_eq!(output.get_tuple(), (1.0, 0));
assert_eq!(output.to(DistanceUnit::mm), 1000.0);
}
#[test]
fn optimize_on_add() {
let f_1 = Force::new(10.0, ForceUnit::N);
let f_2 = Force::new(1.0E12, ForceUnit::N);
let f = f_1 + f_2;
assert!(f.get_multiplier().log10().round() == 0.);
}
#[test]
fn optimize_large() {
let mut x = Force {
multiplier: 1E10,
power: 0,
};
x.optimize();
assert!(x.get_multiplier().log10().round() == 0.);
assert_eq!(x.to(ForceUnit::N), 1E10);
}
#[test]
fn optimize_small() {
let mut x = Force {
multiplier: 1E-10,
power: 0,
};
x.optimize();
assert!(x.get_multiplier().log10().round() == 0.);
assert_eq!(x.to(ForceUnit::N), 1E-10);
}
#[test]
fn from_exponential_preserves_small_multiplier_with_large_positive_power() {
let force = Force::from_exponential(1.0e-20, 20);
assert!((force.to(ForceUnit::N) - 1.0).abs() < 1.0e-12);
}
#[test]
fn as_f64_preserves_denormalized_representation() {
let force = Force {
multiplier: 1.0e-20,
power: 20,
};
assert!((force.as_f64() - 1.0).abs() < 1.0e-12);
assert!((force.to(ForceUnit::N) - 1.0).abs() < 1.0e-12);
}
#[test]
fn optimize_normalizes_small_multiplier_instead_of_zeroing() {
let mut force = Force {
multiplier: 1.0e-20,
power: 20,
};
force.optimize();
assert!((force.to(ForceUnit::N) - 1.0).abs() < 1.0e-12);
assert!(!force.is_zero());
}
#[test]
fn optimize_zero() {
let mut f_1 = Force::zero();
f_1.optimize();
assert_eq!(f_1, Force::zero());
}
#[test]
fn optimize_infinity_is_a_no_op() {
let mut pos = Force::INFINITY;
let mut neg = Force::NEG_INFINITY;
pos.optimize();
neg.optimize();
assert!(pos.get_multiplier().is_infinite());
assert!(neg.get_multiplier().is_infinite());
assert!(pos.get_multiplier().is_sign_positive());
assert!(neg.get_multiplier().is_sign_negative());
assert_eq!(pos.get_power(), 0);
assert_eq!(neg.get_power(), 0);
}
#[test]
fn optimize_saturates_to_infinity_when_upper_bound_is_reached() {
let mut force = Force {
multiplier: 1.0,
power: MAX_ABS_QUANTITY_POWER,
};
force.optimize();
assert!(force.get_multiplier().is_infinite());
assert!(force.get_multiplier().is_sign_positive());
assert_eq!(force.get_power(), 0);
}
#[test]
fn optimize_saturates_to_zero_when_lower_bound_is_reached() {
let mut force = Force {
multiplier: 1.0,
power: -MAX_ABS_QUANTITY_POWER,
};
force.optimize();
assert!(force.is_zero());
assert_eq!(force.get_power(), 0);
}
#[test]
fn scalar_mul_saturates_when_upper_bound_is_reached() {
let force = Force::from_exponential(1.0, MAX_ABS_QUANTITY_POWER - 1) * 10.0;
assert!(force.get_multiplier().is_infinite());
assert!(force.get_multiplier().is_sign_positive());
assert_eq!(force.get_power(), 0);
}
#[test]
fn scalar_div_saturates_to_zero_when_lower_bound_is_reached() {
let force = Force::from_exponential(1.0, -(MAX_ABS_QUANTITY_POWER - 1)) / 10.0;
assert!(force.is_zero());
assert_eq!(force.get_power(), 0);
}
#[test]
fn add_and_sub_keep_normalized_power_within_bound() {
let lhs = Force::from_exponential(1.0e-20, 20);
let rhs = Force::from_exponential(5.0e-21, 20);
let sum = lhs + rhs;
assert!(sum.get_power().abs() < MAX_ABS_QUANTITY_POWER);
assert!((sum.to(ForceUnit::N) - 1.5).abs() < 1.0e-12);
let diff = lhs - rhs;
assert!(diff.get_power().abs() < MAX_ABS_QUANTITY_POWER);
assert!((diff.to(ForceUnit::N) - 0.5).abs() < 1.0e-12);
}
#[test]
fn mul_with_self() {
let a = Quantity::AreaQuantity(Area::new(10.0, AreaUnit::msq));
let b = (a * a).unwrap();
assert_eq!(
b.to(Unit::AreaOfMomentUnit(AreaOfMomentUnit::mhc)).unwrap(),
100.0
);
}
#[test]
fn sqrt() {
let a = Quantity::AreaOfMomentQuantity(AreaOfMoment::new(25.0, AreaOfMomentUnit::mhc));
let b = a.sqrt().unwrap();
assert!((b.to(Unit::AreaUnit(AreaUnit::msq)).unwrap() - 5.0).abs() < 1E-10);
}
#[test]
fn inverse_stress_from_stress_division() {
let stress = Stress::new(2.0, StressUnit::Pa);
let inverse = 1.0 / stress;
assert!((inverse.to(InverseStressUnit::_Pa) - 0.5).abs() < 1E-12);
}
#[test]
fn stress_from_inverse_stress_division() {
let inverse = InverseStress::new(0.5, InverseStressUnit::_Pa);
let stress = 1.0 / inverse;
assert!((stress.to(StressUnit::Pa) - 2.0).abs() < 1E-12);
}
#[test]
fn stress_squared_from_force_stress_over_area() {
let force = Force::new(2.0, ForceUnit::N);
let stress = Stress::new(3.0, StressUnit::Pa);
let area = Area::new(6.0, AreaUnit::msq);
let result = (force * stress) / area;
assert!((result.to(StressSquaredUnit::Nsq_mmhc) - 1.0).abs() < 1E-12);
}
#[test]
fn force_stress_from_stress_squared_times_area() {
let stress_squared = StressSquared::new(2.0, StressSquaredUnit::Nsq_mmhc);
let area = Area::new(3.0, AreaUnit::msq);
let result = stress_squared * area;
assert!((result.to(ForceStressUnit::Nsq_msq) - 6.0).abs() < 1E-12);
}
#[test]
fn test_optimal_unit_with_selection() {
let area = Area::new(0.0001, AreaUnit::msq);
let optimal_unit = area
.optimal_unit(
vec![AreaUnit::kmsq, AreaUnit::cmsq, AreaUnit::nmsq]
.into_iter()
.collect::<std::collections::HashSet<_>>(),
)
.unwrap();
assert_eq!(optimal_unit, AreaUnit::cmsq)
}
}