use danwi::{
UnitDef,
prelude::*,
unit::{prefix::Kilo, si::Gram},
};
fn assert_close(a: f64, b: f64) {
assert!((a - b).abs() <= 1e-12 * b.abs().max(1.0), "{a} != {b}");
}
#[test]
fn construction_forms_agree() {
let v = 10.0_f64 * V;
assert_eq!(v, 10.0.V());
assert_eq!(v, 10.0.volt());
assert_eq!(v, Volt::from(10.0));
assert_eq!(v, Volt::new(10.0, V));
assert_eq!(v, Volt::new(10_000.0, mV));
assert_eq!(v.value(), 10.0);
}
#[test]
fn prefixed_arithmetic() {
let v = (5.0_f64 * mA) * (2.0_f64 * kOhm);
assert_eq!(v, 10.0 * V);
assert_eq!(v.to(mV), 10_000.0);
assert_eq!(v.to(kV), 0.01);
let i = v / 2.0.kOhm();
assert_eq!(i, 5.0.mA());
let t = 1.0.s() + 1e3.ms() + 1e6.us() + 1e9.ns();
assert_eq!(t, 4.0.second());
assert_eq!(t / 2.0.s(), 2.0);
}
#[test]
fn kilogram_is_the_coherent_mass_unit() {
let mass = 1.0.N() / 1.0.mps2();
assert_eq!(mass.to(kg), 1.0);
assert_eq!(mass.to(g), 1_000.0);
assert_eq!(mass, 1.0.kg());
assert_eq!(<Kilo<Gram> as UnitDef>::SCALE_NUM, 1);
assert_eq!(<Kilo<Gram> as UnitDef>::SCALE_DEN, 1);
}
#[test]
fn celsius_offset() {
let t = 25.0_f64 * degC;
assert_eq!(t.value(), 298.15); assert_eq!(t.to(K), 298.15);
assert_eq!(t.to(degC), 25.0);
assert_eq!(t, 25.0.celsius());
assert_eq!((0.0_f64 * degC).to(K), 273.15);
}
#[test]
fn non_decimal_scales() {
assert_eq!(1.5.hour(), 90.0.minute());
assert_eq!(1.0.minute(), 60.0.s());
assert_eq!((1.0_f64 * h).to(min), 60.0);
assert_close((1.0_f64 * inch).to(mm), 25.4);
assert_close((12.0_f64 * inch).value(), 0.3048);
assert_eq!(1.0.liter(), 1_000.0.mL());
assert_eq!((1.0_f64 * L).value(), 0.001);
assert_eq!(1.0.bar(), 100.0.kPa());
assert_eq!(1.0.bar().to(Pa), 100_000.0);
}
#[test]
fn reciprocal_dimensions() {
let period = 1.0.s();
let freq = 1.0 / period;
assert_eq!(freq, 1.0.Hz());
assert_eq!(freq, 1.0.hertz());
}
#[test]
fn display() {
let v = 10.5_f64 * kV;
assert_eq!(format!("{}", v.display_as(kV)), "10.5 kV");
assert_eq!(format!("{}", v.display_as(V)), "10500 V");
assert_eq!(format!("{:.1}", v.display_as(MV)), "0.0 MV");
assert_eq!(format!("{}", (25.0_f64 * degC).display_as(degC)), "25 °C");
assert_eq!(format!("{}", (2.0_f64 * kOhm).display_as(kOhm)), "2 kΩ");
assert_eq!(format!("{}", 3.0.mps().display_as(mps)), "3 m/s");
assert_eq!(format!("{}", 3.0.kmps().display_as(kmps)), "3 km/s");
assert_eq!(format!("{}", 1.5_f64 * kV), "1500");
}
#[test]
fn readme_mixed_units() {
let a = Meter::from(100.0);
let b = 50.0 * cm;
let c = 0.001 * km;
let len = a + b + c;
assert_eq!(len.value(), 101.5);
assert_eq!(format!("{}", len.display_as(cm)), "10150 cm");
}
#[test]
fn scalar_ops_and_negation() {
assert_eq!(3.0.V() - 1.0.V(), 2.0.V());
assert_eq!(-(2.0.V()), Volt::from(-2.0));
assert_eq!(2.0.V() * 3.0, 6.0.V());
assert_eq!(3.0 * 2.0.V(), 6.0.V());
assert_eq!(6.0.V() / 3.0, 2.0.V());
}
#[test]
fn dimensionless_into_scalar() {
assert_eq!(5.0.V() / 5.0.V(), 1.0);
let ratio = 4.0.s() / 2.0.s();
let x: f64 = ratio.into();
assert_eq!(x, 2.0);
fn takes_f64(x: f64) -> f64 {
x
}
assert_eq!(takes_f64((10.0.V() / 5.0.V()).into()), 2.0);
}
#[test]
fn ordering() {
assert!(1.0.mV() < 1.0.V());
assert!(2.0.kOhm() > 500.0.Ohm());
assert!(1.0.V() <= 1.0.V());
let ratio = 4.0.s() / 2.0.s();
assert_eq!(ratio, 2.0);
assert_eq!(2.0, ratio);
assert!(ratio < 3.0);
assert!(3.0 > ratio);
}
#[test]
fn physics_identities() {
assert_eq!(1.0.kg() * 1.0.mps2(), 1.0.N());
assert_eq!(1.0.N() * 1.0.m(), 1.0.J());
assert_eq!(1.0.J() / 1.0.s(), 1.0.W());
assert_eq!(1.0.N() / (1.0.m() * 1.0.m()), 1.0.Pa());
assert_eq!(1.0.m() / 1.0.s(), 1.0.mps());
assert_eq!(1.0.mps() / 1.0.s(), 1.0.mps2());
assert_eq!(1.0.V() * 1.0.A(), 1.0.W());
assert_eq!(1.0.A() * 1.0.s(), 1.0.C());
assert_eq!(1.0.V() / 1.0.A(), 1.0.Ohm());
assert_eq!(1.0 / 1.0.Ohm(), 1.0.S());
assert_eq!(1.0.C() / 1.0.V(), 1.0.F());
assert_eq!(1.0.V() * 1.0.s(), 1.0.Wb());
assert_eq!(1.0.Wb() / (1.0.m() * 1.0.m()), 1.0.T());
assert_eq!(1.0.Wb() / 1.0.A(), 1.0.H());
}
#[test]
fn prefix_ladder_roundtrips() {
fn ulp(a: f64) {
assert!((a - 1.0).abs() <= f64::EPSILON, "{a} != 1.0 within 1 ulp");
}
assert_eq!(1.0.QV().to(QV), 1.0);
assert_eq!(1.0.RV().to(RV), 1.0);
assert_eq!(1.0.YV().to(YV), 1.0);
assert_eq!(1.0.ZV().to(ZV), 1.0);
assert_eq!(1.0.EV().to(EV), 1.0);
assert_eq!(1.0.PV().to(PV), 1.0);
assert_eq!(1.0.TV().to(TV), 1.0);
assert_eq!(1.0.GV().to(GV), 1.0);
assert_eq!(1.0.MV().to(MV), 1.0);
assert_eq!(1.0.kV().to(kV), 1.0);
assert_eq!(1.0.hV().to(hV), 1.0);
assert_eq!(1.0.daV().to(daV), 1.0);
assert_eq!(1.0.V().to(V), 1.0);
ulp(1.0.dV().to(dV));
ulp(1.0.cV().to(cV));
ulp(1.0.mV().to(mV));
ulp(1.0.uV().to(uV));
ulp(1.0.nV().to(nV));
ulp(1.0.pV().to(pV));
ulp(1.0.fV().to(fV));
ulp(1.0.attoV().to(attoV));
ulp(1.0.zV().to(zV));
ulp(1.0.yV().to(yV));
ulp(1.0.rV().to(rV));
ulp(1.0.qV().to(qV));
assert_eq!((1.0_f64 * QV).value(), 1e30);
assert_eq!(1.0.kV().to(mV), 1_000_000.0);
}
#[test]
fn name_form_methods() {
assert_eq!(1.0.kilovolt(), 1.0.kV());
assert_eq!(1.0.millisecond(), 1.0.ms());
assert_eq!(1.0.kilogram(), 1.0.kg());
assert_eq!(1.0.microvolt(), 1.0.uV());
assert_eq!(1.0.attosecond(), 1.0.attos());
assert_eq!(1.0.meter_per_second(), 1.0.mps());
}
#[test]
fn debug_formats() {
assert_eq!(format!("{:?}", 2.5.V()), "Quantity(2.5)");
assert_eq!(format!("{:?}", kV), "Unit(kV)");
assert_eq!(format!("{:?}", degC), "Unit(°C)");
}
#[cfg(feature = "f32")]
#[test]
fn f32_support() {
use danwi::f32::{QuantityExt, constants::*, types};
fn close(a: f32, b: f32) {
assert!((a - b).abs() <= 1e-5 * b.abs().max(1.0), "{a} != {b}");
}
let v: types::Volt = 5.0_f32.kV();
assert_eq!(v.to(V), 5_000.0_f32);
assert_eq!(5.0_f32.mA() * 2.0_f32.kOhm(), 10.0_f32.V());
assert_eq!(format!("{}", v.display_as(kV)), "5 kV");
assert!(1.0_f32.mV() < 1.0_f32.V());
close(25.0_f32.celsius().to(degC), 25.0);
close(25.0_f32.celsius().to(K), 298.15);
}
#[test]
fn standard_gravity_constant() {
assert_eq!(danwi::f64::G_0, 9.80665.mps2());
}