use uninum::{Number, num};
#[test]
fn test_mixed_operations_with_special_floats() {
let inf = num!(f64::INFINITY);
let neg_inf = num!(f64::NEG_INFINITY);
let nan = num!(f64::NAN);
let normal = Number::from(42);
let result = &inf + &normal;
assert!(result.is_infinite());
assert!(result.is_pos_inf());
let result = &neg_inf + &normal;
assert!(result.is_infinite());
assert!(result.is_neg_inf());
let result = &nan + &normal;
assert!(result.is_nan());
let result = &normal + &inf;
assert!(result.is_infinite());
assert!(result.is_pos_inf());
let result = &normal + &neg_inf;
assert!(result.is_infinite());
assert!(result.is_neg_inf());
let result = &normal + &nan;
assert!(result.is_nan());
let result = &inf * &normal;
assert!(result.is_infinite());
assert!(result.is_pos_inf());
let result = &neg_inf * &normal;
assert!(result.is_infinite());
assert!(result.is_neg_inf());
let result = &nan * &normal;
assert!(result.is_nan());
let result = &inf / &normal;
assert!(result.is_infinite());
assert!(result.is_pos_inf());
let result = &neg_inf / &normal;
assert!(result.is_infinite());
assert!(result.is_neg_inf());
let result = &nan / &normal;
assert!(result.is_nan());
let result = &normal / &Number::from(0);
assert!(result.is_infinite());
assert!(result.is_pos_inf());
let result = &Number::from(0) / &Number::from(0);
assert!(result.is_nan());
}
#[cfg(feature = "decimal")]
#[test]
fn test_mixed_operations_with_decimal() {
use rust_decimal::Decimal;
let decimal = Number::from(Decimal::from(42));
let inf = num!(f64::INFINITY);
let neg_inf = num!(f64::NEG_INFINITY);
let nan = num!(f64::NAN);
let result = &decimal + &inf;
assert!(result.try_get_f64().is_some());
assert!(result.is_pos_inf());
let result = &decimal + &neg_inf;
assert!(result.try_get_f64().is_some());
assert!(result.is_neg_inf());
let result = &decimal + &nan;
assert!(result.try_get_f64().is_some());
assert!(result.is_nan());
let result = &decimal * &inf;
assert!(result.try_get_f64().is_some());
assert!(result.is_pos_inf());
let result = &decimal * &neg_inf;
assert!(result.try_get_f64().is_some());
assert!(result.is_neg_inf());
let result = &decimal * &nan;
assert!(result.try_get_f64().is_some());
assert!(result.is_nan());
let result = &decimal / &inf;
assert!(result.try_get_f64().is_some());
assert_eq!(result, num!(0.0));
let result = &decimal / &neg_inf;
assert!(result.try_get_f64().is_some());
assert_eq!(result, num!(-0.0));
let result = &decimal / &nan;
assert!(result.try_get_f64().is_some());
assert!(result.is_nan());
}
#[cfg(feature = "decimal")]
#[test]
fn test_mixed_operations_decimal_zero_handling() {
use rust_decimal::Decimal;
let positive = Number::from(Decimal::new(42, 1)); let negative = Number::from(Decimal::new(-42, 1)); let zero_int = Number::from(0u64);
let pos_div_zero = positive.clone() / zero_int.clone();
assert!(
matches!(pos_div_zero, Number::F64(ref f) if f.0.is_sign_positive() && f.0.is_infinite()),
"Decimal / 0 should yield +∞ via mixed_operation_div"
);
let neg_div_zero = negative.clone() / zero_int.clone();
assert!(
matches!(neg_div_zero, Number::F64(ref f) if f.0.is_sign_negative() && f.0.is_infinite()),
"Negative Decimal / 0 should yield -∞"
);
let zero_decimal = Number::from(Decimal::new(0, 0));
let zero_over_zero = zero_decimal.clone() / zero_int.clone();
assert!(
matches!(zero_over_zero, Number::F64(ref f) if f.0.is_nan()),
"0 / 0 should yield NaN"
);
let remainder_nan = positive % zero_int;
assert!(
matches!(remainder_nan, Number::F64(ref f) if f.0.is_nan()),
"Decimal % 0 should yield NaN"
);
}
#[cfg(feature = "decimal")]
#[test]
fn test_mixed_operations_decimal_conversion_failure_fallback() {
let huge_float = Number::from(f64::MAX);
let small_int = Number::from(2u64);
for operation in [
huge_float.clone() + small_int.clone(),
huge_float.clone() - small_int.clone(),
huge_float.clone() * small_int.clone(),
huge_float.clone() / small_int.clone(),
huge_float % small_int,
] {
assert!(
operation.try_get_decimal().is_none(),
"out-of-range floats should not convert to Decimal"
);
assert!(
operation.try_get_f64().is_some(),
"conversion failure should fall back to F64"
);
}
}
#[test]
fn test_complex_mixed_operations() {
let small_u32 = Number::from(255u64);
let large_u32 = Number::from(u64::from(u32::MAX));
let result = &small_u32 + &large_u32;
match result {
n if n.try_get_u64().is_some() => assert_eq!(n.try_get_u64().unwrap(), 4294967550u64),
n if n.try_get_i64().is_some() => assert_eq!(n.try_get_i64().unwrap(), 4294967550i64),
#[cfg(feature = "decimal")]
n if n.try_get_decimal().is_some() => {
assert_eq!(n.try_get_decimal().unwrap().to_string(), "4294967550");
}
_ => panic!("Unexpected type"),
}
let signed_max = Number::from(i64::from(i32::MAX));
let unsigned_max = Number::from(u64::from(u32::MAX));
let result = &signed_max + &unsigned_max;
#[cfg(feature = "decimal")]
assert!(
result.try_get_u64().is_some() || result.try_get_decimal().is_some(),
"Result should be U64 or Decimal"
);
#[cfg(not(feature = "decimal"))]
assert!(
result.try_get_u64().is_some()
|| result.try_get_i64().is_some()
|| result.try_get_f64().is_some(),
"Result should be U64, I64, or F64"
);
let negative = Number::from(-1000i64);
let positive = Number::from(500u64);
let result = &negative + &positive;
match result {
n if n.try_get_i64().is_some() => assert_eq!(n.try_get_i64().unwrap(), -500),
#[cfg(not(feature = "decimal"))]
n if n.try_get_f64().is_some() => assert_eq!(n.try_get_f64().unwrap(), -500.0),
#[cfg(feature = "decimal")]
n if n.try_get_decimal().is_some() => {
assert_eq!(n.try_get_decimal().unwrap().to_string(), "-500");
}
_ => panic!("Unexpected type"),
}
let small_unsigned = Number::from(10u64);
let large_signed = Number::from(100i64);
let result = &small_unsigned - &large_signed;
match result {
n if n.try_get_i64().is_some() => assert_eq!(n.try_get_i64().unwrap(), -90),
#[cfg(not(feature = "decimal"))]
n if n.try_get_f64().is_some() => assert_eq!(n.try_get_f64().unwrap(), -90.0),
#[cfg(feature = "decimal")]
n if n.try_get_decimal().is_some() => {
assert_eq!(n.try_get_decimal().unwrap().to_string(), "-90");
}
_ => panic!("Unexpected type"),
}
}
#[test]
fn test_cascading_type_promotions() {
let start = Number::from(100u64);
let multiplier = Number::from(100u64);
let addend = Number::from(100u64);
let step1 = &start * &multiplier; assert!(step1.try_get_u64().is_some() || step1.try_get_i64().is_some());
let step2 = &step1 * &multiplier; #[cfg(feature = "decimal")]
assert!(
step2.try_get_u64().is_some()
|| step2.try_get_i64().is_some()
|| step2.try_get_decimal().is_some()
);
#[cfg(not(feature = "decimal"))]
assert!(step2.try_get_u64().is_some() || step2.try_get_i64().is_some());
let step3 = &step2 + &addend; #[cfg(feature = "decimal")]
assert!(step3.try_get_u64().is_some() || step3.try_get_decimal().is_some());
#[cfg(not(feature = "decimal"))]
assert!(step3.try_get_u64().is_some() || step3.try_get_i64().is_some());
let large_multiplier = Number::from(10000u64);
let step4 = &step3 * &large_multiplier; #[cfg(feature = "decimal")]
assert!(step4.try_get_u64().is_some() || step4.try_get_decimal().is_some());
#[cfg(not(feature = "decimal"))]
assert!(step4.try_get_u64().is_some() || step4.try_get_i64().is_some());
}
#[test]
fn test_special_value_propagation() {
let nan_f64 = num!(f64::NAN);
let inf_f64 = num!(f64::INFINITY);
let neg_inf_f64 = num!(f64::NEG_INFINITY);
let normal = Number::from(42);
assert!((&nan_f64 + &normal).is_nan());
assert!((&normal + &nan_f64).is_nan());
assert!((&nan_f64 - &normal).is_nan());
assert!((&normal - &nan_f64).is_nan());
assert!((&nan_f64 * &normal).is_nan());
assert!((&normal * &nan_f64).is_nan());
assert!((&nan_f64 / &normal).is_nan());
assert!((&normal / &nan_f64).is_nan());
assert!((&inf_f64 + &normal).is_pos_inf());
assert!((&normal + &inf_f64).is_pos_inf());
assert!((&inf_f64 - &normal).is_pos_inf());
assert!((&normal - &inf_f64).is_neg_inf());
assert!((&inf_f64 * &normal).is_pos_inf());
assert!((&normal * &inf_f64).is_pos_inf());
assert!((&inf_f64 / &normal).is_pos_inf());
let result = &normal / &inf_f64;
assert_eq!(result.try_get_f64(), Some(0.0));
let result = &normal / &neg_inf_f64;
assert_eq!(result.try_get_f64(), Some(-0.0));
assert!((&inf_f64 - &inf_f64).is_nan());
assert!((&neg_inf_f64 - &neg_inf_f64).is_nan());
assert!((&inf_f64 + &neg_inf_f64).is_nan());
assert!((&inf_f64 / &inf_f64).is_nan());
assert!((&neg_inf_f64 / &neg_inf_f64).is_nan());
assert!((&inf_f64 / &neg_inf_f64).is_nan());
let zero = Number::from(0);
assert!((&zero * &inf_f64).is_nan());
assert!((&zero * &neg_inf_f64).is_nan());
}
#[test]
fn test_operator_precedence_mixed_types() {
let result = Number::from(10) + Number::from(5) * Number::from(2);
assert_eq!(result, Number::from(20));
let num = Number::from(10);
let result = &num + Number::from(5) * Number::from(2) - #
assert_eq!(result, Number::from(10));
let result = Number::from(200) + Number::from(100) - Number::from(50);
assert_eq!(result, Number::from(250));
let result = Number::from(10) + num!(2.5) * Number::from(2);
assert_eq!(result, num!(15.0)); }
#[test]
fn test_overflow_to_f64_preserves_values() {
assert_eq!(
Number::from(1000u64) * Number::from(2u64),
Number::from(2000u64)
);
assert_eq!(
Number::from(-10i64) + Number::from(-20i64),
Number::from(-30i64)
);
#[cfg(feature = "decimal")]
assert!(
(num!(1.0) + num!(2.0)).try_get_f64().is_some()
|| (num!(1.0) + num!(2.0)).try_get_decimal().is_some()
);
#[cfg(not(feature = "decimal"))]
assert!((num!(1.0) + num!(2.0)).try_get_f64().is_some());
}
#[test]
fn test_nan_edge_cases() {
let nan = num!(f64::NAN);
let inf = num!(f64::INFINITY);
let normal = Number::from(42);
assert_eq!(nan.clone(), nan.clone());
assert_ne!(nan.clone(), normal.clone());
assert_eq!(nan.clone().pow(&Number::from(0)), Number::from(1));
assert!(inf.pow(&nan).is_nan());
}
#[test]
fn test_pow_mixed_types() {
assert_eq!(Number::from(42).pow(&Number::from(0)), Number::from(1));
assert_eq!(num!(2.5).pow(&Number::from(2)), num!(6.25));
let inf = num!(f64::INFINITY);
let nan = num!(f64::NAN);
let zero = Number::from(0);
assert_eq!(zero.clone().pow(&zero), Number::from(1));
assert!(inf.clone().pow(&Number::from(2)).is_pos_inf());
assert_eq!(inf.clone().pow(&Number::from(-1)).try_get_f64(), Some(0.0));
assert!(nan.clone().pow(&Number::from(2)).is_nan());
assert_eq!(nan.pow(&Number::from(0)), Number::from(1));
}