use std::convert::TryFrom;
use uninum::{Number, num};
#[cfg(test)]
mod literal_parsing {
use super::*;
#[test]
fn test_integer_literals_basic() {
assert_eq!(num!(0), Number::from(0_i64));
assert_eq!(num!(1), Number::from(1_i64));
assert_eq!(num!(42), Number::from(42_i64));
assert_eq!(num!(-1), Number::from(-1_i64));
assert_eq!(num!(-42), Number::from(-42_i64));
assert_eq!(num!(2147483647), Number::from(2147483647_i64)); assert_eq!(num!(-2147483648), Number::from(-2147483648_i64)); }
#[test]
fn test_integer_literals_with_underscores() {
assert_eq!(num!(1_000), Number::from(1000_i64));
assert_eq!(num!(1_000_000), Number::from(1000000_i64));
assert_eq!(num!(-1_000_000), Number::from(-1000000_i64));
}
#[test]
fn test_integer_literals_different_bases() {
assert_eq!(num!(0xFF), Number::from(255_i64));
assert_eq!(num!(0xff), Number::from(255_i64));
assert_eq!(num!(0xDEADBEEFu32), Number::from(0xDEADBEEF_u64));
assert_eq!(num!(0b1010), Number::from(10_i64));
assert_eq!(num!(0b11111111), Number::from(255_i64));
assert_eq!(num!(0o777), Number::from(511_i64));
assert_eq!(num!(0o644), Number::from(420_i64));
}
#[test]
fn test_float_literals_basic() {
let pi = num!(3.16);
let e = num!(2.72);
let half = num!(0.5);
let one = num!(1.0);
#[cfg(feature = "decimal")]
{
assert!(pi.try_get_decimal().is_some());
assert!(e.try_get_decimal().is_some());
assert!(half.try_get_decimal().is_some());
assert!(one.try_get_decimal().is_some());
}
#[cfg(not(feature = "decimal"))]
{
assert!(pi.try_get_f64().is_some());
assert!(e.try_get_f64().is_some());
assert!(half.try_get_f64().is_some());
assert!(one.try_get_f64().is_some());
}
}
#[test]
fn test_float_literals_various_formats() {
#[cfg(feature = "decimal")]
{
assert!(num!(0.).try_get_decimal().is_some());
assert!(num!(1.).try_get_decimal().is_some());
assert!(num!(0.5).try_get_decimal().is_some());
assert!(num!(123.).try_get_decimal().is_some());
assert!(num!(123.456).try_get_decimal().is_some());
assert!(num!(-0.).try_get_f64().is_some());
assert!(num!(-1.).try_get_decimal().is_some());
assert!(num!(-0.5).try_get_decimal().is_some());
assert!(num!(-123.456).try_get_decimal().is_some());
}
}
#[test]
fn test_float_literals_precision() {
#[cfg(feature = "decimal")]
{
use rust_decimal::Decimal;
let precise = num!(0.123_456_789_012_345_68);
if let Some(d) = precise.try_get_decimal() {
let expected = Decimal::try_from("0.12345678901234568").unwrap();
assert_eq!(**d, expected);
} else {
panic!("Expected Decimal");
}
let many_decimals = num!(1.111_111_111_111_111_2);
assert!(many_decimals.try_get_decimal().is_some());
}
}
#[test]
fn test_scientific_notation_positive_exponent() {
#[cfg(feature = "decimal")]
{
assert!(num!(1e2).try_get_decimal().is_some());
assert!(num!(1E2).try_get_decimal().is_some());
assert!(num!(1.5e2).try_get_decimal().is_some());
assert!(num!(2.5e2).try_get_decimal().is_some());
assert!(num!(1e3).try_get_decimal().is_some());
assert!(num!(1.5e4).try_get_decimal().is_some());
}
#[cfg(not(feature = "decimal"))]
{
assert!(num!(1e2).try_get_f64().is_some());
assert!(num!(1E2).try_get_f64().is_some());
assert!(num!(1.5e2).try_get_f64().is_some());
assert!(num!(2.5e2).try_get_f64().is_some());
assert!(num!(1e3).try_get_f64().is_some());
assert!(num!(1.5e4).try_get_f64().is_some());
}
}
#[test]
fn test_scientific_notation_negative_exponent() {
let small = num!(1e-2);
let tiny = num!(1.5e-10);
#[cfg(feature = "decimal")]
{
assert!(small.try_get_decimal().is_some());
assert!(tiny.try_get_decimal().is_some());
}
#[cfg(not(feature = "decimal"))]
{
assert!(small.try_get_f64().is_some());
assert!(tiny.try_get_f64().is_some());
}
}
#[test]
fn test_scientific_notation_edge_cases() {
#[cfg(feature = "decimal")]
{
assert!(num!(0e0).try_get_f64().is_some());
assert!(num!(0e10).try_get_f64().is_some());
assert!(num!(0e-10).try_get_f64().is_some());
let tiny = num!(1.23e-45);
assert!(tiny.try_get_decimal().is_some() || tiny.try_get_f64().is_some());
}
#[cfg(not(feature = "decimal"))]
{
assert!(num!(0e0).try_get_f64().is_some());
assert!(num!(0e10).try_get_f64().is_some());
assert!(num!(0e-10).try_get_f64().is_some());
assert!(num!(1.23e-45).try_get_f64().is_some());
}
}
#[test]
fn test_string_literal_parsing() {
assert_eq!(Number::try_from("42").unwrap(), Number::from(42_u64));
assert_eq!(Number::try_from("-42").unwrap(), Number::from(-42_i64));
assert_eq!(Number::try_from("1000").unwrap(), Number::from(1000_u64));
assert_eq!(Number::try_from("70000").unwrap(), Number::from(70000_u64));
#[cfg(feature = "decimal")]
{
assert!(matches!(
Number::try_from("3.16").unwrap(),
n if n.try_get_decimal().is_some()
));
assert!(matches!(
Number::try_from("0.123456789012345678901234567890").unwrap(),
n if n.try_get_decimal().is_some()
));
}
assert!(Number::try_from("42u32").is_err());
assert!(Number::try_from("42i64").is_err());
assert!(Number::try_from("3.16f64").is_err());
}
}
#[cfg(test)]
mod type_suffix_tests {
use super::*;
#[test]
fn test_integer_type_suffixes() {
assert_eq!(num!(42u32), Number::from(42_u64));
assert_eq!(num!(42u64), Number::from(42_u64));
assert_eq!(num!(42i32), Number::from(42_i64));
assert_eq!(num!(42i64), Number::from(42_i64));
assert_eq!(num!(-42i32), Number::from(-42_i64));
assert_eq!(num!(-42i64), Number::from(-42_i64));
}
#[test]
fn test_float_type_suffixes() {
assert_eq!(num!(3.16f64), num!(3.16f64));
assert_eq!(num!(0.0f64), num!(0.0f64));
assert_eq!(num!(-3.16f64), num!(-3.16f64));
}
#[test]
fn test_type_suffix_with_underscores() {
assert_eq!(num!(1_000u32), Number::from(1000_u64));
assert_eq!(num!(1_000_000i64), Number::from(1000000_i64));
assert_eq!(num!(3.131_592f64), num!(3.131592f64));
}
#[test]
fn test_type_suffix_with_bases() {
assert_eq!(num!(0xFFu32), Number::from(255_u64));
assert_eq!(num!(0b1010i32), Number::from(10_i64));
assert_eq!(num!(0o777u32), Number::from(511_u64));
}
}
#[cfg(test)]
mod variable_and_expression_tests {
use super::*;
#[test]
fn test_variable_conversion() {
let u32_var: u32 = 70000;
assert_eq!(num!(u32_var), Number::from(70000_u64));
let i32_var: i32 = -70000;
assert_eq!(num!(i32_var), Number::from(-70000_i64));
let u64_var: u64 = 1_000_000_000;
assert_eq!(num!(u64_var), Number::from(1_000_000_000_u64));
let i64_var: i64 = -1_000_000_000;
assert_eq!(num!(i64_var), Number::from(-1_000_000_000_i64));
let f64_var: f64 = 2.72;
assert_eq!(num!(f64_var), num!(2.72f64));
let u8_var: u8 = 42;
assert_eq!(num!(u8_var), Number::from(42_u64));
let i8_var: i8 = -42;
assert_eq!(num!(i8_var), Number::from(-42_i64));
let u16_var: u16 = 1000;
assert_eq!(num!(u16_var), Number::from(1000_u64));
let i16_var: i16 = -1000;
assert_eq!(num!(i16_var), Number::from(-1000_i64));
}
#[test]
fn test_simple_expressions() {
assert_eq!(num!(20u32 + 22u32), Number::from(42_u64));
assert_eq!(num!(100u32 - 50u32), Number::from(50_u64));
assert_eq!(num!(6i32 * 7i32), Number::from(42_i64));
assert_eq!(num!(84u32 / 2u32), Number::from(42_u64));
assert_eq!(num!(10.0f64 / 4.0f64), num!(2.5f64));
}
#[test]
fn test_complex_expressions() {
assert_eq!(num!((10u32 + 5u32) * 2u32), Number::from(30_u64));
assert_eq!(num!((100i32 - 50i32) / 2i32), Number::from(25_i64));
let x = 16u32;
assert_eq!(num!(x.pow(2)), Number::from(256_u64));
let condition = true;
assert_eq!(
num!(if condition { 42u32 } else { 0u32 }),
Number::from(42_u64)
);
}
#[test]
fn test_const_expressions() {
const CONST_VALUE: i32 = 42;
assert_eq!(num!(CONST_VALUE), Number::from(42_i64));
const CONST_EXPR: u64 = 100 * 100;
assert_eq!(num!(CONST_EXPR), Number::from(10000_u64));
}
}
#[cfg(test)]
mod edge_case_tests {
use super::*;
#[test]
fn test_zero_representations() {
assert_eq!(num!(0), Number::from(0_i64));
assert_eq!(num!(-0), Number::from(0_i64));
#[cfg(feature = "decimal")]
{
assert!(num!(0.0).try_get_decimal().is_some());
assert!(num!(0.).try_get_decimal().is_some());
assert!(num!(-0.0).try_get_f64().is_some());
assert!(num!(-0.).try_get_f64().is_some());
}
assert_eq!(num!(0u32), Number::from(0_u64));
assert_eq!(num!(0i64), Number::from(0_i64));
assert_eq!(num!(0.0f64), num!(0.0f64));
}
#[test]
fn test_negative_zero_preservation() {
let neg_zero = num!(-0.0);
assert!(neg_zero.try_get_f64().is_some(), "num!(-0.0) should be F64");
let f64_value = neg_zero.try_get_f64().unwrap();
assert!(
f64_value.is_sign_negative(),
"num!(-0.0) should preserve negative sign"
);
assert_eq!(f64_value, -0.0);
let neg_zero_dot = num!(-0.);
assert!(
neg_zero_dot.try_get_f64().is_some(),
"num!(-0.) should be F64"
);
let f64_value_dot = neg_zero_dot.try_get_f64().unwrap();
assert!(
f64_value_dot.is_sign_negative(),
"num!(-0.) should preserve negative sign"
);
#[cfg(feature = "decimal")]
{
let pos_zero = num!(0.0);
assert!(
pos_zero.try_get_decimal().is_some(),
"num!(0.0) should be Decimal when feature enabled"
);
}
let neg_zero_from = Number::from(-0.0f64);
assert!(neg_zero_from.try_get_f64().is_some());
assert!(neg_zero_from.try_get_f64().unwrap().is_sign_negative());
}
#[test]
fn test_boundary_values() {
assert_eq!(num!(4294967295u32), Number::from(4294967295_u64));
assert_eq!(num!(0u32), Number::from(0_u64));
assert_eq!(num!(2147483647i32), Number::from(2147483647_i64));
assert_eq!(num!(-2147483648i32), Number::from(-2147483648_i64));
assert_eq!(
num!(18446744073709551615u64),
Number::from(18446744073709551615_u64)
);
assert_eq!(
num!(9223372036854775807i64),
Number::from(9223372036854775807_i64)
);
assert_eq!(
num!(-9223372036854775808i64),
Number::from(-9223372036854775808_i64)
);
}
#[test]
fn test_very_small_floats() {
#[cfg(feature = "decimal")]
{
assert!(num!(0.000000000000000001).try_get_decimal().is_some());
assert!(matches!(
num!(0.000000000000000000000000001),
n if n.try_get_decimal().is_some()
));
assert!(num!(1e-28).try_get_decimal().is_some());
assert!(num!(-0.000000000000000001).try_get_decimal().is_some());
assert!(matches!(
num!(-0.000000000000000000000000001),
n if n.try_get_decimal().is_some()
));
assert!(num!(-1e-28).try_get_decimal().is_some());
}
}
#[test]
fn test_very_large_floats() {
#[cfg(feature = "decimal")]
{
assert!(matches!(
num!(79228162514264337593543950335.0),
n if n.try_get_decimal().is_some()
));
assert!(num!(1e50).try_get_f64().is_some());
assert!(matches!(
num!(123456789012345678901234567890123456789.0),
n if n.try_get_f64().is_some()
));
}
}
#[test]
fn test_special_float_constants() {
let pos_inf = num!(f64::INFINITY);
assert!(pos_inf.try_get_f64().is_some());
if let Some(f) = pos_inf.try_get_f64() {
assert!(f.is_infinite() && f.is_sign_positive());
}
let neg_inf = num!(f64::NEG_INFINITY);
assert!(neg_inf.try_get_f64().is_some());
if let Some(f) = neg_inf.try_get_f64() {
assert!(f.is_infinite() && f.is_sign_negative());
}
let nan = num!(f64::NAN);
assert!(nan.try_get_f64().is_some());
if let Some(f) = nan.try_get_f64() {
assert!(f.is_nan());
}
let min = num!(f64::MIN);
assert!(min.try_get_f64().is_some());
let max = num!(f64::MAX);
assert!(max.try_get_f64().is_some());
let epsilon = num!(f64::EPSILON);
assert!(epsilon.try_get_f64().is_some());
}
}
#[cfg(test)]
mod macro_behavior_tests {
use super::*;
#[test]
fn test_macro_hygiene() {
let a = num!(1);
let b = num!(2);
let c = num!(3);
assert_eq!(a, Number::from(1_i64));
assert_eq!(b, Number::from(2_i64));
assert_eq!(c, Number::from(3_i64));
let sum = num!(10) + num!(20) + num!(30);
assert_eq!(sum, Number::from(60_i64));
}
#[test]
fn test_macro_in_different_contexts() {
fn takes_number(n: Number) -> Number {
n
}
assert_eq!(takes_number(num!(42)), Number::from(42_i64));
match num!(100) {
n if n.try_get_i64() == Some(100) => assert_eq!(n.try_get_i64().unwrap(), 100),
_ => panic!("Wrong type"),
}
let numbers = [num!(1), num!(2), num!(3)];
assert_eq!(numbers[0], Number::from(1_i64));
assert_eq!(numbers[1], Number::from(2_i64));
assert_eq!(numbers[2], Number::from(3_i64));
struct Container {
value: Number,
}
let container = Container { value: num!(42) };
assert_eq!(container.value, Number::from(42_i64));
}
#[test]
fn test_macro_with_shadowed_variables() {
let x = 10u32;
assert_eq!(num!(x), Number::from(10_u64));
{
let x = 20u64;
assert_eq!(num!(x), Number::from(20_u64));
}
assert_eq!(num!(x), Number::from(10_u64));
}
#[test]
fn test_consistency_with_from_trait() {
assert_eq!(num!(42u32), Number::from(42u32));
assert_eq!(num!(42i32), Number::from(42i32));
assert_eq!(num!(42u64), Number::from(42u64));
assert_eq!(num!(-100i32), Number::from(-100i32));
assert_eq!(num!(3.16f64), Number::from(3.16f64));
let x = 100u32;
assert_eq!(num!(x), Number::from(x));
let u8_val: u8 = 42;
assert_eq!(num!(u8_val), Number::from(u8_val));
let i16_val: i16 = -100;
assert_eq!(num!(i16_val), Number::from(i16_val));
}
}
#[cfg(test)]
mod feature_dependent_tests {
use super::*;
#[cfg(feature = "decimal")]
#[test]
fn test_decimal_creation() {
use rust_decimal::Decimal;
let pi = num!(3.16);
assert!(pi.try_get_decimal().is_some());
if let Some(d) = pi.try_get_decimal() {
let expected = Decimal::try_from(3.16).unwrap();
assert_eq!(*d.as_ref(), expected);
}
let precise = num!(0.123_456_789_012_345_68);
if let Some(d) = precise.try_get_decimal() {
let expected = Decimal::try_from("0.12345678901234568").unwrap();
assert_eq!(*d.as_ref(), expected);
}
}
#[cfg(feature = "decimal")]
#[test]
fn test_decimal_limits() {
let max_decimal = num!(79228162514264337593543950335.0);
assert!(max_decimal.try_get_decimal().is_some());
let min_decimal = num!(-79228162514264337593543950335.0);
assert!(min_decimal.try_get_decimal().is_some());
let tiny = num!(0.0000000000000000000000000001);
assert!(tiny.try_get_decimal().is_some());
}
#[cfg(not(feature = "decimal"))]
#[test]
fn test_no_decimal_fallback() {
let pi = num!(3.16);
assert!(pi.try_get_f64().is_some());
let precise = num!(0.123_456_789_012_345_68);
assert!(precise.try_get_f64().is_some());
let sci = num!(1.23e-10);
assert!(sci.try_get_f64().is_some());
}
#[cfg(feature = "decimal")]
#[test]
fn test_decimal_overflow_to_f64() {
let huge = num!(1e100);
assert!(huge.try_get_f64().is_some());
let huge_str =
Number::try_from("99999999999999999999999999999999999999999999999.0").unwrap();
assert!(huge_str.try_get_f64().is_some());
}
}
#[cfg(test)]
mod error_cases_and_panics {
use super::*;
#[test]
fn test_invalid_string_parsing() {
assert!(Number::try_from("not_a_number").is_err());
assert!(Number::try_from("").is_err());
assert!(Number::try_from("12.34.56").is_err()); assert!(Number::try_from("42u7").is_err()); assert!(Number::try_from("1.2.3.4").is_err());
assert!(Number::try_from("abc123").is_err());
}
}
#[cfg(test)]
mod arithmetic_with_macro {
use super::*;
#[test]
fn test_arithmetic_operations() {
assert_eq!(num!(10) + num!(20), Number::from(30_i64));
assert_eq!(num!(50) - num!(20), Number::from(30_i64));
assert_eq!(num!(6) * num!(7), Number::from(42_i64));
assert_eq!(num!(84) / num!(2), Number::from(42_i64));
assert_eq!(num!(10) % num!(3), Number::from(1_i64));
}
#[test]
fn test_mixed_type_arithmetic() {
let a = num!(10i64); let b = num!(20u64); let result = a + b;
#[cfg(feature = "decimal")]
{
assert!(result.try_get_decimal().is_some());
assert_eq!(result.to_string(), "30");
}
#[cfg(not(feature = "decimal"))]
{
match result {
ref n
if n.try_get_u64().is_some()
|| n.try_get_i64().is_some()
|| n.try_get_f64().is_some() =>
{
assert_eq!(result.to_string(), "30");
}
_ => panic!(
"Unexpected result type for mixed integer arithmetic: {:?}",
result
),
}
}
let result = num!(3.16f64) * num!(2);
match result {
ref n if n.try_get_f64().is_some() => {}
#[cfg(feature = "decimal")]
ref n if n.try_get_decimal().is_some() => {}
_ => panic!("Expected float or decimal result, got {result:?}"),
}
}
#[test]
fn test_chained_operations() {
let result = num!(1) + num!(2) + num!(3) + num!(4);
assert_eq!(result, Number::from(10_i64));
let complex = (num!(100) - num!(50)) * num!(2) / num!(5);
assert_eq!(complex, Number::from(20_i64));
}
#[cfg(feature = "decimal")]
#[test]
fn test_decimal_arithmetic() {
let a = num!(0.1);
let b = num!(0.2);
let sum = a + b;
assert!(sum.try_get_decimal().is_some());
use rust_decimal::Decimal;
if let Some(d) = sum.try_get_decimal() {
let expected = Decimal::try_from("0.3").unwrap();
assert_eq!(*d.as_ref(), expected);
}
}
}
#[cfg(test)]
mod comparison_tests {
use super::*;
#[test]
fn test_equality_comparisons() {
assert_eq!(num!(42), num!(42));
assert_ne!(num!(42), num!(43));
assert_eq!(num!(3.16f64), num!(3.16f64));
assert_ne!(num!(3.16f64), num!(3.15f64));
#[cfg(feature = "decimal")]
{
assert_eq!(num!(0.1), num!(0.1));
assert_ne!(num!(0.1), num!(0.2));
}
}
#[test]
fn test_ordering_comparisons() {
assert!(num!(10) < num!(20));
assert!(num!(20) > num!(10));
assert!(num!(10) <= num!(10));
assert!(num!(10) >= num!(10));
assert!(num!(3.16f64) > num!(3.15f64));
assert!(num!(-1.0f64) < num!(0.0f64));
}
#[test]
fn test_mixed_type_comparisons() {
assert_eq!(num!(42), 42);
assert_eq!(42, num!(42));
assert!(num!(10) < 20);
assert!(5 < num!(10));
assert_eq!(num!(42u32), num!(42i32));
}
}
#[cfg(test)]
mod comprehensive_coverage {
use super::*;
#[test]
fn test_all_primitive_types_coverage() {
let _: Number = num!(0u32);
let _: Number = num!(0i32);
let _: Number = num!(0u64);
let _: Number = num!(0i64);
let _: Number = num!(0.0f64);
let _: Number = num!(0.0f64);
let u8_val: u8 = 1;
let i8_val: i8 = -1;
let u16_val: u16 = 1000;
let i16_val: i16 = -1000;
let u32_val: u32 = 100000;
let i32_val: i32 = -100000;
let u64_val: u64 = 10000000000;
let i64_val: i64 = -10000000000;
let f64_val: f64 = 2.5;
let _: Number = num!(u8_val);
let _: Number = num!(i8_val);
let _: Number = num!(u16_val);
let _: Number = num!(i16_val);
let _: Number = num!(u32_val);
let _: Number = num!(i32_val);
let _: Number = num!(u64_val);
let _: Number = num!(i64_val);
let _: Number = num!(f64_val);
}
#[test]
fn test_macro_in_const_context() {
let a = Number::from(42_i64);
let b = num!(42);
assert_eq!(a, b);
}
#[test]
fn test_debug_and_display() {
let n = num!(42);
let debug_str = format!("{n:?}");
assert!(debug_str.contains("I64(42)"));
let display_str = format!("{n}");
assert_eq!(display_str, "42");
#[cfg(feature = "decimal")]
{
let d = num!(3.16);
let display_str = format!("{d}");
assert!(display_str.starts_with("3.16"));
}
}
}