#[cfg(feature = "decimal")]
use rust_decimal::{Decimal, prelude::ToPrimitive};
use uninum::{Number, num};
#[test]
fn test_ref_operations_optimization_same_types() {
let a = Number::from(100_u64);
let b = Number::from(200_u64);
let result = &a + &b;
assert_eq!(result, Number::from(300_u64));
let c = num!(3.12);
let d = num!(2.88);
let result = &c + &d;
assert_eq!(result, num!(6.0));
}
#[test]
fn test_ref_operations_mixed_types() {
let int_val = Number::from(42_u64);
let float_val = num!(3.12);
let result = &int_val + &float_val;
assert_eq!(result, num!(45.12));
let result = &float_val - &int_val;
assert_eq!(result, num!(-38.88));
}
#[test]
fn test_sub_ref_unsigned_without_promotion() {
let lhs = Number::from(10u64);
let rhs = Number::from(3u64);
let result = &lhs - &rhs;
assert_eq!(result, Number::from(7u64));
}
#[test]
fn test_u32_overflow_addition() {
let a = Number::from(u64::from(u32::MAX));
let b = Number::from(1_u64);
let result = &a + &b;
assert_eq!(result, Number::from(u32::MAX as u64 + 1));
let result = &a * &Number::from(2_u64);
assert_eq!(result, Number::from(u32::MAX as u64 * 2));
}
#[test]
fn test_i32_overflow_scenarios() {
let i32_max = Number::from(i64::from(i32::MAX));
let i32_min = Number::from(i64::from(i32::MIN));
let one = Number::from(1_i64);
let result = &i32_max + &one;
assert_eq!(result, Number::from(i32::MAX as i64 + 1));
let result = &i32_min - &one;
assert_eq!(result, Number::from(i32::MIN as i64 - 1));
}
#[test]
fn test_u32_subtraction_underflow() {
let small = Number::from(1_000_000_u64);
let large = Number::from(2_000_000_u64);
let result = &small - &large;
assert_eq!(result, Number::from(-1_000_000_i64));
}
#[test]
#[cfg(feature = "decimal")]
fn test_u64_overflow_to_decimal() {
let a = Number::from(u64::MAX);
let b = Number::from(1_u64);
let result = &a + &b;
assert!(result.try_get_decimal().is_some());
if let Some(arc_dec) = result.try_get_decimal() {
let expected = Decimal::from(u64::MAX) + Decimal::ONE;
assert_eq!(**arc_dec, expected);
}
}
#[test]
#[cfg(not(feature = "decimal"))]
fn test_u64_overflow_to_f64_no_decimal() {
let a = Number::from(u64::MAX);
let b = Number::from(1_u64);
let result = &a + &b;
assert!(result.try_get_f64().is_some());
}
#[test]
#[cfg(feature = "decimal")]
fn test_u64_subtraction_underflow() {
let small = Number::from(1_000_000_000_u64);
let large = Number::from(2_000_000_000_u64);
let result = &small - &large;
assert!(result.try_get_decimal().is_some() || result.try_get_f64().is_some());
}
#[test]
#[cfg(not(feature = "decimal"))]
fn test_u64_subtraction_underflow_no_decimal() {
let small = Number::from(1_000_000_000_u64);
let large = Number::from(2_000_000_000_u64);
let result = &small - &large;
assert!(result.try_get_f64().is_some());
}
#[test]
#[cfg(feature = "decimal")]
fn test_i64_overflow_to_decimal() {
let i64_max = Number::from(i64::MAX);
let i64_min = Number::from(i64::MIN);
let one = Number::from(1_i64);
let result = &i64_max + &one;
assert!(result.try_get_decimal().is_some());
let result = &i64_min - &one;
assert!(result.try_get_decimal().is_some());
}
#[test]
#[cfg(not(feature = "decimal"))]
fn test_i64_overflow_to_f64_no_decimal() {
let i64_max = Number::from(i64::MAX);
let one = Number::from(1_i64);
let result = &i64_max + &one;
assert!(result.try_get_f64().is_some());
}
#[test]
fn test_f64_special_values() {
let nan = num!(f64::NAN);
let inf = num!(f64::INFINITY);
let normal = num!(42.0);
let result = &nan + &normal;
assert!(result.is_nan());
let result = &inf + &normal;
assert!(result.is_infinite() && result.is_pos_inf());
}
#[cfg(feature = "decimal")]
#[test]
fn test_decimal_operations() {
let a = Number::from(Decimal::new(312, 2)); let b = Number::from(Decimal::new(288, 2)); let result = &a + &b;
if let Some(arc_dec) = result.try_get_decimal() {
assert_eq!(**arc_dec, Decimal::new(600, 2)); }
let int_val = Number::from(2_u64);
let result = &a + &int_val;
assert!(result.try_get_decimal().is_some() || result.try_get_f64().is_some());
}
#[cfg(feature = "decimal")]
#[test]
fn test_decimal_overflow_to_f64() {
let max_decimal = Number::from(Decimal::MAX);
let two = Number::from(Decimal::from(2));
let result = &max_decimal + &two;
assert!(result.try_get_f64().is_some());
let result = &max_decimal * &two;
assert!(result.try_get_f64().is_some());
}
#[test]
fn test_boundary_conditions() {
let u32_near_max = Number::from(u64::from(u32::MAX - 1));
let u32_one = Number::from(1_u64);
let result = &u32_near_max + &u32_one;
assert_eq!(result, Number::from(u64::from(u32::MAX)));
let u32_two = Number::from(2_u64);
let result = &u32_near_max + &u32_two;
assert_eq!(result, Number::from(u32::MAX as u64 + 1));
let i32_near_min = Number::from(i64::from(i32::MIN + 1));
let i32_one = Number::from(1_i64);
let result = &i32_near_min - &i32_one;
assert_eq!(result, Number::from(i64::from(i32::MIN)));
let i32_two = Number::from(2_i64);
let result = &i32_near_min - &i32_two;
assert_eq!(result, Number::from(i32::MIN as i64 - 1));
}
#[test]
fn test_mixed_type_operations() {
let int_val = Number::from(100_i64);
let float_val = num!(42.5);
let result = &int_val - &float_val;
assert_eq!(result, num!(57.5));
let u_val = Number::from(50_u64);
let i_val = Number::from(-25_i64);
let result = &u_val - &i_val;
assert_eq!(result, Number::from(75_i64));
}
#[test]
fn test_operations_with_primitive_references() {
let number_val = Number::from(42_i64);
let primitive_val = 10i32;
let primitive_ref = &primitive_val;
let result = primitive_ref + &number_val;
assert_eq!(result, Number::from(52_i64));
let result = &number_val + primitive_ref;
assert_eq!(result, Number::from(52_i64));
let result = primitive_ref - &number_val;
assert_eq!(result, Number::from(-32_i64));
let result = &number_val - primitive_ref;
assert_eq!(result, Number::from(32_i64));
let result = primitive_ref * &number_val;
assert_eq!(result, Number::from(420_i64));
let result = &number_val * primitive_ref;
assert_eq!(result, Number::from(420_i64));
}
#[test]
fn test_different_primitive_types() {
let u32_number = Number::from(100_u64);
let f64_number = num!(3.16);
let i32_primitive = 50i32;
let f64_primitive = 2.5f64;
let u64_primitive = 200u64;
let result = &u32_number + i32_primitive;
assert_eq!(result, Number::from(150_i64));
let result = &f64_number * f64_primitive;
assert!(result.approx_eq(&num!(7.9), 1e-15, 0.0));
let result = u64_primitive - &u32_number;
assert_eq!(result, Number::from(100_u64));
}
#[test]
fn test_division_operations() {
let number_val = Number::from(84_i64);
let primitive_val = 4i32;
let result = &number_val / primitive_val;
assert_eq!(result, Number::from(21_i64));
#[cfg(feature = "decimal")]
{
let result = primitive_val / &number_val;
assert!(result.try_get_decimal().is_some());
}
#[cfg(not(feature = "decimal"))]
{
let result = primitive_val / &number_val;
assert_eq!(result, num!(4.0 / 84.0));
}
let float_number = num!(10.5);
let float_primitive = 2.5f64;
let result = &float_number / float_primitive;
assert_eq!(result, num!(4.2));
let result = float_primitive / &float_number;
let expected_value = 2.5 / 10.5;
if let Some(result_f64) = result.try_get_f64() {
assert!((result_f64 - expected_value).abs() < 1e-15);
} else {
#[cfg(feature = "decimal")]
{
if let Some(result_decimal) = result.try_get_decimal() {
let result_f64 = result_decimal.to_f64().unwrap_or(0.0);
assert!((result_f64 - expected_value).abs() < 1e-15);
} else {
panic!("Expected result to be F64 or Decimal");
}
}
#[cfg(not(feature = "decimal"))]
{
panic!("Expected result to be F64");
}
}
}
#[test]
fn test_reference_arithmetic_trait_coverage() {
let lhs = Number::from(9i64);
let rhs = Number::from(3i64);
let four = Number::from(4i64);
assert_eq!((&lhs) - &rhs, Number::from(6i64));
assert_eq!(lhs.clone() - &rhs, Number::from(6i64));
assert_eq!((&lhs) - rhs.clone(), Number::from(6i64));
assert_eq!((&lhs) * &four, Number::from(36i64));
assert_eq!(lhs.clone() * &four, Number::from(36i64));
assert_eq!((&lhs) * four.clone(), Number::from(36i64));
assert_eq!((&lhs) / &rhs, Number::from(3i64));
assert_eq!(lhs.clone() / &rhs, Number::from(3i64));
assert_eq!((&lhs) / rhs.clone(), Number::from(3i64));
assert_eq!((&lhs) % &rhs, Number::from(0i64));
assert_eq!(lhs.clone() % &rhs, Number::from(0i64));
assert_eq!((&lhs) % rhs, Number::from(0i64));
}
#[test]
fn test_fallback_to_clone_add() {
let a = Number::from(42_u64);
let b = num!(3.16);
let result = &a + &b;
let expected = a.clone() + b.clone();
assert_eq!(result, expected);
}
#[test]
#[cfg(feature = "decimal")]
fn test_sub_ref_decimal_overflow_falls_back_to_f64() {
let max_decimal = Number::from(Decimal::MAX);
let negative_one = Number::from(Decimal::new(-1, 0));
let result = &max_decimal - &negative_one;
assert!(
result.try_get_decimal().is_none(),
"overflowing subtraction should not stay Decimal"
);
assert!(
result.try_get_f64().is_some(),
"overflowing subtraction should fall back to F64"
);
}
#[test]
#[cfg(feature = "decimal")]
fn test_u64_multiplication_decimal_overflow_to_f64() {
let a = Number::from(u64::MAX);
let b = Number::from(u64::MAX);
let result = &a * &b;
assert!(result.try_get_f64().is_some());
if let Some(f) = result.try_get_f64() {
let expected = (u64::MAX as f64) * (u64::MAX as f64);
assert_eq!(f, expected);
}
}
#[test]
#[cfg(feature = "decimal")]
fn test_i64_multiplication_decimal_overflow_to_f64() {
let a = Number::from(i64::MAX);
let b = Number::from(i64::MAX);
let result = &a * &b;
assert!(result.try_get_f64().is_some());
if let Some(f) = result.try_get_f64() {
let expected = (i64::MAX as f64) * (i64::MAX as f64);
assert_eq!(f, expected);
}
}