use uninum::{Number, num};
fn generate_test_numbers() -> Vec<Number> {
let numbers = vec![
Number::from(0u64),
Number::from(1u64),
Number::from(42u64),
Number::from(255u64),
Number::from(-128i64),
Number::from(-1i64),
Number::from(0i64),
Number::from(1i64),
Number::from(127i64),
Number::from(256u64),
Number::from(65535u64),
Number::from(-32768i64),
Number::from(32767i64),
Number::from(65536u64),
Number::from(4_294_967_295_u64),
Number::from(-2_147_483_648_i64),
Number::from(2_147_483_647_i64),
Number::from(0u64),
Number::from(4_294_967_296_u64),
Number::from(u64::MAX),
Number::from(i64::MIN),
Number::from(0i64),
Number::from(i64::MAX),
num!(0.0),
num!(-0.0),
num!(1.0),
num!(-1.0),
num!(std::f64::consts::PI),
Number::from(-std::f64::consts::PI),
num!(f64::INFINITY),
num!(f64::NEG_INFINITY),
num!(f64::NAN),
Number::from(42u64),
Number::from(42i64),
num!(42.0),
];
#[cfg(feature = "decimal")]
let numbers = {
use rust_decimal::Decimal;
let mut numbers = numbers;
numbers.extend([
Number::from(Decimal::new(0, 0)),
Number::from(Decimal::new(1, 0)),
Number::from(Decimal::new(42, 0)),
Number::from(Decimal::new(314_159, 5)), Number::from(Decimal::new(-314_159, 5)), ]);
numbers
};
numbers
}
#[test]
fn test_equality_reflexive_property() {
let numbers = generate_test_numbers();
for a in &numbers {
assert_eq!(a, a, "Reflexive property violated for {a:?}");
}
}
#[test]
fn test_equality_symmetric_property() {
let numbers = generate_test_numbers();
for a in &numbers {
for b in &numbers {
if a == b {
assert_eq!(
b, a,
"Symmetric property violated: {a:?} == {b:?} but {b:?} != {a:?}"
);
}
}
}
}
#[test]
fn test_equality_transitive_property() {
let numbers = generate_test_numbers();
for a in &numbers {
for b in &numbers {
for c in &numbers {
if a == b && b == c {
assert_eq!(
a, c,
"Transitive property violated: {a:?} == {b:?} and {b:?} == {c:?} but \
{a:?} != {c:?}"
);
}
}
}
}
}
#[test]
fn test_cross_type_equality_consistency() {
let equivalent_groups = vec![
vec![
Number::from(42u64),
Number::from(42i64),
Number::from(42u64),
Number::from(42i64),
num!(42.0),
],
vec![
Number::from(0u64),
Number::from(0i64),
Number::from(0u64),
Number::from(0i64),
num!(0.0),
num!(-0.0),
],
vec![
Number::from(1u64),
Number::from(1i64),
Number::from(1u64),
Number::from(1i64),
num!(1.0),
],
];
#[cfg(feature = "decimal")]
let equivalent_groups = {
use rust_decimal::Decimal;
let mut equivalent_groups = equivalent_groups;
for (i, group) in equivalent_groups.iter_mut().enumerate() {
match i {
0 => group.push(Number::from(Decimal::new(42, 0))),
1 => group.push(Number::from(Decimal::new(0, 0))),
2 => group.push(Number::from(Decimal::new(1, 0))),
_ => {}
}
}
equivalent_groups
};
for group in equivalent_groups {
for a in &group {
for b in &group {
assert_eq!(
a, b,
"Cross-type equality failed: {a:?} and {b:?} should be equal"
);
}
}
}
}
#[test]
fn test_special_value_equality() {
let nan_f64 = num!(f64::NAN);
let nan_f64_2 = num!(f64::NAN);
assert_eq!(nan_f64, nan_f64, "NaN should equal itself");
assert_eq!(nan_f64, nan_f64_2, "Different NaN values should be equal");
let pos_inf_f64 = num!(f64::INFINITY);
let neg_inf_f64 = num!(f64::NEG_INFINITY);
assert_eq!(
pos_inf_f64, pos_inf_f64,
"Positive infinity should equal itself"
);
assert_eq!(
neg_inf_f64, neg_inf_f64,
"Negative infinity should equal itself"
);
assert_ne!(
pos_inf_f64, neg_inf_f64,
"Positive and negative infinity should not be equal"
);
}
#[test]
fn test_large_number_equality() {
let large_u64 = Number::from(u64::MAX);
let large_u64_2 = Number::from(u64::MAX);
assert_eq!(large_u64, large_u64_2, "Large U64 values should be equal");
let large_val = (i64::MAX as u64) + 1;
let u64_num = Number::from(large_val);
let f64_num = num!(large_val as f64);
if f64_num.is_integer() && u64_num.as_i128() == f64_num.as_i128() {
assert_eq!(
u64_num, f64_num,
"Large U64 and equivalent F64 should be equal"
);
}
}
#[test]
fn test_equality_with_primitives() {
let n_u32 = Number::from(42u64);
let n_i32 = Number::from(42i64);
let n_f64 = num!(42.0);
assert_eq!(n_u32, 42u32);
assert_eq!(42u32, n_u32);
assert_eq!(n_i32, 42i32);
assert_eq!(42i32, n_i32);
assert_eq!(n_f64, 42.0f64);
assert_eq!(42.0f64, n_f64);
assert_eq!(n_u32, 42i32);
assert_eq!(n_i32, 42u32);
assert_eq!(n_u32, 42.0f64);
assert_eq!(n_f64, 42u32);
}
#[test]
fn test_equality_with_references_and_primitives() {
let n_u32 = Number::from(42u64);
let n_i32 = Number::from(42i64);
let n_f64 = num!(42.0);
let n_u32_ref = &n_u32;
let n_i32_ref = &n_i32;
let n_f64_ref = &n_f64;
assert_eq!(n_u32_ref, &42u32);
assert_eq!(n_i32_ref, &42i32);
assert_eq!(n_f64_ref, &42.0f64);
assert_eq!(&42u32, n_u32_ref);
assert_eq!(&42i32, n_i32_ref);
assert_eq!(&42.0f64, n_f64_ref);
assert_eq!(n_u32_ref, &42i32);
assert_eq!(n_i32_ref, &42u32);
assert_eq!(n_u32_ref, &42.0f64);
assert_eq!(n_f64_ref, &42u32);
assert_ne!(n_u32_ref, &43u32);
assert_ne!(&43u32, n_u32_ref);
assert_ne!(n_f64_ref, &43.0f64);
assert_ne!(&43.0f64, n_f64_ref);
let zero_i32 = Number::from(0i64);
let zero_f64 = num!(0.0);
let zero_i32_ref = &zero_i32;
let zero_f64_ref = &zero_f64;
assert_eq!(zero_i32_ref, &0i32);
assert_eq!(&0i32, zero_i32_ref);
assert_eq!(zero_f64_ref, &0.0f64);
assert_eq!(&0.0f64, zero_f64_ref);
assert_eq!(zero_i32_ref, &0.0f64);
assert_eq!(&0.0f64, zero_i32_ref);
assert_eq!(zero_f64_ref, &0i32);
assert_eq!(&0i32, zero_f64_ref);
}
#[test]
fn test_reference_equality_comprehensive() {
let num_u32 = Number::from(42u64);
let prim_u32 = 42u32;
let num_u32_ref = &num_u32;
let prim_u32_ref = &prim_u32;
assert_eq!(
num_u32_ref, prim_u32,
"Failed: &Number == primitive for {num_u32:?} and {prim_u32:?}"
);
assert_eq!(
prim_u32, num_u32_ref,
"Failed: primitive == &Number for {prim_u32:?} and {num_u32:?}"
);
assert_eq!(
num_u32_ref, prim_u32_ref,
"Failed: &Number == &primitive for {num_u32:?} and {prim_u32:?}"
);
assert_eq!(
prim_u32_ref, num_u32_ref,
"Failed: &primitive == &Number for {prim_u32:?} and {num_u32:?}"
);
let num_i32 = Number::from(-42i64);
let prim_i32 = -42i32;
let num_i32_ref = &num_i32;
let prim_i32_ref = &prim_i32;
assert_eq!(
num_i32_ref, prim_i32,
"Failed: &Number == primitive for {num_i32:?} and {prim_i32:?}"
);
assert_eq!(
prim_i32, num_i32_ref,
"Failed: primitive == &Number for {prim_i32:?} and {num_i32:?}"
);
assert_eq!(
num_i32_ref, prim_i32_ref,
"Failed: &Number == &primitive for {num_i32:?} and {prim_i32:?}"
);
assert_eq!(
prim_i32_ref, num_i32_ref,
"Failed: &primitive == &Number for {prim_i32:?} and {num_i32:?}"
);
let num_u64 = Number::from(123u64);
let prim_u64 = 123u64;
let num_u64_ref = &num_u64;
let prim_u64_ref = &prim_u64;
assert_eq!(
num_u64_ref, prim_u64,
"Failed: &Number == primitive for {num_u64:?} and {prim_u64:?}"
);
assert_eq!(
prim_u64, num_u64_ref,
"Failed: primitive == &Number for {prim_u64:?} and {num_u64:?}"
);
assert_eq!(
num_u64_ref, prim_u64_ref,
"Failed: &Number == &primitive for {num_u64:?} and {prim_u64:?}"
);
assert_eq!(
prim_u64_ref, num_u64_ref,
"Failed: &primitive == &Number for {prim_u64:?} and {num_u64:?}"
);
let num_i64 = Number::from(-123i64);
let prim_i64 = -123i64;
let num_i64_ref = &num_i64;
let prim_i64_ref = &prim_i64;
assert_eq!(
num_i64_ref, prim_i64,
"Failed: &Number == primitive for {num_i64:?} and {prim_i64:?}"
);
assert_eq!(
prim_i64, num_i64_ref,
"Failed: primitive == &Number for {prim_i64:?} and {num_i64:?}"
);
assert_eq!(
num_i64_ref, prim_i64_ref,
"Failed: &Number == &primitive for {num_i64:?} and {prim_i64:?}"
);
assert_eq!(
prim_i64_ref, num_i64_ref,
"Failed: &primitive == &Number for {prim_i64:?} and {num_i64:?}"
);
let num_f64 = num!(3.16);
let prim_f64 = 3.16f64;
let num_f64_ref = &num_f64;
let prim_f64_ref = &prim_f64;
assert_eq!(
num_f64_ref, prim_f64,
"Failed: &Number == primitive for {num_f64:?} and {prim_f64:?}"
);
assert_eq!(
prim_f64, num_f64_ref,
"Failed: primitive == &Number for {prim_f64:?} and {num_f64:?}"
);
assert_eq!(
num_f64_ref, prim_f64_ref,
"Failed: &Number == &primitive for {num_f64:?} and {prim_f64:?}"
);
assert_eq!(
prim_f64_ref, num_f64_ref,
"Failed: &primitive == &Number for {prim_f64:?} and {num_f64:?}"
);
}
#[test]
#[allow(invalid_nan_comparisons)]
fn test_eq_helpers_normalize_nan_and_signed_zero() {
let nan_a = num!(f64::NAN);
let nan_b = num!(f64::NAN);
assert_eq!(nan_a, nan_b);
assert!(nan_a == f64::NAN);
assert!(f64::NAN == nan_a);
let pos_zero = num!(0.0f64);
let neg_zero = num!(-0.0f64);
assert_eq!(pos_zero, neg_zero);
assert!(pos_zero == -0.0f64);
assert!(neg_zero == 0i64);
}
#[test]
fn test_reference_inequality_comprehensive() {
let num_u32 = Number::from(42u64);
let prim_u32 = 43u32;
let num_u32_ref = &num_u32;
let prim_u32_ref = &prim_u32;
assert_ne!(
num_u32_ref, prim_u32,
"Failed: &Number != primitive for {num_u32:?} and {prim_u32:?}"
);
assert_ne!(
prim_u32, num_u32_ref,
"Failed: primitive != &Number for {prim_u32:?} and {num_u32:?}"
);
assert_ne!(
num_u32_ref, prim_u32_ref,
"Failed: &Number != &primitive for {num_u32:?} and {prim_u32:?}"
);
assert_ne!(
prim_u32_ref, num_u32_ref,
"Failed: &primitive != &Number for {prim_u32:?} and {num_u32:?}"
);
let num_i32 = Number::from(-42i64);
let prim_i32 = -41i32;
let num_i32_ref = &num_i32;
let prim_i32_ref = &prim_i32;
assert_ne!(
num_i32_ref, prim_i32,
"Failed: &Number != primitive for {num_i32:?} and {prim_i32:?}"
);
assert_ne!(
prim_i32, num_i32_ref,
"Failed: primitive != &Number for {prim_i32:?} and {num_i32:?}"
);
assert_ne!(
num_i32_ref, prim_i32_ref,
"Failed: &Number != &primitive for {num_i32:?} and {prim_i32:?}"
);
assert_ne!(
prim_i32_ref, num_i32_ref,
"Failed: &primitive != &Number for {prim_i32:?} and {num_i32:?}"
);
let num_u64 = Number::from(123u64);
let prim_u64 = 124u64;
let num_u64_ref = &num_u64;
let prim_u64_ref = &prim_u64;
assert_ne!(
num_u64_ref, prim_u64,
"Failed: &Number != primitive for {num_u64:?} and {prim_u64:?}"
);
assert_ne!(
prim_u64, num_u64_ref,
"Failed: primitive != &Number for {prim_u64:?} and {num_u64:?}"
);
assert_ne!(
num_u64_ref, prim_u64_ref,
"Failed: &Number != &primitive for {num_u64:?} and {prim_u64:?}"
);
assert_ne!(
prim_u64_ref, num_u64_ref,
"Failed: &primitive != &Number for {prim_u64:?} and {num_u64:?}"
);
let num_i64 = Number::from(-123i64);
let prim_i64 = -122i64;
let num_i64_ref = &num_i64;
let prim_i64_ref = &prim_i64;
assert_ne!(
num_i64_ref, prim_i64,
"Failed: &Number != primitive for {num_i64:?} and {prim_i64:?}"
);
assert_ne!(
prim_i64, num_i64_ref,
"Failed: primitive != &Number for {prim_i64:?} and {num_i64:?}"
);
assert_ne!(
num_i64_ref, prim_i64_ref,
"Failed: &Number != &primitive for {num_i64:?} and {prim_i64:?}"
);
assert_ne!(
prim_i64_ref, num_i64_ref,
"Failed: &primitive != &Number for {prim_i64:?} and {num_i64:?}"
);
let num_f64 = num!(3.16);
let prim_f64 = 3.15f64;
let num_f64_ref = &num_f64;
let prim_f64_ref = &prim_f64;
assert_ne!(
num_f64_ref, prim_f64,
"Failed: &Number != primitive for {num_f64:?} and {prim_f64:?}"
);
assert_ne!(
prim_f64, num_f64_ref,
"Failed: primitive != &Number for {prim_f64:?} and {num_f64:?}"
);
assert_ne!(
num_f64_ref, prim_f64_ref,
"Failed: &Number != &primitive for {num_f64:?} and {prim_f64:?}"
);
assert_ne!(
prim_f64_ref, num_f64_ref,
"Failed: &primitive != &Number for {prim_f64:?} and {num_f64:?}"
);
}
#[test]
fn test_reference_cross_type_equality() {
let num_u32 = Number::from(42u64);
let prim_i32 = 42i32;
let num_u32_ref = &num_u32;
let prim_i32_ref = &prim_i32;
assert_eq!(
num_u32_ref, prim_i32,
"Failed cross-type: &Number == primitive for {num_u32:?} and {prim_i32:?}"
);
assert_eq!(
prim_i32, num_u32_ref,
"Failed cross-type: primitive == &Number for {prim_i32:?} and {num_u32:?}"
);
assert_eq!(
num_u32_ref, prim_i32_ref,
"Failed cross-type: &Number == &primitive for {num_u32:?} and {prim_i32:?}"
);
assert_eq!(
prim_i32_ref, num_u32_ref,
"Failed cross-type: &primitive == &Number for {prim_i32:?} and {num_u32:?}"
);
let num_i32 = Number::from(42i64);
let prim_u32 = 42u32;
let num_i32_ref = &num_i32;
let prim_u32_ref = &prim_u32;
assert_eq!(
num_i32_ref, prim_u32,
"Failed cross-type: &Number == primitive for {num_i32:?} and {prim_u32:?}"
);
assert_eq!(
prim_u32, num_i32_ref,
"Failed cross-type: primitive == &Number for {prim_u32:?} and {num_i32:?}"
);
assert_eq!(
num_i32_ref, prim_u32_ref,
"Failed cross-type: &Number == &primitive for {num_i32:?} and {prim_u32:?}"
);
assert_eq!(
prim_u32_ref, num_i32_ref,
"Failed cross-type: &primitive == &Number for {prim_u32:?} and {num_i32:?}"
);
let num_u64 = Number::from(42u64);
let prim_i64 = 42i64;
let num_u64_ref = &num_u64;
let prim_i64_ref = &prim_i64;
assert_eq!(
num_u64_ref, prim_i64,
"Failed cross-type: &Number == primitive for {num_u64:?} and {prim_i64:?}"
);
assert_eq!(
prim_i64, num_u64_ref,
"Failed cross-type: primitive == &Number for {prim_i64:?} and {num_u64:?}"
);
assert_eq!(
num_u64_ref, prim_i64_ref,
"Failed cross-type: &Number == &primitive for {num_u64:?} and {prim_i64:?}"
);
assert_eq!(
prim_i64_ref, num_u64_ref,
"Failed cross-type: &primitive == &Number for {prim_i64:?} and {num_u64:?}"
);
let num_i64 = Number::from(42i64);
let prim_u64 = 42u64;
let num_i64_ref = &num_i64;
let prim_u64_ref = &prim_u64;
assert_eq!(
num_i64_ref, prim_u64,
"Failed cross-type: &Number == primitive for {num_i64:?} and {prim_u64:?}"
);
assert_eq!(
prim_u64, num_i64_ref,
"Failed cross-type: primitive == &Number for {prim_u64:?} and {num_i64:?}"
);
assert_eq!(
num_i64_ref, prim_u64_ref,
"Failed cross-type: &Number == &primitive for {num_i64:?} and {prim_u64:?}"
);
assert_eq!(
prim_u64_ref, num_i64_ref,
"Failed cross-type: &primitive == &Number for {prim_u64:?} and {num_i64:?}"
);
let num_f64 = num!(42.0);
let prim_u32_2 = 42u32;
let num_f64_ref = &num_f64;
let prim_u32_2_ref = &prim_u32_2;
assert_eq!(
num_f64_ref, prim_u32_2,
"Failed cross-type: &Number == primitive for {num_f64:?} and {prim_u32_2:?}"
);
assert_eq!(
prim_u32_2, num_f64_ref,
"Failed cross-type: primitive == &Number for {prim_u32_2:?} and {num_f64:?}"
);
assert_eq!(
num_f64_ref, prim_u32_2_ref,
"Failed cross-type: &Number == &primitive for {num_f64:?} and {prim_u32_2:?}"
);
assert_eq!(
prim_u32_2_ref, num_f64_ref,
"Failed cross-type: &primitive == &Number for {prim_u32_2:?} and {num_f64:?}"
);
let num_f64_2 = num!(42.0);
let prim_i32_2 = 42i32;
let num_f64_2_ref = &num_f64_2;
let prim_i32_2_ref = &prim_i32_2;
assert_eq!(
num_f64_2_ref, prim_i32_2,
"Failed cross-type: &Number == primitive for {num_f64_2:?} and {prim_i32_2:?}"
);
assert_eq!(
prim_i32_2, num_f64_2_ref,
"Failed cross-type: primitive == &Number for {prim_i32_2:?} and {num_f64_2:?}"
);
assert_eq!(
num_f64_2_ref, prim_i32_2_ref,
"Failed cross-type: &Number == &primitive for {num_f64_2:?} and {prim_i32_2:?}"
);
assert_eq!(
prim_i32_2_ref, num_f64_2_ref,
"Failed cross-type: &primitive == &Number for {prim_i32_2:?} and {num_f64_2:?}"
);
}
#[test]
fn test_eq_canonical_zero_handling() {
let pos_zero_f64 = num!(0.0);
let neg_zero_f64 = num!(-0.0);
assert_eq!(pos_zero_f64, neg_zero_f64, "+0.0 and -0.0 should be equal");
let zero_i32 = Number::from(0i64);
let zero_u32 = Number::from(0u64);
let zero_i64 = Number::from(0i64);
let zero_u64 = Number::from(0u64);
assert_eq!(
zero_i32, pos_zero_f64,
"I64(0) and F64(0.0) should be equal"
);
assert_eq!(
zero_i32, neg_zero_f64,
"I64(0) and F64(-0.0) should be equal"
);
assert_eq!(
zero_u32, pos_zero_f64,
"U64(0) and F64(0.0) should be equal"
);
assert_eq!(
zero_u32, neg_zero_f64,
"U64(0) and F64(-0.0) should be equal"
);
assert_eq!(
zero_i64, pos_zero_f64,
"I64(0) and F64(0.0) should be equal"
);
assert_eq!(
zero_i64, neg_zero_f64,
"I64(0) and F64(-0.0) should be equal"
);
assert_eq!(
zero_u64, pos_zero_f64,
"U64(0) and F64(0.0) should be equal"
);
assert_eq!(
zero_u64, neg_zero_f64,
"U64(0) and F64(-0.0) should be equal"
);
#[cfg(feature = "decimal")]
{
use rust_decimal::Decimal;
let zero_decimal = Number::from(Decimal::ZERO);
let neg_zero_decimal = Number::from(-Decimal::ZERO);
assert_eq!(
zero_decimal, pos_zero_f64,
"Decimal(0) and F64(0.0) should be equal"
);
assert_eq!(
zero_decimal, neg_zero_f64,
"Decimal(0) and F64(-0.0) should be equal"
);
assert_eq!(
neg_zero_decimal, pos_zero_f64,
"Decimal(-0) and F64(0.0) should be equal"
);
assert_eq!(
neg_zero_decimal, neg_zero_f64,
"Decimal(-0) and F64(-0.0) should be equal"
);
}
}
#[test]
fn test_eq_canonical_nan_handling() {
let nan1 = num!(f64::NAN);
let nan2 = num!(f64::NAN);
assert_eq!(nan1, nan2, "NaN values should be equal to each other");
let finite = num!(42.0);
assert_ne!(nan1, finite, "NaN should not equal finite values");
let pos_inf = num!(f64::INFINITY);
let neg_inf = num!(f64::NEG_INFINITY);
assert_ne!(nan1, pos_inf, "NaN should not equal positive infinity");
assert_ne!(nan1, neg_inf, "NaN should not equal negative infinity");
let zero = num!(0.0);
assert_ne!(nan1, zero, "NaN should not equal zero");
}
#[test]
fn test_eq_canonical_float_comparison_fallback() {
let f1 = num!(42.5);
let f2 = num!(42.5);
let f3 = num!(42.6);
assert_eq!(f1, f2, "Equal floats should be equal");
assert_ne!(f1, f3, "Different floats should not be equal");
let pos_inf1 = num!(f64::INFINITY);
let pos_inf2 = num!(f64::INFINITY);
let neg_inf = num!(f64::NEG_INFINITY);
assert_eq!(pos_inf1, pos_inf2, "Positive infinities should be equal");
assert_ne!(
pos_inf1, neg_inf,
"Positive and negative infinity should not be equal"
);
let small1 = num!(1.0000000000000001);
let small2 = num!(1.0000000000000002);
assert_ne!(small1, small2, "Small float differences should be detected");
}
#[test]
fn test_float64_direct_equality() {
}
#[test]
fn test_float64_direct_hash_consistency() {
}