#![cfg(feature = "dataframe")]
use paft_utils::Decimal128Encode;
const MAX_I128_MANTISSA: i128 = 10_i128.pow(38);
#[cfg(not(feature = "bigdecimal"))]
mod rust_decimal_backend {
use super::{Decimal128Encode, MAX_I128_MANTISSA};
use rust_decimal::Decimal;
#[test]
fn same_scale_small_positive() {
let d = Decimal::from_i128_with_scale(123_456, 3);
assert_eq!(d.try_to_i128_mantissa(3), Some(123_456));
}
#[test]
fn same_scale_small_negative() {
let d = Decimal::from_i128_with_scale(-123_456, 3);
assert_eq!(d.try_to_i128_mantissa(3), Some(-123_456));
}
#[test]
fn same_scale_zero() {
let d = Decimal::from_i128_with_scale(0, 4);
assert_eq!(d.try_to_i128_mantissa(4), Some(0));
}
#[test]
fn same_scale_large_mantissa() {
let m: i128 = 79_228_162_514_264_337_593_543_950_335; let d = Decimal::from_i128_with_scale(m, 5);
assert_eq!(d.try_to_i128_mantissa(5), Some(m));
}
#[test]
fn scale_up_one_to_ten() {
let d = Decimal::from_i128_with_scale(15, 1);
assert_eq!(d.try_to_i128_mantissa(10), Some(15_000_000_000));
}
#[test]
fn scale_down_half_even_round_down_positive() {
let d = Decimal::from_i128_with_scale(125, 2);
assert_eq!(d.try_to_i128_mantissa(1), Some(12));
}
#[test]
fn scale_down_half_even_round_up_positive() {
let d = Decimal::from_i128_with_scale(135, 2);
assert_eq!(d.try_to_i128_mantissa(1), Some(14));
}
#[test]
fn scale_down_half_even_round_down_negative() {
let d = Decimal::from_i128_with_scale(-125, 2);
assert_eq!(d.try_to_i128_mantissa(1), Some(-12));
}
#[test]
fn scale_down_half_even_round_up_negative() {
let d = Decimal::from_i128_with_scale(-135, 2);
assert_eq!(d.try_to_i128_mantissa(1), Some(-14));
}
#[test]
fn scale_down_above_half_rounds_up() {
let d = Decimal::from_i128_with_scale(1_250_001, 6);
assert_eq!(d.try_to_i128_mantissa(1), Some(13));
}
#[test]
fn scale_down_below_half_rounds_down() {
let d = Decimal::from_i128_with_scale(1_249_999, 6);
assert_eq!(d.try_to_i128_mantissa(1), Some(12));
}
#[test]
fn scale_up_overflow_returns_none() {
let m: i128 = 79_228_162_514_264_337_593_543_950_335;
let d = Decimal::from_i128_with_scale(m, 0);
assert_eq!(d.try_to_i128_mantissa(10), None);
}
#[test]
fn rescaled_mantissa_just_below_10pow38_is_accepted() {
let m: i128 = 79_228_162_514_264_337_593_543_950_335;
let d = Decimal::from_i128_with_scale(m, 0);
let got = d.try_to_i128_mantissa(9).expect("should fit");
assert!(got.unsigned_abs() < MAX_I128_MANTISSA.cast_unsigned());
}
#[test]
fn negative_scale_up_overflow_returns_none() {
let m: i128 = -79_228_162_514_264_337_593_543_950_335;
let d = Decimal::from_i128_with_scale(m, 0);
assert_eq!(d.try_to_i128_mantissa(10), None);
}
#[test]
fn target_scale_above_polars_precision_returns_none() {
let d = Decimal::from_i128_with_scale(1, 0);
assert_eq!(d.try_to_i128_mantissa(39), None);
}
}
#[cfg(feature = "bigdecimal")]
mod bigdecimal_backend {
use super::{Decimal128Encode, MAX_I128_MANTISSA};
use bigdecimal::BigDecimal;
use std::str::FromStr;
#[test]
fn same_scale_small_positive() {
let d = BigDecimal::from_str("123.456").unwrap();
assert_eq!(d.try_to_i128_mantissa(3), Some(123_456));
}
#[test]
fn same_scale_small_negative() {
let d = BigDecimal::from_str("-123.456").unwrap();
assert_eq!(d.try_to_i128_mantissa(3), Some(-123_456));
}
#[test]
fn same_scale_zero() {
let d = BigDecimal::from_str("0.0000").unwrap();
assert_eq!(d.try_to_i128_mantissa(4), Some(0));
}
#[test]
fn same_scale_large_mantissa() {
let s = format!("{}", 10_i128.pow(37));
let d = BigDecimal::from_str(&s).unwrap();
assert_eq!(d.try_to_i128_mantissa(0), Some(10_i128.pow(37)));
}
#[test]
fn scale_up_one_to_ten() {
let d = BigDecimal::from_str("1.5").unwrap();
assert_eq!(d.try_to_i128_mantissa(10), Some(15_000_000_000));
}
#[test]
fn scale_down_half_even_round_down_positive() {
let d = BigDecimal::from_str("1.25").unwrap();
assert_eq!(d.try_to_i128_mantissa(1), Some(12));
}
#[test]
fn scale_down_half_even_round_up_positive() {
let d = BigDecimal::from_str("1.35").unwrap();
assert_eq!(d.try_to_i128_mantissa(1), Some(14));
}
#[test]
fn scale_down_half_even_round_down_negative() {
let d = BigDecimal::from_str("-1.25").unwrap();
assert_eq!(d.try_to_i128_mantissa(1), Some(-12));
}
#[test]
fn scale_down_half_even_round_up_negative() {
let d = BigDecimal::from_str("-1.35").unwrap();
assert_eq!(d.try_to_i128_mantissa(1), Some(-14));
}
#[test]
fn scale_down_above_half_rounds_up() {
let d = BigDecimal::from_str("1.250001").unwrap();
assert_eq!(d.try_to_i128_mantissa(1), Some(13));
}
#[test]
fn scale_down_below_half_rounds_down() {
let d = BigDecimal::from_str("1.249999").unwrap();
assert_eq!(d.try_to_i128_mantissa(1), Some(12));
}
#[test]
fn boundary_just_below_10pow38_is_accepted() {
let m = MAX_I128_MANTISSA - 1;
let s = format!("{m}");
let d = BigDecimal::from_str(&s).unwrap();
assert_eq!(d.try_to_i128_mantissa(0), Some(m));
}
#[test]
fn boundary_at_10pow38_is_rejected() {
let s = format!("{MAX_I128_MANTISSA}");
let d = BigDecimal::from_str(&s).unwrap();
assert_eq!(d.try_to_i128_mantissa(0), None);
}
#[test]
fn negative_boundary_just_below_10pow38_is_accepted() {
let m = -(MAX_I128_MANTISSA - 1);
let s = format!("{m}");
let d = BigDecimal::from_str(&s).unwrap();
assert_eq!(d.try_to_i128_mantissa(0), Some(m));
}
#[test]
fn negative_boundary_at_10pow38_is_rejected() {
let s = format!("-{MAX_I128_MANTISSA}");
let d = BigDecimal::from_str(&s).unwrap();
assert_eq!(d.try_to_i128_mantissa(0), None);
}
#[test]
fn zero_at_non_zero_target_scale_succeeds() {
let d = BigDecimal::from_str("0").unwrap();
assert_eq!(d.try_to_i128_mantissa(5), Some(0));
}
#[test]
fn negative_zero_collapses_to_positive_zero() {
let pos = BigDecimal::from_str("0").unwrap();
let neg = BigDecimal::from_str("-0").unwrap();
let pos_m = pos.try_to_i128_mantissa(3).expect("+0 encodes");
let neg_m = neg.try_to_i128_mantissa(3).expect("-0 encodes");
assert_eq!(pos_m, 0);
assert_eq!(neg_m, 0);
assert_eq!(pos_m, neg_m);
}
#[test]
fn target_scale_above_polars_precision_returns_none() {
let d = BigDecimal::from_str("1").unwrap();
assert_eq!(d.try_to_i128_mantissa(39), None);
}
}