diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/rust_decimal/tests | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/rust_decimal/tests')
-rw-r--r-- | third_party/rust/rust_decimal/tests/decimal_tests.rs | 1633 |
1 files changed, 1633 insertions, 0 deletions
diff --git a/third_party/rust/rust_decimal/tests/decimal_tests.rs b/third_party/rust/rust_decimal/tests/decimal_tests.rs new file mode 100644 index 0000000000..4517254e35 --- /dev/null +++ b/third_party/rust/rust_decimal/tests/decimal_tests.rs @@ -0,0 +1,1633 @@ +use num_traits::{Signed, ToPrimitive, Zero}; + +use rust_decimal::{Decimal, RoundingStrategy}; + +use std::{ + cmp::{Ordering, Ordering::*}, + str::FromStr, +}; + +// Parsing + +#[test] +fn it_creates_a_new_negative_decimal() { + let a = Decimal::new(-100, 2); + assert_eq!(a.is_sign_negative(), true); + assert_eq!(a.scale(), 2); + assert_eq!("-1.00", a.to_string()); +} + +#[test] +fn it_creates_a_new_decimal_using_numeric_boundaries() { + let a = Decimal::new(i64::max_value(), 2); + assert_eq!(a.is_sign_negative(), false); + assert_eq!(a.scale(), 2); + assert_eq!("92233720368547758.07", a.to_string()); + + let b = Decimal::new(i64::min_value(), 2); + assert_eq!(b.is_sign_negative(), true); + assert_eq!(b.scale(), 2); + assert_eq!("-92233720368547758.08", b.to_string()); +} + +#[test] +fn it_parses_empty_string() { + assert!(Decimal::from_str("").is_err()); + assert!(Decimal::from_str(" ").is_err()); +} + +#[test] +fn it_parses_positive_int_string() { + let a = Decimal::from_str("233").unwrap(); + assert_eq!(a.is_sign_negative(), false); + assert_eq!(a.scale(), 0); + assert_eq!("233", a.to_string()); +} + +#[test] +fn it_parses_negative_int_string() { + let a = Decimal::from_str("-233").unwrap(); + assert_eq!(a.is_sign_negative(), true); + assert_eq!(a.scale(), 0); + println!("to_string"); + assert_eq!("-233", a.to_string()); +} + +#[test] +fn it_parses_positive_float_string() { + let a = Decimal::from_str("233.323223").unwrap(); + assert_eq!(a.is_sign_negative(), false); + assert_eq!(a.scale(), 6); + assert_eq!("233.323223", a.to_string()); +} + +#[test] +fn it_parses_negative_float_string() { + let a = Decimal::from_str("-233.43343").unwrap(); + assert_eq!(a.is_sign_negative(), true); + assert_eq!(a.scale(), 5); + assert_eq!("-233.43343", a.to_string()); +} + +#[test] +fn it_parses_positive_tiny_float_string() { + let a = Decimal::from_str(".000001").unwrap(); + assert_eq!(a.is_sign_negative(), false); + assert_eq!(a.scale(), 6); + assert_eq!("0.000001", a.to_string()); +} + +#[test] +fn it_parses_negative_tiny_float_string() { + let a = Decimal::from_str("-0.000001").unwrap(); + assert_eq!(a.is_sign_negative(), true); + assert_eq!(a.scale(), 6); + assert_eq!("-0.000001", a.to_string()); +} + +#[test] +fn it_parses_big_integer_string() { + let a = Decimal::from_str("79228162514264337593543950330").unwrap(); + assert_eq!("79228162514264337593543950330", a.to_string()); +} + +#[test] +fn it_parses_big_float_string() { + let a = Decimal::from_str("79.228162514264337593543950330").unwrap(); + assert_eq!("79.228162514264337593543950330", a.to_string()); +} + +#[test] +fn it_can_serialize_deserialize() { + let a = Decimal::from_str("12.3456789").unwrap(); + let bytes = a.serialize(); + let b = Decimal::deserialize(bytes); + assert_eq!("12.3456789", b.to_string()); +} + +// Formatting + +#[test] +fn it_formats() { + let a = Decimal::from_str("233.323223").unwrap(); + assert_eq!(format!("{}", a), "233.323223"); + assert_eq!(format!("{:.9}", a), "233.323223000"); + assert_eq!(format!("{:.0}", a), "233"); + assert_eq!(format!("{:.2}", a), "233.32"); + assert_eq!(format!("{:010.2}", a), "0000233.32"); + assert_eq!(format!("{:0<10.2}", a), "233.320000"); +} +#[test] +fn it_formats_neg() { + let a = Decimal::from_str("-233.323223").unwrap(); + assert_eq!(format!("{}", a), "-233.323223"); + assert_eq!(format!("{:.9}", a), "-233.323223000"); + assert_eq!(format!("{:.0}", a), "-233"); + assert_eq!(format!("{:.2}", a), "-233.32"); + assert_eq!(format!("{:010.2}", a), "-000233.32"); + assert_eq!(format!("{:0<10.2}", a), "-233.32000"); +} +#[test] +fn it_formats_small() { + let a = Decimal::from_str("0.2223").unwrap(); + assert_eq!(format!("{}", a), "0.2223"); + assert_eq!(format!("{:.9}", a), "0.222300000"); + assert_eq!(format!("{:.0}", a), "0"); + assert_eq!(format!("{:.2}", a), "0.22"); + assert_eq!(format!("{:010.2}", a), "0000000.22"); + assert_eq!(format!("{:0<10.2}", a), "0.22000000"); +} +#[test] +fn it_formats_small_leading_zeros() { + let a = Decimal::from_str("0.0023554701772169").unwrap(); + assert_eq!(format!("{}", a), "0.0023554701772169"); + assert_eq!(format!("{:.9}", a), "0.002355470"); + assert_eq!(format!("{:.0}", a), "0"); + assert_eq!(format!("{:.2}", a), "0.00"); + assert_eq!(format!("{:010.2}", a), "0000000.00"); + assert_eq!(format!("{:0<10.2}", a), "0.00000000"); +} +#[test] +fn it_formats_small_neg() { + let a = Decimal::from_str("-0.2223").unwrap(); + assert_eq!(format!("{}", a), "-0.2223"); + assert_eq!(format!("{:.9}", a), "-0.222300000"); + assert_eq!(format!("{:.0}", a), "-0"); + assert_eq!(format!("{:.2}", a), "-0.22"); + assert_eq!(format!("{:010.2}", a), "-000000.22"); + assert_eq!(format!("{:0<10.2}", a), "-0.2200000"); +} +#[test] +fn it_formats_zero() { + let a = Decimal::from_str("0").unwrap(); + assert_eq!(format!("{}", a), "0"); + assert_eq!(format!("{:.9}", a), "0.000000000"); + assert_eq!(format!("{:.0}", a), "0"); + assert_eq!(format!("{:.2}", a), "0.00"); + assert_eq!(format!("{:010.2}", a), "0000000.00"); + assert_eq!(format!("{:0<10.2}", a), "0.00000000"); +} +#[test] +fn it_formats_int() { + let a = Decimal::from_str("5").unwrap(); + assert_eq!(format!("{}", a), "5"); + assert_eq!(format!("{:.9}", a), "5.000000000"); + assert_eq!(format!("{:.0}", a), "5"); + assert_eq!(format!("{:.2}", a), "5.00"); + assert_eq!(format!("{:010.2}", a), "0000005.00"); + assert_eq!(format!("{:0<10.2}", a), "5.00000000"); +} + +// Negation +#[test] +fn it_negates_decimals() { + fn neg(a: &str, b: &str) { + let a = Decimal::from_str(a).unwrap(); + let result = -a; + assert_eq!(b, result.to_string(), "- {}", a.to_string()); + } + + let tests = &[ + ("1", "-1"), + ("2", "-2"), + ("2454495034", "-2454495034"), + (".1", "-0.1"), + ("11.815126050420168067226890757", "-11.815126050420168067226890757"), + ]; + + for &(a, b) in tests { + neg(a, b); + } +} + +// Addition + +#[test] +fn it_adds_decimals() { + fn add(a: &str, b: &str, c: &str) { + let a = Decimal::from_str(a).unwrap(); + let b = Decimal::from_str(b).unwrap(); + let result = a + b; + assert_eq!(c, result.to_string(), "{} + {}", a.to_string(), b.to_string()); + let result = b + a; + assert_eq!(c, result.to_string(), "{} + {}", b.to_string(), a.to_string()); + } + + let tests = &[ + ("2", "3", "5"), + ("2454495034", "3451204593", "5905699627"), + ("24544.95034", ".3451204593", "24545.2954604593"), + (".1", ".1", "0.2"), + (".10", ".1", "0.20"), + (".1", "-.1", "0.0"), + ("0", "1.001", "1.001"), + ("2", "-3", "-1"), + ("-2", "3", "1"), + ("-2", "-3", "-5"), + ("3", "-2", "1"), + ("-3", "2", "-1"), + ("1.234", "2.4567", "3.6907"), + ( + "11.815126050420168067226890757", + "0.6386554621848739495798319328", + "12.453781512605042016806722690", + ), + ( + "-11.815126050420168067226890757", + "0.6386554621848739495798319328", + "-11.176470588235294117647058824", + ), + ( + "11.815126050420168067226890757", + "-0.6386554621848739495798319328", + "11.176470588235294117647058824", + ), + ( + "-11.815126050420168067226890757", + "-0.6386554621848739495798319328", + "-12.453781512605042016806722690", + ), + ( + "11815126050420168067226890757", + "0.4386554621848739495798319328", + "11815126050420168067226890757", + ), + ( + "-11815126050420168067226890757", + "0.4386554621848739495798319328", + "-11815126050420168067226890757", + ), + ( + "11815126050420168067226890757", + "-0.4386554621848739495798319328", + "11815126050420168067226890757", + ), + ( + "-11815126050420168067226890757", + "-0.4386554621848739495798319328", + "-11815126050420168067226890757", + ), + ( + "0.0872727272727272727272727272", + "843.65000000", + "843.7372727272727272727272727", + ), + ( + "7314.6229858868828353570724702", + "1000", + // Overflow causes this to round + "8314.622985886882835357072470", + ), + ( + "108053.27500000000000000000000", + "0.00000000000000000000000", + "108053.27500000000000000000000", + ), + ( + "108053.27500000000000000000000", + // This zero value has too high precision and will be trimmed + "0.000000000000000000000000", + "108053.27500000000000000000000", + ), + ( + "108053.27500000000000000000000", + // This value has too high precision and will be rounded + "0.000000000000000000000001", + "108053.27500000000000000000000", + ), + ( + "108053.27500000000000000000000", + // This value has too high precision and will be rounded + "0.000000000000000000000005", + "108053.27500000000000000000001", + ), + ( + "8097370036018690744.2590371109596744091", + "3807285637671831400.15346897797550749555", + "11904655673690522144.412506089", + ), + ]; + for &(a, b, c) in tests { + add(a, b, c); + } +} + +#[test] +fn it_can_addassign() { + let mut a = Decimal::from_str("1.01").unwrap(); + let b = Decimal::from_str("0.99").unwrap(); + a += b; + assert_eq!("2.00", a.to_string()); + + a += &b; + assert_eq!("2.99", a.to_string()); + + let mut c = &mut a; + c += b; + assert_eq!("3.98", a.to_string()); + + let mut c = &mut a; + c += &b; + assert_eq!("4.97", a.to_string()); +} + +// Subtraction + +#[test] +fn it_subtracts_decimals() { + fn sub(a: &str, b: &str, c: &str) { + let a = Decimal::from_str(a).unwrap(); + let b = Decimal::from_str(b).unwrap(); + let result = a - b; + assert_eq!(c, result.to_string(), "{} - {}", a.to_string(), b.to_string()); + } + + let tests = &[ + ("2", "3", "-1"), + ("3451204593", "2323322332", "1127882261"), + ("24544.95034", ".3451204593", "24544.6052195407"), + (".1", ".1", "0.0"), + (".1", "-.1", "0.2"), + ("1.001", "0", "1.001"), + ("2", "-3", "5"), + ("-2", "3", "-5"), + ("-2", "-3", "1"), + ("3", "-2", "5"), + ("-3", "2", "-5"), + ("1.234", "2.4567", "-1.2227"), + ("844.13000000", "843.65000000", "0.48000000"), + ("79228162514264337593543950335", "79228162514264337593543950335", "0"), // 0xFFFF_FFFF_FFFF_FFFF_FFF_FFFF - 0xFFFF_FFFF_FFFF_FFFF_FFF_FFFF + ("79228162514264337593543950335", "0", "79228162514264337593543950335"), + ("79228162514264337593543950335", "79228162514264337593543950333", "2"), + ("4951760157141521099596496896", "1", "4951760157141521099596496895"), // 0x1000_0000_0000_0000_0000_0000 - 1 = 0x0FFF_FFFF_FFFF_FFFF_FFF_FFFF + ("79228162514264337593543950334", "79228162514264337593543950335", "-1"), + ("1", "4951760157141521099596496895", "-4951760157141521099596496894"), + ("18446744073709551615", "-18446744073709551615", "36893488147419103230"), // 0xFFFF_FFFF_FFFF_FFFF - -0xFFFF_FFFF_FFFF_FFFF + ]; + for &(a, b, c) in tests { + sub(a, b, c); + } +} + +#[test] +fn it_can_subassign() { + let mut a = Decimal::from_str("1.01").unwrap(); + let b = Decimal::from_str("0.51").unwrap(); + a -= b; + assert_eq!("0.50", a.to_string()); + + a -= &b; + assert_eq!("-0.01", a.to_string()); + + let mut c = &mut a; + c -= b; + assert_eq!("-0.52", a.to_string()); + + let mut c = &mut a; + c -= &b; + assert_eq!("-1.03", a.to_string()); +} + +// Multiplication + +#[test] +fn it_multiplies_decimals() { + fn mul(a: &str, b: &str, c: &str) { + let a = Decimal::from_str(a).unwrap(); + let b = Decimal::from_str(b).unwrap(); + let result = a * b; + assert_eq!(c, result.to_string(), "{} * {}", a.to_string(), b.to_string()); + let result = b * a; + assert_eq!(c, result.to_string(), "{} * {}", b.to_string(), a.to_string()); + } + + let tests = &[ + ("2", "3", "6"), + ("2454495034", "3451204593", "8470964534836491162"), + ("24544.95034", ".3451204593", "8470.964534836491162"), + (".1", ".1", "0.01"), + ("0", "1.001", "0"), + ("2", "-3", "-6"), + ("-2", "3", "-6"), + ("-2", "-3", "6"), + ("1", "2.01", "2.01"), + ("1.0", "2.01", "2.010"), // Scale is always additive + ( + "0.00000000000000001", + "0.00000000000000001", + "0.0000000000000000000000000000", + ), + ("0.0000000000000000000000000001", "0.0000000000000000000000000001", "0"), + ( + "0.6386554621848739495798319328", + "11.815126050420168067226890757", + "7.5457947885036367488171739292", + ), + ( + "2123456789012345678901234567.8", + "11.815126050420168067226890757", + "25088909624801327937270048761", + ), + ( + "2123456789012345678901234567.8", + "-11.815126050420168067226890757", + "-25088909624801327937270048761", + ), + ( + "2.1234567890123456789012345678", + "2.1234567890123456789012345678", + "4.5090687348026215523554336227", + ), + ( + "0.48000000", + "0.1818181818181818181818181818", + "0.0872727272727272727272727272", + ), + ]; + for &(a, b, c) in tests { + mul(a, b, c); + } +} + +#[test] +#[should_panic] +fn it_panics_when_multiply_with_overflow() { + let a = Decimal::from_str("2000000000000000000001").unwrap(); + let b = Decimal::from_str("3000000000000000000001").unwrap(); + let _ = a * b; +} + +#[test] +fn it_can_mulassign() { + let mut a = Decimal::from_str("1.25").unwrap(); + let b = Decimal::from_str("0.01").unwrap(); + + a *= b; + assert_eq!("0.0125", a.to_string()); + + a *= &b; + assert_eq!("0.000125", a.to_string()); + + let mut c = &mut a; + c *= b; + assert_eq!("0.00000125", a.to_string()); + + let mut c = &mut a; + c *= &b; + assert_eq!("0.0000000125", a.to_string()); +} + +// Division + +#[test] +fn it_divides_decimals() { + fn div(a: &str, b: &str, c: &str) { + let a = Decimal::from_str(a).unwrap(); + let b = Decimal::from_str(b).unwrap(); + let result = a / b; + assert_eq!(c, result.to_string(), "{} / {}", a.to_string(), b.to_string()); + } + + let tests = &[ + ("6", "3", "2"), + ("10", "2", "5"), + ("2.2", "1.1", "2"), + ("-2.2", "-1.1", "2"), + ("12.88", "5.6", "2.3"), + ("1023427554493", "43432632", "23563.562864276795382789603908"), + ("10000", "3", "3333.3333333333333333333333333"), + ("2", "3", "0.6666666666666666666666666667"), + ("1", "3", "0.3333333333333333333333333333"), + ("-2", "3", "-0.6666666666666666666666666667"), + ("2", "-3", "-0.6666666666666666666666666667"), + ("-2", "-3", "0.6666666666666666666666666667"), + ("1234.567890123456789012345678", "1.234567890123456789012345678", "1000"), + ]; + for &(a, b, c) in tests { + div(a, b, c); + } +} + +#[test] +#[should_panic] +fn it_can_divide_by_zero() { + let a = Decimal::from_str("2").unwrap(); + let _ = a / Decimal::zero(); +} + +#[test] +fn it_can_divassign() { + let mut a = Decimal::from_str("1.25").unwrap(); + let b = Decimal::from_str("0.01").unwrap(); + + a /= b; + assert_eq!("125", a.to_string()); + + a /= &b; + assert_eq!("12500", a.to_string()); + + let mut c = &mut a; + c /= b; + assert_eq!("1250000", a.to_string()); + + let mut c = &mut a; + c /= &b; + assert_eq!("125000000", a.to_string()); +} + +// Modulus and Remainder are not the same thing! +// https://math.stackexchange.com/q/801962/82277 + +#[test] +fn it_rems_decimals() { + fn rem(a: &str, b: &str, c: &str) { + let a = Decimal::from_str(a).unwrap(); + let b = Decimal::from_str(b).unwrap(); + // a = qb + r + let result = a % b; + assert_eq!(c, result.to_string(), "{} % {}", a.to_string(), b.to_string()); + } + + let tests = &[ + ("2", "3", "2"), + ("-2", "3", "-2"), + ("2", "-3", "2"), + ("-2", "-3", "-2"), + ("6", "3", "0"), + ("42.2", "11.9", "6.5"), + ("2.1", "3", "2.1"), + ("2", "3.1", "2"), + ("2.0", "3.1", "2.0"), + ("4", "3.1", "0.9"), + ]; + for &(a, b, c) in tests { + rem(a, b, c); + } +} + +#[test] +fn it_can_remassign() { + let mut a = Decimal::from_str("5").unwrap(); + let b = Decimal::from_str("2").unwrap(); + + a %= b; + assert_eq!("1", a.to_string()); + + a %= &b; + assert_eq!("1", a.to_string()); + + let mut c = &mut a; + c %= b; + assert_eq!("1", a.to_string()); + + let mut c = &mut a; + c %= &b; + assert_eq!("1", a.to_string()); +} + +#[test] +fn it_eqs_decimals() { + fn eq(a: &str, b: &str, c: bool) { + let a = Decimal::from_str(a).unwrap(); + let b = Decimal::from_str(b).unwrap(); + assert_eq!(c, a.eq(&b), "{} == {}", a.to_string(), b.to_string()); + assert_eq!(c, b.eq(&a), "{} == {}", b.to_string(), a.to_string()); + } + + let tests = &[ + ("1", "1", true), + ("1", "-1", false), + ("1", "1.00", true), + ("1.2345000000000", "1.2345", true), + ("1.0000000000000000000000000000", "1.0000000000000000000000000000", true), + ( + "1.0000000000000000000000000001", + "1.0000000000000000000000000000", + false, + ), + ]; + for &(a, b, c) in tests { + eq(a, b, c); + } +} + +#[test] +fn it_cmps_decimals() { + fn cmp(a: &str, b: &str, c: Ordering) { + let a = Decimal::from_str(a).unwrap(); + let b = Decimal::from_str(b).unwrap(); + assert_eq!(c, a.cmp(&b), "{} {:?} {}", a.to_string(), c, b.to_string()); + } + + let tests = &[ + ("1", "1", Equal), + ("1", "-1", Greater), + ("1", "1.00", Equal), + ("1.2345000000000", "1.2345", Equal), + ( + "1.0000000000000000000000000001", + "1.0000000000000000000000000000", + Greater, + ), + ("1.0000000000000000000000000000", "1.0000000000000000000000000001", Less), + ("-1", "100", Less), + ("-100", "1", Less), + ("0", "0.5", Less), + ("0.5", "0", Greater), + ("100", "0.0098", Greater), + ("1000000000000000", "999000000000000.0001", Greater), + ("2.0001", "2.0001", Equal), + ( + "11.815126050420168067226890757", + "0.6386554621848739495798319328", + Greater, + ), + ("0.6386554621848739495798319328", "11.815126050420168067226890757", Less), + ("-0.5", "-0.01", Less), + ("-0.5", "-0.1", Less), + ("-0.01", "-0.5", Greater), + ("-0.1", "-0.5", Greater), + ]; + for &(a, b, c) in tests { + cmp(a, b, c); + } +} + +#[test] +fn it_floors_decimals() { + let tests = &[ + ("1", "1"), + ("1.00", "1"), + ("1.2345", "1"), + ("-1", "-1"), + ("-1.00", "-1"), + ("-1.2345", "-2"), + ]; + for &(a, expected) in tests { + let a = Decimal::from_str(a).unwrap(); + assert_eq!(expected, a.floor().to_string(), "Failed flooring {}", a); + } +} + +#[test] +fn it_ceils_decimals() { + let tests = &[ + ("1", "1"), + ("1.00", "1"), + ("1.2345", "2"), + ("-1", "-1"), + ("-1.00", "-1"), + ("-1.2345", "-1"), + ]; + for &(a, expected) in tests { + let a = Decimal::from_str(a).unwrap(); + assert_eq!(expected, a.ceil().to_string(), "Failed ceiling {}", a); + } +} + +#[test] +fn it_finds_max_of_two() { + let tests = &[("1", "1", "1"), ("2", "1", "2"), ("1", "2", "2")]; + for &(a, b, expected) in tests { + let a = Decimal::from_str(a).unwrap(); + let b = Decimal::from_str(b).unwrap(); + assert_eq!(expected, a.max(b).to_string()); + } +} + +#[test] +fn it_finds_min_of_two() { + let tests = &[("1", "1", "1"), ("2", "1", "1"), ("1", "2", "1")]; + for &(a, b, expected) in tests { + let a = Decimal::from_str(a).unwrap(); + let b = Decimal::from_str(b).unwrap(); + assert_eq!(expected, a.min(b).to_string()); + } +} + +#[test] +fn test_max_compares() { + let x = "225.33543601344182".parse::<Decimal>().unwrap(); + let y = Decimal::max_value(); + assert!(x < y); + assert!(y > x); + assert_ne!(y, x); +} + +#[test] +fn test_min_compares() { + let x = "225.33543601344182".parse::<Decimal>().unwrap(); + let y = Decimal::min_value(); + assert!(x > y); + assert!(y < x); + assert_ne!(y, x); +} + +#[test] +fn it_can_parse_from_i32() { + use num_traits::FromPrimitive; + + let tests = &[ + (0i32, "0"), + (1i32, "1"), + (-1i32, "-1"), + (i32::max_value(), "2147483647"), + (i32::min_value(), "-2147483648"), + ]; + for &(input, expected) in tests { + let parsed = Decimal::from_i32(input).unwrap(); + assert_eq!( + expected, + parsed.to_string(), + "expected {} does not match parsed {}", + expected, + parsed + ); + assert_eq!( + input.to_string(), + parsed.to_string(), + "i32 to_string {} does not match parsed {}", + input, + parsed + ); + } +} + +#[test] +fn it_can_parse_from_i64() { + use num_traits::FromPrimitive; + + let tests = &[ + (0i64, "0"), + (1i64, "1"), + (-1i64, "-1"), + (i64::max_value(), "9223372036854775807"), + (i64::min_value(), "-9223372036854775808"), + ]; + for &(input, expected) in tests { + let parsed = Decimal::from_i64(input).unwrap(); + assert_eq!( + expected, + parsed.to_string(), + "expected {} does not match parsed {}", + expected, + parsed + ); + assert_eq!( + input.to_string(), + parsed.to_string(), + "i64 to_string {} does not match parsed {}", + input, + parsed + ); + } +} + +#[test] +fn it_can_round_to_2dp() { + let a = Decimal::from_str("6.12345").unwrap(); + let b = (Decimal::from_str("100").unwrap() * a).round() / Decimal::from_str("100").unwrap(); + assert_eq!("6.12", b.to_string()); +} + +#[test] +fn it_can_round_using_bankers_rounding() { + let tests = &[ + ("6.12345", 2, "6.12"), + ("6.126", 2, "6.13"), + ("-6.126", 2, "-6.13"), + ("6.5", 0, "6"), + ("7.5", 0, "8"), + ("1.2250", 2, "1.22"), + ("1.2252", 2, "1.23"), + ("1.2249", 2, "1.22"), + ("6.1", 2, "6.1"), + ("0.0000", 2, "0.00"), + ("0.6666666666666666666666666666", 2, "0.67"), + ("1.40", 0, "1"), + ("2.60", 0, "3"), + ("2.1234567890123456789012345678", 27, "2.123456789012345678901234568"), + ]; + for &(input, dp, expected) in tests { + let a = Decimal::from_str(input).unwrap(); + let b = a.round_dp_with_strategy(dp, RoundingStrategy::BankersRounding); + assert_eq!(expected, b.to_string()); + } +} + +#[test] +fn it_can_round_complex_numbers_using_bankers_rounding() { + // Issue #71 + let rate = Decimal::new(19, 2); // 0.19 + let one = Decimal::new(1, 0); // 1 + let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832 + let part = part.round_dp_with_strategy(2, RoundingStrategy::BankersRounding); // 0.16 + assert_eq!("0.16", part.to_string()); +} + +#[test] +fn it_can_round_using_round_half_up() { + let tests = &[ + ("0", 0, "0"), + ("1.234", 3, "1.234"), + ("1.12", 5, "1.12"), + ("6.34567", 2, "6.35"), + ("6.5", 0, "7"), + ("12.49", 0, "12"), + ("0.6666666666666666666666666666", 2, "0.67"), + ("1.40", 0, "1"), + ("2.60", 0, "3"), + ("2.1234567890123456789012345678", 27, "2.123456789012345678901234568"), + ]; + for &(input, dp, expected) in tests { + let a = Decimal::from_str(input).unwrap(); + let b = a.round_dp_with_strategy(dp, RoundingStrategy::RoundHalfUp); + assert_eq!(expected, b.to_string()); + } +} + +#[test] +fn it_can_round_complex_numbers_using_round_half_up() { + // Issue #71 + let rate = Decimal::new(19, 2); // 0.19 + let one = Decimal::new(1, 0); // 1 + let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832 + let part = part.round_dp_with_strategy(2, RoundingStrategy::RoundHalfUp); // 0.16 + assert_eq!("0.16", part.to_string()); +} + +#[test] +fn it_can_round_using_round_half_down() { + let tests = &[ + ("0", 0, "0"), + ("1.234", 3, "1.234"), + ("1.12", 5, "1.12"), + ("6.34567", 2, "6.35"), + ("6.51", 0, "7"), + ("12.5", 0, "12"), + ("0.6666666666666666666666666666", 2, "0.67"), + ("1.40", 0, "1"), + ("2.60", 0, "3"), + ("2.1234567890123456789012345678", 27, "2.123456789012345678901234568"), + ]; + for &(input, dp, expected) in tests { + let a = Decimal::from_str(input).unwrap(); + let b = a.round_dp_with_strategy(dp, RoundingStrategy::RoundHalfDown); + assert_eq!(expected, b.to_string()); + } +} + +#[test] +fn it_can_round_complex_numbers_using_round_half_down() { + // Issue #71 + let rate = Decimal::new(19, 2); // 0.19 + let one = Decimal::new(1, 0); // 1 + let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832 + let part = part.round_dp_with_strategy(2, RoundingStrategy::RoundHalfDown); // 0.16 + assert_eq!("0.16", part.to_string()); +} + +#[test] +fn it_can_round_to_2dp_using_explicit_function() { + let a = Decimal::from_str("6.12345").unwrap(); + let b = a.round_dp(2u32); + assert_eq!("6.12", b.to_string()); +} + +#[test] +fn it_can_round_up_to_2dp_using_explicit_function() { + let a = Decimal::from_str("6.126").unwrap(); + let b = a.round_dp(2u32); + assert_eq!("6.13", b.to_string()); +} + +#[test] +fn it_can_round_down_to_2dp_using_explicit_function() { + let a = Decimal::from_str("-6.126").unwrap(); + let b = a.round_dp(2u32); + assert_eq!("-6.13", b.to_string()); +} + +#[test] +fn it_can_round_down_using_bankers_rounding() { + let a = Decimal::from_str("6.5").unwrap(); + let b = a.round_dp(0u32); + assert_eq!("6", b.to_string()); +} + +#[test] +fn it_can_round_up_using_bankers_rounding() { + let a = Decimal::from_str("7.5").unwrap(); + let b = a.round_dp(0u32); + assert_eq!("8", b.to_string()); +} + +#[test] +fn it_can_round_correctly_using_bankers_rounding_1() { + let a = Decimal::from_str("1.2250").unwrap(); + let b = a.round_dp(2u32); + assert_eq!("1.22", b.to_string()); +} + +#[test] +fn it_can_round_correctly_using_bankers_rounding_2() { + let a = Decimal::from_str("1.2251").unwrap(); + let b = a.round_dp(2u32); + assert_eq!("1.23", b.to_string()); +} + +#[test] +fn it_can_round_down_when_required() { + let a = Decimal::from_str("1.2249").unwrap(); + let b = a.round_dp(2u32); + assert_eq!("1.22", b.to_string()); +} + +#[test] +fn it_can_round_to_2dp_using_explicit_function_without_changing_value() { + let a = Decimal::from_str("6.1").unwrap(); + let b = a.round_dp(2u32); + assert_eq!("6.1", b.to_string()); +} + +#[test] +fn it_can_round_zero() { + let a = Decimal::from_str("0.0000").unwrap(); + let b = a.round_dp(2u32); + assert_eq!("0.00", b.to_string()); +} + +#[test] +fn it_can_round_large_decimals() { + let a = Decimal::from_str("0.6666666666666666666666666666").unwrap(); + let b = a.round_dp(2u32); + assert_eq!("0.67", b.to_string()); +} + +#[test] +fn it_can_round_simple_numbers_down() { + let a = Decimal::from_str("1.40").unwrap(); + let b = a.round_dp(0u32); + assert_eq!("1", b.to_string()); +} + +#[test] +fn it_can_round_simple_numbers_up() { + let a = Decimal::from_str("2.60").unwrap(); + let b = a.round_dp(0u32); + assert_eq!("3", b.to_string()); +} + +#[test] +fn it_can_round_simple_numbers_with_high_precision() { + let a = Decimal::from_str("2.1234567890123456789012345678").unwrap(); + let b = a.round_dp(27u32); + assert_eq!("2.123456789012345678901234568", b.to_string()); +} + +#[test] +fn it_can_round_complex_numbers() { + // Issue #71 + let rate = Decimal::new(19, 2); // 0.19 + let one = Decimal::new(1, 0); // 1 + let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832 + let part = part.round_dp(2); // 0.16 + assert_eq!("0.16", part.to_string()); +} + +#[test] +fn it_can_round_down() { + let a = Decimal::new(470, 3).round_dp_with_strategy(1, RoundingStrategy::RoundDown); + assert_eq!("0.4", a.to_string()); +} + +#[test] +fn it_only_rounds_down_when_needed() { + let a = Decimal::new(400, 3).round_dp_with_strategy(1, RoundingStrategy::RoundDown); + assert_eq!("0.4", a.to_string()); +} + +#[test] +fn it_can_round_up() { + let a = Decimal::new(320, 3).round_dp_with_strategy(1, RoundingStrategy::RoundUp); + assert_eq!("0.4", a.to_string()); +} + +#[test] +fn it_only_rounds_up_when_needed() { + let a = Decimal::new(300, 3).round_dp_with_strategy(1, RoundingStrategy::RoundUp); + assert_eq!("0.3", a.to_string()); +} + +#[test] +fn it_can_trunc() { + let tests = &[("1.00000000000000000000", "1"), ("1.000000000000000000000001", "1")]; + + for &(value, expected) in tests { + let value = Decimal::from_str(value).unwrap(); + let expected = Decimal::from_str(expected).unwrap(); + let trunc = value.trunc(); + assert_eq!(expected.to_string(), trunc.to_string()); + } +} + +#[test] +fn it_can_fract() { + let tests = &[ + ("1.00000000000000000000", "0.00000000000000000000"), + ("1.000000000000000000000001", "0.000000000000000000000001"), + ]; + + for &(value, expected) in tests { + let value = Decimal::from_str(value).unwrap(); + let expected = Decimal::from_str(expected).unwrap(); + let fract = value.fract(); + assert_eq!(expected.to_string(), fract.to_string()); + } +} + +#[test] +fn it_can_normalize() { + let tests = &[ + ("1.00000000000000000000", "1"), + ("1.10000000000000000000000", "1.1"), + ("1.00010000000000000000000", "1.0001"), + ("1", "1"), + ("1.1", "1.1"), + ("1.0001", "1.0001"), + ("-0", "0"), + ("-0.0", "0"), + ("-0.010", "-0.01"), + ("0.0", "0"), + ]; + + for &(value, expected) in tests { + let value = Decimal::from_str(value).unwrap(); + let expected = Decimal::from_str(expected).unwrap(); + let normalized = value.normalize(); + assert_eq!(expected.to_string(), normalized.to_string()); + } +} + +#[test] +fn it_can_return_the_max_value() { + assert_eq!("79228162514264337593543950335", Decimal::max_value().to_string()); +} + +#[test] +fn it_can_return_the_min_value() { + assert_eq!("-79228162514264337593543950335", Decimal::min_value().to_string()); +} + +#[test] +fn it_can_go_from_and_into() { + let d = Decimal::from_str("5").unwrap(); + let di8 = 5u8.into(); + let di32 = 5i32.into(); + let disize = 5isize.into(); + let di64 = 5i64.into(); + let du8 = 5u8.into(); + let du32 = 5u32.into(); + let dusize = 5usize.into(); + let du64 = 5u64.into(); + + assert_eq!(d, di8); + assert_eq!(di8, di32); + assert_eq!(di32, disize); + assert_eq!(disize, di64); + assert_eq!(di64, du8); + assert_eq!(du8, du32); + assert_eq!(du32, dusize); + assert_eq!(dusize, du64); +} + +#[test] +fn it_converts_to_f64() { + assert_eq!(5f64, Decimal::from_str("5").unwrap().to_f64().unwrap()); + assert_eq!(-5f64, Decimal::from_str("-5").unwrap().to_f64().unwrap()); + assert_eq!(0.1f64, Decimal::from_str("0.1").unwrap().to_f64().unwrap()); + assert_eq!(0f64, Decimal::from_str("0.0").unwrap().to_f64().unwrap()); + assert_eq!(0f64, Decimal::from_str("-0.0").unwrap().to_f64().unwrap()); + assert_eq!( + 0.25e-11f64, + Decimal::from_str("0.0000000000025").unwrap().to_f64().unwrap(), + ); + assert_eq!( + 1e6f64, + Decimal::from_str("1000000.0000000000025").unwrap().to_f64().unwrap() + ); + assert_eq!( + 0.25e-25_f64, + Decimal::from_str("0.000000000000000000000000025") + .unwrap() + .to_f64() + .unwrap(), + ); + assert_eq!( + 2.1234567890123456789012345678_f64, + Decimal::from_str("2.1234567890123456789012345678") + .unwrap() + .to_f64() + .unwrap(), + ); + + assert_eq!( + None, + // Cannot be represented in an f64 + Decimal::from_str("21234567890123456789012345678").unwrap().to_f64(), + ); +} + +#[test] +fn it_converts_to_i64() { + assert_eq!(5i64, Decimal::from_str("5").unwrap().to_i64().unwrap()); + assert_eq!(-5i64, Decimal::from_str("-5").unwrap().to_i64().unwrap()); + assert_eq!(5i64, Decimal::from_str("5.12345").unwrap().to_i64().unwrap()); + assert_eq!(-5i64, Decimal::from_str("-5.12345").unwrap().to_i64().unwrap()); + assert_eq!( + 0x7FFF_FFFF_FFFF_FFFF, + Decimal::from_str("9223372036854775807").unwrap().to_i64().unwrap() + ); + assert_eq!(None, Decimal::from_str("92233720368547758089").unwrap().to_i64()); +} + +#[test] +fn it_converts_to_u64() { + assert_eq!(5u64, Decimal::from_str("5").unwrap().to_u64().unwrap()); + assert_eq!(None, Decimal::from_str("-5").unwrap().to_u64()); + assert_eq!(5u64, Decimal::from_str("5.12345").unwrap().to_u64().unwrap()); + assert_eq!( + 0xFFFF_FFFF_FFFF_FFFF, + Decimal::from_str("18446744073709551615").unwrap().to_u64().unwrap() + ); + assert_eq!(None, Decimal::from_str("18446744073709551616").unwrap().to_u64()); +} + +#[test] +fn it_converts_from_f32() { + fn from_f32(f: f32) -> Option<Decimal> { + num_traits::FromPrimitive::from_f32(f) + } + + assert_eq!("1", from_f32(1f32).unwrap().to_string()); + assert_eq!("0", from_f32(0f32).unwrap().to_string()); + assert_eq!("0.12345", from_f32(0.12345f32).unwrap().to_string()); + assert_eq!( + "0.12345678", + from_f32(0.1234567800123456789012345678f32).unwrap().to_string() + ); + assert_eq!( + "0.12345679", + from_f32(0.12345678901234567890123456789f32).unwrap().to_string() + ); + assert_eq!("0", from_f32(0.00000000000000000000000000001f32).unwrap().to_string()); + + assert!(from_f32(std::f32::NAN).is_none()); + assert!(from_f32(std::f32::INFINITY).is_none()); + + // These both overflow + assert!(from_f32(std::f32::MAX).is_none()); + assert!(from_f32(std::f32::MIN).is_none()); +} + +#[test] +fn it_converts_from_f64() { + fn from_f64(f: f64) -> Option<Decimal> { + num_traits::FromPrimitive::from_f64(f) + } + + assert_eq!("1", from_f64(1f64).unwrap().to_string()); + assert_eq!("0", from_f64(0f64).unwrap().to_string()); + assert_eq!("0.12345", from_f64(0.12345f64).unwrap().to_string()); + assert_eq!( + "0.1234567890123456", + from_f64(0.1234567890123456089012345678f64).unwrap().to_string() + ); + assert_eq!( + "0.1234567890123457", + from_f64(0.12345678901234567890123456789f64).unwrap().to_string() + ); + assert_eq!("0", from_f64(0.00000000000000000000000000001f64).unwrap().to_string()); + assert_eq!("0.6927", from_f64(0.6927f64).unwrap().to_string()); + assert_eq!("0.00006927", from_f64(0.00006927f64).unwrap().to_string()); + assert_eq!("0.000000006927", from_f64(0.000000006927f64).unwrap().to_string()); + + assert!(from_f64(std::f64::NAN).is_none()); + assert!(from_f64(std::f64::INFINITY).is_none()); + + // These both overflow + assert!(from_f64(std::f64::MAX).is_none()); + assert!(from_f64(std::f64::MIN).is_none()); +} + +#[test] +fn it_handles_simple_underflow() { + // Issue #71 + let rate = Decimal::new(19, 2); // 0.19 + let one = Decimal::new(1, 0); // 1 + let part = rate / (rate + one); // 0.19 / (0.19 + 1) = 0.1596638655462184873949579832 + let result = one * part; + assert_eq!("0.1596638655462184873949579832", result.to_string()); + + // 169 * 0.1596638655462184873949579832 = 26.983193277310924 + let result = part * Decimal::new(169, 0); + assert_eq!("26.983193277310924369747899161", result.to_string()); + let result = Decimal::new(169, 0) * part; + assert_eq!("26.983193277310924369747899161", result.to_string()); +} + +#[test] +fn it_can_parse_highly_significant_numbers() { + let tests = &[ + ("11.111111111111111111111111111", "11.111111111111111111111111111"), + ("11.11111111111111111111111111111", "11.111111111111111111111111111"), + ("11.1111111111111111111111111115", "11.111111111111111111111111112"), + ("115.111111111111111111111111111", "115.11111111111111111111111111"), + ("1115.11111111111111111111111111", "1115.1111111111111111111111111"), + ("11.1111111111111111111111111195", "11.111111111111111111111111120"), + ("99.9999999999999999999999999995", "100.00000000000000000000000000"), + ("-11.1111111111111111111111111195", "-11.111111111111111111111111120"), + ("-99.9999999999999999999999999995", "-100.00000000000000000000000000"), + ("3.1415926535897932384626433832", "3.1415926535897932384626433832"), + ( + "8808257419827262908.5944405087133154018", + "8808257419827262908.594440509", + ), + ( + "8097370036018690744.2590371109596744091", + "8097370036018690744.259037111", + ), + ( + "8097370036018690744.2590371149596744091", + "8097370036018690744.259037115", + ), + ( + "8097370036018690744.2590371159596744091", + "8097370036018690744.259037116", + ), + ]; + for &(value, expected) in tests { + assert_eq!(expected, Decimal::from_str(value).unwrap().to_string()); + } +} + +#[test] +fn it_can_parse_alternative_formats() { + let tests = &[ + ("1_000", "1000"), + ("1_000_000", "1000000"), + ("10_000_000", "10000000"), + ("100_000", "100000"), + // At the moment, we'll accept this + ("1_____________0", "10"), + ]; + for &(value, expected) in tests { + assert_eq!(expected, Decimal::from_str(value).unwrap().to_string()); + } +} + +#[test] +fn it_can_parse_fractional_numbers_with_underscore_separators() { + let a = Decimal::from_str("0.1_23_456").unwrap(); + assert_eq!(a.is_sign_negative(), false); + assert_eq!(a.scale(), 6); + assert_eq!("0.123456", a.to_string()); +} + +#[test] +fn it_can_parse_numbers_with_underscore_separators_before_decimal_point() { + let a = Decimal::from_str("1_234.56").unwrap(); + assert_eq!(a.is_sign_negative(), false); + assert_eq!(a.scale(), 2); + assert_eq!("1234.56", a.to_string()); +} + +#[test] +fn it_can_parse_numbers_and_round_correctly_with_underscore_separators_before_decimal_point() { + let tests = &[ + ( + "8_097_370_036_018_690_744.2590371159596744091", + "8097370036018690744.259037116", + ), + ( + "8097370036018690744.259_037_115_959_674_409_1", + "8097370036018690744.259037116", + ), + ( + "8_097_370_036_018_690_744.259_037_115_959_674_409_1", + "8097370036018690744.259037116", + ), + ]; + for &(value, expected) in tests { + assert_eq!(expected, Decimal::from_str(value).unwrap().to_string()); + } +} + +#[test] +fn it_can_reject_invalid_formats() { + let tests = &["_1", "1.0.0", "10_00.0_00.0"]; + for &value in tests { + assert!( + Decimal::from_str(value).is_err(), + "This succeeded unexpectedly: {}", + value + ); + } +} + +#[test] +fn it_can_reject_large_numbers_with_panic() { + let tests = &[ + // The maximum number supported is 79,228,162,514,264,337,593,543,950,335 + "79228162514264337593543950336", + "79228162514264337593543950337", + "79228162514264337593543950338", + "79228162514264337593543950339", + "79228162514264337593543950340", + ]; + for &value in tests { + assert!( + Decimal::from_str(value).is_err(), + "This succeeded unexpectedly: {}", + value + ); + } +} + +#[test] +fn it_can_parse_individual_parts() { + let pi = Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28); + assert_eq!(pi.to_string(), "3.1415926535897932384626433832"); +} + +#[test] +fn it_can_parse_scientific_notation() { + let tests = &[ + ("9.7e-7", "0.00000097"), + ("9e-7", "0.0000009"), + ("1.2e10", "12000000000"), + ("1.2e+10", "12000000000"), + ("12e10", "120000000000"), + ("9.7E-7", "0.00000097"), + ]; + + for &(value, expected) in tests { + assert_eq!(expected, Decimal::from_scientific(value).unwrap().to_string()); + } +} + +#[test] +fn it_can_parse_different_radix() { + use num_traits::Num; + + let tests = &[ + // Input, Radix, Success, to_string() + ("123", 10, true, "123"), + ("123", 8, true, "83"), + ("123", 16, true, "291"), + ("abc", 10, false, ""), + ("abc", 16, true, "2748"), + ("78", 10, true, "78"), + ("78", 8, false, ""), + ("101", 2, true, "5"), + // Parse base 2 + ("1111_1111_1111_1111_1111_1111_1111_1111", 2, true, "4294967295"), + // Max supported value + ( + "1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_\ + 1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111", + 2, + true, + &Decimal::max_value().to_string(), + ), + // We limit to 28 dp + ( + "843.6500000000000000000000000000", + 10, + true, + "843.6500000000000000000000000", + ), + ]; + + for &(input, radix, success, expected) in tests { + let result = Decimal::from_str_radix(input, radix); + assert_eq!( + success, + result.is_ok(), + "Failed to parse: {} radix {}: {:?}", + input, + radix, + result.err() + ); + if result.is_ok() { + assert_eq!( + expected, + result.unwrap().to_string(), + "Original input: {} radix {}", + input, + radix + ); + } + } +} + +#[test] +fn it_can_calculate_signum() { + let tests = &[("123", 1), ("-123", -1), ("0", 0)]; + + for &(input, expected) in tests { + let input = Decimal::from_str(input).unwrap(); + assert_eq!(expected, input.signum().to_i32().unwrap(), "Input: {}", input); + } +} + +#[test] +fn it_can_calculate_abs_sub() { + let tests = &[ + ("123", "124", 0), + ("123", "123", 0), + ("123", "122", 123), + ("-123", "-124", 123), + ("-123", "-123", 0), + ("-123", "-122", 0), + ]; + + for &(input1, input2, expected) in tests { + let input1 = Decimal::from_str(input1).unwrap(); + let input2 = Decimal::from_str(input2).unwrap(); + assert_eq!( + expected, + input1.abs_sub(&input2).to_i32().unwrap(), + "Input: {} {}", + input1, + input2 + ); + } +} + +#[test] +#[should_panic] +fn it_panics_when_scale_too_large() { + let _ = Decimal::new(1, 29); +} + +#[test] +fn test_zero_eq_negative_zero() { + let zero: Decimal = 0.into(); + + assert!(zero == zero); + assert!(-zero == zero); + assert!(zero == -zero); +} + +#[cfg(feature = "postgres")] +#[test] +fn to_from_sql() { + use bytes::BytesMut; + use postgres::types::{FromSql, Kind, ToSql, Type}; + + let tests = &[ + "3950.123456", + "3950", + "0.1", + "0.01", + "0.001", + "0.0001", + "0.00001", + "0.000001", + "1", + "-100", + "-123.456", + "119996.25", + "1000000", + "9999999.99999", + "12340.56789", + "79228162514264337593543950335", // 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF (96 bit) + "4951760157141521099596496895", // 0x0FFF_FFFF_FFFF_FFFF_FFFF_FFFF (95 bit) + "4951760157141521099596496896", // 0x1000_0000_0000_0000_0000_0000 + "18446744073709551615", + "-18446744073709551615", + ]; + + let t = Type::new("".into(), 0, Kind::Simple, "".into()); + + for test in tests { + let input = Decimal::from_str(test).unwrap(); + let mut bytes = BytesMut::new(); + input.to_sql(&t, &mut bytes).unwrap(); + let output = Decimal::from_sql(&t, &bytes).unwrap(); + + assert_eq!(input, output); + } +} + +fn hash_it(d: Decimal) -> u64 { + use std::collections::hash_map::DefaultHasher; + use std::hash::Hash; + use std::hash::Hasher; + + let mut h = DefaultHasher::new(); + d.hash(&mut h); + h.finish() +} + +#[test] +fn it_computes_equal_hashes_for_equal_values() { + // From the Rust Hash docs: + // + // "When implementing both Hash and Eq, it is important that the following property holds: + // + // k1 == k2 -> hash(k1) == hash(k2)" + + let k1 = Decimal::from_str("1").unwrap(); + let k2 = Decimal::from_str("1.0").unwrap(); + let k3 = Decimal::from_str("1.00").unwrap(); + let k4 = Decimal::from_str("1.01").unwrap(); + + assert_eq!(k1, k2); + assert_eq!(k1, k3); + assert_ne!(k1, k4); + + let h1 = hash_it(k1); + let h2 = hash_it(k2); + let h3 = hash_it(k3); + let h4 = hash_it(k4); + + assert_eq!(h1, h2); + assert_eq!(h1, h3); + assert_ne!(h1, h4); + + // Test the application of Hash calculation to a HashMap. + + use std::collections::HashMap; + + let mut map = HashMap::new(); + + map.insert(k1, k1.to_string()); + // map[k2] should overwrite map[k1] because k1 == k2. + map.insert(k2, k2.to_string()); + + assert_eq!("1.0", map.get(&k3).expect("could not get k3")); + assert_eq!(1, map.len()); + + // map[k3] should overwrite map[k2] because k3 == k2. + map.insert(k3, k3.to_string()); + // map[k4] should not overwrite map[k3] because k4 != k3. + map.insert(k4, k4.to_string()); + + assert_eq!(2, map.len()); + assert_eq!("1.00", map.get(&k1).expect("could not get k1")); +} + +#[test] +fn it_computes_equal_hashes_for_positive_and_negative_zero() { + // Verify 0 and -0 have the same hash + let k1 = Decimal::from_str("0").unwrap(); + let k2 = Decimal::from_str("-0").unwrap(); + assert_eq!("-0", k2.to_string()); + assert_eq!(k1, k2); + let h1 = hash_it(k1); + let h2 = hash_it(k2); + assert_eq!(h1, h2); + + // Verify 0 and -0.0 have the same hash + let k1 = Decimal::from_str("0").unwrap(); + let k2 = Decimal::from_str("-0.0").unwrap(); + assert_eq!("-0.0", k2.to_string()); + assert_eq!(k1, k2); + let h1 = hash_it(k1); + let h2 = hash_it(k2); + assert_eq!(h1, h2); +} + +#[test] +#[should_panic] +fn it_handles_i128_min() { + Decimal::from_i128_with_scale(std::i128::MIN, 0); +} + +#[test] +fn it_can_rescale() { + let tests = &[ + ("0", 6, "0.000000"), + ("0.000000", 2, "0.00"), + ("0.12345600000", 6, "0.123456"), + ("0.123456", 12, "0.123456000000"), + ("0.123456", 0, "0"), + ("0.000001", 4, "0.0000"), + ("1233456", 4, "1233456.0000"), + ("1.2", 30, "1.2000000000000000000000000000"), + ("79228162514264337593543950335", 0, "79228162514264337593543950335"), + ("4951760157141521099596496895", 1, "4951760157141521099596496895.0"), + ("4951760157141521099596496896", 1, "4951760157141521099596496896.0"), + ("18446744073709551615", 6, "18446744073709551615.000000"), + ("-18446744073709551615", 6, "-18446744073709551615.000000"), + ]; + + for &(value_raw, new_scale, expected_value) in tests { + let new_value = Decimal::from_str(expected_value).unwrap(); + let mut value = Decimal::from_str(value_raw).unwrap(); + value.rescale(new_scale); + assert_eq!(new_value.to_string(), value.to_string()); + } +} |