From 7058f33fa58e5e64c9f08bcc3a856a51a78e8f33 Mon Sep 17 00:00:00 2001 From: Mike Boutin Date: Sat, 16 Dec 2017 10:56:41 -0500 Subject: [PATCH] Create `Test` trait to do type specific comparisons. Handles equality and approximate equality for all underlying storage types. Tests don't need to be type specific or include approximation logic for floating point numbers. Part of #29. --- src/si/acceleration.rs | 11 +- src/si/area.rs | 10 +- src/si/force.rs | 10 +- src/si/frequency.rs | 13 +- src/si/length.rs | 4 +- src/si/velocity.rs | 10 +- src/si/volume.rs | 12 +- src/tests.rs | 569 +++++++++++++++++++++++------------------ 8 files changed, 358 insertions(+), 281 deletions(-) diff --git a/src/si/acceleration.rs b/src/si/acceleration.rs index 692d5b86..b16e39d7 100644 --- a/src/si/acceleration.rs +++ b/src/si/acceleration.rs @@ -61,13 +61,12 @@ quantity! { #[cfg(test)] mod tests { storage_types! { - types: Float; - use num::One; use si::quantities::*; use si::acceleration as a; use si::length as l; use si::time as t; + use tests::Test; #[test] fn check_dimension() { @@ -101,10 +100,10 @@ mod tests { // TODO #17 Convert to == once PartialEq is implemented. fn test, A: a::Conversion>(_l: L, a: A) { - assert_eq!(V::one(), - (Length::new::(V::one()) / - (Time::new::(V::one()) * Time::new::(V::one()))) - .get(a)); + Test::assert_eq(&V::one(), + &(Length::new::(V::one()) / + (Time::new::(V::one()) * Time::new::(V::one()))) + .get(a)); } } } diff --git a/src/si/area.rs b/src/si/area.rs index f053fe6d..8c98654b 100644 --- a/src/si/area.rs +++ b/src/si/area.rs @@ -61,13 +61,12 @@ quantity! { #[cfg(test)] mod tests { storage_types! { - types: Float; - use stdlib::any::TypeId; - use num::{Float, One}; + use num::One; use si::quantities::*; use si::area as a; use si::length as l; + use tests::Test; #[test] fn check_dimension() { @@ -108,9 +107,8 @@ mod tests { // TODO #17 Convert to == once PartialEq is implemented. fn test, A: a::Conversion>(_l: L, a: A) { - assert_ulps_eq!(V::one(), - (Length::new::(V::one()) * Length::new::(V::one())).get(a), - epsilon = V::epsilon()); + Test::assert_eq(&V::one(), + &(Length::new::(V::one()) * Length::new::(V::one())).get(a)); } } } diff --git a/src/si/force.rs b/src/si/force.rs index f902d2ed..fedb670c 100644 --- a/src/si/force.rs +++ b/src/si/force.rs @@ -41,14 +41,13 @@ quantity! { #[cfg(test)] mod tests { storage_types! { - types: Float; - - use num::{Float, One}; + use num::One; use si::quantities::*; use si::force as f; use si::length as l; use si::mass as m; use si::time as t; + use tests::Test; #[test] fn check_dimension() { @@ -121,10 +120,9 @@ mod tests { _t: T, f: F ) { - assert_ulps_eq!(V::one(), ((Mass::new::(V::one()) + Test::assert_approx_eq(&V::one(), &((Mass::new::(V::one()) * Length::new::(V::one())) - / (Time::new::(V::one()) * Time::new::(V::one()))).get(f), - epsilon = V::epsilon()); + / (Time::new::(V::one()) * Time::new::(V::one()))).get(f)); } } } diff --git a/src/si/frequency.rs b/src/si/frequency.rs index a930c479..3a8851ac 100644 --- a/src/si/frequency.rs +++ b/src/si/frequency.rs @@ -41,12 +41,11 @@ quantity! { #[cfg(test)] mod tests { storage_types! { - types: Float; - - use num::{Float, One}; + use num::One; use si::quantities::*; use si::frequency as f; use si::time as t; + use tests::Test; #[test] fn check_dimension() { @@ -80,10 +79,10 @@ mod tests { // TODO #17 Convert to == once PartialEq is implemented. fn test, F: f::Conversion>(t: T, f: F) { - assert_ulps_eq!((V::one() / Time::new::(V::one())).get(f), - Frequency::new::(V::one()).get(f), epsilon = V::epsilon()); - assert_ulps_eq!(Time::new::(V::one()).get(t), - (V::one() / Frequency::new::(V::one())).get(t), epsilon = V::epsilon()); + Test::assert_approx_eq(&(V::one() / Time::new::(V::one())).get(f), + &Frequency::new::(V::one()).get(f)); + Test::assert_approx_eq(&Time::new::(V::one()).get(t), + &(V::one() / Frequency::new::(V::one())).get(t)); } } } diff --git a/src/si/length.rs b/src/si/length.rs index db989e6b..488b28db 100644 --- a/src/si/length.rs +++ b/src/si/length.rs @@ -86,11 +86,13 @@ mod tests { use si::quantities::*; use si::length::meter; + use tests::Test; quickcheck! { #[allow(trivial_casts)] fn hypot(l: V, r: V) -> bool { - l.hypot(r) == Length::new::(l).hypot(Length::new::(r)).get(meter) + Test::eq(&l.hypot(r), + &Length::new::(l).hypot(Length::new::(r)).get(meter)) } } } diff --git a/src/si/velocity.rs b/src/si/velocity.rs index 4849a350..22e2e692 100644 --- a/src/si/velocity.rs +++ b/src/si/velocity.rs @@ -60,17 +60,17 @@ quantity! { #[cfg(test)] mod test { storage_types! { - types: Float; - use num::One; use si::quantities::*; use si::length as l; use si::time as t; use si::velocity as v; + use tests::Test; #[test] fn check_dimension() { - let _: Velocity = Length::new::(V::one()) / Time::new::(V::one()); + let _: Velocity = Length::new::(V::one()) + / Time::new::(V::one()); } #[test] @@ -99,8 +99,8 @@ mod test { // TODO #17 Convert to == once PartialEq is implemented. fn test, E: v::Conversion>(_l: L, v: E) { - assert_eq!(V::one(), - (Length::new::(V::one()) / Time::new::(V::one())).get(v)); + Test::assert_eq(&V::one(), + &(Length::new::(V::one()) / Time::new::(V::one())).get(v)); } } } diff --git a/src/si/volume.rs b/src/si/volume.rs index 86486875..e414d444 100644 --- a/src/si/volume.rs +++ b/src/si/volume.rs @@ -60,14 +60,13 @@ quantity! { #[cfg(test)] mod tests { storage_types! { - types: Float; - use stdlib::any::TypeId; - use num::{Float, One}; + use num::One; use si::quantities::*; use si::area as a; use si::volume as v; use si::length as l; + use tests::Test; #[test] fn check_dimension() { @@ -112,11 +111,10 @@ mod tests { // TODO #17 Convert to == once PartialEq is implemented. fn test, O: v::Conversion>(_l: L, v: O) { - assert_ulps_eq!(V::one(), - (Length::new::(V::one()) + Test::assert_eq(&V::one(), + &(Length::new::(V::one()) * Length::new::(V::one()) - * Length::new::(V::one())).get(v), - epsilon = V::epsilon()); + * Length::new::(V::one())).get(v)); } } } diff --git a/src/tests.rs b/src/tests.rs index 4eda9799..c6fbf93a 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,7 +1,9 @@ +use stdlib::fmt::Debug; use stdlib::marker::PhantomData; #[allow(unused_imports)] use num::{Float, FromPrimitive, One, Signed, Zero}; use quickcheck::TestResult; +#[allow(unused_imports)] use typenum::{N1, P1, P2, P3, Z0}; #[allow(unused_imports)] use {Conversion, ConversionFactor}; @@ -46,6 +48,62 @@ mod quantities { Q!(tests); } +/// Test trait to allow tests to perform storage-type sensitive comparisons. +pub trait Test + : Debug + + Sized + + PartialEq +{ + /// Assert that `lhs` and `rhs` are exactly equal. + fn assert_eq(lhs: &Self, rhs: &Self) { + assert_eq!(lhs, rhs); + } + + /// Assert that `lhs` and `rhs` are approximately equal for floating point types or exactly + /// equal for other types. + fn assert_approx_eq(lhs: &Self, rhs: &Self) { + Test::assert_eq(lhs, rhs); + } + + /// Exactly compare `lhs` and `rhs` and return the result. + fn eq(lhs: &Self, rhs: &Self) -> bool { + lhs == rhs + } + + /// Approximately compare `lhs` and `rhs` for floating point types or exactly compare for other + /// types and return the result. + fn approx_eq(lhs: &Self, rhs: &Self) -> bool { + Test::eq(lhs, rhs) + } +} + +mod test_trait { + storage_types! { + types: Float; + + use num::Float; + + // const EPSILON: V = 64.0 * V::epsilon(); //error[E0015]; calls in constants are limited... + const ULPS: u32 = 16; + + impl super::super::Test for V { + fn assert_approx_eq(lhs: &Self, rhs: &Self) { + assert_ulps_eq!(lhs, rhs, epsilon = 64.0 * V::epsilon(), max_ulps = ULPS); + } + + fn approx_eq(lhs: &Self, rhs: &Self) -> bool { + ulps_eq!(lhs, rhs, epsilon = 64.0 * V::epsilon(), max_ulps = ULPS) + } + } + } + + storage_types! { + types: PrimInt, BigInt, BigUint, Ratio; + + impl super::super::Test for V {} + } +} + mod quantity_macro { use tests::*; @@ -87,8 +145,6 @@ mod quantity_macro { } storage_types! { - types: Float; - use tests::*; Q!(tests, V); @@ -98,8 +154,8 @@ mod quantity_macro { let l = Length { dimension: PhantomData, units: PhantomData, value: V::one(), }; let m = Mass { dimension: PhantomData, units: PhantomData, value: V::one(), }; - assert_eq!(V::one(), l.value); - assert_eq!(V::one(), m.value); + Test::assert_eq(&V::one(), &l.value); + Test::assert_eq(&V::one(), &m.value); } #[test] @@ -108,9 +164,9 @@ mod quantity_macro { let l2 = Length::new::(V::one()); let m1 = Mass::new::(V::one()); - assert_eq!(1000.0, l1.value); - assert_eq!(V::one(), l2.value); - assert_eq!(V::one(), m1.value); + Test::assert_eq(&V::from_f64(1000.0).unwrap(), &l1.value); + Test::assert_eq(&V::one(), &l2.value); + Test::assert_eq(&V::one(), &m1.value); } #[test] @@ -119,18 +175,19 @@ mod quantity_macro { let l2 = Length::new::(V::one()); let m1 = Mass::new::(V::one()); - assert_eq!(1000.0, l1.get(meter)); - assert_eq!(V::one(), l2.get(meter)); - assert_eq!(V::one(), l1.get(kilometer)); - assert_eq!(0.001, l2.get(kilometer)); - assert_eq!(V::one(), m1.get(kilogram)); + Test::assert_eq(&V::from_f64(1000.0).unwrap(), &l1.get(meter)); + Test::assert_eq(&V::one(), &l2.get(meter)); + Test::assert_eq(&V::one(), &l1.get(kilometer)); + Test::assert_eq(&V::from_f64(0.001).unwrap(), &l2.get(kilometer)); + Test::assert_eq(&V::one(), &m1.get(kilogram)); } #[test] fn conversion() { - assert_eq!(1000.0, >::conversion()); - assert_eq!(V::one(), >::conversion()); - assert_eq!(V::one(), >::conversion()); + Test::assert_eq(&V::from_f64(1000.0).unwrap(), + &>::conversion().value()); + Test::assert_eq(&V::one(), &>::conversion().value()); + Test::assert_eq(&V::one(), &>::conversion().value()); } #[cfg(feature = "std")] @@ -146,8 +203,8 @@ mod quantity_macro { format!("{:.2?} m^1", V::one()), format!("{:.2?}", Length::new::(V::one()))); assert_eq!( - format!("{:?} m^1 kg^1", 1.23), - format!("{:?}", Length::new::(1.23) * Mass::new::(V::one()))); + format!("{:?} m^1 kg^1", V::from_f64(1.23).unwrap()), + format!("{:?}", Length::new::(V::from_f64(1.23).unwrap()) * Mass::new::(V::one()))); } } @@ -157,8 +214,6 @@ mod quantity_macro { use tests::*; - const EPSILON: V = 0.00001; - Q!(tests, V); #[test] @@ -170,16 +225,16 @@ mod quantity_macro { let m1 = Mass::new::(3.9999); let m2 = Mass::new::(3.0001); - assert_eq!(3.0, l1.floor(kilometer).get(kilometer)); - assert_eq!(3999.0, l1.floor(meter).get(meter)); - assert_eq!(3.0, l2.floor(kilometer).get(kilometer)); - assert_eq!(3000.0, l2.floor(meter).get(meter)); - assert_eq!(0.0, l3.floor(kilometer).get(kilometer)); - assert_eq!(3.0, l3.floor(meter).get(meter)); - assert_eq!(0.0, l4.floor(kilometer).get(kilometer)); - assert_eq!(3.0, l4.floor(meter).get(meter)); - assert_eq!(3.0, m1.floor(kilogram).get(kilogram)); - assert_eq!(3.0, m2.floor(kilogram).get(kilogram)); + Test::assert_eq(&3.0, &l1.floor(kilometer).get(kilometer)); + Test::assert_eq(&3999.0, &l1.floor(meter).get(meter)); + Test::assert_eq(&3.0, &l2.floor(kilometer).get(kilometer)); + Test::assert_eq(&3000.0, &l2.floor(meter).get(meter)); + Test::assert_eq(&0.0, &l3.floor(kilometer).get(kilometer)); + Test::assert_eq(&3.0, &l3.floor(meter).get(meter)); + Test::assert_eq(&0.0, &l4.floor(kilometer).get(kilometer)); + Test::assert_eq(&3.0, &l4.floor(meter).get(meter)); + Test::assert_eq(&3.0, &m1.floor(kilogram).get(kilogram)); + Test::assert_eq(&3.0, &m2.floor(kilogram).get(kilogram)); } #[test] @@ -191,16 +246,16 @@ mod quantity_macro { let m1 = Mass::new::(3.9999); let m2 = Mass::new::(3.0001); - assert_eq!(4.0, l1.ceil(kilometer).get(kilometer)); - assert_eq!(4000.0, l1.ceil(meter).get(meter)); - assert_eq!(4.0, l2.ceil(kilometer).get(kilometer)); - assert_eq!(3001.0, l2.ceil(meter).get(meter)); - assert_eq!(V::one(), l3.ceil(kilometer).get(kilometer)); - assert_eq!(4.0, l3.ceil(meter).get(meter)); - assert_eq!(1.0, l4.ceil(kilometer).get(kilometer)); - assert_eq!(4.0, l4.ceil(meter).get(meter)); - assert_eq!(4.0, m1.ceil(kilogram).get(kilogram)); - assert_eq!(4.0, m2.ceil(kilogram).get(kilogram)); + Test::assert_eq(&4.0, &l1.ceil(kilometer).get(kilometer)); + Test::assert_eq(&4000.0, &l1.ceil(meter).get(meter)); + Test::assert_eq(&4.0, &l2.ceil(kilometer).get(kilometer)); + Test::assert_eq(&3001.0, &l2.ceil(meter).get(meter)); + Test::assert_eq(&1.0, &l3.ceil(kilometer).get(kilometer)); + Test::assert_eq(&4.0, &l3.ceil(meter).get(meter)); + Test::assert_eq(&1.0, &l4.ceil(kilometer).get(kilometer)); + Test::assert_eq(&4.0, &l4.ceil(meter).get(meter)); + Test::assert_eq(&4.0, &m1.ceil(kilogram).get(kilogram)); + Test::assert_eq(&4.0, &m2.ceil(kilogram).get(kilogram)); } #[test] @@ -212,16 +267,16 @@ mod quantity_macro { let m1 = Mass::new::(3.3); let m2 = Mass::new::(3.5); - assert_eq!(3.0, l1.round(kilometer).get(kilometer)); - assert_eq!(3300.0, l1.round(meter).get(meter)); - assert_eq!(4.0, l2.round(kilometer).get(kilometer)); - assert_eq!(3500.0, l2.round(meter).get(meter)); - assert_eq!(0.0, l3.round(kilometer).get(kilometer)); - assert_eq!(3.0, l3.round(meter).get(meter)); - assert_eq!(0.0, l4.round(kilometer).get(kilometer)); - assert_eq!(4.0, l4.round(meter).get(meter)); - assert_eq!(3.0, m1.round(kilogram).get(kilogram)); - assert_eq!(4.0, m2.round(kilogram).get(kilogram)); + Test::assert_eq(&3.0, &l1.round(kilometer).get(kilometer)); + Test::assert_eq(&3300.0, &l1.round(meter).get(meter)); + Test::assert_eq(&4.0, &l2.round(kilometer).get(kilometer)); + Test::assert_eq(&3500.0, &l2.round(meter).get(meter)); + Test::assert_eq(&0.0, &l3.round(kilometer).get(kilometer)); + Test::assert_eq(&3.0, &l3.round(meter).get(meter)); + Test::assert_eq(&0.0, &l4.round(kilometer).get(kilometer)); + Test::assert_eq(&4.0, &l4.round(meter).get(meter)); + Test::assert_eq(&3.0, &m1.round(kilogram).get(kilogram)); + Test::assert_eq(&4.0, &m2.round(kilogram).get(kilogram)); } #[test] @@ -233,37 +288,35 @@ mod quantity_macro { let m1 = Mass::new::(3.3); let m2 = Mass::new::(3.5); - assert_eq!(3.0, l1.trunc(kilometer).get(kilometer)); - assert_eq!(3300.0, l1.trunc(meter).get(meter)); - assert_eq!(3.0, l2.trunc(kilometer).get(kilometer)); - assert_eq!(3500.0, l2.trunc(meter).get(meter)); - assert_eq!(0.0, l3.trunc(kilometer).get(kilometer)); - assert_eq!(3.0, l3.trunc(meter).get(meter)); - assert_eq!(0.0, l4.trunc(kilometer).get(kilometer)); - assert_eq!(3.0, l4.trunc(meter).get(meter)); - assert_eq!(3.0, m1.trunc(kilogram).get(kilogram)); - assert_eq!(3.0, m2.trunc(kilogram).get(kilogram)); + Test::assert_eq(&3.0, &l1.trunc(kilometer).get(kilometer)); + Test::assert_eq(&3300.0, &l1.trunc(meter).get(meter)); + Test::assert_eq(&3.0, &l2.trunc(kilometer).get(kilometer)); + Test::assert_eq(&3500.0, &l2.trunc(meter).get(meter)); + Test::assert_eq(&0.0, &l3.trunc(kilometer).get(kilometer)); + Test::assert_eq(&3.0, &l3.trunc(meter).get(meter)); + Test::assert_eq(&0.0, &l4.trunc(kilometer).get(kilometer)); + Test::assert_eq(&3.0, &l4.trunc(meter).get(meter)); + Test::assert_eq(&3.0, &m1.trunc(kilogram).get(kilogram)); + Test::assert_eq(&3.0, &m2.trunc(kilogram).get(kilogram)); } #[test] fn fract() { let l1 = Length::new::(3.3); - let l2 = Length::new::(3.5); - let l3 = Length::new::(3.3); - let l4 = Length::new::(3.5); + let l2 = Length::new::(3.3); let m1 = Mass::new::(3.3); - let m2 = Mass::new::(3.5); - assert_ulps_eq!(0.3, l1.fract(kilometer).get(kilometer), epsilon = EPSILON); - assert_ulps_eq!(0.0, l1.fract(meter).get(meter), epsilon = EPSILON); - assert_ulps_eq!(0.5, l2.fract(kilometer).get(kilometer), epsilon = EPSILON); - assert_ulps_eq!(0.0, l2.fract(meter).get(meter), epsilon = EPSILON); - assert_ulps_eq!(0.0033, l3.fract(kilometer).get(kilometer), epsilon = EPSILON); - assert_ulps_eq!(0.3, l3.fract(meter).get(meter), epsilon = EPSILON); - assert_ulps_eq!(0.0035, l4.fract(kilometer).get(kilometer), epsilon = EPSILON); - assert_ulps_eq!(0.5, l4.fract(meter).get(meter), epsilon = EPSILON); - assert_ulps_eq!(0.3, m1.fract(kilogram).get(kilogram), epsilon = EPSILON); - assert_ulps_eq!(0.5, m2.fract(kilogram).get(kilogram), epsilon = EPSILON); + Test::assert_eq(&3.3.fract(), &l1.fract(kilometer).get(kilometer)); + Test::assert_eq(&(3.3.fract() * 1000.0), &l1.fract(kilometer).get(meter)); + Test::assert_eq(&((3.3 * 1000.0).fract() / 1000.0), &l1.fract(meter).get(kilometer)); + Test::assert_eq(&(3.3 * 1000.0).fract(), &l1.fract(meter).get(meter)); + + Test::assert_eq(&(3.3 / 1000.0).fract(), &l2.fract(kilometer).get(kilometer)); + Test::assert_eq(&((3.3 / 1000.0).fract() * 1000.0), &l2.fract(kilometer).get(meter)); + Test::assert_eq(&(3.3.fract() / 1000.0), &l2.fract(meter).get(kilometer)); + Test::assert_eq(&3.3.fract(), &l2.fract(meter).get(meter)); + + Test::assert_eq(&3.3.fract(), &m1.fract(kilogram).get(kilogram)); } } } @@ -271,11 +324,10 @@ mod quantity_macro { mod system_macro { storage_types! { - types: Float; - use tests::*; - const EPSILON: V = 0.00001; + type MeterKilogram = Units; + type KilometerKilogram = Units; Q!(tests, V); @@ -283,113 +335,126 @@ mod system_macro { #[allow(trivial_casts)] fn from_base(v: V) -> bool { - type MeterKilogram = Units; - type KilometerKilogram = Units; + let km: V = >::conversion().value(); // meter -> meter. - ulps_eq!(v, - ::tests::from_base::(&v), - epsilon = EPSILON) + Test::approx_eq(&v, + &::tests::from_base::(&v)) // kilometer -> kilometer. - && ulps_eq!(v, - ::tests::from_base::(&v), - epsilon = EPSILON) + && Test::approx_eq(&v, + &::tests::from_base::(&v)) // meter -> kilometer. - && ulps_eq!(v / >::conversion().value(), - ::tests::from_base::(&v), - epsilon = EPSILON) + && Test::approx_eq(&(&v / &km), + &::tests::from_base::(&v)) // kilometer -> meter. - && ulps_eq!(v * >::conversion().value(), - ::tests::from_base::(&v), - epsilon = EPSILON) + && Test::approx_eq(&(&v * &km), + &::tests::from_base::(&v)) } #[allow(trivial_casts)] fn to_base(v: V) -> bool { - type MeterKilogram = Units; - type KilometerKilogram = Units; + let km: V = >::conversion().value(); // meter -> meter. - ulps_eq!(v, - ::tests::to_base::(&v), - epsilon = EPSILON) + Test::approx_eq(&v, + &::tests::to_base::(&v)) // kilometer -> kilometer. - && ulps_eq!(v, - ::tests::to_base::(&v), - epsilon = EPSILON) + && Test::approx_eq(&v, + &::tests::to_base::(&v)) // kilometer -> meter. - && ulps_eq!(v * >::conversion().value(), - ::tests::to_base::(&v), - epsilon = EPSILON) + && Test::approx_eq(&(&v * &km), + &::tests::to_base::(&v)) // meter -> kilometer. - && ulps_eq!(v / >::conversion().value(), - ::tests::to_base::(&v), - epsilon = EPSILON) + && Test::approx_eq(&(&v / &km), + &::tests::to_base::(&v)) } #[allow(trivial_casts)] fn change_base(v: V) -> bool { - type MeterKilogram = Units; - type KilometerKilogram = Units; + let km: V = >::conversion().value(); // meter -> meter. - ulps_eq!(v, - ::tests::change_base::(&v), - epsilon = EPSILON) + Test::approx_eq(&v, + &::tests::change_base::(&v)) // kilometer -> kilometer. - && ulps_eq!(v, - ::tests::change_base::(&v), - epsilon = EPSILON) + && Test::approx_eq(&v, + &::tests::change_base::(&v)) // kilometer -> meter. - && ulps_eq!(v * >::conversion().value(), - ::tests::change_base::(&v), - epsilon = EPSILON) + && Test::approx_eq(&(&v * &km), + &::tests::change_base::(&v)) // meter -> kilometer. - && ulps_eq!(v / >::conversion().value(), - ::tests::change_base::(&v), - epsilon = EPSILON) + && Test::approx_eq(&(&v / &km), + &::tests::change_base::(&v)) } #[allow(trivial_casts)] fn add(l: V, r: V) -> bool { - (l + r) == (Length::new::(l) + Length::new::(r)).get(meter) + Test::eq(&(&l + &r), + &(Length::new::((l).clone()) + + Length::new::((r).clone())).get(meter)) } #[allow(trivial_casts)] fn sub(l: V, r: V) -> bool { - (l - r) == (Length::new::(l) - Length::new::(r)).get(meter) + Test::eq(&(&l - &r), + &(Length::new::((l).clone()) + - Length::new::((r).clone())).get(meter)) } #[allow(trivial_casts)] fn mul_quantity(l: V, r: V) -> bool { // TODO Use `.get(square_meter)` - (l * r) == (Length::new::(l) * Length::new::(r)).value + Test::eq(&(&l * &r), + &(Length::new::((l).clone()) + * Length::new::((r).clone())).value) } #[allow(trivial_casts)] fn mul_v(l: V, r: V) -> bool { - (l * r) == (Length::new::(l) * r).get(meter) - //&& (l * r) == (l * Length::new::(r)).get(meter) + Test::eq(&(&l * &r), + &(Length::new::((l).clone()) * (r).clone()).get(meter)) + && Test::eq(&(&l * &r), + &((l).clone() * Length::new::((r).clone())).get(meter)) } #[allow(trivial_casts)] - fn div_quantity(l: V, r: V) -> bool { + fn div_quantity(l: V, r: V) -> TestResult { + if r == V::zero() { + return TestResult::discard(); + } + // TODO Use `.get(?)` - (l / r) == (Length::new::(l) / Length::new::(r)).value + TestResult::from_bool( + Test::eq(&(&l / &r), + &(Length::new::((l).clone()) / Length::new::((r).clone())).value)) } #[allow(trivial_casts)] - fn div_v(l: V, r: V) -> bool { + fn div_v(l: V, r: V) -> TestResult { + if r == V::zero() { + return TestResult::discard(); + } + // TODO Use `get(meter^-1)` - (l / r) == (Length::new::(l) / r).get(meter) - //&& (l / r) == (l / Length::new::(r)).value + TestResult::from_bool( + Test::eq(&(&l / &r), + &(Length::new::((l).clone()) / (r).clone()).get(meter)) + && Test::eq(&(&l / &r), + &((l).clone() / Length::new::((r).clone())).value)) } #[allow(trivial_casts)] - fn rem(l: V, r: V) -> bool { - (l % r) == (Length::new::(l) % Length::new::(r)).get(meter) + fn rem(l: V, r: V) -> TestResult { + if r == V::zero() { + return TestResult::discard(); + } + + TestResult::from_bool( + Test::approx_eq(&(&l % &r), + &(Length::new::((l).clone()) + % Length::new::((r).clone())).get(meter))) } } } @@ -449,7 +514,7 @@ mod system_macro { value: v, }.cbrt(); - v.cbrt() == l.value + Test::eq(&v.cbrt(), &l.value) } #[allow(trivial_casts)] @@ -472,7 +537,7 @@ mod system_macro { value: b }); - s.mul_add(a, b) == r.value + Test::eq(&s.mul_add(a, b), &r.value) } #[allow(trivial_casts)] @@ -483,17 +548,17 @@ mod system_macro { value: v, }.recip(); - v.recip() == a.value + Test::eq(&v.recip(), &a.value) } #[allow(trivial_casts)] fn powi(v: V) -> bool { - v.powi(3) == Length::new::(v).powi(P3::new()).value + Test::eq(&v.powi(3), &Length::new::(v).powi(P3::new()).value) } #[allow(trivial_casts)] fn sqrt(v: V) -> TestResult { - if v < 0.0 { + if v < V::zero() { return TestResult::discard(); } @@ -503,17 +568,19 @@ mod system_macro { value: v, }.sqrt(); - TestResult::from_bool(v.sqrt() == l.value) + TestResult::from_bool(Test::eq(&v.sqrt(), &l.value)) } #[allow(trivial_casts)] fn max(l: V, r: V) -> bool { - l.max(r) == Length::new::(l).max(Length::new::(r)).get(meter) + Test::eq(&l.max(r), + &Length::new::(l).max(Length::new::(r)).get(meter)) } #[allow(trivial_casts)] fn min(l: V, r: V) -> bool { - l.min(r) == Length::new::(l).min(Length::new::(r)).get(meter) + Test::eq(&l.min(r), + &Length::new::(l).min(Length::new::(r)).get(meter)) } } } @@ -521,7 +588,7 @@ mod system_macro { mod signed { storage_types! { - types: Float; + types: Signed; use tests::*; @@ -530,17 +597,17 @@ mod system_macro { quickcheck! { #[allow(trivial_casts)] fn abs(v: V) -> bool { - v.abs() == Length::new::(v).abs().get(meter) + Test::eq(&v.abs(), &Length::new::((v).clone()).abs().get(meter)) } #[allow(trivial_casts)] fn signum(v: V) -> bool { - v.signum() == Length::new::(v).signum().get(meter) + Test::eq(&v.signum(), &Length::new::((v).clone()).signum().get(meter)) } #[allow(trivial_casts)] fn neg(l: V) -> bool { - -l == -Length::new::(l).get(meter) + Test::eq(&-(l).clone(), &-Length::new::((l).clone()).get(meter)) } } } @@ -563,7 +630,7 @@ mod system_macro { f += r; v += Length::new::(r); - f == v.get(meter) + Test::eq(&f, &v.get(meter)) } #[allow(trivial_casts)] @@ -574,7 +641,7 @@ mod system_macro { f -= r; v -= Length::new::(r); - f == v.get(meter) + Test::eq(&f, &v.get(meter)) } #[allow(trivial_casts)] @@ -585,29 +652,37 @@ mod system_macro { f *= r; v *= r; - f == v.get(meter) + Test::eq(&f, &v.get(meter)) } #[allow(trivial_casts)] - fn div_assign(l: V, r: V) -> bool { + fn div_assign(l: V, r: V) -> TestResult { + if r == V::zero() { + return TestResult::discard(); + } + let mut f = l; let mut v = Length::new::(l); f /= r; v /= r; - f == v.get(meter) + TestResult::from_bool(Test::eq(&f, &v.get(meter))) } #[allow(trivial_casts)] - fn rem_assign(l: V, r: V) -> bool { + fn rem_assign(l: V, r: V) -> TestResult { + if r == V::zero() { + return TestResult::discard(); + } + let mut f = l; let mut v = Length::new::(l); f %= r; v %= Length::new::(r); - f == v.get(meter) + TestResult::from_bool(Test::approx_eq(&f, &v.get(meter))) } } } @@ -617,12 +692,10 @@ mod system_macro { mod quantities_macro { mod fractional { storage_types! { - types: Float; + types: Float, Ratio; use tests::*; - const EPSILON: V = 0.00001; - mod f { Q!(tests, super::V); } mod k { Q!(tests, super::V, (kilometer, kilogram)); } @@ -632,9 +705,9 @@ mod quantities_macro { let l2 = k::Length::new::(V::one()); let m1 = k::Mass::new::(V::one()); - assert_eq!(V::one(), l1.value); - assert_eq!(1.0_E-3, l2.value); - assert_eq!(V::one(), m1.value); + Test::assert_eq(&V::one(), &l1.value); + Test::assert_eq(&V::from_f64(1.0_E-3).unwrap(), &l2.value); + Test::assert_eq(&V::one(), &m1.value); } #[test] @@ -643,55 +716,65 @@ mod quantities_macro { let l2 = k::Length::new::(V::one()); let m1 = k::Mass::new::(V::one()); - assert_ulps_eq!(1000.0, l1.get(meter)); - assert_ulps_eq!(V::one(), l2.get(meter)); - assert_ulps_eq!(V::one(), l1.get(kilometer)); - assert_ulps_eq!(0.001, l2.get(kilometer)); - assert_ulps_eq!(V::one(), m1.get(kilogram)); + Test::assert_eq(&V::from_f64(1000.0).unwrap(), &l1.get(meter)); + Test::assert_eq(&V::one(), &l2.get(meter)); + Test::assert_eq(&V::one(), &l1.get(kilometer)); + Test::assert_eq(&V::from_f64(0.001).unwrap(), &l2.get(kilometer)); + Test::assert_eq(&V::one(), &m1.get(kilogram)); } quickcheck! { #[allow(trivial_casts)] fn add(l: V, r: V) -> bool { - ulps_eq!(l + r, - (k::Length::new::(l) + f::Length::new::(r)).get(meter), - epsilon = EPSILON) + Test::approx_eq(&(&l + &r), + &(k::Length::new::((l).clone()) + + f::Length::new::((r).clone())).get(meter)) } #[allow(trivial_casts)] fn sub(l: V, r: V) -> bool { - ulps_eq!((l - r), - (k::Length::new::(l) - f::Length::new::(r)).get(meter), - epsilon = EPSILON) + Test::approx_eq(&(&l - &r), + &(k::Length::new::((l).clone()) + - f::Length::new::((r).clone())).get(meter)) } #[allow(trivial_casts)] fn mul_quantity(l: V, r: V) -> bool { // TODO Use `.get(square_meter)` - ulps_eq!(l * r, - (f::Length::new::(l) * k::Length::new::(r)).value, - epsilon = EPSILON) - && ulps_eq!(l * r, - (f::Length::new::(l) * k::Mass::new::(r)).value, - epsilon = EPSILON) - && ulps_eq!(l * r, - (k::Length::new::(l) * f::Mass::new::(r)).value, - epsilon = EPSILON) + Test::approx_eq(&(&l * &r), + &(f::Length::new::((l).clone()) + * k::Length::new::((r).clone())).value) + && Test::approx_eq(&(&l * &r), + &(f::Length::new::((l).clone()) + * k::Mass::new::((r).clone())).value) + && Test::approx_eq(&(&l * &r), + &(k::Length::new::((l).clone()) + * f::Mass::new::((r).clone())).value) } #[allow(trivial_casts)] - fn div_quantity(l: V, r: V) -> bool { + fn div_quantity(l: V, r: V) -> TestResult { + if r == V::zero() { + return TestResult::discard(); + } + // TODO Use `.get(?)` - ulps_eq!(l / r, - (k::Length::new::(l) / f::Length::new::(r)).value, - epsilon = EPSILON) + TestResult::from_bool( + Test::approx_eq(&(&l / &r), + &(k::Length::new::((l).clone()) + / f::Length::new::((r).clone())).value)) } #[allow(trivial_casts)] - fn rem(l: V, r: V) -> bool { - ulps_eq!(l % r, - (k::Length::new::(l) % f::Length::new::(r)).get(meter), - epsilon = EPSILON) + fn rem(l: V, r: V) -> TestResult { + if r == V::zero() { + return TestResult::discard(); + } + + TestResult::from_bool( + Test::approx_eq(&(&l % &r), + &(k::Length::new::((l).clone()) + % f::Length::new::((r).clone())).get(meter))) } } } @@ -703,8 +786,6 @@ mod quantities_macro { use tests::*; - const EPSILON: V = 0.00001; - mod f { Q!(tests, super::V); } mod k { Q!(tests, super::V, (kilometer, kilogram)); } @@ -717,7 +798,7 @@ mod quantities_macro { f += r; v += f::Length::new::(r); - ulps_eq!(f, v.get(meter), epsilon = EPSILON) + Test::approx_eq(&f, &v.get(meter)) } #[allow(trivial_casts)] @@ -728,18 +809,22 @@ mod quantities_macro { f -= r; v -= f::Length::new::(r); - ulps_eq!(f, v.get(meter), epsilon = EPSILON) + Test::approx_eq(&f, &v.get(meter)) } #[allow(trivial_casts)] - fn rem_assign(l: V, r: V) -> bool { + fn rem_assign(l: V, r: V) -> TestResult { + if r == V::zero() { + return TestResult::discard(); + } + let mut f = l; let mut v = k::Length::new::(l); f %= r; v %= f::Length::new::(r); - ulps_eq!(f, v.get(meter), epsilon = EPSILON) + TestResult::from_bool(Test::approx_eq(&f, &v.get(meter))) } } @@ -752,16 +837,16 @@ mod quantities_macro { let m1 = k::Mass::new::(3.9999); let m2 = k::Mass::new::(3.0001); - assert_eq!(3.0, l1.floor(kilometer).get(kilometer)); - assert_eq!(3999.0, l1.floor(meter).get(meter)); - assert_eq!(3.0, l2.floor(kilometer).get(kilometer)); - assert_eq!(3000.0, l2.floor(meter).get(meter)); - assert_eq!(0.0, l3.floor(kilometer).get(kilometer)); - assert_eq!(3.0, l3.floor(meter).get(meter)); - assert_eq!(0.0, l4.floor(kilometer).get(kilometer)); - assert_eq!(3.0, l4.floor(meter).get(meter)); - assert_eq!(3.0, m1.floor(kilogram).get(kilogram)); - assert_eq!(3.0, m2.floor(kilogram).get(kilogram)); + Test::assert_eq(&3.0, &l1.floor(kilometer).get(kilometer)); + Test::assert_eq(&3999.0, &l1.floor(meter).get(meter)); + Test::assert_eq(&3.0, &l2.floor(kilometer).get(kilometer)); + Test::assert_eq(&3000.0, &l2.floor(meter).get(meter)); + Test::assert_eq(&0.0, &l3.floor(kilometer).get(kilometer)); + Test::assert_eq(&3.0, &l3.floor(meter).get(meter)); + Test::assert_eq(&0.0, &l4.floor(kilometer).get(kilometer)); + Test::assert_eq(&3.0, &l4.floor(meter).get(meter)); + Test::assert_eq(&3.0, &m1.floor(kilogram).get(kilogram)); + Test::assert_eq(&3.0, &m2.floor(kilogram).get(kilogram)); } #[test] @@ -773,16 +858,16 @@ mod quantities_macro { let m1 = k::Mass::new::(3.9999); let m2 = k::Mass::new::(3.0001); - assert_eq!(4.0, l1.ceil(kilometer).get(kilometer)); - assert_eq!(4000.0, l1.ceil(meter).get(meter)); - assert_eq!(4.0, l2.ceil(kilometer).get(kilometer)); - assert_eq!(3001.0, l2.ceil(meter).get(meter)); - assert_eq!(V::one(), l3.ceil(kilometer).get(kilometer)); - assert_eq!(4.0, l3.ceil(meter).get(meter)); - assert_eq!(V::one(), l4.ceil(kilometer).get(kilometer)); - assert_eq!(4.0, l4.ceil(meter).get(meter)); - assert_eq!(4.0, m1.ceil(kilogram).get(kilogram)); - assert_eq!(4.0, m2.ceil(kilogram).get(kilogram)); + Test::assert_eq(&4.0, &l1.ceil(kilometer).get(kilometer)); + Test::assert_eq(&4000.0, &l1.ceil(meter).get(meter)); + Test::assert_eq(&4.0, &l2.ceil(kilometer).get(kilometer)); + Test::assert_eq(&3001.0, &l2.ceil(meter).get(meter)); + Test::assert_eq(&1.0, &l3.ceil(kilometer).get(kilometer)); + Test::assert_eq(&4.0, &l3.ceil(meter).get(meter)); + Test::assert_eq(&1.0, &l4.ceil(kilometer).get(kilometer)); + Test::assert_eq(&4.0, &l4.ceil(meter).get(meter)); + Test::assert_eq(&4.0, &m1.ceil(kilogram).get(kilogram)); + Test::assert_eq(&4.0, &m2.ceil(kilogram).get(kilogram)); } #[test] @@ -794,16 +879,16 @@ mod quantities_macro { let m1 = k::Mass::new::(3.3); let m2 = k::Mass::new::(3.5); - assert_eq!(3.0, l1.round(kilometer).get(kilometer)); - assert_eq!(3300.0, l1.round(meter).get(meter)); - assert_eq!(4.0, l2.round(kilometer).get(kilometer)); - assert_eq!(3500.0, l2.round(meter).get(meter)); - assert_eq!(0.0, l3.round(kilometer).get(kilometer)); - assert_eq!(3.0, l3.round(meter).get(meter)); - assert_eq!(0.0, l4.round(kilometer).get(kilometer)); - assert_eq!(4.0, l4.round(meter).get(meter)); - assert_eq!(3.0, m1.round(kilogram).get(kilogram)); - assert_eq!(4.0, m2.round(kilogram).get(kilogram)); + Test::assert_eq(&3.0, &l1.round(kilometer).get(kilometer)); + Test::assert_eq(&3300.0, &l1.round(meter).get(meter)); + Test::assert_eq(&4.0, &l2.round(kilometer).get(kilometer)); + Test::assert_eq(&3500.0, &l2.round(meter).get(meter)); + Test::assert_eq(&0.0, &l3.round(kilometer).get(kilometer)); + Test::assert_eq(&3.0, &l3.round(meter).get(meter)); + Test::assert_eq(&0.0, &l4.round(kilometer).get(kilometer)); + Test::assert_eq(&4.0, &l4.round(meter).get(meter)); + Test::assert_eq(&3.0, &m1.round(kilogram).get(kilogram)); + Test::assert_eq(&4.0, &m2.round(kilogram).get(kilogram)); } #[test] @@ -815,37 +900,35 @@ mod quantities_macro { let m1 = k::Mass::new::(3.3); let m2 = k::Mass::new::(3.5); - assert_eq!(3.0, l1.trunc(kilometer).get(kilometer)); - assert_eq!(3300.0, l1.trunc(meter).get(meter)); - assert_eq!(3.0, l2.trunc(kilometer).get(kilometer)); - assert_eq!(3500.0, l2.trunc(meter).get(meter)); - assert_eq!(0.0, l3.trunc(kilometer).get(kilometer)); - assert_eq!(3.0, l3.trunc(meter).get(meter)); - assert_eq!(0.0, l4.trunc(kilometer).get(kilometer)); - assert_eq!(3.0, l4.trunc(meter).get(meter)); - assert_eq!(3.0, m1.trunc(kilogram).get(kilogram)); - assert_eq!(3.0, m2.trunc(kilogram).get(kilogram)); + Test::assert_eq(&3.0, &l1.trunc(kilometer).get(kilometer)); + Test::assert_eq(&3300.0, &l1.trunc(meter).get(meter)); + Test::assert_eq(&3.0, &l2.trunc(kilometer).get(kilometer)); + Test::assert_eq(&3500.0, &l2.trunc(meter).get(meter)); + Test::assert_eq(&0.0, &l3.trunc(kilometer).get(kilometer)); + Test::assert_eq(&3.0, &l3.trunc(meter).get(meter)); + Test::assert_eq(&0.0, &l4.trunc(kilometer).get(kilometer)); + Test::assert_eq(&3.0, &l4.trunc(meter).get(meter)); + Test::assert_eq(&3.0, &m1.trunc(kilogram).get(kilogram)); + Test::assert_eq(&3.0, &m2.trunc(kilogram).get(kilogram)); } #[test] fn fract() { let l1 = k::Length::new::(3.3); - let l2 = k::Length::new::(3.5); - let l3 = k::Length::new::(3.3); - let l4 = k::Length::new::(3.5); + let l2 = k::Length::new::(3.3); let m1 = k::Mass::new::(3.3); - let m2 = k::Mass::new::(3.5); - assert_ulps_eq!(0.3, l1.fract(kilometer).get(kilometer), epsilon = EPSILON); - assert_ulps_eq!(0.0, l1.fract(meter).get(meter), epsilon = EPSILON); - assert_ulps_eq!(0.5, l2.fract(kilometer).get(kilometer), epsilon = EPSILON); - assert_ulps_eq!(0.0, l2.fract(meter).get(meter), epsilon = EPSILON); - assert_ulps_eq!(0.0033, l3.fract(kilometer).get(kilometer), epsilon = EPSILON); - assert_ulps_eq!(0.3, l3.fract(meter).get(meter), epsilon = EPSILON); - assert_ulps_eq!(0.0035, l4.fract(kilometer).get(kilometer), epsilon = EPSILON); - assert_ulps_eq!(0.5, l4.fract(meter).get(meter), epsilon = EPSILON); - assert_ulps_eq!(0.3, m1.fract(kilogram).get(kilogram), epsilon = EPSILON); - assert_ulps_eq!(0.5, m2.fract(kilogram).get(kilogram), epsilon = EPSILON); + Test::assert_eq(&3.3.fract(), &l1.fract(kilometer).get(kilometer)); + Test::assert_eq(&(3.3.fract() * 1000.0), &l1.fract(kilometer).get(meter)); + Test::assert_eq(&((3.3 * 1000.0).fract() / 1000.0), &l1.fract(meter).get(kilometer)); + Test::assert_eq(&(3.3 * 1000.0).fract(), &l1.fract(meter).get(meter)); + + Test::assert_eq(&(3.3 / 1000.0).fract(), &l2.fract(kilometer).get(kilometer)); + Test::assert_eq(&((3.3 / 1000.0).fract() * 1000.0), &l2.fract(kilometer).get(meter)); + Test::assert_eq(&(3.3.fract() / 1000.0), &l2.fract(meter).get(kilometer)); + Test::assert_eq(&3.3.fract(), &l2.fract(meter).get(meter)); + + Test::assert_eq(&3.3.fract(), &m1.fract(kilogram).get(kilogram)); } } }