decimal.rs (3711B)
1 mod common; 2 3 use core::str::FromStr; 4 5 use radroots_core::{Decimal, decimal::Error}; 6 7 #[test] 8 fn display_normalizes_trailing_zeros() { 9 let d = Decimal::from_str("1.2300").unwrap(); 10 assert_eq!(d.to_string(), "1.23"); 11 } 12 13 #[test] 14 fn scale_reflects_input_precision() { 15 let d = Decimal::from_str("1.2300").unwrap(); 16 assert_eq!(d.scale(), 4); 17 } 18 19 #[test] 20 fn to_u64_exact_requires_whole_number() { 21 let whole = common::dec("42.0"); 22 let frac = common::dec("42.5"); 23 assert_eq!(whole.to_u64_exact(), Some(42)); 24 assert_eq!(frac.to_u64_exact(), None); 25 } 26 27 #[test] 28 fn from_f64_display_roundtrips_reasonably() { 29 let d = Decimal::from_f64_display(1.25).unwrap(); 30 let v = d.to_f64_lossy().expect("f64 conversion"); 31 assert!((v - 1.25).abs() < 1e-12); 32 } 33 34 #[test] 35 fn parsing_normalizes_zero_and_owns_parse_errors() { 36 let zero = Decimal::from_str("-0.000").unwrap(); 37 assert_eq!(zero, Decimal::ZERO); 38 assert_eq!(zero.scale(), 0); 39 assert_eq!( 40 Decimal::from_str("not-a-decimal"), 41 Err(Error::InvalidFormat) 42 ); 43 assert_eq!( 44 Decimal::from_str_exact("0.00000000000000000000000000001"), 45 Err(Error::OutOfRange) 46 ); 47 } 48 49 #[test] 50 fn checked_arithmetic_reports_overflow_and_zero_division() { 51 assert_eq!( 52 Decimal::MAX.checked_add(Decimal::ONE), 53 Err(Error::ArithmeticOverflow) 54 ); 55 assert_eq!( 56 Decimal::MIN.checked_sub(Decimal::ONE), 57 Err(Error::ArithmeticOverflow) 58 ); 59 assert_eq!( 60 Decimal::MAX.checked_mul(Decimal::from(2u32)), 61 Err(Error::ArithmeticOverflow) 62 ); 63 assert_eq!( 64 Decimal::ONE.checked_div(Decimal::ZERO), 65 Err(Error::DivisionByZero) 66 ); 67 } 68 69 #[test] 70 fn exact_rescale_rejects_rounding_and_unrepresentable_scales() { 71 let mut exact = Decimal::from_str("1.2300").unwrap(); 72 exact.try_rescale_exact(2).unwrap(); 73 assert_eq!(exact.scale(), 2); 74 assert_eq!(exact, common::dec("1.23")); 75 76 let mut would_round = common::dec("1.25"); 77 assert_eq!(would_round.try_rescale_exact(1), Err(Error::PrecisionLoss)); 78 assert_eq!(would_round, common::dec("1.25")); 79 80 assert_eq!( 81 would_round.try_rescale_exact(Decimal::MAX_SCALE + 1), 82 Err(Error::ScaleOutOfRange) 83 ); 84 } 85 86 #[test] 87 fn display_parse_roundtrips_normalized_values() { 88 for input in ["0", "-42.1250", "999999.000001", "0.00000001"] { 89 let value = Decimal::from_str(input).unwrap(); 90 let reparsed = Decimal::from_str(&value.to_string()).unwrap(); 91 assert_eq!(reparsed, value); 92 } 93 } 94 95 #[test] 96 fn float_conversion_rejects_non_finite_values() { 97 assert_eq!( 98 Decimal::from_f64_display(f64::NAN), 99 Err(Error::InvalidFormat) 100 ); 101 assert_eq!( 102 Decimal::from_f64_display(f64::INFINITY), 103 Err(Error::InvalidFormat) 104 ); 105 } 106 107 #[test] 108 fn from_str_exact_and_primitive_conversion_paths_are_exercised() { 109 let exact = Decimal::from_str_exact("42.000").unwrap(); 110 assert_eq!(exact, common::dec("42")); 111 112 let from_u32 = Decimal::from(7u32); 113 let from_i32 = Decimal::from(-2i32); 114 let from_u64 = Decimal::from(11u64); 115 let from_i64 = Decimal::from(-9i64); 116 assert_eq!(from_u32, common::dec("7")); 117 assert_eq!(from_i32, common::dec("-2")); 118 assert_eq!(from_u64, common::dec("11")); 119 assert_eq!(from_i64, common::dec("-9")); 120 } 121 122 #[cfg(feature = "serde")] 123 #[test] 124 fn serde_deserialize_error_paths_are_exercised() { 125 let parse_err = serde_json::from_str::<Decimal>("\"not-a-decimal\"").unwrap_err(); 126 assert!(!parse_err.to_string().is_empty()); 127 let non_string_err = serde_json::from_str::<Decimal>("123").unwrap_err(); 128 assert!(non_string_err.to_string().contains("invalid type")); 129 }