use std::convert::TryFrom;
#[cfg(feature = "decimal")]
use rust_decimal::Decimal;
#[cfg(feature = "decimal")]
use std::str::FromStr;
use uninum::{Number, TryFromNumberError, num};
#[test]
fn test_try_from_to_u8() {
assert_eq!(u8::try_from(Number::from(0_u64)).unwrap(), 0);
assert_eq!(u8::try_from(Number::from(255_u64)).unwrap(), 255);
assert!(matches!(
u8::try_from(Number::from(256_u64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(u8::try_from(Number::from(0_i64)).unwrap(), 0);
assert_eq!(u8::try_from(Number::from(255_i64)).unwrap(), 255);
assert!(matches!(
u8::try_from(Number::from(-1_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert!(matches!(
u8::try_from(Number::from(256_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(u8::try_from(Number::from(0_u64)).unwrap(), 0);
assert_eq!(u8::try_from(Number::from(255_u64)).unwrap(), 255);
assert!(matches!(
u8::try_from(Number::from(256_u64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(u8::try_from(Number::from(0_i64)).unwrap(), 0);
assert_eq!(u8::try_from(Number::from(255_i64)).unwrap(), 255);
assert!(matches!(
u8::try_from(Number::from(-1_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert!(matches!(
u8::try_from(Number::from(256_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(u8::try_from(num!(200.0f64)).unwrap(), 200);
assert!(matches!(
u8::try_from(num!(200.5f64)),
Err(TryFromNumberError::TypeMismatch { .. })
));
assert!(matches!(
u8::try_from(num!(-1.0f64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert!(matches!(
u8::try_from(num!(256.0f64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert!(matches!(
u8::try_from(num!(f64::INFINITY)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert!(matches!(
u8::try_from(num!(f64::NEG_INFINITY)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert!(matches!(
u8::try_from(num!(f64::NAN)),
Err(TryFromNumberError::TypeMismatch { .. })
));
#[cfg(feature = "decimal")]
{
use std::str::FromStr;
use rust_decimal::Decimal;
let int_dec = Number::from(Decimal::new(42, 0));
assert_eq!(u8::try_from(int_dec).unwrap(), 42);
let frac_dec = Number::from(Decimal::new(425, 1)); assert!(matches!(
u8::try_from(frac_dec),
Err(TryFromNumberError::TypeMismatch { .. })
));
let large_dec = Number::from(Decimal::new(256, 0));
assert!(matches!(
u8::try_from(large_dec),
Err(TryFromNumberError::OutOfRange { .. })
));
let neg_dec = Number::from(Decimal::new(-1, 0));
assert!(matches!(
u8::try_from(neg_dec),
Err(TryFromNumberError::OutOfRange { .. })
));
let large = Number::from(Decimal::from_str("256").unwrap());
assert!(matches!(
u8::try_from(large),
Err(TryFromNumberError::OutOfRange { .. })
));
}
}
#[test]
fn test_try_from_to_i8() {
assert_eq!(i8::try_from(Number::from(127_u64)).unwrap(), 127);
assert!(matches!(
i8::try_from(Number::from(128_u64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(i8::try_from(Number::from(-128_i64)).unwrap(), -128);
assert_eq!(i8::try_from(Number::from(127_i64)).unwrap(), 127);
assert!(matches!(
i8::try_from(Number::from(-129_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert!(matches!(
i8::try_from(Number::from(128_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(i8::try_from(Number::from(127_u64)).unwrap(), 127);
assert!(matches!(
i8::try_from(Number::from(128_u64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(i8::try_from(Number::from(-128_i64)).unwrap(), -128);
assert_eq!(i8::try_from(Number::from(127_i64)).unwrap(), 127);
assert!(matches!(
i8::try_from(Number::from(-129_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert!(matches!(
i8::try_from(Number::from(128_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(i8::try_from(num!(100.0f64)).unwrap(), 100);
assert!(matches!(
i8::try_from(num!(100.5f64)),
Err(TryFromNumberError::TypeMismatch { .. })
));
assert_eq!(i8::try_from(num!(-128.0f64)).unwrap(), -128);
assert!(matches!(
i8::try_from(num!(127.5f64)),
Err(TryFromNumberError::TypeMismatch { .. })
));
assert!(matches!(
i8::try_from(num!(128.0f64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert!(matches!(
i8::try_from(num!(-129.0f64)),
Err(TryFromNumberError::OutOfRange { .. })
));
#[cfg(feature = "decimal")]
{
let int_dec = Number::from(Decimal::new(42, 0));
assert_eq!(i8::try_from(int_dec).unwrap(), 42);
let frac_dec = Number::from(Decimal::new(425, 1)); assert!(matches!(
i8::try_from(frac_dec),
Err(TryFromNumberError::TypeMismatch { .. })
));
let large_dec = Number::from(Decimal::new(128, 0));
assert!(matches!(
i8::try_from(large_dec),
Err(TryFromNumberError::OutOfRange { .. })
));
let neg_large_dec = Number::from(Decimal::new(-129, 0));
assert!(matches!(
i8::try_from(neg_large_dec),
Err(TryFromNumberError::OutOfRange { .. })
));
let min_dec = Number::from(Decimal::new(-128, 0));
assert_eq!(i8::try_from(min_dec).unwrap(), -128);
let max_dec = Number::from(Decimal::new(127, 0));
assert_eq!(i8::try_from(max_dec).unwrap(), 127);
}
}
#[test]
fn test_try_from_to_u16() {
assert_eq!(u16::try_from(Number::from(65535_i64)).unwrap(), 65535);
assert!(matches!(
u16::try_from(Number::from(65536_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert!(matches!(
u16::try_from(Number::from(-1_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(u16::try_from(Number::from(65535_u64)).unwrap(), 65535);
assert!(matches!(
u16::try_from(Number::from(65536_u64)),
Err(TryFromNumberError::OutOfRange { .. })
));
}
#[test]
fn test_try_from_to_i16() {
assert_eq!(i16::try_from(Number::from(32767_u64)).unwrap(), 32767);
assert!(matches!(
i16::try_from(Number::from(32768_u64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(i16::try_from(Number::from(-32768_i64)).unwrap(), -32768);
assert!(matches!(
i16::try_from(Number::from(-32769_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(i16::try_from(num!(1000.0f64)).unwrap(), 1000);
assert!(matches!(
i16::try_from(num!(1000.5f64)),
Err(TryFromNumberError::TypeMismatch { .. })
));
assert!(matches!(
i16::try_from(num!(32768.0f64)),
Err(TryFromNumberError::OutOfRange { .. })
));
}
#[test]
fn test_try_from_to_u32() {
assert_eq!(u32::try_from(Number::from(0_u64)).unwrap(), 0);
assert_eq!(
u32::try_from(Number::from(4294967295_u64)).unwrap(),
4294967295
);
assert_eq!(
u32::try_from(Number::from(2147483647_i64)).unwrap(),
2147483647
);
assert!(matches!(
u32::try_from(Number::from(-1_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert!(matches!(
u32::try_from(Number::from(4294967296_u64)),
Err(TryFromNumberError::OutOfRange { .. })
));
}
#[test]
fn test_try_from_to_i32() {
assert_eq!(
i32::try_from(Number::from(2147483647_u64)).unwrap(),
2147483647
);
assert!(matches!(
i32::try_from(Number::from(2147483648_u64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(
i32::try_from(Number::from(-2147483648_i64)).unwrap(),
-2147483648
);
assert!(matches!(
i32::try_from(Number::from(-2147483649_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(i32::try_from(num!(1000.0f64)).unwrap(), 1000);
assert!(matches!(
i32::try_from(num!(1000.5f64)),
Err(TryFromNumberError::TypeMismatch { .. })
));
assert!(matches!(
i32::try_from(num!(2147483648.0f64)),
Err(TryFromNumberError::OutOfRange { .. })
));
}
#[test]
fn test_try_from_to_u64() {
assert_eq!(u64::try_from(Number::from(0_u64)).unwrap(), 0);
assert_eq!(
u64::try_from(Number::from(18446744073709551615_u64)).unwrap(),
18446744073709551615
);
assert_eq!(
u64::try_from(Number::from(9223372036854775807_i64)).unwrap(),
9223372036854775807
);
assert!(matches!(
u64::try_from(Number::from(-1_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(u64::try_from(num!(1000.0f64)).unwrap(), 1000);
assert!(matches!(
u64::try_from(num!(1000.5f64)),
Err(TryFromNumberError::TypeMismatch { .. })
));
let large_u64 = Number::from(9007199254740993_u64); assert!(matches!(
f64::try_from(large_u64),
Err(TryFromNumberError::TypeMismatch { .. })
));
let f64_large_int = num!(9007199254740992.0f64); assert_eq!(u64::try_from(f64_large_int).unwrap(), 9007199254740992);
let f64_large_loss = num!(42.5f64); assert!(matches!(
u64::try_from(f64_large_loss),
Err(TryFromNumberError::TypeMismatch { .. })
));
}
#[test]
fn test_try_from_to_i64() {
assert_eq!(
i64::try_from(Number::from(i64::from(i32::MIN))).unwrap(),
i32::MIN as i64
);
assert_eq!(
i64::try_from(Number::from(u64::from(u32::MAX))).unwrap(),
u32::MAX as i64
);
assert_eq!(i64::try_from(Number::from(i64::MIN)).unwrap(), i64::MIN);
assert_eq!(i64::try_from(Number::from(0_u64)).unwrap(), 0);
assert_eq!(
i64::try_from(Number::from(i64::MAX as u64)).unwrap(),
i64::MAX
);
assert!(matches!(
i64::try_from(Number::from(i64::MAX as u64 + 1)),
Err(TryFromNumberError::OutOfRange { .. })
));
let f64_large = Number::from(i64::MAX as f64 + 1.0);
assert!(matches!(
i64::try_from(f64_large),
Err(TryFromNumberError::OutOfRange { .. })
));
let f64_prec_loss = num!(42.5f64); assert!(matches!(
i64::try_from(f64_prec_loss),
Err(TryFromNumberError::TypeMismatch { .. })
));
let boundary = Number::from(9223372036854775808.0f64); assert!(matches!(
i64::try_from(boundary),
Err(TryFromNumberError::OutOfRange { .. })
));
let neg_boundary = Number::from(-9223372036854775809.0f64); assert_eq!(i64::try_from(neg_boundary).unwrap(), i64::MIN);
let far_below_min = Number::from(-1e20f64);
assert!(matches!(
i64::try_from(far_below_min),
Err(TryFromNumberError::OutOfRange { .. })
));
#[cfg(feature = "decimal")]
{
let dec_int = Number::from(Decimal::new(42, 0));
assert_eq!(i64::try_from(dec_int).unwrap(), 42);
let dec_frac = Number::from(Decimal::new(42, 1));
assert!(matches!(
i64::try_from(dec_frac),
Err(TryFromNumberError::TypeMismatch { .. })
));
let dec_large = Number::from(Decimal::MAX);
assert!(matches!(
i64::try_from(dec_large),
Err(TryFromNumberError::OutOfRange { .. })
));
let dec_min = Number::from(Decimal::MIN);
assert!(matches!(
i64::try_from(dec_min),
Err(TryFromNumberError::OutOfRange { .. })
));
}
}
#[test]
fn test_try_from_to_f64() {
let u64_exact = Number::from(9007199254740992_u64); assert_eq!(f64::try_from(u64_exact).unwrap(), 9007199254740992.0); let u64_loss = Number::from(9007199254740993_u64); assert!(matches!(
f64::try_from(u64_loss),
Err(TryFromNumberError::TypeMismatch { .. })
));
let u64_large_exact = Number::from(9007199254740994_u64); assert_eq!(f64::try_from(u64_large_exact).unwrap(), 9007199254740994.0);
let i64_large = Number::from(9007199254740991_i64); assert_eq!(f64::try_from(i64_large).unwrap(), 9007199254740991.0); let i64_neg_loss = Number::from(-9007199254740993_i64); assert!(matches!(
f64::try_from(i64_neg_loss),
Err(TryFromNumberError::TypeMismatch { .. })
));
assert_eq!(
f64::try_from(Number::from(std::f64::consts::PI)).unwrap(),
std::f64::consts::PI
);
assert!(f64::try_from(num!(f64::NAN)).is_ok());
assert!(f64::try_from(num!(f64::INFINITY)).is_ok());
#[cfg(feature = "decimal")]
{
let dec = Number::from(Decimal::from_str("1.234567890123456789").unwrap());
assert!(f64::try_from(dec).is_ok());
}
}
#[test]
fn test_try_from_to_decimal() {
#[cfg(feature = "decimal")]
{
use std::str::FromStr;
use rust_decimal::Decimal;
assert_eq!(
Decimal::try_from(Number::from(42_u64)).unwrap(),
Decimal::from(42)
);
assert_eq!(
Decimal::try_from(Number::from(-42_i64)).unwrap(),
Decimal::from(-42)
);
assert_eq!(
Decimal::try_from(Number::from(u64::MAX)).unwrap(),
Decimal::from(u64::MAX)
);
assert_eq!(
Decimal::try_from(Number::from(i64::MIN)).unwrap(),
Decimal::from(i64::MIN)
);
let f64_ok = Number::from(std::f64::consts::E);
assert!(Decimal::try_from(f64_ok).is_ok());
let f64_nan = num!(f64::NAN);
assert!(matches!(
Decimal::try_from(f64_nan),
Err(TryFromNumberError::TypeMismatch { .. })
));
let f64_inf = num!(f64::INFINITY);
assert!(matches!(
Decimal::try_from(f64_inf),
Err(TryFromNumberError::TypeMismatch { .. })
));
let f64_neg_inf = num!(f64::NEG_INFINITY);
assert!(matches!(
Decimal::try_from(f64_neg_inf),
Err(TryFromNumberError::TypeMismatch { .. })
));
let dec = Number::from(Decimal::from_str("1.234").unwrap());
assert_eq!(
Decimal::try_from(dec).unwrap(),
Decimal::from_str("1.234").unwrap()
);
let f64_large = num!(f64::MAX);
assert!(matches!(
Decimal::try_from(f64_large),
Err(TryFromNumberError::TypeMismatch { .. })
)); }
}
#[test]
fn test_special_float_values() {
let nan = num!(f64::NAN);
let inf = num!(f64::INFINITY);
let neg_inf = num!(f64::NEG_INFINITY);
assert!(matches!(
i32::try_from(nan.clone()),
Err(TryFromNumberError::TypeMismatch { .. })
));
assert!(matches!(
u64::try_from(inf.clone()),
Err(TryFromNumberError::OutOfRange { .. })
));
assert!(matches!(
i8::try_from(neg_inf.clone()),
Err(TryFromNumberError::OutOfRange { .. })
));
assert!(f64::try_from(nan.clone()).is_ok());
assert!(f64::try_from(inf.clone()).is_ok());
assert!(f64::try_from(neg_inf.clone()).is_ok());
#[cfg(feature = "decimal")]
{
assert!(matches!(
Decimal::try_from(nan),
Err(TryFromNumberError::TypeMismatch { .. })
));
assert!(matches!(
Decimal::try_from(inf),
Err(TryFromNumberError::TypeMismatch { .. })
));
assert!(matches!(
Decimal::try_from(neg_inf),
Err(TryFromNumberError::TypeMismatch { .. })
));
}
}
#[test]
fn test_precision_loss_detection() {
let u64_precise = Number::from(9007199254740993_u64); assert!(matches!(
f64::try_from(u64_precise.clone()),
Err(TryFromNumberError::TypeMismatch { .. })
));
let f64_frac = num!(42.5f64);
assert!(matches!(
i32::try_from(f64_frac),
Err(TryFromNumberError::TypeMismatch { .. })
));
#[cfg(feature = "decimal")]
{
let dec_frac = Number::from(Decimal::new(425, 1)); assert!(matches!(
u8::try_from(dec_frac),
Err(TryFromNumberError::TypeMismatch { .. })
));
}
}
#[test]
fn test_boundary_conditions() {
assert_eq!(u8::try_from(Number::from(255_u64)).unwrap(), 255);
assert!(matches!(
u8::try_from(Number::from(256_u64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(i8::try_from(Number::from(127_i64)).unwrap(), 127);
assert!(matches!(
i8::try_from(Number::from(128_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(i8::try_from(Number::from(-128_i64)).unwrap(), -128);
assert!(matches!(
i8::try_from(Number::from(-129_i64)),
Err(TryFromNumberError::OutOfRange { .. })
));
let f64_max_i64 = num!(i64::MAX as f64);
let result = i64::try_from(f64_max_i64);
assert!(result.is_ok() || matches!(result, Err(TryFromNumberError::OutOfRange { .. })));
let f64_min_i64 = num!(i64::MIN as f64);
let result = i64::try_from(f64_min_i64);
assert!(result.is_ok() || matches!(result, Err(TryFromNumberError::OutOfRange { .. })));
let at_clamp_boundary = Number::from(18446744073709551616.0f64); assert!(matches!(
u64::try_from(at_clamp_boundary),
Err(TryFromNumberError::OutOfRange { .. })
));
let at_neg_clamp_boundary = Number::from(-9223372036854775809.0f64); assert_eq!(i64::try_from(at_neg_clamp_boundary).unwrap(), i64::MIN);
let clearly_out_of_range = Number::from(-1e20f64);
assert!(matches!(
i64::try_from(clearly_out_of_range),
Err(TryFromNumberError::OutOfRange { .. })
));
}
#[test]
fn test_subnormal_and_small_values() {
let subnormal_f64 = num!(f64::MIN_POSITIVE / 2.0);
assert!(matches!(
u8::try_from(subnormal_f64.clone()),
Err(TryFromNumberError::TypeMismatch { .. })
));
let subnormal_f64 = num!(f64::MIN_POSITIVE / 2.0);
assert!(matches!(
i32::try_from(subnormal_f64),
Err(TryFromNumberError::TypeMismatch { .. })
));
let tiny_values = [
f64::MIN_POSITIVE,
f64::MIN_POSITIVE * 2.0,
f64::MIN_POSITIVE / 2.0, 1e-300,
1e-310,
];
for &val in &tiny_values {
let f64_num = Number::from(val);
let f64_result = f64::try_from(f64_num);
assert!(f64_result.is_ok());
if let Ok(f64_val) = f64_result {
assert!(f64_val >= 0.0);
}
}
}
#[test]
fn test_negative_zero_handling() {
let neg_zero_f64 = num!(-0.0f64);
assert_eq!(i32::try_from(neg_zero_f64.clone()).unwrap(), 0i32);
assert_eq!(u32::try_from(neg_zero_f64).unwrap(), 0u32);
}
#[test]
fn test_cross_type_conversions() {
let f64_val = Number::from(std::f64::consts::PI);
assert!(matches!(
u8::try_from(f64_val.clone()),
Err(TryFromNumberError::TypeMismatch { .. })
));
assert!(matches!(
i32::try_from(f64_val),
Err(TryFromNumberError::TypeMismatch { .. })
));
let neg_i32 = Number::from(-1000_i64);
assert!(matches!(
u32::try_from(neg_i32),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(
i8::try_from(Number::from(u64::from(i8::MAX as u32))).unwrap(),
i8::MAX
);
assert!(matches!(
i8::try_from(Number::from(u64::from(i8::MAX as u32 + 1))),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(
i16::try_from(Number::from(u64::from(i16::MAX as u32))).unwrap(),
i16::MAX
);
assert!(matches!(
i16::try_from(Number::from(u64::from(i16::MAX as u32 + 1))),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(
i32::try_from(Number::from(u64::from(i32::MAX as u32))).unwrap(),
i32::MAX
);
assert!(matches!(
i32::try_from(Number::from(u64::from(i32::MAX as u32 + 1))),
Err(TryFromNumberError::OutOfRange { .. })
));
assert_eq!(
i64::try_from(Number::from(i64::MAX as u64)).unwrap(),
i64::MAX
);
assert!(matches!(
i64::try_from(Number::from(i64::MAX as u64 + 1)),
Err(TryFromNumberError::OutOfRange { .. })
));
}
#[cfg(feature = "decimal")]
#[test]
fn test_decimal_edge_cases() {
use std::str::FromStr;
use rust_decimal::Decimal;
let zero_scale_0 = Number::from(Decimal::new(0, 0));
let zero_scale_10 = Number::from(Decimal::new(0, 10));
let zero_scale_28 = Number::from(Decimal::new(0, 28));
assert_eq!(u8::try_from(zero_scale_0).unwrap(), 0);
assert_eq!(u8::try_from(zero_scale_10).unwrap(), 0);
assert_eq!(u8::try_from(zero_scale_28).unwrap(), 0);
let one_scale_0 = Number::from(Decimal::new(1, 0)); let one_scale_1 = Number::from(Decimal::new(1, 1)); let one_scale_2 = Number::from(Decimal::new(1, 2)); assert_eq!(u8::try_from(one_scale_0).unwrap(), 1);
assert!(matches!(
u8::try_from(one_scale_1),
Err(TryFromNumberError::TypeMismatch { .. })
));
assert!(matches!(
u8::try_from(one_scale_2),
Err(TryFromNumberError::TypeMismatch { .. })
));
let float_max = num!(f64::MAX);
assert!(matches!(
Decimal::try_from(float_max),
Err(TryFromNumberError::TypeMismatch { .. })
));
let float_min = num!(f64::MIN);
assert!(matches!(
Decimal::try_from(float_min),
Err(TryFromNumberError::TypeMismatch { .. })
));
let exact_tenth = Number::from(Decimal::from_str("0.1").unwrap());
let f64_tenth = f64::try_from(exact_tenth).unwrap();
assert!((f64_tenth - 0.1f64).abs() < f64::EPSILON * 10.0);
let financial = Number::from(Decimal::from_str("123.45").unwrap());
assert!(matches!(
u8::try_from(financial.clone()),
Err(TryFromNumberError::TypeMismatch { .. })
));
let f64_financial = f64::try_from(financial).unwrap();
assert_eq!(f64_financial, 123.45);
}