foundation: move apsis-units tests into tests directory

This commit is contained in:
ApsisRS contributors 2026-09-26 13:02:01 +08:00
parent d1666ac28a
commit 1adbbe3b64
10 changed files with 227 additions and 239 deletions

View File

@ -129,65 +129,3 @@ impl fmt::Display for Degrees {
impl_quantity_ops!(Radians);
impl_quantity_ops!(Degrees);
#[cfg(test)]
mod tests {
use super::{Degrees, Radians};
use crate::dimension::Angle;
use apsis_core::{Quantity, Unit};
use core::f64::consts::PI;
#[test]
fn direct_conversions_are_consistent() {
assert!((Degrees::new(180.0).to_radians().value() - PI).abs() < 1e-12);
assert!((Radians::new(PI).to_degrees().value() - 180.0).abs() < 1e-12);
assert!((Degrees::new(90.0).to_radians().value() - PI / 2.0).abs() < 1e-12);
}
#[test]
fn generic_conversion_matches_direct_conversion() {
let angle = Degrees::new(45.0);
let via_trait: Radians = angle.to_unit();
assert!((via_trait.value() - angle.to_radians().value()).abs() < 1e-12);
}
#[test]
fn conversion_round_trips() {
let original = Degrees::new(137.5);
let round_tripped: Degrees = original.to_unit::<Radians>().to_unit();
assert!((round_tripped.value() - original.value()).abs() < 1e-12);
}
#[test]
fn wrap_places_angles_in_the_canonical_range() {
for turns in -3..=3 {
let angle = Radians::new(PI + f64::from(turns) * 2.0 * PI);
let wrapped = angle.wrap();
assert!(wrapped.value() >= -PI);
assert!(wrapped.value() < PI);
// Wrapping shifts by whole turns, so the angle is preserved
// modulo two pi.
let difference = angle.value() - wrapped.value();
assert!((difference / (2.0 * PI)).fract().abs() < 1e-12);
}
assert!((Radians::new(0.0).wrap().value()).abs() < 1e-12);
assert!((Radians::new(PI).wrap().value() + PI).abs() < 1e-12);
}
#[test]
fn unit_metadata_is_available() {
assert_eq!(Radians::symbol(), "rad");
assert_eq!(Degrees::symbol(), "deg");
assert_eq!(Radians::factor_to_base(), 1.0);
assert!((Degrees::factor_to_base() - PI / 180.0).abs() < 1e-15);
fn assert_angle<U: Unit<Dimension = Angle>>() {}
assert_angle::<Radians>();
assert_angle::<Degrees>();
}
#[test]
fn display_includes_the_symbol() {
assert_eq!(Radians::new(1.0).to_string(), "1 rad");
assert_eq!(Degrees::new(90.0).to_string(), "90 deg");
}
}

View File

@ -63,34 +63,3 @@ impl fmt::Display for Hertz {
}
impl_quantity_ops!(Hertz);
#[cfg(test)]
mod tests {
use super::Hertz;
use crate::dimension::Frequency;
use apsis_core::Unit;
#[test]
fn stores_the_given_value() {
assert_eq!(Hertz::new(1_575.42).value(), 1_575.42);
}
#[test]
fn period_is_the_reciprocal() {
assert!((Hertz::new(2.0).period() - 0.5).abs() < 1e-12);
assert!(Hertz::new(0.0).period().is_infinite());
}
#[test]
fn unit_metadata_is_available() {
assert_eq!(Hertz::symbol(), "Hz");
assert_eq!(Hertz::factor_to_base(), 1.0);
fn assert_frequency<U: Unit<Dimension = Frequency>>() {}
assert_frequency::<Hertz>();
}
#[test]
fn display_includes_the_symbol() {
assert_eq!(Hertz::new(1_000.0).to_string(), "1000 Hz");
}
}

View File

@ -113,72 +113,3 @@ impl fmt::Display for Kilometers {
impl_quantity_ops!(Meters);
impl_quantity_ops!(Kilometers);
#[cfg(test)]
mod tests {
use super::{Kilometers, Meters};
use crate::dimension::Length;
use apsis_core::{Quantity, Unit};
#[test]
fn stores_the_given_value() {
assert_eq!(Meters::new(12.5).value(), 12.5);
assert_eq!(Kilometers::new(-3.0).value(), -3.0);
}
#[test]
fn direct_conversions_are_consistent() {
assert_eq!(Meters::new(2_500.0).to_kilometers().value(), 2.5);
assert_eq!(Kilometers::new(2.5).to_meters().value(), 2_500.0);
}
#[test]
fn generic_conversion_matches_direct_conversion() {
let distance = Meters::new(2_500.0);
let via_trait: Kilometers = distance.to_unit();
assert_eq!(via_trait, distance.to_kilometers());
}
#[test]
fn conversion_round_trips() {
let original = Kilometers::new(42.195);
let round_tripped: Kilometers = original.to_unit::<Meters>().to_unit();
assert!((round_tripped.value() - original.value()).abs() < 1e-12);
}
#[test]
fn units_report_their_metadata() {
assert_eq!(Meters::symbol(), "m");
assert_eq!(Kilometers::symbol(), "km");
assert_eq!(Meters::factor_to_base(), 1.0);
assert_eq!(Kilometers::factor_to_base(), 1_000.0);
// Both units measure the same dimension, which is what makes the
// generic conversion above type check.
fn assert_length<U: Unit<Dimension = Length>>() {}
assert_length::<Meters>();
assert_length::<Kilometers>();
}
#[test]
fn arithmetic_operates_on_the_stored_value() {
let sum = Meters::new(1.5) + Meters::new(2.5);
assert_eq!(sum.value(), 4.0);
let difference = Meters::new(4.0) - Meters::new(1.0);
assert_eq!(difference.value(), 3.0);
let scaled = Meters::new(3.0) * 2.0;
assert_eq!(scaled.value(), 6.0);
let straddled = 2.0 * Meters::new(3.0);
assert_eq!(straddled.value(), 6.0);
let halved = Meters::new(3.0) / 2.0;
assert_eq!(halved.value(), 1.5);
let ratio = Meters::new(3.0) / Meters::new(1.5);
assert_eq!(ratio, 2.0);
assert_eq!((-Meters::new(1.0)).value(), -1.0);
}
#[test]
fn display_includes_the_symbol() {
assert_eq!(Meters::new(1.0).to_string(), "1 m");
assert_eq!(Kilometers::new(2.0).to_string(), "2 km");
}
}

View File

@ -77,46 +77,3 @@ impl fmt::Display for Kelvin {
}
impl_quantity_ops!(Kelvin);
#[cfg(test)]
mod tests {
use super::Kelvin;
use crate::dimension::Temperature;
use apsis_core::Unit;
use apsis_core::constant::ZERO_CELSIUS_IN_KELVIN;
#[test]
fn stores_the_given_value() {
assert_eq!(Kelvin::new(290.0).value(), 290.0);
}
#[test]
fn celsius_conversion_uses_the_exact_offset() {
let freezing = Kelvin::from_celsius(0.0);
assert_eq!(freezing.value(), ZERO_CELSIUS_IN_KELVIN);
assert_eq!(freezing.to_celsius(), 0.0);
let boiling = Kelvin::from_celsius(100.0);
assert!((boiling.to_celsius() - 100.0).abs() < 1e-12);
}
#[test]
fn celsius_conversion_round_trips() {
let original = Kelvin::new(273.15 + 21.5);
assert!(
(Kelvin::from_celsius(original.to_celsius()).value() - original.value()).abs() < 1e-12
);
}
#[test]
fn unit_metadata_is_available() {
assert_eq!(Kelvin::symbol(), "K");
assert_eq!(Kelvin::factor_to_base(), 1.0);
fn assert_temperature<U: Unit<Dimension = Temperature>>() {}
assert_temperature::<Kelvin>();
}
#[test]
fn display_includes_the_symbol() {
assert_eq!(Kelvin::new(300.0).to_string(), "300 K");
}
}

View File

@ -55,37 +55,3 @@ impl fmt::Display for Seconds {
}
impl_quantity_ops!(Seconds);
#[cfg(test)]
mod tests {
use super::Seconds;
use crate::dimension::Time;
use apsis_core::Unit;
#[test]
fn stores_the_given_value() {
assert_eq!(Seconds::new(0.5).value(), 0.5);
}
#[test]
fn unit_metadata_is_available() {
assert_eq!(Seconds::symbol(), "s");
assert_eq!(Seconds::factor_to_base(), 1.0);
fn assert_time<U: Unit<Dimension = Time>>() {}
assert_time::<Seconds>();
}
#[test]
fn arithmetic_operates_on_the_stored_value() {
assert_eq!((Seconds::new(1.0) + Seconds::new(2.0)).value(), 3.0);
assert_eq!((Seconds::new(3.0) - Seconds::new(2.0)).value(), 1.0);
assert_eq!((Seconds::new(3.0) * 2.0).value(), 6.0);
assert_eq!((Seconds::new(3.0) / 3.0).value(), 1.0);
assert_eq!(Seconds::new(6.0) / Seconds::new(3.0), 2.0);
}
#[test]
fn display_includes_the_symbol() {
assert_eq!(Seconds::new(1.5).to_string(), "1.5 s");
}
}

View File

@ -0,0 +1,60 @@
//! Tests for plane angle quantities.
use apsis_core::{Quantity, Unit};
use apsis_units::dimension::Angle;
use apsis_units::{Degrees, Radians};
use core::f64::consts::PI;
#[test]
fn direct_conversions_are_consistent() {
assert!((Degrees::new(180.0).to_radians().value() - PI).abs() < 1e-12);
assert!((Radians::new(PI).to_degrees().value() - 180.0).abs() < 1e-12);
assert!((Degrees::new(90.0).to_radians().value() - PI / 2.0).abs() < 1e-12);
}
#[test]
fn generic_conversion_matches_direct_conversion() {
let angle = Degrees::new(45.0);
let via_trait: Radians = angle.to_unit();
assert!((via_trait.value() - angle.to_radians().value()).abs() < 1e-12);
}
#[test]
fn conversion_round_trips() {
let original = Degrees::new(137.5);
let round_tripped: Degrees = original.to_unit::<Radians>().to_unit();
assert!((round_tripped.value() - original.value()).abs() < 1e-12);
}
#[test]
fn wrap_places_angles_in_the_canonical_range() {
for turns in -3..=3 {
let angle = Radians::new(PI + f64::from(turns) * 2.0 * PI);
let wrapped = angle.wrap();
assert!(wrapped.value() >= -PI);
assert!(wrapped.value() < PI);
// Wrapping shifts by whole turns, so the angle is preserved
// modulo two pi.
let difference = angle.value() - wrapped.value();
assert!((difference / (2.0 * PI)).fract().abs() < 1e-12);
}
assert!((Radians::new(0.0).wrap().value()).abs() < 1e-12);
assert!((Radians::new(PI).wrap().value() + PI).abs() < 1e-12);
}
#[test]
fn unit_metadata_is_available() {
assert_eq!(Radians::symbol(), "rad");
assert_eq!(Degrees::symbol(), "deg");
assert_eq!(Radians::factor_to_base(), 1.0);
assert!((Degrees::factor_to_base() - PI / 180.0).abs() < 1e-15);
fn assert_angle<U: Unit<Dimension = Angle>>() {}
assert_angle::<Radians>();
assert_angle::<Degrees>();
}
#[test]
fn display_includes_the_symbol() {
assert_eq!(Radians::new(1.0).to_string(), "1 rad");
assert_eq!(Degrees::new(90.0).to_string(), "90 deg");
}

View File

@ -0,0 +1,29 @@
//! Tests for frequency quantities.
use apsis_core::Unit;
use apsis_units::Hertz;
use apsis_units::dimension::Frequency;
#[test]
fn stores_the_given_value() {
assert_eq!(Hertz::new(1_575.42).value(), 1_575.42);
}
#[test]
fn period_is_the_reciprocal() {
assert!((Hertz::new(2.0).period() - 0.5).abs() < 1e-12);
assert!(Hertz::new(0.0).period().is_infinite());
}
#[test]
fn unit_metadata_is_available() {
assert_eq!(Hertz::symbol(), "Hz");
assert_eq!(Hertz::factor_to_base(), 1.0);
fn assert_frequency<U: Unit<Dimension = Frequency>>() {}
assert_frequency::<Hertz>();
}
#[test]
fn display_includes_the_symbol() {
assert_eq!(Hertz::new(1_000.0).to_string(), "1000 Hz");
}

View File

@ -0,0 +1,67 @@
//! Tests for length quantities.
use apsis_core::{Quantity, Unit};
use apsis_units::dimension::Length;
use apsis_units::{Kilometers, Meters};
#[test]
fn stores_the_given_value() {
assert_eq!(Meters::new(12.5).value(), 12.5);
assert_eq!(Kilometers::new(-3.0).value(), -3.0);
}
#[test]
fn direct_conversions_are_consistent() {
assert_eq!(Meters::new(2_500.0).to_kilometers().value(), 2.5);
assert_eq!(Kilometers::new(2.5).to_meters().value(), 2_500.0);
}
#[test]
fn generic_conversion_matches_direct_conversion() {
let distance = Meters::new(2_500.0);
let via_trait: Kilometers = distance.to_unit();
assert_eq!(via_trait, distance.to_kilometers());
}
#[test]
fn conversion_round_trips() {
let original = Kilometers::new(42.195);
let round_tripped: Kilometers = original.to_unit::<Meters>().to_unit();
assert!((round_tripped.value() - original.value()).abs() < 1e-12);
}
#[test]
fn units_report_their_metadata() {
assert_eq!(Meters::symbol(), "m");
assert_eq!(Kilometers::symbol(), "km");
assert_eq!(Meters::factor_to_base(), 1.0);
assert_eq!(Kilometers::factor_to_base(), 1_000.0);
// Both units measure the same dimension, which is what makes the
// generic conversion above type check.
fn assert_length<U: Unit<Dimension = Length>>() {}
assert_length::<Meters>();
assert_length::<Kilometers>();
}
#[test]
fn arithmetic_operates_on_the_stored_value() {
let sum = Meters::new(1.5) + Meters::new(2.5);
assert_eq!(sum.value(), 4.0);
let difference = Meters::new(4.0) - Meters::new(1.0);
assert_eq!(difference.value(), 3.0);
let scaled = Meters::new(3.0) * 2.0;
assert_eq!(scaled.value(), 6.0);
let straddled = 2.0 * Meters::new(3.0);
assert_eq!(straddled.value(), 6.0);
let halved = Meters::new(3.0) / 2.0;
assert_eq!(halved.value(), 1.5);
let ratio = Meters::new(3.0) / Meters::new(1.5);
assert_eq!(ratio, 2.0);
assert_eq!((-Meters::new(1.0)).value(), -1.0);
}
#[test]
fn display_includes_the_symbol() {
assert_eq!(Meters::new(1.0).to_string(), "1 m");
assert_eq!(Kilometers::new(2.0).to_string(), "2 km");
}

View File

@ -0,0 +1,39 @@
//! Tests for thermodynamic temperature quantities.
use apsis_core::Unit;
use apsis_core::constant::ZERO_CELSIUS_IN_KELVIN;
use apsis_units::Kelvin;
use apsis_units::dimension::Temperature;
#[test]
fn stores_the_given_value() {
assert_eq!(Kelvin::new(290.0).value(), 290.0);
}
#[test]
fn celsius_conversion_uses_the_exact_offset() {
let freezing = Kelvin::from_celsius(0.0);
assert_eq!(freezing.value(), ZERO_CELSIUS_IN_KELVIN);
assert_eq!(freezing.to_celsius(), 0.0);
let boiling = Kelvin::from_celsius(100.0);
assert!((boiling.to_celsius() - 100.0).abs() < 1e-12);
}
#[test]
fn celsius_conversion_round_trips() {
let original = Kelvin::new(273.15 + 21.5);
assert!((Kelvin::from_celsius(original.to_celsius()).value() - original.value()).abs() < 1e-12);
}
#[test]
fn unit_metadata_is_available() {
assert_eq!(Kelvin::symbol(), "K");
assert_eq!(Kelvin::factor_to_base(), 1.0);
fn assert_temperature<U: Unit<Dimension = Temperature>>() {}
assert_temperature::<Kelvin>();
}
#[test]
fn display_includes_the_symbol() {
assert_eq!(Kelvin::new(300.0).to_string(), "300 K");
}

View File

@ -0,0 +1,32 @@
//! Tests for the duration quantity.
use apsis_core::Unit;
use apsis_units::Seconds;
use apsis_units::dimension::Time;
#[test]
fn stores_the_given_value() {
assert_eq!(Seconds::new(0.5).value(), 0.5);
}
#[test]
fn unit_metadata_is_available() {
assert_eq!(Seconds::symbol(), "s");
assert_eq!(Seconds::factor_to_base(), 1.0);
fn assert_time<U: Unit<Dimension = Time>>() {}
assert_time::<Seconds>();
}
#[test]
fn arithmetic_operates_on_the_stored_value() {
assert_eq!((Seconds::new(1.0) + Seconds::new(2.0)).value(), 3.0);
assert_eq!((Seconds::new(3.0) - Seconds::new(2.0)).value(), 1.0);
assert_eq!((Seconds::new(3.0) * 2.0).value(), 6.0);
assert_eq!((Seconds::new(3.0) / 3.0).value(), 1.0);
assert_eq!(Seconds::new(6.0) / Seconds::new(3.0), 2.0);
}
#[test]
fn display_includes_the_symbol() {
assert_eq!(Seconds::new(1.5).to_string(), "1.5 s");
}